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.c149
1 files changed, 130 insertions, 19 deletions
diff --git a/mdk-stage1/thirdparty.c b/mdk-stage1/thirdparty.c
index 1c8942d3c..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,10 +17,12 @@
#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"
@@ -31,7 +33,10 @@
#include "thirdparty.h"
#define THIRDPARTY_MOUNT_LOCATION "/tmp/thirdparty"
-#define THIRDPARTY_DIRECTORY "/install/thirdparty"
+
+#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)
{
@@ -63,7 +68,7 @@ static enum return_type thirdparty_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)
@@ -127,15 +132,18 @@ static enum return_type thirdparty_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
@@ -153,6 +161,7 @@ static enum return_type thirdparty_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;
}
@@ -211,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, int load_probed_only)
+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];
@@ -231,12 +315,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);
@@ -249,7 +333,7 @@ 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);
@@ -262,19 +346,36 @@ static enum return_type thirdparty_autoload_modules(const char *modules_location
static enum return_type thirdparty_try_directory(char * root_directory, int interactive) {
char modules_location[100];
- char list_filename[50];
+ char modules_location_release[100];
+ char *list_filename;
FILE *f_load, *f_detect;
- char **modules_list;
+ char **modules_list, **modules_list_release;
+ struct utsname kernel_uname;
/* look first in the specific third-party directory */
- strcpy(modules_location, root_directory);
- strcat(modules_location, THIRDPARTY_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);
@@ -286,6 +387,8 @@ static enum return_type thirdparty_try_directory(char * root_directory, int inte
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) {
@@ -296,6 +399,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);
}
@@ -340,6 +445,7 @@ void thirdparty_load_modules(void)
}
log_message("third party: using device %s", device);
+ add_to_env("THIRDPARTY_DEVICE", device);
results = thirdparty_try_directory(THIRDPARTY_MOUNT_LOCATION, 1);
umount(THIRDPARTY_MOUNT_LOCATION);
@@ -347,3 +453,8 @@ void thirdparty_load_modules(void)
if (results != RETURN_OK)
return thirdparty_load_modules();
}
+
+void thirdparty_destroy(void)
+{
+ probing_destroy();
+}