diff options
Diffstat (limited to 'mdk-stage1/thirdparty.c')
| -rw-r--r-- | mdk-stage1/thirdparty.c | 246 |
1 files changed, 193 insertions, 53 deletions
diff --git a/mdk-stage1/thirdparty.c b/mdk-stage1/thirdparty.c index cd4e6b83c..78bbf485a 100644 --- a/mdk-stage1/thirdparty.c +++ b/mdk-stage1/thirdparty.c @@ -1,8 +1,8 @@ /* - * Guillaume Cottenceau (gc@mandrakesoft.com) - * Olivier Blin (oblin@mandrakesoft.com) + * Guillaume Cottenceau (gc) + * Olivier Blin (oblin) * - * Copyright 2005 Mandrakesoft + * Copyright 2005 Mandriva * * This software may be freely redistributed under the terms of the GNU * public license. @@ -17,22 +17,28 @@ #include <stdio.h> #include <string.h> #include <sys/mount.h> +#include <sys/utsname.h> #include "stage1.h" +#include "tools.h" +#include "utils.h" #include "log.h" -#include "insmod.h" #include "modules.h" #include "mount.h" #include "frontend.h" #include "partition.h" #include "automatic.h" +#include "probing.h" #include "thirdparty.h" #define THIRDPARTY_MOUNT_LOCATION "/tmp/thirdparty" -#define THIRDPARTY_DIRECTORY "/install/thirdparty" -static enum return_type third_party_choose_device(char ** device, int probe_only) +#define N_PCITABLE_ENTRIES 100 +static struct pcitable_entry pcitable[N_PCITABLE_ENTRIES]; +static int pcitable_len = 0; + +static enum return_type thirdparty_choose_device(char ** device, int probe_only) { char ** medias, ** medias_models; char ** ptr, ** ptr_models; @@ -62,7 +68,7 @@ static enum return_type third_party_choose_device(char ** device, int probe_only #endif floppy_dev = floppy_device(); - if (strstr(floppy_dev, "/dev/") == floppy_dev) { + if (floppy_dev && strstr(floppy_dev, "/dev/") == floppy_dev) { floppy_dev = floppy_dev + 5; } if (floppy_dev) @@ -126,15 +132,18 @@ static enum return_type third_party_choose_device(char ** device, int probe_only return results; } - /* a floppy is selected, don't try to list partitions */ - if (streq(*device, floppy_dev)) { + if (floppy_dev && streq(*device, floppy_dev)) { + /* a floppy is selected, don't try to list partitions */ return RETURN_OK; } #ifndef DISABLE_CDROM - /* a cdrom is selected, don't try to list partitions */ - if (device >= cdrom_medias) { - return RETURN_OK; + for (ptr = cdrom_medias; ptr < cdrom_medias + cdrom_count; ptr++) { + if (*device == *ptr) { + /* a cdrom is selected, don't try to list partitions */ + log_message("thirdparty: a cdrom is selected, using it (%s)", *device); + return RETURN_OK; + } } #endif @@ -152,6 +161,7 @@ static enum return_type third_party_choose_device(char ** device, int probe_only /* only one partition has been discovered, don't ask which one to use */ if (parts[1] == NULL) { + log_message("thirdparty: found only one partition on device (%s)", parts[0]); *device = parts[0]; return RETURN_OK; } @@ -210,7 +220,82 @@ 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) +static int pcitable_orderer(const void *a, const void *b) +{ + int ret; + struct pcitable_entry *ap = (struct pcitable_entry *)a; + struct pcitable_entry *bp = (struct pcitable_entry *)b; + + if ((ret = ap->vendor - bp->vendor) != 0) + return ret; + if ((ret = ap->device - bp->device) != 0) + return ret; + if ((ret = ap->subvendor - bp->subvendor) != 0) + return ret; + if ((ret = ap->subdevice - bp->subdevice) != 0) + return ret; + + return 0; +} + + +static void thirdparty_load_pcitable(const char *modules_location) +{ + char pcitable_filename[100]; + FILE * f = NULL; + + snprintf(pcitable_filename, sizeof(pcitable_filename), "%s/pcitable", modules_location); + if (!(f = fopen(pcitable_filename, "rb"))) { + log_message("third_party: no external pcitable found"); + return; + } + pcitable_len = 0; + while (pcitable_len < N_PCITABLE_ENTRIES) { + char buf[200]; + struct pcitable_entry *e; + if (!fgets(buf, sizeof(buf), f)) break; + e = &pcitable[pcitable_len++]; + if (sscanf(buf, "%hx\t%hx\t\"%[^ \"]\"\t\"%[^\"]\"", &e->vendor, &e->device, e->module, e->description) == 4) + e->subvendor = e->subdevice = PCITABLE_MATCH_ALL; + else + sscanf(buf, "%hx\t%hx\t%x\t%x\t\"%[^ \"]\"\t\"%[^\"]\"", &e->vendor, &e->device, &e->subvendor, &e->subdevice, e->module, e->description); + } + fclose(f); + + /* sort pcitable by most specialised entries first */ + qsort(pcitable, pcitable_len, sizeof(pcitable[0]), pcitable_orderer); +} + + +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)) { + const int subvendor = pcitable[j].subvendor; + const int subdevice = pcitable[j].subdevice; + if ((subvendor == PCITABLE_MATCH_ALL && subdevice == PCITABLE_MATCH_ALL) || + (subvendor == detected_devices[i].subvendor && subdevice == detected_devices[i].subdevice)) { + 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,7 +315,12 @@ static enum return_type thirdparty_autoload_modules(const char *modules_location options++; } - log_message("third party: auto-loading module (%s) (%s)", module, options); + 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) 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); @@ -243,38 +333,111 @@ static enum return_type thirdparty_autoload_modules(const char *modules_location entry++; } if (!entry || !*entry) { - enum insmod_return ret = my_insmod(module, ANY_DRIVER_TYPE, options, 0); + enum insmod_return ret = my_modprobe(module, ANY_DRIVER_TYPE, options); if (ret != INSMOD_OK) { log_message("\t%s (marfile): failed", module); stg1_error_message("Insmod %s (marfile) failed.", module); } } } - fclose(f); return RETURN_OK; } +static enum return_type thirdparty_try_directory(char * root_directory, int interactive) { + char modules_location[100]; + char modules_location_release[100]; + char *list_filename; + FILE *f_load, *f_detect; + char **modules_list, **modules_list_release; + struct utsname kernel_uname; + + /* look first in the specific third-party directory */ + snprintf(modules_location, sizeof(modules_location), "%s" THIRDPARTY_DIRECTORY, root_directory); + modules_list = list_directory(modules_location); + + /* if it's empty, look in the root of selected device */ + if (!modules_list || !modules_list[0]) { + modules_location[strlen(root_directory)] = '\0'; + modules_list = list_directory(modules_location); + if (interactive) + add_to_env("THIRDPARTY_DIR", ""); + } else { + if (interactive) + add_to_env("THIRDPARTY_DIR", THIRDPARTY_DIRECTORY); + } + + if (uname(&kernel_uname)) { + log_perror("uname failed"); + return RETURN_ERROR; + } + snprintf(modules_location_release, sizeof(modules_location_release), "%s/%s", modules_location, kernel_uname.release); + modules_list_release = list_directory(modules_location_release); + if (modules_list_release && modules_list_release[0]) { + strcpy(modules_location, modules_location_release); + modules_list = modules_list_release; + } + + log_message("third party: using modules location %s", modules_location); + + if (!modules_list || !*modules_list) { + log_message("third party: no modules found"); + if (interactive) + stg1_error_message("No modules found on selected device."); + return RETURN_ERROR; + } + + list_filename = alloca(strlen(modules_location) + 10 /* max: "/to_detect" */ + 1); + + sprintf(list_filename, "%s/to_load", modules_location); + f_load = fopen(list_filename, "rb"); + if (f_load) { + thirdparty_autoload_modules(modules_location, modules_list, f_load, 0); + fclose(f_load); + } + + 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); + } + + if (f_load || f_detect) + return RETURN_OK; + else if (interactive) { + if (IS_AUTOMATIC) + stg1_error_message("I can't find a \"to_load\" file. Please select the modules manually."); + log_message("third party: no \"to_load\" file, prompting for modules"); + return thirdparty_prompt_modules(modules_location, modules_list); + } else { + return RETURN_OK; + } +} + +void thirdparty_load_media_modules(void) +{ + thirdparty_try_directory(IMAGE_LOCATION, 0); +} void thirdparty_load_modules(void) { enum return_type results; - char * device, * modules_location; - char ** modules_list; - char toload_name[500]; - FILE * f; + char * device; device = NULL; if (IS_AUTOMATIC) { device = get_auto_value("thirdparty"); - third_party_choose_device(NULL, 1); /* probe only to create devices */ + thirdparty_choose_device(NULL, 1); /* probe only to create devices */ log_message("third party: trying automatic device %s", device); if (thirdparty_mount_device(device) != RETURN_OK) device = NULL; } while (!device || streq(device, "")) { - results = third_party_choose_device(&device, 0); + results = thirdparty_choose_device(&device, 0); if (results == RETURN_BACK) return; if (thirdparty_mount_device(device) != RETURN_OK) @@ -282,39 +445,16 @@ void thirdparty_load_modules(void) } log_message("third party: using device %s", device); + add_to_env("THIRDPARTY_DEVICE", device); - /* look first in the specific third-party directory */ - modules_location = THIRDPARTY_MOUNT_LOCATION THIRDPARTY_DIRECTORY; - modules_list = list_directory(modules_location); - if (!modules_list || !modules_list[0]) { - /* if it's empty, look in the root of selected device */ - modules_location = THIRDPARTY_MOUNT_LOCATION; - modules_list = list_directory(modules_location); - } - - log_message("third party: using modules location %s", modules_location); - - if (!modules_list || !*modules_list) { - log_message("third party: no modules found"); - stg1_error_message("No modules found on selected device."); - umount(THIRDPARTY_MOUNT_LOCATION); - return thirdparty_load_modules(); - } - - sprintf(toload_name, "%s/to_load", modules_location); - f = fopen(toload_name, "rb"); - if (f) { - results = thirdparty_autoload_modules(modules_location, modules_list, f); - } else { - if (IS_AUTOMATIC) - stg1_error_message("I can't find a \"to_load\" file. Please select the modules manually."); - log_message("third party: no \"to_load\" file, prompting for modules"); - results = thirdparty_prompt_modules(modules_location, modules_list); - } + results = thirdparty_try_directory(THIRDPARTY_MOUNT_LOCATION, 1); umount(THIRDPARTY_MOUNT_LOCATION); - if (results == RETURN_OK) - return; - else + if (results != RETURN_OK) return thirdparty_load_modules(); } + +void thirdparty_destroy(void) +{ + probing_destroy(); +} |
