Blame view

common/usb_kbd.c 17 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
affae2bff   wdenk   Initial revision
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.
affae2bff   wdenk   Initial revision
8
9
   */
  #include <common.h>
24b852a7a   Simon Glass   Move console defi...
10
  #include <console.h>
697033cbf   Simon Glass   dm: usb: Support ...
11
  #include <dm.h>
7b51b576d   Simon Glass   env: Move env_get...
12
  #include <env.h>
0ea09dfe8   Hans de Goede   usb: kbd: Do not ...
13
  #include <errno.h>
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
14
  #include <malloc.h>
cf92e05c0   Simon Glass   Move ALLOC_CACHE_...
15
  #include <memalign.h>
52cb4d4fb   Jean-Christophe PLAGNIOL-VILLARD   stdio/device: rew...
16
  #include <stdio_dev.h>
f8f3e0e53   Michal Simek   usb_kbd: Add supp...
17
  #include <watchdog.h>
c918261c6   Christian Eggers   USB: replace old ...
18
  #include <asm/byteorder.h>
affae2bff   wdenk   Initial revision
19

affae2bff   wdenk   Initial revision
20
  #include <usb.h>
affae2bff   wdenk   Initial revision
21
  /*
00b7d6ecc   Marek Vasut   USB: Squash check...
22
   * If overwrite_console returns 1, the stdin, stderr and stdout
affae2bff   wdenk   Initial revision
23
24
25
   * are switched to the serial port, else the settings in the
   * environment are used
   */
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
26
  #ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
00b7d6ecc   Marek Vasut   USB: Squash check...
27
  extern int overwrite_console(void);
affae2bff   wdenk   Initial revision
28
  #else
00b7d6ecc   Marek Vasut   USB: Squash check...
29
  int overwrite_console(void)
affae2bff   wdenk   Initial revision
30
  {
00b7d6ecc   Marek Vasut   USB: Squash check...
31
  	return 0;
affae2bff   wdenk   Initial revision
32
33
  }
  #endif
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
34
  /* Keyboard sampling rate */
8454c84af   Hans de Goede   usb: kbd: Fix key...
35
  #define REPEAT_RATE	40		/* 40msec -> 25cps */
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
36
  #define REPEAT_DELAY	10		/* 10 x REPEAT_RATE = 400msec */
affae2bff   wdenk   Initial revision
37
38
  
  #define NUM_LOCK	0x53
00b7d6ecc   Marek Vasut   USB: Squash check...
39
40
  #define CAPS_LOCK	0x39
  #define SCROLL_LOCK	0x47
affae2bff   wdenk   Initial revision
41

affae2bff   wdenk   Initial revision
42
  /* Modifier bits */
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
43
44
45
46
47
48
49
50
51
52
53
54
55
  #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   Marek Vasut   USB: Squash check...
56
  #define DEVNAME			"usbkbd"
affae2bff   wdenk   Initial revision
57

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
58
59
  /* Keyboard maps */
  static const unsigned char usb_kbd_numkey[] = {
00b7d6ecc   Marek Vasut   USB: Squash check...
60
61
62
  	'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
  	'\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']',
  	'\\', '#', ';', '\'', '`', ',', '.', '/'
affae2bff   wdenk   Initial revision
63
  };
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
64
  static const unsigned char usb_kbd_numkey_shifted[] = {
00b7d6ecc   Marek Vasut   USB: Squash check...
65
66
67
  	'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  	'\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}',
  	'|', '~', ':', '"', '~', '<', '>', '?'
affae2bff   wdenk   Initial revision
68
  };
d53da847c   Vincent Palatin   usb: add numeric ...
69
70
71
72
73
  static const unsigned char usb_kbd_num_keypad[] = {
  	'/', '*', '-', '+', '\r',
  	'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
  	'.', 0, 0, 0, '='
  };
