Replace USB encoded 'u32 endp' scheme with explicit struct fields.
[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
13 struct usb_pipe *keyboard_pipe VAR16VISIBLE;
14
15
16 /****************************************************************
17  * Setup
18  ****************************************************************/
19
20 static int
21 set_protocol(struct usb_pipe *pipe, u16 val)
22 {
23     struct usb_ctrlrequest req;
24     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
25     req.bRequest = HID_REQ_SET_PROTOCOL;
26     req.wValue = val;
27     req.wIndex = 0;
28     req.wLength = 0;
29     return send_default_control(pipe, &req, NULL);
30 }
31
32 static int
33 set_idle(struct usb_pipe *pipe, int ms)
34 {
35     struct usb_ctrlrequest req;
36     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
37     req.bRequest = HID_REQ_SET_IDLE;
38     req.wValue = (ms/4)<<8;
39     req.wIndex = 0;
40     req.wLength = 0;
41     return send_default_control(pipe, &req, NULL);
42 }
43
44 #define KEYREPEATWAITMS 500
45 #define KEYREPEATMS 33
46
47 int
48 usb_keyboard_init(struct usb_pipe *pipe
49                   , struct usb_interface_descriptor *iface, int imax)
50 {
51     if (! CONFIG_USB_KEYBOARD)
52         return -1;
53     if (keyboard_pipe)
54         // XXX - this enables the first found keyboard (could be random)
55         return -1;
56     dprintf(2, "usb_keyboard_setup %p\n", pipe);
57
58     // Find intr in endpoint.
59     struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
60         iface, imax, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
61     if (!epdesc || epdesc->wMaxPacketSize != 8) {
62         dprintf(1, "No keyboard intr in?\n");
63         return -1;
64     }
65
66     // Enable "boot" protocol.
67     int ret = set_protocol(pipe, 1);
68     if (ret)
69         return -1;
70     // Periodically send reports to enable key repeat.
71     ret = set_idle(pipe, KEYREPEATMS);
72     if (ret)
73         return -1;
74
75     keyboard_pipe = alloc_intr_pipe(pipe, epdesc);
76     if (!keyboard_pipe)
77         return -1;
78
79     dprintf(1, "USB keyboard initialized\n");
80     return 0;
81 }
82
83 void
84 usb_keyboard_setup(void)
85 {
86     if (! CONFIG_USB_KEYBOARD)
87         return;
88     keyboard_pipe = NULL;
89 }
90
91
92 /****************************************************************
93  * Keyboard events
94  ****************************************************************/
95
96 static u16 KeyToScanCode[] VAR16 = {
97     0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
98     0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
99     0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
100     0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
101     0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
102     0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
103     0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
104     0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
105     0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
106     0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
107     0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
108     0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
109     0x0048, 0x0049, 0x0052, 0x0053
110 };
111
112 static u16 ModifierToScanCode[] VAR16 = {
113     //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
114     0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
115 };
116
117 #define RELEASEBIT 0x80
118
119 struct keyevent {
120     u8 modifiers;
121     u8 reserved;
122     u8 keys[6];
123 };
124
125 static void
126 prockeys(u16 keys)
127 {
128     if (keys > 0xff) {
129         u8 key = keys>>8;
130         if (key == 0xe1) {
131             // Pause key
132             process_key(0xe1);
133             process_key(0x1d | (keys & RELEASEBIT));
134             process_key(0x45 | (keys & RELEASEBIT));
135             return;
136         }
137         process_key(key);
138     }
139     process_key(keys);
140 }
141
142 static void
143 procscankey(u8 key, u8 flags)
144 {
145     if (key >= ARRAY_SIZE(KeyToScanCode))
146         return;
147     u16 keys = GET_GLOBAL(KeyToScanCode[key]);
148     if (keys)
149         prockeys(keys | flags);
150 }
151
152 static void
153 procmodkey(u8 mods, u8 flags)
154 {
155     int i;
156     for (i=0; mods; i++)
157         if (mods & (1<<i)) {
158             // Modifier key change.
159             prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
160             mods &= ~(1<<i);
161         }
162 }
163
164 static void noinline
165 handle_key(struct keyevent *data)
166 {
167     dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
168
169     // Load old keys.
170     u16 ebda_seg = get_ebda_seg();
171     struct usbkeyinfo old;
172     old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
173
174     // Check for keys no longer pressed.
175     int addpos = 0;
176     int i;
177     for (i=0; i<ARRAY_SIZE(old.keys); i++) {
178         u8 key = old.keys[i];
179         if (!key)
180             break;
181         int j;
182         for (j=0;; j++) {
183             if (j>=ARRAY_SIZE(data->keys)) {
184                 // Key released.
185                 procscankey(key, RELEASEBIT);
186                 if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
187                     // Last pressed key released - disable repeat.
188                     old.repeatcount = 0xff;
189                 break;
190             }
191             if (data->keys[j] == key) {
192                 // Key still pressed.
193                 data->keys[j] = 0;
194                 old.keys[addpos++] = key;
195                 break;
196             }
197         }
198     }
199     procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
200
201     // Process new keys
202     procmodkey(data->modifiers & ~old.modifiers, 0);
203     old.modifiers = data->modifiers;
204     for (i=0; i<ARRAY_SIZE(data->keys); i++) {
205         u8 key = data->keys[i];
206         if (!key)
207             continue;
208         // New key pressed.
209         procscankey(key, 0);
210         old.keys[addpos++] = key;
211         old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
212     }
213     if (addpos < ARRAY_SIZE(old.keys))
214         old.keys[addpos] = 0;
215
216     // Check for key repeat event.
217     if (addpos) {
218         if (!old.repeatcount)
219             procscankey(old.keys[addpos-1], 0);
220         else if (old.repeatcount != 0xff)
221             old.repeatcount--;
222     }
223
224     // Update old keys
225     SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
226 }
227
228 void
229 usb_check_key(void)
230 {
231     if (! CONFIG_USB_KEYBOARD)
232         return;
233     struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
234     if (!pipe)
235         return;
236
237     for (;;) {
238         struct keyevent data;
239         int ret = usb_poll_intr(pipe, &data);
240         if (ret)
241             break;
242         handle_key(&data);
243     }
244 }