Commit 6498d023 authored by Nikolai Kondrashov's avatar Nikolai Kondrashov Committed by Jiri Kosina

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: default avatarNikolai Kondrashov <spbnick@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 657d6dc4
...@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = { ...@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
0xC0 /* End Collection */ 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 */ /* Driver data */
struct huion_drvdata { struct huion_drvdata {
__u8 *rdesc; __u8 *rdesc;
...@@ -115,7 +124,8 @@ static int huion_tablet_enable(struct hid_device *hdev) ...@@ -115,7 +124,8 @@ static int huion_tablet_enable(struct hid_device *hdev)
int rc; int rc;
struct usb_device *usb_dev = hid_to_usb_dev(hdev); struct usb_device *usb_dev = hid_to_usb_dev(hdev);
struct huion_drvdata *drvdata = hid_get_drvdata(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 params[HUION_PH_ID_NUM];
s32 resolution; s32 resolution;
__u8 *p; __u8 *p;
...@@ -127,27 +137,38 @@ static int huion_tablet_enable(struct hid_device *hdev) ...@@ -127,27 +137,38 @@ static int huion_tablet_enable(struct hid_device *hdev)
* driver traffic. * driver traffic.
* NOTE: This enables fully-functional tablet mode. * 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), rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + 0x64, (USB_DT_STRING << 8) + 0x64,
0x0409, buf, sizeof(buf), 0x0409, buf, len,
USB_CTRL_GET_TIMEOUT); USB_CTRL_GET_TIMEOUT);
if (rc == -EPIPE) { if (rc == -EPIPE) {
hid_err(hdev, "device parameters not found\n"); hid_err(hdev, "device parameters not found\n");
return -ENODEV; rc = -ENODEV;
goto cleanup;
} else if (rc < 0) { } else if (rc < 0) {
hid_err(hdev, "failed to get device parameters: %d\n", rc); hid_err(hdev, "failed to get device parameters: %d\n", rc);
return -ENODEV; rc = -ENODEV;
} else if (rc != sizeof(buf)) { goto cleanup;
} else if (rc != len) {
hid_err(hdev, "invalid device parameters\n"); hid_err(hdev, "invalid device parameters\n");
return -ENODEV; rc = -ENODEV;
goto cleanup;
} }
/* Extract device parameters */ /* Extract device parameters */
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]); params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]); params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]); params[HUION_PH_ID_PRESSURE_LM] =
resolution = le16_to_cpu(buf[5]); le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
if (resolution == 0) { if (resolution == 0) {
params[HUION_PH_ID_X_PM] = 0; params[HUION_PH_ID_X_PM] = 0;
params[HUION_PH_ID_Y_PM] = 0; params[HUION_PH_ID_Y_PM] = 0;
...@@ -164,7 +185,8 @@ static int huion_tablet_enable(struct hid_device *hdev) ...@@ -164,7 +185,8 @@ static int huion_tablet_enable(struct hid_device *hdev)
GFP_KERNEL); GFP_KERNEL);
if (drvdata->rdesc == NULL) { if (drvdata->rdesc == NULL) {
hid_err(hdev, "failed to allocate fixed rdesc\n"); hid_err(hdev, "failed to allocate fixed rdesc\n");
return -ENOMEM; rc = -ENOMEM;
goto cleanup;
} }
drvdata->rsize = sizeof(huion_tablet_rdesc_template); drvdata->rsize = sizeof(huion_tablet_rdesc_template);
...@@ -183,7 +205,11 @@ static int huion_tablet_enable(struct hid_device *hdev) ...@@ -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) static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment