mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Christian Krause <chkr@plauener.de>
To: linux-kernel@vger.kernel.org
Subject: bug in handling of highspeed usb HID devices
Date: Wed, 12 Oct 2005 21:55:32 +0200	[thread overview]
Message-ID: <m34q7mwlvv.fsf@gondor.middle-earth.priv> (raw)

Hi folks,

During the development of an USB device I found a bug in the handling of
Highspeed HID devices in the kernel.

What happened?

Highspeed HID devices are correctly recognized and enumerated by the
kernel. But even if usbhid kernel module is loaded, no HID reports are
received by the kernel.

The output of the hardware USB analyzer told me that the host doesn't
even poll for interrupt IN transfers (even the "interrupt in" USB
transfer are polled by the host).


After some debugging in hid-core.c I've found the reason.

In case of a highspeed device, the endpoint interval is re-calculated in
driver/usb/input/hid-core.c:

line 1669:
             /* handle potential highspeed HID correctly */
             interval = endpoint->bInterval;
             if (dev->speed == USB_SPEED_HIGH)
                   interval = 1 << (interval - 1);

Basically this calculation is correct (refer to USB 2.0 spec, 9.6.6).
This new calculated value of "interval" is used as input for
usb_fill_int_urb:

line 1685:

            usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
                   hid_irq_in, hid, interval);

Unfortunately the same calculation as above is done a second time in 
usb_fill_int_urb in the file include/linux/usb.h:

line 933:
        if (dev->speed == USB_SPEED_HIGH)
                urb->interval = 1 << (interval - 1);
        else
                urb->interval = interval;

This means, that if the endpoint descriptor (of a high speed device)
specifies e.g. bInterval = 7, the urb->interval gets the value:

hid-core.c: interval = 1 << (7-1) = 0x40 = 64
urb->interval = 1 << (interval -1) = 1 << (63) = integer overflow

Because of this the value of urb->interval is sometimes negative and is
rejected in core/urb.c:
line 353:
                /* too small? */
                if (urb->interval <= 0)
                        return -EINVAL;


The conclusion is, that the recalculaton of the interval (which is
necessary for highspeed) should not be made twice, because this is
simply wrong. ;-)


Re-calculation in usb_fill_int_urb makes more sense, because it is the
most general approach. So it would make sense to remove it from
hid-core.c.


Because in hid-core.c the interval variable is only used for calling
usb_fill_int_urb, it is no problem to remove the highspeed
re-calculation in this file.

Here is a small patch which solves the whole problem:

--------------------------
--- hid-core.c.old      2005-10-12 21:29:29.000000000 +0200
+++ hid-core.c  2005-10-12 21:31:02.000000000 +0200
@@ -1667,11 +1667,6 @@
                if ((endpoint->bmAttributes & 3) != 3)          /* Not an interrupt endpoint */
                        continue;
 
-               /* handle potential highspeed HID correctly */
-               interval = endpoint->bInterval;
-               if (dev->speed == USB_SPEED_HIGH)
-                       interval = 1 << (interval - 1);
-
                /* Change the polling interval of mice. */
                if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
                        interval = hid_mousepoll_interval;

----------------------------

Please review my investigation and if you come to the same conclusion
please apply this patch in the next kernel versions. If not, please tell
me why. ;-)


Best regards,
Christian

             reply	other threads:[~2005-10-12 19:55 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-10-12 19:55 Christian Krause [this message]
2005-10-13 22:48 ` Greg KH
2005-10-14 17:57   ` [PATCH] " Christian Krause
2005-10-14 23:42     ` Greg KH
2005-10-15  1:43       ` Parag Warudkar
2005-10-15  2:18         ` Greg KH
2005-10-15  8:24           ` Christian Krause
2005-10-14 17:57   ` Christian Krause
2005-10-14 18:09     ` Greg KH
2005-10-12 21:10 kernel-stuff
2005-10-12 21:42 ` Christian Krause
2005-10-12 23:32 Parag Warudkar
2005-10-13 18:05 ` Christian Krause
2005-10-13 20:11 Parag Warudkar
2005-10-13 20:25 ` Andrew Morton
2005-10-14  2:10 Parag Warudkar
2005-10-14  3:31 ` Greg KH
2005-10-14 15:21 kernel-stuff

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m34q7mwlvv.fsf@gondor.middle-earth.priv \
    --to=chkr@plauener.de \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®