aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolai Kondrashov <spbnick@gmail.com>2014-08-11 13:45:32 -0400
committerJiri Kosina <jkosina@suse.cz>2014-08-12 06:44:59 -0400
commit6498d02306b337393b0bc92164857f3e6949c4e8 (patch)
tree9e1e243f2584375c902ed64c23f59d03e42cadd3
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>
-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[] = {
84 0xC0 /* End Collection */ 84 0xC0 /* End Collection */
85}; 85};
86 86
87/* Parameter indices */
88enum huion_prm {
89 HUION_PRM_X_LM = 1,
90 HUION_PRM_Y_LM = 2,
91 HUION_PRM_PRESSURE_LM = 4,
92 HUION_PRM_RESOLUTION = 5,
93 HUION_PRM_NUM
94};
95
87/* Driver data */ 96/* Driver data */
88struct huion_drvdata { 97struct huion_drvdata {
89 __u8 *rdesc; 98 __u8 *rdesc;
@@ -115,7 +124,8 @@ static int huion_tablet_enable(struct hid_device *hdev)
115 int rc; 124 int rc;
116 struct usb_device *usb_dev = hid_to_usb_dev(hdev); 125 struct usb_device *usb_dev = hid_to_usb_dev(hdev);
117 struct huion_drvdata *drvdata = hid_get_drvdata(hdev); 126 struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
118 __le16 buf[6]; 127 __le16 *buf = NULL;
128 size_t len;
119 s32 params[HUION_PH_ID_NUM]; 129 s32 params[HUION_PH_ID_NUM];
120 s32 resolution; 130 s32 resolution;
121 __u8 *p; 131 __u8 *p;
@@ -127,27 +137,38 @@ static int huion_tablet_enable(struct hid_device *hdev)
127 * driver traffic. 137 * driver traffic.
128 * NOTE: This enables fully-functional tablet mode. 138 * NOTE: This enables fully-functional tablet mode.
129 */ 139 */
140 len = HUION_PRM_NUM * sizeof(*buf);
141 buf = kmalloc(len, GFP_KERNEL);
142 if (buf == NULL) {
143 hid_err(hdev, "failed to allocate parameter buffer\n");
144 rc = -ENOMEM;
145 goto cleanup;
146 }
130 rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 147 rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
131 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, 148 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
132 (USB_DT_STRING << 8) + 0x64, 149 (USB_DT_STRING << 8) + 0x64,
133 0x0409, buf, sizeof(buf), 150 0x0409, buf, len,
134 USB_CTRL_GET_TIMEOUT); 151 USB_CTRL_GET_TIMEOUT);
135 if (rc == -EPIPE) { 152 if (rc == -EPIPE) {
136 hid_err(hdev, "device parameters not found\n"); 153 hid_err(hdev, "device parameters not found\n");
137 return -ENODEV; 154 rc = -ENODEV;
155 goto cleanup;
138 } else if (rc < 0) { 156 } else if (rc < 0) {
139 hid_err(hdev, "failed to get device parameters: %d\n", rc); 157 hid_err(hdev, "failed to get device parameters: %d\n", rc);
140 return -ENODEV; 158 rc = -ENODEV;
141 } else if (rc != sizeof(buf)) { 159 goto cleanup;
160 } else if (rc != len) {
142 hid_err(hdev, "invalid device parameters\n"); 161 hid_err(hdev, "invalid device parameters\n");
143 return -ENODEV; 162 rc = -ENODEV;
163 goto cleanup;
144 } 164 }
145 165
146 /* Extract device parameters */ 166 /* Extract device parameters */
147 params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]); 167 params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
148 params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]); 168 params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
149 params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]); 169 params[HUION_PH_ID_PRESSURE_LM] =
150 resolution = le16_to_cpu(buf[5]); 170 le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
171 resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
151 if (resolution == 0) { 172 if (resolution == 0) {
152 params[HUION_PH_ID_X_PM] = 0; 173 params[HUION_PH_ID_X_PM] = 0;
153 params[HUION_PH_ID_Y_PM] = 0; 174 params[HUION_PH_ID_Y_PM] = 0;
@@ -164,7 +185,8 @@ static int huion_tablet_enable(struct hid_device *hdev)
164 GFP_KERNEL); 185 GFP_KERNEL);
165 if (drvdata->rdesc == NULL) { 186 if (drvdata->rdesc == NULL) {
166 hid_err(hdev, "failed to allocate fixed rdesc\n"); 187 hid_err(hdev, "failed to allocate fixed rdesc\n");
167 return -ENOMEM; 188 rc = -ENOMEM;
189 goto cleanup;
168 } 190 }
169 drvdata->rsize = sizeof(huion_tablet_rdesc_template); 191 drvdata->rsize = sizeof(huion_tablet_rdesc_template);
170 192
@@ -183,7 +205,11 @@ static int huion_tablet_enable(struct hid_device *hdev)
183 } 205 }
184 } 206 }
185 207
186 return 0; 208 rc = 0;
209
210cleanup:
211 kfree(buf);
212 return rc;
187} 213}
188 214
189static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id) 215static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)