blob: c850a9194749f632d2863627f611728122edb168 [file] [log] [blame]
bellard59ae5402005-11-05 16:57:08 +00001/*
2 * QEMU USB HID devices
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard59ae5402005-11-05 16:57:08 +00004 * Copyright (c) 2005 Fabrice Bellard
balrog47b2d332007-06-22 08:16:00 +00005 * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
ths5fafdf22007-09-16 21:08:06 +00006 *
bellard59ae5402005-11-05 16:57:08 +00007 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
pbrook87ecb682007-11-17 17:14:51 +000025#include "hw.h"
26#include "console.h"
27#include "usb.h"
bellard59ae5402005-11-05 16:57:08 +000028
29/* HID interface requests */
30#define GET_REPORT 0xa101
31#define GET_IDLE 0xa102
32#define GET_PROTOCOL 0xa103
balrog47b2d332007-06-22 08:16:00 +000033#define SET_REPORT 0x2109
bellard59ae5402005-11-05 16:57:08 +000034#define SET_IDLE 0x210a
35#define SET_PROTOCOL 0x210b
36
balrog47b2d332007-06-22 08:16:00 +000037/* HID descriptor types */
38#define USB_DT_HID 0x21
39#define USB_DT_REPORT 0x22
40#define USB_DT_PHY 0x23
41
42#define USB_MOUSE 1
43#define USB_TABLET 2
44#define USB_KEYBOARD 3
bellard09b26c52006-04-12 21:09:08 +000045
bellard59ae5402005-11-05 16:57:08 +000046typedef struct USBMouseState {
bellard59ae5402005-11-05 16:57:08 +000047 int dx, dy, dz, buttons_state;
bellard09b26c52006-04-12 21:09:08 +000048 int x, y;
bellard09b26c52006-04-12 21:09:08 +000049 int mouse_grabbed;
ths455204e2007-01-05 16:42:13 +000050 QEMUPutMouseEntry *eh_entry;
bellard59ae5402005-11-05 16:57:08 +000051} USBMouseState;
52
balrog47b2d332007-06-22 08:16:00 +000053typedef struct USBKeyboardState {
54 uint16_t modifiers;
55 uint8_t leds;
56 uint8_t key[16];
57 int keys;
58} USBKeyboardState;
59
60typedef struct USBHIDState {
61 USBDevice dev;
62 union {
63 USBMouseState ptr;
64 USBKeyboardState kbd;
65 };
66 int kind;
67 int protocol;
aliguori181a29c2009-01-07 16:41:47 +000068 uint8_t idle;
pbrook117b3ae2007-09-09 21:16:01 +000069 int changed;
balrog47e699d2008-09-29 00:25:17 +000070 void *datain_opaque;
71 void (*datain)(void *);
balrog47b2d332007-06-22 08:16:00 +000072} USBHIDState;
73
bellard59ae5402005-11-05 16:57:08 +000074/* mostly the same values as the Bochs USB Mouse device */
75static const uint8_t qemu_mouse_dev_descriptor[] = {
76 0x12, /* u8 bLength; */
77 0x01, /* u8 bDescriptorType; Device */
thse126cf12007-03-31 18:23:26 +000078 0x00, 0x01, /* u16 bcdUSB; v1.0 */
bellard59ae5402005-11-05 16:57:08 +000079
80 0x00, /* u8 bDeviceClass; */
81 0x00, /* u8 bDeviceSubClass; */
82 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
83 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
84
85 0x27, 0x06, /* u16 idVendor; */
86 0x01, 0x00, /* u16 idProduct; */
87 0x00, 0x00, /* u16 bcdDevice */
88
89 0x03, /* u8 iManufacturer; */
90 0x02, /* u8 iProduct; */
91 0x01, /* u8 iSerialNumber; */
92 0x01 /* u8 bNumConfigurations; */
93};
94
95static const uint8_t qemu_mouse_config_descriptor[] = {
96 /* one configuration */
97 0x09, /* u8 bLength; */
98 0x02, /* u8 bDescriptorType; Configuration */
99 0x22, 0x00, /* u16 wTotalLength; */
100 0x01, /* u8 bNumInterfaces; (1) */
101 0x01, /* u8 bConfigurationValue; */
102 0x04, /* u8 iConfiguration; */
ths5fafdf22007-09-16 21:08:06 +0000103 0xa0, /* u8 bmAttributes;
bellard59ae5402005-11-05 16:57:08 +0000104 Bit 7: must be set,
105 6: Self-powered,
106 5: Remote wakeup,
107 4..0: resvd */
108 50, /* u8 MaxPower; */
ths3b46e622007-09-17 08:09:54 +0000109
bellard59ae5402005-11-05 16:57:08 +0000110 /* USB 1.1:
111 * USB 2.0, single TT organization (mandatory):
112 * one interface, protocol 0
113 *
114 * USB 2.0, multiple TT organization (optional):
115 * two interfaces, protocols 1 (like single TT)
116 * and 2 (multiple TT mode) ... config is
117 * sometimes settable
118 * NOT IMPLEMENTED
119 */
120
121 /* one interface */
122 0x09, /* u8 if_bLength; */
123 0x04, /* u8 if_bDescriptorType; Interface */
124 0x00, /* u8 if_bInterfaceNumber; */
125 0x00, /* u8 if_bAlternateSetting; */
126 0x01, /* u8 if_bNumEndpoints; */
127 0x03, /* u8 if_bInterfaceClass; */
128 0x01, /* u8 if_bInterfaceSubClass; */
129 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
balrog47b2d332007-06-22 08:16:00 +0000130 0x07, /* u8 if_iInterface; */
ths3b46e622007-09-17 08:09:54 +0000131
bellard59ae5402005-11-05 16:57:08 +0000132 /* HID descriptor */
133 0x09, /* u8 bLength; */
134 0x21, /* u8 bDescriptorType; */
135 0x01, 0x00, /* u16 HID_class */
136 0x00, /* u8 country_code */
137 0x01, /* u8 num_descriptors */
138 0x22, /* u8 type; Report */
balrogc21c5832008-04-26 01:43:07 +0000139 52, 0, /* u16 len */
bellard09b26c52006-04-12 21:09:08 +0000140
141 /* one endpoint (status change endpoint) */
142 0x07, /* u8 ep_bLength; */
143 0x05, /* u8 ep_bDescriptorType; Endpoint */
144 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
145 0x03, /* u8 ep_bmAttributes; Interrupt */
balrogc21c5832008-04-26 01:43:07 +0000146 0x04, 0x00, /* u16 ep_wMaxPacketSize; */
bellard09b26c52006-04-12 21:09:08 +0000147 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
148};
149
150static const uint8_t qemu_tablet_config_descriptor[] = {
151 /* one configuration */
152 0x09, /* u8 bLength; */
153 0x02, /* u8 bDescriptorType; Configuration */
154 0x22, 0x00, /* u16 wTotalLength; */
155 0x01, /* u8 bNumInterfaces; (1) */
156 0x01, /* u8 bConfigurationValue; */
balrog47b2d332007-06-22 08:16:00 +0000157 0x05, /* u8 iConfiguration; */
ths5fafdf22007-09-16 21:08:06 +0000158 0xa0, /* u8 bmAttributes;
bellard09b26c52006-04-12 21:09:08 +0000159 Bit 7: must be set,
160 6: Self-powered,
161 5: Remote wakeup,
162 4..0: resvd */
163 50, /* u8 MaxPower; */
ths3b46e622007-09-17 08:09:54 +0000164
bellard09b26c52006-04-12 21:09:08 +0000165 /* USB 1.1:
166 * USB 2.0, single TT organization (mandatory):
167 * one interface, protocol 0
168 *
169 * USB 2.0, multiple TT organization (optional):
170 * two interfaces, protocols 1 (like single TT)
171 * and 2 (multiple TT mode) ... config is
172 * sometimes settable
173 * NOT IMPLEMENTED
174 */
175
176 /* one interface */
177 0x09, /* u8 if_bLength; */
178 0x04, /* u8 if_bDescriptorType; Interface */
179 0x00, /* u8 if_bInterfaceNumber; */
180 0x00, /* u8 if_bAlternateSetting; */
181 0x01, /* u8 if_bNumEndpoints; */
182 0x03, /* u8 if_bInterfaceClass; */
183 0x01, /* u8 if_bInterfaceSubClass; */
184 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
balrog47b2d332007-06-22 08:16:00 +0000185 0x07, /* u8 if_iInterface; */
bellard09b26c52006-04-12 21:09:08 +0000186
187 /* HID descriptor */
188 0x09, /* u8 bLength; */
189 0x21, /* u8 bDescriptorType; */
190 0x01, 0x00, /* u16 HID_class */
191 0x00, /* u8 country_code */
192 0x01, /* u8 num_descriptors */
193 0x22, /* u8 type; Report */
194 74, 0, /* u16 len */
195
196 /* one endpoint (status change endpoint) */
197 0x07, /* u8 ep_bLength; */
198 0x05, /* u8 ep_bDescriptorType; Endpoint */
199 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
200 0x03, /* u8 ep_bmAttributes; Interrupt */
201 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
bellardf2f1ac82007-02-11 19:01:48 +0000202 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
bellard59ae5402005-11-05 16:57:08 +0000203};
204
balrog47b2d332007-06-22 08:16:00 +0000205static const uint8_t qemu_keyboard_config_descriptor[] = {
206 /* one configuration */
207 0x09, /* u8 bLength; */
208 USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */
209 0x22, 0x00, /* u16 wTotalLength; */
210 0x01, /* u8 bNumInterfaces; (1) */
211 0x01, /* u8 bConfigurationValue; */
212 0x06, /* u8 iConfiguration; */
ths5fafdf22007-09-16 21:08:06 +0000213 0xa0, /* u8 bmAttributes;
balrog47b2d332007-06-22 08:16:00 +0000214 Bit 7: must be set,
215 6: Self-powered,
216 5: Remote wakeup,
217 4..0: resvd */
218 0x32, /* u8 MaxPower; */
219
220 /* USB 1.1:
221 * USB 2.0, single TT organization (mandatory):
222 * one interface, protocol 0
223 *
224 * USB 2.0, multiple TT organization (optional):
225 * two interfaces, protocols 1 (like single TT)
226 * and 2 (multiple TT mode) ... config is
227 * sometimes settable
228 * NOT IMPLEMENTED
229 */
230
231 /* one interface */
232 0x09, /* u8 if_bLength; */
233 USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */
234 0x00, /* u8 if_bInterfaceNumber; */
235 0x00, /* u8 if_bAlternateSetting; */
236 0x01, /* u8 if_bNumEndpoints; */
237 0x03, /* u8 if_bInterfaceClass; HID */
238 0x01, /* u8 if_bInterfaceSubClass; Boot */
239 0x01, /* u8 if_bInterfaceProtocol; Keyboard */
240 0x07, /* u8 if_iInterface; */
241
242 /* HID descriptor */
243 0x09, /* u8 bLength; */
244 USB_DT_HID, /* u8 bDescriptorType; */
245 0x11, 0x01, /* u16 HID_class */
246 0x00, /* u8 country_code */
247 0x01, /* u8 num_descriptors */
248 USB_DT_REPORT, /* u8 type; Report */
249 0x3f, 0x00, /* u16 len */
250
251 /* one endpoint (status change endpoint) */
252 0x07, /* u8 ep_bLength; */
253 USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */
254 USB_DIR_IN | 0x01, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
255 0x03, /* u8 ep_bmAttributes; Interrupt */
256 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
257 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
258};
259
bellard59ae5402005-11-05 16:57:08 +0000260static const uint8_t qemu_mouse_hid_report_descriptor[] = {
balrog976f8ee2008-05-17 19:55:28 +0000261 0x05, 0x01, /* Usage Page (Generic Desktop) */
262 0x09, 0x02, /* Usage (Mouse) */
263 0xa1, 0x01, /* Collection (Application) */
264 0x09, 0x01, /* Usage (Pointer) */
265 0xa1, 0x00, /* Collection (Physical) */
266 0x05, 0x09, /* Usage Page (Button) */
267 0x19, 0x01, /* Usage Minimum (1) */
268 0x29, 0x03, /* Usage Maximum (3) */
269 0x15, 0x00, /* Logical Minimum (0) */
270 0x25, 0x01, /* Logical Maximum (1) */
271 0x95, 0x03, /* Report Count (3) */
272 0x75, 0x01, /* Report Size (1) */
273 0x81, 0x02, /* Input (Data, Variable, Absolute) */
274 0x95, 0x01, /* Report Count (1) */
275 0x75, 0x05, /* Report Size (5) */
276 0x81, 0x01, /* Input (Constant) */
277 0x05, 0x01, /* Usage Page (Generic Desktop) */
278 0x09, 0x30, /* Usage (X) */
279 0x09, 0x31, /* Usage (Y) */
280 0x09, 0x38, /* Usage (Wheel) */
281 0x15, 0x81, /* Logical Minimum (-0x7f) */
282 0x25, 0x7f, /* Logical Maximum (0x7f) */
283 0x75, 0x08, /* Report Size (8) */
284 0x95, 0x03, /* Report Count (3) */
285 0x81, 0x06, /* Input (Data, Variable, Relative) */
286 0xc0, /* End Collection */
287 0xc0, /* End Collection */
bellard59ae5402005-11-05 16:57:08 +0000288};
289
bellard09b26c52006-04-12 21:09:08 +0000290static const uint8_t qemu_tablet_hid_report_descriptor[] = {
balrog976f8ee2008-05-17 19:55:28 +0000291 0x05, 0x01, /* Usage Page (Generic Desktop) */
292 0x09, 0x01, /* Usage (Pointer) */
293 0xa1, 0x01, /* Collection (Application) */
294 0x09, 0x01, /* Usage (Pointer) */
295 0xa1, 0x00, /* Collection (Physical) */
296 0x05, 0x09, /* Usage Page (Button) */
297 0x19, 0x01, /* Usage Minimum (1) */
298 0x29, 0x03, /* Usage Maximum (3) */
299 0x15, 0x00, /* Logical Minimum (0) */
300 0x25, 0x01, /* Logical Maximum (1) */
301 0x95, 0x03, /* Report Count (3) */
302 0x75, 0x01, /* Report Size (1) */
303 0x81, 0x02, /* Input (Data, Variable, Absolute) */
304 0x95, 0x01, /* Report Count (1) */
305 0x75, 0x05, /* Report Size (5) */
306 0x81, 0x01, /* Input (Constant) */
307 0x05, 0x01, /* Usage Page (Generic Desktop) */
308 0x09, 0x30, /* Usage (X) */
309 0x09, 0x31, /* Usage (Y) */
310 0x15, 0x00, /* Logical Minimum (0) */
balrogde5c2d02008-09-15 22:26:35 +0000311 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */
balrog976f8ee2008-05-17 19:55:28 +0000312 0x35, 0x00, /* Physical Minimum (0) */
balrogde5c2d02008-09-15 22:26:35 +0000313 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */
balrog976f8ee2008-05-17 19:55:28 +0000314 0x75, 0x10, /* Report Size (16) */
315 0x95, 0x02, /* Report Count (2) */
316 0x81, 0x02, /* Input (Data, Variable, Absolute) */
317 0x05, 0x01, /* Usage Page (Generic Desktop) */
318 0x09, 0x38, /* Usage (Wheel) */
319 0x15, 0x81, /* Logical Minimum (-0x7f) */
320 0x25, 0x7f, /* Logical Maximum (0x7f) */
321 0x35, 0x00, /* Physical Minimum (same as logical) */
322 0x45, 0x00, /* Physical Maximum (same as logical) */
323 0x75, 0x08, /* Report Size (8) */
324 0x95, 0x01, /* Report Count (1) */
325 0x81, 0x06, /* Input (Data, Variable, Relative) */
326 0xc0, /* End Collection */
327 0xc0, /* End Collection */
bellard09b26c52006-04-12 21:09:08 +0000328};
329
balrog47b2d332007-06-22 08:16:00 +0000330static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
331 0x05, 0x01, /* Usage Page (Generic Desktop) */
332 0x09, 0x06, /* Usage (Keyboard) */
333 0xa1, 0x01, /* Collection (Application) */
334 0x75, 0x01, /* Report Size (1) */
335 0x95, 0x08, /* Report Count (8) */
336 0x05, 0x07, /* Usage Page (Key Codes) */
337 0x19, 0xe0, /* Usage Minimum (224) */
338 0x29, 0xe7, /* Usage Maximum (231) */
339 0x15, 0x00, /* Logical Minimum (0) */
340 0x25, 0x01, /* Logical Maximum (1) */
341 0x81, 0x02, /* Input (Data, Variable, Absolute) */
342 0x95, 0x01, /* Report Count (1) */
343 0x75, 0x08, /* Report Size (8) */
344 0x81, 0x01, /* Input (Constant) */
345 0x95, 0x05, /* Report Count (5) */
346 0x75, 0x01, /* Report Size (1) */
347 0x05, 0x08, /* Usage Page (LEDs) */
348 0x19, 0x01, /* Usage Minimum (1) */
349 0x29, 0x05, /* Usage Maximum (5) */
350 0x91, 0x02, /* Output (Data, Variable, Absolute) */
351 0x95, 0x01, /* Report Count (1) */
352 0x75, 0x03, /* Report Size (3) */
353 0x91, 0x01, /* Output (Constant) */
354 0x95, 0x06, /* Report Count (6) */
355 0x75, 0x08, /* Report Size (8) */
356 0x15, 0x00, /* Logical Minimum (0) */
357 0x25, 0xff, /* Logical Maximum (255) */
358 0x05, 0x07, /* Usage Page (Key Codes) */
359 0x19, 0x00, /* Usage Minimum (0) */
360 0x29, 0xff, /* Usage Maximum (255) */
361 0x81, 0x00, /* Input (Data, Array) */
362 0xc0, /* End Collection */
363};
364
365#define USB_HID_USAGE_ERROR_ROLLOVER 0x01
366#define USB_HID_USAGE_POSTFAIL 0x02
367#define USB_HID_USAGE_ERROR_UNDEFINED 0x03
368
369/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
370 * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
371static const uint8_t usb_hid_usage_keys[0x100] = {
372 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
373 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
374 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
375 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
376 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
377 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
378 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
379 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
380 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
381 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
382 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
383 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
384 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
388
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
396 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
398 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
399 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
402 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
404 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405};
406
balrog47e699d2008-09-29 00:25:17 +0000407static void usb_hid_changed(USBHIDState *hs)
408{
409 hs->changed = 1;
410
411 if (hs->datain)
412 hs->datain(hs->datain_opaque);
413}
414
bellard59ae5402005-11-05 16:57:08 +0000415static void usb_mouse_event(void *opaque,
416 int dx1, int dy1, int dz1, int buttons_state)
417{
pbrook117b3ae2007-09-09 21:16:01 +0000418 USBHIDState *hs = opaque;
419 USBMouseState *s = &hs->ptr;
bellard59ae5402005-11-05 16:57:08 +0000420
421 s->dx += dx1;
422 s->dy += dy1;
423 s->dz += dz1;
424 s->buttons_state = buttons_state;
balrog47e699d2008-09-29 00:25:17 +0000425
426 usb_hid_changed(hs);
bellard59ae5402005-11-05 16:57:08 +0000427}
428
bellard09b26c52006-04-12 21:09:08 +0000429static void usb_tablet_event(void *opaque,
430 int x, int y, int dz, int buttons_state)
431{
pbrook117b3ae2007-09-09 21:16:01 +0000432 USBHIDState *hs = opaque;
433 USBMouseState *s = &hs->ptr;
bellard09b26c52006-04-12 21:09:08 +0000434
435 s->x = x;
436 s->y = y;
437 s->dz += dz;
438 s->buttons_state = buttons_state;
balrog47e699d2008-09-29 00:25:17 +0000439
440 usb_hid_changed(hs);
bellard09b26c52006-04-12 21:09:08 +0000441}
442
balrog47b2d332007-06-22 08:16:00 +0000443static void usb_keyboard_event(void *opaque, int keycode)
444{
pbrook117b3ae2007-09-09 21:16:01 +0000445 USBHIDState *hs = opaque;
446 USBKeyboardState *s = &hs->kbd;
balrog47b2d332007-06-22 08:16:00 +0000447 uint8_t hid_code, key;
448 int i;
449
450 key = keycode & 0x7f;
451 hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
452 s->modifiers &= ~(1 << 8);
453
454 switch (hid_code) {
455 case 0x00:
456 return;
457
458 case 0xe0:
459 if (s->modifiers & (1 << 9)) {
460 s->modifiers ^= 3 << 8;
461 return;
462 }
463 case 0xe1 ... 0xe7:
464 if (keycode & (1 << 7)) {
465 s->modifiers &= ~(1 << (hid_code & 0x0f));
466 return;
467 }
468 case 0xe8 ... 0xef:
469 s->modifiers |= 1 << (hid_code & 0x0f);
470 return;
471 }
472
473 if (keycode & (1 << 7)) {
474 for (i = s->keys - 1; i >= 0; i --)
475 if (s->key[i] == hid_code) {
476 s->key[i] = s->key[-- s->keys];
477 s->key[s->keys] = 0x00;
balrog47e699d2008-09-29 00:25:17 +0000478 usb_hid_changed(hs);
479 break;
balrog47b2d332007-06-22 08:16:00 +0000480 }
balrog47e699d2008-09-29 00:25:17 +0000481 if (i < 0)
482 return;
balrog47b2d332007-06-22 08:16:00 +0000483 } else {
484 for (i = s->keys - 1; i >= 0; i --)
485 if (s->key[i] == hid_code)
balrog47e699d2008-09-29 00:25:17 +0000486 break;
487 if (i < 0) {
488 if (s->keys < sizeof(s->key))
489 s->key[s->keys ++] = hid_code;
490 } else
491 return;
balrog47b2d332007-06-22 08:16:00 +0000492 }
balrog47e699d2008-09-29 00:25:17 +0000493
494 usb_hid_changed(hs);
balrog47b2d332007-06-22 08:16:00 +0000495}
496
bellard59ae5402005-11-05 16:57:08 +0000497static inline int int_clamp(int val, int vmin, int vmax)
498{
499 if (val < vmin)
500 return vmin;
501 else if (val > vmax)
502 return vmax;
503 else
504 return val;
505}
506
pbrook117b3ae2007-09-09 21:16:01 +0000507static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len)
bellard59ae5402005-11-05 16:57:08 +0000508{
509 int dx, dy, dz, b, l;
pbrook117b3ae2007-09-09 21:16:01 +0000510 USBMouseState *s = &hs->ptr;
bellard59ae5402005-11-05 16:57:08 +0000511
bellard09b26c52006-04-12 21:09:08 +0000512 if (!s->mouse_grabbed) {
pbrook117b3ae2007-09-09 21:16:01 +0000513 s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs,
ths455204e2007-01-05 16:42:13 +0000514 0, "QEMU USB Mouse");
bellard09b26c52006-04-12 21:09:08 +0000515 s->mouse_grabbed = 1;
516 }
ths3b46e622007-09-17 08:09:54 +0000517
balrog976f8ee2008-05-17 19:55:28 +0000518 dx = int_clamp(s->dx, -127, 127);
519 dy = int_clamp(s->dy, -127, 127);
520 dz = int_clamp(s->dz, -127, 127);
bellard59ae5402005-11-05 16:57:08 +0000521
522 s->dx -= dx;
523 s->dy -= dy;
524 s->dz -= dz;
ths3b46e622007-09-17 08:09:54 +0000525
balrog976f8ee2008-05-17 19:55:28 +0000526 /* Appears we have to invert the wheel direction */
527 dz = 0 - dz;
528
bellard59ae5402005-11-05 16:57:08 +0000529 b = 0;
530 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
531 b |= 0x01;
532 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
533 b |= 0x02;
534 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
535 b |= 0x04;
ths3b46e622007-09-17 08:09:54 +0000536
balrogc21c5832008-04-26 01:43:07 +0000537 l = 0;
538 if (len > l)
539 buf[l ++] = b;
540 if (len > l)
541 buf[l ++] = dx;
542 if (len > l)
543 buf[l ++] = dy;
544 if (len > l)
545 buf[l ++] = dz;
bellard59ae5402005-11-05 16:57:08 +0000546 return l;
547}
548
pbrook117b3ae2007-09-09 21:16:01 +0000549static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len)
bellard09b26c52006-04-12 21:09:08 +0000550{
551 int dz, b, l;
pbrook117b3ae2007-09-09 21:16:01 +0000552 USBMouseState *s = &hs->ptr;
bellard09b26c52006-04-12 21:09:08 +0000553
554 if (!s->mouse_grabbed) {
pbrook117b3ae2007-09-09 21:16:01 +0000555 s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
ths455204e2007-01-05 16:42:13 +0000556 1, "QEMU USB Tablet");
bellard09b26c52006-04-12 21:09:08 +0000557 s->mouse_grabbed = 1;
558 }
ths3b46e622007-09-17 08:09:54 +0000559
balrog976f8ee2008-05-17 19:55:28 +0000560 dz = int_clamp(s->dz, -127, 127);
bellard09b26c52006-04-12 21:09:08 +0000561 s->dz -= dz;
562
563 /* Appears we have to invert the wheel direction */
564 dz = 0 - dz;
565 b = 0;
566 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
567 b |= 0x01;
568 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
569 b |= 0x02;
570 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
571 b |= 0x04;
572
573 buf[0] = b;
574 buf[1] = s->x & 0xff;
575 buf[2] = s->x >> 8;
576 buf[3] = s->y & 0xff;
577 buf[4] = s->y >> 8;
578 buf[5] = dz;
579 l = 6;
580
581 return l;
582}
583
balrog47b2d332007-06-22 08:16:00 +0000584static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len)
bellard59ae5402005-11-05 16:57:08 +0000585{
balrog47b2d332007-06-22 08:16:00 +0000586 if (len < 2)
587 return 0;
bellard59ae5402005-11-05 16:57:08 +0000588
balrog47b2d332007-06-22 08:16:00 +0000589 buf[0] = s->modifiers & 0xff;
590 buf[1] = 0;
591 if (s->keys > 6)
592 memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
593 else
594 memcpy(buf + 2, s->key, MIN(8, len) - 2);
595
596 return MIN(8, len);
bellard59ae5402005-11-05 16:57:08 +0000597}
598
balrog47b2d332007-06-22 08:16:00 +0000599static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
600{
601 if (len > 0) {
602 /* 0x01: Num Lock LED
603 * 0x02: Caps Lock LED
604 * 0x04: Scroll Lock LED
605 * 0x08: Compose LED
606 * 0x10: Kana LED */
607 s->leds = buf[0];
608 }
609 return 0;
610}
611
612static void usb_mouse_handle_reset(USBDevice *dev)
613{
614 USBHIDState *s = (USBHIDState *)dev;
615
616 s->ptr.dx = 0;
617 s->ptr.dy = 0;
618 s->ptr.dz = 0;
619 s->ptr.x = 0;
620 s->ptr.y = 0;
621 s->ptr.buttons_state = 0;
622 s->protocol = 1;
623}
624
625static void usb_keyboard_handle_reset(USBDevice *dev)
626{
627 USBHIDState *s = (USBHIDState *)dev;
628
balrog926acf82007-09-17 17:27:00 +0000629 qemu_add_kbd_event_handler(usb_keyboard_event, s);
balrog47b2d332007-06-22 08:16:00 +0000630 s->protocol = 1;
631}
632
633static int usb_hid_handle_control(USBDevice *dev, int request, int value,
bellard59ae5402005-11-05 16:57:08 +0000634 int index, int length, uint8_t *data)
635{
balrog47b2d332007-06-22 08:16:00 +0000636 USBHIDState *s = (USBHIDState *)dev;
bellard09b26c52006-04-12 21:09:08 +0000637 int ret = 0;
bellard59ae5402005-11-05 16:57:08 +0000638
639 switch(request) {
640 case DeviceRequest | USB_REQ_GET_STATUS:
641 data[0] = (1 << USB_DEVICE_SELF_POWERED) |
642 (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
643 data[1] = 0x00;
644 ret = 2;
645 break;
646 case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
647 if (value == USB_DEVICE_REMOTE_WAKEUP) {
648 dev->remote_wakeup = 0;
649 } else {
650 goto fail;
651 }
652 ret = 0;
653 break;
654 case DeviceOutRequest | USB_REQ_SET_FEATURE:
655 if (value == USB_DEVICE_REMOTE_WAKEUP) {
656 dev->remote_wakeup = 1;
657 } else {
658 goto fail;
659 }
660 ret = 0;
661 break;
662 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
663 dev->addr = value;
664 ret = 0;
665 break;
666 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
667 switch(value >> 8) {
668 case USB_DT_DEVICE:
ths5fafdf22007-09-16 21:08:06 +0000669 memcpy(data, qemu_mouse_dev_descriptor,
bellard59ae5402005-11-05 16:57:08 +0000670 sizeof(qemu_mouse_dev_descriptor));
671 ret = sizeof(qemu_mouse_dev_descriptor);
672 break;
673 case USB_DT_CONFIG:
bellard09b26c52006-04-12 21:09:08 +0000674 if (s->kind == USB_MOUSE) {
ths5fafdf22007-09-16 21:08:06 +0000675 memcpy(data, qemu_mouse_config_descriptor,
bellard09b26c52006-04-12 21:09:08 +0000676 sizeof(qemu_mouse_config_descriptor));
677 ret = sizeof(qemu_mouse_config_descriptor);
678 } else if (s->kind == USB_TABLET) {
ths5fafdf22007-09-16 21:08:06 +0000679 memcpy(data, qemu_tablet_config_descriptor,
bellard09b26c52006-04-12 21:09:08 +0000680 sizeof(qemu_tablet_config_descriptor));
681 ret = sizeof(qemu_tablet_config_descriptor);
balrog47b2d332007-06-22 08:16:00 +0000682 } else if (s->kind == USB_KEYBOARD) {
ths5fafdf22007-09-16 21:08:06 +0000683 memcpy(data, qemu_keyboard_config_descriptor,
balrog47b2d332007-06-22 08:16:00 +0000684 sizeof(qemu_keyboard_config_descriptor));
685 ret = sizeof(qemu_keyboard_config_descriptor);
686 }
bellard59ae5402005-11-05 16:57:08 +0000687 break;
688 case USB_DT_STRING:
689 switch(value & 0xff) {
690 case 0:
691 /* language ids */
692 data[0] = 4;
693 data[1] = 3;
694 data[2] = 0x09;
695 data[3] = 0x04;
696 ret = 4;
697 break;
698 case 1:
699 /* serial number */
700 ret = set_usb_string(data, "1");
701 break;
702 case 2:
703 /* product description */
balrog47b2d332007-06-22 08:16:00 +0000704 ret = set_usb_string(data, s->dev.devname);
bellard59ae5402005-11-05 16:57:08 +0000705 break;
706 case 3:
707 /* vendor description */
708 ret = set_usb_string(data, "QEMU " QEMU_VERSION);
709 break;
710 case 4:
711 ret = set_usb_string(data, "HID Mouse");
712 break;
713 case 5:
balrog47b2d332007-06-22 08:16:00 +0000714 ret = set_usb_string(data, "HID Tablet");
715 break;
716 case 6:
717 ret = set_usb_string(data, "HID Keyboard");
718 break;
719 case 7:
bellard59ae5402005-11-05 16:57:08 +0000720 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
721 break;
722 default:
723 goto fail;
724 }
725 break;
726 default:
727 goto fail;
728 }
729 break;
730 case DeviceRequest | USB_REQ_GET_CONFIGURATION:
731 data[0] = 1;
732 ret = 1;
733 break;
734 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
735 ret = 0;
736 break;
737 case DeviceRequest | USB_REQ_GET_INTERFACE:
738 data[0] = 0;
739 ret = 1;
740 break;
741 case DeviceOutRequest | USB_REQ_SET_INTERFACE:
742 ret = 0;
743 break;
744 /* hid specific requests */
745 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
746 switch(value >> 8) {
747 case 0x22:
bellard09b26c52006-04-12 21:09:08 +0000748 if (s->kind == USB_MOUSE) {
ths5fafdf22007-09-16 21:08:06 +0000749 memcpy(data, qemu_mouse_hid_report_descriptor,
bellard09b26c52006-04-12 21:09:08 +0000750 sizeof(qemu_mouse_hid_report_descriptor));
751 ret = sizeof(qemu_mouse_hid_report_descriptor);
752 } else if (s->kind == USB_TABLET) {
ths5fafdf22007-09-16 21:08:06 +0000753 memcpy(data, qemu_tablet_hid_report_descriptor,
bellard09b26c52006-04-12 21:09:08 +0000754 sizeof(qemu_tablet_hid_report_descriptor));
755 ret = sizeof(qemu_tablet_hid_report_descriptor);
balrog47b2d332007-06-22 08:16:00 +0000756 } else if (s->kind == USB_KEYBOARD) {
ths5fafdf22007-09-16 21:08:06 +0000757 memcpy(data, qemu_keyboard_hid_report_descriptor,
balrog47b2d332007-06-22 08:16:00 +0000758 sizeof(qemu_keyboard_hid_report_descriptor));
759 ret = sizeof(qemu_keyboard_hid_report_descriptor);
760 }
761 break;
bellard59ae5402005-11-05 16:57:08 +0000762 default:
763 goto fail;
764 }
765 break;
766 case GET_REPORT:
bellard09b26c52006-04-12 21:09:08 +0000767 if (s->kind == USB_MOUSE)
pbrook117b3ae2007-09-09 21:16:01 +0000768 ret = usb_mouse_poll(s, data, length);
bellard09b26c52006-04-12 21:09:08 +0000769 else if (s->kind == USB_TABLET)
pbrook117b3ae2007-09-09 21:16:01 +0000770 ret = usb_tablet_poll(s, data, length);
balrog47b2d332007-06-22 08:16:00 +0000771 else if (s->kind == USB_KEYBOARD)
772 ret = usb_keyboard_poll(&s->kbd, data, length);
773 break;
774 case SET_REPORT:
775 if (s->kind == USB_KEYBOARD)
776 ret = usb_keyboard_write(&s->kbd, data, length);
777 else
778 goto fail;
779 break;
780 case GET_PROTOCOL:
781 if (s->kind != USB_KEYBOARD)
782 goto fail;
783 ret = 1;
784 data[0] = s->protocol;
785 break;
786 case SET_PROTOCOL:
787 if (s->kind != USB_KEYBOARD)
788 goto fail;
789 ret = 0;
790 s->protocol = value;
791 break;
792 case GET_IDLE:
793 ret = 1;
794 data[0] = s->idle;
bellard59ae5402005-11-05 16:57:08 +0000795 break;
796 case SET_IDLE:
aliguori181a29c2009-01-07 16:41:47 +0000797 s->idle = (uint8_t) (value >> 8);
bellard59ae5402005-11-05 16:57:08 +0000798 ret = 0;
799 break;
800 default:
801 fail:
802 ret = USB_RET_STALL;
803 break;
804 }
805 return ret;
806}
807
balrog47b2d332007-06-22 08:16:00 +0000808static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
bellard59ae5402005-11-05 16:57:08 +0000809{
balrog47b2d332007-06-22 08:16:00 +0000810 USBHIDState *s = (USBHIDState *)dev;
bellard09b26c52006-04-12 21:09:08 +0000811 int ret = 0;
bellard59ae5402005-11-05 16:57:08 +0000812
pbrook4d611c92006-08-12 01:04:27 +0000813 switch(p->pid) {
bellard59ae5402005-11-05 16:57:08 +0000814 case USB_TOKEN_IN:
pbrook4d611c92006-08-12 01:04:27 +0000815 if (p->devep == 1) {
pbrook117b3ae2007-09-09 21:16:01 +0000816 /* TODO: Implement finite idle delays. */
817 if (!(s->changed || s->idle))
818 return USB_RET_NAK;
819 s->changed = 0;
balrog47b2d332007-06-22 08:16:00 +0000820 if (s->kind == USB_MOUSE)
pbrook117b3ae2007-09-09 21:16:01 +0000821 ret = usb_mouse_poll(s, p->data, p->len);
balrog47b2d332007-06-22 08:16:00 +0000822 else if (s->kind == USB_TABLET)
pbrook117b3ae2007-09-09 21:16:01 +0000823 ret = usb_tablet_poll(s, p->data, p->len);
balrog47b2d332007-06-22 08:16:00 +0000824 else if (s->kind == USB_KEYBOARD)
825 ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
bellard59ae5402005-11-05 16:57:08 +0000826 } else {
827 goto fail;
828 }
829 break;
830 case USB_TOKEN_OUT:
831 default:
832 fail:
833 ret = USB_RET_STALL;
834 break;
835 }
836 return ret;
837}
838
balrog47b2d332007-06-22 08:16:00 +0000839static void usb_hid_handle_destroy(USBDevice *dev)
bellard059809e2006-07-19 18:06:15 +0000840{
balrog47b2d332007-06-22 08:16:00 +0000841 USBHIDState *s = (USBHIDState *)dev;
bellard059809e2006-07-19 18:06:15 +0000842
balrog47b2d332007-06-22 08:16:00 +0000843 if (s->kind != USB_KEYBOARD)
844 qemu_remove_mouse_event_handler(s->ptr.eh_entry);
845 /* TODO: else */
bellard059809e2006-07-19 18:06:15 +0000846 qemu_free(s);
847}
848
bellard09b26c52006-04-12 21:09:08 +0000849USBDevice *usb_tablet_init(void)
850{
balrog47b2d332007-06-22 08:16:00 +0000851 USBHIDState *s;
bellard09b26c52006-04-12 21:09:08 +0000852
balrog47b2d332007-06-22 08:16:00 +0000853 s = qemu_mallocz(sizeof(USBHIDState));
bellard09b26c52006-04-12 21:09:08 +0000854 s->dev.speed = USB_SPEED_FULL;
855 s->dev.handle_packet = usb_generic_handle_packet;
856
857 s->dev.handle_reset = usb_mouse_handle_reset;
balrog47b2d332007-06-22 08:16:00 +0000858 s->dev.handle_control = usb_hid_handle_control;
859 s->dev.handle_data = usb_hid_handle_data;
860 s->dev.handle_destroy = usb_hid_handle_destroy;
bellard09b26c52006-04-12 21:09:08 +0000861 s->kind = USB_TABLET;
pbrook117b3ae2007-09-09 21:16:01 +0000862 /* Force poll routine to be run and grab input the first time. */
863 s->changed = 1;
bellard09b26c52006-04-12 21:09:08 +0000864
bellard1f6e24e2006-06-26 21:00:51 +0000865 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
866
bellard09b26c52006-04-12 21:09:08 +0000867 return (USBDevice *)s;
868}
869
bellard59ae5402005-11-05 16:57:08 +0000870USBDevice *usb_mouse_init(void)
871{
balrog47b2d332007-06-22 08:16:00 +0000872 USBHIDState *s;
bellard59ae5402005-11-05 16:57:08 +0000873
balrog47b2d332007-06-22 08:16:00 +0000874 s = qemu_mallocz(sizeof(USBHIDState));
bellard59ae5402005-11-05 16:57:08 +0000875 s->dev.speed = USB_SPEED_FULL;
876 s->dev.handle_packet = usb_generic_handle_packet;
877
878 s->dev.handle_reset = usb_mouse_handle_reset;
balrog47b2d332007-06-22 08:16:00 +0000879 s->dev.handle_control = usb_hid_handle_control;
880 s->dev.handle_data = usb_hid_handle_data;
881 s->dev.handle_destroy = usb_hid_handle_destroy;
bellard09b26c52006-04-12 21:09:08 +0000882 s->kind = USB_MOUSE;
pbrook117b3ae2007-09-09 21:16:01 +0000883 /* Force poll routine to be run and grab input the first time. */
884 s->changed = 1;
bellard59ae5402005-11-05 16:57:08 +0000885
bellard1f6e24e2006-06-26 21:00:51 +0000886 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
887
bellard59ae5402005-11-05 16:57:08 +0000888 return (USBDevice *)s;
889}
balrog47b2d332007-06-22 08:16:00 +0000890
891USBDevice *usb_keyboard_init(void)
892{
893 USBHIDState *s;
894
895 s = qemu_mallocz(sizeof(USBHIDState));
balrog47b2d332007-06-22 08:16:00 +0000896 s->dev.speed = USB_SPEED_FULL;
897 s->dev.handle_packet = usb_generic_handle_packet;
898
899 s->dev.handle_reset = usb_keyboard_handle_reset;
900 s->dev.handle_control = usb_hid_handle_control;
901 s->dev.handle_data = usb_hid_handle_data;
902 s->dev.handle_destroy = usb_hid_handle_destroy;
903 s->kind = USB_KEYBOARD;
904
905 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard");
906
907 return (USBDevice *) s;
908}
balrog47e699d2008-09-29 00:25:17 +0000909
910void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
911{
912 USBHIDState *s = (USBHIDState *)dev;
913
914 s->datain_opaque = opaque;
915 s->datain = datain;
916}