Sergey Vlasov wrote:

Seems that the real problem is in hid-core.c:


                endpoint = &interface->endpoint[n].desc;
                if ((endpoint->bmAttributes & 3) != 3)           /* Not an interrupt 
endpoint */
                        continue;

                if (endpoint->bEndpointAddress & USB_DIR_IN) {
                        if (hid->urbin)
                                continue;
                        if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
                                goto fail;
                        pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
                        usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
                                         hid_irq_in, hid, endpoint->bInterval);
                        hid->urbin->transfer_dma = hid->inbuf_dma;
                        hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                } else {
                        if (hid->urbout)
                                continue;
                        if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
                                goto fail;
                        pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress);
                        usb_fill_bulk_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
                                          hid_irq_out, hid);
                        hid->urbout->transfer_dma = hid->outbuf_dma;
                        hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                }

Notice that for the input endpoint it correctly uses usb_rcvintpipe()
and usb_fill_int_urb(), but for the output endpoint usb_sndbulkpipe()
and usb_fill_bulk_urb() are used (even though it is really an
interrupt endpoint).  How could this work?

So it is the HID core which must be fixed.  Unfortunately, I don't
have any HID device which would have an interrupt out endpoint...

Attached is a patch doing two things:
hid-lgff.c: Fixes an obvious list handling issue.
hid-core.c: - Use INT out urbs instead of bulk out urbs. That's the way it should be
- Remove some report->id magic.


IMPORTANT NOTE: You probably do not want to apply this patch yet. I do not understand what the report->id thing is supposed to do, but I know it prevents my driver to work (no complaint from usb_submit_urb, but my device just won't react to it)

--
Johann Deneux
diff -u linux-2.6.0-test9-old/drivers/usb/input/hid-core.c 
linux-2.6.0-test9-new/drivers/usb/input/hid-core.c
--- linux-2.6.0-test9-old/drivers/usb/input/hid-core.c  2003-10-25 18:43:52.000000000 
+0000
+++ linux-2.6.0-test9-new/drivers/usb/input/hid-core.c  2003-12-15 23:14:05.000000000 
+0000
@@ -953,9 +953,6 @@
 {
        unsigned n;
 
-       if (report->id > 0)
-               *data++ = report->id;
-
        for (n = 0; n < report->maxfield; n++)
                hid_output_field(report->field[n], data);
 }
@@ -1046,17 +1043,18 @@
 static int hid_submit_out(struct hid_device *hid)
 {
        struct hid_report *report;
+       int err;
 
        report = hid->out[hid->outtail];
 
        hid_output_report(report, hid->outbuf);
-       hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + 
(report->id > 0);
+       hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1;
        hid->urbout->dev = hid->dev;
 
-       dbg("submitting out urb");
+       dbg("submitting out urb with size %d", hid->urbout->transfer_buffer_length);
 
-       if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) {
-               err("usb_submit_urb(out) failed");
+       if ((err = usb_submit_urb(hid->urbout, GFP_ATOMIC))) {
+               err("usb_submit_urb(out) failed (%d)", err);
                return -1;
        }
 
@@ -1521,9 +1519,9 @@
                                continue;
                        if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
                                goto fail;
-                       pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress);
-                       usb_fill_bulk_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
-                                         hid_irq_out, hid);
+                       pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
+                       usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
+                                         hid_irq_out, hid, 1);
                        hid->urbout->transfer_dma = hid->outbuf_dma;
                        hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                }
diff -u linux-2.6.0-test9-old/drivers/usb/input/hid-lgff.c 
linux-2.6.0-test9-new/drivers/usb/input/hid-lgff.c
--- linux-2.6.0-test9-old/drivers/usb/input/hid-lgff.c  2003-10-25 18:44:16.000000000 
+0000
+++ linux-2.6.0-test9-new/drivers/usb/input/hid-lgff.c  2003-12-15 23:11:44.000000000 
+0000
@@ -31,7 +31,7 @@
 #include <linux/input.h>
 #include <linux/sched.h>
 
-#define DEBUG
+//#define DEBUG
 #include <linux/usb.h>
 
 #include <linux/circ_buf.h>
@@ -254,7 +254,7 @@
        signed short* ff;
        u16 idVendor = hid->dev->descriptor.idVendor;
        u16 idProduct = hid->dev->descriptor.idProduct;
-       struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
+       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, 
list);
 
        while (dev->idVendor && (idVendor != dev->idVendor || idProduct != 
dev->idProduct))
                dev++;

Reply via email to