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(); +} | 
