summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
authorNikolai Kondrashov <spbnick@gmail.com>2014-08-11 20:45:32 +0300
committerJiri Kosina <jkosina@suse.cz>2014-08-12 12:44:59 +0200
commit6498d02306b337393b0bc92164857f3e6949c4e8 (patch)
tree9e1e243f2584375c902ed64c23f59d03e42cadd3 /drivers/hid
parent657d6dc4197e9bc13522d0ed0e1a4ae7d0d84614 (diff)
HID: huion: Use allocated buffer for DMA
Allocate a buffer with kmalloc for receiving the parameters string descriptor with usb_control_msg, instead of using a buffer on the stack, as the latter is unsafe. Use an enum for indices into the buffer to ensure the buffer size if sufficient. This fixes the static checker error "doing dma on the stack (buf)". Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
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)