summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/thirdparty.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1/thirdparty.c')
-rw-r--r--mdk-stage1/thirdparty.c246
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();
+}