On Mon, 22 Oct 2001, David Brownell wrote:
>> Someone proposed an ioctl() some time ago to force a kernel-module to >> release an interface, but I never saw it implemented. > >It was implemented, and I hope to dust off the patch this week. Check >list archives for January. The original posting is here: http://marc.theaimsgroup.com/?l=linux-usb-devel&m=98002097701710&w=2 and below is the patch updated to 2.4.12, with additions. Dave, since this is your patch, you may want to update it differently or at least check the patch below, however see below... One important change/addition is the fact that the user-supplied ifnum needs to be the actual interface number, not the interface position, which is only the same as the number for devices with sequentially numbered interfaces. So, I changed devio.proc_ioctl() to use the interface number (not position); left usb_find_interface_driver() unchanged; and added a (exported) function usb_find_interface_driver_for_ifnum(), which just converts and calls the static function. Patch below. diff -urN 2.4.12-clean/drivers/usb/devio.c linux/drivers/usb/devio.c --- 2.4.12-clean/drivers/usb/devio.c Mon Sep 10 11:06:32 2001 +++ linux/drivers/usb/devio.c Mon Oct 22 18:43:58 2001 @@ -1040,6 +1040,8 @@ int size; void *buf = 0; int retval = 0; + struct usb_interface *ifp = 0; + struct usb_driver *driver = 0; /* get input parameters and alloc buffer */ if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl))) @@ -1057,32 +1059,41 @@ } } - /* ioctl to device */ - if (ctrl.ifno < 0) { - switch (ctrl.ioctl_code) { - /* access/release token for issuing control messages - * ask a particular driver to bind/unbind, ... etc - */ - } - retval = -ENOSYS; + if (!ps->dev) + retval = -ENODEV; + else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) + retval = -EINVAL; + else switch (ctrl.ioctl_code) { - /* ioctl to the driver which has claimed a given interface */ - } else { - struct usb_interface *ifp = 0; - if (!ps->dev) - retval = -ENODEV; - else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces) + /* disconnect kernel driver from interface, leaving it unbound. */ + case USBDEVFS_DISCONNECT: + driver = ifp->driver; + if (driver) { + down (&driver->serialize); + dbg ("disconnect '%s' from dev %d interface %d", + driver->name, ps->dev->devnum, ctrl.ifno); + driver->disconnect (ps->dev, ifp->private_data); + usb_driver_release_interface (driver, ifp); + up (&driver->serialize); + } else retval = -EINVAL; + break; + + /* let kernel drivers try to (re)bind to the interface */ + case USBDEVFS_CONNECT: + usb_find_interface_driver_for_ifnum (ps->dev, ctrl.ifno); + break; + + /* talk directly to the interface's driver */ + default: + driver = ifp->driver; + if (driver == 0 || driver->ioctl == 0) + retval = -ENOSYS; else { - if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) - retval = -EINVAL; - else if (ifp->driver == 0 || ifp->driver->ioctl == 0) - retval = -ENOSYS; - } - if (retval == 0) /* ifno might usefully be passed ... */ - retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf); + retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf); /* size = min_t(int, size, retval)? */ + } } /* cleanup and return */ diff -urN 2.4.12-clean/drivers/usb/usb.c linux/drivers/usb/usb.c --- 2.4.12-clean/drivers/usb/usb.c Tue Oct 9 18:15:02 2001 +++ linux/drivers/usb/usb.c Mon Oct 22 19:24:09 2001 @@ -193,6 +193,17 @@ read_unlock_irq (&usb_bus_list_lock); } +int usb_ifnum_to_ifpos(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 i; + + return -EINVAL; +} + struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) { int i; @@ -682,9 +693,12 @@ * the drivers don't have to dig around in our structures to set the * private pointer if they only need one interface. * + * Note that the parameter ifpos is the position, not number, of the interface. + * See usb_find_interface_driver_for_ifnum() for details. + * * Returns: 0 if a driver accepted the interface, -1 otherwise */ -static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum) +static int usb_find_interface_driver(struct usb_device *dev, unsigned ifpos) { struct list_head *tmp; struct usb_interface *interface; @@ -693,14 +707,14 @@ struct usb_driver *driver; int i; - if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) { + if ((!dev) || (ifpos >= dev->actconfig->bNumInterfaces)) { err("bad find_interface_driver params"); return -1; } down(&dev->serialize); - interface = dev->actconfig->interface + ifnum; + interface = dev->actconfig->interface + ifpos; if (usb_interface_claimed(interface)) goto out_err; @@ -718,7 +732,7 @@ id = usb_match_id(dev, interface, id); if (id) { down(&driver->serialize); - private = driver->probe(dev,ifnum,id); + private = driver->probe(dev,ifpos,id); up(&driver->serialize); if (private != NULL) break; @@ -730,12 +744,12 @@ interface->act_altsetting = 0; } else { /* "old style" driver */ down(&driver->serialize); - private = driver->probe(dev, ifnum, NULL); + private = driver->probe(dev, ifpos, NULL); up(&driver->serialize); } /* probe() may have changed the config on us */ - interface = dev->actconfig->interface + ifnum; + interface = dev->actconfig->interface + ifpos; if (private) { usb_driver_claim_interface(driver, interface, private); @@ -749,6 +763,23 @@ return -1; } +/* + * This simply converts the interface _number_ (as in interface.bInterfaceNumber) + * to the interface _position_ (as in dev->actconfig->interface + position) + * and calls usb_find_interface_driver(). + * + * Note that the number is the same as the position for all interfaces _except_ + * devices with interfaces not sequentially numbered (e.g., 0, 2, 3, etc). + */ +int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned ifnum) +{ + int ifpos = usb_ifnum_to_ifpos(dev, ifnum); + + if (0 > ifpos) + return -EINVAL; + + return usb_find_interface_driver(dev, ifpos); +} #ifdef CONFIG_HOTPLUG @@ -2358,6 +2389,7 @@ * 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_ifpos); EXPORT_SYMBOL(usb_ifnum_to_if); EXPORT_SYMBOL(usb_epnum_to_ep_desc); @@ -2372,6 +2404,7 @@ EXPORT_SYMBOL(usb_free_dev); EXPORT_SYMBOL(usb_inc_dev_use); +EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum); EXPORT_SYMBOL(usb_driver_claim_interface); EXPORT_SYMBOL(usb_interface_claimed); EXPORT_SYMBOL(usb_driver_release_interface); diff -urN 2.4.12-clean/include/linux/usb.h linux/include/linux/usb.h --- 2.4.12-clean/include/linux/usb.h Thu Oct 11 02:47:25 2001 +++ linux/include/linux/usb.h Mon Oct 22 18:46:02 2001 @@ -645,6 +645,7 @@ struct usb_device *children[USB_MAXCHILDREN]; }; +extern int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum); extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); extern struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum); @@ -653,6 +654,7 @@ extern void usb_scan_devices(void); /* used these for multi-interface device registration */ +extern int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned int +ifnum); 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); diff -urN 2.4.12-clean/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h --- 2.4.12-clean/include/linux/usbdevice_fs.h Thu Oct 11 02:47:51 2001 +++ linux/include/linux/usbdevice_fs.h Mon Oct 22 13:59:53 2001 @@ -142,6 +142,8 @@ #define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) #define USBDEVFS_RESET _IO('U', 20) #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) +#define USBDEVFS_DISCONNECT _IO('U', 22) +#define USBDEVFS_CONNECT _IO('U', 23) /* --------------------------------------------------------------------- */ _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel