summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-huion.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/drivers/hid/hid-huion.c b/drivers/hid/hid-huion.c
index a683d4b4a531..61b68ca27790 100644
--- a/drivers/hid/hid-huion.c
+++ b/drivers/hid/hid-huion.c
@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
0xC0 /* End Collection */
};
+/* Parameter indices */
+enum huion_prm {
+ HUION_PRM_X_LM = 1,
+ HUION_PRM_Y_LM = 2,
+ HUION_PRM_PRESSURE_LM = 4,
+ HUION_PRM_RESOLUTION = 5,
+ HUION_PRM_NUM
+};
+
/* Driver data */
struct huion_drvdata {
__u8 *rdesc;
@@ -115,7 +124,8 @@ static int huion_tablet_enable(struct hid_device *hdev)
int rc;
struct usb_device *usb_dev = hid_to_usb_dev(hdev);
struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
- __le16 buf[6];
+ __le16 *buf = NULL;
+ size_t len;
s32 params[HUION_PH_ID_NUM];
s32 resolution;
__u8 *p;
@@ -127,27 +137,38 @@ static int huion_tablet_enable(struct hid_device *hdev)
* driver traffic.
* NOTE: This enables fully-functional tablet mode.
*/
+ len = HUION_PRM_NUM * sizeof(*buf);
+ buf = kmalloc(len, GFP_KERNEL);
+ if (buf == NULL) {
+ hid_err(hdev, "failed to allocate parameter buffer\n");
+ rc = -ENOMEM;
+ goto cleanup;
+ }
rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + 0x64,
- 0x0409, buf, sizeof(buf),
+ 0x0409, buf, len,
USB_CTRL_GET_TIMEOUT);
if (rc == -EPIPE) {
hid_err(hdev, "device parameters not found\n");
- return -ENODEV;
+ rc = -ENODEV;
+ goto cleanup;
} else if (rc < 0) {
hid_err(hdev, "failed to get device parameters: %d\n", rc);
- return -ENODEV;
- } else if (rc != sizeof(buf)) {
+ rc = -ENODEV;
+ goto cleanup;
+ } else if (rc != len) {
hid_err(hdev, "invalid device parameters\n");
- return -ENODEV;
+ rc = -ENODEV;
+ goto cleanup;
}
/* Extract device parameters */
- params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]);
- params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]);
- params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]);
- resolution = le16_to_cpu(buf[5]);
+ params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
+ params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
+ params[HUION_PH_ID_PRESSURE_LM] =
+ le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
+ resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
if (resolution == 0) {
params[HUION_PH_ID_X_PM] = 0;
params[HUION_PH_ID_Y_PM] = 0;
@@ -164,7 +185,8 @@ static int huion_tablet_enable(struct hid_device *hdev)
GFP_KERNEL);
if (drvdata->rdesc == NULL) {
hid_err(hdev, "failed to allocate fixed rdesc\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto cleanup;
}
drvdata->rsize = sizeof(huion_tablet_rdesc_template);
@@ -183,7 +205,11 @@ static int huion_tablet_enable(struct hid_device *hdev)
}
}
- return 0;
+ rc = 0;
+
+cleanup:
+ kfree(buf);
+ return rc;
}
static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)