3352c2114   Heinrich Schuchardt   usb: kbd: simplif...
74
  static const u8 usb_special_keys[] = {
87e91bcca   Heinrich Schuchardt   usb: kbd: impleme...
75
76
77
  #ifdef CONFIG_USB_KEYBOARD_FN_KEYS
  	'2', 'H', '5', '3', 'F', '6', 'C', 'D', 'B', 'A'
  #else
3352c2114   Heinrich Schuchardt   usb: kbd: simplif...
78
  	'C', 'D', 'B', 'A'
87e91bcca   Heinrich Schuchardt   usb: kbd: impleme...
79
  #endif
4151a400c   Allen Martin   USB: add arrow ke...
80
81
82
  };
  
  /*
9a8c72a6c   Marek Vasut   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   Marek Vasut   USB: Add function...
90

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
91
92
  #define USB_KBD_LEDMASK		\
  	(USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK)
48c8073ec   Marek Vasut   USB: Add function...
93

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
94
  struct usb_kbd_pdata {
8f8d7d245   Hans de Goede   usb: kbd: Cache p...
95
96
97
  	unsigned long	intpipe;
  	int		intpktsize;
  	int		intinterval;
8454c84af   Hans de Goede   usb: kbd: Fix key...
98
  	unsigned long	last_report;
8e5531198   Hans de Goede   usb: kbd: Add (op...
99
  	struct int_queue *intq;
8f8d7d245   Hans de Goede   usb: kbd: Cache p...
100

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
101
  	uint32_t	repeat_delay;
affae2bff   wdenk   Initial revision
102

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
103
104
105
  	uint32_t	usb_in_pointer;
  	uint32_t	usb_out_pointer;
  	uint8_t		usb_kbd_buffer[USB_KBD_BUFFER_LEN];
48c8073ec   Marek Vasut   USB: Add function...
106

d7475386b   Allen Martin   USB: make usb_kbd...
107
  	uint8_t		*new;
08a98b89d   Adrian Cox   usb: Fix USB keyb...
108
  	uint8_t		old[USB_KBD_BOOT_REPORT_SIZE];
48c8073ec   Marek Vasut   USB: Add function...
109

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
110
111
  	uint8_t		flags;
  };
48c8073ec   Marek Vasut   USB: Add function...
112

07551f234   Jim Lin   console: usb: kbd...
113
114
115
116
  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   Marek Vasut   USB: Rework usb_k...
117
  /* Puts character in the queue and sets up the in and out pointer. */
28dfa7d80   Heinrich Schuchardt   usb: kbd: signatu...
118
  static void usb_kbd_put_queue(struct usb_kbd_pdata *data, u8 c)
affae2bff   wdenk   Initial revision
119
  {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
120
121
122
123
  	if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
  		/* Check for buffer full. */
  		if (data->usb_out_pointer == 0)
  			return;
affae2bff   wdenk   Initial revision
124

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
125
126
127
128
129
  		data->usb_in_pointer = 0;
  	} else {
  		/* Check for buffer full. */
  		if (data->usb_in_pointer == data->usb_out_pointer - 1)
  			return;
affae2bff   wdenk   Initial revision
130

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
131
132
  		data->usb_in_pointer++;
  	}
affae2bff   wdenk   Initial revision
133

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
134
  	data->usb_kbd_buffer[data->usb_in_pointer] = c;
affae2bff   wdenk   Initial revision
135
  }
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
136
137
138
139
  /*
   * 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   wdenk   Initial revision
140
   */
affae2bff   wdenk   Initial revision
141
142
  static void usb_kbd_setled(struct usb_device *dev)
  {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
143
144
  	struct usb_interface *iface = &dev->config.if_desc[0];
  	struct usb_kbd_pdata *data = dev->privptr;
9b2393812   Hans de Goede   usb: kbd: Fix una...
145
  	ALLOC_ALIGN_BUFFER(uint32_t, leds, 1, USB_DMA_MINALIGN);
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
146

9b2393812   Hans de Goede   usb: kbd: Fix una...
147
  	*leds = data->flags & USB_KBD_LEDMASK;
affae2bff   wdenk   Initial revision
148
149
  	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  		USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
9b2393812   Hans de Goede   usb: kbd: Fix una...
150
  		0x200, iface->desc.bInterfaceNumber, leds, 1, 0);
