I guess it has been a few releases since I last thought
about the /proc/bus/usb facilities, and it looks like
linux-2.4.3/drivers/usb/devio.c contains some handy new ioctl's,
like USBDEVFS_{SUBMIT,DISCARD,REAP}URB.  It looks like it is now
possible to write a user level USB driver that can read USB interrupt
pipes using these ioctl's.  This has been a roadblock to user level
Human Interface Device drivers.

        I noticed this as I was writing a patch to implement a
USBDEVFS_INTERRUPT ioctl for doing transfers from interrupt pipes
(like USBDEVFS_BULK).  I have attached the patch, in case anybody is
curios (it compiles and seems harmless, but I don't know if it works).
If this code is unnecessary, then there is no need to bloat the kernel
with it.  However, I figure that, in case it is needed, I will included
for reference with this email.

        Anyhow, if someone could clarify the situation, that would
be very helpful to me.

        I am currently interested in the USB user level drivers because
I think it may be better to move all Human Input Device USB drivers
to user land.  The HID "report" descriptors are fairly complex, so
they do not lend themselves easily to the design of a MODULE_DEVICE_TABLE
structure for use in selecting kernel modules, plus they are complex
enough so that you may be a fairly complex task for a driver to figure
out what parts of the HID device it can control.  The advantages of
this would be that it would be easier to provide more elaborate support
for different Human Input Devices (and other things that have nothing
to do with human input but use the HID class, like uninterruptible
power supplies).

        Since HID devices are pretty low bandwidth, I do not think there
is a performance reason for including them in the kernel, although I
would be more reassured in this feeling if I had some numbers on what kind
of latency is needed for joysticks and the like in things like fast video
games.

-- 
Adam J. Richter     __     ______________   4880 Stevens Creek Blvd, Suite 104
[EMAIL PROTECTED]     \ /                  San Jose, California 95129-1034
+1 408 261-6630         | g g d r a s i l   United States of America
fax +1 408 261-6631      "Free Software For The Rest Of Us."
--- linux-2.4.3/include/linux/usbdevice_fs.h    Mon Mar 26 15:50:12 2001
+++ linux/include/linux/usbdevice_fs.h  Sat Mar 31 00:05:23 2001
@@ -125,6 +125,7 @@
 };
 
 #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
+#define USBDEVFS_INTERRUPT         _IOWR('U', 1, struct usbdevfs_bulktransfer)
 #define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
 #define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
 #define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
--- linux-2.4.3/include/linux/usb.h     Mon Mar 26 15:49:54 2001
+++ linux/include/linux/usb.h   Sat Mar 31 00:21:04 2001
@@ -532,6 +532,8 @@
 int usb_unlink_urb(purb_t purb);
 int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 
devrequest *cmd,  void *data, int len, int timeout);
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, 
int *actual_length, int timeout);
+int usb_intr_msg(struct usb_device *usb_dev, unsigned int pipe, 
+                void *data, int len, int *actual_length, int timeout);
 
 /*-------------------------------------------------------------------*
  *                         SYNCHRONOUS CALL SUPPORT                  *
--- linux-2.4.3/drivers/usb/usb.c       Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/usb.c     Sat Mar 31 00:20:45 2001
@@ -19,7 +19,7 @@
  * It should be considered a slave, with no callbacks. Callbacks
  * are evil.
  *
- * $Id: usb.c,v 1.53 2000/01/14 16:19:09 acher Exp $
+ * $Id$
  */
 
 #include <linux/config.h>
@@ -1002,6 +1002,9 @@
 {
        api_wrapper_data *awd = (api_wrapper_data *)urb->context;
 
+       if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
+               usb_unlink_urb(urb);
+
        if (waitqueue_active(awd->wakeup))
                wake_up(awd->wakeup);
 #if 0
@@ -1165,6 +1168,24 @@
 
        FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len,   /* build urb */
                        (usb_complete_t)usb_api_blocking_completion,0);
