summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/usb/usbkbd.h
blob: 7eab24e460e673ce277234490643dd3af2fbd139 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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
129
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
#ifndef _USBKBD_H
#define _USBKBD_H

/** @file
 *
 * USB keyboard driver
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <assert.h>
#include <ipxe/usb.h>
#include <ipxe/usbhid.h>

/** Keyboard protocol */
#define USBKBD_PROTOCOL 1

/** A USB keyboard report */
struct usb_keyboard_report {
	/** Modifier keys */
	uint8_t modifiers;
	/** Reserved */
	uint8_t reserved;
	/** Keycodes */
	uint8_t keycode[6];
} __attribute__ (( packed ));

/** USB modifier keys */
enum usb_keyboard_modifier {
	/** Left Ctrl key */
	USBKBD_CTRL_LEFT = 0x01,
	/** Left Shift key */
	USBKBD_SHIFT_LEFT = 0x02,
	/** Left Alt key */
	USBKBD_ALT_LEFT = 0x04,
	/** Left GUI key */
	USBKBD_GUI_LEFT = 0x08,
	/** Right Ctrl key */
	USBKBD_CTRL_RIGHT = 0x10,
	/** Right Shift key */
	USBKBD_SHIFT_RIGHT = 0x20,
	/** Right Alt key */
	USBKBD_ALT_RIGHT = 0x40,
	/** Right GUI key */
	USBKBD_GUI_RIGHT = 0x80,
};

/** Either Ctrl key */
#define USBKBD_CTRL ( USBKBD_CTRL_LEFT | USBKBD_CTRL_RIGHT )

/** Either Shift key */
#define USBKBD_SHIFT ( USBKBD_SHIFT_LEFT | USBKBD_SHIFT_RIGHT )

/** Either Alt key */
#define USBKBD_ALT ( USBKBD_ALT_LEFT | USBKBD_ALT_RIGHT )

/** Either GUI key */
#define USBKBD_GUI ( USBKBD_GUI_LEFT | USBKBD_GUI_RIGHT )

/** USB keycodes */
enum usb_keycode {
	USBKBD_KEY_A = 0x04,
	USBKBD_KEY_Z = 0x1d,
	USBKBD_KEY_1 = 0x1e,
	USBKBD_KEY_0 = 0x27,
	USBKBD_KEY_ENTER = 0x28,
	USBKBD_KEY_SPACE = 0x2c,
	USBKBD_KEY_MINUS = 0x2d,
	USBKBD_KEY_SLASH = 0x38,
	USBKBD_KEY_CAPSLOCK = 0x39,
	USBKBD_KEY_UP = 0x52,
};

/** Keyboard idle duration (in 4ms units)
 *
 * This is a policy decision.  We choose to use an autorepeat rate of
 * approximately 40ms.
 */
#define USBKBD_IDLE_DURATION 10 /* 10 x 4ms = 40ms */

/** Keyboard auto-repeat hold-off (in units of USBKBD_IDLE_DURATION)
 *
 * This is a policy decision.  We choose to use an autorepeat delay of
 * approximately 500ms.
 */
#define USBKBD_HOLDOFF 12 /* 12 x 40ms = 480ms */

/** Interrupt endpoint maximum fill level
 *
 * When idling, we are likely to poll the USB endpoint at only the
 * 18.2Hz system timer tick rate.  With a typical observed bInterval
 * of 10ms (which will be rounded down to 8ms by the HCI drivers),
 * this gives approximately 7 completions per poll.
 */
#define USBKBD_INTR_MAX_FILL 8

/** Keyboard buffer size
 *
 * Must be a power of two.
 */
#define USBKBD_BUFSIZE 8

/** A USB keyboard device */
struct usb_keyboard {
	/** Name */
	const char *name;
	/** List of all USB keyboards */
	struct list_head list;

	/** USB bus */
	struct usb_bus *bus;
	/** USB human interface device */
	struct usb_hid hid;

	/** Most recent keyboard report */
	struct usb_keyboard_report report;
	/** Most recently pressed non-modifier key (if any) */
	unsigned int keycode;
	/** Autorepeat hold-off time (in number of completions reported) */
	unsigned int holdoff;

	/** Keyboard buffer
	 *
	 * This stores iPXE key values.
	 */
	unsigned int key[USBKBD_BUFSIZE];
	/** Keyboard buffer producer counter */
	unsigned int prod;
	/** Keyboard buffer consumer counter */
	unsigned int cons;
	/** Keyboard buffer sub-consumer counter
	 *
	 * This represents the index within the ANSI escape sequence
	 * corresponding to an iPXE key value.
	 */
	unsigned int subcons;
};

/**
 * Calculate keyboard buffer fill level
 *
 * @v kbd		USB keyboard
 * @ret fill		Keyboard buffer fill level
 */
static inline __attribute__ (( always_inline )) unsigned int
usbkbd_fill ( struct usb_keyboard *kbd ) {
	unsigned int fill = ( kbd->prod - kbd->cons );

	assert ( fill <= USBKBD_BUFSIZE );
	return fill;
}

#endif /* _USBKBD_H */