affae2bff   wdenk   Initial revision
151
  }
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
152
  #define CAPITAL_MASK	0x20
affae2bff   wdenk   Initial revision
153
  /* Translate the scancode in ASCII */
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
154
155
  static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
  				unsigned char modifier, int pressed)
affae2bff   wdenk   Initial revision
156
  {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
157
  	uint8_t keycode = 0;
affae2bff   wdenk   Initial revision
158

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
159
  	/* Key released */
00b7d6ecc   Marek Vasut   USB: Squash check...
160
  	if (pressed == 0) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
161
  		data->repeat_delay = 0;
affae2bff   wdenk   Initial revision
162
163
  		return 0;
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
164

00b7d6ecc   Marek Vasut   USB: Squash check...
165
  	if (pressed == 2) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
166
167
  		data->repeat_delay++;
  		if (data->repeat_delay < REPEAT_DELAY)
affae2bff   wdenk   Initial revision
168
  			return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
169
170
  
  		data->repeat_delay = REPEAT_DELAY;
affae2bff   wdenk   Initial revision
171
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
172
173
174
175
176
177
  
  	/* Alphanumeric values */
  	if ((scancode > 3) && (scancode <= 0x1d)) {
  		keycode = scancode - 4 + 'a';
  
  		if (data->flags & USB_KBD_CAPSLOCK)
00b7d6ecc   Marek Vasut   USB: Squash check...
178
  			keycode &= ~CAPITAL_MASK;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
179
180
181
  
  		if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) {
  			/* Handle CAPSLock + Shift pressed simultaneously */
00b7d6ecc   Marek Vasut   USB: Squash check...
182
  			if (keycode & CAPITAL_MASK)
00b7d6ecc   Marek Vasut   USB: Squash check...
183
  				keycode &= ~CAPITAL_MASK;
affae2bff   wdenk   Initial revision
184
  			else
00b7d6ecc   Marek Vasut   USB: Squash check...
185
  				keycode |= CAPITAL_MASK;
affae2bff   wdenk   Initial revision
186
187
  		}
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
188

bdbcbe752   Marek Vasut   usb: kbd: Prevent...
189
  	if ((scancode > 0x1d) && (scancode < 0x39)) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
190
191
192
193
194
  		/* Shift pressed */
  		if (modifier & (LEFT_SHIFT | RIGHT_SHIFT))
  			keycode = usb_kbd_numkey_shifted[scancode - 0x1e];
  		else
  			keycode = usb_kbd_numkey[scancode - 0x1e];
affae2bff   wdenk   Initial revision
195
  	}
4785a694c   Zhang Wei   Add Ctrl combo ke...
196

d53da847c   Vincent Palatin   usb: add numeric ...
197
198
199
  	/* Numeric keypad */
  	if ((scancode >= 0x54) && (scancode <= 0x67))
  		keycode = usb_kbd_num_keypad[scancode - 0x54];
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
200
  	if (data->flags & USB_KBD_CTRL)
4785a694c   Zhang Wei   Add Ctrl combo ke...
201
  		keycode = scancode - 0x3;
00b7d6ecc   Marek Vasut   USB: Squash check...
202
203
  	if (pressed == 1) {
  		if (scancode == NUM_LOCK) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
204
  			data->flags ^= USB_KBD_NUMLOCK;
affae2bff   wdenk   Initial revision
205
206
  			return 1;
  		}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
207

00b7d6ecc   Marek Vasut   USB: Squash check...
208
  		if (scancode == CAPS_LOCK) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
209
  			data->flags ^= USB_KBD_CAPSLOCK;
affae2bff   wdenk   Initial revision
210
211
  			return 1;
  		}
00b7d6ecc   Marek Vasut   USB: Squash check...
212
  		if (scancode == SCROLL_LOCK) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
213
  			data->flags ^= USB_KBD_SCROLLLOCK;
affae2bff   wdenk   Initial revision
214
215
216
  			return 1;
  		}
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
217
218
  
  	/* Report keycode if any */
