Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

pci_bus_device.c

00001 /***************************************************************************
00002  * CVSID: $Id: pci_bus_device.c,v 1.5 2004/04/22 21:52:05 david Exp $
00003  *
00004  * PCI bus devices
00005  *
00006  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
00007  *
00008  * Licensed under the Academic Free License version 2.0
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  **************************************************************************/
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #include <ctype.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <getopt.h>
00035 #include <assert.h>
00036 #include <unistd.h>
00037 #include <stdarg.h>
00038 
00039 #include "../logger.h"
00040 #include "../device_store.h"
00041 #include "bus_device.h"
00042 #include "common.h"
00043 
00053 static char *pci_ids = NULL;
00054 
00056 static unsigned int pci_ids_len;
00057 
00059 static unsigned int pci_ids_iter_pos;
00060 
00062 static void
00063 pci_ids_line_iter_init ()
00064 {
00065     pci_ids_iter_pos = 0;
00066 }
00067 
00069 #define PCI_IDS_MAX_LINE_LEN 512
00070 
00078 static char *
00079 pci_ids_line_iter_get_line (unsigned int *line_len)
00080 {
00081     unsigned int i;
00082     static char line[PCI_IDS_MAX_LINE_LEN];
00083 
00084     for (i = 0;
00085          pci_ids_iter_pos < pci_ids_len &&
00086          i < PCI_IDS_MAX_LINE_LEN - 1 &&
00087          pci_ids[pci_ids_iter_pos] != '\n'; i++, pci_ids_iter_pos++) {
00088         line[i] = pci_ids[pci_ids_iter_pos];
00089     }
00090 
00091     line[i] = '\0';
00092     if (line_len != NULL)
00093         *line_len = i;
00094 
00095     pci_ids_iter_pos++;
00096 
00097     return line;
00098 }
00099 
00104 static dbus_bool_t
00105 pci_ids_line_iter_has_more ()
00106 {
00107     return pci_ids_iter_pos < pci_ids_len;
00108 }
00109 
00110 
00125 static void
00126 pci_ids_find (int vendor_id, int product_id,
00127           int subsys_vendor_id, int subsys_product_id,
00128           char **vendor_name, char **product_name,
00129           char **subsys_vendor_name, char **subsys_product_name)
00130 {
00131     char *line;
00132     unsigned int i;
00133     unsigned int line_len;
00134     unsigned int num_tabs;
00135     char rep_vi[8];
00136     char rep_pi[8];
00137     char rep_svi[8];
00138     char rep_spi[8];
00139     static char store_vn[PCI_IDS_MAX_LINE_LEN];
00140     static char store_pn[PCI_IDS_MAX_LINE_LEN];
00141     static char store_svn[PCI_IDS_MAX_LINE_LEN];
00142     static char store_spn[PCI_IDS_MAX_LINE_LEN];
00143     dbus_bool_t vendor_matched = FALSE;
00144     dbus_bool_t product_matched = FALSE;
00145 
00146     snprintf (rep_vi, 8, "%04x", vendor_id);
00147     snprintf (rep_pi, 8, "%04x", product_id);
00148     snprintf (rep_svi, 8, "%04x", subsys_vendor_id);
00149     snprintf (rep_spi, 8, "%04x", subsys_product_id);
00150 
00151     *vendor_name = NULL;
00152     *product_name = NULL;
00153     *subsys_vendor_name = NULL;
00154     *subsys_product_name = NULL;
00155 
00156     for (pci_ids_line_iter_init (); pci_ids_line_iter_has_more ();) {
00157         line = pci_ids_line_iter_get_line (&line_len);
00158 
00159         /* skip lines with no content */
00160         if (line_len < 4)
00161             continue;
00162 
00163         /* skip comments */
00164         if (line[0] == '#')
00165             continue;
00166 
00167         /* count number of tabs */
00168         num_tabs = 0;
00169         for (i = 0; i < line_len; i++) {
00170             if (line[i] != '\t')
00171                 break;
00172             num_tabs++;
00173         }
00174 
00175         switch (num_tabs) {
00176         case 0:
00177             /* vendor names */
00178             vendor_matched = FALSE;
00179 
00180             /* first check subsys_vendor_id, if haven't done 
00181              * already */
00182             if (*subsys_vendor_name == NULL
00183                 && subsys_vendor_id != 0) {
00184                 if ((*((dbus_uint32_t *) line)) ==
00185                     (*((dbus_uint32_t *) rep_svi))) {
00186                     /* found it */
00187                     for (i = 4; i < line_len; i++) {
00188                         if (!isspace (line[i]))
00189                             break;
00190                     }
00191                     strncpy (store_svn, line + i,
00192                          PCI_IDS_MAX_LINE_LEN);
00193                     *subsys_vendor_name = store_svn;
00194                 }
00195             }
00196 
00197             /* check vendor_id */
00198             if (vendor_id != 0) {
00199                 if (memcmp (line, rep_vi, 4) == 0) {
00200                     /* found it */
00201                     vendor_matched = TRUE;
00202 
00203                     for (i = 4; i < line_len; i++) {
00204                         if (!isspace (line[i]))
00205                             break;
00206                     }
00207                     strncpy (store_vn, line + i,
00208                          PCI_IDS_MAX_LINE_LEN);
00209                     *vendor_name = store_vn;
00210                 }
00211             }
00212 
00213             break;
00214 
00215         case 1:
00216             product_matched = FALSE;
00217 
00218             /* product names */
00219             if (!vendor_matched)
00220                 continue;
00221 
00222             /* check product_id */
00223             if (product_id != 0) {
00224                 if (memcmp (line + 1, rep_pi, 4) == 0) {
00225                     /* found it */
00226 
00227                     product_matched = TRUE;
00228 
00229                     for (i = 5; i < line_len; i++) {
00230                         if (!isspace (line[i]))
00231                             break;
00232                     }
00233                     strncpy (store_pn, line + i,
00234                          PCI_IDS_MAX_LINE_LEN);
00235                     *product_name = store_pn;
00236                 }
00237             }
00238             break;
00239 
00240         case 2:
00241             /* subsystem_vendor subsystem_product */
00242             if (!vendor_matched || !product_matched)
00243                 continue;
00244 
00245             /* check product_id */
00246             if (subsys_vendor_id != 0
00247                 && subsys_product_id != 0) {
00248                 if (memcmp (line + 2, rep_svi, 4) == 0
00249                     && memcmp (line + 7, rep_spi,
00250                            4) == 0) {
00251                     /* found it */
00252                     for (i = 11; i < line_len; i++) {
00253                         if (!isspace (line[i]))
00254                             break;
00255                     }
00256                     strncpy (store_spn, line + i,
00257                          PCI_IDS_MAX_LINE_LEN);
00258                     *subsys_product_name = store_spn;
00259                 }
00260             }
00261 
00262             break;
00263 
00264         default:
00265             break;
00266         }
00267 
00268     }
00269 }
00270 
00278 static dbus_bool_t
00279 pci_ids_load (const char *path)
00280 {
00281     FILE *fp;
00282     unsigned int num_read;
00283 
00284     fp = fopen (path, "r");
00285     if (fp == NULL) {
00286         HAL_ERROR (("couldn't open PCI database at %s,", path));
00287         return FALSE;
00288     }
00289 
00290     fseek (fp, 0, SEEK_END);
00291     pci_ids_len = ftell (fp);
00292     fseek (fp, 0, SEEK_SET);
00293 
00294     pci_ids = malloc (pci_ids_len);
00295     if (pci_ids == NULL) {
00296         DIE (("Couldn't allocate %d bytes for PCI database file\n",
00297               pci_ids_len));
00298     }
00299 
00300     num_read = fread (pci_ids, sizeof (char), pci_ids_len, fp);
00301     if (pci_ids_len != num_read) {
00302         HAL_ERROR (("Error loading PCI database file\n"));
00303         free (pci_ids);
00304         pci_ids = NULL;
00305         return FALSE;
00306     }
00307 
00308     return TRUE;
00309 }
00310 
00315 static dbus_bool_t
00316 pci_ids_free ()
00317 {
00318     if (pci_ids != NULL) {
00319         free (pci_ids);
00320         pci_ids = NULL;
00321         return TRUE;
00322     }
00323     return FALSE;
00324 }
00325 
00326 
00345 static char *
00346 pci_device_compute_udi (HalDevice *d, int append_num)
00347 {
00348     static char buf[256];
00349 
00350     if (append_num == -1)
00351         sprintf (buf, "/org/freedesktop/Hal/devices/pci_%x_%x",
00352              hal_device_property_get_int (d, "pci.vendor_id"),
00353              hal_device_property_get_int (d, "pci.product_id"));
00354     else
00355         sprintf (buf, "/org/freedesktop/Hal/devices/pci_%x_%x/%d",
00356              hal_device_property_get_int (d, "pci.vendor_id"),
00357              hal_device_property_get_int (d, "pci.product_id"),
00358              append_num);
00359 
00360     return buf;
00361 }
00362 
00363 
00367 static void
00368 pci_device_init (BusDeviceHandler *self)
00369 {
00370     /* get all drivers under /sys/bus/pci/drivers */
00371     drivers_collect ("pci");
00372 
00373     /* Load /usr/share/hwdata/pci.ids */
00374     pci_ids_load (HWDATA_DIR "/pci.ids");
00375 }
00376 
00380 static void
00381 pci_device_shutdown (BusDeviceHandler *self)
00382 {
00383     pci_ids_free ();
00384 }
00385 
00386 
00387 static void 
00388 pci_device_pre_process (BusDeviceHandler *self,
00389             HalDevice *d,
00390             const char *sysfs_path,
00391             struct sysfs_device *device)
00392 {
00393     int i;
00394     int len;
00395     int vendor_id = 0;
00396     int product_id = 0;
00397     int subsys_vendor_id = 0;
00398     int subsys_product_id = 0;
00399     char *vendor_name;
00400     char *product_name;
00401     char *subsys_vendor_name;
00402     char *subsys_product_name;
00403     struct sysfs_attribute *cur;
00404     char attr_name[SYSFS_NAME_LEN];
00405     dbus_int32_t cls = 0x00ffffff;
00406     char namebuf[512];
00407 
00408     dlist_for_each_data (sysfs_get_device_attributes (device), cur,
00409                  struct sysfs_attribute) {
00410 
00411         if (sysfs_get_name_from_path (cur->path,
00412                           attr_name,
00413                           SYSFS_NAME_LEN) != 0)
00414             continue;
00415 
00416         /* strip whitespace */
00417         len = strlen (cur->value);
00418         for (i = len - 1; isspace (cur->value[i]); --i)
00419             cur->value[i] = '\0';
00420 
00421         /*printf("attr_name=%s -> '%s'\n", attr_name, cur->value); */
00422 
00423         if (strcmp (attr_name, "device") == 0)
00424             product_id = parse_hex (cur->value);
00425         else if (strcmp (attr_name, "vendor") == 0)
00426             vendor_id = parse_hex (cur->value);
00427         else if (strcmp (attr_name, "subsystem_device") == 0)
00428             subsys_product_id = parse_hex (cur->value);
00429         else if (strcmp (attr_name, "subsystem_vendor") == 0)
00430             subsys_vendor_id = parse_hex (cur->value);
00431         else if (strcmp (attr_name, "class") == 0) {
00432             cls = parse_hex (cur->value);
00433         }
00434     }
00435 
00436     hal_device_property_set_int (d, "pci.vendor_id", vendor_id);
00437     hal_device_property_set_int (d, "pci.product_id", product_id);
00438     hal_device_property_set_int (d, "pci.subsys_vendor_id", subsys_vendor_id);
00439     hal_device_property_set_int (d, "pci.subsys_product_id",
00440                  subsys_product_id);
00441 
00442     /* Lookup names in pci.ids */
00443     pci_ids_find (vendor_id, product_id, subsys_vendor_id,
00444               subsys_product_id, &vendor_name, &product_name,
00445               &subsys_vendor_name, &subsys_product_name);
00446     if (vendor_name != NULL)
00447         hal_device_property_set_string (d, "pci.vendor", vendor_name);
00448     if (product_name != NULL)
00449         hal_device_property_set_string (d, "pci.product", product_name);
00450     if (subsys_vendor_name != NULL)
00451         hal_device_property_set_string (d, "pci.subsys_vendor",
00452                     subsys_vendor_name);
00453     if (subsys_product_name != NULL)
00454         hal_device_property_set_string (d, "pci.subsys_product",
00455                     subsys_product_name);
00456 
00457     /* Provide best-guess of name, goes in Product property; 
00458      * .fdi files can override this */
00459     if (product_name != NULL) {
00460         hal_device_property_set_string (d, "info.product", product_name);
00461     } else {
00462         snprintf (namebuf, sizeof(namebuf), "Unknown (0x%04x)", product_id);
00463         hal_device_property_set_string (d, "info.product", namebuf);
00464     }
00465 
00466     /* Provide best-guess of vendor, goes in Vendor property; 
00467      * .fdi files can override this */
00468     if (vendor_name != NULL) {
00469         hal_device_property_set_string (d, "info.vendor", vendor_name);
00470     } else {
00471         snprintf (namebuf, sizeof(namebuf), "Unknown (0x%04x)", vendor_id);
00472         hal_device_property_set_string (d, "info.vendor", namebuf);
00473     }
00474 
00475 
00476     hal_device_property_set_int (d, "pci.device_class", (cls >> 16) & 0xff);
00477     hal_device_property_set_int (d, "pci.device_subclass", (cls >> 8) & 0xff);
00478     hal_device_property_set_int (d, "pci.device_protocol", cls & 0xff);
00479 }
00480 
00481 
00483 BusDeviceHandler pci_bus_handler = {
00484     pci_device_init,           
00485     bus_device_detection_done, 
00486     pci_device_shutdown,       
00487     bus_device_tick,           
00488     bus_device_accept,         
00489     bus_device_visit,          
00490     bus_device_removed,        
00491     pci_device_compute_udi,    
00492     pci_device_pre_process,    
00493     bus_device_got_udi,        
00494     "pci",                     
00495     "pci"                      
00496 };
00497 
00498 

Generated on Sat Apr 24 19:57:45 2004 for HAL by doxygen 1.3.6-20040222