00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00160 if (line_len < 4)
00161 continue;
00162
00163
00164 if (line[0] == '#')
00165 continue;
00166
00167
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
00178 vendor_matched = FALSE;
00179
00180
00181
00182 if (*subsys_vendor_name == NULL
00183 && subsys_vendor_id != 0) {
00184 if ((*((dbus_uint32_t *) line)) ==
00185 (*((dbus_uint32_t *) rep_svi))) {
00186
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
00198 if (vendor_id != 0) {
00199 if (memcmp (line, rep_vi, 4) == 0) {
00200
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
00219 if (!vendor_matched)
00220 continue;
00221
00222
00223 if (product_id != 0) {
00224 if (memcmp (line + 1, rep_pi, 4) == 0) {
00225
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
00242 if (!vendor_matched || !product_matched)
00243 continue;
00244
00245
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
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
00371 drivers_collect ("pci");
00372
00373
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
00417 len = strlen (cur->value);
00418 for (i = len - 1; isspace (cur->value[i]); --i)
00419 cur->value[i] = '\0';
00420
00421
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
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
00458
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
00467
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