3352c2114   Heinrich Schuchardt   usb: kbd: simplif...
219
  	if (keycode) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
220
  		debug("%c", keycode);
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
221
  		usb_kbd_put_queue(data, keycode);
3352c2114   Heinrich Schuchardt   usb: kbd: simplif...
222
  		return 0;
affae2bff   wdenk   Initial revision
223
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
224

87e91bcca   Heinrich Schuchardt   usb: kbd: impleme...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  #ifdef CONFIG_USB_KEYBOARD_FN_KEYS
  	if (scancode < 0x3a || scancode > 0x52 ||
  	    scancode == 0x46 || scancode == 0x47)
  		return 1;
  
  	usb_kbd_put_queue(data, 0x1b);
  	if (scancode < 0x3e) {
  		/* F1 - F4 */
  		usb_kbd_put_queue(data, 0x4f);
  		usb_kbd_put_queue(data, scancode - 0x3a + 'P');
  		return 0;
  	}
  	usb_kbd_put_queue(data, '[');
  	if (scancode < 0x42) {
  		/* F5 - F8 */
  		usb_kbd_put_queue(data, '1');
  		if (scancode == 0x3e)
  			--scancode;
  		keycode = scancode - 0x3f + '7';
  	} else if (scancode < 0x49) {
  		/* F9 - F12 */
  		usb_kbd_put_queue(data, '2');
  		if (scancode > 0x43)
  			++scancode;
  		keycode = scancode - 0x42 + '0';
  	} else {
  		/*
  		 * INSERT, HOME, PAGE UP, DELETE, END, PAGE DOWN,
  		 * RIGHT, LEFT, DOWN, UP
  		 */
  		keycode = usb_special_keys[scancode - 0x49];
  	}
  	usb_kbd_put_queue(data, keycode);
  	if (scancode < 0x4f && scancode != 0x4a && scancode != 0x4d)
  		usb_kbd_put_queue(data, '~');
  	return 0;
  #else
3352c2114   Heinrich Schuchardt   usb: kbd: simplif...
262
263
264
265
266
267
268
269
  	/* Left, Right, Up, Down */
  	if (scancode > 0x4e && scancode < 0x53) {
  		usb_kbd_put_queue(data, 0x1b);
  		usb_kbd_put_queue(data, '[');
  		usb_kbd_put_queue(data, usb_special_keys[scancode - 0x4f]);
  		return 0;
  	}
  	return 1;
87e91bcca   Heinrich Schuchardt   usb: kbd: impleme...
270
  #endif /* CONFIG_USB_KEYBOARD_FN_KEYS */
affae2bff   wdenk   Initial revision
271
  }
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  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   Adrian Cox   usb: Fix USB keyb...
286
287
288
  	if ((old[i] > 3) &&
  	    (memscan(new + 2, old[i], USB_KBD_BOOT_REPORT_SIZE - 2) ==
  			new + USB_KBD_BOOT_REPORT_SIZE)) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
289
  		res |= usb_kbd_translate(data, old[i], data->new[0], up);
08a98b89d   Adrian Cox   usb: Fix USB keyb...
290
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
291
292
293
  
  	return res;
  }
affae2bff   wdenk   Initial revision
294
  /* Interrupt service routine */
48c8073ec   Marek Vasut   USB: Add function...
295
  static int usb_kbd_irq_worker(struct usb_device *dev)
