Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: wacom: Remove static WACOM_PKGLEN_MAX limit

Rather than memcpy every packet that we receive from HID into our own
local fixed-size array, we can just access the data directly through
the original pointer. While we're at it, remove the few other places
that assume a fixed maximum packet size and make them dynamic (in
particular: temporary buffers created by the wacom_wac_queue_flush and
wacom_intuos_bt_process_data functions; and the pen_fifo FIFO).

To ensure pen_fifo allocation has access to the maximum used packet
length, this commit also moves the function call to occur a little
later in the probe process.

Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>

authored by

Jason Gerecke and committed by
Jiri Kosina
5e013ad2 58c9bf33

+27 -23
+21 -14
drivers/hid/wacom_sys.c
··· 69 69 struct kfifo_rec_ptr_2 *fifo) 70 70 { 71 71 while (!kfifo_is_empty(fifo)) { 72 - u8 buf[WACOM_PKGLEN_MAX]; 73 - int size; 72 + int size = kfifo_peek_len(fifo); 73 + u8 *buf = kzalloc(size, GFP_KERNEL); 74 + unsigned int count; 74 75 int err; 75 76 76 - size = kfifo_out(fifo, buf, sizeof(buf)); 77 + count = kfifo_out(fifo, buf, size); 78 + if (count != size) { 79 + // Hard to say what is the "right" action in this 80 + // circumstance. Skipping the entry and continuing 81 + // to flush seems reasonable enough, however. 82 + hid_warn(hdev, "%s: removed fifo entry with unexpected size\n", 83 + __func__); 84 + continue; 85 + } 77 86 err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false); 78 87 if (err) { 79 88 hid_warn(hdev, "%s: unable to flush event due to error %d\n", 80 89 __func__, err); 81 90 } 91 + 92 + kfree(buf); 82 93 } 83 94 } 84 95 ··· 169 158 if (wacom->wacom_wac.features.type == BOOTLOADER) 170 159 return 0; 171 160 172 - if (size > WACOM_PKGLEN_MAX) 173 - return 1; 174 - 175 161 if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size)) 176 162 return -1; 177 163 178 - memcpy(wacom->wacom_wac.data, raw_data, size); 164 + wacom->wacom_wac.data = raw_data; 179 165 180 166 wacom_wac_irq(&wacom->wacom_wac, size); 181 167 ··· 1294 1286 static int wacom_devm_kfifo_alloc(struct wacom *wacom) 1295 1287 { 1296 1288 struct wacom_wac *wacom_wac = &wacom->wacom_wac; 1289 + int fifo_size = min(PAGE_SIZE, 10 * wacom_wac->features.pktlen); 1297 1290 struct kfifo_rec_ptr_2 *pen_fifo; 1298 1291 int error; 1299 1292 ··· 1305 1296 if (!pen_fifo) 1306 1297 return -ENOMEM; 1307 1298 1308 - error = kfifo_alloc(pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL); 1299 + error = kfifo_alloc(pen_fifo, fifo_size, GFP_KERNEL); 1309 1300 if (error) { 1310 1301 devres_free(pen_fifo); 1311 1302 return error; ··· 2361 2352 unsigned int connect_mask = HID_CONNECT_HIDRAW; 2362 2353 2363 2354 features->pktlen = wacom_compute_pktlen(hdev); 2364 - if (features->pktlen > WACOM_PKGLEN_MAX) 2365 - return -EINVAL; 2366 2355 2367 2356 if (!devres_open_group(&hdev->dev, wacom, GFP_KERNEL)) 2368 2357 return -ENOMEM; 2358 + 2359 + error = wacom_devm_kfifo_alloc(wacom); 2360 + if (error) 2361 + goto fail; 2369 2362 2370 2363 wacom->resources = true; 2371 2364 ··· 2831 2820 2832 2821 if (features->check_for_hid_type && features->hid_type != hdev->type) 2833 2822 return -ENODEV; 2834 - 2835 - error = wacom_devm_kfifo_alloc(wacom); 2836 - if (error) 2837 - return error; 2838 2823 2839 2824 wacom_wac->hid_data.inputmode = -1; 2840 2825 wacom_wac->mode_report = -1;
+4 -4
drivers/hid/wacom_wac.c
··· 1201 1201 1202 1202 static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) 1203 1203 { 1204 - unsigned char data[WACOM_PKGLEN_MAX]; 1204 + u8 *data = kmemdup(wacom->data, len, GFP_KERNEL); 1205 1205 int i = 1; 1206 1206 unsigned power_raw, battery_capacity, bat_charging, ps_connected; 1207 - 1208 - memcpy(data, wacom->data, len); 1209 1207 1210 1208 switch (data[0]) { 1211 1209 case 0x04: ··· 1228 1230 dev_dbg(wacom->pen_input->dev.parent, 1229 1231 "Unknown report: %d,%d size:%zu\n", 1230 1232 data[0], data[1], len); 1231 - return 0; 1233 + break; 1232 1234 } 1235 + 1236 + kfree(data); 1233 1237 return 0; 1234 1238 } 1235 1239
+2 -5
drivers/hid/wacom_wac.h
··· 7 7 #include <linux/hid.h> 8 8 #include <linux/kfifo.h> 9 9 10 - /* maximum packet length for USB/BT devices */ 11 - #define WACOM_PKGLEN_MAX 361 12 - 13 10 #define WACOM_NAME_MAX 64 14 11 #define WACOM_MAX_REMOTES 5 15 12 #define WACOM_STATUS_UNKNOWN 255 ··· 274 277 unsigned touch_max; 275 278 int oVid; 276 279 int oPid; 277 - int pktlen; 280 + unsigned int pktlen; 278 281 bool check_for_hid_type; 279 282 int hid_type; 280 283 }; ··· 338 341 char pen_name[WACOM_NAME_MAX]; 339 342 char touch_name[WACOM_NAME_MAX]; 340 343 char pad_name[WACOM_NAME_MAX]; 341 - unsigned char data[WACOM_PKGLEN_MAX]; 344 + u8 *data; 342 345 int tool[2]; 343 346 int id[2]; 344 347 __u64 serial[2];