]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'master' into for-3.12/upstream
authorJiri Kosina <jkosina@suse.cz>
Wed, 4 Sep 2013 08:49:39 +0000 (10:49 +0200)
committerJiri Kosina <jkosina@suse.cz>
Wed, 4 Sep 2013 08:49:57 +0000 (10:49 +0200)
Sync with Linus' tree to be able to apply fixup patch on top
of 9d9a04ee75 ("HID: apple: Add support for the 2013 Macbook Air")

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1  2 
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-dj.c
drivers/hid/hidraw.c
net/bluetooth/hidp/core.c

diff --combined drivers/hid/hid-core.c
index 3c28e5bf3675159a1bc9aeb7f127e83edf5d8b7c,36668d1aca8fc2133299e93cf994857d78cbea2e..ebf57813d31a0a6c78034301689a6ca5da766bb9
@@@ -450,7 -450,7 +450,7 @@@ static int hid_parser_local(struct hid_
                        }
                        parser->local.delimiter_depth--;
                }
 -              return 1;
 +              return 0;
  
        case HID_LOCAL_ITEM_TAG_USAGE:
  
@@@ -1128,8 -1128,7 +1128,8 @@@ static void hid_output_field(const stru
  }
  
  /*
 - * Create a report.
 + * Create a report. 'data' has to be allocated using
 + * hid_alloc_report_buf() so that it has proper size.
   */
  
  void hid_output_report(struct hid_report *report, __u8 *data)
  }
  EXPORT_SYMBOL_GPL(hid_output_report);
  
 +/*
 + * Allocator for buffer that is going to be passed to hid_output_report()
 + */
 +u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
 +{
 +      /*
 +       * 7 extra bytes are necessary to achieve proper functionality
 +       * of implement() working on 8 byte chunks
 +       */
 +
 +      int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
 +
 +      return kmalloc(len, flags);
 +}
 +EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
 +
  /*
   * Set a field value. The report this field belongs to has to be
   * created and transferred to the device, to set this value in the
@@@ -1564,6 -1547,9 +1564,9 @@@ static const struct hid_device_id hid_h
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
@@@ -2209,6 -2192,9 +2212,9 @@@ static const struct hid_device_id hid_m
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
diff --combined drivers/hid/hid-ids.h
index 6ad292eee4ce5911471ec9645361d72415fb704c,ffe4c7ae3340150cdcfb8c9f3db9c241422cf8eb..9386df57f19587b93e35ca50a0617077420eb007
  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI  0x0255
  #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
+ #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI  0x0291
+ #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO   0x0292
+ #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS   0x0293
  #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY  0x030a
  #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY   0x030b
  #define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
  #define USB_VENDOR_ID_KYE             0x0458
  #define USB_DEVICE_ID_KYE_ERGO_525V   0x0087
  #define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE        0x0138
 +#define USB_DEVICE_ID_GENIUS_GX_IMPERATOR     0x4018
  #define USB_DEVICE_ID_KYE_GPEN_560    0x5003
  #define USB_DEVICE_ID_KYE_EASYPEN_I405X       0x5010
  #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X      0x5011
  #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16   0x0012
  #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17   0x0013
  #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18   0x0014
 +#define USB_DEVICE_ID_NTRIG_DUOSENSE 0x1500
  
  #define USB_VENDOR_ID_ONTRAK          0x0a07
  #define USB_DEVICE_ID_ONTRAK_ADU100   0x0064
  #define USB_DEVICE_ID_ROCCAT_KONE     0x2ced
  #define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
  #define USB_DEVICE_ID_ROCCAT_KONEPURE 0x2dbe
 +#define USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL 0x2db4
  #define USB_DEVICE_ID_ROCCAT_KONEXTD  0x2e22
  #define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
  #define USB_DEVICE_ID_ROCCAT_LUA      0x2c2e
  #define USB_VENDOR_ID_XAT     0x2505
  #define USB_DEVICE_ID_XAT_CSR 0x0220
  
 +#define USB_VENDOR_ID_XIN_MO                  0x16c0
 +#define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE      0x05e1
 +
  #define USB_VENDOR_ID_XIROKU          0x1477
  #define USB_DEVICE_ID_XIROKU_SPX      0x1006
  #define USB_DEVICE_ID_XIROKU_MPX      0x1007
index d318222c63157e80a1e4b39155f15d95683a28a1,cd33084c78602146d42efca60e358d08f00da219..d0e5963c1ba189a877ece23123839d8f3a29df8c
@@@ -192,6 -192,7 +192,7 @@@ static struct hid_ll_driver logi_dj_ll_
  static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
                                        size_t count,
                                        unsigned char report_type);
+ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
  
  static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
                                                struct dj_report *dj_report)
@@@ -232,6 -233,7 +233,7 @@@ static void logi_dj_recv_add_djhid_devi
        if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
            SPFUNCTION_DEVICE_LIST_EMPTY) {
                dbg_hid("%s: device list is empty\n", __func__);
+               djrcv_dev->querying_devices = false;
                return;
        }
  
                return;
        }
  
+       if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
+               /* The device is already known. No need to reallocate it. */
+               dbg_hid("%s: device is already known\n", __func__);
+               return;
+       }
        dj_hiddev = hid_allocate_device();
        if (IS_ERR(dj_hiddev)) {
                dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@@@ -305,6 -313,7 +313,7 @@@ static void delayedwork_callback(struc
        struct dj_report dj_report;
        unsigned long flags;
        int count;
+       int retval;
  
        dbg_hid("%s\n", __func__);
  
                logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
                break;
        default:
+       /* A normal report (i. e. not belonging to a pair/unpair notification)
+        * arriving here, means that the report arrived but we did not have a
+        * paired dj_device associated to the report's device_index, this
+        * means that the original "device paired" notification corresponding
+        * to this dj_device never arrived to this driver. The reason is that
+        * hid-core discards all packets coming from a device while probe() is
+        * executing. */
+       if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
+               /* ok, we don't know the device, just re-ask the
+                * receiver for the list of connected devices. */
+               retval = logi_dj_recv_query_paired_devices(djrcv_dev);
+               if (!retval) {
+                       /* everything went fine, so just leave */
+                       break;
+               }
+               dev_err(&djrcv_dev->hdev->dev,
+                       "%s:logi_dj_recv_query_paired_devices "
+                       "error:%d\n", __func__, retval);
+               }
                dbg_hid("%s: unexpected report type\n", __func__);
        }
  }
