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.

Please merge to Linus' latest.

- Dave

--- ./include/linux/usb.h-dist  Wed Sep 18 10:25:54 2002
+++ ./include/linux/usb.h       Fri Sep 27 11:59:00 2002
@@ -452,9 +452,9 @@
  * User mode code can read these tables to choose which modules to load.
  * Declare the table as a MODULE_DEVICE_TABLE.
  *
- * The third probe() parameter will point to a matching entry from this
- * table.  (Null value reserved.)  Use the driver_data field for each
- * match to hold information tied to that match:  device quirks, etc.
+ * A probe() parameter will point to a matching entry from this table.
+ * Use the driver_info field for each match to hold information tied
+ * to that match:  device quirks, etc.
  *
  * Terminate the driver's table with an all-zeroes entry.
  * Use the flag values to control which fields are compared.
@@ -604,17 +604,14 @@
  * @name: The driver name should be unique among USB drivers,
  *     and should normally be the same as the module name.
  * @probe: Called to see if the driver is willing to manage a particular
- *     interface on a device.  The probe routine returns a handle that 
- *     will later be provided to disconnect(), or a null pointer to
- *     indicate that the driver will not handle the interface.
- *     The handle is normally a pointer to driver-specific data.
- *     If the probe() routine needs to access the interface
- *     structure itself, use usb_ifnum_to_if() to make sure it's using
- *     the right one.
+ *     interface on a device.  If it is, probe returns zero and uses
+ *     dev_set_drvdata() to associate driver-specific data with the
+ *     interface.  It may also use usb_set_interface() to specify the
+ *     appropriate altsetting.  If unwilling to manage the interface,
+ *     return a negative errno value.
  * @disconnect: Called when the interface is no longer accessible, usually
- *     because its device has been (or is being) disconnected.  The
- *     handle passed is what was returned by probe(), or was provided
- *     to usb_driver_claim_interface().
+ *     because its device has been (or is being) disconnected or the
+ *     driver module is being unloaded.
  * @ioctl: Used for drivers that want to talk to userspace through
  *     the "usbfs" filesystem.  This lets devices provide ways to
  *     expose information to user space regardless of where they
@@ -648,7 +645,7 @@
 
        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;
 
--- ./include/linux/usbdevice_fs.h-dist Wed Jul 17 08:41:40 2002
+++ ./include/linux/usbdevice_fs.h      Fri Sep 27 11:50:52 2002
@@ -108,7 +108,7 @@
        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 {
        int     ifno;           /* interface 0..N ; negative numbers reserved */
        int     ioctl_code;     /* MUST encode size + direction of data so the
--- ./drivers/usb-dist/core/hcd.c       Wed Sep 18 10:25:48 2002
+++ ./drivers/usb/core/hcd.c    Fri Sep 27 12:06:45 2002
@@ -1024,6 +1024,11 @@
         */
        urb = usb_get_urb (urb);
        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;
                return rh_urb_enqueue (hcd, urb);
        }
@@ -1132,11 +1137,11 @@
                goto done;
        }
 
-       /* For non-periodic transfers, any status except -EINPROGRESS means
-        * the HCD has already started to unlink this URB from the hardware.
-        * In that case, there's no more work to do.
+       /* Except for interrupt transfers, any status except -EINPROGRESS
+        * means the HCD already started to unlink this URB from the hardware.
+        * 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
         * tell the driver to unlink, error status might get clobbered ...
         * unless that transfer hasn't yet restarted.  One such case is when
@@ -1144,13 +1149,10 @@
         *
         * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
         */
