Blame view

drivers/input/input.c 19.9 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
9bc590e51   Simon Glass   input: Add generi...
2
3
4
5
6
  /*
   * Translate key codes into ASCII
   *
   * Copyright (c) 2011 The Chromium OS Authors.
   * (C) Copyright 2004 DENX Software Engineering, Wolfgang Denk, wd@denx.de
9bc590e51   Simon Glass   input: Add generi...
7
8
9
   */
  
  #include <common.h>
24b852a7a   Simon Glass   Move console defi...
10
  #include <console.h>
cd810918f   Bin Meng   input: Call keybo...
11
  #include <dm.h>
92778b278   Simon Glass   input: Return -EN...
12
  #include <errno.h>
9bc590e51   Simon Glass   input: Add generi...
13
14
  #include <stdio_dev.h>
  #include <input.h>
cd810918f   Bin Meng   input: Call keybo...
15
16
17
  #ifdef CONFIG_DM_KEYBOARD
  #include <keyboard.h>
  #endif
9bc590e51   Simon Glass   input: Add generi...
18
19
20
21
  #include <linux/input.h>
  
  enum {
  	/* These correspond to the lights on the keyboard */
377a06964   Bin Meng   input: Change LED...
22
23
24
  	FLAG_SCROLL_LOCK	= 1 << 0,
  	FLAG_NUM_LOCK		= 1 << 1,
  	FLAG_CAPS_LOCK		= 1 << 2,
9bc590e51   Simon Glass   input: Add generi...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  
  	/* Special flag ORed with key code to indicate release */
  	KEY_RELEASE		= 1 << 15,
  	KEY_MASK		= 0xfff,
  };
  
  /*
   * These takes map key codes to ASCII. 0xff means no key, or special key.
   * Three tables are provided - one for plain keys, one for when the shift
   * 'modifier' key is pressed and one for when the ctrl modifier key is
   * pressed.
   */
  static const uchar kbd_plain_xlate[] = {
  	0xff, 0x1b, '1',  '2',  '3',  '4',  '5',  '6',
  	'7',  '8',  '9',  '0',  '-',  '=', '\b', '\t',	/* 0x00 - 0x0f */
  	'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
  	'o',  'p',  '[',  ']', '\r', 0xff,  'a',  's',  /* 0x10 - 0x1f */
  	'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',
  	'\'',  '`', 0xff, '\\', 'z',  'x',  'c',  'v',	/* 0x20 - 0x2f */
  	'b',  'n',  'm',  ',' ,  '.', '/', 0xff, 0xff, 0xff,
  	' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 0x30 - 0x3f */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  '7',
  	'8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',	/* 0x40 - 0x4f */
  	'2',  '3',  '0',  '.', 0xff, 0xff, 0xff, 0xff,
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 0x50 - 0x5F */
77c7f0459   Simon Glass   input: Add a few ...
50
  	'\r', 0xff, '/',  '*',
9bc590e51   Simon Glass   input: Add generi...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  };
  
  static unsigned char kbd_shift_xlate[] = {
  	0xff, 0x1b, '!', '@', '#', '$', '%', '^',
  	'&', '*', '(', ')', '_', '+', '\b', '\t',	/* 0x00 - 0x0f */
  	'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
  	'O', 'P', '{', '}', '\r', 0xff, 'A', 'S',	/* 0x10 - 0x1f */
  	'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
  	'"', '~', 0xff, '|', 'Z', 'X', 'C', 'V',	/* 0x20 - 0x2f */
  	'B', 'N', 'M', '<', '>', '?', 0xff, 0xff, 0xff,
  	' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 0x30 - 0x3f */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
  	'8', '9', '-', '4', '5', '6', '+', '1',	/* 0x40 - 0x4f */
  	'2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff, 0xff,
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 0x50 - 0x5F */
77c7f0459   Simon Glass   input: Add a few ...
66
  	'\r', 0xff, '/',  '*',
9bc590e51   Simon Glass   input: Add generi...
67
68
69
70
71
  };
  
  static unsigned char kbd_ctrl_xlate[] = {
  	0xff, 0x1b, '1', 0x00, '3', '4', '5', 0x1E,
  	'7', '8', '9', '0', 0x1F, '=', '\b', '\t',	/* 0x00 - 0x0f */
2e5513bda   Simon Glass   input: Correct ke...
72
  	0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09,
9bc590e51   Simon Glass   input: Add generi...
73
74
75
76
77
78
79
80
81
82
  	0x0f, 0x10, 0x1b, 0x1d, '
  ', 0xff, 0x01, 0x13,	/* 0x10 - 0x1f */
  	0x04, 0x06, 0x08, 0x09, 0x0a, 0x0b, 0x0c, ';',
  	'\'', '~', 0x00, 0x1c, 0x1a, 0x18, 0x03, 0x16,	/* 0x20 - 0x2f */
  	0x02, 0x0e, 0x0d, '<', '>', '?', 0xff, 0xff,
  	0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 0x30 - 0x3f */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
  	'8', '9', '-', '4', '5', '6', '+', '1',		/* 0x40 - 0x4f */
  	'2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff,
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 0x50 - 0x5F */
77c7f0459   Simon Glass   input: Add a few ...
83
  	'\r', 0xff, '/',  '*',
9bc590e51   Simon Glass   input: Add generi...
84
  };
