These are some minor patches to add a couple of a new features.
They are from my bigger devfs patch but have nothing to do with devfs.
The features
- read() from a device now returns cached descriptors as well
- new GETDRIVER command to see what driver is bound to an interface
the only difference from my previous patch is the lack of activated
field since it doesn't apply without the userspace binding patch
- new CONNECTINFO to get device speed and device id
- serialize all probe() and disconnect() calls to one driver
- set address before grabbing descriptor
The patch is against 2.4.0-test1.
JE
diff -urN linux-2.4.0-test1.orig/drivers/usb/devio.c
linux-2.4.0-test1/drivers/usb/devio.c
--- linux-2.4.0-test1.orig/drivers/usb/devio.c Wed Apr 26 15:22:55 2000
+++ linux-2.4.0-test1/drivers/usb/devio.c Thu May 25 17:43:02 2000
@@ -187,26 +187,60 @@
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;
}
@@ -376,12 +410,9 @@
}
struct usb_driver usbdevfs_driver = {
- "usbdevfs",
- driver_probe,
- driver_disconnect,
- LIST_HEAD_INIT(usbdevfs_driver.driver_list),
- NULL,
- 0
+ name: "usbdevfs",
+ probe: driver_probe,
+ disconnect: driver_disconnect,
};
static int claimintf(struct dev_state *ps, unsigned int intf)
@@ -481,6 +512,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
*/
@@ -662,16 +715,51 @@
return 0;
}
+static int proc_getdriver(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_getdriver 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_connectinfo(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_connectinfo ci;
+
+ ci.devnum = ps->dev->devnum;
+ ci.slow = ps->dev->slow;
+ copy_to_user_ret(arg, &ci, sizeof(ci), -EFAULT);
+ return 0;
+}
+
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 +1030,14 @@
ret = proc_resetep(ps, (void *)arg);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_GETDRIVER:
+ ret = proc_getdriver(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_CONNECTINFO:
+ ret = proc_connectinfo(ps, (void *)arg);
break;
case USBDEVFS_SETINTERFACE:
diff -urN linux-2.4.0-test1.orig/drivers/usb/usb-core.c
linux-2.4.0-test1/drivers/usb/usb-core.c
--- linux-2.4.0-test1.orig/drivers/usb/usb-core.c Fri Apr 21 14:03:00 2000
+++ linux-2.4.0-test1/drivers/usb/usb-core.c Thu May 25 17:25:10 2000
@@ -65,7 +65,7 @@
#endif
{
usb_major_init();
- usbdevfs_init();
+ usbdevfs_init();
usb_hub_init();
#ifndef CONFIG_USB_MODULE
diff -urN linux-2.4.0-test1.orig/drivers/usb/usb.c linux-2.4.0-test1/drivers/usb/usb.c
--- linux-2.4.0-test1.orig/drivers/usb/usb.c Mon May 8 17:37:28 2000
+++ linux-2.4.0-test1/drivers/usb/usb.c Thu May 25 17:56:55 2000
@@ -61,6 +61,9 @@
}
info("registered new driver %s", new_driver->name);
+
+ init_MUTEX(&new_driver->serialize);
+
/* Add it to the list of known drivers */
list_add(&new_driver->driver_list, &usb_driver_list);
@@ -105,7 +108,9 @@
struct usb_interface *interface = &dev->actconfig->interface[i];
if (interface->driver == driver) {
+ down(&driver->serialize);
driver->disconnect(dev, interface->private_data);
+ up(&driver->serialize);
usb_driver_release_interface(driver, interface);
/*
* This will go through the list looking for another
@@ -142,6 +147,16 @@
}
}
+struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
+{
+ 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;
+}
/*
* calc_bus_time:
@@ -242,7 +257,7 @@
bus->bandwidth_isoc_reqs = 0;
INIT_LIST_HEAD(&bus->bus_list);
- INIT_LIST_HEAD(&bus->inodes);
+ INIT_LIST_HEAD(&bus->inodes);
return bus;
}
@@ -393,7 +408,10 @@
driver_list);
tmp = tmp->next;
- if (!(private = driver->probe(dev, ifnum)))
+ down(&driver->serialize);
+ private = driver->probe(dev, ifnum);
+ up(&driver->serialize);
+ if (!private)
continue;
usb_driver_claim_interface(driver, interface, private);
@@ -452,8 +470,8 @@
dev->bus = bus;
dev->parent = parent;
atomic_set(&dev->refcnt, 1);
- INIT_LIST_HEAD(&dev->inodes);
- INIT_LIST_HEAD(&dev->filelist);
+ INIT_LIST_HEAD(&dev->inodes);
+ INIT_LIST_HEAD(&dev->filelist);
dev->bus->op->allocate(dev);
@@ -826,7 +844,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;
@@ -987,6 +1005,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];
@@ -1129,7 +1154,9 @@
struct usb_interface *interface =
&dev->actconfig->interface[i];
struct usb_driver *driver = interface->driver;
if (driver) {
+ down(&driver->serialize);
driver->disconnect(dev, interface->private_data);
+ up(&driver->serialize);
usb_driver_release_interface(driver, interface);
}
}
@@ -1143,14 +1170,13 @@
}
/* remove /proc/bus/usb entry */
- usbdevfs_remove_device(dev);
+ usbdevfs_remove_device(dev);
/* Free up the device itself, including its device number */
if (dev->devnum > 0)
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
-
+
usb_free_dev(dev);
-
}
/*
@@ -1337,15 +1363,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;
@@ -1407,11 +1428,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;
@@ -1435,9 +1455,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);
@@ -1445,41 +1470,41 @@
if (result < 0)
err("unable to get descriptor");
else
- err("config descriptor too short (expected %i, got
%i)",8,result);
+ err("config descriptor too short (expected %i, got
+%i)", 8, result);
goto err;
}
/* 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;
+ 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;
+
+ result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
if (result > 0)
dbg("descriptor data left");
- else if (result < 0)
- {
- result=-1;
+ else if (result < 0) {
+ result = -1;
goto err;
}
}
@@ -1560,8 +1585,7 @@
*/
int usb_new_device(struct usb_device *dev)
{
- int addr, err;
- int tmp;
+ int err;
info("USB new device connect, assigned device number %d", dev->devnum);
@@ -1572,10 +1596,15 @@
dev->epmaxpacketin [0] = 8;
dev->epmaxpacketout[0] = 8;
- /* Even though we have assigned an address for the device, we */
- /* haven't told it what it's address is yet */
- addr = dev->devnum;
- dev->devnum = 0;
+ err = usb_set_address(dev);
+ if (err < 0) {
+ err("USB device not accepting new address (error=%d)", err);
+ clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+ dev->devnum = -1;
+ return 1;
+ }
+
+ wait_ms(10); /* Let the SET_ADDRESS settle */
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
if (err < 8) {
@@ -1583,34 +1612,19 @@
err("USB device not responding, giving up (error=%d)", err);
else
err("USB device descriptor short read (expected %i, got
%i)",8,err);
- clear_bit(addr, &dev->bus->devmap.devicemap);
+ clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
- dev->devnum = addr;
-
- err = usb_set_address(dev);
-
- if (err < 0) {
- err("USB device not accepting new address (error=%d)", err);
- clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
- dev->devnum = -1;
- return 1;
- }
-
- wait_ms(10); /* Let the SET_ADDRESS settle */
-
- tmp = sizeof(dev->descriptor);
-
err = usb_get_device_descriptor(dev);
- if (err < tmp) {
+ if (err < sizeof(dev->descriptor)) {
if (err < 0)
- err("unable to get device descriptor (error=%d)",err);
+ err("unable to get device descriptor (error=%d)", err);
else
- err("USB device descriptor short read (expected %i, got
%i)",tmp,err);
+ err("USB device descriptor short read (expected %i, got %i)",
+sizeof(dev->descriptor), err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
dev->devnum = -1;
@@ -1646,7 +1660,7 @@
#endif
/* now that the basic setup is over, add a /proc/bus/usb entry */
- usbdevfs_add_device(dev);
+ usbdevfs_add_device(dev);
/* find drivers willing to handle this device */
usb_find_drivers(dev);
@@ -1704,6 +1718,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);
diff -urN linux-2.4.0-test1.orig/include/linux/usb.h
linux-2.4.0-test1/include/linux/usb.h
--- linux-2.4.0-test1.orig/include/linux/usb.h Mon May 8 17:37:44 2000
+++ linux-2.4.0-test1/include/linux/usb.h Thu May 25 17:37:50 2000
@@ -307,6 +307,8 @@
struct file_operations *fops;
int minor;
+
+ struct semaphore serialize;
};
/*
@@ -492,7 +494,7 @@
int bandwidth_isoc_reqs; /* number of Isoc. requesters */
/* usbdevfs inode list */
- struct list_head inodes;
+ struct list_head inodes;
};
#define USB_MAXCHILDREN (8) /* This is arbitrary */
@@ -506,7 +508,6 @@
unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] =
OUT) */
unsigned int halted[2]; /* endpoint halts; one bit per endpoint # &
direction; */
/* [0] = IN, [1] = OUT */
- struct usb_config_descriptor *actconfig;/* the active configuration */
int epmaxpacketin[16]; /* INput endpoint specific maximums */
int epmaxpacketout[16]; /* OUTput endpoint specific maximums */
@@ -515,6 +516,9 @@
struct usb_device_descriptor descriptor;/* Descriptor */
struct usb_config_descriptor *config; /* All of the configs */
+ struct usb_config_descriptor *actconfig;/* the active configuration */
+
+ char **rawdescriptors; /* Raw descriptors for each config */
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
@@ -522,8 +526,8 @@
void *hcpriv; /* Host Controller private data */
/* usbdevfs inode list */
- struct list_head inodes;
- struct list_head filelist;
+ struct list_head inodes;
+ struct list_head filelist;
/*
* Child devices - these can be either new devices
@@ -536,6 +540,8 @@
int maxchild; /* Number of ports if hub */
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 *);
diff -urN linux-2.4.0-test1.orig/include/linux/usbdevice_fs.h
linux-2.4.0-test1/include/linux/usbdevice_fs.h
--- linux-2.4.0-test1.orig/include/linux/usbdevice_fs.h Sat May 20 09:21:42 2000
+++ linux-2.4.0-test1/include/linux/usbdevice_fs.h Thu May 25 17:43:32 2000
@@ -66,6 +66,18 @@
void *context;
};
+#define USBDEVFS_MAXDRIVERNAME 255
+
+struct usbdevfs_getdriver {
+ unsigned int interface;
+ char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
+struct usbdevfs_connectinfo {
+ unsigned int devnum;
+ unsigned char slow;
+};
+
#define USBDEVFS_URB_DISABLE_SPD 1
#define USBDEVFS_URB_ISO_ASAP 2
@@ -101,6 +113,7 @@
#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_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver)
#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb)
#define USBDEVFS_DISCARDURB _IO('U', 11)
#define USBDEVFS_REAPURB _IOW('U', 12, void *)
@@ -108,6 +121,7 @@
#define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal)
#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
+#define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo)
/* --------------------------------------------------------------------- */
@@ -164,7 +178,6 @@
extern struct inode_operations usbdevfs_bus_inode_operations;
extern struct file_operations usbdevfs_bus_file_operations;
extern void usbdevfs_conn_disc_event(void);
-
#endif /* __KERNEL__ */
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]