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)
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)))
......@@ -1074,33 +1076,41 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
}
}
/* 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;
/* 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)
if (!ps->dev)
retval = -ENODEV;
else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
retval = -EINVAL;
else switch (ctrl.ioctl_code) {
/* 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) {
if (ifp->driver->owner)
__MOD_INC_USE_COUNT(ifp->driver->owner);
/* 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)? */
if (ifp->driver->owner)
__MOD_DEC_USE_COUNT(ifp->driver->owner);
......
......@@ -196,6 +196,26 @@ void usb_deregister(struct usb_driver *driver)
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
* @dev: the device whose current configuration is considered
......@@ -570,6 +590,23 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
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
......@@ -2636,6 +2673,7 @@ module_exit(usb_exit);
* 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);
......@@ -2647,6 +2685,7 @@ EXPORT_SYMBOL(usb_alloc_dev);
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);
......
......@@ -305,6 +305,7 @@ struct usb_qualifier_descriptor {
} __attribute__ ((packed));
/* helpers for driver access to descriptors */
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 *
......@@ -1052,6 +1053,7 @@ extern void usb_inc_dev_use(struct usb_device *);
#define usb_dec_dev_use usb_free_dev
/* 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);
......
......@@ -142,6 +142,8 @@ struct usbdevfs_hub_portinfo {
#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)
/* --------------------------------------------------------------------- */
......
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