[patch] miniprobe

Jeff Garzik (jgarzik@pobox.com)
Fri, 01 Oct 1999 04:26:43 -0400


This is a multi-part message in MIME format.
--------------C2379D6AF213F6EC7AF9FC4F
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The attached module probes for a lists of module, where request_module
is called if and only if a PCI device is known to exist.

This is probably of narrow interest/usefulness, but I think it may be
useful for cases where you don't want to build, or run through, a really
big /etc/conf.modules. initrd image builders may find this useful for
example.

Documentation is in a comment at the top of miniprobe.c.

Jeff

-- 
Custom driver development	|    Never worry about theory as long
Open source programming		|    as the machinery does what it's
				|    supposed to do.  -- R. A. Heinlein
--------------C2379D6AF213F6EC7AF9FC4F
Content-Type: text/plain; charset=us-ascii;
 name="miniprobe.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="miniprobe.c"

/* * miniprobe.c - Linux kernel module to call modprobe for list of * discovered devices * Copyright 1999 Jeff Garzik <jgarzik@pobox.com> * * General usage: send one or more commands to /proc/miniprobe * * Sample usage: * * # scans PCI list for the below two devices. * # calls request_module() on given module, * # if device is found * $ echo "pci, 5333, 8811, s3trio" > /proc/miniprobe * $ echo "pci, 1023, 8400, trident" > /proc/miniprobe * $ echo "doit" > /proc/miniprobe * * Available commands: * * pci, {vendor id}, {device id}, {module name} - * Add PCI device to miniprobe list * clear - * Clear miniprobe list * doit - * Probe for each device in list, * calling request_module if the device * is found * * Other stuff: * $ cat /proc/miniprobe # dump miniprobe list * */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/kmod.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/proc_fs.h> #include <asm/uaccess.h>

#define LINE_BUFFER_SIZE 80 #define min(a,b) ( (a) < (b) ? (a) : (b) ) #define max(a,b) ( (a) > (b) ? (a) : (b) )

#define PFX "miniprobe: "

typedef enum { MP_PCI, } mp_ent_type_t;

struct mp_ent; struct mp_ent { mp_ent_type_t ent_type; unsigned long data[2]; char *mod_name; struct mp_ent *next; };

static struct proc_dir_entry *proc_ent = NULL; static struct mp_ent *root = NULL;

static int mp_clear_list (void) { struct mp_ent *tmp; while (root) { tmp = root; root = root->next; kfree (tmp); } return 0; }

static int mp_do_probe (void) { struct mp_ent *tmp; struct pci_dev *pdev; int rc; tmp = root; while (tmp) { switch (tmp->ent_type) { case MP_PCI: pdev = pci_find_device ((unsigned short) tmp->data[0], (unsigned short) tmp->data[1], NULL); if (pdev) { rc = request_module (tmp->mod_name); if (rc) return rc; } break;

default: /* do nothing */ break; } tmp = tmp->next; } return 0; }

static int mp_parse_pci_line (char *line) { char *ven_s=NULL, *dev_s=NULL, *mod_name=NULL; unsigned long vendor, device; struct mp_ent *ent; ven_s = strtok (line, ", "); if (!ven_s) goto err_out; vendor = simple_strtoul (ven_s, NULL, 10) & 0xFFFF; if (!vendor) goto err_out; dev_s = strtok (NULL, ", "); if (!dev_s) goto err_out; device = simple_strtoul (dev_s, NULL, 10) & 0xFFFF; if (!device) goto err_out; mod_name = strtok (NULL, ", "); if (!mod_name || !strlen (mod_name)) goto err_out;

ent = kmalloc (sizeof (struct mp_ent) + strlen (mod_name) + 1, GFP_KERNEL); if (!ent) return -1; ent->ent_type = MP_PCI; ent->data[0] = vendor; ent->data[1] = device; ent->mod_name = ((char *)ent) + sizeof (struct mp_ent); ent->next = NULL; strcpy (ent->mod_name, mod_name); if (!root) root = ent; else { struct mp_ent *tmp; tmp = root; while (tmp->next != NULL) tmp = tmp->next; tmp->next = ent; }

return 0; err_out: printk (KERN_WARNING PFX "invalid PCI line 'pci,%s,%s,%s'\n", ven_s ? ven_s : "", dev_s ? dev_s : "", mod_name ? mod_name : ""); return -1; }

static int mp_parse_line (char *line) { /* ignore blank lines and comments */ if (!*line || *line == '#') return 0; else if (strcmp (line, "doit") == 0) return mp_do_probe ();

else if (strcmp (line, "clear") == 0) return mp_clear_list ();

else if (strncmp (line, "pci,", 4) == 0) return mp_parse_pci_line (line + strlen ("pci,"));

else { printk (KERN_WARNING PFX "invalid line '%s', ignoring\n", line); } return 0; }

/* FIXME long list can overrun proc buffer */ static int mp_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; struct mp_ent *tmp; tmp = root; while (tmp) { switch (tmp->ent_type) { case MP_PCI: len += sprintf (page+len, "pci,%ld,%ld,%s\n", tmp->data[0], tmp->data[1], tmp->mod_name); break; default: /* do nothing */ break; } } return len; }

static int mp_write_proc (struct file *file, const char *buf, unsigned long len, void *data) { static char line_buf[LINE_BUFFER_SIZE] = ""; static size_t line_strlen = 0; size_t copy_size; int rc; char *npos;

if (!suser ()) return -EPERM;

copy_size = min (LINE_BUFFER_SIZE - line_strlen, len) - 1; if (copy_from_user (line_buf + line_strlen, buf, copy_size)) return -EFAULT; line_buf[LINE_BUFFER_SIZE - 1] = 0; line_strlen = strlen (line_buf);

npos = strchr (line_buf, '\n'); if (npos == NULL) { printk (KERN_WARNING PFX "line missing linefeed, ignoring\n"); line_buf[0] = line_strlen = 0; return len; } *npos = 0;

rc = mp_parse_line (line_buf);

npos++; copy_size = strlen (npos); if (copy_size) { memmove (line_buf, npos, copy_size + 1); line_strlen = copy_size; } else { line_buf[0] = line_strlen = 0; }

return rc ? rc : len; }

static int __init mp_init_module (void) { proc_ent = create_proc_entry ("miniprobe", 0, 0); if (!proc_ent) { printk (KERN_ERR PFX "error creating /proc entry, aborting\n"); return -ENODEV; } proc_ent->read_proc = mp_read_proc; proc_ent->write_proc = mp_write_proc;

return 0; }

static void mp_cleanup_module (void) { mp_clear_list (); remove_proc_entry ("miniprobe", NULL); }

int __init init_module (void) { return mp_init_module (); }

void cleanup_module (void) { mp_cleanup_module (); }

--------------C2379D6AF213F6EC7AF9FC4F Content-Type: text/plain; charset=us-ascii; name="miniprobe.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="miniprobe.patch"

Index: drivers/char/Config.in =================================================================== RCS file: /home/cvsgarzik/linux_2_2/drivers/char/Config.in,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.1 diff -u -r1.1.1.3 -r1.1.1.3.2.1 --- Config.in 1999/09/30 22:51:28 1.1.1.3 +++ Config.in 1999/10/01 08:13:52 1.1.1.3.2.1 @@ -60,6 +60,7 @@ bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK fi fi +tristate 'Miniprobe helper' CONFIG_MINIPROBE bool 'Mouse Support (not serial mice)' CONFIG_MOUSE if [ "$CONFIG_MOUSE" = "y" ]; then Index: drivers/char/Makefile =================================================================== RCS file: /home/cvsgarzik/linux_2_2/drivers/char/Makefile,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.2.1 diff -u -r1.1.1.3 -r1.1.1.3.2.1 --- Makefile 1999/09/30 22:51:15 1.1.1.3 +++ Makefile 1999/10/01 08:13:52 1.1.1.3.2.1 @@ -204,6 +204,14 @@ endif endif +ifeq ($(CONFIG_MINIPROBE),y) +L_OBJS += miniprobe.o +else + ifeq ($(CONFIG_MINIPROBE),m) + M_OBJS += miniprobe.o + endif +endif + ifeq ($(CONFIG_PRINTER),y) L_OBJS += lp.o else

--------------C2379D6AF213F6EC7AF9FC4F--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/