lkml.org 
[lkml]   [1999]   [Oct]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[patch] miniprobe
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/*
* 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 ();
}
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
\
 
 \ /
  Last update: 2005-03-22 13:54    [W:1.981 / U:0.100 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site