On Sun, Dec 14, 2003 at 04:40:54PM +0000, Johann Deneux wrote:
> I've had bug reports from users trying to use hid with force feed back 
> enabled for logitech devices (kernel 2.6.0-test9). The device causing 
> trouble is the cordless rumble pad. It is a low-speed device, and 
> stubbornly refuses to rumble. It works fine as an input-only device, 
> however.
> 
> hid-lgff.c, which implements force feedback for this device, needs to 
> submit output reports to the device. hid_submit_out submits an output 
> bulk urb to the device. ohci-hcd seems fine with that (at least it used 
> to, back in 2.4.x times), but uhci-hcd is not.
> 
> I commented out two lines in uhci-hcd to force it to accept to submit 
> bulk out urbs to low-speed devices:
> 
> static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb 
> *urb, struc
> t urb *eurb)
> {
>         int ret;
> 
>         /* Can't have low speed bulk transfers */
> /*      if (urb->dev->speed == USB_SPEED_LOW)
>                 return -EINVAL;*/
> 
> 
> It made by pad rumble, so this quick dirty fix does the job.
> Now, I don't know what the clean fix would be. Maybe change hid to 
> submit one-shot-interrupt out urbs when dealing with low-speed devices, 
> or just lift the restriction in uhci (I guess there are reasons for this 
> restriction, though).
> 
> PS: when replying, please include me. I am not subscribed to the list.

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...

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to