|
|
@@ -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,12 @@ 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;
|
|
|
+ s32 v;
|
|
|
|
|
|
/*
|
|
|
* Read string descriptor containing tablet parameters. The specific
|
|
|
@@ -123,65 +137,79 @@ 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_warn(hdev, "device parameters not found\n");
|
|
|
- else if (rc < 0)
|
|
|
- hid_warn(hdev, "failed to get device parameters: %d\n", rc);
|
|
|
- else if (rc != sizeof(buf))
|
|
|
- hid_warn(hdev, "invalid device parameters\n");
|
|
|
- else {
|
|
|
- s32 params[HUION_PH_ID_NUM];
|
|
|
- s32 resolution;
|
|
|
- __u8 *p;
|
|
|
- s32 v;
|
|
|
+ if (rc == -EPIPE) {
|
|
|
+ hid_err(hdev, "device parameters not found\n");
|
|
|
+ rc = -ENODEV;
|
|
|
+ goto cleanup;
|
|
|
+ } else if (rc < 0) {
|
|
|
+ hid_err(hdev, "failed to get device parameters: %d\n", rc);
|
|
|
+ rc = -ENODEV;
|
|
|
+ goto cleanup;
|
|
|
+ } else if (rc != len) {
|
|
|
+ hid_err(hdev, "invalid device parameters\n");
|
|
|
+ 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]);
|
|
|
- if (resolution == 0) {
|
|
|
- params[HUION_PH_ID_X_PM] = 0;
|
|
|
- params[HUION_PH_ID_Y_PM] = 0;
|
|
|
- } else {
|
|
|
- params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
|
|
|
- 1000 / resolution;
|
|
|
- params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
|
|
|
- 1000 / resolution;
|
|
|
- }
|
|
|
+ /* Extract device parameters */
|
|
|
+ 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;
|
|
|
+ } else {
|
|
|
+ params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
|
|
|
+ 1000 / resolution;
|
|
|
+ params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
|
|
|
+ 1000 / resolution;
|
|
|
+ }
|
|
|
|
|
|
- /* Allocate fixed report descriptor */
|
|
|
- drvdata->rdesc = devm_kmalloc(&hdev->dev,
|
|
|
- sizeof(huion_tablet_rdesc_template),
|
|
|
- GFP_KERNEL);
|
|
|
- if (drvdata->rdesc == NULL) {
|
|
|
- hid_err(hdev, "failed to allocate fixed rdesc\n");
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
- drvdata->rsize = sizeof(huion_tablet_rdesc_template);
|
|
|
+ /* Allocate fixed report descriptor */
|
|
|
+ drvdata->rdesc = devm_kmalloc(&hdev->dev,
|
|
|
+ sizeof(huion_tablet_rdesc_template),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (drvdata->rdesc == NULL) {
|
|
|
+ hid_err(hdev, "failed to allocate fixed rdesc\n");
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto cleanup;
|
|
|
+ }
|
|
|
+ drvdata->rsize = sizeof(huion_tablet_rdesc_template);
|
|
|
|
|
|
- /* Format fixed report descriptor */
|
|
|
- memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
|
|
|
- drvdata->rsize);
|
|
|
- for (p = drvdata->rdesc;
|
|
|
- p <= drvdata->rdesc + drvdata->rsize - 4;) {
|
|
|
- if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
|
|
|
- p[3] < sizeof(params)) {
|
|
|
- v = params[p[3]];
|
|
|
- put_unaligned(cpu_to_le32(v), (s32 *)p);
|
|
|
- p += 4;
|
|
|
- } else {
|
|
|
- p++;
|
|
|
- }
|
|
|
+ /* Format fixed report descriptor */
|
|
|
+ memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
|
|
|
+ drvdata->rsize);
|
|
|
+ for (p = drvdata->rdesc;
|
|
|
+ p <= drvdata->rdesc + drvdata->rsize - 4;) {
|
|
|
+ if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
|
|
|
+ p[3] < sizeof(params)) {
|
|
|
+ v = params[p[3]];
|
|
|
+ put_unaligned(cpu_to_le32(v), (s32 *)p);
|
|
|
+ p += 4;
|
|
|
+ } else {
|
|
|
+ p++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ rc = 0;
|
|
|
+
|
|
|
+cleanup:
|
|
|
+ kfree(buf);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
|