Skip to content

Commit

Permalink
HID: huion: Use allocated buffer for DMA
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Nikolai Kondrashov authored and Jiri Kosina committed Aug 12, 2014
1 parent 657d6dc commit 6498d02
Showing 1 changed file with 38 additions and 12 deletions.
50 changes: 38 additions & 12 deletions drivers/hid/hid-huion.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);

Expand All @@ -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)
Expand Down

0 comments on commit 6498d02

Please sign in to comment.