-       switch (usb_pipetype (urb->pipe)) {
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-               if (urb->status != -EINPROGRESS) {
-                       retval = -EINVAL;
-                       goto done;
-               }
+       if (urb->status != -EINPROGRESS
+                       && usb_pipetype (urb->pipe) != PIPE_INTERRUPT) {
+               retval = -EINVAL;
+               goto done;
        }
 
        /* maybe set up to block on completion notification */
--- ./drivers/usb-dist/core/hub.c       Wed Sep 18 10:25:48 2002
+++ ./drivers/usb/core/hub.c    Fri Sep 27 11:59:00 2002
@@ -547,8 +547,11 @@
        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) */
        switch (code) {
        case USBDEVFS_HUB_PORTINFO: {
--- ./drivers/usb-dist/core/usb.c       Fri Sep 27 08:08:16 2002
+++ ./drivers/usb/core/usb.c    Fri Sep 27 11:59:00 2002
@@ -123,6 +123,8 @@
        if (driver->owner) {
                m = try_inc_mod_count(driver->owner);
                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");
                        return -EIO;
                }
@@ -1196,6 +1198,8 @@
  * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping
  * hardware for long idle periods.  The implementation varies between
  * 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().
  */
--- ./drivers/usb-dist/core/urb.c       Sun Sep  1 22:29:48 2002
+++ ./drivers/usb/core/urb.c    Fri Sep 27 12:38:40 2002
@@ -232,22 +232,19 @@
                return -EMSGSIZE;
        }
 
-       /* "high bandwidth" mode, 1-3 packets/uframe? */
-       if (dev->speed == USB_SPEED_HIGH) {
-               int     mult;
-               switch (temp) {
-               case PIPE_ISOCHRONOUS:
-               case PIPE_INTERRUPT:
-                       mult = 1 + ((max >> 11) & 0x03);
+       /* periodic transfers limit size per frame/uframe,
+        * but drivers only control those sizes for ISO.
+        * while we're checking, initialize return status.
+        */
+       if (temp == PIPE_ISOCHRONOUS) {
+               int     n, len;
+
+               /* "high bandwidth" mode, 1-3 packets/uframe? */
+               if (dev->speed == USB_SPEED_HIGH) {
+                       int     mult = 1 + ((max >> 11) & 0x03);
                        max &= 0x03ff;
                        max *= mult;
                }
-       }
-
-       /* periodic transfers limit size per frame/uframe */
-       switch (temp) {
-       case PIPE_ISOCHRONOUS: {
-               int     n, len;
 
                if (urb->number_of_packets <= 0)                    
                        return -EINVAL;
@@ -255,13 +252,9 @@
                        len = urb->iso_frame_desc [n].length;
                        if (len < 0 || len > max) 
                                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 */
--- ./drivers/usb-dist/core/devio.c     Wed Sep 18 10:25:48 2002
+++ ./drivers/usb/core/devio.c  Fri Sep 27 18:38:57 2002
@@ -1067,6 +1067,10 @@
        /* disconnect kernel driver from interface, leaving it unbound.  */
        case USBDEVFS_DISCONNECT:
                /* 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;
                if (driver) {
                        dbg ("disconnect '%s' from dev %d interface %d",
@@ -1081,26 +1085,28 @@
                retval = usb_device_probe (&ifp->dev);
                break;
 
-       /* talk directly to the interface's driver */
-       default:
-               lock_kernel(); /* against module unload */
-               driver = ifp->driver;
-               if (driver == 0 || driver->ioctl == 0) {
+       /* talk directly to the interface's driver */
+       default:
+               /* BKL used here to protect against changing the binding
+                * of this driver to this device, as well as unloading its
+                * driver module.
+                */
+               lock_kernel ();
+               driver = ifp->driver;
+               if (driver == 0 || driver->ioctl == 0) {
                        unlock_kernel();
                        retval = -ENOSYS;
                } else {
-                       if (ifp->driver->owner) {
-                               __MOD_INC_USE_COUNT(ifp->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 {
+                       if (driver->owner
+                                       && !try_inc_mod_count (driver->owner)) {
                                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)
--- ./drivers/usb-dist/core/message.c   Tue Aug 27 15:46:58 2002
+++ ./drivers/usb/core/message.c        Fri Sep 27 11:59:00 2002
@@ -123,6 +123,9 @@
  *     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
  *     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,
                         __u16 value, __u16 index, void *data, __u16 size, int timeout)
@@ -170,6 +173,9 @@
  *     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 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, 
                        void *data, int len, int *actual_length, int timeout)
--- ./drivers/usb-dist/host/ohci-hcd.c  Fri Sep 27 08:08:16 2002
+++ ./drivers/usb/host/ohci-hcd.c       Fri Sep 27 11:59:00 2002
@@ -193,12 +193,6 @@
                        break;
                case PIPE_ISOCHRONOUS: /* number of packets from URB */
                        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;
        }
 

Reply via email to