Blame view
common/usb_kbd.c
16.1 KB
affae2bff Initial revision |
1 2 3 4 5 6 7 |
/* * (C) Copyright 2001 * Denis Peter, MPL AG Switzerland * * Part of this source has been derived from the Linux USB * project. * |
1a4596601 Add GPL-2.0+ SPDX... |
8 |
* SPDX-License-Identifier: GPL-2.0+ |
affae2bff Initial revision |
9 10 |
*/ #include <common.h> |
24b852a7a Move console defi... |
11 |
#include <console.h> |
697033cbf dm: usb: Support ... |
12 |
#include <dm.h> |
0ea09dfe8 usb: kbd: Do not ... |
13 |
#include <errno.h> |
9a8c72a6c USB: Rework usb_k... |
14 |
#include <malloc.h> |
cf92e05c0 Move ALLOC_CACHE_... |
15 |
#include <memalign.h> |
52cb4d4fb stdio/device: rew... |
16 |
#include <stdio_dev.h> |
c918261c6 USB: replace old ... |
17 |
#include <asm/byteorder.h> |
affae2bff Initial revision |
18 |
|
affae2bff Initial revision |
19 |
#include <usb.h> |
affae2bff Initial revision |
20 |
/* |
00b7d6ecc USB: Squash check... |
21 |
* If overwrite_console returns 1, the stdin, stderr and stdout |
affae2bff Initial revision |
22 23 24 |
* are switched to the serial port, else the settings in the * environment are used */ |
6d0f6bcf3 rename CFG_ macro... |
25 |
#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE |
00b7d6ecc USB: Squash check... |
26 |
extern int overwrite_console(void); |
affae2bff Initial revision |
27 |
#else |
00b7d6ecc USB: Squash check... |
28 |
int overwrite_console(void) |
affae2bff Initial revision |
29 |
{ |
00b7d6ecc USB: Squash check... |
30 |
return 0; |
affae2bff Initial revision |
31 32 |
} #endif |
9a8c72a6c USB: Rework usb_k... |
33 |
/* Keyboard sampling rate */ |
8454c84af usb: kbd: Fix key... |
34 |
#define REPEAT_RATE 40 /* 40msec -> 25cps */ |
9a8c72a6c USB: Rework usb_k... |
35 |
#define REPEAT_DELAY 10 /* 10 x REPEAT_RATE = 400msec */ |
affae2bff Initial revision |
36 37 |
#define NUM_LOCK 0x53 |
00b7d6ecc USB: Squash check... |
38 39 |
#define CAPS_LOCK 0x39 #define SCROLL_LOCK 0x47 |
affae2bff Initial revision |
40 |
|
affae2bff Initial revision |
41 |
/* Modifier bits */ |
9a8c72a6c USB: Rework usb_k... |
42 43 44 45 46 47 48 49 50 51 52 53 54 |
#define LEFT_CNTR (1 << 0) #define LEFT_SHIFT (1 << 1) #define LEFT_ALT (1 << 2) #define LEFT_GUI (1 << 3) #define RIGHT_CNTR (1 << 4) #define RIGHT_SHIFT (1 << 5) #define RIGHT_ALT (1 << 6) #define RIGHT_GUI (1 << 7) /* Size of the keyboard buffer */ #define USB_KBD_BUFFER_LEN 0x20 /* Device name */ |
00b7d6ecc USB: Squash check... |
55 |
#define DEVNAME "usbkbd" |
affae2bff Initial revision |
56 |
|
9a8c72a6c USB: Rework usb_k... |
57 58 |
/* Keyboard maps */ static const unsigned char usb_kbd_numkey[] = { |
00b7d6ecc USB: Squash check... |
59 60 61 |
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']', '\\', '#', ';', '\'', '`', ',', '.', '/' |
affae2bff Initial revision |
62 |
}; |
9a8c72a6c USB: Rework usb_k... |
63 |
static const unsigned char usb_kbd_numkey_shifted[] = { |
00b7d6ecc USB: Squash check... |
64 65 66 |
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?' |
affae2bff Initial revision |
67 |
}; |
d53da847c usb: add numeric ... |
68 69 70 71 72 |
static const unsigned char usb_kbd_num_keypad[] = { '/', '*', '-', '+', '\r', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.', 0, 0, 0, '=' }; |
9a8c72a6c USB: Rework usb_k... |
73 |
/* |
4151a400c USB: add arrow ke... |
74 75 76 77 78 79 80 81 82 |
* map arrow keys to ^F/^B ^N/^P, can't really use the proper * ANSI sequence for arrow keys because the queuing code breaks * when a single keypress expands to 3 queue elements */ static const unsigned char usb_kbd_arrow[] = { 0x6, 0x2, 0xe, 0x10 }; /* |
9a8c72a6c USB: Rework usb_k... |
83 84 85 86 87 88 89 |
* NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this * order. See usb_kbd_setled() function! */ #define USB_KBD_NUMLOCK (1 << 0) #define USB_KBD_CAPSLOCK (1 << 1) #define USB_KBD_SCROLLLOCK (1 << 2) #define USB_KBD_CTRL (1 << 3) |
48c8073ec USB: Add function... |
90 |
|
9a8c72a6c USB: Rework usb_k... |
91 92 |
#define USB_KBD_LEDMASK \ (USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK) |
48c8073ec USB: Add function... |
93 |
|
08a98b89d usb: Fix USB keyb... |
94 95 96 97 98 |
/* * USB Keyboard reports are 8 bytes in boot protocol. * Appendix B of HID Device Class Definition 1.11 */ #define USB_KBD_BOOT_REPORT_SIZE 8 |
9a8c72a6c USB: Rework usb_k... |
99 |
struct usb_kbd_pdata { |
8f8d7d245 usb: kbd: Cache p... |
100 101 102 |
unsigned long intpipe; int intpktsize; int intinterval; |
8454c84af usb: kbd: Fix key... |
103 |
unsigned long last_report; |
8e5531198 usb: kbd: Add (op... |
104 |
struct int_queue *intq; |
8f8d7d245 usb: kbd: Cache p... |
105 |
|
9a8c72a6c USB: Rework usb_k... |
106 |
uint32_t repeat_delay; |
affae2bff Initial revision |
107 |
|
9a8c72a6c USB: Rework usb_k... |
108 109 110 |
uint32_t usb_in_pointer; uint32_t usb_out_pointer; uint8_t usb_kbd_buffer[USB_KBD_BUFFER_LEN]; |
48c8073ec USB: Add function... |
111 |
|
d7475386b USB: make usb_kbd... |
112 |
uint8_t *new; |
08a98b89d usb: Fix USB keyb... |
113 |
uint8_t old[USB_KBD_BOOT_REPORT_SIZE]; |
48c8073ec USB: Add function... |
114 |
|
9a8c72a6c USB: Rework usb_k... |
115 116 |
uint8_t flags; }; |
48c8073ec USB: Add function... |
117 |
|
07551f234 console: usb: kbd... |
118 119 120 121 |
extern int __maybe_unused net_busy_flag; /* The period of time between two calls of usb_kbd_testc(). */ static unsigned long __maybe_unused kbd_testc_tms; |
9a8c72a6c USB: Rework usb_k... |
122 123 |
/* Puts character in the queue and sets up the in and out pointer. */ static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c) |
affae2bff Initial revision |
124 |
{ |
9a8c72a6c USB: Rework usb_k... |
125 126 127 128 |
if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) { /* Check for buffer full. */ if (data->usb_out_pointer == 0) return; |
affae2bff Initial revision |
129 |
|
9a8c72a6c USB: Rework usb_k... |
130 131 132 133 134 |
data->usb_in_pointer = 0; } else { /* Check for buffer full. */ if (data->usb_in_pointer == data->usb_out_pointer - 1) return; |
affae2bff Initial revision |
135 |
|
9a8c72a6c USB: Rework usb_k... |
136 137 |
data->usb_in_pointer++; } |
affae2bff Initial revision |
138 |
|
9a8c72a6c USB: Rework usb_k... |
139 |
data->usb_kbd_buffer[data->usb_in_pointer] = c; |
affae2bff Initial revision |
140 |
} |
9a8c72a6c USB: Rework usb_k... |
141 142 143 144 |
/* * Set the LEDs. Since this is used in the irq routine, the control job is * issued with a timeout of 0. This means, that the job is queued without * waiting for job completion. |
affae2bff Initial revision |
145 |
*/ |
affae2bff Initial revision |
146 147 |
static void usb_kbd_setled(struct usb_device *dev) { |
9a8c72a6c USB: Rework usb_k... |
148 149 |
struct usb_interface *iface = &dev->config.if_desc[0]; struct usb_kbd_pdata *data = dev->privptr; |
9b2393812 usb: kbd: Fix una... |
150 |
ALLOC_ALIGN_BUFFER(uint32_t, leds, 1, USB_DMA_MINALIGN); |
9a8c72a6c USB: Rework usb_k... |
151 |
|
9b2393812 usb: kbd: Fix una... |
152 |
*leds = data->flags & USB_KBD_LEDMASK; |
affae2bff Initial revision |
153 154 |
usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
9b2393812 usb: kbd: Fix una... |
155 |
0x200, iface->desc.bInterfaceNumber, leds, 1, 0); |
affae2bff Initial revision |
156 |
} |
9a8c72a6c USB: Rework usb_k... |
157 |
#define CAPITAL_MASK 0x20 |
affae2bff Initial revision |
158 |
/* Translate the scancode in ASCII */ |
9a8c72a6c USB: Rework usb_k... |
159 160 |
static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode, unsigned char modifier, int pressed) |
affae2bff Initial revision |
161 |
{ |
9a8c72a6c USB: Rework usb_k... |
162 |
uint8_t keycode = 0; |
affae2bff Initial revision |
163 |
|
9a8c72a6c USB: Rework usb_k... |
164 |
/* Key released */ |
00b7d6ecc USB: Squash check... |
165 |
if (pressed == 0) { |
9a8c72a6c USB: Rework usb_k... |
166 |
data->repeat_delay = 0; |
affae2bff Initial revision |
167 168 |
return 0; } |
9a8c72a6c USB: Rework usb_k... |
169 |
|
00b7d6ecc USB: Squash check... |
170 |
if (pressed == 2) { |
9a8c72a6c USB: Rework usb_k... |
171 172 |
data->repeat_delay++; if (data->repeat_delay < REPEAT_DELAY) |
affae2bff Initial revision |
173 |
return 0; |
9a8c72a6c USB: Rework usb_k... |
174 175 |
data->repeat_delay = REPEAT_DELAY; |
affae2bff Initial revision |
176 |
} |
9a8c72a6c USB: Rework usb_k... |
177 178 179 180 181 182 |
/* Alphanumeric values */ if ((scancode > 3) && (scancode <= 0x1d)) { keycode = scancode - 4 + 'a'; if (data->flags & USB_KBD_CAPSLOCK) |
00b7d6ecc USB: Squash check... |
183 |
keycode &= ~CAPITAL_MASK; |
9a8c72a6c USB: Rework usb_k... |
184 185 186 |
if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) { /* Handle CAPSLock + Shift pressed simultaneously */ |
00b7d6ecc USB: Squash check... |
187 |
if (keycode & CAPITAL_MASK) |
00b7d6ecc USB: Squash check... |
188 |
keycode &= ~CAPITAL_MASK; |
affae2bff Initial revision |
189 |
else |
00b7d6ecc USB: Squash check... |
190 |
keycode |= CAPITAL_MASK; |
affae2bff Initial revision |
191 192 |
} } |
9a8c72a6c USB: Rework usb_k... |
193 |
|
bdbcbe752 usb: kbd: Prevent... |
194 |
if ((scancode > 0x1d) && (scancode < 0x39)) { |
9a8c72a6c USB: Rework usb_k... |
195 196 197 198 199 |
/* Shift pressed */ if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) keycode = usb_kbd_numkey_shifted[scancode - 0x1e]; else keycode = usb_kbd_numkey[scancode - 0x1e]; |
affae2bff Initial revision |
200 |
} |
4785a694c Add Ctrl combo ke... |
201 |
|
4151a400c USB: add arrow ke... |
202 203 204 |
/* Arrow keys */ if ((scancode >= 0x4f) && (scancode <= 0x52)) keycode = usb_kbd_arrow[scancode - 0x4f]; |
d53da847c usb: add numeric ... |
205 206 207 |
/* Numeric keypad */ if ((scancode >= 0x54) && (scancode <= 0x67)) keycode = usb_kbd_num_keypad[scancode - 0x54]; |
9a8c72a6c USB: Rework usb_k... |
208 |
if (data->flags & USB_KBD_CTRL) |
4785a694c Add Ctrl combo ke... |
209 |
keycode = scancode - 0x3; |
00b7d6ecc USB: Squash check... |
210 211 |
if (pressed == 1) { if (scancode == NUM_LOCK) { |
9a8c72a6c USB: Rework usb_k... |
212 |
data->flags ^= USB_KBD_NUMLOCK; |
affae2bff Initial revision |
213 214 |
return 1; } |
9a8c72a6c USB: Rework usb_k... |
215 |
|
00b7d6ecc USB: Squash check... |
216 |
if (scancode == CAPS_LOCK) { |
9a8c72a6c USB: Rework usb_k... |
217 |
data->flags ^= USB_KBD_CAPSLOCK; |
affae2bff Initial revision |
218 219 |
return 1; } |
00b7d6ecc USB: Squash check... |
220 |
if (scancode == SCROLL_LOCK) { |
9a8c72a6c USB: Rework usb_k... |
221 |
data->flags ^= USB_KBD_SCROLLLOCK; |
affae2bff Initial revision |
222 223 224 |
return 1; } } |
9a8c72a6c USB: Rework usb_k... |
225 226 227 |
/* Report keycode if any */ if (keycode) { |
ceb4972a8 usb: common: Weed... |
228 |
debug("%c", keycode); |
9a8c72a6c USB: Rework usb_k... |
229 |
usb_kbd_put_queue(data, keycode); |
affae2bff Initial revision |
230 |
} |
9a8c72a6c USB: Rework usb_k... |
231 |
|
affae2bff Initial revision |
232 233 |
return 0; } |
9a8c72a6c USB: Rework usb_k... |
234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
static uint32_t usb_kbd_service_key(struct usb_device *dev, int i, int up) { uint32_t res = 0; struct usb_kbd_pdata *data = dev->privptr; uint8_t *new; uint8_t *old; if (up) { new = data->old; old = data->new; } else { new = data->new; old = data->old; } |
08a98b89d usb: Fix USB keyb... |
248 249 250 |
if ((old[i] > 3) && (memscan(new + 2, old[i], USB_KBD_BOOT_REPORT_SIZE - 2) == new + USB_KBD_BOOT_REPORT_SIZE)) { |
9a8c72a6c USB: Rework usb_k... |
251 |
res |= usb_kbd_translate(data, old[i], data->new[0], up); |
08a98b89d usb: Fix USB keyb... |
252 |
} |
9a8c72a6c USB: Rework usb_k... |
253 254 255 |
return res; } |
affae2bff Initial revision |
256 |
/* Interrupt service routine */ |
48c8073ec USB: Add function... |
257 |
static int usb_kbd_irq_worker(struct usb_device *dev) |
affae2bff Initial revision |
258 |
{ |
9a8c72a6c USB: Rework usb_k... |
259 260 |
struct usb_kbd_pdata *data = dev->privptr; int i, res = 0; |
4785a694c Add Ctrl combo ke... |
261 |
|
9a8c72a6c USB: Rework usb_k... |
262 263 264 265 266 267 |
/* No combo key pressed */ if (data->new[0] == 0x00) data->flags &= ~USB_KBD_CTRL; /* Left or Right Ctrl pressed */ else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR)) data->flags |= USB_KBD_CTRL; |
00b7d6ecc USB: Squash check... |
268 |
|
08a98b89d usb: Fix USB keyb... |
269 |
for (i = 2; i < USB_KBD_BOOT_REPORT_SIZE; i++) { |
9a8c72a6c USB: Rework usb_k... |
270 271 |
res |= usb_kbd_service_key(dev, i, 0); res |= usb_kbd_service_key(dev, i, 1); |
affae2bff Initial revision |
272 |
} |
00b7d6ecc USB: Squash check... |
273 |
|
9a8c72a6c USB: Rework usb_k... |
274 275 276 |
/* Key is still pressed */ if ((data->new[2] > 3) && (data->old[2] == data->new[2])) res |= usb_kbd_translate(data, data->new[2], data->new[0], 2); |
00b7d6ecc USB: Squash check... |
277 |
if (res == 1) |
affae2bff Initial revision |
278 |
usb_kbd_setled(dev); |
00b7d6ecc USB: Squash check... |
279 |
|
08a98b89d usb: Fix USB keyb... |
280 |
memcpy(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE); |
00b7d6ecc USB: Squash check... |
281 |
|
9a8c72a6c USB: Rework usb_k... |
282 |
return 1; |
affae2bff Initial revision |
283 |
} |
9a8c72a6c USB: Rework usb_k... |
284 |
/* Keyboard interrupt handler */ |
48c8073ec USB: Add function... |
285 286 |
static int usb_kbd_irq(struct usb_device *dev) { |
08a98b89d usb: Fix USB keyb... |
287 288 |
if ((dev->irq_status != 0) || (dev->irq_act_len != USB_KBD_BOOT_REPORT_SIZE)) { |
ceb4972a8 usb: common: Weed... |
289 290 291 |
debug("USB KBD: Error %lX, len %d ", dev->irq_status, dev->irq_act_len); |
48c8073ec USB: Add function... |
292 293 294 295 296 |
return 1; } return usb_kbd_irq_worker(dev); } |
9a8c72a6c USB: Rework usb_k... |
297 298 299 |
/* Interrupt polling */ static inline void usb_kbd_poll_for_event(struct usb_device *dev) { |
8454c84af usb: kbd: Fix key... |
300 |
#if defined(CONFIG_SYS_USB_EVENT_POLL) |
8f8d7d245 usb: kbd: Cache p... |
301 |
struct usb_kbd_pdata *data = dev->privptr; |
f9636e8d3 USB: move keyboar... |
302 303 |
/* Submit a interrupt transfer request */ |
8f8d7d245 usb: kbd: Cache p... |
304 305 |
usb_submit_int_msg(dev, data->intpipe, &data->new[0], data->intpktsize, data->intinterval); |
f9636e8d3 USB: move keyboar... |
306 |
|
9a8c72a6c USB: Rework usb_k... |
307 |
usb_kbd_irq_worker(dev); |
8454c84af usb: kbd: Fix key... |
308 309 310 |
#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) || \ defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) #if defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) |
9a8c72a6c USB: Rework usb_k... |
311 312 313 314 |
struct usb_interface *iface; struct usb_kbd_pdata *data = dev->privptr; iface = &dev->config.if_desc[0]; usb_get_report(dev, iface->desc.bInterfaceNumber, |
08a98b89d usb: Fix USB keyb... |
315 |
1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE); |
8454c84af usb: kbd: Fix key... |
316 |
if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) { |
9a8c72a6c USB: Rework usb_k... |
317 |
usb_kbd_irq_worker(dev); |
8454c84af usb: kbd: Fix key... |
318 |
#else |
8e5531198 usb: kbd: Add (op... |
319 320 321 322 323 324 |
struct usb_kbd_pdata *data = dev->privptr; if (poll_int_queue(dev, data->intq)) { usb_kbd_irq_worker(dev); /* We've consumed all queued int packets, create new */ destroy_int_queue(dev, data->intq); data->intq = create_int_queue(dev, data->intpipe, 1, |
8bb6c1d1e usb: Add an inter... |
325 326 |
USB_KBD_BOOT_REPORT_SIZE, data->new, data->intinterval); |
8454c84af usb: kbd: Fix key... |
327 328 329 330 331 332 333 |
#endif data->last_report = get_timer(0); /* Repeat last usb hid report every REPEAT_RATE ms for keyrepeat */ } else if (data->last_report != -1 && get_timer(data->last_report) > REPEAT_RATE) { usb_kbd_irq_worker(dev); data->last_report = get_timer(0); |
8e5531198 usb: kbd: Add (op... |
334 |
} |
9a8c72a6c USB: Rework usb_k... |
335 336 337 338 |
#endif } /* test if a character is in the queue */ |
709ea543b stdio: Pass devic... |
339 |
static int usb_kbd_testc(struct stdio_dev *sdev) |
9a8c72a6c USB: Rework usb_k... |
340 341 342 343 |
{ struct stdio_dev *dev; struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; |
c95e2b9ea console: usb: kbd... |
344 345 346 347 348 349 350 351 352 353 |
#ifdef CONFIG_CMD_NET /* * If net_busy_flag is 1, NET transfer is running, * then we check key-pressed every second (first check may be * less than 1 second) to improve TFTP booting performance. */ if (net_busy_flag && (get_timer(kbd_testc_tms) < CONFIG_SYS_HZ)) return 0; kbd_testc_tms = get_timer(0); #endif |
9a8c72a6c USB: Rework usb_k... |
354 355 356 357 358 359 360 361 362 363 |
dev = stdio_get_by_name(DEVNAME); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; usb_kbd_poll_for_event(usb_kbd_dev); return !(data->usb_in_pointer == data->usb_out_pointer); } /* gets the character from the queue */ |
709ea543b stdio: Pass devic... |
364 |
static int usb_kbd_getc(struct stdio_dev *sdev) |
9a8c72a6c USB: Rework usb_k... |
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
{ struct stdio_dev *dev; struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; dev = stdio_get_by_name(DEVNAME); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; while (data->usb_in_pointer == data->usb_out_pointer) usb_kbd_poll_for_event(usb_kbd_dev); if (data->usb_out_pointer == USB_KBD_BUFFER_LEN - 1) data->usb_out_pointer = 0; else data->usb_out_pointer++; return data->usb_kbd_buffer[data->usb_out_pointer]; } /* probes the USB device dev for keyboard type. */ |
34ab37eef dm: usb: Add supp... |
386 |
static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) |
affae2bff Initial revision |
387 |
{ |
8f8bd565f USB Consolidate d... |
388 |
struct usb_interface *iface; |
affae2bff Initial revision |
389 |
struct usb_endpoint_descriptor *ep; |
9a8c72a6c USB: Rework usb_k... |
390 |
struct usb_kbd_pdata *data; |
affae2bff Initial revision |
391 |
|
00b7d6ecc USB: Squash check... |
392 393 |
if (dev->descriptor.bNumConfigurations != 1) return 0; |
9a8c72a6c USB: Rework usb_k... |
394 |
|
affae2bff Initial revision |
395 |
iface = &dev->config.if_desc[ifnum]; |
2cdb58ebd usb: Avoid open-c... |
396 |
if (iface->desc.bInterfaceClass != USB_CLASS_HID) |
8f8bd565f USB Consolidate d... |
397 |
return 0; |
9a8c72a6c USB: Rework usb_k... |
398 |
|
2cdb58ebd usb: Avoid open-c... |
399 |
if (iface->desc.bInterfaceSubClass != USB_SUB_HID_BOOT) |
8f8bd565f USB Consolidate d... |
400 |
return 0; |
9a8c72a6c USB: Rework usb_k... |
401 |
|
2cdb58ebd usb: Avoid open-c... |
402 |
if (iface->desc.bInterfaceProtocol != USB_PROT_HID_KEYBOARD) |
8f8bd565f USB Consolidate d... |
403 |
return 0; |
9a8c72a6c USB: Rework usb_k... |
404 |
|
8f8bd565f USB Consolidate d... |
405 406 |
if (iface->desc.bNumEndpoints != 1) return 0; |
affae2bff Initial revision |
407 408 |
ep = &iface->ep_desc[0]; |
9a8c72a6c USB: Rework usb_k... |
409 |
/* Check if endpoint 1 is interrupt endpoint */ |
00b7d6ecc USB: Squash check... |
410 411 |
if (!(ep->bEndpointAddress & 0x80)) return 0; |
9a8c72a6c USB: Rework usb_k... |
412 |
|
00b7d6ecc USB: Squash check... |
413 414 |
if ((ep->bmAttributes & 3) != 3) return 0; |
9a8c72a6c USB: Rework usb_k... |
415 |
|
ceb4972a8 usb: common: Weed... |
416 417 |
debug("USB KBD: found set protocol... "); |
9a8c72a6c USB: Rework usb_k... |
418 419 420 421 422 423 424 425 426 427 |
data = malloc(sizeof(struct usb_kbd_pdata)); if (!data) { printf("USB KBD: Error allocating private data "); return 0; } /* Clear private data */ memset(data, 0, sizeof(struct usb_kbd_pdata)); |
d7475386b USB: make usb_kbd... |
428 |
/* allocate input buffer aligned and sized to USB DMA alignment */ |
08a98b89d usb: Fix USB keyb... |
429 430 |
data->new = memalign(USB_DMA_MINALIGN, roundup(USB_KBD_BOOT_REPORT_SIZE, USB_DMA_MINALIGN)); |
d7475386b USB: make usb_kbd... |
431 |
|
9a8c72a6c USB: Rework usb_k... |
432 433 434 435 436 |
/* Insert private data into USB device structure */ dev->privptr = data; /* Set IRQ handler */ dev->irq_handle = usb_kbd_irq; |
8f8d7d245 usb: kbd: Cache p... |
437 438 439 440 |
data->intpipe = usb_rcvintpipe(dev, ep->bEndpointAddress); data->intpktsize = min(usb_maxpacket(dev, data->intpipe), USB_KBD_BOOT_REPORT_SIZE); data->intinterval = ep->bInterval; |
8454c84af usb: kbd: Fix key... |
441 |
data->last_report = -1; |
9a8c72a6c USB: Rework usb_k... |
442 443 444 |
/* We found a USB Keyboard, install it. */ usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0); |
de451493f usb: kbd: Disable... |
445 446 |
debug("USB KBD: found set idle... "); |
8454c84af usb: kbd: Fix key... |
447 448 |
#if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \ !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) |
8454c84af usb: kbd: Fix key... |
449 |
usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0); |
de451493f usb: kbd: Disable... |
450 451 |
#else usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0); |
8454c84af usb: kbd: Fix key... |
452 |
#endif |
9a8c72a6c USB: Rework usb_k... |
453 |
|
ceb4972a8 usb: common: Weed... |
454 455 |
debug("USB KBD: enable interrupt pipe... "); |
8e5531198 usb: kbd: Add (op... |
456 457 |
#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE data->intq = create_int_queue(dev, data->intpipe, 1, |
8bb6c1d1e usb: Add an inter... |
458 459 |
USB_KBD_BOOT_REPORT_SIZE, data->new, data->intinterval); |
8e5531198 usb: kbd: Add (op... |
460 |
if (!data->intq) { |
e4b70d803 usb: kbd: don't u... |
461 462 463 |
#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) if (usb_get_report(dev, iface->desc.bInterfaceNumber, 1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE) < 0) { |
8e5531198 usb: kbd: Add (op... |
464 |
#else |
8f8d7d245 usb: kbd: Cache p... |
465 466 |
if (usb_submit_int_msg(dev, data->intpipe, data->new, data->intpktsize, data->intinterval) < 0) { |
8e5531198 usb: kbd: Add (op... |
467 |
#endif |
5da2dc978 usb: workaround n... |
468 469 470 471 472 473 |
printf("Failed to get keyboard state from device %04x:%04x ", dev->descriptor.idVendor, dev->descriptor.idProduct); /* Abort, we don't want to use that non-functional keyboard. */ return 0; } |
9a8c72a6c USB: Rework usb_k... |
474 475 |
/* Success. */ |
affae2bff Initial revision |
476 477 |
return 1; } |
603afaf0e dm: usb: Split ou... |
478 479 480 481 482 483 484 |
static int probe_usb_keyboard(struct usb_device *dev) { char *stdinname; struct stdio_dev usb_kbd_dev; int error; /* Try probing the keyboard */ |
34ab37eef dm: usb: Add supp... |
485 |
if (usb_kbd_probe_dev(dev, 0) != 1) |
603afaf0e dm: usb: Split ou... |
486 487 488 489 490 491 492 |
return -ENOENT; /* Register the keyboard */ debug("USB KBD: register. "); memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev)); strcpy(usb_kbd_dev.name, DEVNAME); |
1caf934a0 video: Drop DEV_F... |
493 |
usb_kbd_dev.flags = DEV_FLAGS_INPUT; |
603afaf0e dm: usb: Split ou... |
494 495 496 497 498 499 |
usb_kbd_dev.getc = usb_kbd_getc; usb_kbd_dev.tstc = usb_kbd_testc; usb_kbd_dev.priv = (void *)dev; error = stdio_register(&usb_kbd_dev); if (error) return error; |
00caae6d4 env: Rename geten... |
500 |
stdinname = env_get("stdin"); |
b02654294 console: Don't en... |
501 |
#if CONFIG_IS_ENABLED(CONSOLE_MUX) |
603afaf0e dm: usb: Split ou... |
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
error = iomux_doenv(stdin, stdinname); if (error) return error; #else /* Check if this is the standard input device. */ if (strcmp(stdinname, DEVNAME)) return 1; /* Reassign the console */ if (overwrite_console()) return 1; error = console_assign(stdin, DEVNAME); if (error) return error; #endif return 0; } |
34ab37eef dm: usb: Add supp... |
521 |
#ifndef CONFIG_DM_USB |
9a8c72a6c USB: Rework usb_k... |
522 523 524 |
/* Search for keyboard and register it if found. */ int drv_usb_kbd_init(void) { |
9a8c72a6c USB: Rework usb_k... |
525 |
int error, i; |
697033cbf dm: usb: Support ... |
526 527 |
debug("%s: Probing for keyboard ", __func__); |
697033cbf dm: usb: Support ... |
528 |
/* Scan all USB Devices */ |
9a8c72a6c USB: Rework usb_k... |
529 |
for (i = 0; i < USB_MAX_DEVICE; i++) { |
603afaf0e dm: usb: Split ou... |
530 |
struct usb_device *dev; |
9a8c72a6c USB: Rework usb_k... |
531 532 533 |
/* Get USB device. */ dev = usb_get_dev_index(i); if (!dev) |
603afaf0e dm: usb: Split ou... |
534 |
break; |
9a8c72a6c USB: Rework usb_k... |
535 536 537 |
if (dev->devnum == -1) continue; |
603afaf0e dm: usb: Split ou... |
538 539 |
error = probe_usb_keyboard(dev); if (!error) |
9a8c72a6c USB: Rework usb_k... |
540 |
return 1; |
603afaf0e dm: usb: Split ou... |
541 |
if (error && error != -ENOENT) |
9a8c72a6c USB: Rework usb_k... |
542 |
return error; |
9a8c72a6c USB: Rework usb_k... |
543 544 545 546 547 548 549 |
} /* No USB Keyboard found */ return -1; } /* Deregister the keyboard. */ |
8a8a2257e usb: kbd: Allow "... |
550 |
int usb_kbd_deregister(int force) |
9a8c72a6c USB: Rework usb_k... |
551 |
{ |
869588dec Convert CONFIG_SY... |
552 |
#if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER) |
dfe5b1c86 usb: kbd: Fix mem... |
553 554 555 556 557 558 559 560 561 562 |
struct stdio_dev *dev; struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; dev = stdio_get_by_name(DEVNAME); if (dev) { usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; if (stdio_deregister_dev(dev, force) != 0) return 1; |
b02654294 console: Don't en... |
563 |
#if CONFIG_IS_ENABLED(CONSOLE_MUX) |
00caae6d4 env: Rename geten... |
564 |
if (iomux_doenv(stdin, env_get("stdin")) != 0) |
3cbcb2892 usb: Fix usb_kbd_... |
565 566 |
return 1; #endif |
8e5531198 usb: kbd: Add (op... |
567 568 569 |
#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE destroy_int_queue(usb_kbd_dev, data->intq); #endif |
dfe5b1c86 usb: kbd: Fix mem... |
570 571 572 |
free(data->new); free(data); } |
0ea09dfe8 usb: kbd: Do not ... |
573 574 |
return 0; |
9a8c72a6c USB: Rework usb_k... |
575 576 577 578 |
#else return 1; #endif } |
34ab37eef dm: usb: Add supp... |
579 |
|
9a80e7143 usb: kbd: Do not ... |
580 |
#endif |
34ab37eef dm: usb: Add supp... |
581 582 583 584 585 |
#ifdef CONFIG_DM_USB static int usb_kbd_probe(struct udevice *dev) { struct usb_device *udev = dev_get_parent_priv(dev); |
34ab37eef dm: usb: Add supp... |
586 |
|
8319aeb1d usb: squash lines... |
587 |
return probe_usb_keyboard(udev); |
34ab37eef dm: usb: Add supp... |
588 |
} |
8a8348703 dm: usb: Add a re... |
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
static int usb_kbd_remove(struct udevice *dev) { struct usb_device *udev = dev_get_parent_priv(dev); struct usb_kbd_pdata *data; struct stdio_dev *sdev; int ret; sdev = stdio_get_by_name(DEVNAME); if (!sdev) { ret = -ENXIO; goto err; } data = udev->privptr; if (stdio_deregister_dev(sdev, true)) { ret = -EPERM; goto err; } |
b02654294 console: Don't en... |
606 |
#if CONFIG_IS_ENABLED(CONSOLE_MUX) |
00caae6d4 env: Rename geten... |
607 |
if (iomux_doenv(stdin, env_get("stdin"))) { |
8a8348703 dm: usb: Add a re... |
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 |
ret = -ENOLINK; goto err; } #endif #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE destroy_int_queue(udev, data->intq); #endif free(data->new); free(data); return 0; err: printf("%s: warning, ret=%d", __func__, ret); return ret; } |
34ab37eef dm: usb: Add supp... |
623 624 625 626 627 628 629 630 631 632 |
static const struct udevice_id usb_kbd_ids[] = { { .compatible = "usb-keyboard" }, { } }; U_BOOT_DRIVER(usb_kbd) = { .name = "usb_kbd", .id = UCLASS_KEYBOARD, .of_match = usb_kbd_ids, .probe = usb_kbd_probe, |
8a8348703 dm: usb: Add a re... |
633 |
.remove = usb_kbd_remove, |
34ab37eef dm: usb: Add supp... |
634 |
}; |
34ab37eef dm: usb: Add supp... |
635 636 637 638 639 640 |
static const struct usb_device_id kbd_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL, .bInterfaceClass = USB_CLASS_HID, |
2cdb58ebd usb: Avoid open-c... |
641 642 |
.bInterfaceSubClass = USB_SUB_HID_BOOT, .bInterfaceProtocol = USB_PROT_HID_KEYBOARD, |
34ab37eef dm: usb: Add supp... |
643 644 645 646 647 648 649 |
}, { } /* Terminating entry */ }; U_BOOT_USB_DEVICE(usb_kbd, kbd_id_table); #endif |