affae2bff   wdenk   Initial revision
296
  {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
297
298
  	struct usb_kbd_pdata *data = dev->privptr;
  	int i, res = 0;
4785a694c   Zhang Wei   Add Ctrl combo ke...
299

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
300
301
302
303
304
305
  	/* 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   Marek Vasut   USB: Squash check...
306

08a98b89d   Adrian Cox   usb: Fix USB keyb...
307
  	for (i = 2; i < USB_KBD_BOOT_REPORT_SIZE; i++) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
308
309
  		res |= usb_kbd_service_key(dev, i, 0);
  		res |= usb_kbd_service_key(dev, i, 1);
affae2bff   wdenk   Initial revision
310
  	}
00b7d6ecc   Marek Vasut   USB: Squash check...
311

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
312
313
314
  	/* 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   Marek Vasut   USB: Squash check...
315
  	if (res == 1)
affae2bff   wdenk   Initial revision
316
  		usb_kbd_setled(dev);
00b7d6ecc   Marek Vasut   USB: Squash check...
317

08a98b89d   Adrian Cox   usb: Fix USB keyb...
318
  	memcpy(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE);
00b7d6ecc   Marek Vasut   USB: Squash check...
319

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
320
  	return 1;
affae2bff   wdenk   Initial revision
321
  }
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
322
  /* Keyboard interrupt handler */
48c8073ec   Marek Vasut   USB: Add function...
323
324
  static int usb_kbd_irq(struct usb_device *dev)
  {
08a98b89d   Adrian Cox   usb: Fix USB keyb...
325
326
  	if ((dev->irq_status != 0) ||
  	    (dev->irq_act_len != USB_KBD_BOOT_REPORT_SIZE)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
327
328
329
  		debug("USB KBD: Error %lX, len %d
  ",
  		      dev->irq_status, dev->irq_act_len);
48c8073ec   Marek Vasut   USB: Add function...
330
331
332
333
334
  		return 1;
  	}
  
  	return usb_kbd_irq_worker(dev);
  }
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
335
336
337
  /* Interrupt polling */
  static inline void usb_kbd_poll_for_event(struct usb_device *dev)
  {
8454c84af   Hans de Goede   usb: kbd: Fix key...
338
  #if defined(CONFIG_SYS_USB_EVENT_POLL)
8f8d7d245   Hans de Goede   usb: kbd: Cache p...
339
  	struct usb_kbd_pdata *data = dev->privptr;
f9636e8d3   amartin@nvidia.com   USB: move keyboar...
340

216db3af2   Heinrich Schuchardt   usb: kbd: fix typo
341
  	/* Submit an interrupt transfer request */
fdd135bf8   Michal Suchanek   usb: usb_submit_i...
342
  	if (usb_int_msg(dev, data->intpipe, &data->new[0],
3437121c0   Michal Suchanek   usb: Add nonblock...
343
  			data->intpktsize, data->intinterval, true) >= 0)
3e816a242   Michal Suchanek   usb_kdb: only pro...
344
  		usb_kbd_irq_worker(dev);
8454c84af   Hans de Goede   usb: kbd: Fix key...
345
346
347
  #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   Marek Vasut   USB: Rework usb_k...
348
349
350
351
  	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   Adrian Cox   usb: Fix USB keyb...
352
  		       1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE);
8454c84af   Hans de Goede   usb: kbd: Fix key...
353
  	if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
354
  		usb_kbd_irq_worker(dev);
8454c84af   Hans de Goede   usb: kbd: Fix key...
355
  #else
8e5531198   Hans de Goede   usb: kbd: Add (op...
356
357
358
359
360
361
  	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   Hans de Goede   usb: Add an inter...
362
363
  				      USB_KBD_BOOT_REPORT_SIZE, data->new,
  				      data->intinterval);
8454c84af   Hans de Goede   usb: kbd: Fix key...
364
365
366
367
368
369
370
  #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   Hans de Goede   usb: kbd: Add (op...
371
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
372
373
374
375
  #endif
  }
  
  /* test if a character is in the queue */