a84f55926   Heinrich Schuchardt   input: indicate t...
85
86
87
  /*
   * German keymap. Special letters are mapped according to code page 437.
   */
b1d7a1875   Simon Glass   input: Support th...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  static const uchar kbd_plain_xlate_german[] = {
  	0xff, 0x1b,  '1',  '2',  '3',  '4',  '5',  '6', /* scan 00-07 */
  	 '7',  '8',  '9',  '0', 0xe1, '\'', 0x08, '\t', /* scan 08-0F */
  	 'q',  'w',  'e',  'r',  't',  'z',  'u',  'i', /* scan 10-17 */
  	 'o',  'p', 0x81,  '+', '\r', 0xff,  'a',  's', /* scan 18-1F */
  	 'd',  'f',  'g',  'h',  'j',  'k',  'l', 0x94, /* scan 20-27 */
  	0x84,  '^', 0xff,  '#',  'y',  'x',  'c',  'v', /* scan 28-2F */
  	 'b',  'n',  'm',  ',',  '.',  '-', 0xff,  '*', /* scan 30-37 */
  	 ' ',  ' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  '7', /* scan 40-47 */
  	 '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1', /* scan 48-4F */
  	 '2',  '3',  '0',  ',', 0xff, 0xff,  '<', 0xff, /* scan 50-57 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
  	'\r', 0xff,  '/',  '*',
  };
  
  static unsigned char kbd_shift_xlate_german[] = {
  	   0xff, 0x1b,  '!',  '"', 0x15,  '$',  '%',  '&', /* scan 00-07 */
  	 '/',  '(',  ')',  '=',  '?',  '`', 0x08, '\t', /* scan 08-0F */
  	 'Q',  'W',  'E',  'R',  'T',  'Z',  'U',  'I', /* scan 10-17 */
  	 'O',  'P', 0x9a,  '*', '\r', 0xff,  'A',  'S', /* scan 18-1F */
  	 'D',  'F',  'G',  'H',  'J',  'K',  'L', 0x99, /* scan 20-27 */
  	0x8e, 0xf8, 0xff, '\'',  'Y',  'X',  'C',  'V', /* scan 28-2F */
  	 'B',  'N',  'M',  ';',  ':',  '_', 0xff,  '*', /* scan 30-37 */
  	 ' ',  ' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  '7', /* scan 40-47 */
  	 '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1', /* scan 48-4F */
  	 '2',  '3',  '0',  ',', 0xff, 0xff,  '>', 0xff, /* scan 50-57 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
  	'\r', 0xff,  '/',  '*',
  };
  
  static unsigned char kbd_right_alt_xlate_german[] = {
a84f55926   Heinrich Schuchardt   input: indicate t...
129
  	0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, /* scan 00-07 */
b1d7a1875   Simon Glass   input: Support th...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  	 '{',  '[',  ']',  '}', '\\', 0xff, 0xff, 0xff, /* scan 08-0F */
  	 '@', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10-17 */
  	0xff, 0xff, 0xff,  '~', 0xff, 0xff, 0xff, 0xff, /* scan 18-1F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20-27 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28-2F */
  	0xff, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30-37 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40-47 */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */
  	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  '|', 0xff, /* scan 50-57 */
  };
  
  enum kbd_mask {
  	KBD_ENGLISH	= 1 << 0,
  	KBD_GERMAN	= 1 << 1,
  };
  
  static struct kbd_entry {
  	int kbd_mask;		/* Which languages this is for */
  	int left_keycode;	/* Left keycode to select this map */
  	int right_keycode;	/* Right keycode to select this map */
  	const uchar *xlate;	/* Ascii code for each keycode */
  	int num_entries;	/* Number of entries in xlate */
  } kbd_entry[] = {
  	{ KBD_ENGLISH, -1, -1,
  		kbd_plain_xlate, ARRAY_SIZE(kbd_plain_xlate) },
  	{ KBD_GERMAN, -1, -1,
  		kbd_plain_xlate_german, ARRAY_SIZE(kbd_plain_xlate_german) },
  	{ KBD_ENGLISH, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
  		kbd_shift_xlate, ARRAY_SIZE(kbd_shift_xlate) },
  	{ KBD_GERMAN, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
  		kbd_shift_xlate_german, ARRAY_SIZE(kbd_shift_xlate_german) },
  	{ KBD_ENGLISH | KBD_GERMAN, KEY_LEFTCTRL, KEY_RIGHTCTRL,
  		kbd_ctrl_xlate, ARRAY_SIZE(kbd_ctrl_xlate) },
  	{ KBD_GERMAN, -1, KEY_RIGHTALT,
  		kbd_right_alt_xlate_german,
  		ARRAY_SIZE(kbd_right_alt_xlate_german) },
  	{},
  };
