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 "linux_pci.h"
00042
00052 static char* pci_ids = NULL;
00053
00055 static unsigned int pci_ids_len;
00056
00058 static unsigned int pci_ids_iter_pos;
00059
00061 static void pci_ids_line_iter_init()
00062 {
00063 pci_ids_iter_pos = 0;
00064 }
00065
00067 #define PCI_IDS_MAX_LINE_LEN 512
00068
00076 static char* pci_ids_line_iter_get_line(unsigned int* line_len)
00077 {
00078 unsigned int i;
00079 static char line[PCI_IDS_MAX_LINE_LEN];
00080
00081 for(i=0;
00082 pci_ids_iter_pos<pci_ids_len &&
00083 i<PCI_IDS_MAX_LINE_LEN-1 &&
00084 pci_ids[pci_ids_iter_pos]!='\n';
00085 i++, pci_ids_iter_pos++)
00086 {
00087 line[i] = pci_ids[pci_ids_iter_pos];
00088 }
00089
00090 line[i] = '\0';
00091 if( line_len!=NULL )
00092 *line_len = i;
00093
00094 pci_ids_iter_pos++;
00095
00096 return line;
00097 }
00098
00103 static dbus_bool_t pci_ids_line_iter_has_more()
00104 {
00105 return pci_ids_iter_pos<pci_ids_len;
00106 }
00107
00108
00123 static void pci_ids_find(int vendor_id, int product_id,
00124 int subsys_vendor_id, int subsys_product_id,
00125 char** vendor_name, char** product_name,
00126 char** subsys_vendor_name,char** subsys_product_name)
00127 {
00128 char* line;
00129 unsigned int i;
00130 unsigned int line_len;
00131 unsigned int num_tabs;
00132 char rep_vi[8];
00133 char rep_pi[8];
00134 char rep_svi[8];
00135 char rep_spi[8];
00136 static char store_vn[PCI_IDS_MAX_LINE_LEN];
00137 static char store_pn[PCI_IDS_MAX_LINE_LEN];
00138 static char store_svn[PCI_IDS_MAX_LINE_LEN];
00139 static char store_spn[PCI_IDS_MAX_LINE_LEN];
00140 dbus_bool_t vendor_matched=FALSE;
00141 dbus_bool_t product_matched=FALSE;
00142
00143 snprintf(rep_vi, 8, "%04x", vendor_id);
00144 snprintf(rep_pi, 8, "%04x", product_id);
00145 snprintf(rep_svi, 8, "%04x", subsys_vendor_id);
00146 snprintf(rep_spi, 8, "%04x", subsys_product_id);
00147
00148 *vendor_name = NULL;
00149 *product_name = NULL;
00150 *subsys_vendor_name = NULL;
00151 *subsys_product_name = NULL;
00152
00153 for(pci_ids_line_iter_init(); pci_ids_line_iter_has_more(); )
00154 {
00155 line = pci_ids_line_iter_get_line(&line_len);
00156
00157
00158 if( line_len<4 )
00159 continue;
00160
00161
00162 if( line[0]=='#' )
00163 continue;
00164
00165
00166 num_tabs = 0;
00167 for(i=0; i<line_len; i++)
00168 {
00169 if( line[i]!='\t' )
00170 break;
00171 num_tabs++;
00172 }
00173
00174 switch( num_tabs )
00175 {
00176 case 0:
00177
00178 vendor_matched = FALSE;
00179
00180
00181 if( *subsys_vendor_name==NULL && subsys_vendor_id!=0 )
00182 {
00183 if( (*((dbus_uint32_t*)line))==(*((dbus_uint32_t*)rep_svi)) )
00184 {
00185
00186 for(i=4; i<line_len; i++)
00187 {
00188 if( !isspace(line[i]) )
00189 break;
00190 }
00191 strncpy(store_svn, line+i, PCI_IDS_MAX_LINE_LEN);
00192 *subsys_vendor_name = store_svn;
00193 }
00194 }
00195
00196
00197 if( vendor_id!=0 )
00198 {
00199 if( memcmp(line, rep_vi, 4)==0 )
00200 {
00201
00202 vendor_matched = TRUE;
00203
00204 for(i=4; i<line_len; i++)
00205 {
00206 if( !isspace(line[i]) )
00207 break;
00208 }
00209 strncpy(store_vn, line+i, PCI_IDS_MAX_LINE_LEN);
00210 *vendor_name = store_vn;
00211 }
00212 }
00213
00214 break;
00215
00216 case 1:
00217 product_matched = FALSE;
00218
00219
00220 if( !vendor_matched )
00221 continue;
00222
00223
00224 if( product_id!=0 )
00225 {
00226 if( memcmp(line+1, rep_pi, 4)==0 )
00227 {
00228
00229
00230 product_matched = TRUE;
00231
00232 for(i=5; i<line_len; i++)
00233 {
00234 if( !isspace(line[i]) )
00235 break;
00236 }
00237 strncpy(store_pn, line+i, PCI_IDS_MAX_LINE_LEN);
00238 *product_name = store_pn;
00239 }
00240 }
00241 break;
00242
00243 case 2:
00244
00245 if( !vendor_matched || !product_matched )
00246 continue;
00247
00248
00249 if( subsys_vendor_id!=0 && subsys_product_id!=0 )
00250 {
00251 if( memcmp(line+2, rep_svi, 4)==0 &&
00252 memcmp(line+7, rep_spi, 4)==0 )
00253 {
00254
00255 for(i=11; i<line_len; i++)
00256 {
00257 if( !isspace(line[i]) )
00258 break;
00259 }
00260 strncpy(store_spn, line+i, PCI_IDS_MAX_LINE_LEN);
00261 *subsys_product_name = store_spn;
00262 }
00263 }
00264
00265 break;
00266
00267 default:
00268 break;
00269 }
00270
00271 }
00272 }
00273
00281 static dbus_bool_t pci_ids_load(const char* path)
00282 {
00283 FILE* fp;
00284 unsigned int num_read;
00285
00286 fp = fopen(path, "r");
00287 if( fp==NULL )
00288 {
00289 HAL_ERROR(("couldn't open PCI database at %s,", path));
00290 return FALSE;
00291 }
00292
00293 fseek(fp, 0, SEEK_END);
00294 pci_ids_len = ftell(fp);
00295 fseek(fp, 0, SEEK_SET);
00296
00297 pci_ids = malloc(pci_ids_len);
00298 if( pci_ids==NULL )
00299 {
00300 DIE(("Couldn't allocate %d bytes for PCI database file\n",
00301 pci_ids_len));
00302 }
00303
00304 num_read = fread(pci_ids, sizeof(char), pci_ids_len, fp);
00305 if( pci_ids_len!=num_read )
00306 {
00307 HAL_ERROR(("Error loading PCI database file\n"));
00308 free(pci_ids);
00309 pci_ids=NULL;
00310 return FALSE;
00311 }
00312
00313 return TRUE;
00314 }
00315
00320 static dbus_bool_t pci_ids_free()
00321 {
00322 if( pci_ids!=NULL )
00323 {
00324 free(pci_ids);
00325 pci_ids=NULL;
00326 return TRUE;
00327 }
00328 return FALSE;
00329 }
00330
00331
00350 static char* pci_compute_udi(HalDevice* d, int append_num)
00351 {
00352 static char buf[256];
00353
00354 if( append_num==-1 )
00355 sprintf(buf, "/org/freedesktop/Hal/devices/pci_%x_%x",
00356 ds_property_get_int(d, "pci.vendor_id"),
00357 ds_property_get_int(d, "pci.product_id"));
00358 else
00359 sprintf(buf, "/org/freedesktop/Hal/devices/pci_%x_%x/%d",
00360 ds_property_get_int(d, "pci.vendor_id"),
00361 ds_property_get_int(d, "pci.product_id"),
00362 append_num);
00363
00364 return buf;
00365 }
00366
00367
00376 static void pci_add_caps_from_class(HalDevice* d,
00377 int dev_class,
00378 int dev_sub_class,
00379 int dev_proto)
00380 {
00381 char* cat = NULL;
00382
00383 switch( dev_class )
00384 {
00385 case 0x01:
00386 cat = "storage_controller";
00387 ds_add_capability(d, "storage_controller");
00388 switch( dev_sub_class)
00389 {
00390 case 0x00:
00391 ds_add_capability(d, "storage_controller.scsi");
00392 break;
00393 case 0x01:
00394 ds_add_capability(d, "storage_controller.ide");
00395 break;
00396 case 0x02:
00397 ds_add_capability(d, "storage_controller.floppy");
00398 break;
00399 case 0x03:
00400 ds_add_capability(d, "storage_controller.ipi");
00401 break;
00402 case 0x04:
00403 ds_add_capability(d, "storage_controller.raid");
00404 break;
00405 }
00406 break;
00407 case 0x02:
00408 cat = "net";
00409 ds_add_capability(d, "net");
00410 switch( dev_sub_class)
00411 {
00412 case 0x00:
00413 ds_add_capability(d, "net.ethernet");
00414 break;
00415 case 0x01:
00416 ds_add_capability(d, "net.tokenring");
00417 break;
00418 case 0x02:
00419 ds_add_capability(d, "net.fddi");
00420 break;
00421 case 0x03:
00422 ds_add_capability(d, "net.atm");
00423 break;
00424 case 0x04:
00425 ds_add_capability(d, "net.isdn");
00426 break;
00427 }
00428 break;
00429 case 0x03:
00430 cat = "video";
00431 ds_add_capability(d, "video");
00432 if( dev_sub_class==0x00 && dev_proto==0x00 )
00433 ds_add_capability(d, "video.vga");
00434 if( dev_sub_class==0x00 && dev_proto==0x01 )
00435 ds_add_capability(d, "video.8514");
00436 else if( dev_sub_class==0x01 )
00437 ds_add_capability(d, "video.xga");
00438 else if( dev_sub_class==0x02 )
00439 ds_add_capability(d, "video.3d");
00440 break;
00441 case 0x04:
00442 cat = "multimedia";
00443 ds_add_capability(d, "multimedia");
00444 switch( dev_sub_class)
00445 {
00446 case 0x00:
00447 ds_add_capability(d, "multimedia.video");
00448 cat = "multimedia.video";
00449 break;
00450 case 0x01:
00451 ds_add_capability(d, "multimedia.audio");
00452 cat = "multimedia.audio";
00453 break;
00454 case 0x02:
00455 ds_add_capability(d, "multimedia.telephony");
00456 cat = "multimedia.telephony";
00457 break;
00458 }
00459 break;
00460 case 0x06:
00461 cat = "bridge";
00462 ds_add_capability(d, "bridge");
00463 switch( dev_sub_class)
00464 {
00465 case 0x00:
00466 ds_add_capability(d, "bridge.host");
00467 break;
00468 case 0x01:
00469 ds_add_capability(d, "bridge.isa");
00470 break;
00471 case 0x02:
00472 ds_add_capability(d, "bridge.eisa");
00473 break;
00474 case 0x03:
00475 ds_add_capability(d, "bridge.micro_channel");
00476 break;
00477 case 0x04:
00478 ds_add_capability(d, "bridge.pci");
00479 break;
00480 case 0x05:
00481 ds_add_capability(d, "bridge.pcmcia");
00482 break;
00483 case 0x06:
00484 ds_add_capability(d, "bridge.nubus");
00485 break;
00486 case 0x07:
00487 cat = "bridge.cardbus";
00488 ds_add_capability(d, "bridge.cardbus");
00489 break;
00490 case 0x08:
00491 ds_add_capability(d, "bridge.raceway");
00492 break;
00493 case 0x09:
00494 ds_add_capability(d, "bridge.semi_transparent");
00495 break;
00496 case 0x0a:
00497 ds_add_capability(d, "bridge.infiniband");
00498 break;
00499 }
00500 break;
00501 case 0x07:
00502 cat = "comm";
00503 ds_add_capability(d, "comm");
00504 if( dev_sub_class==0x00 )
00505 {
00506 cat = "comm.serial";
00507 ds_add_capability(d, "comm.serial");
00508 switch( dev_proto)
00509 {
00510 case 0x00:
00511 ds_add_capability(d, "comm.serial.8250");
00512 break;
00513 case 0x01:
00514 ds_add_capability(d, "comm.serial.16450");
00515 break;
00516 case 0x02:
00517 ds_add_capability(d, "comm.serial.16550");
00518 break;
00519 case 0x03:
00520 ds_add_capability(d, "comm.serial.16650");
00521 break;
00522 case 0x04:
00523 ds_add_capability(d, "comm.serial.16750");
00524 break;
00525 case 0x05:
00526 ds_add_capability(d, "comm.serial.16850");
00527 break;
00528 case 0x06:
00529 ds_add_capability(d, "comm.serial.16950");
00530 break;
00531 }
00532 }
00533 else if( dev_sub_class==0x01 )
00534 {
00535 cat = "comm.parallel";
00536 ds_add_capability(d, "comm.parallel");
00537 switch( dev_proto)
00538 {
00539 case 0x00:
00540 ds_add_capability(d, "comm.parallel.spp");
00541 break;
00542 case 0x01:
00543 ds_add_capability(d, "comm.parallel.bidir");
00544 break;
00545 case 0x02:
00546 ds_add_capability(d, "comm.parallel.ecp");
00547 break;
00548 case 0x03:
00549 ds_add_capability(d, "comm.parallel.ieee1284");
00550 break;
00551 case 0xfe:
00552 ds_add_capability(d, "comm.parallel.ieee1284_target");
00553 break;
00554 }
00555 }
00556 else if( dev_sub_class==0x02 )
00557 {
00558 cat = "comm.serial";
00559 ds_add_capability(d, "comm.serial");
00560 ds_add_capability(d, "comm.serial.multiport");
00561 }
00562 else if( dev_sub_class==0x03 )
00563 {
00564 cat = "modem";
00565 ds_add_capability(d, "modem");
00566 if( dev_proto>=0x01 && dev_proto<=0x04 )
00567 ds_add_capability(d, "modem.hayes");
00568 }
00569 break;
00570 case 0x0c:
00571 cat = "serial_controller";
00572 ds_add_capability(d, "serial_controller");
00573 switch( dev_sub_class)
00574 {
00575 case 0x00:
00576 cat = "serial_controller.ieee1394";
00577 ds_add_capability(d, "serial_controller.ieee1394");
00578 if( dev_proto==0x10 )
00579 ds_add_capability(d, "serial_controller.ieee1394.ohci");
00580 break;
00581 case 0x01:
00582 ds_add_capability(d, "serial_controller.access");
00583 break;
00584 case 0x02:
00585 ds_add_capability(d, "serial_controller.ssa");
00586 break;
00587 case 0x03:
00588 cat = "serial_controller.usb";
00589 ds_add_capability(d, "serial_controller.usb");
00590 switch( dev_proto )
00591 {
00592 case 0x00:
00593 ds_add_capability(d, "serial_controller.usb.uhci");
00594 break;
00595 case 0x01:
00596 ds_add_capability(d, "serial_controller.usb.ohci");
00597 break;
00598 case 0x02:
00599 ds_add_capability(d, "serial_controller.usb.ehci");
00600 break;
00601 case 0xfe:
00602 ds_add_capability(d, "serial_controller.usb.device");
00603 break;
00604 }
00605 break;
00606 }
00607 break;
00608 case 0x0d:
00609 cat = "wireless";
00610 ds_add_capability(d, "wireless");
00611 switch( dev_sub_class)
00612 {
00613 case 0x00:
00614 ds_add_capability(d, "wireless.irda");
00615 break;
00616 case 0x01:
00617 ds_add_capability(d, "wireless.consumer_controller");
00618 break;
00619 case 0x02:
00620 ds_add_capability(d, "wireless.rf_controller");
00621 break;
00622 }
00623 break;
00624 case 0x0f:
00625 cat = "satellite_controller";
00626 ds_add_capability(d, "satellite_controller");
00627 switch( dev_sub_class)
00628 {
00629 case 0x00:
00630 ds_add_capability(d, "satellite_controller.tv");
00631 break;
00632 case 0x01:
00633 ds_add_capability(d, "satellite_controller.audio");
00634 break;
00635 case 0x02:
00636 ds_add_capability(d, "satellite_controller.video");
00637 break;
00638 case 0x03:
00639 ds_add_capability(d, "satellite_controller.data");
00640 break;
00641 }
00642 break;
00643 }
00644
00645 if( cat!=NULL )
00646 ds_property_set_string(d, "info.category", cat);
00647 }
00648
00649
00650
00651 static void visit_device_pci_got_parent(HalDevice* parent,
00652 void* data1, void* data2);
00653
00662 void visit_device_pci(const char* path, struct sysfs_device *device)
00663 {
00664 int i;
00665 int len;
00666 HalDevice* d;
00667 char attr_name[SYSFS_NAME_LEN];
00668 struct sysfs_attribute* cur;
00669 int vendor_id=0;
00670 int product_id=0;
00671 int subsys_vendor_id=0;
00672 int subsys_product_id=0;
00673 char* vendor_name;
00674 char* product_name;
00675 char* subsys_vendor_name;
00676 char* subsys_product_name;
00677 const char* driver;
00678 dbus_int32_t cls = 0x00ffffff;
00679 char namebuf[512];
00680 char* parent_sysfs_path;
00681
00682
00683
00684
00685 d = ds_device_new();
00686 ds_property_set_string(d, "info.bus", "pci");
00687 ds_property_set_string(d, "linux.sysfs_path", path);
00688 ds_property_set_string(d, "linux.sysfs_path_device", path);
00693 ds_property_set_string(d, "pci.linux.sysfs_path", path);
00694
00695
00696
00697 driver = drivers_lookup(path);
00698 if( driver!=NULL )
00699 ds_property_set_string(d, "linux.driver", driver);
00700
00701 dlist_for_each_data(sysfs_get_device_attributes(device), cur,
00702 struct sysfs_attribute)
00703 {
00704
00705 if( sysfs_get_name_from_path(cur->path,
00706 attr_name, SYSFS_NAME_LEN) != 0 )
00707 continue;
00708
00709
00710 len = strlen(cur->value);
00711 for(i=len-1; isspace(cur->value[i]); --i)
00712 cur->value[i] = '\0';
00713
00714
00715
00716 if( strcmp(attr_name, "device")==0 )
00717 product_id = parse_hex(cur->value);
00718 else if( strcmp(attr_name, "vendor")==0 )
00719 vendor_id = parse_hex(cur->value);
00720 else if( strcmp(attr_name, "subsystem_device")==0 )
00721 subsys_product_id = parse_hex(cur->value);
00722 else if( strcmp(attr_name, "subsystem_vendor")==0 )
00723 subsys_vendor_id = parse_hex(cur->value);
00724 else if( strcmp(attr_name, "class")==0 )
00725 {
00726 cls = parse_hex(cur->value);
00727 }
00728 }
00729
00730 ds_property_set_int(d, "pci.vendor_id", vendor_id);
00731 ds_property_set_int(d, "pci.product_id", product_id);
00732 ds_property_set_int(d, "pci.subsys_vendor_id", subsys_vendor_id);
00733 ds_property_set_int(d, "pci.subsys_product_id",subsys_product_id);
00734
00735
00736 pci_ids_find(vendor_id, product_id, subsys_vendor_id, subsys_product_id,
00737 &vendor_name, &product_name,
00738 &subsys_vendor_name, &subsys_product_name);
00739 if( vendor_name!=NULL )
00740 ds_property_set_string(d, "pci.vendor", vendor_name);
00741 if( product_name!=NULL )
00742 ds_property_set_string(d, "pci.product", product_name);
00743 if( subsys_vendor_name!=NULL )
00744 ds_property_set_string(d, "pci.subsys_vendor", subsys_vendor_name);
00745 if( subsys_product_name!=NULL )
00746 ds_property_set_string(d, "pci.subsys_product", subsys_product_name);
00747
00748
00749
00750 if( product_name!=NULL )
00751 {
00752 ds_property_set_string(d, "info.product", product_name);
00753 }
00754 else
00755 {
00756 snprintf(namebuf, 512, "Unknown (0x%04x)", product_id);
00757 ds_property_set_string(d, "info.product", namebuf);
00758 }
00759
00760
00761
00762 if( vendor_name!=NULL )
00763 {
00764 ds_property_set_string(d, "info.vendor", vendor_name);
00765 }
00766 else
00767 {
00768 snprintf(namebuf, 512, "Unknown (0x%04x)", vendor_id);
00769 ds_property_set_string(d, "info.vendor", namebuf);
00770 }
00771
00772
00773 ds_property_set_int(d, "pci.device_class", (cls>>16)&0xff);
00774 ds_property_set_int(d, "pci.device_subclass",(cls>>8)&0xff);
00775 ds_property_set_int(d, "pci.device_protocol", cls&0xff);
00776 pci_add_caps_from_class(d, (cls>>16)&0xff, (cls>>8)&0xff, cls&0xff);
00777
00778 parent_sysfs_path = get_parent_sysfs_path(path);
00779
00780
00781
00782
00783
00784 ds_device_async_find_by_key_value_string("linux.sysfs_path_device",
00785 parent_sysfs_path,
00786 TRUE,
00787 visit_device_pci_got_parent,
00788 (void*) d, NULL,
00789 is_probing ? 0 :
00790 HAL_LINUX_HOTPLUG_TIMEOUT);
00791
00792 free(parent_sysfs_path);
00793 }
00794
00802 static void visit_device_pci_got_parent(HalDevice* parent,
00803 void* data1, void* data2)
00804 {
00805 char* new_udi = NULL;
00806 HalDevice* new_d = NULL;
00807 HalDevice* d = (HalDevice*) data1;
00808
00809 if( parent!=NULL )
00810 {
00811 ds_property_set_string(d, "info.parent", parent->udi);
00812 }
00813
00814
00815
00816
00817 new_udi = rename_and_merge(d, pci_compute_udi, "pci");
00818 if( new_udi!=NULL )
00819 {
00820 new_d = ds_device_find(new_udi);
00821 if( new_d!=NULL )
00822 {
00823 ds_gdl_add(new_d);
00824 }
00825 }
00826 }
00827
00828
00832 void linux_pci_init()
00833 {
00834
00835 drivers_collect("pci");
00836
00837
00838 pci_ids_load(HWDATA_DIR "/pci.ids");
00839 }
00840
00845 void linux_pci_detection_done()
00846 {
00847 }
00848
00852 void linux_pci_shutdown()
00853 {
00854 pci_ids_free();
00855 }
00856