diff options
-rw-r--r-- | mdk-stage1/probing.c | 129 | ||||
-rw-r--r-- | mdk-stage1/probing.h | 14 | ||||
-rw-r--r-- | mdk-stage1/thirdparty.c | 55 |
3 files changed, 175 insertions, 23 deletions
diff --git a/mdk-stage1/probing.c b/mdk-stage1/probing.c index 9059a6f20..176101169 100644 --- a/mdk-stage1/probing.c +++ b/mdk-stage1/probing.c @@ -121,19 +121,121 @@ char * get_net_intf_description(char * intf_name) } #endif -static struct pci_module_map_full orphan_devices[50]; /* might be overkill, we only need the driver for now */ -static int orphan_devices_len = 0; +struct pcitable_entry detected_devices[50]; +int detected_devices_len = 0; -int exists_orphan_device(char *driver) { +/* FIXME: factorize with probe_that_type() */ + +static void add_detected_device(unsigned short vendor, unsigned short device, const char *name, const char *module) +{ + struct pcitable_entry *dev = &detected_devices[detected_devices_len++]; + dev->vendor = vendor; + dev->device = device; + strncpy(dev->module, module, 19); + dev->module[19] = '\0'; + strncpy(dev->description, name, 99); + dev->description[99] = '\0'; + log_message("detected device (%x, %x, %s, %s)", vendor, device, name, module); +} + +static int check_device_full(struct pci_module_map_full * pcidb_full, unsigned int len_full, + unsigned short vendor, unsigned short device, + unsigned short subvendor, unsigned short subdevice) +{ + int i; + for (i = 0; i < len_full; i++) + if (pcidb_full[i].vendor == vendor && pcidb_full[i].device == device) { + if (pcidb_full[i].subvendor == subvendor && pcidb_full[i].subdevice == subdevice) { + add_detected_device(pcidb_full[i].vendor, pcidb_full[i].device, + pcidb_full[i].name, pcidb_full[i].module); + return 1; + } + } + return 0; +} + +static int check_device(struct pci_module_map * pcidb, unsigned int len, + unsigned short vendor, unsigned short device) { int i; - for (i = 0; i < orphan_devices_len ; i++) { - if (!strcmp(orphan_devices[i].module, driver)) { - log_message("probing: found orphan device for module %s", driver); + for (i = 0; i < len; i++) + if (pcidb[i].vendor == vendor && pcidb[i].device == device) { + add_detected_device(pcidb[i].vendor, pcidb[i].device, + pcidb[i].name, pcidb[i].module); return 1; } + return 0; +} + +void probing_detect_devices() +{ + FILE * f = NULL; + char buf[200]; + static int already_detected_devices = 0; + + if (already_detected_devices) + return; + + if (!(f = fopen("/proc/bus/pci/devices", "rb"))) { + log_message("PCI: could not open proc file"); + return; + } + + while (1) { + unsigned int i; + unsigned short vendor, device, subvendor, subdevice, devbusfn; + if (!fgets(buf, sizeof(buf), f)) break; + sscanf(buf, "%hx %x", &devbusfn, &i); + device = i; + vendor = i >> 16; + { + int bus = devbusfn >> 8; + int device_p = (devbusfn & 0xff) >> 3; + int function = (devbusfn & 0xff) & 0x07; + char file[100]; + int sf; + sprintf(file, "/proc/bus/pci/%02x/%02x.%d", bus, device_p, function); + if ((sf = open(file, O_RDONLY)) == -1) { + log_message("PCI: could not open file for full probe (%s)", file); + continue; + } + if (read(sf, buf, 48) == -1) { + log_message("PCI: could not read 48 bytes from %s", file); + close(sf); + continue; + } + close(sf); + memcpy(&subvendor, buf+44, 2); + memcpy(&subdevice, buf+46, 2); + } + + +#ifndef DISABLE_PCIADAPTERS +#ifndef DISABLE_MEDIAS + if (check_device_full(medias_pci_ids_full, medias_num_ids_full, vendor, device, subvendor, subdevice)) + continue; + if (check_device(medias_pci_ids, medias_num_ids, vendor, device)) + continue; +#endif + +#ifndef DISABLE_NETWORK + if (check_device_full(network_pci_ids_full, network_num_ids_full, vendor, device, subvendor, subdevice)) + continue; + if (check_device(network_pci_ids, network_num_ids, vendor, device)) + continue; +#endif +#endif + +#ifdef ENABLE_USB + if (check_device(usb_pci_ids, usb_num_ids, vendor, device)) + continue; +#endif + + /* device can't be found in built-in pcitables, but keep it */ + add_detected_device(vendor, device, "", ""); } - log_message("probing: no orphan device for module %s", driver); - return 0; + + fclose(f); + already_detected_devices = 1; } void discovered_device(enum driver_type type, @@ -166,17 +268,6 @@ void discovered_device(enum driver_type type, /* we can't allow additional modules floppy since we need usbkbd for keystrokes of usb keyboards */ failed = my_insmod(driver, USB_CONTROLLERS, NULL, 0); #endif - - if (failed != INSMOD_OK) { - struct pci_module_map_full *dev = &orphan_devices[orphan_devices_len++]; - log_message("adding orphan device (%x, %x, %s)", vendor, device, driver); - dev->vendor = vendor; - dev->device = device; - dev->subvendor = subvendor; - dev->subdevice = subdevice; - dev->name = description; - dev->module = driver; - } } #ifdef ENABLE_USB diff --git a/mdk-stage1/probing.h b/mdk-stage1/probing.h index 4f72a9269..6efa7b464 100644 --- a/mdk-stage1/probing.h +++ b/mdk-stage1/probing.h @@ -34,6 +34,18 @@ void net_discovered_interface(char * intf_name); char * get_net_intf_description(char * intf_name); void prepare_intf_descr(const char * intf_descr); void probe_that_type(enum driver_type type, enum media_bus bus); -int exists_orphan_device(char *driver); + +struct pcitable_entry { + /* some bits stolen from pci-resource/pci-ids.h + * FIXME: split pci-ids.h into pci-ids.c and pci-ids.h so that the header can be re-used + */ + unsigned short vendor; /* PCI vendor id */ + unsigned short device; /* PCI device id */ + char module[20]; /* module to load */ + char description[100]; /* PCI human readable description */ +}; +extern struct pcitable_entry detected_devices[50]; +extern int detected_devices_len; +void probing_detect_devices(); #endif diff --git a/mdk-stage1/thirdparty.c b/mdk-stage1/thirdparty.c index e3a90a047..b8b731dfd 100644 --- a/mdk-stage1/thirdparty.c +++ b/mdk-stage1/thirdparty.c @@ -32,6 +32,9 @@ #define THIRDPARTY_MOUNT_LOCATION "/tmp/thirdparty" +static struct pcitable_entry pcitable[100]; +static int pcitable_len = 0; + static enum return_type thirdparty_choose_device(char ** device, int probe_only) { char ** medias, ** medias_models; @@ -210,7 +213,51 @@ static enum return_type thirdparty_prompt_modules(const char *modules_location, } -static enum return_type thirdparty_autoload_modules(const char *modules_location, char ** modules_list, FILE *f, int load_probed_only) +static void thirdparty_load_pcitable(const char *modules_location) +{ + char pcitable_filename[100]; + FILE * f = NULL; + + sprintf(pcitable_filename, "%s/pcitable", modules_location); + if (!(f = fopen(pcitable_filename, "rb"))) { + log_message("third_party: no external pcitable found"); + return; + } + while (1) { + char buf[200]; + struct pcitable_entry *e; + if (!fgets(buf, sizeof(buf), f)) break; + e = &pcitable[pcitable_len++]; + sscanf(buf, "%hx\t%hx\t\"%[^ \"]\"\t\"%[^ \"]\"", &e->vendor, &e->device, e->module, e->description); + } + fclose(f); +} + + +static int thirdparty_is_detected(char *driver) { + int i, j; + + for (i = 0; i < detected_devices_len ; i++) { + /* first look for the IDs in the third-party pcitable */ + for (j = 0; j < pcitable_len ; j++) { + if (pcitable[j].vendor == detected_devices[i].vendor && + pcitable[j].device == detected_devices[i].device && + !strcmp(pcitable[j].module, driver)) { + log_message("probing: found device for module %s", driver); + return 1; + } + } + /* if not found, compare with the detected driver */ + if (!strcmp(detected_devices[i].module, driver)) { + log_message("probing: found device for module %s", driver); + return 1; + } + } + + return 0; +} + +static enum return_type thirdparty_autoload_modules(const char *modules_location, char ** modules_list, FILE *f, int load_detected_only) { while (1) { char final_name[500]; @@ -230,12 +277,12 @@ static enum return_type thirdparty_autoload_modules(const char *modules_location options++; } - if (load_probed_only && !exists_orphan_device(module)) { + if (load_detected_only && !thirdparty_is_detected(module)) { log_message("third party: no device detected for module %s, skipping", module); continue; } - log_message("third party: auto-loading module (%s) (%s)", module, options); + log_message("third party: auto-loading module (%s) with options (%s)", module, options); while (entry && *entry) { if (!strncmp(*entry, module, strlen(module)) && (*entry)[strlen(module)] == '.') { sprintf(final_name, "%s/%s", modules_location, *entry); @@ -300,6 +347,8 @@ static enum return_type thirdparty_try_directory(char * root_directory, int inte sprintf(list_filename, "%s/to_detect", modules_location); f_detect = fopen(list_filename, "rb"); if (f_detect) { + probing_detect_devices(); + thirdparty_load_pcitable(modules_location); thirdparty_autoload_modules(modules_location, modules_list, f_detect, 1); fclose(f_detect); } |