Commit 08a98b89df39d25a1260f390c19be4649dfd303d
Committed by
Marek Vasut
1 parent
ea42777567
Exists in
v2017.01-smarct4x
and in
40 other branches
usb: Fix USB keyboard polling via control endpoint
USB keyboard polling failed for some keyboards on PowerPC 5020. This was caused by requesting only 4 bytes of data from keyboards that produce an 8 byte HID report. Signed-off-by: Adrian Cox <adrian@humboldt.co.uk> Signed-off-by: Wolfgang Denk <wd@denx.de> Cc: Marek Vasut <marex@denx.de>
Showing 1 changed file with 25 additions and 11 deletions Side-by-side Diff
common/usb_kbd.c
... | ... | @@ -91,6 +91,12 @@ |
91 | 91 | #define USB_KBD_LEDMASK \ |
92 | 92 | (USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK) |
93 | 93 | |
94 | +/* | |
95 | + * USB Keyboard reports are 8 bytes in boot protocol. | |
96 | + * Appendix B of HID Device Class Definition 1.11 | |
97 | + */ | |
98 | +#define USB_KBD_BOOT_REPORT_SIZE 8 | |
99 | + | |
94 | 100 | struct usb_kbd_pdata { |
95 | 101 | uint32_t repeat_delay; |
96 | 102 | |
... | ... | @@ -99,7 +105,7 @@ |
99 | 105 | uint8_t usb_kbd_buffer[USB_KBD_BUFFER_LEN]; |
100 | 106 | |
101 | 107 | uint8_t *new; |
102 | - uint8_t old[8]; | |
108 | + uint8_t old[USB_KBD_BOOT_REPORT_SIZE]; | |
103 | 109 | |
104 | 110 | uint8_t flags; |
105 | 111 | }; |
... | ... | @@ -131,7 +137,8 @@ |
131 | 137 | /* Submit a interrupt transfer request */ |
132 | 138 | maxp = usb_maxpacket(usb_kbd_dev, pipe); |
133 | 139 | usb_submit_int_msg(usb_kbd_dev, pipe, data->new, |
134 | - maxp > 8 ? 8 : maxp, ep->bInterval); | |
140 | + min(maxp, USB_KBD_BOOT_REPORT_SIZE), | |
141 | + ep->bInterval); | |
135 | 142 | } |
136 | 143 | |
137 | 144 | /* Puts character in the queue and sets up the in and out pointer. */ |
138 | 145 | |
... | ... | @@ -266,8 +273,11 @@ |
266 | 273 | old = data->old; |
267 | 274 | } |
268 | 275 | |
269 | - if ((old[i] > 3) && (memscan(new + 2, old[i], 6) == new + 8)) | |
276 | + if ((old[i] > 3) && | |
277 | + (memscan(new + 2, old[i], USB_KBD_BOOT_REPORT_SIZE - 2) == | |
278 | + new + USB_KBD_BOOT_REPORT_SIZE)) { | |
270 | 279 | res |= usb_kbd_translate(data, old[i], data->new[0], up); |
280 | + } | |
271 | 281 | |
272 | 282 | return res; |
273 | 283 | } |
... | ... | @@ -285,7 +295,7 @@ |
285 | 295 | else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR)) |
286 | 296 | data->flags |= USB_KBD_CTRL; |
287 | 297 | |
288 | - for (i = 2; i < 8; i++) { | |
298 | + for (i = 2; i < USB_KBD_BOOT_REPORT_SIZE; i++) { | |
289 | 299 | res |= usb_kbd_service_key(dev, i, 0); |
290 | 300 | res |= usb_kbd_service_key(dev, i, 1); |
291 | 301 | } |
... | ... | @@ -297,7 +307,7 @@ |
297 | 307 | if (res == 1) |
298 | 308 | usb_kbd_setled(dev); |
299 | 309 | |
300 | - memcpy(data->old, data->new, 8); | |
310 | + memcpy(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE); | |
301 | 311 | |
302 | 312 | return 1; |
303 | 313 | } |
... | ... | @@ -305,7 +315,8 @@ |
305 | 315 | /* Keyboard interrupt handler */ |
306 | 316 | static int usb_kbd_irq(struct usb_device *dev) |
307 | 317 | { |
308 | - if ((dev->irq_status != 0) || (dev->irq_act_len != 8)) { | |
318 | + if ((dev->irq_status != 0) || | |
319 | + (dev->irq_act_len != USB_KBD_BOOT_REPORT_SIZE)) { | |
309 | 320 | debug("USB KBD: Error %lX, len %d\n", |
310 | 321 | dev->irq_status, dev->irq_act_len); |
311 | 322 | return 1; |
... | ... | @@ -333,7 +344,8 @@ |
333 | 344 | /* Submit a interrupt transfer request */ |
334 | 345 | maxp = usb_maxpacket(dev, pipe); |
335 | 346 | usb_submit_int_msg(dev, pipe, &data->new[0], |
336 | - maxp > 8 ? 8 : maxp, ep->bInterval); | |
347 | + min(maxp, USB_KBD_BOOT_REPORT_SIZE), | |
348 | + ep->bInterval); | |
337 | 349 | |
338 | 350 | usb_kbd_irq_worker(dev); |
339 | 351 | #elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) |
... | ... | @@ -341,8 +353,8 @@ |
341 | 353 | struct usb_kbd_pdata *data = dev->privptr; |
342 | 354 | iface = &dev->config.if_desc[0]; |
343 | 355 | usb_get_report(dev, iface->desc.bInterfaceNumber, |
344 | - 1, 0, data->new, sizeof(data->new)); | |
345 | - if (memcmp(data->old, data->new, sizeof(data->new))) | |
356 | + 1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE); | |
357 | + if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) | |
346 | 358 | usb_kbd_irq_worker(dev); |
347 | 359 | #endif |
348 | 360 | } |
... | ... | @@ -441,7 +453,8 @@ |
441 | 453 | memset(data, 0, sizeof(struct usb_kbd_pdata)); |
442 | 454 | |
443 | 455 | /* allocate input buffer aligned and sized to USB DMA alignment */ |
444 | - data->new = memalign(USB_DMA_MINALIGN, roundup(8, USB_DMA_MINALIGN)); | |
456 | + data->new = memalign(USB_DMA_MINALIGN, | |
457 | + roundup(USB_KBD_BOOT_REPORT_SIZE, USB_DMA_MINALIGN)); | |
445 | 458 | |
446 | 459 | /* Insert private data into USB device structure */ |
447 | 460 | dev->privptr = data; |
... | ... | @@ -459,7 +472,8 @@ |
459 | 472 | usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0); |
460 | 473 | |
461 | 474 | debug("USB KBD: enable interrupt pipe...\n"); |
462 | - if (usb_submit_int_msg(dev, pipe, data->new, maxp > 8 ? 8 : maxp, | |
475 | + if (usb_submit_int_msg(dev, pipe, data->new, | |
476 | + min(maxp, USB_KBD_BOOT_REPORT_SIZE), | |
463 | 477 | ep->bInterval) < 0) { |
464 | 478 | printf("Failed to get keyboard state from device %04x:%04x\n", |
465 | 479 | dev->descriptor.idVendor, dev->descriptor.idProduct); |