diff -u usbutils-0.7/configure usbutils/configure --- usbutils-0.7/configure Fri Nov 3 08:51:23 2000 +++ usbutils/configure Mon Feb 5 14:01:30 2001 @@ -781,7 +781,7 @@ PACKAGE=usbutils -VERSION=0.7 +VERSION=0.7hotplug if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } diff -u usbutils-0.7/usbmodules.8 usbutils/usbmodules.8 --- usbutils-0.7/usbmodules.8 Fri Nov 3 07:30:51 2000 +++ usbutils/usbmodules.8 Mon Feb 5 13:59:06 2001 @@ -1,19 +1,24 @@ -.TH usbmodules 8 "03 November 2000" "usbutils-0.6" "Linux USB Utilities" +.TH usbmodules 8 "05 February 2001" "usbutils-0.7hotplug" "Linux USB Utilities" .IX usbmodules .SH NAME -usbmodules \- List kernel driver modules available for all currently plugged -in USB devices +usbmodules \- List kernel driver modules available for a plugged +in USB device .SH SYNOPSIS .B usbmodules -.RB [ --device /proc/bus/bus/NNN/NNN ] -.RB [ --check modulename ] +.RB [ "--device " /proc/bus/bus/NNN/NNN ] +.RB [ "--check " modulename ] .RB [ --help ] +.RB [ "--mapfile " pathname ] +.RB [ "--version " pathname ] .SH DESCRIPTION .B usbmodules -lists all driver modules for all currently plugged in USB devices. -.B usbmodules -should be run at by /sbin/hotplug of /etc/usb/policy, and whenever -a USB device is "hot plugged" into the system. This can be done by +lists driver modules that may be +able to manage interfaces on +currently plugged in USB devices. +.B usbmodules +may be used by /sbin/hotplug or one of its agents (normally +.IR /etc/hotplug/usb.agent ) +when USB devices are "hot plugged" into the system. This can be done by the following Bourne shell syntax: .IP for module in $(usbmodules --device $DEVICE) ; do @@ -22,7 +27,11 @@ .IP done .PP -The DEVICE environment variable is passed from the kernel to /sbin/hotplug. +The DEVICE environment variable is passed from the kernel to /sbin/hotplug +during USB hotplugging if the kernel was configured using +.I usbdevfs. +.B usbmodules +currently requires usbdevfs to operate. .PP When a USB device is removed from the system, the Linux kernel will decrement a usage count on USB driver module. If this count drops @@ -33,38 +42,52 @@ .PP .SH OPTIONS .TP -.B --check modulename +.BI "--check " modulename Instead of listing the relevant modules, just exit with code 0 (success) if the given module's exported USB ID patterns matches. Otherwise, return failure. .B usbmodules emits no output either way. .TP -.B --device /proc/bus/usb/NNN/NNN +.BI "--device " /proc/bus/usb/MMM/NNN Selects which device .B usbmodules will examine. The argument is currently mandatory. .TP .B --help, -h Print a help message -.SH FILES .TP +.BI "--mapfile " /etc/hotplug/usb.handmap +Use the specified file instead of the +/lib/modules/.../modules.usbmap file +corresponding to the running kernel. +.TP +.B --version +Identifies the version of +.I usbutils +this tool was built with. .SH FILES +.TP .B /lib/modules//modules.usbmap This file is automatically generated by .B depmod, -and used by +versions 2.4.2 and later, and is used by .B usbmodules to determine which modules correspond to which USB ID's. .TP .B /proc/bus/usb -An interface to USB bus configuration space provided by the post-2.1.82 Linux -kernels. Contains per-bus subdirectories with per-card config space files and a +An optional interface to USB devices provided by Linux kernels with +versions of the 2.4 USB support. Contains per-bus subdirectories +with per-device files (offering a usermode driver API as well +as access to device and configuration descriptors), a .I devices -file containing a list of all USB devices. +file containing a list of all USB devices, and a +.I drivers +file listing USB device drivers known to the USB subsystem. .SH SEE ALSO -.BR lsusb (8) +.BR lsusb (8), +.I http://linux-hotplug.sourceforge.net .SH AUTHOR .B usbmodules @@ -73,6 +96,8 @@ .B lsusb, which was written by Thomas Sailer . + +.\" Code and documentation updated by David Brownell. .SH COPYRIGHT diff -u usbutils-0.7/usbmodules.c usbutils/usbmodules.c --- usbutils-0.7/usbmodules.c Fri Nov 3 07:30:52 2000 +++ usbutils/usbmodules.c Mon Feb 5 13:04:05 2001 @@ -3,13 +3,17 @@ /* * usmodules.c -- pcimodules like utility for the USB bus * - * Written by primarily by Adam J. Richter. lspci.c is derived from: - * lsusb.c, written by Thomas Sailer, and pcimodules.c, which is - * also written by Adam J. Richter. usbmodules.h is derived from - * linux-2.4.0-test10/include/linux/usb.h (exact authorship unknown, - * probably Randy Dunlap). + * lsusb.c is derived from: * - * Copyright (C) 2000 Yggdrasil Computing, Inc. + * lspci.c by Thomas Sailer, + * pcimodules.c by Adam J. Richter + * linux-2.4.0-test10/include/linux/usb.h probably by Randy Dunlap + * + * The code in usbmodules not derived from elsewhere was written by + * Adam J. Richter. David Brownell added the --mapfile and --version + * options. + * + * Copyright (C) 2000, 2001 Yggdrasil Computing, Inc. * Copyright (C) 1999 Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify @@ -68,12 +72,14 @@ #define _GNU_SOURCE #include -#define OPT_STRING "c:d:h" +#define OPT_STRING "c:d:hm:v" static struct option long_options[] = { {"check", required_argument, NULL, 'c'}, - {"device", required_argument, NULL, 'd'}, + {"device", required_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, - { 0, 0, NULL, 0} + {"mapfile", required_argument, NULL, 'm'}, + {"version", no_argument, NULL, 'v'}, + { 0, 0, NULL, 0} }; #define MODDIR "/lib/modules" @@ -92,8 +98,6 @@ static char *checkname = NULL; -static const char *procbususb = "/proc/bus/usb"; - static int idVendor; static int idProduct; static int bcdDevice; @@ -109,27 +113,103 @@ fprintf(stderr, "Memory allocation failure.\n"); exit(1); } + return result; +} + +static int +scan_without_flags(const char *line, struct usbmap_entry *entry, char *name) { + unsigned int driver_info; + if (sscanf(line, + "%s 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + name, + &entry->idVendor, + &entry->idProduct, + &entry->bcdDevice_lo, + &entry->bcdDevice_hi, + &entry->bDeviceClass, + &entry->bDeviceSubClass, + &entry->bDeviceProtocol, + &entry->bInterfaceClass, + &entry->bInterfaceSubClass, + &entry->bInterfaceProtocol, + &driver_info) != 12) + return 0; + + entry->match_flags = 0; + + /* idVendor==0 is the wildcard for both idVendor and idProduct, + because idProduct==0 is a legitimate product ID. */ + if (entry->idVendor) + entry->match_flags |= USB_MATCH_VENDOR | USB_MATCH_PRODUCT; + + if (entry->bcdDevice_lo) + entry->match_flags |= USB_MATCH_DEV_LO; + + if (entry->bcdDevice_hi) + entry->match_flags |= USB_MATCH_DEV_HI; + + if (entry->bDeviceClass) + entry->match_flags |= USB_MATCH_DEV_CLASS; + + if (entry->bDeviceSubClass) + entry->match_flags |= USB_MATCH_DEV_SUBCLASS; + + if (entry->bDeviceProtocol) + entry->match_flags |= USB_MATCH_DEV_PROTOCOL; + + if (entry->bInterfaceClass) + entry->match_flags |= USB_MATCH_INT_CLASS; + + if (entry->bInterfaceSubClass) + entry->match_flags |= USB_MATCH_INT_SUBCLASS; + + if (entry->bInterfaceProtocol) + entry->match_flags |= USB_MATCH_INT_PROTOCOL; + + return 1; +} + +static int +scan_with_flags(const char *line, struct usbmap_entry *entry, char *name) { + unsigned int driver_info; + return (sscanf(line, "%s 0x%x 0x%x " + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + name, + &entry->match_flags, + &entry->idVendor, + &entry->idProduct, + &entry->bcdDevice_lo, + &entry->bcdDevice_hi, + &entry->bDeviceClass, + &entry->bDeviceSubClass, + &entry->bDeviceProtocol, + &entry->bInterfaceClass, + &entry->bInterfaceSubClass, + &entry->bInterfaceProtocol, + &driver_info) == 13); } void -read_modules_usbmap(void) +read_modules_usbmap(char *pathname) { - struct utsname utsname; char filename[MAXPATHLEN]; FILE *usbmap_file; char line[LINELENGTH]; struct usbmap_entry *prev; struct usbmap_entry *entry; - unsigned int driver_data; char name[LINELENGTH]; - if (uname(&utsname) < 0) { - perror("uname"); - exit(1); + if (pathname == NULL) { + struct utsname utsname; + if (uname(&utsname) < 0) { + perror("uname"); + exit(1); + } + sprintf(filename, "%s/%s/%s", MODDIR, utsname.release, USBMAP); + pathname = filename; } - sprintf(filename, "%s/%s/%s", MODDIR, utsname.release, USBMAP); - if ((usbmap_file = fopen(filename, "r")) == NULL) { - perror(filename); + if ((usbmap_file = fopen(pathname, "r")) == NULL) { + perror(pathname); exit(1); } @@ -140,18 +220,8 @@ entry = xmalloc(sizeof(struct usbmap_entry)); - if (sscanf(line, "%s 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", - name, - &entry->idVendor, - &entry->idProduct, - &entry->bcdDevice_lo, - &entry->bcdDevice_hi, - &entry->bDeviceClass, - &entry->bDeviceSubClass, - &entry->bDeviceProtocol, - &entry->bInterfaceClass, - &entry->bInterfaceSubClass, - &entry->bInterfaceProtocol) != 10) { + if (!scan_with_flags(line, entry, name) && + !scan_without_flags(line, entry, name)) { fprintf (stderr, "modules.usbmap unparsable line: %s.\n", line); free(entry); @@ -195,45 +265,44 @@ for (mod = usbmap_list; mod != NULL; mod = mod->next) { - if (mod->idVendor && + if ((mod->match_flags & USB_MATCH_VENDOR) && mod->idVendor != idVendor) continue; - if (mod->idProduct && + if ((mod->match_flags & USB_MATCH_PRODUCT) && mod->idProduct != idProduct) continue; - /* No need to test mod->bcdDevice_lo != 0, since 0 is never - greater than any unsigned number. */ - if (mod->bcdDevice_lo > bcdDevice) + if ((mod->match_flags & USB_MATCH_DEV_LO) && + mod->bcdDevice_lo > bcdDevice) continue; - if (mod->bcdDevice_hi && + if ((mod->match_flags & USB_MATCH_DEV_HI) && mod->bcdDevice_hi < bcdDevice) continue; - if (mod->bDeviceClass && + if ((mod->match_flags & USB_MATCH_DEV_CLASS) && mod->bDeviceClass != bDeviceClass) continue; - if (mod->bDeviceSubClass && - mod->bDeviceSubClass!= bDeviceClass) + if ((mod->match_flags & USB_MATCH_DEV_SUBCLASS) && + mod->bDeviceSubClass != bDeviceSubClass) continue; - if (mod->bDeviceProtocol && + if ((mod->match_flags & USB_MATCH_DEV_PROTOCOL) && mod->bDeviceProtocol != bDeviceProtocol) continue; - if (mod->bInterfaceClass - && mod->bInterfaceClass != bInterfaceClass) + if ((mod->match_flags & USB_MATCH_INT_CLASS) && + mod->bInterfaceClass != bInterfaceClass) continue; - if (mod->bInterfaceSubClass && + if ((mod->match_flags & USB_MATCH_INT_SUBCLASS) && mod->bInterfaceSubClass != bInterfaceSubClass) continue; - if (mod->bInterfaceProtocol - && mod->bInterfaceProtocol != bInterfaceProtocol) + if ((mod->match_flags & USB_MATCH_INT_PROTOCOL) && + mod->bInterfaceProtocol != bInterfaceProtocol) continue; if (checkname != NULL) { @@ -286,9 +355,6 @@ { unsigned char buf[1024], *p; unsigned int sz; - int bInterfaceClass; - int bInterfaceSubClass; - int bInterfaceProtocol; if (usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_CONFIG << 8) | nr, @@ -327,8 +393,6 @@ static void process_device(const char *path) { unsigned char buf[USB_DT_DEVICE_SIZE]; - unsigned int vid, pid; - char vendor[128], product[128]; int fd; unsigned int i, maxcfg; @@ -367,6 +431,7 @@ int opt_index = 0; int opt; char *device = NULL; + char *pathname = NULL; while ((opt = getopt_long(argc, argv, OPT_STRING, long_options, &opt_index)) != -1) { @@ -378,10 +443,17 @@ device = optarg; break; case 'h': - printf ("Usage: usbmodules [--help] [--device //proc/bus/usb/NNN/NNN] [--check module]\n" + printf ("Usage: usbmodules [--help] [--device /proc/bus/usb/NNN/NNN] [--check module]\n" + "\t[--mapfile pathname] [--version]\n" " Lists kernel modules corresponding to USB devices currently plugged\n" " into the computer.\n"); return 0; + case 'm': + pathname = optarg; + break; + case 'v': + puts (VERSION); + return 0; default: fprintf(stderr, "Unknown argument character \"%c\".\n", @@ -396,7 +468,7 @@ "\tusbmodules --device /proc/bus/usb/001/009\n"); return 1; } - read_modules_usbmap(); + read_modules_usbmap(pathname); process_device(device); if (checkname != NULL) diff -u usbutils-0.7/usbmodules.h usbutils/usbmodules.h --- usbutils-0.7/usbmodules.h Fri Nov 3 06:00:32 2000 +++ usbutils/usbmodules.h Mon Feb 5 12:54:16 2001 @@ -1,7 +1,19 @@ /* Declaring the usb_device_id fields as unsigned int simplifies the sscanf call. */ +#define USB_MATCH_VENDOR 0x0001 +#define USB_MATCH_PRODUCT 0x0002 +#define USB_MATCH_DEV_LO 0x0004 +#define USB_MATCH_DEV_HI 0x0008 +#define USB_MATCH_DEV_CLASS 0x0010 +#define USB_MATCH_DEV_SUBCLASS 0x0020 +#define USB_MATCH_DEV_PROTOCOL 0x0040 +#define USB_MATCH_INT_CLASS 0x0080 +#define USB_MATCH_INT_SUBCLASS 0x0100 +#define USB_MATCH_INT_PROTOCOL 0x0200 + struct usbmap_entry { + unsigned int match_flags; /* * vendor/product codes are checked, if vendor is nonzero * Range is for device revision (bcdDevice), inclusive;