|
1 /* |
|
2 * QEMU USB HID devices |
|
3 * |
|
4 * Copyright (c) 2005 Fabrice Bellard |
|
5 * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) |
|
6 * |
|
7 * 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 */ |
|
25 #include "hw.h" |
|
26 #include "console.h" |
|
27 #include "usb.h" |
|
28 #include "gui.h" |
|
29 |
|
30 /* HID interface requests */ |
|
31 #define GET_REPORT 0xa101 |
|
32 #define GET_IDLE 0xa102 |
|
33 #define GET_PROTOCOL 0xa103 |
|
34 #define SET_REPORT 0x2109 |
|
35 #define SET_IDLE 0x210a |
|
36 #define SET_PROTOCOL 0x210b |
|
37 |
|
38 /* HID descriptor types */ |
|
39 #define USB_DT_HID 0x21 |
|
40 #define USB_DT_REPORT 0x22 |
|
41 #define USB_DT_PHY 0x23 |
|
42 |
|
43 #define USB_MOUSE 1 |
|
44 #define USB_TABLET 2 |
|
45 #define USB_KEYBOARD 3 |
|
46 |
|
47 typedef struct USBMouseState { |
|
48 int dx, dy, dz, buttons_state; |
|
49 int x, y; |
|
50 int mouse_grabbed; |
|
51 QEMUPutMouseEntry *eh_entry; |
|
52 } USBMouseState; |
|
53 |
|
54 typedef struct USBKeyboardState { |
|
55 uint16_t modifiers; |
|
56 uint8_t leds; |
|
57 uint8_t key[16]; |
|
58 int keys; |
|
59 } USBKeyboardState; |
|
60 |
|
61 typedef struct USBHIDState { |
|
62 USBDevice dev; |
|
63 union { |
|
64 USBMouseState ptr; |
|
65 USBKeyboardState kbd; |
|
66 }; |
|
67 int kind; |
|
68 int protocol; |
|
69 int idle; |
|
70 int changed; |
|
71 void *datain_opaque; |
|
72 void (*datain)(void *); |
|
73 } USBHIDState; |
|
74 |
|
75 /* mostly the same values as the Bochs USB Mouse device */ |
|
76 static const uint8_t qemu_mouse_dev_descriptor[] = { |
|
77 0x12, /* u8 bLength; */ |
|
78 0x01, /* u8 bDescriptorType; Device */ |
|
79 0x00, 0x01, /* u16 bcdUSB; v1.0 */ |
|
80 |
|
81 0x00, /* u8 bDeviceClass; */ |
|
82 0x00, /* u8 bDeviceSubClass; */ |
|
83 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ |
|
84 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ |
|
85 |
|
86 0x27, 0x06, /* u16 idVendor; */ |
|
87 0x01, 0x00, /* u16 idProduct; */ |
|
88 0x00, 0x00, /* u16 bcdDevice */ |
|
89 |
|
90 0x03, /* u8 iManufacturer; */ |
|
91 0x02, /* u8 iProduct; */ |
|
92 0x01, /* u8 iSerialNumber; */ |
|
93 0x01 /* u8 bNumConfigurations; */ |
|
94 }; |
|
95 |
|
96 static const uint8_t qemu_mouse_config_descriptor[] = { |
|
97 /* one configuration */ |
|
98 0x09, /* u8 bLength; */ |
|
99 0x02, /* u8 bDescriptorType; Configuration */ |
|
100 0x22, 0x00, /* u16 wTotalLength; */ |
|
101 0x01, /* u8 bNumInterfaces; (1) */ |
|
102 0x01, /* u8 bConfigurationValue; */ |
|
103 0x04, /* u8 iConfiguration; */ |
|
104 0xa0, /* u8 bmAttributes; |
|
105 Bit 7: must be set, |
|
106 6: Self-powered, |
|
107 5: Remote wakeup, |
|
108 4..0: resvd */ |
|
109 50, /* u8 MaxPower; */ |
|
110 |
|
111 /* USB 1.1: |
|
112 * USB 2.0, single TT organization (mandatory): |
|
113 * one interface, protocol 0 |
|
114 * |
|
115 * USB 2.0, multiple TT organization (optional): |
|
116 * two interfaces, protocols 1 (like single TT) |
|
117 * and 2 (multiple TT mode) ... config is |
|
118 * sometimes settable |
|
119 * NOT IMPLEMENTED |
|
120 */ |
|
121 |
|
122 /* one interface */ |
|
123 0x09, /* u8 if_bLength; */ |
|
124 0x04, /* u8 if_bDescriptorType; Interface */ |
|
125 0x00, /* u8 if_bInterfaceNumber; */ |
|
126 0x00, /* u8 if_bAlternateSetting; */ |
|
127 0x01, /* u8 if_bNumEndpoints; */ |
|
128 0x03, /* u8 if_bInterfaceClass; */ |
|
129 0x01, /* u8 if_bInterfaceSubClass; */ |
|
130 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ |
|
131 0x07, /* u8 if_iInterface; */ |
|
132 |
|
133 /* HID descriptor */ |
|
134 0x09, /* u8 bLength; */ |
|
135 0x21, /* u8 bDescriptorType; */ |
|
136 0x01, 0x00, /* u16 HID_class */ |
|
137 0x00, /* u8 country_code */ |
|
138 0x01, /* u8 num_descriptors */ |
|
139 0x22, /* u8 type; Report */ |
|
140 52, 0, /* u16 len */ |
|
141 |
|
142 /* one endpoint (status change endpoint) */ |
|
143 0x07, /* u8 ep_bLength; */ |
|
144 0x05, /* u8 ep_bDescriptorType; Endpoint */ |
|
145 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ |
|
146 0x03, /* u8 ep_bmAttributes; Interrupt */ |
|
147 0x04, 0x00, /* u16 ep_wMaxPacketSize; */ |
|
148 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ |
|
149 }; |
|
150 |
|
151 static const uint8_t qemu_tablet_config_descriptor[] = { |
|
152 /* one configuration */ |
|
153 0x09, /* u8 bLength; */ |
|
154 0x02, /* u8 bDescriptorType; Configuration */ |
|
155 0x22, 0x00, /* u16 wTotalLength; */ |
|
156 0x01, /* u8 bNumInterfaces; (1) */ |
|
157 0x01, /* u8 bConfigurationValue; */ |
|
158 0x05, /* u8 iConfiguration; */ |
|
159 0xa0, /* u8 bmAttributes; |
|
160 Bit 7: must be set, |
|
161 6: Self-powered, |
|
162 5: Remote wakeup, |
|
163 4..0: resvd */ |
|
164 50, /* u8 MaxPower; */ |
|
165 |
|
166 /* USB 1.1: |
|
167 * USB 2.0, single TT organization (mandatory): |
|
168 * one interface, protocol 0 |
|
169 * |
|
170 * USB 2.0, multiple TT organization (optional): |
|
171 * two interfaces, protocols 1 (like single TT) |
|
172 * and 2 (multiple TT mode) ... config is |
|
173 * sometimes settable |
|
174 * NOT IMPLEMENTED |
|
175 */ |
|
176 |
|
177 /* one interface */ |
|
178 0x09, /* u8 if_bLength; */ |
|
179 0x04, /* u8 if_bDescriptorType; Interface */ |
|
180 0x00, /* u8 if_bInterfaceNumber; */ |
|
181 0x00, /* u8 if_bAlternateSetting; */ |
|
182 0x01, /* u8 if_bNumEndpoints; */ |
|
183 0x03, /* u8 if_bInterfaceClass; */ |
|
184 0x01, /* u8 if_bInterfaceSubClass; */ |
|
185 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ |
|
186 0x07, /* u8 if_iInterface; */ |
|
187 |
|
188 /* HID descriptor */ |
|
189 0x09, /* u8 bLength; */ |
|
190 0x21, /* u8 bDescriptorType; */ |
|
191 0x01, 0x00, /* u16 HID_class */ |
|
192 0x00, /* u8 country_code */ |
|
193 0x01, /* u8 num_descriptors */ |
|
194 0x22, /* u8 type; Report */ |
|
195 74, 0, /* u16 len */ |
|
196 |
|
197 /* one endpoint (status change endpoint) */ |
|
198 0x07, /* u8 ep_bLength; */ |
|
199 0x05, /* u8 ep_bDescriptorType; Endpoint */ |
|
200 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ |
|
201 0x03, /* u8 ep_bmAttributes; Interrupt */ |
|
202 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ |
|
203 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ |
|
204 }; |
|
205 |
|
206 static const uint8_t qemu_keyboard_config_descriptor[] = { |
|
207 /* one configuration */ |
|
208 0x09, /* u8 bLength; */ |
|
209 USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ |
|
210 0x22, 0x00, /* u16 wTotalLength; */ |
|
211 0x01, /* u8 bNumInterfaces; (1) */ |
|
212 0x01, /* u8 bConfigurationValue; */ |
|
213 0x06, /* u8 iConfiguration; */ |
|
214 0xa0, /* u8 bmAttributes; |
|
215 Bit 7: must be set, |
|
216 6: Self-powered, |
|
217 5: Remote wakeup, |
|
218 4..0: resvd */ |
|
219 0x32, /* u8 MaxPower; */ |
|
220 |
|
221 /* USB 1.1: |
|
222 * USB 2.0, single TT organization (mandatory): |
|
223 * one interface, protocol 0 |
|
224 * |
|
225 * USB 2.0, multiple TT organization (optional): |
|
226 * two interfaces, protocols 1 (like single TT) |
|
227 * and 2 (multiple TT mode) ... config is |
|
228 * sometimes settable |
|
229 * NOT IMPLEMENTED |
|
230 */ |
|
231 |
|
232 /* one interface */ |
|
233 0x09, /* u8 if_bLength; */ |
|
234 USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ |
|
235 0x00, /* u8 if_bInterfaceNumber; */ |
|
236 0x00, /* u8 if_bAlternateSetting; */ |
|
237 0x01, /* u8 if_bNumEndpoints; */ |
|
238 0x03, /* u8 if_bInterfaceClass; HID */ |
|
239 0x01, /* u8 if_bInterfaceSubClass; Boot */ |
|
240 0x01, /* u8 if_bInterfaceProtocol; Keyboard */ |
|
241 0x07, /* u8 if_iInterface; */ |
|
242 |
|
243 /* HID descriptor */ |
|
244 0x09, /* u8 bLength; */ |
|
245 USB_DT_HID, /* u8 bDescriptorType; */ |
|
246 0x11, 0x01, /* u16 HID_class */ |
|
247 0x00, /* u8 country_code */ |
|
248 0x01, /* u8 num_descriptors */ |
|
249 USB_DT_REPORT, /* u8 type; Report */ |
|
250 0x3f, 0x00, /* u16 len */ |
|
251 |
|
252 /* one endpoint (status change endpoint) */ |
|
253 0x07, /* u8 ep_bLength; */ |
|
254 USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */ |
|
255 USB_DIR_IN | 0x01, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ |
|
256 0x03, /* u8 ep_bmAttributes; Interrupt */ |
|
257 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ |
|
258 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ |
|
259 }; |
|
260 |
|
261 static const uint8_t qemu_mouse_hid_report_descriptor[] = { |
|
262 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
|
263 0x09, 0x02, /* Usage (Mouse) */ |
|
264 0xa1, 0x01, /* Collection (Application) */ |
|
265 0x09, 0x01, /* Usage (Pointer) */ |
|
266 0xa1, 0x00, /* Collection (Physical) */ |
|
267 0x05, 0x09, /* Usage Page (Button) */ |
|
268 0x19, 0x01, /* Usage Minimum (1) */ |
|
269 0x29, 0x03, /* Usage Maximum (3) */ |
|
270 0x15, 0x00, /* Logical Minimum (0) */ |
|
271 0x25, 0x01, /* Logical Maximum (1) */ |
|
272 0x95, 0x03, /* Report Count (3) */ |
|
273 0x75, 0x01, /* Report Size (1) */ |
|
274 0x81, 0x02, /* Input (Data, Variable, Absolute) */ |
|
275 0x95, 0x01, /* Report Count (1) */ |
|
276 0x75, 0x05, /* Report Size (5) */ |
|
277 0x81, 0x01, /* Input (Constant) */ |
|
278 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
|
279 0x09, 0x30, /* Usage (X) */ |
|
280 0x09, 0x31, /* Usage (Y) */ |
|
281 0x09, 0x38, /* Usage (Wheel) */ |
|
282 0x15, 0x81, /* Logical Minimum (-0x7f) */ |
|
283 0x25, 0x7f, /* Logical Maximum (0x7f) */ |
|
284 0x75, 0x08, /* Report Size (8) */ |
|
285 0x95, 0x03, /* Report Count (3) */ |
|
286 0x81, 0x06, /* Input (Data, Variable, Relative) */ |
|
287 0xc0, /* End Collection */ |
|
288 0xc0, /* End Collection */ |
|
289 }; |
|
290 |
|
291 static const uint8_t qemu_tablet_hid_report_descriptor[] = { |
|
292 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
|
293 0x09, 0x01, /* Usage (Pointer) */ |
|
294 0xa1, 0x01, /* Collection (Application) */ |
|
295 0x09, 0x01, /* Usage (Pointer) */ |
|
296 0xa1, 0x00, /* Collection (Physical) */ |
|
297 0x05, 0x09, /* Usage Page (Button) */ |
|
298 0x19, 0x01, /* Usage Minimum (1) */ |
|
299 0x29, 0x03, /* Usage Maximum (3) */ |
|
300 0x15, 0x00, /* Logical Minimum (0) */ |
|
301 0x25, 0x01, /* Logical Maximum (1) */ |
|
302 0x95, 0x03, /* Report Count (3) */ |
|
303 0x75, 0x01, /* Report Size (1) */ |
|
304 0x81, 0x02, /* Input (Data, Variable, Absolute) */ |
|
305 0x95, 0x01, /* Report Count (1) */ |
|
306 0x75, 0x05, /* Report Size (5) */ |
|
307 0x81, 0x01, /* Input (Constant) */ |
|
308 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
|
309 0x09, 0x30, /* Usage (X) */ |
|
310 0x09, 0x31, /* Usage (Y) */ |
|
311 0x15, 0x00, /* Logical Minimum (0) */ |
|
312 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */ |
|
313 0x35, 0x00, /* Physical Minimum (0) */ |
|
314 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */ |
|
315 0x75, 0x10, /* Report Size (16) */ |
|
316 0x95, 0x02, /* Report Count (2) */ |
|
317 0x81, 0x02, /* Input (Data, Variable, Absolute) */ |
|
318 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
|
319 0x09, 0x38, /* Usage (Wheel) */ |
|
320 0x15, 0x81, /* Logical Minimum (-0x7f) */ |
|
321 0x25, 0x7f, /* Logical Maximum (0x7f) */ |
|
322 0x35, 0x00, /* Physical Minimum (same as logical) */ |
|
323 0x45, 0x00, /* Physical Maximum (same as logical) */ |
|
324 0x75, 0x08, /* Report Size (8) */ |
|
325 0x95, 0x01, /* Report Count (1) */ |
|
326 0x81, 0x06, /* Input (Data, Variable, Relative) */ |
|
327 0xc0, /* End Collection */ |
|
328 0xc0, /* End Collection */ |
|
329 }; |
|
330 |
|
331 static const uint8_t qemu_keyboard_hid_report_descriptor[] = { |
|
332 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
|
333 0x09, 0x06, /* Usage (Keyboard) */ |
|
334 0xa1, 0x01, /* Collection (Application) */ |
|
335 0x75, 0x01, /* Report Size (1) */ |
|
336 0x95, 0x08, /* Report Count (8) */ |
|
337 0x05, 0x07, /* Usage Page (Key Codes) */ |
|
338 0x19, 0xe0, /* Usage Minimum (224) */ |
|
339 0x29, 0xe7, /* Usage Maximum (231) */ |
|
340 0x15, 0x00, /* Logical Minimum (0) */ |
|
341 0x25, 0x01, /* Logical Maximum (1) */ |
|
342 0x81, 0x02, /* Input (Data, Variable, Absolute) */ |
|
343 0x95, 0x01, /* Report Count (1) */ |
|
344 0x75, 0x08, /* Report Size (8) */ |
|
345 0x81, 0x01, /* Input (Constant) */ |
|
346 0x95, 0x05, /* Report Count (5) */ |
|
347 0x75, 0x01, /* Report Size (1) */ |
|
348 0x05, 0x08, /* Usage Page (LEDs) */ |
|
349 0x19, 0x01, /* Usage Minimum (1) */ |
|
350 0x29, 0x05, /* Usage Maximum (5) */ |
|
351 0x91, 0x02, /* Output (Data, Variable, Absolute) */ |
|
352 0x95, 0x01, /* Report Count (1) */ |
|
353 0x75, 0x03, /* Report Size (3) */ |
|
354 0x91, 0x01, /* Output (Constant) */ |
|
355 0x95, 0x06, /* Report Count (6) */ |
|
356 0x75, 0x08, /* Report Size (8) */ |
|
357 0x15, 0x00, /* Logical Minimum (0) */ |
|
358 0x25, 0xff, /* Logical Maximum (255) */ |
|
359 0x05, 0x07, /* Usage Page (Key Codes) */ |
|
360 0x19, 0x00, /* Usage Minimum (0) */ |
|
361 0x29, 0xff, /* Usage Maximum (255) */ |
|
362 0x81, 0x00, /* Input (Data, Array) */ |
|
363 0xc0, /* End Collection */ |
|
364 }; |
|
365 |
|
366 #define USB_HID_USAGE_ERROR_ROLLOVER 0x01 |
|
367 #define USB_HID_USAGE_POSTFAIL 0x02 |
|
368 #define USB_HID_USAGE_ERROR_UNDEFINED 0x03 |
|
369 |
|
370 /* Indices are QEMU keycodes, values are from HID Usage Table. Indices |
|
371 * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ |
|
372 static const uint8_t usb_hid_usage_keys[0x100] = { |
|
373 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
|
374 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, |
|
375 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, |
|
376 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, |
|
377 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, |
|
378 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, |
|
379 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, |
|
380 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, |
|
381 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, |
|
382 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, |
|
383 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, |
|
384 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, |
|
385 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, |
|
386 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, |
|
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
388 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, |
|
389 |
|
390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
392 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
393 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, |
|
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, |
|
397 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, |
|
399 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, |
|
400 0x51, 0x4e, 0x49, 0x4c, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
406 }; |
|
407 |
|
408 static void usb_hid_changed(USBHIDState *hs) |
|
409 { |
|
410 hs->changed = 1; |
|
411 |
|
412 if (hs->datain) |
|
413 hs->datain(hs->datain_opaque); |
|
414 } |
|
415 |
|
416 static void usb_mouse_event(void *opaque, |
|
417 int dx1, int dy1, int dz1, int buttons_state) |
|
418 { |
|
419 USBHIDState *hs = opaque; |
|
420 USBMouseState *s = &hs->ptr; |
|
421 |
|
422 s->dx += dx1; |
|
423 s->dy += dy1; |
|
424 s->dz += dz1; |
|
425 s->buttons_state = buttons_state; |
|
426 |
|
427 usb_hid_changed(hs); |
|
428 } |
|
429 |
|
430 static void usb_tablet_event(void *opaque, |
|
431 int x, int y, int dz, int buttons_state) |
|
432 { |
|
433 USBHIDState *hs = opaque; |
|
434 USBMouseState *s = &hs->ptr; |
|
435 |
|
436 s->x = x; |
|
437 s->y = y; |
|
438 s->dz += dz; |
|
439 s->buttons_state = buttons_state; |
|
440 |
|
441 usb_hid_changed(hs); |
|
442 } |
|
443 |
|
444 static void usb_keyboard_event(void *opaque, int keycode) |
|
445 { |
|
446 USBHIDState *hs = opaque; |
|
447 USBKeyboardState *s = &hs->kbd; |
|
448 uint8_t hid_code, key; |
|
449 int i; |
|
450 |
|
451 key = keycode & 0x7f; |
|
452 hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))]; |
|
453 s->modifiers &= ~(1 << 8); |
|
454 |
|
455 switch (hid_code) { |
|
456 case 0x00: |
|
457 return; |
|
458 |
|
459 case 0xe0: |
|
460 if (s->modifiers & (1 << 9)) { |
|
461 s->modifiers ^= 3 << 8; |
|
462 return; |
|
463 } |
|
464 case 0xe1 ... 0xe7: |
|
465 if (keycode & (1 << 7)) { |
|
466 s->modifiers &= ~(1 << (hid_code & 0x0f)); |
|
467 return; |
|
468 } |
|
469 case 0xe8 ... 0xef: |
|
470 s->modifiers |= 1 << (hid_code & 0x0f); |
|
471 return; |
|
472 } |
|
473 |
|
474 if (keycode & (1 << 7)) { |
|
475 for (i = s->keys - 1; i >= 0; i --) |
|
476 if (s->key[i] == hid_code) { |
|
477 s->key[i] = s->key[-- s->keys]; |
|
478 s->key[s->keys] = 0x00; |
|
479 usb_hid_changed(hs); |
|
480 break; |
|
481 } |
|
482 if (i < 0) |
|
483 return; |
|
484 } else { |
|
485 for (i = s->keys - 1; i >= 0; i --) |
|
486 if (s->key[i] == hid_code) |
|
487 break; |
|
488 if (i < 0) { |
|
489 if (s->keys < sizeof(s->key)) |
|
490 s->key[s->keys ++] = hid_code; |
|
491 } else |
|
492 return; |
|
493 } |
|
494 |
|
495 usb_hid_changed(hs); |
|
496 } |
|
497 |
|
498 static inline int int_clamp(int val, int vmin, int vmax) |
|
499 { |
|
500 if (val < vmin) |
|
501 return vmin; |
|
502 else if (val > vmax) |
|
503 return vmax; |
|
504 else |
|
505 return val; |
|
506 } |
|
507 |
|
508 static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) |
|
509 { |
|
510 int dx, dy, dz, b, l; |
|
511 USBMouseState *s = &hs->ptr; |
|
512 |
|
513 if (!s->mouse_grabbed) { |
|
514 s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs, |
|
515 0, "QEMU USB Mouse"); |
|
516 s->mouse_grabbed = 1; |
|
517 } |
|
518 |
|
519 dx = int_clamp(s->dx, -127, 127); |
|
520 dy = int_clamp(s->dy, -127, 127); |
|
521 dz = int_clamp(s->dz, -127, 127); |
|
522 |
|
523 s->dx -= dx; |
|
524 s->dy -= dy; |
|
525 s->dz -= dz; |
|
526 |
|
527 /* Appears we have to invert the wheel direction */ |
|
528 dz = 0 - dz; |
|
529 |
|
530 b = 0; |
|
531 if (s->buttons_state & MOUSE_EVENT_LBUTTON) |
|
532 b |= 0x01; |
|
533 if (s->buttons_state & MOUSE_EVENT_RBUTTON) |
|
534 b |= 0x02; |
|
535 if (s->buttons_state & MOUSE_EVENT_MBUTTON) |
|
536 b |= 0x04; |
|
537 |
|
538 l = 0; |
|
539 if (len > l) |
|
540 buf[l ++] = b; |
|
541 if (len > l) |
|
542 buf[l ++] = dx; |
|
543 if (len > l) |
|
544 buf[l ++] = dy; |
|
545 if (len > l) |
|
546 buf[l ++] = dz; |
|
547 return l; |
|
548 } |
|
549 |
|
550 static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len) |
|
551 { |
|
552 int dz, b, l; |
|
553 USBMouseState *s = &hs->ptr; |
|
554 |
|
555 if (!s->mouse_grabbed) { |
|
556 s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs, |
|
557 1, "QEMU USB Tablet"); |
|
558 s->mouse_grabbed = 1; |
|
559 } |
|
560 |
|
561 dz = int_clamp(s->dz, -127, 127); |
|
562 s->dz -= dz; |
|
563 |
|
564 /* Appears we have to invert the wheel direction */ |
|
565 dz = 0 - dz; |
|
566 b = 0; |
|
567 if (s->buttons_state & MOUSE_EVENT_LBUTTON) |
|
568 b |= 0x01; |
|
569 if (s->buttons_state & MOUSE_EVENT_RBUTTON) |
|
570 b |= 0x02; |
|
571 if (s->buttons_state & MOUSE_EVENT_MBUTTON) |
|
572 b |= 0x04; |
|
573 |
|
574 buf[0] = b; |
|
575 buf[1] = s->x & 0xff; |
|
576 buf[2] = s->x >> 8; |
|
577 buf[3] = s->y & 0xff; |
|
578 buf[4] = s->y >> 8; |
|
579 buf[5] = dz; |
|
580 l = 6; |
|
581 |
|
582 return l; |
|
583 } |
|
584 |
|
585 static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len) |
|
586 { |
|
587 if (len < 2) |
|
588 return 0; |
|
589 |
|
590 buf[0] = s->modifiers & 0xff; |
|
591 buf[1] = 0; |
|
592 if (s->keys > 6) |
|
593 memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); |
|
594 else |
|
595 memcpy(buf + 2, s->key, MIN(8, len) - 2); |
|
596 |
|
597 return MIN(8, len); |
|
598 } |
|
599 |
|
600 static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len) |
|
601 { |
|
602 if (len > 0) { |
|
603 /* 0x01: Num Lock LED |
|
604 * 0x02: Caps Lock LED |
|
605 * 0x04: Scroll Lock LED |
|
606 * 0x08: Compose LED |
|
607 * 0x10: Kana LED */ |
|
608 s->leds = buf[0]; |
|
609 } |
|
610 return 0; |
|
611 } |
|
612 |
|
613 static void usb_mouse_handle_reset(USBDevice *dev) |
|
614 { |
|
615 USBHIDState *s = (USBHIDState *)dev; |
|
616 |
|
617 s->ptr.dx = 0; |
|
618 s->ptr.dy = 0; |
|
619 s->ptr.dz = 0; |
|
620 s->ptr.x = 0; |
|
621 s->ptr.y = 0; |
|
622 s->ptr.buttons_state = 0; |
|
623 s->protocol = 1; |
|
624 } |
|
625 |
|
626 static void usb_keyboard_handle_reset(USBDevice *dev) |
|
627 { |
|
628 USBHIDState *s = (USBHIDState *)dev; |
|
629 |
|
630 gui_register_dev_key_callback(usb_keyboard_event, s); |
|
631 s->protocol = 1; |
|
632 } |
|
633 |
|
634 static int usb_hid_handle_control(USBDevice *dev, int request, int value, |
|
635 int index, int length, uint8_t *data) |
|
636 { |
|
637 USBHIDState *s = (USBHIDState *)dev; |
|
638 int ret = 0; |
|
639 |
|
640 switch(request) { |
|
641 case DeviceRequest | USB_REQ_GET_STATUS: |
|
642 data[0] = (1 << USB_DEVICE_SELF_POWERED) | |
|
643 (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); |
|
644 data[1] = 0x00; |
|
645 ret = 2; |
|
646 break; |
|
647 case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: |
|
648 if (value == USB_DEVICE_REMOTE_WAKEUP) { |
|
649 dev->remote_wakeup = 0; |
|
650 } else { |
|
651 goto fail; |
|
652 } |
|
653 ret = 0; |
|
654 break; |
|
655 case DeviceOutRequest | USB_REQ_SET_FEATURE: |
|
656 if (value == USB_DEVICE_REMOTE_WAKEUP) { |
|
657 dev->remote_wakeup = 1; |
|
658 } else { |
|
659 goto fail; |
|
660 } |
|
661 ret = 0; |
|
662 break; |
|
663 case DeviceOutRequest | USB_REQ_SET_ADDRESS: |
|
664 dev->addr = value; |
|
665 ret = 0; |
|
666 break; |
|
667 case DeviceRequest | USB_REQ_GET_DESCRIPTOR: |
|
668 switch(value >> 8) { |
|
669 case USB_DT_DEVICE: |
|
670 memcpy(data, qemu_mouse_dev_descriptor, |
|
671 sizeof(qemu_mouse_dev_descriptor)); |
|
672 ret = sizeof(qemu_mouse_dev_descriptor); |
|
673 break; |
|
674 case USB_DT_CONFIG: |
|
675 if (s->kind == USB_MOUSE) { |
|
676 memcpy(data, qemu_mouse_config_descriptor, |
|
677 sizeof(qemu_mouse_config_descriptor)); |
|
678 ret = sizeof(qemu_mouse_config_descriptor); |
|
679 } else if (s->kind == USB_TABLET) { |
|
680 memcpy(data, qemu_tablet_config_descriptor, |
|
681 sizeof(qemu_tablet_config_descriptor)); |
|
682 ret = sizeof(qemu_tablet_config_descriptor); |
|
683 } else if (s->kind == USB_KEYBOARD) { |
|
684 memcpy(data, qemu_keyboard_config_descriptor, |
|
685 sizeof(qemu_keyboard_config_descriptor)); |
|
686 ret = sizeof(qemu_keyboard_config_descriptor); |
|
687 } |
|
688 break; |
|
689 case USB_DT_STRING: |
|
690 switch(value & 0xff) { |
|
691 case 0: |
|
692 /* language ids */ |
|
693 data[0] = 4; |
|
694 data[1] = 3; |
|
695 data[2] = 0x09; |
|
696 data[3] = 0x04; |
|
697 ret = 4; |
|
698 break; |
|
699 case 1: |
|
700 /* serial number */ |
|
701 ret = set_usb_string(data, "1"); |
|
702 break; |
|
703 case 2: |
|
704 /* product description */ |
|
705 ret = set_usb_string(data, s->dev.devname); |
|
706 break; |
|
707 case 3: |
|
708 /* vendor description */ |
|
709 ret = set_usb_string(data, "QEMU " QEMU_VERSION); |
|
710 break; |
|
711 case 4: |
|
712 ret = set_usb_string(data, "HID Mouse"); |
|
713 break; |
|
714 case 5: |
|
715 ret = set_usb_string(data, "HID Tablet"); |
|
716 break; |
|
717 case 6: |
|
718 ret = set_usb_string(data, "HID Keyboard"); |
|
719 break; |
|
720 case 7: |
|
721 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); |
|
722 break; |
|
723 default: |
|
724 goto fail; |
|
725 } |
|
726 break; |
|
727 default: |
|
728 goto fail; |
|
729 } |
|
730 break; |
|
731 case DeviceRequest | USB_REQ_GET_CONFIGURATION: |
|
732 data[0] = 1; |
|
733 ret = 1; |
|
734 break; |
|
735 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: |
|
736 ret = 0; |
|
737 break; |
|
738 case DeviceRequest | USB_REQ_GET_INTERFACE: |
|
739 data[0] = 0; |
|
740 ret = 1; |
|
741 break; |
|
742 case DeviceOutRequest | USB_REQ_SET_INTERFACE: |
|
743 ret = 0; |
|
744 break; |
|
745 /* hid specific requests */ |
|
746 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: |
|
747 switch(value >> 8) { |
|
748 case 0x22: |
|
749 if (s->kind == USB_MOUSE) { |
|
750 memcpy(data, qemu_mouse_hid_report_descriptor, |
|
751 sizeof(qemu_mouse_hid_report_descriptor)); |
|
752 ret = sizeof(qemu_mouse_hid_report_descriptor); |
|
753 } else if (s->kind == USB_TABLET) { |
|
754 memcpy(data, qemu_tablet_hid_report_descriptor, |
|
755 sizeof(qemu_tablet_hid_report_descriptor)); |
|
756 ret = sizeof(qemu_tablet_hid_report_descriptor); |
|
757 } else if (s->kind == USB_KEYBOARD) { |
|
758 memcpy(data, qemu_keyboard_hid_report_descriptor, |
|
759 sizeof(qemu_keyboard_hid_report_descriptor)); |
|
760 ret = sizeof(qemu_keyboard_hid_report_descriptor); |
|
761 } |
|
762 break; |
|
763 default: |
|
764 goto fail; |
|
765 } |
|
766 break; |
|
767 case GET_REPORT: |
|
768 if (s->kind == USB_MOUSE) |
|
769 ret = usb_mouse_poll(s, data, length); |
|
770 else if (s->kind == USB_TABLET) |
|
771 ret = usb_tablet_poll(s, data, length); |
|
772 else if (s->kind == USB_KEYBOARD) |
|
773 ret = usb_keyboard_poll(&s->kbd, data, length); |
|
774 break; |
|
775 case SET_REPORT: |
|
776 if (s->kind == USB_KEYBOARD) |
|
777 ret = usb_keyboard_write(&s->kbd, data, length); |
|
778 else |
|
779 goto fail; |
|
780 break; |
|
781 case GET_PROTOCOL: |
|
782 if (s->kind != USB_KEYBOARD) |
|
783 goto fail; |
|
784 ret = 1; |
|
785 data[0] = s->protocol; |
|
786 break; |
|
787 case SET_PROTOCOL: |
|
788 if (s->kind != USB_KEYBOARD) |
|
789 goto fail; |
|
790 ret = 0; |
|
791 s->protocol = value; |
|
792 break; |
|
793 case GET_IDLE: |
|
794 ret = 1; |
|
795 data[0] = s->idle; |
|
796 break; |
|
797 case SET_IDLE: |
|
798 s->idle = value; |
|
799 ret = 0; |
|
800 break; |
|
801 default: |
|
802 fail: |
|
803 ret = USB_RET_STALL; |
|
804 break; |
|
805 } |
|
806 return ret; |
|
807 } |
|
808 |
|
809 static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) |
|
810 { |
|
811 USBHIDState *s = (USBHIDState *)dev; |
|
812 int ret = 0; |
|
813 |
|
814 switch(p->pid) { |
|
815 case USB_TOKEN_IN: |
|
816 if (p->devep == 1) { |
|
817 /* TODO: Implement finite idle delays. */ |
|
818 if (!(s->changed || s->idle)) |
|
819 return USB_RET_NAK; |
|
820 s->changed = 0; |
|
821 if (s->kind == USB_MOUSE) |
|
822 ret = usb_mouse_poll(s, p->data, p->len); |
|
823 else if (s->kind == USB_TABLET) |
|
824 ret = usb_tablet_poll(s, p->data, p->len); |
|
825 else if (s->kind == USB_KEYBOARD) |
|
826 ret = usb_keyboard_poll(&s->kbd, p->data, p->len); |
|
827 } else { |
|
828 goto fail; |
|
829 } |
|
830 break; |
|
831 case USB_TOKEN_OUT: |
|
832 default: |
|
833 fail: |
|
834 ret = USB_RET_STALL; |
|
835 break; |
|
836 } |
|
837 return ret; |
|
838 } |
|
839 |
|
840 static void usb_hid_handle_destroy(USBDevice *dev) |
|
841 { |
|
842 USBHIDState *s = (USBHIDState *)dev; |
|
843 |
|
844 if (s->kind != USB_KEYBOARD) |
|
845 qemu_remove_mouse_event_handler(s->ptr.eh_entry); |
|
846 /* TODO: else */ |
|
847 qemu_free(s); |
|
848 } |
|
849 |
|
850 USBDevice *usb_tablet_init(void) |
|
851 { |
|
852 USBHIDState *s; |
|
853 |
|
854 s = qemu_mallocz(sizeof(USBHIDState)); |
|
855 if (!s) |
|
856 return NULL; |
|
857 s->dev.speed = USB_SPEED_FULL; |
|
858 s->dev.handle_packet = usb_generic_handle_packet; |
|
859 |
|
860 s->dev.handle_reset = usb_mouse_handle_reset; |
|
861 s->dev.handle_control = usb_hid_handle_control; |
|
862 s->dev.handle_data = usb_hid_handle_data; |
|
863 s->dev.handle_destroy = usb_hid_handle_destroy; |
|
864 s->kind = USB_TABLET; |
|
865 /* Force poll routine to be run and grab input the first time. */ |
|
866 s->changed = 1; |
|
867 |
|
868 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); |
|
869 |
|
870 return (USBDevice *)s; |
|
871 } |
|
872 |
|
873 USBDevice *usb_mouse_init(void) |
|
874 { |
|
875 USBHIDState *s; |
|
876 |
|
877 s = qemu_mallocz(sizeof(USBHIDState)); |
|
878 if (!s) |
|
879 return NULL; |
|
880 s->dev.speed = USB_SPEED_FULL; |
|
881 s->dev.handle_packet = usb_generic_handle_packet; |
|
882 |
|
883 s->dev.handle_reset = usb_mouse_handle_reset; |
|
884 s->dev.handle_control = usb_hid_handle_control; |
|
885 s->dev.handle_data = usb_hid_handle_data; |
|
886 s->dev.handle_destroy = usb_hid_handle_destroy; |
|
887 s->kind = USB_MOUSE; |
|
888 /* Force poll routine to be run and grab input the first time. */ |
|
889 s->changed = 1; |
|
890 |
|
891 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); |
|
892 |
|
893 return (USBDevice *)s; |
|
894 } |
|
895 |
|
896 USBDevice *usb_keyboard_init(void) |
|
897 { |
|
898 USBHIDState *s; |
|
899 |
|
900 s = qemu_mallocz(sizeof(USBHIDState)); |
|
901 if (!s) |
|
902 return NULL; |
|
903 s->dev.speed = USB_SPEED_FULL; |
|
904 s->dev.handle_packet = usb_generic_handle_packet; |
|
905 |
|
906 s->dev.handle_reset = usb_keyboard_handle_reset; |
|
907 s->dev.handle_control = usb_hid_handle_control; |
|
908 s->dev.handle_data = usb_hid_handle_data; |
|
909 s->dev.handle_destroy = usb_hid_handle_destroy; |
|
910 s->kind = USB_KEYBOARD; |
|
911 |
|
912 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard"); |
|
913 |
|
914 return (USBDevice *) s; |
|
915 } |
|
916 |
|
917 void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *)) |
|
918 { |
|
919 USBHIDState *s = (USBHIDState *)dev; |
|
920 |
|
921 s->datain_opaque = opaque; |
|
922 s->datain = datain; |
|
923 } |