Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 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 | |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 7 | #include "biosvar.h" // GET_GLOBAL |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 8 | #include "config.h" // CONFIG_* |
| 9 | #include "output.h" // dprintf |
Kevin O'Connor | dd5a8a6 | 2010-05-01 19:59:34 -0400 | [diff] [blame] | 10 | #include "ps2port.h" // ATKBD_CMD_GETID |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 11 | #include "usb.h" // usb_ctrlrequest |
| 12 | #include "usb-hid.h" // usb_keyboard_setup |
| 13 | #include "util.h" // process_key |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 14 | |
Kevin O'Connor | 89a2f96 | 2013-02-18 23:36:03 -0500 | [diff] [blame] | 15 | struct usb_pipe *keyboard_pipe VARFSEG; |
| 16 | struct usb_pipe *mouse_pipe VARFSEG; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 17 | |
| 18 | |
| 19 | /**************************************************************** |
| 20 | * Setup |
| 21 | ****************************************************************/ |
| 22 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 23 | // Send USB HID protocol message. |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 24 | static int |
Kevin O'Connor | 357bdfa | 2010-02-26 08:57:13 -0500 | [diff] [blame] | 25 | set_protocol(struct usb_pipe *pipe, u16 val) |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 26 | { |
| 27 | struct usb_ctrlrequest req; |
| 28 | req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; |
| 29 | req.bRequest = HID_REQ_SET_PROTOCOL; |
| 30 | req.wValue = val; |
| 31 | req.wIndex = 0; |
| 32 | req.wLength = 0; |
Kevin O'Connor | 222bad4 | 2014-10-16 12:11:12 -0400 | [diff] [blame] | 33 | return usb_send_default_control(pipe, &req, NULL); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 34 | } |
| 35 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 36 | // Send USB HID SetIdle request. |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 37 | static int |
Kevin O'Connor | 357bdfa | 2010-02-26 08:57:13 -0500 | [diff] [blame] | 38 | set_idle(struct usb_pipe *pipe, int ms) |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 39 | { |
| 40 | struct usb_ctrlrequest req; |
| 41 | req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; |
| 42 | req.bRequest = HID_REQ_SET_IDLE; |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 43 | req.wValue = (ms/4)<<8; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 44 | req.wIndex = 0; |
| 45 | req.wLength = 0; |
Kevin O'Connor | 222bad4 | 2014-10-16 12:11:12 -0400 | [diff] [blame] | 46 | return usb_send_default_control(pipe, &req, NULL); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 47 | } |
| 48 | |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 49 | #define KEYREPEATWAITMS 500 |
| 50 | #define KEYREPEATMS 33 |
| 51 | |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 52 | static int |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 53 | usb_kbd_setup(struct usbdevice_s *usbdev |
| 54 | , struct usb_endpoint_descriptor *epdesc) |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 55 | { |
| 56 | if (! CONFIG_USB_KEYBOARD) |
| 57 | return -1; |
| 58 | if (keyboard_pipe) |
Kevin O'Connor | a5826b5 | 2009-10-24 17:57:29 -0400 | [diff] [blame] | 59 | // XXX - this enables the first found keyboard (could be random) |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 60 | return -1; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 61 | |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 62 | if (epdesc->wMaxPacketSize != 8) |
Kevin O'Connor | 3c160dd | 2010-02-17 23:06:52 -0500 | [diff] [blame] | 63 | return -1; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 64 | |
| 65 | // Enable "boot" protocol. |
Kevin O'Connor | 6a8e895 | 2012-03-08 07:20:30 -0500 | [diff] [blame] | 66 | int ret = set_protocol(usbdev->defpipe, 0); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 67 | if (ret) |
| 68 | return -1; |
Kevin O'Connor | 3c160dd | 2010-02-17 23:06:52 -0500 | [diff] [blame] | 69 | // Periodically send reports to enable key repeat. |
Kevin O'Connor | 6a8e895 | 2012-03-08 07:20:30 -0500 | [diff] [blame] | 70 | ret = set_idle(usbdev->defpipe, KEYREPEATMS); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 71 | if (ret) |
| 72 | return -1; |
| 73 | |
Kevin O'Connor | c3d96c2 | 2012-03-10 09:03:25 -0500 | [diff] [blame] | 74 | keyboard_pipe = usb_alloc_pipe(usbdev, epdesc); |
Kevin O'Connor | 357bdfa | 2010-02-26 08:57:13 -0500 | [diff] [blame] | 75 | if (!keyboard_pipe) |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 76 | return -1; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 77 | |
Kevin O'Connor | 357bdfa | 2010-02-26 08:57:13 -0500 | [diff] [blame] | 78 | dprintf(1, "USB keyboard initialized\n"); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 79 | return 0; |
| 80 | } |
| 81 | |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 82 | static int |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 83 | usb_mouse_setup(struct usbdevice_s *usbdev |
| 84 | , struct usb_endpoint_descriptor *epdesc) |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 85 | { |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 86 | if (! CONFIG_USB_MOUSE) |
| 87 | return -1; |
| 88 | if (mouse_pipe) |
| 89 | // XXX - this enables the first found mouse (could be random) |
| 90 | return -1; |
| 91 | |
| 92 | if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8) |
| 93 | return -1; |
| 94 | |
| 95 | // Enable "boot" protocol. |
Kevin O'Connor | 6a8e895 | 2012-03-08 07:20:30 -0500 | [diff] [blame] | 96 | int ret = set_protocol(usbdev->defpipe, 0); |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 97 | if (ret) |
| 98 | return -1; |
| 99 | |
Kevin O'Connor | c3d96c2 | 2012-03-10 09:03:25 -0500 | [diff] [blame] | 100 | mouse_pipe = usb_alloc_pipe(usbdev, epdesc); |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 101 | if (!mouse_pipe) |
| 102 | return -1; |
| 103 | |
| 104 | dprintf(1, "USB mouse initialized\n"); |
| 105 | return 0; |
| 106 | } |
| 107 | |
| 108 | // Initialize a found USB HID device (if applicable). |
| 109 | int |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 110 | usb_hid_setup(struct usbdevice_s *usbdev) |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 111 | { |
Kevin O'Connor | 48dc6a6 | 2014-03-31 23:50:42 -0400 | [diff] [blame] | 112 | if (! CONFIG_USB_KEYBOARD && ! CONFIG_USB_MOUSE) |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 113 | return -1; |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 114 | dprintf(2, "usb_hid_setup %p\n", usbdev->defpipe); |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 115 | |
Kevin O'Connor | 6a8e895 | 2012-03-08 07:20:30 -0500 | [diff] [blame] | 116 | struct usb_interface_descriptor *iface = usbdev->iface; |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 117 | if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT) |
| 118 | // Doesn't support boot protocol. |
| 119 | return -1; |
| 120 | |
| 121 | // Find intr in endpoint. |
Kevin O'Connor | 674f140 | 2014-10-16 12:08:00 -0400 | [diff] [blame] | 122 | struct usb_endpoint_descriptor *epdesc = usb_find_desc( |
Kevin O'Connor | 6a8e895 | 2012-03-08 07:20:30 -0500 | [diff] [blame] | 123 | usbdev, USB_ENDPOINT_XFER_INT, USB_DIR_IN); |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 124 | if (!epdesc) { |
| 125 | dprintf(1, "No usb hid intr in?\n"); |
| 126 | return -1; |
| 127 | } |
| 128 | |
| 129 | if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD) |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 130 | return usb_kbd_setup(usbdev, epdesc); |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 131 | if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 132 | return usb_mouse_setup(usbdev, epdesc); |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 133 | return -1; |
| 134 | } |
| 135 | |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 136 | |
| 137 | /**************************************************************** |
| 138 | * Keyboard events |
| 139 | ****************************************************************/ |
| 140 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 141 | // Mapping from USB key id to ps2 key sequence. |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 142 | static u16 KeyToScanCode[] VAR16 = { |
| 143 | 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020, |
| 144 | 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026, |
| 145 | 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, |
| 146 | 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003, |
| 147 | 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, |
| 148 | 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a, |
| 149 | 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, |
| 150 | 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, |
| 151 | 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046, |
| 152 | 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d, |
| 153 | 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e, |
| 154 | 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047, |
| 155 | 0x0048, 0x0049, 0x0052, 0x0053 |
| 156 | }; |
| 157 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 158 | // Mapping from USB modifier id to ps2 key sequence. |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 159 | static u16 ModifierToScanCode[] VAR16 = { |
| 160 | //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui |
| 161 | 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c |
| 162 | }; |
| 163 | |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 164 | #define RELEASEBIT 0x80 |
| 165 | |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 166 | // Format of USB keyboard event data |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 167 | struct keyevent { |
| 168 | u8 modifiers; |
| 169 | u8 reserved; |
| 170 | u8 keys[6]; |
| 171 | }; |
| 172 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 173 | // Translate data from KeyToScanCode[] to calls to process_key(). |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 174 | static void |
| 175 | prockeys(u16 keys) |
| 176 | { |
| 177 | if (keys > 0xff) { |
| 178 | u8 key = keys>>8; |
| 179 | if (key == 0xe1) { |
| 180 | // Pause key |
| 181 | process_key(0xe1); |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 182 | process_key(0x1d | (keys & RELEASEBIT)); |
| 183 | process_key(0x45 | (keys & RELEASEBIT)); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 184 | return; |
| 185 | } |
| 186 | process_key(key); |
| 187 | } |
| 188 | process_key(keys); |
| 189 | } |
| 190 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 191 | // Handle a USB key press/release event. |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 192 | static void |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 193 | procscankey(u8 key, u8 flags) |
| 194 | { |
| 195 | if (key >= ARRAY_SIZE(KeyToScanCode)) |
| 196 | return; |
| 197 | u16 keys = GET_GLOBAL(KeyToScanCode[key]); |
| 198 | if (keys) |
| 199 | prockeys(keys | flags); |
| 200 | } |
| 201 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 202 | // Handle a USB modifier press/release event. |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 203 | static void |
| 204 | procmodkey(u8 mods, u8 flags) |
| 205 | { |
| 206 | int i; |
| 207 | for (i=0; mods; i++) |
| 208 | if (mods & (1<<i)) { |
| 209 | // Modifier key change. |
| 210 | prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags); |
| 211 | mods &= ~(1<<i); |
| 212 | } |
| 213 | } |
| 214 | |
Kevin O'Connor | 2d012ec | 2012-05-13 12:39:16 -0400 | [diff] [blame] | 215 | struct usbkeyinfo { |
| 216 | union { |
| 217 | struct { |
| 218 | u8 modifiers; |
| 219 | u8 repeatcount; |
| 220 | u8 keys[6]; |
| 221 | }; |
| 222 | u64 data; |
| 223 | }; |
| 224 | }; |
| 225 | struct usbkeyinfo LastUSBkey VARLOW; |
| 226 | |
Kevin O'Connor | 5718d56 | 2010-05-01 19:25:41 -0400 | [diff] [blame] | 227 | // Process USB keyboard data. |
Kevin O'Connor | ac7eb5e | 2012-05-28 14:42:16 -0400 | [diff] [blame] | 228 | static void |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 229 | handle_key(struct keyevent *data) |
| 230 | { |
Kevin O'Connor | 7852331 | 2010-02-14 19:07:43 -0500 | [diff] [blame] | 231 | dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]); |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 232 | |
| 233 | // Load old keys. |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 234 | struct usbkeyinfo old; |
Kevin O'Connor | 2d012ec | 2012-05-13 12:39:16 -0400 | [diff] [blame] | 235 | old.data = GET_LOW(LastUSBkey.data); |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 236 | |
| 237 | // Check for keys no longer pressed. |
| 238 | int addpos = 0; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 239 | int i; |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 240 | for (i=0; i<ARRAY_SIZE(old.keys); i++) { |
| 241 | u8 key = old.keys[i]; |
| 242 | if (!key) |
| 243 | break; |
| 244 | int j; |
| 245 | for (j=0;; j++) { |
| 246 | if (j>=ARRAY_SIZE(data->keys)) { |
| 247 | // Key released. |
| 248 | procscankey(key, RELEASEBIT); |
| 249 | if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1]) |
| 250 | // Last pressed key released - disable repeat. |
| 251 | old.repeatcount = 0xff; |
| 252 | break; |
| 253 | } |
| 254 | if (data->keys[j] == key) { |
| 255 | // Key still pressed. |
| 256 | data->keys[j] = 0; |
| 257 | old.keys[addpos++] = key; |
| 258 | break; |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT); |
| 263 | |
| 264 | // Process new keys |
| 265 | procmodkey(data->modifiers & ~old.modifiers, 0); |
| 266 | old.modifiers = data->modifiers; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 267 | for (i=0; i<ARRAY_SIZE(data->keys); i++) { |
| 268 | u8 key = data->keys[i]; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 269 | if (!key) |
| 270 | continue; |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 271 | // New key pressed. |
| 272 | procscankey(key, 0); |
| 273 | old.keys[addpos++] = key; |
| 274 | old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1; |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 275 | } |
Kevin O'Connor | 84a4d4b | 2010-02-11 22:32:12 -0500 | [diff] [blame] | 276 | if (addpos < ARRAY_SIZE(old.keys)) |
| 277 | old.keys[addpos] = 0; |
| 278 | |
| 279 | // Check for key repeat event. |
| 280 | if (addpos) { |
| 281 | if (!old.repeatcount) |
| 282 | procscankey(old.keys[addpos-1], 0); |
| 283 | else if (old.repeatcount != 0xff) |
| 284 | old.repeatcount--; |
| 285 | } |
| 286 | |
| 287 | // Update old keys |
Kevin O'Connor | 2d012ec | 2012-05-13 12:39:16 -0400 | [diff] [blame] | 288 | SET_LOW(LastUSBkey.data, old.data); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 289 | } |
| 290 | |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 291 | // Check if a USB keyboard event is pending and process it if so. |
| 292 | static void |
Kevin O'Connor | 1ca05b0 | 2010-01-03 17:43:37 -0500 | [diff] [blame] | 293 | usb_check_key(void) |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 294 | { |
| 295 | if (! CONFIG_USB_KEYBOARD) |
| 296 | return; |
Kevin O'Connor | 1c46a54 | 2009-10-17 23:53:32 -0400 | [diff] [blame] | 297 | struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe); |
Kevin O'Connor | 114592f | 2009-09-28 21:32:08 -0400 | [diff] [blame] | 298 | if (!pipe) |
| 299 | return; |
| 300 | |
| 301 | for (;;) { |
| 302 | struct keyevent data; |
| 303 | int ret = usb_poll_intr(pipe, &data); |
| 304 | if (ret) |
| 305 | break; |
| 306 | handle_key(&data); |
| 307 | } |
| 308 | } |
Kevin O'Connor | dd5a8a6 | 2010-05-01 19:59:34 -0400 | [diff] [blame] | 309 | |
| 310 | // Test if USB keyboard is active. |
| 311 | inline int |
| 312 | usb_kbd_active(void) |
| 313 | { |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 314 | if (! CONFIG_USB_KEYBOARD) |
| 315 | return 0; |
Kevin O'Connor | dd5a8a6 | 2010-05-01 19:59:34 -0400 | [diff] [blame] | 316 | return GET_GLOBAL(keyboard_pipe) != NULL; |
| 317 | } |
| 318 | |
| 319 | // Handle a ps2 style keyboard command. |
| 320 | inline int |
| 321 | usb_kbd_command(int command, u8 *param) |
| 322 | { |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 323 | if (! CONFIG_USB_KEYBOARD) |
| 324 | return -1; |
| 325 | dprintf(9, "usb keyboard cmd=%x\n", command); |
Kevin O'Connor | dd5a8a6 | 2010-05-01 19:59:34 -0400 | [diff] [blame] | 326 | switch (command) { |
| 327 | case ATKBD_CMD_GETID: |
| 328 | // Return the id of a standard AT keyboard. |
| 329 | param[0] = 0xab; |
| 330 | param[1] = 0x83; |
| 331 | return 0; |
| 332 | default: |
| 333 | return -1; |
| 334 | } |
| 335 | } |
Kevin O'Connor | 0e88576 | 2010-05-01 22:14:40 -0400 | [diff] [blame] | 336 | |
| 337 | |
| 338 | /**************************************************************** |
| 339 | * Mouse events |
| 340 | ****************************************************************/ |
| 341 | |
| 342 | // Format of USB mouse event data |
| 343 | struct mouseevent { |
| 344 | u8 buttons; |
| 345 | u8 x, y; |
| 346 | u8 reserved[5]; |
| 347 | }; |
| 348 | |
| 349 | // Process USB mouse data. |
| 350 | static void |
| 351 | handle_mouse(struct mouseevent *data) |
| 352 | { |
| 353 | dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y); |
| 354 | |
| 355 | s8 x = data->x, y = -data->y; |
| 356 | u8 flag = ((data->buttons & 0x7) | (1<<3) |
| 357 | | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0)); |
| 358 | process_mouse(flag); |
| 359 | process_mouse(x); |
| 360 | process_mouse(y); |
| 361 | } |
| 362 | |
| 363 | // Check if a USB mouse event is pending and process it if so. |
| 364 | static void |
| 365 | usb_check_mouse(void) |
| 366 | { |
| 367 | if (! CONFIG_USB_MOUSE) |
| 368 | return; |
| 369 | struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe); |
| 370 | if (!pipe) |
| 371 | return; |
| 372 | |
| 373 | for (;;) { |
| 374 | struct mouseevent data; |
| 375 | int ret = usb_poll_intr(pipe, &data); |
| 376 | if (ret) |
| 377 | break; |
| 378 | handle_mouse(&data); |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | // Test if USB mouse is active. |
| 383 | inline int |
| 384 | usb_mouse_active(void) |
| 385 | { |
| 386 | if (! CONFIG_USB_MOUSE) |
| 387 | return 0; |
| 388 | return GET_GLOBAL(mouse_pipe) != NULL; |
| 389 | } |
| 390 | |
| 391 | // Handle a ps2 style mouse command. |
| 392 | inline int |
| 393 | usb_mouse_command(int command, u8 *param) |
| 394 | { |
| 395 | if (! CONFIG_USB_MOUSE) |
| 396 | return -1; |
| 397 | dprintf(9, "usb mouse cmd=%x\n", command); |
| 398 | switch (command) { |
| 399 | case PSMOUSE_CMD_ENABLE: |
| 400 | case PSMOUSE_CMD_DISABLE: |
| 401 | case PSMOUSE_CMD_SETSCALE11: |
| 402 | return 0; |
| 403 | case PSMOUSE_CMD_SETSCALE21: |
| 404 | case PSMOUSE_CMD_SETRATE: |
| 405 | case PSMOUSE_CMD_SETRES: |
| 406 | // XXX |
| 407 | return 0; |
| 408 | case PSMOUSE_CMD_RESET_BAT: |
| 409 | case PSMOUSE_CMD_GETID: |
| 410 | // Return the id of a standard AT mouse. |
| 411 | param[0] = 0xaa; |
| 412 | param[1] = 0x00; |
| 413 | return 0; |
| 414 | |
| 415 | case PSMOUSE_CMD_GETINFO: |
| 416 | param[0] = 0x00; |
| 417 | param[1] = 4; |
| 418 | param[2] = 100; |
| 419 | return 0; |
| 420 | |
| 421 | default: |
| 422 | return -1; |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | // Check for USB events pending - called periodically from timer interrupt. |
| 427 | void |
| 428 | usb_check_event(void) |
| 429 | { |
| 430 | usb_check_key(); |
| 431 | usb_check_mouse(); |
| 432 | } |