blob: 7e5b3098fef7b38378450c4351d8010b3143ad02 [file] [log] [blame]
Kevin O'Connor114592f2009-09-28 21:32:08 -04001// 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
13void *keyboard_pipe VAR16VISIBLE;
14
15
16/****************************************************************
17 * Setup
18 ****************************************************************/
19
20static int
21set_protocol(u32 endp, 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(endp, &req, NULL);
30}
31
32static int
33set_idle(u32 endp, u8 val)
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 = val<<8;
39 req.wIndex = 0;
40 req.wLength = 0;
41 return send_default_control(endp, &req, NULL);
42}
43
44int
45usb_keyboard_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
46{
47 if (! CONFIG_USB_KEYBOARD)
48 return -1;
49 if (keyboard_pipe)
50 return -1;
51 dprintf(2, "usb_keyboard_setup %x\n", endp);
52
53 struct usb_endpoint_descriptor *epdesc = (void*)&iface[1];
54 for (;;) {
55 if ((void*)epdesc >= (void*)iface + imax
56 || epdesc->bDescriptorType == USB_DT_INTERFACE) {
57 dprintf(1, "No keyboard intr in?\n");
58 return -1;
59 }
60 if (epdesc->bDescriptorType == USB_DT_ENDPOINT
61 && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN
62 && ((epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
63 == USB_ENDPOINT_XFER_INT)
64 && epdesc->wMaxPacketSize == 8)
65 break;
66 epdesc = (void*)epdesc + epdesc->bLength;
67 }
68 u32 inendp = mkendp(endp2cntl(endp), endp2devaddr(endp)
69 , epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK
70 , endp2speed(endp), epdesc->wMaxPacketSize);
71
72 // Enable "boot" protocol.
73 int ret = set_protocol(endp, 1);
74 if (ret)
75 return -1;
76 // Only send reports on a new key event.
77 ret = set_idle(endp, 0);
78 if (ret)
79 return -1;
80
81 void *pipe = alloc_intr_pipe(inendp, epdesc->bInterval);
82 if (!pipe)
83 return -1;
84 keyboard_pipe = pipe;
85
86 return 0;
87}
88
89void
90usb_keyboard_setup()
91{
92 if (! CONFIG_USB_KEYBOARD)
93 return;
94 keyboard_pipe = NULL;
95}
96
97
98/****************************************************************
99 * Keyboard events
100 ****************************************************************/
101
102static u16 KeyToScanCode[] VAR16 = {
103 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
104 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
105 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
106 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
107 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
108 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
109 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
110 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
111 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
112 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
113 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
114 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
115 0x0048, 0x0049, 0x0052, 0x0053
116};
117
118static u16 ModifierToScanCode[] VAR16 = {
119 //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
120 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
121};
122
123struct keyevent {
124 u8 modifiers;
125 u8 reserved;
126 u8 keys[6];
127};
128
129static void
130prockeys(u16 keys)
131{
132 if (keys > 0xff) {
133 u8 key = keys>>8;
134 if (key == 0xe1) {
135 // Pause key
136 process_key(0xe1);
137 process_key(0x1d | (keys & 0x80));
138 process_key(0x45 | (keys & 0x80));
139 return;
140 }
141 process_key(key);
142 }
143 process_key(keys);
144}
145
146static void
147handle_key(struct keyevent *data)
148{
149 dprintf(5, "Got key %x %x\n", data->modifiers, data->keys[0]);
150 // XXX
151 int i;
152 for (i=0; i<8; i++)
153 if (data->modifiers & (1<<i))
154 prockeys(GET_GLOBAL(ModifierToScanCode[i]));
155 for (i=0; i<ARRAY_SIZE(data->keys); i++) {
156 u8 key = data->keys[i];
157 if (key >= ARRAY_SIZE(KeyToScanCode))
158 continue;
159 key = GET_GLOBAL(KeyToScanCode[key]);
160 if (!key)
161 continue;
162 prockeys(key);
163 }
164 for (i=0; i<8; i++)
165 if (data->modifiers & (1<<i))
166 prockeys(GET_GLOBAL(ModifierToScanCode[i]) | 0x80);
167}
168
169void
170usb_check_key()
171{
172 if (! CONFIG_USB_KEYBOARD)
173 return;
174 void *pipe = GET_GLOBAL(keyboard_pipe);
175 if (!pipe)
176 return;
177
178 for (;;) {
179 struct keyevent data;
180 int ret = usb_poll_intr(pipe, &data);
181 if (ret)
182 break;
183 handle_key(&data);
184 }
185}