@@@ -367,6 -395,12 +395,12 @@@ static void logi_dj_recv_forward_null_r
        if (!djdev) {
                dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
                        " is NULL, index %d\n", dj_report->device_index);
+               kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+               if (schedule_work(&djrcv_dev->work) == 0) {
+                       dbg_hid("%s: did not schedule the work item, was already "
+                       "queued\n", __func__);
+               }
                return;
        }
  
@@@ -397,6 -431,12 +431,12 @@@ static void logi_dj_recv_forward_report
        if (dj_device == NULL) {
                dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
                        " is NULL, index %d\n", dj_report->device_index);
+               kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+               if (schedule_work(&djrcv_dev->work) == 0) {
+                       dbg_hid("%s: did not schedule the work item, was already "
+                       "queued\n", __func__);
+               }
                return;
        }
  
@@@ -444,6 -484,10 +484,10 @@@ static int logi_dj_recv_query_paired_de
        struct dj_report *dj_report;
        int retval;
  
+       /* no need to protect djrcv_dev->querying_devices */
+       if (djrcv_dev->querying_devices)
+               return 0;
        dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
        if (!dj_report)
                return -ENOMEM;
        return retval;
  }
  
  static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
                                          unsigned timeout)
  {
@@@ -574,7 -619,7 +619,7 @@@ static int logi_dj_ll_input_event(struc
  
        struct hid_field *field;
        struct hid_report *report;
 -      unsigned char data[8];
 +      unsigned char *data;
        int offset;
  
        dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
                return -1;
        }
        hid_set_field(field, offset, value);
 +
 +      data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
 +      if (!data) {
 +              dev_warn(&dev->dev, "failed to allocate report buf memory\n");
 +              return -1;
 +      }
 +
        hid_output_report(field->report, &data[0]);
  
        output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
  
        hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
  
 -      return 0;
 +      kfree(data);
  
 +      return 0;
  }
  
  static int logi_dj_ll_start(struct hid_device *hid)
