4 * Copyright (c) 2005 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 /* HID interface requests */
27 #define GET_REPORT 0xa101
28 #define GET_IDLE 0xa102
29 #define GET_PROTOCOL 0xa103
30 #define SET_IDLE 0x210a
31 #define SET_PROTOCOL 0x210b
36 typedef struct USBMouseState
{
38 int dx
, dy
, dz
, buttons_state
;
42 QEMUPutMouseEntry
*eh_entry
;
45 /* mostly the same values as the Bochs USB Mouse device */
46 static const uint8_t qemu_mouse_dev_descriptor
[] = {
47 0x12, /* u8 bLength; */
48 0x01, /* u8 bDescriptorType; Device */
49 0x00, 0x01, /* u16 bcdUSB; v1.0 */
51 0x00, /* u8 bDeviceClass; */
52 0x00, /* u8 bDeviceSubClass; */
53 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
54 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
56 0x27, 0x06, /* u16 idVendor; */
57 0x01, 0x00, /* u16 idProduct; */
58 0x00, 0x00, /* u16 bcdDevice */
60 0x03, /* u8 iManufacturer; */
61 0x02, /* u8 iProduct; */
62 0x01, /* u8 iSerialNumber; */
63 0x01 /* u8 bNumConfigurations; */
66 static const uint8_t qemu_mouse_config_descriptor
[] = {
67 /* one configuration */
68 0x09, /* u8 bLength; */
69 0x02, /* u8 bDescriptorType; Configuration */
70 0x22, 0x00, /* u16 wTotalLength; */
71 0x01, /* u8 bNumInterfaces; (1) */
72 0x01, /* u8 bConfigurationValue; */
73 0x04, /* u8 iConfiguration; */
74 0xa0, /* u8 bmAttributes;
79 50, /* u8 MaxPower; */
82 * USB 2.0, single TT organization (mandatory):
83 * one interface, protocol 0
85 * USB 2.0, multiple TT organization (optional):
86 * two interfaces, protocols 1 (like single TT)
87 * and 2 (multiple TT mode) ... config is
93 0x09, /* u8 if_bLength; */
94 0x04, /* u8 if_bDescriptorType; Interface */
95 0x00, /* u8 if_bInterfaceNumber; */
96 0x00, /* u8 if_bAlternateSetting; */
97 0x01, /* u8 if_bNumEndpoints; */
98 0x03, /* u8 if_bInterfaceClass; */
99 0x01, /* u8 if_bInterfaceSubClass; */
100 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
101 0x05, /* u8 if_iInterface; */
104 0x09, /* u8 bLength; */
105 0x21, /* u8 bDescriptorType; */
106 0x01, 0x00, /* u16 HID_class */
107 0x00, /* u8 country_code */
108 0x01, /* u8 num_descriptors */
109 0x22, /* u8 type; Report */
112 /* one endpoint (status change endpoint) */
113 0x07, /* u8 ep_bLength; */
114 0x05, /* u8 ep_bDescriptorType; Endpoint */
115 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
116 0x03, /* u8 ep_bmAttributes; Interrupt */
117 0x03, 0x00, /* u16 ep_wMaxPacketSize; */
118 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
121 static const uint8_t qemu_tablet_config_descriptor
[] = {
122 /* one configuration */
123 0x09, /* u8 bLength; */
124 0x02, /* u8 bDescriptorType; Configuration */
125 0x22, 0x00, /* u16 wTotalLength; */
126 0x01, /* u8 bNumInterfaces; (1) */
127 0x01, /* u8 bConfigurationValue; */
128 0x04, /* u8 iConfiguration; */
129 0xa0, /* u8 bmAttributes;
134 50, /* u8 MaxPower; */
137 * USB 2.0, single TT organization (mandatory):
138 * one interface, protocol 0
140 * USB 2.0, multiple TT organization (optional):
141 * two interfaces, protocols 1 (like single TT)
142 * and 2 (multiple TT mode) ... config is
148 0x09, /* u8 if_bLength; */
149 0x04, /* u8 if_bDescriptorType; Interface */
150 0x00, /* u8 if_bInterfaceNumber; */
151 0x00, /* u8 if_bAlternateSetting; */
152 0x01, /* u8 if_bNumEndpoints; */
153 0x03, /* u8 if_bInterfaceClass; */
154 0x01, /* u8 if_bInterfaceSubClass; */
155 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
156 0x05, /* u8 if_iInterface; */
159 0x09, /* u8 bLength; */
160 0x21, /* u8 bDescriptorType; */
161 0x01, 0x00, /* u16 HID_class */
162 0x00, /* u8 country_code */
163 0x01, /* u8 num_descriptors */
164 0x22, /* u8 type; Report */
167 /* one endpoint (status change endpoint) */
168 0x07, /* u8 ep_bLength; */
169 0x05, /* u8 ep_bDescriptorType; Endpoint */
170 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
171 0x03, /* u8 ep_bmAttributes; Interrupt */
172 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
173 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
176 static const uint8_t qemu_mouse_hid_report_descriptor
[] = {
177 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
178 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
179 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
180 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
181 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
182 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
186 static const uint8_t qemu_tablet_hid_report_descriptor
[] = {
187 0x05, 0x01, /* Usage Page Generic Desktop */
188 0x09, 0x01, /* Usage Mouse */
189 0xA1, 0x01, /* Collection Application */
190 0x09, 0x01, /* Usage Pointer */
191 0xA1, 0x00, /* Collection Physical */
192 0x05, 0x09, /* Usage Page Button */
193 0x19, 0x01, /* Usage Minimum Button 1 */
194 0x29, 0x03, /* Usage Maximum Button 3 */
195 0x15, 0x00, /* Logical Minimum 0 */
196 0x25, 0x01, /* Logical Maximum 1 */
197 0x95, 0x03, /* Report Count 3 */
198 0x75, 0x01, /* Report Size 1 */
199 0x81, 0x02, /* Input (Data, Var, Abs) */
200 0x95, 0x01, /* Report Count 1 */
201 0x75, 0x05, /* Report Size 5 */
202 0x81, 0x01, /* Input (Cnst, Var, Abs) */
203 0x05, 0x01, /* Usage Page Generic Desktop */
204 0x09, 0x30, /* Usage X */
205 0x09, 0x31, /* Usage Y */
206 0x15, 0x00, /* Logical Minimum 0 */
207 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */
208 0x35, 0x00, /* Physical Minimum 0 */
209 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */
210 0x75, 0x10, /* Report Size 16 */
211 0x95, 0x02, /* Report Count 2 */
212 0x81, 0x02, /* Input (Data, Var, Abs) */
213 0x05, 0x01, /* Usage Page Generic Desktop */
214 0x09, 0x38, /* Usage Wheel */
215 0x15, 0x81, /* Logical Minimum -127 */
216 0x25, 0x7F, /* Logical Maximum 127 */
217 0x35, 0x00, /* Physical Minimum 0 (same as logical) */
218 0x45, 0x00, /* Physical Maximum 0 (same as logical) */
219 0x75, 0x08, /* Report Size 8 */
220 0x95, 0x01, /* Report Count 1 */
221 0x81, 0x02, /* Input (Data, Var, Rel) */
222 0xC0, /* End Collection */
223 0xC0, /* End Collection */
226 static void usb_mouse_event(void *opaque
,
227 int dx1
, int dy1
, int dz1
, int buttons_state
)
229 USBMouseState
*s
= opaque
;
234 s
->buttons_state
= buttons_state
;
237 static void usb_tablet_event(void *opaque
,
238 int x
, int y
, int dz
, int buttons_state
)
240 USBMouseState
*s
= opaque
;
245 s
->buttons_state
= buttons_state
;
248 static inline int int_clamp(int val
, int vmin
, int vmax
)
258 static int usb_mouse_poll(USBMouseState
*s
, uint8_t *buf
, int len
)
260 int dx
, dy
, dz
, b
, l
;
262 if (!s
->mouse_grabbed
) {
263 s
->eh_entry
= qemu_add_mouse_event_handler(usb_mouse_event
, s
,
264 0, "QEMU USB Mouse");
265 s
->mouse_grabbed
= 1;
268 dx
= int_clamp(s
->dx
, -128, 127);
269 dy
= int_clamp(s
->dy
, -128, 127);
270 dz
= int_clamp(s
->dz
, -128, 127);
277 if (s
->buttons_state
& MOUSE_EVENT_LBUTTON
)
279 if (s
->buttons_state
& MOUSE_EVENT_RBUTTON
)
281 if (s
->buttons_state
& MOUSE_EVENT_MBUTTON
)
295 static int usb_tablet_poll(USBMouseState
*s
, uint8_t *buf
, int len
)
299 if (!s
->mouse_grabbed
) {
300 s
->eh_entry
= qemu_add_mouse_event_handler(usb_tablet_event
, s
,
301 1, "QEMU USB Tablet");
302 s
->mouse_grabbed
= 1;
305 dz
= int_clamp(s
->dz
, -128, 127);
308 /* Appears we have to invert the wheel direction */
311 if (s
->buttons_state
& MOUSE_EVENT_LBUTTON
)
313 if (s
->buttons_state
& MOUSE_EVENT_RBUTTON
)
315 if (s
->buttons_state
& MOUSE_EVENT_MBUTTON
)
319 buf
[1] = s
->x
& 0xff;
321 buf
[3] = s
->y
& 0xff;
329 static void usb_mouse_handle_reset(USBDevice
*dev
)
331 USBMouseState
*s
= (USBMouseState
*)dev
;
338 s
->buttons_state
= 0;
341 static int usb_mouse_handle_control(USBDevice
*dev
, int request
, int value
,
342 int index
, int length
, uint8_t *data
)
344 USBMouseState
*s
= (USBMouseState
*)dev
;
348 case DeviceRequest
| USB_REQ_GET_STATUS
:
349 data
[0] = (1 << USB_DEVICE_SELF_POWERED
) |
350 (dev
->remote_wakeup
<< USB_DEVICE_REMOTE_WAKEUP
);
354 case DeviceOutRequest
| USB_REQ_CLEAR_FEATURE
:
355 if (value
== USB_DEVICE_REMOTE_WAKEUP
) {
356 dev
->remote_wakeup
= 0;
362 case DeviceOutRequest
| USB_REQ_SET_FEATURE
:
363 if (value
== USB_DEVICE_REMOTE_WAKEUP
) {
364 dev
->remote_wakeup
= 1;
370 case DeviceOutRequest
| USB_REQ_SET_ADDRESS
:
374 case DeviceRequest
| USB_REQ_GET_DESCRIPTOR
:
377 memcpy(data
, qemu_mouse_dev_descriptor
,
378 sizeof(qemu_mouse_dev_descriptor
));
379 ret
= sizeof(qemu_mouse_dev_descriptor
);
382 if (s
->kind
== USB_MOUSE
) {
383 memcpy(data
, qemu_mouse_config_descriptor
,
384 sizeof(qemu_mouse_config_descriptor
));
385 ret
= sizeof(qemu_mouse_config_descriptor
);
386 } else if (s
->kind
== USB_TABLET
) {
387 memcpy(data
, qemu_tablet_config_descriptor
,
388 sizeof(qemu_tablet_config_descriptor
));
389 ret
= sizeof(qemu_tablet_config_descriptor
);
393 switch(value
& 0xff) {
404 ret
= set_usb_string(data
, "1");
407 /* product description */
408 if (s
->kind
== USB_MOUSE
)
409 ret
= set_usb_string(data
, "QEMU USB Mouse");
410 else if (s
->kind
== USB_TABLET
)
411 ret
= set_usb_string(data
, "QEMU USB Tablet");
414 /* vendor description */
415 ret
= set_usb_string(data
, "QEMU " QEMU_VERSION
);
418 ret
= set_usb_string(data
, "HID Mouse");
421 ret
= set_usb_string(data
, "Endpoint1 Interrupt Pipe");
431 case DeviceRequest
| USB_REQ_GET_CONFIGURATION
:
435 case DeviceOutRequest
| USB_REQ_SET_CONFIGURATION
:
438 case DeviceRequest
| USB_REQ_GET_INTERFACE
:
442 case DeviceOutRequest
| USB_REQ_SET_INTERFACE
:
445 /* hid specific requests */
446 case InterfaceRequest
| USB_REQ_GET_DESCRIPTOR
:
449 if (s
->kind
== USB_MOUSE
) {
450 memcpy(data
, qemu_mouse_hid_report_descriptor
,
451 sizeof(qemu_mouse_hid_report_descriptor
));
452 ret
= sizeof(qemu_mouse_hid_report_descriptor
);
453 } else if (s
->kind
== USB_TABLET
) {
454 memcpy(data
, qemu_tablet_hid_report_descriptor
,
455 sizeof(qemu_tablet_hid_report_descriptor
));
456 ret
= sizeof(qemu_tablet_hid_report_descriptor
);
464 if (s
->kind
== USB_MOUSE
)
465 ret
= usb_mouse_poll(s
, data
, length
);
466 else if (s
->kind
== USB_TABLET
)
467 ret
= usb_tablet_poll(s
, data
, length
);
480 static int usb_mouse_handle_data(USBDevice
*dev
, USBPacket
*p
)
482 USBMouseState
*s
= (USBMouseState
*)dev
;
488 if (s
->kind
== USB_MOUSE
)
489 ret
= usb_mouse_poll(s
, p
->data
, p
->len
);
490 else if (s
->kind
== USB_TABLET
)
491 ret
= usb_tablet_poll(s
, p
->data
, p
->len
);
505 static void usb_mouse_handle_destroy(USBDevice
*dev
)
507 USBMouseState
*s
= (USBMouseState
*)dev
;
509 qemu_remove_mouse_event_handler(s
->eh_entry
);
513 USBDevice
*usb_tablet_init(void)
517 s
= qemu_mallocz(sizeof(USBMouseState
));
520 s
->dev
.speed
= USB_SPEED_FULL
;
521 s
->dev
.handle_packet
= usb_generic_handle_packet
;
523 s
->dev
.handle_reset
= usb_mouse_handle_reset
;
524 s
->dev
.handle_control
= usb_mouse_handle_control
;
525 s
->dev
.handle_data
= usb_mouse_handle_data
;
526 s
->dev
.handle_destroy
= usb_mouse_handle_destroy
;
527 s
->kind
= USB_TABLET
;
529 pstrcpy(s
->dev
.devname
, sizeof(s
->dev
.devname
), "QEMU USB Tablet");
531 return (USBDevice
*)s
;
534 USBDevice
*usb_mouse_init(void)
538 s
= qemu_mallocz(sizeof(USBMouseState
));
541 s
->dev
.speed
= USB_SPEED_FULL
;
542 s
->dev
.handle_packet
= usb_generic_handle_packet
;
544 s
->dev
.handle_reset
= usb_mouse_handle_reset
;
545 s
->dev
.handle_control
= usb_mouse_handle_control
;
546 s
->dev
.handle_data
= usb_mouse_handle_data
;
547 s
->dev
.handle_destroy
= usb_mouse_handle_destroy
;
550 pstrcpy(s
->dev
.devname
, sizeof(s
->dev
.devname
), "QEMU USB Mouse");
552 return (USBDevice
*)s
;