--- linux/drivers/usb-pre3/usb.c Sun Nov 12 07:52:36 2000 +++ linux/drivers/usb/usb.c Sun Nov 12 10:55:16 2000 @@ -635,6 +635,9 @@ break; } } + /* if driver not bound, leave defaults unchanged */ + if (private == NULL) + interface->act_altsetting = 0; } else /* "old style" driver */ private = driver->probe(dev, ifnum, NULL); @@ -650,58 +653,15 @@ } -#if defined(CONFIG_KMOD) +#ifdef CONFIG_HOTPLUG /* * USB hotplugging invokes what /proc/sys/kernel/hotplug says * (normally /sbin/hotplug) when USB devices get added or removed. - */ - -static int to_bcd (char *buf, __u16 *bcdValue) -{ - int retval = 0; - char *value = (char *) bcdValue; - int temp; - - /* digits are 0-9 then ":;<=>?" for devices using - * non-bcd (non-standard!) values here ... */ - - /* No leading (or later, trailing) zeroes since scripts do - * literal matches, and that's how they're doing them. */ - if ((temp = value [1] & 0xf0) != 0) { - temp >>= 4; - temp += '0'; - *buf++ = (char) temp; - retval++; - } - - temp = value [1] & 0x0f; - temp += '0'; - *buf++ = (char) temp; - retval++; - - *buf++ = '.'; - retval++; - - temp = value [0] & 0xf0; - temp >>= 4; - temp += '0'; - *buf++ = (char) temp; - retval++; - - if ((temp = value [0] & 0x0f) != 0) { - temp += '0'; - *buf++ = (char) temp; - retval++; - } - *buf++ = 0; - - return retval; -} - -/* + * * This invokes a user mode policy agent, typically helping to load driver - * or other modules, configure the device, or both. + * or other modules, configure the device, and more. Drivers can provide + * a MODULE_DEVICE_TABLE to help with module loading subtasks. * * Some synchronization is important: removes can't start processing * before the add-device processing completes, and vice versa. That keeps @@ -772,9 +732,7 @@ * all the device descriptors we don't tell them about. Or * even act as usermode drivers. * - * XXX how little intelligence can we hardwire? - * (a) mount point: /devfs, /dev, /proc/bus/usb etc. - * (b) naming convention: bus1/device3, 001/003 etc. + * FIXME reduce hardwired intelligence here */ envp [i++] = "DEVFS=/proc/bus/usb"; envp [i++] = scratch; @@ -782,14 +740,14 @@ dev->bus->busnum, dev->devnum) + 1; #endif - /* per-device configuration hacks are often necessary */ + /* per-device configuration hacks are common */ envp [i++] = scratch; - scratch += sprintf (scratch, "PRODUCT=%x/%x/", + scratch += sprintf (scratch, "PRODUCT=%x/%x/%x", dev->descriptor.idVendor, - dev->descriptor.idProduct); - scratch += to_bcd (scratch, &dev->descriptor.bcdDevice) + 1; + dev->descriptor.idProduct, + dev->descriptor.bcdDevice) + 1; - /* otherwise, use a simple (so far) generic driver binding model */ + /* class-based driver binding models */ envp [i++] = scratch; scratch += sprintf (scratch, "TYPE=%d/%d/%d", dev->descriptor.bDeviceClass, @@ -798,17 +756,18 @@ if (dev->descriptor.bDeviceClass == 0) { int alt = dev->actconfig->interface [0].act_altsetting; - /* simple/common case: one config, one interface, one driver - * unsimple cases: everything else + /* a simple/common case: one config, one interface, one driver + * with current altsetting being a reasonable setting. + * everything needs a smart agent and usbdevfs; or can rely on + * device-specific binding policies. */ + envp [i++] = scratch; scratch += sprintf (scratch, "INTERFACE=%d/%d/%d", dev->actconfig->interface [0].altsetting [alt].bInterfaceClass, dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass, dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol) + 1; /* INTERFACE-0, INTERFACE-1, ... ? */ - } else { - /* simple/common case: generic device, handled generically */ } envp [i++] = 0; /* assert: (scratch - buf) < sizeof buf */ --- linux/Documentation.pre3/usb/hotplug.txt Sun Nov 12 10:53:27 2000 +++ linux/Documentation/usb/hotplug.txt Sun Nov 12 10:51:28 2000 @@ -0,0 +1,124 @@ +USB HOTPLUGGING + +In hotpluggable busses like USB (and Cardbus PCI), end-users plug devices +into the bus with power on. In most cases, users expect the devices to become +immediately usable. That means the system must do many things, including: + + - Find a driver that can handle the device. That may involve + loading a kernel module; newer drivers can use modutils to + publish their device (and class) support to user utilities. + + - Bind a driver to that device. That's done using the USB + device driver's probe() routine. + + - Tell other subsystems to configure the new device. Print + queues may need to be enabled, networks brought up, disk + partitions mounted, and so on. In some cases these will + be driver-specific actions. + +This involves a mix of kernel mode and user mode actions. Making devices +be immediately usable means that any user mode actions can't wait for an +administrator to do them: the kernel must trigger them, either passively +(triggering some monitoring daemon to invoke a helper program) or +actively (calling such a user mode helper program directly). + +Those triggered actions must support a system's administrative policies; +such programs are called "policy agents" here. Typically they involve +shell scripts that dispatch to more familiar administration tools. + + +KERNEL HOTPLUG HELPER (/sbin/hotplug) + +When you compile with CONFIG_HOTPLUG, you get a new kernel parameter: +/proc/sys/kernel/hotplug, which normally holds the pathname "/sbin/hotplug". +That parameter names a program which the kernel may invoke at various times. + +The /sbin/hotplug program can be invoked by any subsystem as part of its +reaction to a configuration change, from a thread in that subsystem. +Only one parameter is required: the name of a subsystem being notified of +some kernel event. That name is used as the first key for further event +dispatch; any other argument and environment parameters are specified by +the subsystem making that invocation. + +A reference implementation of a /sbin/hotplug script is available at the +http://www.linux-usb.org website, which works USB for but also knows how to +delegate to any /etc/hotplug/$TYPE.agent policy agent present. + + +USB POLICY AGENT + +The USB subsystem currently invokes /sbin/hotplug when USB devices +are added or removed from system. The invocation is done by the kernel +hub daemon thread [khubd], or else as part of root hub initialization +(done by init, modprobe, kapmd, etc). Its single command line parameter +is the string "usb", and it passes these environment variables: + + ACTION ... "add", "remove" + PRODUCT ... USB vendor, product, and version codes (hex) + TYPE ... device class codes (decimal) + INTERFACE ... interface 0 class codes (decimal) + +If "usbdevfs" is configured, DEVICE and DEVFS are also passed. DEVICE is +the pathname of the device, and is useful for devices with multiple and/or +alternate interfaces that complicate driver selection. + +Currently available policy agent implementations can load drivers for +modules, and can invoke driver-specific setup scripts. The newest ones +leverage USB modutils support. Later agents might unload drivers. + + +USB MODUTILS SUPPORT + +Current versions of modutils will create a "modules.usbmap" file which +contains the entries from each driver's MODULE_DEVICE_TABLE. Such files +can be used by various user mode policy agents to make sure all the right +driver modules get loaded, either at boot time or later. + +See for full information about such table entries; or look +at existing drivers. Each table entry describes one or more criteria to +be used when matching a driver to a device or class of devices. + +A short example, for a driver that supports several specific USB devices +and their quirks, might have a MODULE_DEVICE_TABLE like this: + + static const struct usb_device_id mydriver_id_table = { + { idVendor: 0x9999, idProduct 0xaaaa, driver_info: QUIRK_X }, + { idVendor: 0xbbbb, idProduct 0x8888, driver_info: QUIRK_Y|QUIRK_Z }, + ... + { } /* end with an all-zeroes entry */ + } + MODULE_DEVICE_TABLE (usb, mydriver_id_table); + +Most USB device drivers should pass these tables to the USB subsystem as +well as to the module management subsystem. Not all, though: some driver +frameworks connect using interfaces layered over USB, and so they won't +need such a "struct usb_driver". + +Drivers that connect directly to the USB subsystem should be declared +something like this: + + static struct usb_driver mydriver = { + name: "mydriver", + id_table: mydriver_id_table, + probe: my_probe, + disconnect: my_disconnect, + + /* + if using the usb chardev framework: + minor: MY_USB_MINOR_START, + fops: my_file_ops, + if exposing any operations through usbdevfs: + ioctl: my_ioctl, + */ + } + +When the USB subsystem knows about a driver's device ID table, it's used when +choosing drivers to probe(). The thread doing new device processing checks +drivers' device ID entries from the MODULE_DEVICE_TABLE against interface and +device descriptors for the device. It will only call probe() if there is a +match, and the third argument to probe() will be the entry that matched. + +If you don't provide an id_table for your driver, then your driver may get +probed for each new device; the third parameter to probe() will be null. + +