44abe47de   Hung-Te Lin   input: Add ANSI 3...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  /*
   * Scan key code to ANSI 3.64 escape sequence table.  This table is
   * incomplete in that it does not include all possible extra keys.
   */
  static struct {
  	int kbd_scan_code;
  	char *escape;
  } kbd_to_ansi364[] = {
  	{ KEY_UP, "\033[A"},
  	{ KEY_DOWN, "\033[B"},
  	{ KEY_RIGHT, "\033[C"},
  	{ KEY_LEFT, "\033[D"},
  };
  
  /* Maximum number of output characters that an ANSI sequence expands to */
  #define ANSI_CHAR_MAX	3
9bc590e51   Simon Glass   input: Add generi...
185

c14e94e56   Kim Phillips   drivers/input/inp...
186
  static int input_queue_ascii(struct input_config *config, int ch)
9bc590e51   Simon Glass   input: Add generi...
187
188
189
190
191
192
193
194
195
196
197
  {
  	if (config->fifo_in + 1 == INPUT_BUFFER_LEN) {
  		if (!config->fifo_out)
  			return -1; /* buffer full */
  		else
  			config->fifo_in = 0;
  	} else {
  		if (config->fifo_in + 1 == config->fifo_out)
  			return -1; /* buffer full */
  		config->fifo_in++;
  	}
3a85e4362   Simon Glass   input: Add a func...
198
  	debug(" {%02x} ", ch);
9bc590e51   Simon Glass   input: Add generi...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  	config->fifo[config->fifo_in] = (uchar)ch;
  
  	return 0;
  }
  
  int input_tstc(struct input_config *config)
  {
  	if (config->fifo_in == config->fifo_out && config->read_keys) {
  		if (!(*config->read_keys)(config))
  			return 0;
  	}
  	return config->fifo_in != config->fifo_out;
  }
  
  int input_getc(struct input_config *config)
  {
  	int err = 0;
  
  	while (config->fifo_in == config->fifo_out) {
  		if (config->read_keys)
  			err = (*config->read_keys)(config);
  		if (err)
  			return -1;
  	}
  
  	if (++config->fifo_out == INPUT_BUFFER_LEN)
  		config->fifo_out = 0;
  
  	return config->fifo[config->fifo_out];
  }
  
  /**
   * Process a modifier/special key press or release and decide which key
   * translation array should be used as a result.
   *
   * TODO: Should keep track of modifier press/release
   *
   * @param config	Input state
   * @param key		Key code to process
   * @param release	0 if a press, 1 if a release
   * @return pointer to keycode->ascii translation table that should be used
   */
  static struct input_key_xlate *process_modifier(struct input_config *config,
  						int key, int release)
  {
cd810918f   Bin Meng   input: Call keybo...
244
245
246
247
  #ifdef CONFIG_DM_KEYBOARD
  	struct udevice *dev = config->dev;
  	struct keyboard_ops *ops = keyboard_get_ops(dev);
  #endif
9bc590e51   Simon Glass   input: Add generi...
248
  	struct input_key_xlate *table;
9bc590e51   Simon Glass   input: Add generi...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  	int i;
  
  	/* Start with the main table, and see what modifiers change it */
  	assert(config->num_tables > 0);
  	table = &config->table[0];
  	for (i = 1; i < config->num_tables; i++) {
  		struct input_key_xlate *tab = &config->table[i];
  
  		if (key == tab->left_keycode || key == tab->right_keycode)
  			table = tab;
  	}
  
  	/* Handle the lighted keys */
  	if (!release) {
a683d0d34   Simon Glass   input: Adjust str...
263
  		int flip = -1;
9bc590e51   Simon Glass   input: Add generi...
264
265
266
267
268
269
270
271
272
273
274
  		switch (key) {
  		case KEY_SCROLLLOCK:
  			flip = FLAG_SCROLL_LOCK;
  			break;
  		case KEY_NUMLOCK:
  			flip = FLAG_NUM_LOCK;
  			break;
  		case KEY_CAPSLOCK:
  			flip = FLAG_CAPS_LOCK;
  			break;
  		}
9bc590e51   Simon Glass   input: Add generi...
275

a683d0d34   Simon Glass   input: Adjust str...
276
277
  		if (flip != -1) {
  			int leds = 0;
533c81a94   Bin Meng   input: Save keybo...
278
  			config->flags ^= flip;
a683d0d34   Simon Glass   input: Adjust str...
279
280
281
282
283
284
285
  			if (config->flags & FLAG_NUM_LOCK)
  				leds |= INPUT_LED_NUM;
  			if (config->flags & FLAG_CAPS_LOCK)
  				leds |= INPUT_LED_CAPS;
  			if (config->flags & FLAG_SCROLL_LOCK)
  				leds |= INPUT_LED_SCROLL;
  			config->leds = leds;
3b5f6f500   Simon Glass   input: Allow upda...
286
  			config->leds_changed = flip;
cd810918f   Bin Meng   input: Call keybo...
287
288
289
290
291
292
293
294
  
  #ifdef CONFIG_DM_KEYBOARD
  			if (ops->update_leds) {
  				if (ops->update_leds(dev, config->leds))
  					debug("Update keyboard's LED failed
  ");
  			}
  #endif
a683d0d34   Simon Glass   input: Adjust str...
295
  		}
9bc590e51   Simon Glass   input: Add generi...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  	}
  
  	return table;
  }
  
  /**
   * Search an int array for a key value
   *
   * @param array	Array to search
   * @param count	Number of elements in array
   * @param key	Key value to find
   * @return element where value was first found, -1 if none
   */
  static int array_search(int *array, int count, int key)
  {
  	int i;
  
  	for (i = 0; i < count; i++) {
  		if (array[i] == key)
  			return i;
  	}
  
  	return -1;
  }
  
  /**
   * Sort an array so that those elements that exist in the ordering are
   * first in the array, and in the same order as the ordering. The algorithm
   * is O(count * ocount) and designed for small arrays.
   *
   * TODO: Move this to common / lib?
   *
   * @param dest		Array with elements to sort, also destination array
   * @param count		Number of elements to sort
   * @param order		Array containing ordering elements
   * @param ocount	Number of ordering elements
   * @return number of elements in dest that are in order (these will be at the
   *	start of dest).
   */
  static int sort_array_by_ordering(int *dest, int count, int *order,
  				   int ocount)
  {
  	int temp[count];
  	int dest_count;
  	int same;	/* number of elements which are the same */
  	int i;
  
  	/* setup output items, copy items to be sorted into our temp area */
  	memcpy(temp, dest, count * sizeof(*dest));
  	dest_count = 0;
  
  	/* work through the ordering, move over the elements we agree on */
  	for (i = 0; i < ocount; i++) {
  		if (array_search(temp, count, order[i]) != -1)
  			dest[dest_count++] = order[i];
  	}
  	same = dest_count;
  
  	/* now move over the elements that are not in the ordering */
  	for (i = 0; i < count; i++) {
  		if (array_search(order, ocount, temp[i]) == -1)
  			dest[dest_count++] = temp[i];
  	}
  	assert(dest_count == count);
  	return same;
  }
  
  /**
   * Check a list of key codes against the previous key scan
   *
   * Given a list of new key codes, we check how many of these are the same
   * as last time.
   *
   * @param config	Input state
   * @param keycode	List of key codes to examine
   * @param num_keycodes	Number of key codes
   * @param same		Returns number of key codes which are the same
   */
  static int input_check_keycodes(struct input_config *config,
  			   int keycode[], int num_keycodes, int *same)
  {
  	/* Select the 'plain' xlate table to start with */
  	if (!config->num_tables) {
  		debug("%s: No xlate tables: cannot decode keys
  ", __func__);
  		return -1;
  	}
  
  	/* sort the keycodes into the same order as the previous ones */
  	*same = sort_array_by_ordering(keycode, num_keycodes,
  			config->prev_keycodes, config->num_prev_keycodes);
  
  	memcpy(config->prev_keycodes, keycode, num_keycodes * sizeof(int));
  	config->num_prev_keycodes = num_keycodes;
  
  	return *same != num_keycodes;
  }
  
  /**
44abe47de   Hung-Te Lin   input: Add ANSI 3...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
   * Checks and converts a special key code into ANSI 3.64 escape sequence.
   *
   * @param config	Input state
   * @param keycode	Key code to examine
   * @param output_ch	Buffer to place output characters into. It should
   *			be at least ANSI_CHAR_MAX bytes long, to allow for
   *			an ANSI sequence.
   * @param max_chars	Maximum number of characters to add to output_ch
   * @return number of characters output, if the key was converted, otherwise 0.
   *	This may be larger than max_chars, in which case the overflow
   *	characters are not output.
   */
  static int input_keycode_to_ansi364(struct input_config *config,
  		int keycode, char output_ch[], int max_chars)
  {
  	const char *escape;
  	int ch_count;
  	int i;
  
  	for (i = ch_count = 0; i < ARRAY_SIZE(kbd_to_ansi364); i++) {
  		if (keycode != kbd_to_ansi364[i].kbd_scan_code)
  			continue;
  		for (escape = kbd_to_ansi364[i].escape; *escape; escape++) {
  			if (ch_count < max_chars)
  				output_ch[ch_count] = *escape;
  			ch_count++;
  		}
  		return ch_count;
  	}
  
  	return 0;
  }
  
  /**
   * Converts and queues a list of key codes in escaped ASCII string form
9bc590e51   Simon Glass   input: Add generi...
430
431
432
   * Convert a list of key codes into ASCII
   *
   * You must call input_check_keycodes() before this. It turns the keycode
44abe47de   Hung-Te Lin   input: Add ANSI 3...
433
   * list into a list of ASCII characters and sends them to the input layer.
9bc590e51   Simon Glass   input: Add generi...
434
435
   *
   * Characters which were seen last time do not generate fresh ASCII output.
44abe47de   Hung-Te Lin   input: Add ANSI 3...
436
437
   * The output (calls to queue_ascii) may be longer than num_keycodes, if the
   * keycode contains special keys that was encoded to longer escaped sequence.
9bc590e51   Simon Glass   input: Add generi...
438
439
440
441
   *
   * @param config	Input state
   * @param keycode	List of key codes to examine
   * @param num_keycodes	Number of key codes
44abe47de   Hung-Te Lin   input: Add ANSI 3...
442
443
444
445
   * @param output_ch	Buffer to place output characters into. It should
   *			be at last ANSI_CHAR_MAX * num_keycodes, to allow for
   *			ANSI sequences.
   * @param max_chars	Maximum number of characters to add to output_ch
9bc590e51   Simon Glass   input: Add generi...
446
   * @param same		Number of key codes which are the same
44abe47de   Hung-Te Lin   input: Add ANSI 3...
447
448
   * @return number of characters written into output_ch, or -1 if we would
   *	exceed max_chars chars.
9bc590e51   Simon Glass   input: Add generi...
449
450
   */
  static int input_keycodes_to_ascii(struct input_config *config,
44abe47de   Hung-Te Lin   input: Add ANSI 3...
451
452
  		int keycode[], int num_keycodes, char output_ch[],
  		int max_chars, int same)
9bc590e51   Simon Glass   input: Add generi...
453
454
  {
  	struct input_key_xlate *table;
44abe47de   Hung-Te Lin   input: Add ANSI 3...
455
  	int ch_count = 0;
9bc590e51   Simon Glass   input: Add generi...
456
457
458
459
460
461
462
463
464
465
466
467
468
  	int i;
  
  	table = &config->table[0];
  
  	/* deal with modifiers first */
  	for (i = 0; i < num_keycodes; i++) {
  		int key = keycode[i] & KEY_MASK;
  
  		if (key >= table->num_entries || table->xlate[key] == 0xff) {
  			table = process_modifier(config, key,
  					keycode[i] & KEY_RELEASE);
  		}
  	}
44abe47de   Hung-Te Lin   input: Add ANSI 3...
469
470
  	/* Start conversion by looking for the first new keycode (by same). */
  	for (i = same; i < num_keycodes; i++) {
9bc590e51   Simon Glass   input: Add generi...
471
  		int key = keycode[i];
ba4203426   Simon Glass   input: Handle cap...
472
  		int ch;
9bc590e51   Simon Glass   input: Add generi...
473

44abe47de   Hung-Te Lin   input: Add ANSI 3...
474
475
476
477
  		/*
  		 * For a normal key (with an ASCII value), add it; otherwise
  		 * translate special key to escape sequence if possible.
  		 */
ba4203426   Simon Glass   input: Handle cap...
478
479
480
481
482
  		if (key < table->num_entries) {
  			ch = table->xlate[key];
  			if ((config->flags & FLAG_CAPS_LOCK) &&
  			    ch >= 'a' && ch <= 'z')
  				ch -= 'a' - 'A';
e5f330c48   Bin Meng   input: Ban digit ...
483
484
485
486
487
488
  			/* ban digit numbers if 'Num Lock' is not on */
  			if (!(config->flags & FLAG_NUM_LOCK)) {
  				if (key >= KEY_KP7 && key <= KEY_KPDOT &&
  				    key != KEY_KPMINUS && key != KEY_KPPLUS)
  					ch = 0xff;
  			}
ba4203426   Simon Glass   input: Handle cap...
489
490
  			if (ch_count < max_chars && ch != 0xff)
  				output_ch[ch_count++] = (uchar)ch;
44abe47de   Hung-Te Lin   input: Add ANSI 3...
491
492
493
  		} else {
  			ch_count += input_keycode_to_ansi364(config, key,
  						output_ch, max_chars);
9bc590e51   Simon Glass   input: Add generi...
494
495
  		}
  	}
44abe47de   Hung-Te Lin   input: Add ANSI 3...
496
497
498
499
500
501
  	if (ch_count > max_chars) {
  		debug("%s: Output char buffer overflow size=%d, need=%d
  ",
  		      __func__, max_chars, ch_count);
  		return -1;
  	}
9bc590e51   Simon Glass   input: Add generi...
502
503
504
  	/* ok, so return keys */
  	return ch_count;
  }
3a85e4362   Simon Glass   input: Add a func...
505
506
  static int _input_send_keycodes(struct input_config *config, int keycode[],
  				int num_keycodes, bool do_send)
9bc590e51   Simon Glass   input: Add generi...
507
  {
44abe47de   Hung-Te Lin   input: Add ANSI 3...
508
  	char ch[num_keycodes * ANSI_CHAR_MAX];
9bc590e51   Simon Glass   input: Add generi...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  	int count, i, same = 0;
  	int is_repeat = 0;
  	unsigned delay_ms;
  
  	config->modifiers = 0;
  	if (!input_check_keycodes(config, keycode, num_keycodes, &same)) {
  		/*
  		 * Same as last time - is it time for another repeat?
  		 * TODO(sjg@chromium.org) We drop repeats here and since
  		 * the caller may not call in again for a while, our
  		 * auto-repeat speed is not quite correct. We should
  		 * insert another character if we later realise that we
  		 * have missed a repeat slot.
  		 */
0b186c082   Simon Glass   input: Allow repe...
523
524
  		is_repeat = config->allow_repeats || (config->repeat_rate_ms &&
  			(int)get_timer(config->next_repeat_ms) >= 0);
9bc590e51   Simon Glass   input: Add generi...
525
526
527
528
529
  		if (!is_repeat)
  			return 0;
  	}
  
  	count = input_keycodes_to_ascii(config, keycode, num_keycodes,
44abe47de   Hung-Te Lin   input: Add ANSI 3...
530
  					ch, sizeof(ch), is_repeat ? 0 : same);
3a85e4362   Simon Glass   input: Add a func...
531
532
533
534
  	if (do_send) {
  		for (i = 0; i < count; i++)
  			input_queue_ascii(config, ch[i]);
  	}
9bc590e51   Simon Glass   input: Add generi...
535
536
537
538
539
  	delay_ms = is_repeat ?
  			config->repeat_rate_ms :
  			config->repeat_delay_ms;
  
  	config->next_repeat_ms = get_timer(0) + delay_ms;
44abe47de   Hung-Te Lin   input: Add ANSI 3...
540
541
  
  	return count;
9bc590e51   Simon Glass   input: Add generi...
542
  }
3a85e4362   Simon Glass   input: Add a func...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  int input_send_keycodes(struct input_config *config, int keycode[],
  			int num_keycodes)
  {
  	return _input_send_keycodes(config, keycode, num_keycodes, true);
  }
  
  int input_add_keycode(struct input_config *config, int new_keycode,
  		      bool release)
  {
  	int keycode[INPUT_MAX_MODIFIERS + 1];
  	int count, i;
  
  	/* Add the old keycodes which are not removed by this new one */
  	for (i = 0, count = 0; i < config->num_prev_keycodes; i++) {
  		int code = config->prev_keycodes[i];
  
  		if (new_keycode == code) {
  			if (release)
  				continue;
  			new_keycode = -1;
  		}
  		keycode[count++] = code;
  	}
  
  	if (!release && new_keycode != -1)
  		keycode[count++] = new_keycode;
  	debug("
  codes for %02x/%d: ", new_keycode, release);
  	for (i = 0; i < count; i++)
  		debug("%02x ", keycode[i]);
  	debug("
  ");
  
  	/* Don't output any ASCII characters if this is a key release */
  	return _input_send_keycodes(config, keycode, count, !release);
  }
9bc590e51   Simon Glass   input: Add generi...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
  int input_add_table(struct input_config *config, int left_keycode,
  		    int right_keycode, const uchar *xlate, int num_entries)
  {
  	struct input_key_xlate *table;
  
  	if (config->num_tables == INPUT_MAX_MODIFIERS) {
  		debug("%s: Too many modifier tables
  ", __func__);
  		return -1;
  	}
  
  	table = &config->table[config->num_tables++];
  	table->left_keycode = left_keycode;
  	table->right_keycode = right_keycode;
  	table->xlate = xlate;
  	table->num_entries = num_entries;
  
  	return 0;
  }
1b1d3e646   Simon Glass   input: Separate o...
598
  void input_set_delays(struct input_config *config, int repeat_delay_ms,
9bc590e51   Simon Glass   input: Add generi...
599
600
  	       int repeat_rate_ms)
  {
9bc590e51   Simon Glass   input: Add generi...
601
602
  	config->repeat_delay_ms = repeat_delay_ms;
  	config->repeat_rate_ms = repeat_rate_ms;
1b1d3e646   Simon Glass   input: Separate o...
603
  }
0b186c082   Simon Glass   input: Allow repe...
604
605
606
607
  void input_allow_repeats(struct input_config *config, bool allow_repeats)
  {
  	config->allow_repeats = allow_repeats;
  }
3b5f6f500   Simon Glass   input: Allow upda...
608
609
610
611
612
613
614
  int input_leds_changed(struct input_config *config)
  {
  	if (config->leds_changed)
  		return config->leds;
  
  	return -1;
  }
b1d7a1875   Simon Glass   input: Support th...
615
  int input_add_tables(struct input_config *config, bool german)
66877b0f5   Simon Glass   input: Add the ke...
616
  {
b1d7a1875   Simon Glass   input: Support th...
617
618
  	struct kbd_entry *entry;
  	int mask;
66877b0f5   Simon Glass   input: Add the ke...
619
  	int ret;
b1d7a1875   Simon Glass   input: Support th...
620
621
622
623
624
625
626
627
628
629
630
631
  	mask = german ? KBD_GERMAN : KBD_ENGLISH;
  	for (entry = kbd_entry; entry->kbd_mask; entry++) {
  		if (!(mask & entry->kbd_mask))
  			continue;
  		ret = input_add_table(config, entry->left_keycode,
  				      entry->right_keycode, entry->xlate,
  				      entry->num_entries);
  		if (ret)
  			return ret;
  	}
  
  	return 0;
66877b0f5   Simon Glass   input: Add the ke...
632
  }
1b1d3e646   Simon Glass   input: Separate o...
633
634
635
636
  int input_init(struct input_config *config, int leds)
  {
  	memset(config, '\0', sizeof(*config));
  	config->leds = leds;
9bc590e51   Simon Glass   input: Add generi...
637
638
639
640
641
642
643
644
645
  
  	return 0;
  }
  
  int input_stdio_register(struct stdio_dev *dev)
  {
  	int error;
  
  	error = stdio_register(dev);
985ca3945   Simon Glass   spl: input: Allow...
646
  #if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT)
9bc590e51   Simon Glass   input: Add generi...
647
  	/* check if this is the standard input device */
00caae6d4   Simon Glass   env: Rename geten...
648
  	if (!error && strcmp(env_get("stdin"), dev->name) == 0) {
9bc590e51   Simon Glass   input: Add generi...
649
650
651
652
653
  		/* reassign the console */
  		if (OVERWRITE_CONSOLE ||
  				console_assign(stdin, dev->name))
  			return -1;
  	}
985ca3945   Simon Glass   spl: input: Allow...
654
655
656
  #else
  	error = error;
  #endif
9bc590e51   Simon Glass   input: Add generi...
657
658
659
  
  	return 0;
  }