Commit 846f917c authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] usbcore misc cleanup

This has minor usbcore cleanups:

DOC:
    - the changes passing a usb_interface to driver probe() and disconnect()
      weren't reflected in their adjacent docs.  likewise they still said
      it was possible to get a null usb_device_id (no more).

    - the (root) hub API restrictions from rmk's ARM patch weren't
      flagged

    - mention the non-dma-coherent cache issue for usb_buffer_alloc()

    - mention disconnect() cleanup issue with usb_{control,bulk}_msg()
      [ you can't cancel those urbs from disconnect() ]

CODE
    - make driver ioctl() use 'usb_interface' too ... this update
      also resolves an old 'one instance per device' bad assumption

    - module locking on driver->ioctl() was goofy, kept BKL way too
      long and didn't try_inc_mod_count() like the rest of usbcore

    - hcd unlink code treated iso inappropriately like interrupt;
      only interrupt still wants that automagic mode

    - move iso init out of ohci into shared submit_urb logic

    - remove interrupt transfer length restriction; hcds that don't
      handle packetization (just like bulk :) should be updated,
      but device drivers won't care for now.
parent b1611055
...@@ -1067,6 +1067,10 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1067,6 +1067,10 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
/* disconnect kernel driver from interface, leaving it unbound. */ /* disconnect kernel driver from interface, leaving it unbound. */
case USBDEVFS_DISCONNECT: case USBDEVFS_DISCONNECT:
/* this function is voodoo. */ /* this function is voodoo. */
/* which function ... usb_device_remove()?
* FIXME either the module lock (BKL) should be involved
* here too, or the 'default' case below is broken
*/
driver = ifp->driver; driver = ifp->driver;
if (driver) { if (driver) {
dbg ("disconnect '%s' from dev %d interface %d", dbg ("disconnect '%s' from dev %d interface %d",
...@@ -1081,26 +1085,28 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1081,26 +1085,28 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
retval = usb_device_probe (&ifp->dev); retval = usb_device_probe (&ifp->dev);
break; break;
/* talk directly to the interface's driver */ /* talk directly to the interface's driver */
default: default:
lock_kernel(); /* against module unload */ /* BKL used here to protect against changing the binding
driver = ifp->driver; * of this driver to this device, as well as unloading its
if (driver == 0 || driver->ioctl == 0) { * driver module.
*/
lock_kernel ();
driver = ifp->driver;
if (driver == 0 || driver->ioctl == 0) {
unlock_kernel(); unlock_kernel();
retval = -ENOSYS; retval = -ENOSYS;
} else { } else {
if (ifp->driver->owner) { if (driver->owner
__MOD_INC_USE_COUNT(ifp->driver->owner); && !try_inc_mod_count (driver->owner)) {
unlock_kernel();
}
/* ifno might usefully be passed ... */
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);
} else {
unlock_kernel(); unlock_kernel();
retval = -ENOSYS;
break;
} }
unlock_kernel ();
retval = driver->ioctl (ifp, ctrl.ioctl_code, buf);
if (driver->owner)
__MOD_DEC_USE_COUNT (driver->owner);
} }
if (retval == -ENOIOCTLCMD) if (retval == -ENOIOCTLCMD)
......
...@@ -1024,6 +1024,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1024,6 +1024,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
*/ */
urb = usb_get_urb (urb); urb = usb_get_urb (urb);
if (urb->dev == hcd->self.root_hub) { if (urb->dev == hcd->self.root_hub) {
/* NOTE: requirement on hub callers (usbfs and the hub
* driver, for now) that URBs' urb->transfer_buffer be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data.
*/
urb->transfer_flags |= URB_NO_DMA_MAP; urb->transfer_flags |= URB_NO_DMA_MAP;
return rh_urb_enqueue (hcd, urb); return rh_urb_enqueue (hcd, urb);
} }
...@@ -1132,11 +1137,11 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1132,11 +1137,11 @@ static int hcd_unlink_urb (struct urb *urb)
goto done; goto done;
} }
/* For non-periodic transfers, any status except -EINPROGRESS means /* Except for interrupt transfers, any status except -EINPROGRESS
* the HCD has already started to unlink this URB from the hardware. * means the HCD already started to unlink this URB from the hardware.
* In that case, there's no more work to do. * So there's no more work to do.
* *
* For periodic transfers, this is the only way to trigger unlinking * For interrupt transfers, this is the only way to trigger unlinking
* from the hardware. Since we (currently) overload urb->status to * from the hardware. Since we (currently) overload urb->status to
* tell the driver to unlink, error status might get clobbered ... * tell the driver to unlink, error status might get clobbered ...
* unless that transfer hasn't yet restarted. One such case is when * unless that transfer hasn't yet restarted. One such case is when
...@@ -1144,13 +1149,10 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1144,13 +1149,10 @@ static int hcd_unlink_urb (struct urb *urb)
* *
* FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
*/ */
switch (usb_pipetype (urb->pipe)) { if (urb->status != -EINPROGRESS
case PIPE_CONTROL: && usb_pipetype (urb->pipe) != PIPE_INTERRUPT) {
case PIPE_BULK: retval = -EINVAL;
if (urb->status != -EINPROGRESS) { goto done;
retval = -EINVAL;
goto done;
}
} }
/* maybe set up to block on completion notification */ /* maybe set up to block on completion notification */
......
...@@ -547,8 +547,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -547,8 +547,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
return -ENODEV; return -ENODEV;
} }
static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data) static int
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
{ {
struct usb_device *hub = interface_to_usbdev (intf);
/* assert ifno == 0 (part of hub spec) */ /* assert ifno == 0 (part of hub spec) */
switch (code) { switch (code) {
case USBDEVFS_HUB_PORTINFO: { case USBDEVFS_HUB_PORTINFO: {
......
...@@ -123,6 +123,9 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, ...@@ -123,6 +123,9 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
* Don't use this function from within an interrupt context, like a * Don't use this function from within an interrupt context, like a
* bottom half handler. If you need an asynchronous message, or need to send * bottom half handler. If you need an asynchronous message, or need to send
* a message from within interrupt context, use usb_submit_urb() * a message from within interrupt context, use usb_submit_urb()
* If a thread in your driver uses this call, make sure your disconnect()
* method can wait for it to complete. Since you don't have a handle on
* the URB used, you can't cancel the request.
*/ */
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout) __u16 value, __u16 index, void *data, __u16 size, int timeout)
...@@ -170,6 +173,9 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u ...@@ -170,6 +173,9 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
* Don't use this function from within an interrupt context, like a * Don't use this function from within an interrupt context, like a
* bottom half handler. If you need an asynchronous message, or need to * bottom half handler. If you need an asynchronous message, or need to
* send a message from within interrupt context, use usb_submit_urb() * send a message from within interrupt context, use usb_submit_urb()
* If a thread in your driver uses this call, make sure your disconnect()
* method can wait for it to complete. Since you don't have a handle on
* the URB used, you can't cancel the request.
*/ */
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout) void *data, int len, int *actual_length, int timeout)
......
...@@ -232,22 +232,19 @@ int usb_submit_urb(struct urb *urb, int mem_flags) ...@@ -232,22 +232,19 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
return -EMSGSIZE; return -EMSGSIZE;
} }
/* "high bandwidth" mode, 1-3 packets/uframe? */ /* periodic transfers limit size per frame/uframe,
if (dev->speed == USB_SPEED_HIGH) { * but drivers only control those sizes for ISO.
int mult; * while we're checking, initialize return status.
switch (temp) { */
case PIPE_ISOCHRONOUS: if (temp == PIPE_ISOCHRONOUS) {
case PIPE_INTERRUPT: int n, len;
mult = 1 + ((max >> 11) & 0x03);
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) {
int mult = 1 + ((max >> 11) & 0x03);
max &= 0x03ff; max &= 0x03ff;
max *= mult; max *= mult;
} }
}
/* periodic transfers limit size per frame/uframe */
switch (temp) {
case PIPE_ISOCHRONOUS: {
int n, len;
if (urb->number_of_packets <= 0) if (urb->number_of_packets <= 0)
return -EINVAL; return -EINVAL;
...@@ -255,13 +252,9 @@ int usb_submit_urb(struct urb *urb, int mem_flags) ...@@ -255,13 +252,9 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
len = urb->iso_frame_desc [n].length; len = urb->iso_frame_desc [n].length;
if (len < 0 || len > max) if (len < 0 || len > max)
return -EMSGSIZE; return -EMSGSIZE;
urb->iso_frame_desc [n].status = -EXDEV;
urb->iso_frame_desc [n].actual_length = 0;
} }
}
break;
case PIPE_INTERRUPT:
if (urb->transfer_buffer_length > max)
return -EMSGSIZE;
} }
/* the I/O buffer must be mapped/unmapped, except when length=0 */ /* the I/O buffer must be mapped/unmapped, except when length=0 */
......
...@@ -124,6 +124,8 @@ int usb_device_remove(struct device *dev) ...@@ -124,6 +124,8 @@ int usb_device_remove(struct device *dev)
if (driver->owner) { if (driver->owner) {
m = try_inc_mod_count(driver->owner); m = try_inc_mod_count(driver->owner);
if (m == 0) { if (m == 0) {
// FIXME this happens even when we just rmmod
// drivers that aren't in active use...
err("Dieing driver still bound to device.\n"); err("Dieing driver still bound to device.\n");
return -EIO; return -EIO;
} }
...@@ -1096,6 +1098,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1096,6 +1098,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
* avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping
* hardware for long idle periods. The implementation varies between * hardware for long idle periods. The implementation varies between
* platforms, depending on details of how DMA will work to this device. * platforms, depending on details of how DMA will work to this device.
* Using these buffers also helps prevent cacheline sharing problems on
* architectures where CPU caches are not DMA-coherent.
* *
* When the buffer is no longer used, free it with usb_buffer_free(). * When the buffer is no longer used, free it with usb_buffer_free().
*/ */
......
...@@ -193,12 +193,6 @@ static int ohci_urb_enqueue ( ...@@ -193,12 +193,6 @@ static int ohci_urb_enqueue (
break; break;
case PIPE_ISOCHRONOUS: /* number of packets from URB */ case PIPE_ISOCHRONOUS: /* number of packets from URB */
size = urb->number_of_packets; size = urb->number_of_packets;
if (size <= 0)
return -EINVAL;
for (i = 0; i < urb->number_of_packets; i++) {
urb->iso_frame_desc [i].actual_length = 0;
urb->iso_frame_desc [i].status = -EXDEV;
}
break; break;
} }
......
...@@ -452,9 +452,9 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) ...@@ -452,9 +452,9 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
* User mode code can read these tables to choose which modules to load. * User mode code can read these tables to choose which modules to load.
* Declare the table as a MODULE_DEVICE_TABLE. * Declare the table as a MODULE_DEVICE_TABLE.
* *
* The third probe() parameter will point to a matching entry from this * A probe() parameter will point to a matching entry from this table.
* table. (Null value reserved.) Use the driver_data field for each * Use the driver_info field for each match to hold information tied
* match to hold information tied to that match: device quirks, etc. * to that match: device quirks, etc.
* *
* Terminate the driver's table with an all-zeroes entry. * Terminate the driver's table with an all-zeroes entry.
* Use the flag values to control which fields are compared. * Use the flag values to control which fields are compared.
...@@ -604,17 +604,14 @@ struct usb_device_id { ...@@ -604,17 +604,14 @@ struct usb_device_id {
* @name: The driver name should be unique among USB drivers, * @name: The driver name should be unique among USB drivers,
* and should normally be the same as the module name. * and should normally be the same as the module name.
* @probe: Called to see if the driver is willing to manage a particular * @probe: Called to see if the driver is willing to manage a particular
* interface on a device. The probe routine returns a handle that * interface on a device. If it is, probe returns zero and uses
* will later be provided to disconnect(), or a null pointer to * dev_set_drvdata() to associate driver-specific data with the
* indicate that the driver will not handle the interface. * interface. It may also use usb_set_interface() to specify the
* The handle is normally a pointer to driver-specific data. * appropriate altsetting. If unwilling to manage the interface,
* If the probe() routine needs to access the interface * return a negative errno value.
* structure itself, use usb_ifnum_to_if() to make sure it's using
* the right one.
* @disconnect: Called when the interface is no longer accessible, usually * @disconnect: Called when the interface is no longer accessible, usually
* because its device has been (or is being) disconnected. The * because its device has been (or is being) disconnected or the
* handle passed is what was returned by probe(), or was provided * driver module is being unloaded.
* to usb_driver_claim_interface().
* @ioctl: Used for drivers that want to talk to userspace through * @ioctl: Used for drivers that want to talk to userspace through
* the "usbfs" filesystem. This lets devices provide ways to * the "usbfs" filesystem. This lets devices provide ways to
* expose information to user space regardless of where they * expose information to user space regardless of where they
...@@ -648,7 +645,7 @@ struct usb_driver { ...@@ -648,7 +645,7 @@ struct usb_driver {
void (*disconnect) (struct usb_interface *intf); void (*disconnect) (struct usb_interface *intf);
int (*ioctl) (struct usb_device *dev, unsigned int code, void *buf); int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
const struct usb_device_id *id_table; const struct usb_device_id *id_table;
......
...@@ -108,7 +108,7 @@ struct usbdevfs_urb { ...@@ -108,7 +108,7 @@ struct usbdevfs_urb {
struct usbdevfs_iso_packet_desc iso_frame_desc[0]; struct usbdevfs_iso_packet_desc iso_frame_desc[0];
}; };
/* ioctls for talking to drivers in the usbcore module: */ /* ioctls for talking directly to drivers */
struct usbdevfs_ioctl { struct usbdevfs_ioctl {
int ifno; /* interface 0..N ; negative numbers reserved */ int ifno; /* interface 0..N ; negative numbers reserved */
int ioctl_code; /* MUST encode size + direction of data so the int ioctl_code; /* MUST encode size + direction of data so the
......
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