+
+       return usb_start_wait_urb(urb,timeout,actual_length);
+}
+
+int usb_intr_msg(struct usb_device *usb_dev, unsigned int pipe, 
+                       void *data, int len, int *actual_length, int timeout)
+{
+       urb_t *urb;
+
+       if (len < 0)
+               return -EINVAL;
+
+       urb=usb_alloc_urb(0);
+       if (!urb)
+               return -ENOMEM;
+
+       FILL_INT_URB(urb,usb_dev,pipe,(unsigned char*)data,len,   /* build urb */
+                       (usb_complete_t)usb_api_blocking_completion,0, 0);
 
        return usb_start_wait_urb(urb,timeout,actual_length);
 }
--- linux-2.4.3/drivers/usb/devio.c     Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/devio.c   Sat Mar 31 00:21:38 2001
@@ -19,7 +19,7 @@
  *      along with this program; if not, write to the Free Software
  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *  $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $
+ *  $Id$
  *
  *  This file implements the usbdevfs/x/y files, where
  *  x is the bus number and y the device number.
@@ -622,6 +622,63 @@
        return len2;
 }
 
+static int proc_interrupt(struct dev_state *ps, void *arg)
+{
+       struct usb_device *dev = ps->dev;
+       struct usbdevfs_bulktransfer intr;
+       unsigned int tmo, len1, pipe;
+       int len2;
+       unsigned char *tbuf;
+       int i, ret;
+
+       if (copy_from_user(&intr, (void *)arg, sizeof(intr)))
+               return -EFAULT;
+       if ((ret = findintfep(ps->dev, intr.ep)) < 0)
+               return ret;
+       if ((ret = checkintf(ps, ret)))
+               return ret;
+       if (intr.ep & USB_DIR_IN)
+               pipe = usb_rcvintpipe(dev, intr.ep & 0x7f);
+       else
+               pipe = usb_sndintpipe(dev, intr.ep & 0x7f);
+       if (!usb_maxpacket(dev, pipe, !(intr.ep & USB_DIR_IN)))
+               return -EINVAL;
+       len1 = intr.len;
+       if (len1 > PAGE_SIZE)
+               return -EINVAL;
+       if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+               return -ENOMEM;
+       tmo = (intr.timeout * HZ + 999) / 1000;
+       if (intr.ep & 0x80) {
+               if (len1 && !access_ok(VERIFY_WRITE, intr.data, len1)) {
+                       free_page((unsigned long)tbuf);
+                       return -EINVAL;
+               }
+               i = usb_intr_msg(dev, pipe, tbuf, len1, &len2, tmo);
+               if (!i && len2) {
+                       if (copy_to_user(intr.data, tbuf, len2)) {
+                               free_page((unsigned long)tbuf);
+                               return -EFAULT;
+                       }
+               }
+       } else {
+               if (len1) {
+                       if (copy_from_user(tbuf, intr.data, len1)) {
+                               free_page((unsigned long)tbuf);
+                               return -EFAULT;
+                       }
+               }
+               i = usb_intr_msg(dev, pipe, tbuf, len1, &len2, tmo);
+       }
+       free_page((unsigned long)tbuf);
+       if (i < 0) {
+               printk(KERN_WARNING "usbdevfs: USBDEVFS_INTR failed dev %d ep 0x%x len 
+%u ret %d\n", 
+                      dev->devnum, intr.ep, intr.len, i);
+               return i;
+       }
+       return len2;
+}
+
 static int proc_resetep(struct dev_state *ps, void *arg)
 {
        unsigned int ep;
@@ -1116,6 +1173,12 @@
 
        case USBDEVFS_BULK:
                ret = proc_bulk(ps, (void *)arg);
+               if (ret >= 0)
+                       inode->i_mtime = CURRENT_TIME;
+               break;
+
+       case USBDEVFS_INTERRUPT:
+               ret = proc_interrupt(ps, (void *)arg);
                if (ret >= 0)
                        inode->i_mtime = CURRENT_TIME;
                break;

Reply via email to