summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mdk-stage1/probing.c129
-rw-r--r--mdk-stage1/probing.h14
-rw-r--r--mdk-stage1/thirdparty.c55
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);
}