7e5b3098fef7b38378450c4351d8010b3143ad02
[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 void *keyboard_pipe VAR16VISIBLE;
14
15
16 /****************************************************************
17  * Setup
18  ****************************************************************/
19
20 static int
21 set_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
32 static int
33 set_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
44 int
45 usb_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
89 void
90 usb_keyboard_setup()
91 {
92     if (! CONFIG_USB_KEYBOARD)
93         return;
94     keyboard_pipe = NULL;
95 }
96
97
98 /****************************************************************
99  * Keyboard events
100  ****************************************************************/
101
102 static 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
118 static u16 ModifierToScanCode[] VAR16 = {
119     //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
120     0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
121 };
122
123 struct keyevent {
124     u8 modifiers;
125     u8 reserved;
126     u8 keys[6];
127 };
128
129 static void
130 prockeys(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
146 static void
147 handle_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
169 void
170 usb_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 }