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