This is an implementation of the proposed changes I sent an email about
last week.
See http://www.electricrain.com/lists/archive/linux-usb/2000/03/msg00860.html
for the original email and explanation.
There are 2 patches. The first one is for the kernel and it is against
2.3.99-pre4-3. The second patch is for devfsd and is against the 3-FEB-2000
release.
Sorry it took so long, but between changing my mind on how it should be
implemented mid way through, losing many of my changes in a filesystem
corruption incident and other responsibilities, it took longer than
expected.
Kernel changes
==============
These changes should make it into the kernel regardless:
- Reset data toggle on set_interface (9.1.1.5 in USB 1.1 spec)
- Use correct macro for size in memcpy call in usb_parse_configuration
This wasn't fatal since the sizes for the macros were the same, but this
should be fixed for correctness
Changelog for the kernel patch:
- Cache descriptors for those devices which don't work correctly and only
send them once
- Serve cached descriptor dump via read() call on USB device nodes
- Don't mutilate the cached descriptors, so we can serve them to userspace
as we received them from the device
- devfs support (for drivers, devices and per device)
- Add new GETDRIVER, SETDRIVER, DEVICEPROBE, ACTIVATE usbdevfs ioctl()'s
- SETINTERFACE now allows the alternate setting to be changed, if the
interface has not been claimed without claiming the interface first
- Update Virtual Root hub code to support GET_INTERFACE and SET_INTERFACE
(only implemented for uhci.o and it's basically a noop, like SET_CONFIG)
- Remove all probing code from the USB core
- Serialize all connect() and disconnect() calls
- Update these drivers to new probe/connect scheme
hub
acm
usbdevfs
cpia_usb
printer
hid
devfsd changes
==============
- Add new MODULE option to dlopen a shared library and call for connections
- Add USB probing code and driver loading (see the original email for a
description)
Notes
=====
This does not have enough testing to be merged into the kernel yet.
For devfsd to function properly, you need this line in your /etc/devfsd.conf
file:
REGISTER usb/bus.* MODULE /usr/src/devfsd/usb/usb.so
This will call the USB module code for all connections that match usb/bus.*
The devfsd code needs better integration/testing
The devfsd module API I created needs to be thought out correctly so it can
support any event, not just REGISTER's.
Config file support for specifying USB options for devfsd. All of the devices
and classes are hardcoded in a table. The devfsd config file isn't easily
extendable to do what is needed.
The kernel code is relatively well tested, but there are bound to be some
bugs.
I don't think the device_probe callback is serialized. Does it need to be?
JE
diff -ur linux-2.3.99-pre4-3.orig/drivers/char/cpia_usb.c
linux-2.3.99-pre4-3.je/drivers/char/cpia_usb.c
--- linux-2.3.99-pre4-3.orig/drivers/char/cpia_usb.c Tue Apr 4 12:51:46 2000
+++ linux-2.3.99-pre4-3.je/drivers/char/cpia_usb.c Tue Apr 4 14:07:19 2000
@@ -21,6 +21,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/wait.h>
@@ -450,28 +451,50 @@
/* Probing and initializing */
-static void *cpia_probe(struct usb_device *udev, unsigned int ifnum)
+static void cpia_device_probe(struct usb_device *dev);
+static void *cpia_connect(struct usb_device *dev, int ifnum);
+static void cpia_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver cpia_driver = {
+ name: "cpia",
+ device_probe: cpia_device_probe,
+ connect: cpia_connect,
+ disconnect: cpia_disconnect,
+};
+
+static void cpia_device_probe(struct usb_device *dev)
{
struct usb_interface_descriptor *interface;
- struct usb_cpia *ucpia;
- struct cam_data *cam;
- int ret;
+ struct usb_interface *iface;
/* A multi-config CPiA camera? */
- if (udev->descriptor.bNumConfigurations != 1)
- return NULL;
+ if (dev->descriptor.bNumConfigurations != 1)
+ return;
- interface = &udev->actconfig->interface[ifnum].altsetting[0];
+ iface = &dev->actconfig->interface[0];
+ interface = &iface->altsetting[0];
/* Is it a CPiA? */
- if (udev->descriptor.idVendor != 0x0553)
- return NULL;
- if (udev->descriptor.idProduct != 0x0002)
- return NULL;
+ if (dev->descriptor.idVendor != 0x0553)
+ return;
+ if (dev->descriptor.idProduct != 0x0002)
+ return;
/* We found a CPiA */
printk(KERN_INFO "USB CPiA camera found\n");
+ usb_driver_claim_interface(&cpia_driver, iface, NULL);
+}
+
+static void *cpia_connect(struct usb_device *dev, int ifnum)
+{
+ struct usb_interface_descriptor *interface;
+ struct usb_cpia *ucpia;
+ struct cam_data *cam;
+ int ret;
+
+ interface = &dev->actconfig->interface[0].altsetting[0];
+
ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL);
if (!ucpia) {
printk(KERN_ERR "couldn't kmalloc cpia struct\n");
@@ -480,7 +503,7 @@
memset(ucpia, 0, sizeof(*ucpia));
- ucpia->dev = udev;
+ ucpia->dev = dev;
ucpia->iface = interface->bInterfaceNumber;
init_waitqueue_head(&ucpia->wq_stream);
@@ -506,7 +529,7 @@
ucpia->buffers[1]->next = ucpia->buffers[2];
ucpia->buffers[2]->next = ucpia->buffers[0];
- ret = usb_set_interface(udev, ucpia->iface, 0);
+ ret = usb_set_interface(dev, ucpia->iface, 0);
if (ret < 0) {
printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n",
ret);
/* goto fail_all; */
@@ -539,15 +562,6 @@
return NULL;
}
-static void cpia_disconnect(struct usb_device *dev, void *ptr);
-
-static struct usb_driver cpia_driver = {
- "cpia",
- cpia_probe,
- cpia_disconnect,
- { NULL, NULL }
-};
-
/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */
/* will do it for us as well as passing a udev structure - jerdfelt */
@@ -603,13 +617,6 @@
void usb_cpia_cleanup(void)
{
-/*
- struct cam_data *cam;
-
- while ((cam = cam_list) != NULL)
- cpia_disconnect(NULL, cam);
-*/
-
usb_deregister(&cpia_driver);
}
@@ -623,4 +630,5 @@
{
usb_cpia_cleanup();
}
+
#endif /* !MODULE */
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/acm.c
linux-2.3.99-pre4-3.je/drivers/usb/acm.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/acm.c Tue Apr 4 12:51:48 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/acm.c Tue Apr 4 11:39:55 2000
@@ -476,113 +476,107 @@
/*
* USB probe and disconnect routines.
*/
-
-static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
+static void *acm_connect(struct usb_device *dev, unsigned int ifnum)
{
struct acm *acm;
- struct usb_config_descriptor *cfacm;
struct usb_interface_descriptor *ifcom, *ifdata;
struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
- int readsize, ctrlsize, minor, i;
+ int readsize, ctrlsize, minor;
unsigned char *buf;
- if (dev->descriptor.bDeviceClass != 2 || dev->descriptor.bDeviceSubClass != 0
- || dev->descriptor.bDeviceProtocol != 0) return NULL;
-
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-
- cfacm = dev->config + i;
-
- dbg("probing config %d", cfacm->bConfigurationValue);
-
- if (cfacm->bNumInterfaces != 2 ||
- usb_interface_claimed(cfacm->interface + 0) ||
- usb_interface_claimed(cfacm->interface + 1))
- continue;
-
- ifcom = cfacm->interface[0].altsetting + 0;
- ifdata = cfacm->interface[1].altsetting + 0;
-
- if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
- ifcom = cfacm->interface[1].altsetting + 0;
- ifdata = cfacm->interface[0].altsetting + 0;
- if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints !=
2)
- continue;
- }
+ if (dev->descriptor.bDeviceClass != 2 ||
+ dev->descriptor.bDeviceSubClass != 0 ||
+ dev->descriptor.bDeviceProtocol != 0)
+ return NULL;
+
+ if (dev->actconfig->bNumInterfaces != 2 ||
+ usb_interface_claimed(dev->actconfig->interface + 0) ||
+ usb_interface_claimed(dev->actconfig->interface + 1))
+ return NULL;
+
+ ifcom = dev->actconfig->interface[0].altsetting + 0;
+ ifdata = dev->actconfig->interface[1].altsetting + 0;
+
+ if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
+ ifcom = dev->actconfig->interface[1].altsetting + 0;
+ ifdata = dev->actconfig->interface[0].altsetting + 0;
+ if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
+ return NULL;
+ }
- if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
- ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
- continue;
+ if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+ ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
+ return NULL;
+
+ epctrl = ifcom->endpoint + 0;
+ epread = ifdata->endpoint + 0;
+ epwrite = ifdata->endpoint + 1;
+
+ if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) !=
+3 ||
+ (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+ ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) !=
+0x80)
+ return NULL;
+
+ if ((epread->bEndpointAddress & 0x80) != 0x80) {
+ epread = ifdata->endpoint + 1;
+ epwrite = ifdata->endpoint + 0;
+ }
- epctrl = ifcom->endpoint + 0;
- epread = ifdata->endpoint + 0;
- epwrite = ifdata->endpoint + 1;
+ usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
- if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes
& 3) != 3 ||
- (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2
||
- ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress &
0x80)) != 0x80)
- continue;
+ for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++)
+ ;
- if ((epread->bEndpointAddress & 0x80) != 0x80) {
- epread = ifdata->endpoint + 1;
- epwrite = ifdata->endpoint + 0;
- }
+ if (acm_table[minor]) {
+ err("no more free acm devices");
+ return NULL;
+ }
- usb_set_configuration(dev, cfacm->bConfigurationValue);
+ if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+ err("out of memory");
+ return NULL;
+ }
+ memset(acm, 0, sizeof(struct acm));
- for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
- if (acm_table[minor]) {
- err("no more free acm devices");
- return NULL;
- }
+ ctrlsize = epctrl->wMaxPacketSize;
+ readsize = epread->wMaxPacketSize;
+ acm->writesize = epwrite->wMaxPacketSize;
+ acm->iface = dev->actconfig->interface;
+ acm->minor = minor;
+ acm->dev = dev;
- if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
- err("out of memory");
- return NULL;
- }
- memset(acm, 0, sizeof(struct acm));
+ acm->tqueue.routine = acm_softint;
+ acm->tqueue.data = acm;
- ctrlsize = epctrl->wMaxPacketSize;
- readsize = epread->wMaxPacketSize;
- acm->writesize = epwrite->wMaxPacketSize;
- acm->iface = cfacm->interface;
- acm->minor = minor;
- acm->dev = dev;
-
- acm->tqueue.routine = acm_softint;
- acm->tqueue.data = acm;
-
- if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize,
GFP_KERNEL))) {
- err("out of memory");
- kfree(acm);
- return NULL;
- }
+ if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+ err("out of memory");
+ kfree(acm);
+ return NULL;
+ }
- FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev,
epctrl->bEndpointAddress),
- buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+ FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
+ buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
- FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev,
epread->bEndpointAddress),
- buf += ctrlsize, readsize, acm_read_bulk, acm);
+ FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev,
+epread->bEndpointAddress),
+ buf += ctrlsize, readsize, acm_read_bulk, acm);
- FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev,
epwrite->bEndpointAddress),
- buf += readsize, acm->writesize, acm_write_bulk, acm);
+ FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev,
+epwrite->bEndpointAddress),
+ buf += readsize, acm->writesize, acm_write_bulk, acm);
- printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+ printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
- acm_set_control(acm, acm->ctrlout);
+ acm_set_control(acm, acm->ctrlout);
- acm->line.speed = cpu_to_le32(9600);
- acm->line.databits = 8;
- acm_set_line(acm, &acm->line);
+ acm->line.speed = cpu_to_le32(9600);
+ acm->line.databits = 8;
+ acm_set_line(acm, &acm->line);
- usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
- usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+ usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+ usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
- tty_register_devfs(&acm_tty_driver, 0, minor);
- return acm_table[minor] = acm;
- }
+ tty_register_devfs(&acm_tty_driver, 0, minor);
- return NULL;
+ return acm_table[minor] = acm;
}
static void acm_disconnect(struct usb_device *dev, void *ptr)
@@ -622,7 +616,7 @@
static struct usb_driver acm_driver = {
name: "acm",
- probe: acm_probe,
+ connect: acm_connect,
disconnect: acm_disconnect
};
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/devio.c
linux-2.3.99-pre4-3.je/drivers/usb/devio.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/devio.c Fri Mar 10 16:18:34 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/devio.c Tue Apr 4 14:08:58 2000
@@ -187,26 +187,58 @@
ssize_t ret = 0;
unsigned len;
loff_t pos;
+ int i;
pos = *ppos;
down_read(&ps->devsem);
- if (!ps->dev)
+ if (!ps->dev) {
ret = -ENODEV;
- else if (pos < 0)
+ goto err;
+ } else if (pos < 0) {
ret = -EINVAL;
- else if (pos < sizeof(struct usb_device_descriptor)) {
+ goto err;
+ }
+
+ if (pos < sizeof(struct usb_device_descriptor)) {
len = sizeof(struct usb_device_descriptor) - pos;
if (len > nbytes)
len = nbytes;
- if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len))
+ if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) {
ret = -EFAULT;
- else {
+ goto err;
+ }
+
+ *ppos += len;
+ buf += len;
+ nbytes -= len;
+ ret += len;
+ }
+
+ pos = sizeof(struct usb_device_descriptor);
+ for (i = 0; nbytes && i < ps->dev->descriptor.bNumConfigurations; i++) {
+ struct usb_config_descriptor *config =
+ (struct usb_config_descriptor *)ps->dev->rawdescriptors[i];
+ unsigned int length = le16_to_cpu(config->wTotalLength);
+
+ if (*ppos < pos + length) {
+ len = length - (*ppos - pos);
+ if (len > nbytes)
+ len = nbytes;
+ if (copy_to_user(buf, ps->dev->rawdescriptors[i] + (*ppos -
+pos), len)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
*ppos += len;
buf += len;
nbytes -= len;
ret += len;
}
+
+ pos += length;
}
+
+err:
up_read(&ps->devsem);
return ret;
}
@@ -363,7 +395,7 @@
* interface claiming
*/
-static void *driver_probe(struct usb_device *dev, unsigned int intf)
+static void *driver_connect(struct usb_device *dev, unsigned int intf)
{
return NULL;
}
@@ -376,12 +408,9 @@
}
struct usb_driver usbdevfs_driver = {
- "usbdevfs",
- driver_probe,
- driver_disconnect,
- LIST_HEAD_INIT(usbdevfs_driver.driver_list),
- NULL,
- 0
+ name: "usbdevfs",
+ connect: driver_connect,
+ disconnect: driver_disconnect,
};
static int claimintf(struct dev_state *ps, unsigned int intf)
@@ -481,6 +510,28 @@
return -ENOENT;
}
+extern struct list_head usb_driver_list;
+
+static int finddriver(struct usb_driver **driver, char *name)
+{
+ struct list_head *tmp;
+
+ tmp = usb_driver_list.next;
+ while (tmp != &usb_driver_list) {
+ struct usb_driver *d = list_entry(tmp, struct usb_driver,
+ driver_list);
+
+ if (!strcmp(d->name, name)) {
+ *driver = d;
+ return 0;
+ }
+
+ tmp = tmp->next;
+ }
+
+ return -EINVAL;
+}
+
/*
* file operations
*/
@@ -497,9 +548,11 @@
*/
lock_kernel();
ret = -ENOENT;
+ /* FIXME: hack --jerdfelt */
if (ITYPE(inode->i_ino) != IDEVICE)
- goto out;
- dev = inode->u.usbdev_i.p.dev;
+ dev = file->private_data;
+ else
+ dev = inode->u.usbdev_i.p.dev;
if (!dev)
goto out;
ret = -ENOMEM;
@@ -662,16 +715,77 @@
return 0;
}
+static int proc_setdriver(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_driver sd;
+ struct usb_driver *driver;
+ int ret;
+
+ copy_from_user_ret(&sd, arg, sizeof(sd), -EFAULT);
+ if ((ret = findintfif(ps->dev, sd.interface)) < 0)
+ return ret;
+ if ((ret = finddriver(&driver, sd.driver)))
+ return ret;
+ if (usb_set_driver(ps->dev, sd.interface, driver))
+ return -EINVAL;
+ return 0;
+}
+
+static int proc_getdriver(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_driver gd;
+ struct usb_interface *interface;
+ int ret;
+
+ copy_from_user_ret(&gd, arg, sizeof(gd), -EFAULT);
+ if ((ret = findintfif(ps->dev, gd.interface)) < 0)
+ return ret;
+ interface = usb_ifnum_to_if(ps->dev, gd.interface);
+ if (!interface)
+ return -EINVAL;
+ if (!interface->driver)
+ return -ENODATA;
+ strcpy(gd.driver, interface->driver->name);
+ copy_to_user_ret(arg, &gd, sizeof(gd), -EFAULT);
+ return 0;
+}
+
+static int proc_deviceprobe(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_deviceprobe dp;
+ struct usb_driver *driver;
+ int ret;
+
+ copy_from_user_ret(&dp, arg, sizeof(dp), -EFAULT);
+ if ((ret = finddriver(&driver, dp.driver)))
+ return ret;
+ if (!driver->device_probe)
+ return -ESRCH;
+ driver->device_probe(ps->dev);
+ return 0;
+}
+
+static int proc_activate(struct dev_state *ps)
+{
+ return usb_device_activate(ps->dev);
+}
+
static int proc_setintf(struct dev_state *ps, void *arg)
{
struct usbdevfs_setinterface setintf;
+ struct usb_interface *interface;
int ret;
copy_from_user_ret(&setintf, arg, sizeof(setintf), -EFAULT);
if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
+ interface = usb_ifnum_to_if(ps->dev, setintf.interface);
+ if (!interface)
+ return -EINVAL;
+ if (interface->driver) {
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ }
if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
return -EINVAL;
return 0;
@@ -942,6 +1056,22 @@
ret = proc_resetep(ps, (void *)arg);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_SETDRIVER:
+ ret = proc_setdriver(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_DEVICEPROBE:
+ ret = proc_deviceprobe(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_ACTIVATE:
+ ret = proc_activate(ps);
+ break;
+
+ case USBDEVFS_GETDRIVER:
+ ret = proc_getdriver(ps, (void *)arg);
break;
case USBDEVFS_SETINTERFACE:
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/hid.c
linux-2.3.99-pre4-3.je/drivers/usb/hid.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/hid.c Sun Mar 19 18:29:40 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/hid.c Fri Mar 31 11:53:31 2000
@@ -1413,7 +1413,7 @@
return hid;
}
-static void* hid_probe(struct usb_device *dev, unsigned int ifnum)
+static void *hid_connect(struct usb_device *dev, unsigned int ifnum)
{
char *hid_name[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
"Gamepad", "Keyboard", "Keypad", "Multi-Axis
Controller"};
@@ -1448,7 +1448,7 @@
static struct usb_driver hid_driver = {
name: "hid",
- probe: hid_probe,
+ connect: hid_connect,
disconnect: hid_disconnect
};
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/hub.c
linux-2.3.99-pre4-3.je/drivers/usb/hub.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/hub.c Tue Apr 4 12:51:48 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/hub.c Tue Apr 4 14:10:00 2000
@@ -197,17 +197,16 @@
return 0;
}
-static void *hub_probe(struct usb_device *dev, unsigned int i)
+static void *hub_connect(struct usb_device *dev, unsigned int i)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_hub *hub;
unsigned long flags;
- unsigned int pipe;
- int maxp, ret;
- interface = &dev->actconfig->interface[i].altsetting[0];
+ interface =
+&dev->actconfig->interface[i].altsetting[dev->actconfig->interface[i].act_altsetting];
+#if 0
/* Is it a hub? */
if (interface->bInterfaceClass != USB_CLASS_HUB)
return NULL;
@@ -221,16 +220,21 @@
/* Multiple endpoints? What kind of mutant ninja-hub is this? */
if (interface->bNumEndpoints != 1)
return NULL;
+#endif
endpoint = &interface->endpoint[0];
/* Output endpoint? Curiousier and curiousier.. */
- if (!(endpoint->bEndpointAddress & USB_DIR_IN))
+ if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {
+ err("invalid endpoint on hub");
return NULL;
+ }
/* If it's not an interrupt endpoint, we'd better punt! */
- if ((endpoint->bmAttributes & 3) != 3)
+ if ((endpoint->bmAttributes & 3) != 3) {
+ err("invalid endpoint type on hub");
return NULL;
+ }
/* We found a hub */
info("USB hub found");
@@ -244,17 +248,18 @@
memset(hub, 0, sizeof(*hub));
INIT_LIST_HEAD(&hub->event_list);
+ INIT_LIST_HEAD(&hub->hub_list);
hub->dev = dev;
/* Record the new hub's existence */
spin_lock_irqsave(&hub_event_lock, flags);
- INIT_LIST_HEAD(&hub->hub_list);
list_add(&hub->hub_list, &hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
if (usb_hub_configure(hub) >= 0) {
- pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
- maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+ unsigned int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+ int ret;
if (maxp > sizeof(hub->buffer))
maxp = sizeof(hub->buffer);
@@ -329,8 +334,9 @@
int tries;
wait_ms(100);
+
/* Check status */
- if (usb_get_port_status(hub, port + 1, &portsts)<0) {
+ if (usb_get_port_status(hub, port + 1, &portsts) < 0) {
err("get_port_status failed");
return;
}
@@ -345,7 +351,7 @@
/* Disconnect any existing devices under this port */
if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
- (!(portstatus & USB_PORT_STAT_ENABLE)))|| (hub->children[port])) {
+ (!(portstatus & USB_PORT_STAT_ENABLE))) || (hub->children[port])) {
usb_disconnect(&hub->children[port]);
/* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION))
@@ -357,12 +363,11 @@
#define MAX_TRIES 5
- for(tries=0;tries<MAX_TRIES;tries++) {
-
+ for (tries = 0; tries < MAX_TRIES; tries++) {
usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
wait_ms(200);
- if (usb_get_port_status(hub, port + 1, &portsts)<0) {
+ if (usb_get_port_status(hub, port + 1, &portsts) < 0) {
err("get_port_status failed");
return;
}
@@ -381,8 +386,8 @@
wait_ms(200);
}
- if (tries==MAX_TRIES) {
- err("Cannot enable port %i after %i retries, disabling port.", port+1,
MAX_TRIES);
+ if (tries == MAX_TRIES) {
+ err("Cannot enable port %i after %i retries, disabling port", port+1,
+MAX_TRIES);
err("Maybe the USB cable is bad?");
return;
}
@@ -507,7 +512,7 @@
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dbg("hub overcurrent change");
- wait_ms(500); //Cool down
+ wait_ms(500); /* Cool down */
usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
usb_hub_power_on(hub);
}
@@ -555,10 +560,9 @@
}
static struct usb_driver hub_driver = {
- "hub",
- hub_probe,
- hub_disconnect,
- { NULL, NULL }
+ name: "hub",
+ connect: hub_connect,
+ disconnect: hub_disconnect,
};
/*
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/inode.c
linux-2.3.99-pre4-3.je/drivers/usb/inode.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/inode.c Sun Mar 12 19:13:06 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/inode.c Fri Mar 31 11:40:01 2000
@@ -37,6 +37,7 @@
#include <linux/locks.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/usb.h>
#include <asm/uaccess.h>
@@ -602,7 +603,12 @@
void usbdevfs_add_bus(struct usb_bus *bus)
{
struct list_head *slist;
+#ifdef CONFIG_DEVFS_FS
+ char bus_path[100];
+ sprintf(bus_path, "usb/bus%d", bus->busnum);
+ bus->devfs_handle = devfs_mk_dir(NULL, bus_path, 0, bus);
+#endif
lock_kernel();
for (slist = superlist.next; slist != &superlist; slist = slist->next)
new_bus_inode(bus, list_entry(slist, struct super_block,
u.usbdevfs_sb.slist));
@@ -612,6 +618,10 @@
void usbdevfs_remove_bus(struct usb_bus *bus)
{
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(bus->devfs_handle);
+ bus->devfs_handle = NULL;
+#endif
lock_kernel();
while (!list_empty(&bus->inodes))
free_inode(list_entry(bus->inodes.next, struct inode,
u.usbdev_i.dlist));
@@ -622,7 +632,14 @@
void usbdevfs_add_device(struct usb_device *dev)
{
struct list_head *slist;
+#ifdef CONFIG_DEVFS_FS
+ char dev_path[100];
+ sprintf(dev_path, "device%d", dev->devnum);
+ dev->devfs_handle = devfs_register(dev->bus->devfs_handle, dev_path,
+ 0, DEVFS_FL_REMOVABLE, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, 0, 0,
+ &usbdevfs_device_file_operations, dev);
+#endif
lock_kernel();
for (slist = superlist.next; slist != &superlist; slist = slist->next)
new_dev_inode(dev, list_entry(slist, struct super_block,
u.usbdevfs_sb.slist));
@@ -635,6 +652,10 @@
struct dev_state *ds;
struct siginfo sinfo;
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(dev->devfs_handle);
+ dev->devfs_handle = NULL;
+#endif
lock_kernel();
while (!list_empty(&dev->inodes))
free_inode(list_entry(dev->inodes.next, struct inode,
u.usbdev_i.dlist));
@@ -663,6 +684,11 @@
static struct proc_dir_entry *usbdir = NULL;
#endif
+#ifdef CONFIG_DEVFS_FS
+static devfs_handle_t devices_devfs_handle = NULL;
+static devfs_handle_t drivers_devfs_handle = NULL;
+#endif
+
int __init usbdevfs_init(void)
{
int ret;
@@ -678,6 +704,14 @@
/* create mount point for usbdevfs */
usbdir = proc_mkdir("usb", proc_bus);
#endif
+#ifdef CONFIG_DEVFS_FS
+ devices_devfs_handle = devfs_register(NULL, "usb/devices", 0,
+ DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, 0, 0,
+ &usbdevfs_devices_fops, NULL);
+ drivers_devfs_handle = devfs_register(NULL, "usb/drivers", 0,
+ DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, 0, 0,
+ &usbdevfs_drivers_fops, NULL);
+#endif
return ret;
}
@@ -688,6 +722,10 @@
#ifdef CONFIG_PROC_FS
if (usbdir)
remove_proc_entry("usb", proc_bus);
+#endif
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(devices_devfs_handle);
+ devfs_unregister(drivers_devfs_handle);
#endif
}
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/printer.c
linux-2.3.99-pre4-3.je/drivers/usb/printer.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/printer.c Fri Mar 10 16:18:34 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/printer.c Fri Mar 31 12:04:17 2000
@@ -302,7 +302,7 @@
return count;
}
-static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usblp_connect(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *epread, *epwrite;
@@ -310,9 +310,7 @@
int minor, i, alts = -1, bidir = 0;
char *buf;
-
for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
-
interface = &dev->actconfig->interface[ifnum].altsetting[i];
if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass
!= 1 ||
@@ -424,7 +422,7 @@
static struct usb_driver usblp_driver = {
name: "usblp",
- probe: usblp_probe,
+ connect: usblp_connect,
disconnect: usblp_disconnect,
fops: &usblp_fops,
minor: USBLP_MINOR_BASE
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/uhci.c
linux-2.3.99-pre4-3.je/drivers/usb/uhci.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/uhci.c Thu Mar 23 14:59:08 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/uhci.c Tue Apr 4 12:48:11 2000
@@ -1636,6 +1636,11 @@
OK(1);
case RH_SET_CONFIGURATION:
OK(0);
+ case RH_GET_INTERFACE | RH_INTERFACE:
+ *(__u8 *)data = 0x00;
+ OK(1);
+ case RH_SET_INTERFACE | RH_INTERFACE:
+ OK(0);
default:
stat = -EPIPE;
}
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/uhci.h
linux-2.3.99-pre4-3.je/drivers/usb/uhci.h
--- linux-2.3.99-pre4-3.orig/drivers/usb/uhci.h Fri Mar 24 13:06:32 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/uhci.h Tue Apr 4 12:47:45 2000
@@ -355,6 +355,7 @@
Virtual Root HUB
------------------------------------------------------------------------- */
/* destination of request */
+#define RH_DEVICE 0x00
#define RH_INTERFACE 0x01
#define RH_ENDPOINT 0x02
#define RH_OTHER 0x03
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/usb.c
linux-2.3.99-pre4-3.je/drivers/usb/usb.c
--- linux-2.3.99-pre4-3.orig/drivers/usb/usb.c Tue Apr 4 12:51:49 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/usb.c Tue Apr 4 14:13:12 2000
@@ -32,13 +32,6 @@
#include <linux/usb.h>
/*
- * Prototypes for the device driver probing/loading functions
- */
-static void usb_find_drivers(struct usb_device *);
-static int usb_find_interface_driver(struct usb_device *, unsigned int);
-static void usb_check_support(struct usb_device *);
-
-/*
* We have a per-interface "registered driver" list.
*/
LIST_HEAD(usb_driver_list);
@@ -48,10 +41,22 @@
static struct usb_driver *usb_minors[16];
-int usb_register(struct usb_driver *new_driver)
+/* We use this to serialize connect and disconnect calls */
+static DECLARE_MUTEX(usb_connect_serialize);
+
+struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
{
- struct list_head *tmp;
+ int i;
+
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+ if (dev->actconfig->interface[i].altsetting[0]. bInterfaceNumber ==
+ifnum)
+ return &dev->actconfig->interface[i];
+ return NULL;
+}
+
+int usb_register(struct usb_driver *new_driver)
+{
if (new_driver->fops != NULL) {
if (usb_minors[new_driver->minor/16]) {
err("error registering %s driver", new_driver->name);
@@ -61,23 +66,10 @@
}
info("registered new driver %s", new_driver->name);
+
/* Add it to the list of known drivers */
list_add(&new_driver->driver_list, &usb_driver_list);
- /*
- * We go through all existing devices, and see if any of them would
- * be acceptable to the new driver.. This is done using a depth-first
- * search for devices without a registered driver already, then
- * running 'probe' with each of the drivers registered on every one
- * of these.
- */
- tmp = usb_bus_list.next;
- while (tmp != &usb_bus_list) {
- struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
-
- tmp = tmp->next;
- usb_check_support(bus->root_hub);
- }
return 0;
}
@@ -104,14 +96,11 @@
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
- if (interface->driver == driver) {
+ if (interface->driver == driver && interface->activated) {
+ down(&usb_connect_serialize);
driver->disconnect(dev, interface->private_data);
+ up(&usb_connect_serialize);
usb_driver_release_interface(driver, interface);
- /*
- * This will go through the list looking for another
- * driver that can handle the device
- */
- usb_find_interface_driver(dev, i);
}
}
}
@@ -291,33 +280,6 @@
}
/*
- * This function is for doing a depth-first search for devices which
- * have support, for dynamic loading of driver modules.
- */
-static void usb_check_support(struct usb_device *dev)
-{
- int i;
-
- if (!dev) {
- err("null device being checked!!!");
- return;
- }
-
- for (i=0; i<USB_MAXCHILDREN; i++)
- if (dev->children[i])
- usb_check_support(dev->children[i]);
-
- if (!dev->actconfig)
- return;
-
- /* now we check this device */
- if (dev->devnum > 0)
- for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
- usb_find_interface_driver(dev, i);
-}
-
-
-/*
* This is intended to be used by usb device drivers that need to
* claim more than one interface on a device at once when probing
* (audio and acm are good examples). No device driver should have
@@ -358,81 +320,47 @@
iface->driver = NULL;
iface->private_data = NULL;
+ iface->activated = 0;
}
-/*
- * This entrypoint gets called for each new device.
- *
- * We now walk the list of registered USB drivers,
- * looking for one that will accept this interface.
- *
- * The probe return value is changed to be a private pointer. This way
- * the drivers don't have to dig around in our structures to set the
- * private pointer if they only need one interface.
- *
- * Returns: 0 if a driver accepted the interface, -1 otherwise
- */
-static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
+int usb_set_driver(struct usb_device *dev, unsigned ifnum, struct usb_driver *driver)
{
- struct list_head *tmp = usb_driver_list.next;
struct usb_interface *interface;
- if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
+ interface = usb_ifnum_to_if(dev, ifnum);
+ if (!interface) {
err("bad find_interface_driver params");
return -1;
}
- interface = dev->actconfig->interface + ifnum;
-
if (usb_interface_claimed(interface))
return -1;
- while (tmp != &usb_driver_list) {
- void *private;
- struct usb_driver *driver = list_entry(tmp, struct usb_driver,
- driver_list);
-
- tmp = tmp->next;
- if (!(private = driver->probe(dev, ifnum)))
- continue;
- usb_driver_claim_interface(driver, interface, private);
+ usb_driver_claim_interface(driver, interface, NULL);
- return 0;
- }
-
- return -1;
+ return 0;
}
-/*
- * This entrypoint gets called for each new device.
- *
- * All interfaces are scanned for matching drivers.
- */
-static void usb_find_drivers(struct usb_device *dev)
+int usb_device_activate(struct usb_device *dev)
{
- unsigned ifnum;
- unsigned rejected = 0;
- unsigned claimed = 0;
-
- for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
- /* if this interface hasn't already been claimed */
- if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) {
- if (usb_find_interface_driver(dev, ifnum))
- rejected++;
- else
- claimed++;
+ int i;
+
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+ struct usb_interface *interface =
+ &dev->actconfig->interface[i];
+
+ if (interface->driver && !interface->activated) {
+ void *ptr;
+
+ down(&usb_connect_serialize);
+ ptr = interface->driver->connect(dev, i);
+ up(&usb_connect_serialize);
+ interface->activated = 1;
+ interface->private_data = ptr;
}
}
-
- if (rejected)
- dbg("unhandled interfaces on device");
- if (!claimed) {
- warn("This device is not recognized by any installed USB driver.");
-#ifdef DEBUG
- usb_show_device(dev);
-#endif
- }
+ return 0;
}
/*
@@ -981,7 +909,7 @@
begin = buffer;
numskipped = 0;
- /* Skip over at Interface class or vendor descriptors */
+ /* Skip over any interface, class or vendor descriptors */
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
@@ -1084,7 +1012,7 @@
int size;
struct usb_descriptor_header *header;
- memcpy(config, buffer, USB_DT_INTERFACE_SIZE);
+ memcpy(config, buffer, USB_DT_CONFIG_SIZE);
le16_to_cpus(&config->wTotalLength);
size = config->wTotalLength;
@@ -1142,6 +1070,13 @@
if (!dev->config)
return;
+ if (dev->rawdescriptors) {
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+ kfree(dev->rawdescriptors[i]);
+
+ kfree(dev->rawdescriptors);
+ }
+
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_config_descriptor *cf = &dev->config[c];
@@ -1283,8 +1218,10 @@
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface =
&dev->actconfig->interface[i];
struct usb_driver *driver = interface->driver;
- if (driver) {
+ if (driver && interface->activated) {
+ down(&usb_connect_serialize);
driver->disconnect(dev, interface->private_data);
+ up(&usb_connect_serialize);
usb_driver_release_interface(driver, interface);
}
}
@@ -1492,15 +1429,10 @@
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
- struct usb_interface *iface = NULL;
- int ret, i;
+ struct usb_interface *iface;
+ int ret;
- for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
- if (dev->actconfig->interface[i].altsetting->bInterfaceNumber ==
interface) {
- iface = &dev->actconfig->interface[i];
- break;
- }
- }
+ iface = usb_ifnum_to_if(dev, interface);
if (!iface) {
warn("selecting invalid interface %d", interface);
return -EINVAL;
@@ -1512,7 +1444,10 @@
return ret;
iface->act_altsetting = alternate;
+ dev->toggle[0] = 0; /* 9.1.1.5 says to do this */
+ dev->toggle[1] = 0;
usb_set_maxpacket(dev);
+
return 0;
}
@@ -1560,11 +1495,10 @@
int usb_get_configuration(struct usb_device *dev)
{
- int result;
- unsigned int cfgno;
+ int result;
+ unsigned int cfgno, length;
unsigned char buffer[8];
unsigned char *bigbuffer;
- unsigned int tmp;
struct usb_config_descriptor *desc =
(struct usb_config_descriptor *)buffer;
@@ -1588,9 +1522,14 @@
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor));
- for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
-
+ dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *
+ dev->descriptor.bNumConfigurations, GFP_KERNEL);
+ if (!dev->rawdescriptors) {
+ err("out of memory");
+ return -1;
+ }
+ for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
@@ -1603,30 +1542,30 @@
}
/* Get the full buffer */
- le16_to_cpus(&desc->wTotalLength);
+ length = le16_to_cpu(desc->wTotalLength);
- bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL);
+ bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) {
err("unable to allocate memory for configuration descriptors");
result=-ENOMEM;
goto err;
}
- tmp=desc->wTotalLength;
+
/* Now that we know the length, get the whole thing */
- result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer,
desc->wTotalLength);
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer,
+length);
if (result < 0) {
err("couldn't get all of config descriptors");
kfree(bigbuffer);
goto err;
}
- if (result < tmp) {
- err("config descriptor too short (expected %i, got
%i)",tmp,result);
+ if (result < length) {
+ err("config descriptor too short (expected %i, got %i)",
+length, result);
kfree(bigbuffer);
goto err;
}
result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
- kfree(bigbuffer);
+ dev->rawdescriptors[cfgno] = bigbuffer;
if (result > 0)
dbg("descriptor data left");
@@ -1803,9 +1742,6 @@
/* now that the basic setup is over, add a /proc/bus/usb entry */
usbdevfs_add_device(dev);
- /* find drivers willing to handle this device */
- usb_find_drivers(dev);
-
return 0;
}
@@ -1859,6 +1795,8 @@
* into the kernel, and other device drivers are built as modules,
* then these symbols need to be exported for the modules to use.
*/
+EXPORT_SYMBOL(usb_ifnum_to_if);
+
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_alloc_bus);
@@ -1872,6 +1810,8 @@
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
+EXPORT_SYMBOL(usb_set_driver);
+EXPORT_SYMBOL(usb_device_activate);
EXPORT_SYMBOL(usb_init_root_hub);
EXPORT_SYMBOL(usb_root_hub_string);
diff -ur linux-2.3.99-pre4-3.orig/drivers/usb/usbdevice_fs.h
linux-2.3.99-pre4-3.je/drivers/usb/usbdevice_fs.h
--- linux-2.3.99-pre4-3.orig/drivers/usb/usbdevice_fs.h Fri Mar 24 13:06:50 2000
+++ linux-2.3.99-pre4-3.je/drivers/usb/usbdevice_fs.h Thu Mar 30 15:36:36 2000
@@ -59,6 +59,17 @@
unsigned int altsetting;
};
+#define USBDEVFS_MAXDRIVERNAME 255
+
+struct usbdevfs_driver {
+ unsigned int interface;
+ char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
+struct usbdevfs_deviceprobe {
+ char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
struct usbdevfs_disconnectsignal {
unsigned int signr;
void *context;
@@ -99,6 +110,10 @@
#define USBDEVFS_RESETEP _IOR('U', 3, unsigned int)
#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface)
#define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
+#define USBDEVFS_DEVICEPROBE _IOR('U', 6, struct usbdevfs_deviceprobe)
+#define USBDEVFS_SETDRIVER _IOR('U', 7, struct usbdevfs_driver)
+#define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_driver)
+#define USBDEVFS_ACTIVATE _IO('U', 9)
#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb)
#define USBDEVFS_DISCARDURB _IO('U', 11)
#define USBDEVFS_REAPURB _IOW('U', 12, void *)
diff -ur linux-2.3.99-pre4-3.orig/include/linux/usb.h
linux-2.3.99-pre4-3.je/include/linux/usb.h
--- linux-2.3.99-pre4-3.orig/include/linux/usb.h Tue Apr 4 12:51:52 2000
+++ linux-2.3.99-pre4-3.je/include/linux/usb.h Tue Apr 4 11:56:41 2000
@@ -128,6 +128,7 @@
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/delay.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/config.h>
#include <linux/list.h>
@@ -306,6 +307,7 @@
int num_altsetting; /* number of alternate settings */
int max_altsetting; /* total memory allocated */
+ int activated; /* have we called _connect() yet? */
struct usb_driver *driver; /* driver */
void *private_data;
};
@@ -336,7 +338,8 @@
struct usb_driver {
const char *name;
- void * (*probe)(struct usb_device *, unsigned int);
+ void (*device_probe)(struct usb_device *);
+ void *(*connect)(struct usb_device *, unsigned int);
void (*disconnect)(struct usb_device *, void *);
struct list_head driver_list;
@@ -363,9 +366,9 @@
*/
typedef int (*usb_device_irq)(int, void *, int, void *);
-/*----------------------------------------------------------------------------*
+/* ---------------------------------------------------------------------------*
* New USB Structures *
- *----------------------------------------------------------------------------*/
+ * ---------------------------------------------------------------------------*/
#define USB_DISABLE_SPD 0x0001
#define USB_ISO_ASAP 0x0002
@@ -529,6 +532,10 @@
/* usbdevfs inode list */
struct list_head inodes;
+
+#ifdef CONFIG_DEVFS_FS
+ devfs_handle_t devfs_handle;
+#endif
};
#define USB_MAXCHILDREN (8) /* This is arbitrary */
@@ -553,6 +560,8 @@
struct usb_device_descriptor descriptor;/* Descriptor */
struct usb_config_descriptor *config; /* All of the configs */
+ char **rawdescriptors; /* Raw descriptors for each config */
+
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
@@ -562,6 +571,8 @@
struct list_head inodes;
struct list_head filelist;
+ devfs_handle_t devfs_handle;
+
/*
* Child devices - these can be either new devices
* (if this is a hub device), or different instances
@@ -574,6 +585,8 @@
struct usb_device *children[USB_MAXCHILDREN];
};
+extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+
extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *);
@@ -581,6 +594,8 @@
extern void usb_driver_claim_interface(struct usb_driver *driver, struct
usb_interface *iface, void* priv);
extern int usb_interface_claimed(struct usb_interface *iface);
extern void usb_driver_release_interface(struct usb_driver *driver, struct
usb_interface *iface);
+extern int usb_set_driver(struct usb_device *dev, unsigned ifnum, struct usb_driver
+*driver);
+extern int usb_device_activate(struct usb_device *dev);
extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
extern void usb_free_bus(struct usb_bus *);
diff -urN devfsd/Makefile devfsd.je/Makefile
--- devfsd/Makefile Wed Feb 2 20:31:16 2000
+++ devfsd.je/Makefile Mon Apr 3 12:40:21 2000
@@ -1,8 +1,12 @@
-BINDIR = /sbin
-CONFIG_FILE = /etc/devfsd.conf
+BINDIR = /sbin
+CONFIG_FILE = /etc/devfsd.conf
-all: devfsd
+SUBDIRS = usb
+all: devfsd
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir; \
+ done
OBJECTS = devfsd.o expression.o
@@ -13,7 +17,7 @@
endif
devfsd: $(OBJECTS)
- cc -O2 -o devfsd $(OBJECTS) $(CFLAGS) -ldl
+ cc -export-dynamic -o devfsd $(OBJECTS) $(CFLAGS) -ldl
install: devfsd
rm -f $(BINDIR)/devfsd
@@ -24,6 +28,6 @@
clean:
-rm -f *~ *.o
-
distclean: clean
-rm -f devfsd
+
diff -urN devfsd/devfsd.c devfsd.je/devfsd.c
--- devfsd/devfsd.c Wed Feb 2 20:50:38 2000
+++ devfsd.je/devfsd.c Mon Apr 3 13:47:46 2000
@@ -178,6 +178,7 @@
#define AC_MKNEWCOMPAT 5
#define AC_RMOLDCOMPAT 6
#define AC_RMNEWCOMPAT 7
+#define AC_MODULE 8
#define MKACTION(what,when) (struct action_type) {what, when}
@@ -204,6 +205,16 @@
unsigned int when;
};
+struct module
+{
+ struct module *next;
+
+ void *handle;
+
+ int (*register_func)();
+ int (*unregister_func)();
+};
+
struct config_entry
{
struct action_type action;
@@ -214,6 +225,7 @@
struct execute_type execute;
}
u;
+ struct module *module;
struct config_entry *next;
};
@@ -262,9 +274,11 @@
/* Private data */
static struct config_entry *first_config = NULL;
static struct config_entry *last_config = NULL;
+static struct module *first_module = NULL;
+static struct module *last_module = NULL;
static const char *mount_point = NULL;
static flag no_syslog = FALSE;
-static flag syslog_is_open = FALSE;
+flag syslog_is_open = FALSE;
static char trace_level = 0;
static flag debug_protocol = FALSE;
static struct initial_symlink_struct
@@ -595,6 +609,43 @@
new->action.what = AC_RMOLDCOMPAT;
else if (strcasecmp (what, "RMNEWCOMPAT") == 0)
new->action.what = AC_RMNEWCOMPAT;
+ else if (strcasecmp (what, "MODULE") == 0) {
+ struct module *module;
+
+ new->action.what = AC_MODULE;
+ if (!p[0]) {
+ SYSLOG (LOG_ERR, "no module specified in config line: \"%s\"\n",
+ line);
+ SYSLOG (LOG_ERR, "exiting\n");
+ exit (1);
+ }
+
+ module = malloc(sizeof *module);
+ if (!module) {
+ SYSLOG (LOG_ERR, "error allocating\n");
+ SYSLOG (LOG_ERR, "exiting\n");
+ exit (1);
+ }
+
+ new->module = module;
+
+ module->handle = dlopen(p[0], RTLD_NOW);
+ if (!module->handle) {
+ SYSLOG (LOG_ERR, "error dlopen()ing %s: %s\n", p[0], dlerror());
+ SYSLOG (LOG_ERR, "exiting\n");
+ exit (1);
+ }
+
+ module->register_func = dlsym(module->handle, "devfs_register");
+ module->unregister_func = dlsym(module->handle, "devfs_unregister");
+
+ if (last_module)
+ last_module->next = module;
+ last_module = module;
+
+ if (!first_module)
+ first_module = module;
+ }
else
{
SYSLOG (LOG_ERR, "bad WHAT in config line: \"%s\"\n", line);
@@ -716,6 +767,12 @@
case AC_RMNEWCOMPAT:
action_compat (info, entry->action.what);
break;
+ case AC_MODULE:
+ if (entry->action.when == DEVFSD_NOTIFY_REGISTERED)
+ entry->module->register_func(info);
+ else
+ entry->module->unregister_func(info);
+ break;
default:
SYSLOG (LOG_ERR, "Unknown action type: %u\n", entry->action.what);
exit (1);
@@ -779,56 +836,62 @@
}
} /* End Function action_permissions */
-static void action_modload (const struct devfsd_notify_struct *info,
- const struct config_entry *entry)
-/* [SUMMARY] Load a module.
- <info> The devfs change.
- <entry> The config file entry.
- [RETURNS] Nothing.
-*/
+int modprobe(char *module)
{
char *argv[4];
- char device[STRING_LENGTH];
- static int (*modprobe) (int argc, char **argv) = NULL;
+ static int (*modprobe_f)(int argc, char **argv) = NULL;
static flag first_time = TRUE;
- if (first_time)
- {
+ if (first_time) {
void *lib;
first_time = FALSE;
- if ( ( lib = dlopen ("/lib/modutils.so", RTLD_NOW) ) != NULL )
- modprobe = dlsym (lib, "modprobe");
+ lib = dlopen("/lib/modutils.so", RTLD_NOW);
+ if (lib)
+ modprobe_f = dlsym(lib, "modprobe");
}
+
argv[0] = "/sbin/modprobe";
argv[1] = "-k";
- argv[2] = device;
+ argv[2] = module;
argv[3] = NULL;
- strcpy (device, "/dev/");
- strcpy (device + 5, info->devname);
- if (modprobe != NULL)
- {
- (*modprobe) (3, argv);
- return;
+
+ if (modprobe_f) {
+ (*modprobe_f)(3, argv);
+ return 0;
}
- switch ( fork () )
- {
- case 0:
- /* Child */
+
+ switch (fork()) {
+ case 0: /* Child */
break;
- case -1:
- /* Error */
- SYSLOG (LOG_ERR, "error forking\t%s\n", ERRSTRING);
- exit (2);
- /*break;*/
- default:
- /* Parent */
- wait (NULL);
- return;
- /*break;*/
+ case -1: /* Error */
+ SYSLOG(LOG_ERR, "error forking %s\n", ERRSTRING);
+ exit(2);
+ default: /* Parent */
+ wait(NULL);
+ return 0;
}
- execvp (argv[0], argv);
- SYSLOG (LOG_ERR, "error execing: \"%s\"\t%s\n", argv[0], ERRSTRING);
+
+ execvp(argv[0], argv);
+ SYSLOG(LOG_ERR, "error execing: \"%s\"\t%s\n", argv[0], ERRSTRING);
+
+ return -1;
+}
+
+static void action_modload (const struct devfsd_notify_struct *info,
+ const struct config_entry *entry)
+/* [SUMMARY] Load a module.
+ <info> The devfs change.
+ <entry> The config file entry.
+ [RETURNS] Nothing.
+*/
+{
+ char device[STRING_LENGTH];
+
+ strcpy (device, "/dev/");
+ strcpy (device + 5, info->devname);
+
+ modprobe(device);
} /* End Function action_modload */
static void action_execute (const struct devfsd_notify_struct *info,
@@ -1361,10 +1424,17 @@
free (entry->u.execute.argv[count]);
}
}
+ else if (entry->action.what == AC_MODULE)
+ {
+ dlclose(entry->module->handle);
+ free(entry->module);
+ }
free (entry);
}
first_config = NULL;
last_config = NULL;
+ first_module = NULL;
+ last_module = NULL;
} /* End Function free_config */
static void do_debug (int fd)
diff -urN devfsd/usb/Makefile devfsd.je/usb/Makefile
--- devfsd/usb/Makefile Wed Dec 31 16:00:00 1969
+++ devfsd.je/usb/Makefile Mon Apr 3 13:02:37 2000
@@ -0,0 +1,24 @@
+BINDIR = /sbin
+CONFIG_FILE = /etc/devfsd.conf
+
+all: usb.so
+
+USB_SO_OBJS = usb.o io.o
+
+ifdef KERNEL_INCLUDES
+CFLAGS = -O2 -I. -I$(KERNEL_INCLUDES) -Wall $(CEXTRAS)
+else
+CFLAGS = -O2 -I. -Wall $(CEXTRAS)
+endif
+
+usb.so: $(USB_SO_OBJS)
+ cc -o usb.so -shared -fPIC $(USB_SO_OBJS)
+
+# install: usb.so
+
+clean:
+ -rm -f *~ *.o
+
+distclean: clean
+ -rm -f usb.so
+
diff -urN devfsd/usb/io.c devfsd.je/usb/io.c
--- devfsd/usb/io.c Wed Dec 31 16:00:00 1969
+++ devfsd.je/usb/io.c Mon Apr 3 13:04:26 2000
@@ -0,0 +1,21 @@
+#include <sys/ioctl.h>
+
+#include "io.h"
+#include "usb.h"
+
+int usb_control_msg(int fd, u_int8_t request, u_int8_t requesttype,
+ u_int16_t value, u_int16_t index, void *data, u_int16_t length)
+{
+ struct usb_ctrltransfer ctrl;
+
+ ctrl.request = request;
+ ctrl.requesttype = requesttype;
+ ctrl.value = value;
+ ctrl.index = index;
+ ctrl.data = data;
+ ctrl.length = length;
+ ctrl.timeout = 1000 * 5;
+
+ return ioctl(fd, USB_CONTROL, (void *)&ctrl);
+}
+
diff -urN devfsd/usb/io.h devfsd.je/usb/io.h
--- devfsd/usb/io.h Wed Dec 31 16:00:00 1969
+++ devfsd.je/usb/io.h Mon Apr 3 13:03:58 2000
@@ -0,0 +1,10 @@
+#ifndef IO_H
+#define IO_H
+
+#include <sys/types.h>
+
+int usb_control_msg(int fd, u_int8_t request, u_int8_t requesttype,
+ u_int16_t value, u_int16_t index, void *data, u_int16_t length);
+
+#endif
+
diff -urN devfsd/usb/usb.c devfsd.je/usb/usb.c
--- devfsd/usb/usb.c Wed Dec 31 16:00:00 1969
+++ devfsd.je/usb/usb.c Tue Apr 4 12:32:43 2000
@@ -0,0 +1,475 @@
+/* usb.c
+
+ USB specific routines for devfsd
+
+ Copyright (C) 2000 Johannes Erdfelt <[EMAIL PROTECTED]>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/devfs_fs.h>
+
+#include "usb.h"
+#include "io.h"
+
+struct devdriver {
+ u_int16_t vendor;
+ u_int16_t product;
+
+ char *driver;
+};
+
+struct devdriver devdrivers[] = {
+ { 0x0553, 0x0002, "cpia" },
+};
+
+int num_device_drivers = sizeof(devdrivers) / sizeof(devdrivers[0]);
+
+#define IF_CLASS 0x01
+#define IF_SUBCLASS 0x02
+#define IF_PROTOCOL 0x04
+
+struct ifdriver {
+ u_int8_t class;
+ u_int8_t subclass;
+ u_int8_t protocol;
+
+ int priority;
+ int flags;
+
+ char *driver;
+};
+
+struct ifdriver ifdrivers[] = {
+ { 0x01, 0x00, 0x00, 50, IF_CLASS, "audio" },
+ { 0x02, 0x00, 0x00, 50, IF_CLASS, "acm" },
+ { 0x03, 0x00, 0x00, 50, IF_CLASS, "hid" },
+/*
+ { 0x03, 0x01, 0x01, 50, IF_CLASS | IF_SUBCLASS | IF_PROTOCOL, "keybdev" },
+ { 0x03, 0x01, 0x02, 50, IF_CLASS | IF_SUBCLASS | IF_PROTOCOL, "mousedev" },
+*/
+ { 0x07, 0x00, 0x00, 50, IF_CLASS, "printer" },
+ { 0x08, 0x00, 0x00, 50, IF_CLASS, "usb-storage" },
+ { 0x09, 0x00, 0x00, 50, IF_CLASS, "hub" },
+};
+
+int num_interface_drivers = sizeof(ifdrivers) / sizeof(ifdrivers[0]);
+
+char *parse_interface(struct usb_interface *iface, char *b, char *end)
+{
+ iface->num_altsetting = 0;
+ iface->altsetting = NULL;
+
+ while (b < end) {
+ struct usb_descriptor_header *header;
+ header = (struct usb_descriptor_header *)b;
+
+ if (header->bDescriptorType == USB_DT_INTERFACE) {
+ struct usb_interface_descriptor *ifd =
+ (struct usb_interface_descriptor *)b;
+ int altifnum = iface->num_altsetting;
+
+ if (iface->num_altsetting && !ifd->bAlternateSetting)
+ return b;
+
+ iface->num_altsetting++;
+ iface->altsetting = realloc(iface->altsetting, iface->num_altsetting *
+ sizeof(*iface->altsetting));
+ memcpy(iface->altsetting + altifnum, b, header->bLength);
+ }
+ b += header->bLength;
+ }
+
+ return b;
+}
+
+extern int modprobe(char *module);
+
+int usb_driver_loaded(char *name)
+{
+ FILE *f;
+ int found = 0;
+
+ f = fopen("/dev/usb/drivers", "r");
+ if (!f) {
+ perror("fopen");
+ return 1;
+ }
+
+ while (!feof(f)) {
+ char buf[USB_MAXDRIVERNAME + 1];
+ char *ret;
+
+ ret = fgets(buf, sizeof(buf), f);
+ if (!ret)
+ continue;
+
+ if (ret < 0) {
+ perror("fgets");
+ return 1;
+ }
+ if (strlen(buf) <= 0)
+ continue;
+
+ if (buf[strlen(buf) - 1] == '\n')
+ buf[strlen(buf) - 1] = 0;
+
+ ret = strchr(buf, ':');
+ if (ret)
+ strcpy(buf, ret + 1);
+
+ while (isspace(buf[0]))
+ strcpy(buf, buf + 1);
+
+ if (!strcmp(buf, name))
+ found = 1;
+ }
+
+ fclose(f);
+
+ return found;
+}
+
+void load_module(char *name)
+{
+ modprobe(name);
+}
+
+int interface_claimed(int fd, struct usb_interface *interface)
+{
+ struct usb_driver gd;
+ int ret;
+
+ /* This is ok since the bInterfaceNumber is the same for all altsettings */
+ gd.interface = interface->altsetting[0].bInterfaceNumber;
+ ret = ioctl(fd, USB_GETDRIVER, (void *)&gd);
+ if (!ret)
+ return 1;
+
+ return 0;
+}
+
+int match_interface(int fd, struct usb_interface *interface, int *altsetting, int
+*devdrv)
+{
+ int *altdrivers;
+ int i, j, selected;
+
+ altdrivers = malloc(interface->num_altsetting * sizeof(*altdrivers));
+ if (!altdrivers) {
+ perror("malloc");
+ return -1;
+ }
+
+ for (i = 0; i < interface->num_altsetting; i++) {
+ struct usb_interface_descriptor *ifd = &interface->altsetting[i];
+
+ altdrivers[i] = -1;
+
+ for (j = 0; j < num_interface_drivers; j++) {
+ struct ifdriver *id = &ifdrivers[j];
+
+ /* Gotta match something */
+ if (!id->flags)
+ continue;
+
+ if (id->flags & (IF_CLASS | IF_SUBCLASS | IF_PROTOCOL) &&
+ id->class == ifd->bInterfaceClass &&
+ id->subclass == ifd->bInterfaceSubClass &&
+ id->protocol == ifd->bInterfaceProtocol) {
+ altdrivers[i] = j;
+ continue;
+ }
+
+ if (id->flags & (IF_CLASS | IF_SUBCLASS) &&
+ id->class == ifd->bInterfaceClass &&
+ id->subclass == ifd->bInterfaceSubClass) {
+ altdrivers[i] = j;
+ continue;
+ }
+
+ if (id->flags & IF_CLASS &&
+ id->class == ifd->bInterfaceClass) {
+ altdrivers[i] = j;
+ continue;
+ }
+ }
+ }
+
+ selected = -1;
+
+ for (i = 0; i < interface->num_altsetting; i++) {
+ if (altdrivers[i] < 0)
+ continue;
+
+ if (selected < 0 ||
+ ifdrivers[altdrivers[i]].priority > ifdrivers[selected].priority)
+ selected = i;
+ }
+
+ if (selected >= 0) {
+ *altsetting = selected;
+ *devdrv = altdrivers[selected];
+
+ free(altdrivers);
+
+ return 0;
+ }
+
+ free(altdrivers);
+
+ return -1;
+}
+
+int usb_set_configuration(int fd, int configuration)
+{
+ int ret;
+
+ fprintf(stderr, "setting configuration %d\n", configuration);
+
+ ret = ioctl(fd, USB_SETCONFIGURATION, &configuration);
+ if (ret < 0) {
+ perror("ioctl(USB_SETCONFIGURATION)");
+ return -1;
+ }
+
+ return 0;
+}
+
+int usb_set_interface(int fd, int interface, int altsetting)
+{
+ struct usb_setinterface si;
+ int ret;
+
+ fprintf(stderr, "setting interface %d to alternate setting %d\n",
+ interface, altsetting);
+
+ si.interface = interface;
+ si.altsetting = altsetting;
+
+ ret = ioctl(fd, USB_SETINTERFACE, (void *)&si);
+ if (ret < 0) {
+ perror("ioctl(USB_SETINTERFACE)");
+ return -1;
+ }
+
+ return 0;
+}
+
+int usb_set_interface_driver(int fd, struct usb_interface *interface, int ifdrv)
+{
+ struct usb_driver sd;
+ int ret;
+
+ fprintf(stderr, "setting driver to %s\n", ifdrivers[ifdrv].driver);
+
+ if (!usb_driver_loaded(ifdrivers[ifdrv].driver))
+ load_module(ifdrivers[ifdrv].driver);
+
+ /* This is ok since all alternate settings have the same bInterfaceNumber */
+ sd.interface = interface->altsetting[0].bInterfaceNumber;
+ strcpy(sd.driver, ifdrivers[ifdrv].driver);
+
+ ret = ioctl(fd, USB_SETDRIVER, (void *)&sd);
+ if (ret < 0) {
+ perror("ioctl(USB_SETDRIVER)");
+ return -1;
+ }
+
+ return 0;
+}
+
+int usb_device_probe(int fd, struct devdriver *dd)
+{
+ struct usb_deviceprobe dp;
+ int ret;
+
+ if (!usb_driver_loaded(dd->driver))
+ load_module(dd->driver);
+
+ strcpy(dp.driver, dd->driver);
+
+ ret = ioctl(fd, USB_DEVICEPROBE, (void *)&dp);
+ if (ret < 0) {
+ perror("ioctl(USB_DEVICEPROBE)");
+ return -1;
+ }
+
+ return 0;
+}
+
+int devfs_register(struct devfsd_notify_struct *info)
+{
+ int fd, ret;
+ int i, j, defcfg, claimedifs, altsetting;
+ unsigned char cfgno;
+ struct usb_device_descriptor device;
+ struct usb_config *configs;
+
+ fd = open(info->devname, O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ ret = read(fd, (void *)&device, sizeof(device));
+ if (ret < 0) {
+ perror("read");
+ return 1;
+ }
+
+ /* First check the device against any of the device probing functions */
+ for (i = 0; i < num_device_drivers; i++) {
+ if ((devdrivers[i].vendor == device.idVendor) &&
+ (devdrivers[i].product == device.idProduct))
+ usb_device_probe(fd, &devdrivers[i]);
+ }
+
+ /* Now read in and parse the configs */
+ configs = malloc(device.bNumConfigurations * sizeof(*configs));
+ if (!configs) {
+ perror("malloc");
+ return 1;
+ }
+
+ for (i = 0; i < device.bNumConfigurations; i++) {
+ char *b, *end;
+
+ ret = read(fd, (void *)&configs[i].desc, sizeof(configs[i].desc));
+ if (ret < 0) {
+ perror("read");
+ return 1;
+ }
+
+ configs[i].buffer = malloc(configs[i].desc.wTotalLength);
+ if (!configs[i].buffer) {
+ perror("malloc");
+ return 1;
+ }
+
+ memcpy((void *)configs[i].buffer, (void *)&configs[i].desc,
+ sizeof(configs[i].desc));
+
+ ret = read(fd, (void *)configs[i].buffer, configs[i].desc.wTotalLength -
+sizeof(configs[i].desc));
+ if (ret < 0) {
+ perror("read");
+ return 1;
+ }
+
+ configs[i].ifaces = malloc(sizeof(configs[i].ifaces[0]) *
+configs[i].desc.bNumInterfaces);
+ if (!configs[i].ifaces) {
+ perror("malloc");
+ return 1;
+ }
+ memset((void *)configs[i].ifaces, 0, sizeof(configs[i].ifaces[0]) *
+configs[i].desc.bNumInterfaces);
+
+ /* Then parse it */
+ b = (char *)configs[i].buffer;
+ end = (char *)configs[i].buffer + (configs[i].desc.wTotalLength -
+sizeof(configs[i].desc));
+ j = 0;
+ while (b < end) {
+ struct usb_descriptor_header *header;
+
+ header = (struct usb_descriptor_header *)b;
+ if (header->bDescriptorType == USB_DT_INTERFACE) {
+ b = parse_interface(&configs[i].ifaces[j], b, end);
+ j++;
+ } else
+ b += header->bLength;
+ }
+ }
+
+ /* Grab the current active configuration for the device */
+ ret = usb_control_msg(fd, USB_REQ_GET_CONFIGURATION, 0x80, 0, 0, &cfgno, 1);
+ if (ret < 0) {
+ /* We'll treat this as a soft error and start with the first config */
+ perror("usb_control_msg");
+
+ cfgno = configs[0].desc.bConfigurationValue;
+ }
+
+ /* Find the config struct for it */
+ for (i = 0; i < device.bNumConfigurations; i++)
+ if (configs[i].desc.bConfigurationValue == cfgno)
+ break;
+
+ if (i >= device.bNumConfigurations) {
+ fprintf(stderr, "unable to locate active configuration\n");
+ return 1;
+ }
+
+ defcfg = i;
+ claimedifs = 0;
+
+ /* Go through the active configuration probing all devices and seeing */
+ /* how many others are already claimed */
+ for (j = 0; j < configs[defcfg].desc.bNumInterfaces; j++) {
+ int selected;
+
+ if (interface_claimed(fd, &configs[defcfg].ifaces[j])) {
+ claimedifs++;
+ continue;
+ }
+
+ ret = match_interface(fd, &configs[defcfg].ifaces[j], &altsetting, &selected);
+ if (!ret) {
+ usb_set_interface(fd, configs[defcfg].ifaces[j].altsetting[0].bInterfaceNumber,
+altsetting);
+ usb_set_interface_driver(fd, &configs[defcfg].ifaces[j], selected);
+ claimedifs++;
+ }
+ }
+
+ for (i = 0; i < device.bNumConfigurations && !claimedifs; i++) {
+ /* Don't do the active configuration twice */
+ if (configs[i].desc.bConfigurationValue == defcfg)
+ continue;
+
+ for (j = 0; j < configs[i].desc.bNumInterfaces; j++) {
+ int selected;
+
+ if (interface_claimed(fd, &configs[i].ifaces[j])) {
+ claimedifs++;
+ continue;
+ }
+
+ ret = match_interface(fd, &configs[i].ifaces[j], &altsetting, &selected);
+ if (!ret) {
+ usb_set_interface(fd, configs[i].ifaces[j].altsetting[0].bInterfaceNumber,
+altsetting);
+ if (!claimedifs) {
+ if (usb_set_configuration(fd, configs[i].desc.bConfigurationValue))
+ return 1;
+ }
+
+ usb_set_interface_driver(fd, &configs[i].ifaces[j], selected);
+ claimedifs++;
+ }
+ }
+ }
+
+ /* Activate the device */
+ ret = ioctl(fd, USB_ACTIVATE);
+ if (ret < 0)
+ perror("ioctl(USB_ACTIVATE)");
+
+ close(fd);
+
+ return 0;
+}
diff -urN devfsd/usb/usb.h devfsd.je/usb/usb.h
--- devfsd/usb/usb.h Wed Dec 31 16:00:00 1969
+++ devfsd.je/usb/usb.h Mon Apr 3 15:15:24 2000
@@ -0,0 +1,120 @@
+#ifndef USB_H
+#define USB_H
+
+#include <sys/types.h>
+
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE 18
+#define USB_DT_CONFIG_SIZE 9
+#define USB_DT_INTERFACE_SIZE 9
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE 7
+#define USB_DT_HID_SIZE 9
+
+#define USB_REQ_GET_CONFIGURATION 0x08
+
+struct usb_descriptor_header {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+};
+
+struct usb_device_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int16_t bcdUSB;
+ u_int8_t bDeviceClass;
+ u_int8_t bDeviceSubClass;
+ u_int8_t bDeviceProtocol;
+ u_int8_t bMaxPacketSize0;
+ u_int16_t idVendor;
+ u_int16_t idProduct;
+ u_int16_t bcdDevice;
+ u_int8_t iManufacturer;
+ u_int8_t iProduct;
+ u_int8_t iSerialNumber;
+ u_int8_t bNumConfigurations;
+} __attribute__ ((packed));
+
+struct usb_config_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int16_t wTotalLength;
+ u_int8_t bNumInterfaces;
+ u_int8_t bConfigurationValue;
+ u_int8_t iConfiguration;
+ u_int8_t bmAttributes;
+ u_int8_t MaxPower;
+} __attribute__ ((packed));
+
+struct usb_config {
+ struct usb_config_descriptor desc;
+
+ char *buffer;
+
+ struct usb_interface *ifaces;
+};
+
+struct usb_interface_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int8_t bInterfaceNumber;
+ u_int8_t bAlternateSetting;
+ u_int8_t bNumEndpoints;
+ u_int8_t bInterfaceClass;
+ u_int8_t bInterfaceSubClass;
+ u_int8_t bInterfaceProtocol;
+ u_int8_t iInterface;
+} __attribute__ ((packed));
+
+struct usb_interface {
+ int num_altsetting;
+
+ struct usb_interface_descriptor *altsetting;
+};
+
+/* usbdevfs stuff */
+struct usb_ctrltransfer {
+ u_int8_t requesttype;
+ u_int8_t request;
+ u_int16_t value;
+ u_int16_t index;
+ u_int16_t length;
+ u_int32_t timeout; /* in milliseconds */
+ void *data;
+};
+
+#define USB_MAXDRIVERNAME 255
+
+struct usb_setinterface {
+ unsigned int interface;
+ unsigned int altsetting;
+};
+
+struct usb_driver {
+ unsigned int interface;
+ char driver[USB_MAXDRIVERNAME + 1];
+};
+
+struct usb_deviceprobe {
+ char driver[USB_MAXDRIVERNAME + 1];
+};
+
+#define USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer)
+#define USB_SETINTERFACE _IOR('U', 4, struct usb_setinterface)
+#define USB_SETCONFIGURATION _IOR('U', 5, unsigned int)
+#define USB_DEVICEPROBE _IOR('U', 6, struct usb_deviceprobe)
+#define USB_SETDRIVER _IOR('U', 7, struct usb_driver)
+#define USB_GETDRIVER _IOW('U', 8, struct usb_driver)
+#define USB_ACTIVATE _IO('U', 9)
+
+#endif
+
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]