Commit b46bff09 authored by Dan Streetman's avatar Dan Streetman Committed by Greg Kroah-Hartman

[PATCH] usbfs disconnect

This was originally created by David many months ago and posted to the
list, but not put into the kernel.

I modified the original patch to:
-patch against the 2.5.7 kernel
-use the 'real' interface number, not position (to do this I added 2
 methods in usb.c)
parent a64c6e4b
...@@ -1057,6 +1057,8 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1057,6 +1057,8 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
int size; int size;
void *buf = 0; void *buf = 0;
int retval = 0; int retval = 0;
struct usb_interface *ifp = 0;
struct usb_driver *driver = 0;
/* get input parameters and alloc buffer */ /* get input parameters and alloc buffer */
if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl))) if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl)))
...@@ -1074,33 +1076,41 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1074,33 +1076,41 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
} }
} }
/* ioctl to device */ if (!ps->dev)
if (ctrl.ifno < 0) { retval = -ENODEV;
switch (ctrl.ioctl_code) { else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
/* access/release token for issuing control messages retval = -EINVAL;
* ask a particular driver to bind/unbind, ... etc else switch (ctrl.ioctl_code) {
*/
} /* disconnect kernel driver from interface, leaving it unbound. */
retval = -ENOSYS; case USBDEVFS_DISCONNECT:
driver = ifp->driver;
/* ioctl to the driver which has claimed a given interface */ if (driver) {
} else { down (&driver->serialize);
struct usb_interface *ifp = 0; dbg ("disconnect '%s' from dev %d interface %d",
if (!ps->dev) driver->name, ps->dev->devnum, ctrl.ifno);
retval = -ENODEV; driver->disconnect (ps->dev, ifp->private_data);
else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces) usb_driver_release_interface (driver, ifp);
up (&driver->serialize);
} else
retval = -EINVAL; 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 { 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) {
if (ifp->driver->owner) if (ifp->driver->owner)
__MOD_INC_USE_COUNT(ifp->driver->owner); __MOD_INC_USE_COUNT(ifp->driver->owner);
/* ifno might usefully be passed ... */ /* 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)? */ /* size = min_t(int, size, retval)? */
if (ifp->driver->owner) if (ifp->driver->owner)
__MOD_DEC_USE_COUNT(ifp->driver->owner); __MOD_DEC_USE_COUNT(ifp->driver->owner);
......
...@@ -196,6 +196,26 @@ void usb_deregister(struct usb_driver *driver) ...@@ -196,6 +196,26 @@ void usb_deregister(struct usb_driver *driver)
usbfs_update_special(); usbfs_update_special();
} }
/*
* usb_ifnum_to_ifpos - convert the interface _number_ (as in interface.bInterfaceNumber)
* to the interface _position_ (as in dev->actconfig->interface + position)
* @dev: the device to use
* @ifnum: the interface number (bInterfaceNumber); not interface position
*
* 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_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;
}
/** /**
* usb_ifnum_to_if - get the interface object with a given interface number * usb_ifnum_to_if - get the interface object with a given interface number
* @dev: the device whose current configuration is considered * @dev: the device whose current configuration is considered
...@@ -570,6 +590,23 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum) ...@@ -570,6 +590,23 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
return -1; return -1;
} }
/*
* usb_find_interface_driver_for_ifnum - convert ifnum to ifpos via
* usb_ifnum_to_ifpos and call usb_find_interface_driver().
* @dev: the device to use
* @ifnum: the interface number (bInterfaceNumber); not interface position!
*
* Note usb_find_interface_driver's ifnum parameter is actually interface position.
*/
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 #ifdef CONFIG_HOTPLUG
...@@ -2636,6 +2673,7 @@ module_exit(usb_exit); ...@@ -2636,6 +2673,7 @@ module_exit(usb_exit);
* into the kernel, and other device drivers are built as modules, * into the kernel, and other device drivers are built as modules,
* then these symbols need to be exported for the modules to use. * 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_ifnum_to_if);
EXPORT_SYMBOL(usb_epnum_to_ep_desc); EXPORT_SYMBOL(usb_epnum_to_ep_desc);
...@@ -2647,6 +2685,7 @@ EXPORT_SYMBOL(usb_alloc_dev); ...@@ -2647,6 +2685,7 @@ EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_free_dev); EXPORT_SYMBOL(usb_free_dev);
EXPORT_SYMBOL(usb_inc_dev_use); EXPORT_SYMBOL(usb_inc_dev_use);
EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
EXPORT_SYMBOL(usb_driver_claim_interface); EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed); EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_driver_release_interface);
......
...@@ -305,6 +305,7 @@ struct usb_qualifier_descriptor { ...@@ -305,6 +305,7 @@ struct usb_qualifier_descriptor {
} __attribute__ ((packed)); } __attribute__ ((packed));
/* helpers for driver access to descriptors */ /* helpers for driver access to descriptors */
extern int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum);
extern struct usb_interface * extern struct usb_interface *
usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
extern struct usb_endpoint_descriptor * extern struct usb_endpoint_descriptor *
...@@ -1052,6 +1053,7 @@ extern void usb_inc_dev_use(struct usb_device *); ...@@ -1052,6 +1053,7 @@ extern void usb_inc_dev_use(struct usb_device *);
#define usb_dec_dev_use usb_free_dev #define usb_dec_dev_use usb_free_dev
/* used these for multi-interface device registration */ /* 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, extern void usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void* priv); struct usb_interface *iface, void* priv);
extern int usb_interface_claimed(struct usb_interface *iface); extern int usb_interface_claimed(struct usb_interface *iface);
......
...@@ -142,6 +142,8 @@ struct usbdevfs_hub_portinfo { ...@@ -142,6 +142,8 @@ struct usbdevfs_hub_portinfo {
#define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) #define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo)
#define USBDEVFS_RESET _IO('U', 20) #define USBDEVFS_RESET _IO('U', 20)
#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)
#define USBDEVFS_DISCONNECT _IO('U', 22)
#define USBDEVFS_CONNECT _IO('U', 23)
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment