When USB keyboard active, don't send keyboard commands to ps2 port.
[seabios.git] / src / usb-hid.c
1 // Code for handling USB Human Interface Devices (HID).
2 //
3 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "util.h" // dprintf
8 #include "usb-hid.h" // usb_keyboard_setup
9 #include "config.h" // CONFIG_*
10 #include "usb.h" // usb_ctrlrequest
11 #include "biosvar.h" // GET_GLOBAL
12 #include "ps2port.h" // ATKBD_CMD_GETID
13
14 struct usb_pipe *keyboard_pipe VAR16VISIBLE;
15
16
17 /****************************************************************
18  * Setup
19  ****************************************************************/
20
21 // Send USB HID protocol message.
22 static int
23 set_protocol(struct usb_pipe *pipe, u16 val)
24 {
25     struct usb_ctrlrequest req;
26     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
27     req.bRequest = HID_REQ_SET_PROTOCOL;
28     req.wValue = val;
29     req.wIndex = 0;
30     req.wLength = 0;
31     return send_default_control(pipe, &req, NULL);
32 }
33
34 // Send USB HID SetIdle request.
35 static int
36 set_idle(struct usb_pipe *pipe, int ms)
37 {
38     struct usb_ctrlrequest req;
39     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
40     req.bRequest = HID_REQ_SET_IDLE;
41     req.wValue = (ms/4)<<8;
42     req.wIndex = 0;
43     req.wLength = 0;
44     return send_default_control(pipe, &req, NULL);
45 }
46
47 #define KEYREPEATWAITMS 500
48 #define KEYREPEATMS 33
49
50 int
51 usb_keyboard_init(struct usb_pipe *pipe
52                   , struct usb_interface_descriptor *iface, int imax)
53 {
54     if (! CONFIG_USB_KEYBOARD)
55         return -1;
56     if (keyboard_pipe)
57         // XXX - this enables the first found keyboard (could be random)
58         return -1;
59     dprintf(2, "usb_keyboard_setup %p\n", pipe);
60
61     // Find intr in endpoint.
62     struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
63         iface, imax, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
64     if (!epdesc || epdesc->wMaxPacketSize != 8) {
65         dprintf(1, "No keyboard intr in?\n");
66         return -1;
67     }
68
69     // Enable "boot" protocol.
70     int ret = set_protocol(pipe, 1);
71     if (ret)
72         return -1;
73     // Periodically send reports to enable key repeat.
74     ret = set_idle(pipe, KEYREPEATMS);
75     if (ret)
76         return -1;
77
78     keyboard_pipe = alloc_intr_pipe(pipe, epdesc);
79     if (!keyboard_pipe)
80         return -1;
81
82     dprintf(1, "USB keyboard initialized\n");
83     return 0;
84 }
85
86 void
87 usb_keyboard_setup(void)
88 {
89     if (! CONFIG_USB_KEYBOARD)
90         return;
91     keyboard_pipe = NULL;
92 }
93
94
95 /****************************************************************
96  * Keyboard events
97  ****************************************************************/
98
99 // Mapping from USB key id to ps2 key sequence.
100 static u16 KeyToScanCode[] VAR16 = {
101     0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
102     0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
103     0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
104     0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
105     0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
106     0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
107     0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
108     0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
109     0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
110     0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
111     0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
112     0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
113     0x0048, 0x0049, 0x0052, 0x0053
114 };
115
116 // Mapping from USB modifier id to ps2 key sequence.
117 static u16 ModifierToScanCode[] VAR16 = {
118     //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
119     0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
120 };
121
122 #define RELEASEBIT 0x80
123
124 // Format of USB event data
125 struct keyevent {
126     u8 modifiers;
127     u8 reserved;
128     u8 keys[6];
129 };
130
131 // Translate data from KeyToScanCode[] to calls to process_key().
132 static void
133 prockeys(u16 keys)
134 {
135     if (keys > 0xff) {
136         u8 key = keys>>8;
137         if (key == 0xe1) {
138             // Pause key
139             process_key(0xe1);
140             process_key(0x1d | (keys & RELEASEBIT));
141             process_key(0x45 | (keys & RELEASEBIT));
142             return;
143         }
144         process_key(key);
145     }
146     process_key(keys);
147 }
148
149 // Handle a USB key press/release event.
150 static void
151 procscankey(u8 key, u8 flags)
152 {
153     if (key >= ARRAY_SIZE(KeyToScanCode))
154         return;
155     u16 keys = GET_GLOBAL(KeyToScanCode[key]);
156     if (keys)
157         prockeys(keys | flags);
158 }
159
160 // Handle a USB modifier press/release event.
161 static void
162 procmodkey(u8 mods, u8 flags)
163 {
164     int i;
165     for (i=0; mods; i++)
166         if (mods & (1<<i)) {
167             // Modifier key change.
168             prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
169             mods &= ~(1<<i);
170         }
171 }
172
173 // Process USB keyboard data.
174 static void noinline
175 handle_key(struct keyevent *data)
176 {
177     dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
178
179     // Load old keys.
180     u16 ebda_seg = get_ebda_seg();
181     struct usbkeyinfo old;
182     old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
183
184     // Check for keys no longer pressed.
185     int addpos = 0;
186     int i;
187     for (i=0; i<ARRAY_SIZE(old.keys); i++) {
188         u8 key = old.keys[i];
189         if (!key)
190             break;
191         int j;
192         for (j=0;; j++) {
193             if (j>=ARRAY_SIZE(data->keys)) {
194                 // Key released.
195                 procscankey(key, RELEASEBIT);
196                 if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
197                     // Last pressed key released - disable repeat.
198                     old.repeatcount = 0xff;
199                 break;
200             }
201             if (data->keys[j] == key) {
202                 // Key still pressed.
203                 data->keys[j] = 0;
204                 old.keys[addpos++] = key;
205                 break;
206             }
207         }
208     }
209     procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
210
211     // Process new keys
212     procmodkey(data->modifiers & ~old.modifiers, 0);
213     old.modifiers = data->modifiers;
214     for (i=0; i<ARRAY_SIZE(data->keys); i++) {
215         u8 key = data->keys[i];
216         if (!key)
217             continue;
218         // New key pressed.
219         procscankey(key, 0);
220         old.keys[addpos++] = key;
221         old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
222     }
223     if (addpos < ARRAY_SIZE(old.keys))
224         old.keys[addpos] = 0;
225
226     // Check for key repeat event.
227     if (addpos) {
228         if (!old.repeatcount)
229             procscankey(old.keys[addpos-1], 0);
230         else if (old.repeatcount != 0xff)
231             old.repeatcount--;
232     }
233
234     // Update old keys
235     SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
236 }
237
238 // Check for USB events pending - called periodically from timer interrupt.
239 void
240 usb_check_key(void)
241 {
242     if (! CONFIG_USB_KEYBOARD)
243         return;
244     struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
245     if (!pipe)
246         return;
247
248     for (;;) {
249         struct keyevent data;
250         int ret = usb_poll_intr(pipe, &data);
251         if (ret)
252             break;
253         handle_key(&data);
254     }
255 }
256
257 // Test if USB keyboard is active.
258 inline int
259 usb_kbd_active(void)
260 {
261     return GET_GLOBAL(keyboard_pipe) != NULL;
262 }
263
264 // Handle a ps2 style keyboard command.
265 inline int
266 usb_kbd_command(int command, u8 *param)
267 {
268     switch (command) {
269     case ATKBD_CMD_GETID:
270         // Return the id of a standard AT keyboard.
271         param[0] = 0xab;
272         param[1] = 0x83;
273         return 0;
274     default:
275         return -1;
276     }
277 }