diff options
-rwxr-xr-x | mdk-stage1/pci-resource/update-pci-ids.pl | 40 | ||||
-rw-r--r-- | mdk-stage1/probing.c | 113 |
2 files changed, 110 insertions, 43 deletions
diff --git a/mdk-stage1/pci-resource/update-pci-ids.pl b/mdk-stage1/pci-resource/update-pci-ids.pl index 73f1d151b..1d179c06d 100755 --- a/mdk-stage1/pci-resource/update-pci-ids.pl +++ b/mdk-stage1/pci-resource/update-pci-ids.pl @@ -16,6 +16,15 @@ struct pci_module_map { const char *module; /* module to load */ }; +struct pci_module_map_full { + unsigned short vendor; /* PCI vendor id */ + unsigned short device; /* PCI device id */ + unsigned short subvendor; /* PCI subvendor id */ + unsigned short subdevice; /* PCI subdevice id */ + const char *name; /* PCI human readable name */ + const char *module; /* module to load */ +}; + '; my %t = ( @@ -26,20 +35,37 @@ my %t = ( foreach my $type (keys %t) { my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1:"$t{$type}"`); - print "#ifndef DISABLE_".uc($type)." -struct pci_module_map ${type}_pci_ids[] = { -"; + my (@entries, @entries_full); foreach my $k (sort keys %$pci) { my $v = $pci->{$k}; member($v->[0], @modules) or next; - $k =~ /^(....)(....)/; - printf qq|\t{ 0x%s, 0x%s, "%s", "%s" },\n|, - $1, $2, $v->[1], $v->[0]; + $k =~ /^(....)(....)(....)(....)/; + my $values = { vendor => $1, device => $2, subvendor => $3, subdevice => $4, driver => $v->[0], description => $v->[1] }; + if ($values->{subdevice} eq 'ffff' && $values->{subvendor} eq 'ffff') { + push @entries, $values; + } else { + push @entries_full, $values; + } } + print "#ifndef DISABLE_".uc($type)." +struct pci_module_map ${type}_pci_ids[] = { +"; + printf qq|\t{ 0x%s, 0x%s, "%s", "%s" },\n|, $_->{vendor}, $_->{device}, $_->{description}, $_->{driver} + foreach @entries; + print "}; +unsigned int ${type}_num_ids = sizeof(${type}_pci_ids) / sizeof(struct pci_module_map); +"; + + print " +struct pci_module_map_full ${type}_pci_ids_full[] = { +"; + printf qq|\t{ 0x%s, 0x%s, 0x%s, 0x%s, "%s", "%s" },\n|, $_->{vendor}, $_->{device}, $_->{subvendor}, $_->{subdevice}, $_->{description}, $_->{driver} + foreach @entries_full; print "}; -int ${type}_num_ids = sizeof(${type}_pci_ids) / sizeof(struct pci_module_map); +unsigned int ${type}_num_ids_full = sizeof(${type}_pci_ids_full) / sizeof(struct pci_module_map_full); + #endif "; diff --git a/mdk-stage1/probing.c b/mdk-stage1/probing.c index d46c35e4d..cfb9bae69 100644 --- a/mdk-stage1/probing.c +++ b/mdk-stage1/probing.c @@ -120,6 +120,41 @@ char * get_net_intf_description(char * intf_name) } #endif +void discovered_device(enum driver_type type, + unsigned short vendor, unsigned short device, unsigned short subvendor, unsigned short subdevice, + const char * description, const char * driver) +{ + log_message("PCI: device %04x %04x %04x %04x is \"%s\", driver is %s", vendor, device, subvendor, subdevice, description, driver); +#ifndef DISABLE_MEDIAS + if (type == SCSI_ADAPTERS) { + int wait_msg = 0; + enum insmod_return failed; + if (IS_AUTOMATIC) { + wait_message("Loading driver for SCSI adapter:\n \n%s", description); + wait_msg = 1; + } else + stg1_info_message("About to load driver for SCSI adapter:\n \n%s", description); + failed = my_insmod(driver, SCSI_ADAPTERS, NULL); + if (wait_msg) + remove_wait_message(); + warning_insmod_failed(failed); + } +#endif +#ifndef DISABLE_NETWORK + if (type == NETWORK_DEVICES) { + stg1_info_message("About to load driver for network device:\n \n%s", description); + prepare_intf_descr(description); + warning_insmod_failed(my_insmod(driver, NETWORK_DEVICES, NULL)); + if (intf_descr_for_discover) /* for modules providing more than one net intf */ + net_discovered_interface(NULL); + } +#endif +#ifdef ENABLE_USB + if (type == USB_CONTROLLERS) + my_insmod(driver, USB_CONTROLLERS, NULL); +#endif +} + #ifdef ENABLE_USB void probe_that_type(enum driver_type type, enum media_bus bus) #else @@ -129,9 +164,11 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u /* ---- PCI probe ---------------------------------------------- */ { FILE * f; - int len = 0; + unsigned int len = 0; + unsigned int len_full = 0; char buf[200]; struct pci_module_map * pcidb = NULL; + struct pci_module_map_full * pcidb_full = NULL; switch (type) { #ifndef DISABLE_PCIADAPTERS @@ -143,12 +180,16 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u already_probed_scsi_adapters = 1; pcidb = medias_pci_ids; len = medias_num_ids; + pcidb_full = medias_pci_ids_full; + len_full = medias_num_ids_full; break; #endif #ifndef DISABLE_NETWORK case NETWORK_DEVICES: pcidb = network_pci_ids; len = network_num_ids; + pcidb_full = network_pci_ids_full; + len_full = network_num_ids_full; break; #endif #endif @@ -177,48 +218,48 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u } while (1) { - int i, garb, vendor, device; + unsigned int i; + unsigned short vendor, device, subvendor, subdevice, devbusfn; + subvendor = 0xFFFF; if (!fgets(buf, sizeof(buf), f)) break; - sscanf(buf, "%x %x", &garb, &vendor); - device = vendor & 0xFFFF; /* because scanf from dietlibc does not support %4f */ - vendor = (vendor >> 16) & 0xFFFF; + sscanf(buf, "%hx %x", &devbusfn, &i); + device = i; + vendor = i >> 16; - for (i = 0; i < len; i++) { - if (pcidb[i].vendor == vendor && pcidb[i].device == device) { - log_message("PCI: device %04x %04x is \"%s\" (%s)", vendor, device, pcidb[i].name, pcidb[i].module); -#ifndef DISABLE_MEDIAS - if (type == SCSI_ADAPTERS) { - int wait_msg = 0; - enum insmod_return failed; - if (IS_AUTOMATIC) { - wait_message("Loading driver for SCSI adapter:\n \n%s", pcidb[i].name); - wait_msg = 1; - } else - stg1_info_message("About to load driver for SCSI adapter:\n \n%s", pcidb[i].name); - failed = my_insmod(pcidb[i].module, SCSI_ADAPTERS, NULL); - if (wait_msg) - remove_wait_message(); - warning_insmod_failed(failed); - + for (i = 0; i < len_full; i++) + if (pcidb_full[i].vendor == vendor && pcidb_full[i].device == device) { + if (subvendor == 0xFFFF) { + int bus = devbusfn >> 8; + int device_p = (devbusfn & 0xff) >> 3; + int function = (devbusfn & 0xff) & 0x07; + char file[100]; + FILE * sf; + log_message("PCI: device %04x %04x needs full pci probe", vendor, device); + sprintf(file, "/proc/bus/pci/%02x/%02x.%d", bus, device_p, function); + if (!(sf = fopen(file, "rb"))) { + log_message("PCI: could not open file for full probe (%s)", file); + continue; + } + fread(&buf, 48, 1, sf); + fclose(sf); + memcpy(&subvendor, buf+44, 2); + memcpy(&subdevice, buf+46, 2); + log_message("PCI: device is actually %04x %04x %04x %04x", vendor, device, subvendor, subdevice); } -#endif -#ifndef DISABLE_NETWORK - if (type == NETWORK_DEVICES) { - stg1_info_message("About to load driver for network device:\n \n%s", pcidb[i].name); - prepare_intf_descr(pcidb[i].name); - warning_insmod_failed(my_insmod(pcidb[i].module, NETWORK_DEVICES, NULL)); - if (intf_descr_for_discover) /* for modules providing more than one net intf */ - net_discovered_interface(NULL); + if (pcidb_full[i].subvendor == subvendor && pcidb_full[i].subdevice == subdevice) { + discovered_device(type, vendor, device, subvendor, subdevice, pcidb_full[i].name, pcidb_full[i].module); + goto next_pci_device; } -#endif -#ifdef ENABLE_USB - if (type == USB_CONTROLLERS) - my_insmod(pcidb[i].module, USB_CONTROLLERS, NULL); -#endif } - } + + for (i = 0; i < len; i++) + if (pcidb[i].vendor == vendor && pcidb[i].device == device) { + discovered_device(type, vendor, device, 0xFFFF, 0xFFFF, pcidb[i].name, pcidb[i].module); + goto next_pci_device; + } + next_pci_device:; } fclose(f); end_pci_probe:; |