HID: usbhid: Fix warning caused by 0-length input reports
[linux-2.6-microblaze.git] / drivers / hid / usbhid / hid-core.c
index 4e90773..c56cb03 100644 (file)
@@ -377,27 +377,27 @@ static int hid_submit_ctrl(struct hid_device *hid)
        len = hid_report_len(report);
        if (dir == USB_DIR_OUT) {
                usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
-               usbhid->urbctrl->transfer_buffer_length = len;
                if (raw_report) {
                        memcpy(usbhid->ctrlbuf, raw_report, len);
                        kfree(raw_report);
                        usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
                }
        } else {
-               int maxpacket, padlen;
+               int maxpacket;
 
                usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
                maxpacket = usb_maxpacket(hid_to_usb_dev(hid),
                                          usbhid->urbctrl->pipe, 0);
                if (maxpacket > 0) {
-                       padlen = DIV_ROUND_UP(len, maxpacket);
-                       padlen *= maxpacket;
-                       if (padlen > usbhid->bufsize)
-                               padlen = usbhid->bufsize;
+                       len += (len == 0);    /* Don't allow 0-length reports */
+                       len = DIV_ROUND_UP(len, maxpacket);
+                       len *= maxpacket;
+                       if (len > usbhid->bufsize)
+                               len = usbhid->bufsize;
                } else
-                       padlen = 0;
-               usbhid->urbctrl->transfer_buffer_length = padlen;
+                       len = 0;
        }
+       usbhid->urbctrl->transfer_buffer_length = len;
        usbhid->urbctrl->dev = hid_to_usb_dev(hid);
 
        usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
@@ -505,7 +505,7 @@ static void hid_ctrl(struct urb *urb)
 
        if (unplug) {
                usbhid->ctrltail = usbhid->ctrlhead;
-       } else {
+       } else if (usbhid->ctrlhead != usbhid->ctrltail) {
                usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
                if (usbhid->ctrlhead != usbhid->ctrltail &&
@@ -1223,9 +1223,20 @@ static void usbhid_stop(struct hid_device *hid)
        mutex_lock(&usbhid->mutex);
 
        clear_bit(HID_STARTED, &usbhid->iofl);
+
        spin_lock_irq(&usbhid->lock);   /* Sync with error and led handlers */
        set_bit(HID_DISCONNECTED, &usbhid->iofl);
+       while (usbhid->ctrltail != usbhid->ctrlhead) {
+               if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_OUT) {
+                       kfree(usbhid->ctrl[usbhid->ctrltail].raw_report);
+                       usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
+               }
+
+               usbhid->ctrltail = (usbhid->ctrltail + 1) &
+                       (HID_CONTROL_FIFO_SIZE - 1);
+       }
        spin_unlock_irq(&usbhid->lock);
+
        usb_kill_urb(usbhid->urbin);
        usb_kill_urb(usbhid->urbout);
        usb_kill_urb(usbhid->urbctrl);
@@ -1304,6 +1315,13 @@ static int usbhid_idle(struct hid_device *hid, int report, int idle,
        return hid_set_idle(dev, ifnum, report, idle);
 }
 
+static bool usbhid_may_wakeup(struct hid_device *hid)
+{
+       struct usb_device *dev = hid_to_usb_dev(hid);
+
+       return device_may_wakeup(&dev->dev);
+}
+
 struct hid_ll_driver usb_hid_driver = {
        .parse = usbhid_parse,
        .start = usbhid_start,
@@ -1316,6 +1334,7 @@ struct hid_ll_driver usb_hid_driver = {
        .raw_request = usbhid_raw_request,
        .output_report = usbhid_output_report,
        .idle = usbhid_idle,
+       .may_wakeup = usbhid_may_wakeup,
 };
 EXPORT_SYMBOL_GPL(usb_hid_driver);