709ea543b   Simon Glass   stdio: Pass devic...
376
  static int usb_kbd_testc(struct stdio_dev *sdev)
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
377
378
379
380
  {
  	struct stdio_dev *dev;
  	struct usb_device *usb_kbd_dev;
  	struct usb_kbd_pdata *data;
c95e2b9ea   Jim Lin   console: usb: kbd...
381
382
383
384
385
386
387
388
389
390
  #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
4fb67f47f   Michal Simek   usb_kdb: Get stdi...
391
  	dev = stdio_get_by_name(sdev->name);
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
392
393
394
395
396
397
398
399
400
  	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   Simon Glass   stdio: Pass devic...
401
  static int usb_kbd_getc(struct stdio_dev *sdev)
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
402
403
404
405
  {
  	struct stdio_dev *dev;
  	struct usb_device *usb_kbd_dev;
  	struct usb_kbd_pdata *data;
4fb67f47f   Michal Simek   usb_kdb: Get stdi...
406
  	dev = stdio_get_by_name(sdev->name);
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
407
408
  	usb_kbd_dev = (struct usb_device *)dev->priv;
  	data = usb_kbd_dev->privptr;
f8f3e0e53   Michal Simek   usb_kbd: Add supp...
409
410
  	while (data->usb_in_pointer == data->usb_out_pointer) {
  		WATCHDOG_RESET();
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
411
  		usb_kbd_poll_for_event(usb_kbd_dev);
f8f3e0e53   Michal Simek   usb_kbd: Add supp...
412
  	}
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
413
414
415
416
417
418
419
420
421
422
  
  	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   Simon Glass   dm: usb: Add supp...
423
  static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
affae2bff   wdenk   Initial revision
424
  {
8f8bd565f   Tom Rix   USB Consolidate d...
425
  	struct usb_interface *iface;
affae2bff   wdenk   Initial revision
426
  	struct usb_endpoint_descriptor *ep;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
427
  	struct usb_kbd_pdata *data;
affae2bff   wdenk   Initial revision
428

00b7d6ecc   Marek Vasut   USB: Squash check...
429
430
  	if (dev->descriptor.bNumConfigurations != 1)
  		return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
431

affae2bff   wdenk   Initial revision
432
  	iface = &dev->config.if_desc[ifnum];
2cdb58ebd   Simon Glass   usb: Avoid open-c...
433
  	if (iface->desc.bInterfaceClass != USB_CLASS_HID)
8f8bd565f   Tom Rix   USB Consolidate d...
434
  		return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
435

2cdb58ebd   Simon Glass   usb: Avoid open-c...
436
  	if (iface->desc.bInterfaceSubClass != USB_SUB_HID_BOOT)
8f8bd565f   Tom Rix   USB Consolidate d...
437
  		return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
438

2cdb58ebd   Simon Glass   usb: Avoid open-c...
439
  	if (iface->desc.bInterfaceProtocol != USB_PROT_HID_KEYBOARD)
8f8bd565f   Tom Rix   USB Consolidate d...
440
  		return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
441

8f8bd565f   Tom Rix   USB Consolidate d...
442
443
  	if (iface->desc.bNumEndpoints != 1)
  		return 0;
affae2bff   wdenk   Initial revision
444
445
  
  	ep = &iface->ep_desc[0];
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
446
  	/* Check if endpoint 1 is interrupt endpoint */
00b7d6ecc   Marek Vasut   USB: Squash check...
447
448
  	if (!(ep->bEndpointAddress & 0x80))
  		return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
449

00b7d6ecc   Marek Vasut   USB: Squash check...
450
451
  	if ((ep->bmAttributes & 3) != 3)
  		return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
452

ceb4972a8   Vivek Gautam   usb: common: Weed...
453
454
  	debug("USB KBD: found set protocol...
  ");
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
455
456
457
458
459
460
461
462
463
464
  
  	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   Allen Martin   USB: make usb_kbd...
465
  	/* allocate input buffer aligned and sized to USB DMA alignment */
08a98b89d   Adrian Cox   usb: Fix USB keyb...
466
467
  	data->new = memalign(USB_DMA_MINALIGN,
  		roundup(USB_KBD_BOOT_REPORT_SIZE, USB_DMA_MINALIGN));
d7475386b   Allen Martin   USB: make usb_kbd...
468

9a8c72a6c   Marek Vasut   USB: Rework usb_k...
469
470
471
472
473
  	/* Insert private data into USB device structure */
  	dev->privptr = data;
  
  	/* Set IRQ handler */
  	dev->irq_handle = usb_kbd_irq;
8f8d7d245   Hans de Goede   usb: kbd: Cache p...
474
475
476
477
  	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   Hans de Goede   usb: kbd: Fix key...
478
  	data->last_report = -1;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
479
480
481
  
  	/* We found a USB Keyboard, install it. */
  	usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
de451493f   Hans de Goede   usb: kbd: Disable...
482
483
  	debug("USB KBD: found set idle...
  ");
8454c84af   Hans de Goede   usb: kbd: Fix key...
484
485
  #if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \
      !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)
8454c84af   Hans de Goede   usb: kbd: Fix key...
486
  	usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0);
de451493f   Hans de Goede   usb: kbd: Disable...
487
488
  #else
  	usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0);
8454c84af   Hans de Goede   usb: kbd: Fix key...
489
  #endif
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
490

ceb4972a8   Vivek Gautam   usb: common: Weed...
491
492
  	debug("USB KBD: enable interrupt pipe...
  ");
8e5531198   Hans de Goede   usb: kbd: Add (op...
493
494
  #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
  	data->intq = create_int_queue(dev, data->intpipe, 1,
8bb6c1d1e   Hans de Goede   usb: Add an inter...
495
496
  				      USB_KBD_BOOT_REPORT_SIZE, data->new,
  				      data->intinterval);
8e5531198   Hans de Goede   usb: kbd: Add (op...
497
  	if (!data->intq) {
e4b70d803   Stephen Warren   usb: kbd: don't u...
498
499
500
  #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   Hans de Goede   usb: kbd: Add (op...
501
  #else
fdd135bf8   Michal Suchanek   usb: usb_submit_i...
502
  	if (usb_int_msg(dev, data->intpipe, data->new, data->intpktsize,
3437121c0   Michal Suchanek   usb: Add nonblock...
503
  			data->intinterval, false) < 0) {
8e5531198   Hans de Goede   usb: kbd: Add (op...
504
  #endif
5da2dc978   Vincent Palatin   usb: workaround n...
505
506
507
508
509
510
  		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   Marek Vasut   USB: Rework usb_k...
511
512
  
  	/* Success. */
affae2bff   wdenk   Initial revision
513
514
  	return 1;
  }
603afaf0e   Simon Glass   dm: usb: Split ou...
515
516
517
518
519
520
521
  static int probe_usb_keyboard(struct usb_device *dev)
  {
  	char *stdinname;
  	struct stdio_dev usb_kbd_dev;
  	int error;
  
  	/* Try probing the keyboard */
34ab37eef   Simon Glass   dm: usb: Add supp...
522
  	if (usb_kbd_probe_dev(dev, 0) != 1)
603afaf0e   Simon Glass   dm: usb: Split ou...
523
524
525
526
527
528
529
  		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   Bin Meng   video: Drop DEV_F...
530
  	usb_kbd_dev.flags =  DEV_FLAGS_INPUT;
603afaf0e   Simon Glass   dm: usb: Split ou...
531
532
533
534
535
536
  	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   Simon Glass   env: Rename geten...
537
  	stdinname = env_get("stdin");
b02654294   Simon Glass   console: Don't en...
538
  #if CONFIG_IS_ENABLED(CONSOLE_MUX)
603afaf0e   Simon Glass   dm: usb: Split ou...
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  	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;
  }
fd09c205f   Sven Schwermer   usb: s/CONFIG_DM_...
558
  #if !CONFIG_IS_ENABLED(DM_USB)
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
559
560
561
  /* Search for keyboard and register it if found. */
  int drv_usb_kbd_init(void)
  {
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
562
  	int error, i;
697033cbf   Simon Glass   dm: usb: Support ...
563
564
  	debug("%s: Probing for keyboard
  ", __func__);
697033cbf   Simon Glass   dm: usb: Support ...
565
  	/* Scan all USB Devices */
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
566
  	for (i = 0; i < USB_MAX_DEVICE; i++) {
603afaf0e   Simon Glass   dm: usb: Split ou...
567
  		struct usb_device *dev;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
568
569
570
  		/* Get USB device. */
  		dev = usb_get_dev_index(i);
  		if (!dev)
603afaf0e   Simon Glass   dm: usb: Split ou...
571
  			break;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
572
573
574
  
  		if (dev->devnum == -1)
  			continue;
603afaf0e   Simon Glass   dm: usb: Split ou...
575
576
  		error = probe_usb_keyboard(dev);
  		if (!error)
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
577
  			return 1;
603afaf0e   Simon Glass   dm: usb: Split ou...
578
  		if (error && error != -ENOENT)
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
579
  			return error;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
580
581
582
583
584
585
586
  	}
  
  	/* No USB Keyboard found */
  	return -1;
  }
  
  /* Deregister the keyboard. */
8a8a2257e   Hans de Goede   usb: kbd: Allow "...
587
  int usb_kbd_deregister(int force)
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
588
  {
869588dec   Simon Glass   Convert CONFIG_SY...
589
  #if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER)
dfe5b1c86   Hans de Goede   usb: kbd: Fix mem...
590
591
592
593
594
595
596
597
598
599
  	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   Simon Glass   console: Don't en...
600
  #if CONFIG_IS_ENABLED(CONSOLE_MUX)
00caae6d4   Simon Glass   env: Rename geten...
601
  		if (iomux_doenv(stdin, env_get("stdin")) != 0)
3cbcb2892   Hans de Goede   usb: Fix usb_kbd_...
602
603
  			return 1;
  #endif
8e5531198   Hans de Goede   usb: kbd: Add (op...
604
605
606
  #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
  		destroy_int_queue(usb_kbd_dev, data->intq);
  #endif
dfe5b1c86   Hans de Goede   usb: kbd: Fix mem...
607
608
609
  		free(data->new);
  		free(data);
  	}
0ea09dfe8   Hans de Goede   usb: kbd: Do not ...
610
611
  
  	return 0;
9a8c72a6c   Marek Vasut   USB: Rework usb_k...
612
613
614
615
  #else
  	return 1;
  #endif
  }
34ab37eef   Simon Glass   dm: usb: Add supp...
616

9a80e7143   Hans de Goede   usb: kbd: Do not ...
617
  #endif
fd09c205f   Sven Schwermer   usb: s/CONFIG_DM_...
618
  #if CONFIG_IS_ENABLED(DM_USB)
34ab37eef   Simon Glass   dm: usb: Add supp...
619
620
621
622
  
  static int usb_kbd_probe(struct udevice *dev)
  {
  	struct usb_device *udev = dev_get_parent_priv(dev);
34ab37eef   Simon Glass   dm: usb: Add supp...
623

8319aeb1d   Masahiro Yamada   usb: squash lines...
624
  	return probe_usb_keyboard(udev);
34ab37eef   Simon Glass   dm: usb: Add supp...
625
  }
8a8348703   Simon Glass   dm: usb: Add a re...
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  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   Simon Glass   console: Don't en...
643
  #if CONFIG_IS_ENABLED(CONSOLE_MUX)
00caae6d4   Simon Glass   env: Rename geten...
644
  	if (iomux_doenv(stdin, env_get("stdin"))) {
8a8348703   Simon Glass   dm: usb: Add a re...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
  		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   Simon Glass   dm: usb: Add supp...
660
661
662
663
664
665
666
667
668
669
  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   Simon Glass   dm: usb: Add a re...
670
  	.remove = usb_kbd_remove,
34ab37eef   Simon Glass   dm: usb: Add supp...
671
  };
34ab37eef   Simon Glass   dm: usb: Add supp...
672
673
674
675
676
677
  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   Simon Glass   usb: Avoid open-c...
678
679
  		.bInterfaceSubClass = USB_SUB_HID_BOOT,
  		.bInterfaceProtocol = USB_PROT_HID_KEYBOARD,
34ab37eef   Simon Glass   dm: usb: Add supp...
680
681
682
683
684
685
686
  	},
  	{ }		/* Terminating entry */
  };
  
  U_BOOT_USB_DEVICE(usb_kbd, kbd_id_table);
  
  #endif