diff --combined drivers/hid/hidraw.c
index 194a5660a389b7339d7707aff0d3fd8f7d66e92c,6f1feb2c2e97b5defb0628d92bfc98a719449685..8918dd12bb6915d08ab588e04b22b64a24d6e827
@@@ -113,7 -113,7 +113,7 @@@ static ssize_t hidraw_send_report(struc
        __u8 *buf;
        int ret = 0;
  
 -      if (!hidraw_table[minor]) {
 +      if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
                ret = -ENODEV;
                goto out;
        }
@@@ -253,7 -253,6 +253,7 @@@ static int hidraw_open(struct inode *in
        unsigned int minor = iminor(inode);
        struct hidraw *dev;
        struct hidraw_list *list;
 +      unsigned long flags;
        int err = 0;
  
        if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
        }
  
        mutex_lock(&minors_lock);
 -      if (!hidraw_table[minor]) {
 +      if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
                err = -ENODEV;
                goto out_unlock;
        }
  
 -      list->hidraw = hidraw_table[minor];
 -      mutex_init(&list->read_mutex);
 -      list_add_tail(&list->node, &hidraw_table[minor]->list);
 -      file->private_data = list;
 -
        dev = hidraw_table[minor];
        if (!dev->open++) {
                err = hid_hw_power(dev->hid, PM_HINT_FULLON);
                if (err < 0) {
                        hid_hw_power(dev->hid, PM_HINT_NORMAL);
                        dev->open--;
 +                      goto out_unlock;
                }
        }
  
 +      list->hidraw = hidraw_table[minor];
 +      mutex_init(&list->read_mutex);
 +      spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
 +      list_add_tail(&list->node, &hidraw_table[minor]->list);
 +      spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
 +      file->private_data = list;
  out_unlock:
        mutex_unlock(&minors_lock);
  out:
@@@ -305,41 -302,39 +305,41 @@@ static int hidraw_fasync(int fd, struc
        return fasync_helper(fd, file, on, &list->fasync);
  }
  
 +static void drop_ref(struct hidraw *hidraw, int exists_bit)
 +{
 +      if (exists_bit) {
 +              hid_hw_close(hidraw->hid);
 +              hidraw->exist = 0;
 +              if (hidraw->open)
 +                      wake_up_interruptible(&hidraw->wait);
 +      } else {
 +              --hidraw->open;
 +      }
 +
 +      if (!hidraw->open && !hidraw->exist) {
 +              device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 +              hidraw_table[hidraw->minor] = NULL;
 +              kfree(hidraw);
 +      }
 +}
 +
  static int hidraw_release(struct inode * inode, struct file * file)
  {
        unsigned int minor = iminor(inode);
 -      struct hidraw *dev;
        struct hidraw_list *list = file->private_data;
 -      int ret;
 -      int i;
 +      unsigned long flags;
  
        mutex_lock(&minors_lock);
 -      if (!hidraw_table[minor]) {
 -              ret = -ENODEV;
 -              goto unlock;
 -      }
  
 +      spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
        list_del(&list->node);
 -      dev = hidraw_table[minor];
 -      if (!--dev->open) {
 -              if (list->hidraw->exist) {
 -                      hid_hw_power(dev->hid, PM_HINT_NORMAL);
 -                      hid_hw_close(dev->hid);
 -              } else {
 -                      kfree(list->hidraw);
 -              }
 -      }
 -
 -      for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
 -              kfree(list->buffer[i].value);
 +      spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
        kfree(list);
 -      ret = 0;
 -unlock:
 -      mutex_unlock(&minors_lock);
  
 -      return ret;
 +      drop_ref(hidraw_table[minor], 0);
 +
 +      mutex_unlock(&minors_lock);
 +      return 0;
  }
  
  static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@@ -462,9 -457,7 +462,9 @@@ int hidraw_report_event(struct hid_devi
        struct hidraw *dev = hid->hidraw;
        struct hidraw_list *list;
        int ret = 0;
 +      unsigned long flags;
  
 +      spin_lock_irqsave(&dev->list_lock, flags);
        list_for_each_entry(list, &dev->list, node) {
                int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
  
                list->head = new_head;
                kill_fasync(&list->fasync, SIGIO, POLL_IN);
        }
 +      spin_unlock_irqrestore(&dev->list_lock, flags);
  
        wake_up_interruptible(&dev->wait);
        return ret;
@@@ -526,9 -518,7 +526,8 @@@ int hidraw_connect(struct hid_device *h
                goto out;
        }
  
-       mutex_unlock(&minors_lock);
        init_waitqueue_head(&dev->wait);
 +      spin_lock_init(&dev->list_lock);
        INIT_LIST_HEAD(&dev->list);
  
        dev->hid = hid;
        dev->exist = 1;
        hid->hidraw = dev;
  
+       mutex_unlock(&minors_lock);
  out:
        return result;
  
@@@ -548,9 -539,18 +548,9 @@@ void hidraw_disconnect(struct hid_devic
        struct hidraw *hidraw = hid->hidraw;
  
        mutex_lock(&minors_lock);
 -      hidraw->exist = 0;
  
 -      device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 +      drop_ref(hidraw, 1);
  
 -      hidraw_table[hidraw->minor] = NULL;
 -
 -      if (hidraw->open) {
 -              hid_hw_close(hid);
 -              wake_up_interruptible(&hidraw->wait);
 -      } else {
 -              kfree(hidraw);
 -      }
        mutex_unlock(&minors_lock);
  }
  EXPORT_SYMBOL_GPL(hidraw_disconnect);
index 2e658ade4454365ccb20c7fb6a062a4d17697442,0c699cdc3696edbdf7e7c3d3e213a88979da662e..d38ab152700698baf92f3e7dc128495f3beca713
@@@ -76,25 -76,19 +76,19 @@@ static void hidp_copy_session(struct hi
        ci->flags = session->flags;
        ci->state = BT_CONNECTED;
  
-       ci->vendor  = 0x0000;
-       ci->product = 0x0000;
-       ci->version = 0x0000;
        if (session->input) {
                ci->vendor  = session->input->id.vendor;
                ci->product = session->input->id.product;
                ci->version = session->input->id.version;
                if (session->input->name)
-                       strncpy(ci->name, session->input->name, 128);
+                       strlcpy(ci->name, session->input->name, 128);
                else
-                       strncpy(ci->name, "HID Boot Device", 128);
-       }
-       if (session->hid) {
+                       strlcpy(ci->name, "HID Boot Device", 128);
+       } else if (session->hid) {
                ci->vendor  = session->hid->vendor;
                ci->product = session->hid->product;
                ci->version = session->hid->version;
-               strncpy(ci->name, session->hid->name, 128);
+               strlcpy(ci->name, session->hid->name, 128);
        }
  }
  
@@@ -231,22 -225,17 +225,22 @@@ static void hidp_input_report(struct hi
  
  static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
  {
 -      unsigned char buf[32], hdr;
 -      int rsize;
 +      unsigned char hdr;
 +      u8 *buf;
 +      int rsize, ret;
  
 -      rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 -      if (rsize > sizeof(buf))
 +      buf = hid_alloc_report_buf(report, GFP_ATOMIC);
 +      if (!buf)
                return -EIO;
  
        hid_output_report(report, buf);
        hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
  
 -      return hidp_send_intr_message(session, hdr, buf, rsize);
 +      rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 +      ret = hidp_send_intr_message(session, hdr, buf, rsize);
 +
 +      kfree(buf);
 +      return ret;
  }
  
  static int hidp_get_raw_report(struct hid_device *hid,