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
;
44 /* mostly the same values as the Bochs USB Mouse device */
45 static const uint8_t qemu_mouse_dev_descriptor
[] = {
46 0x12, /* u8 bLength; */
47 0x01, /* u8 bDescriptorType; Device */
48 0x10, 0x00, /* u16 bcdUSB; v1.0 */
50 0x00, /* u8 bDeviceClass; */
51 0x00, /* u8 bDeviceSubClass; */
52 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
53 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
55 0x27, 0x06, /* u16 idVendor; */
56 0x01, 0x00, /* u16 idProduct; */
57 0x00, 0x00, /* u16 bcdDevice */
59 0x03, /* u8 iManufacturer; */
60 0x02, /* u8 iProduct; */
61 0x01, /* u8 iSerialNumber; */
62 0x01 /* u8 bNumConfigurations; */
65 static const uint8_t qemu_mouse_config_descriptor
[] = {
66 /* one configuration */
67 0x09, /* u8 bLength; */
68 0x02, /* u8 bDescriptorType; Configuration */
69 0x22, 0x00, /* u16 wTotalLength; */
70 0x01, /* u8 bNumInterfaces; (1) */
71 0x01, /* u8 bConfigurationValue; */
72 0x04, /* u8 iConfiguration; */
73 0xa0, /* u8 bmAttributes;
78 50, /* u8 MaxPower; */
81 * USB 2.0, single TT organization (mandatory):
82 * one interface, protocol 0
84 * USB 2.0, multiple TT organization (optional):
85 * two interfaces, protocols 1 (like single TT)
86 * and 2 (multiple TT mode) ... config is
92 0x09, /* u8 if_bLength; */
93 0x04, /* u8 if_bDescriptorType; Interface */
94 0x00, /* u8 if_bInterfaceNumber; */
95 0x00, /* u8 if_bAlternateSetting; */
96 0x01, /* u8 if_bNumEndpoints; */
97 0x03, /* u8 if_bInterfaceClass; */
98 0x01, /* u8 if_bInterfaceSubClass; */
99 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
100 0x05, /* u8 if_iInterface; */
103 0x09, /* u8 bLength; */
104 0x21, /* u8 bDescriptorType; */
105 0x01, 0x00, /* u16 HID_class */
106 0x00, /* u8 country_code */
107 0x01, /* u8 num_descriptors */
108 0x22, /* u8 type; Report */
111 /* one endpoint (status change endpoint) */
112 0x07, /* u8 ep_bLength; */
113 0x05, /* u8 ep_bDescriptorType; Endpoint */
114 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
115 0x03, /* u8 ep_bmAttributes; Interrupt */
116 0x03, 0x00, /* u16 ep_wMaxPacketSize; */
117 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
120 static const uint8_t qemu_tablet_config_descriptor
[] = {
121 /* one configuration */
122 0x09, /* u8 bLength; */
123 0x02, /* u8 bDescriptorType; Configuration */
124 0x22, 0x00, /* u16 wTotalLength; */
125 0x01, /* u8 bNumInterfaces; (1) */
126 0x01, /* u8 bConfigurationValue; */
127 0x04, /* u8 iConfiguration; */
128 0xa0, /* u8 bmAttributes;
133 50, /* u8 MaxPower; */
136 * USB 2.0, single TT organization (mandatory):
137 * one interface, protocol 0
139 * USB 2.0, multiple TT organization (optional):
140 * two interfaces, protocols 1 (like single TT)
141 * and 2 (multiple TT mode) ... config is
147 0x09, /* u8 if_bLength; */
148 0x04, /* u8 if_bDescriptorType; Interface */
149 0x00, /* u8 if_bInterfaceNumber; */
150 0x00, /* u8 if_bAlternateSetting; */
151 0x01, /* u8 if_bNumEndpoints; */
152 0x03, /* u8 if_bInterfaceClass; */
153 0x01, /* u8 if_bInterfaceSubClass; */
154 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
155 0x05, /* u8 if_iInterface; */
158 0x09, /* u8 bLength; */
159 0x21, /* u8 bDescriptorType; */
160 0x01, 0x00, /* u16 HID_class */
161 0x00, /* u8 country_code */
162 0x01, /* u8 num_descriptors */
163 0x22, /* u8 type; Report */
166 /* one endpoint (status change endpoint) */
167 0x07, /* u8 ep_bLength; */
168 0x05, /* u8 ep_bDescriptorType; Endpoint */
169 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
170 0x03, /* u8 ep_bmAttributes; Interrupt */
171 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
172 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
175 static const uint8_t qemu_mouse_hid_report_descriptor
[] = {
176 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
177 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
178 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
179 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
180 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
181 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
185 static const uint8_t qemu_tablet_hid_report_descriptor
[] = {
186 0x05, 0x01, /* Usage Page Generic Desktop */
187 0x09, 0x01, /* Usage Mouse */
188 0xA1, 0x01, /* Collection Application */
189 0x09, 0x01, /* Usage Pointer */
190 0xA1, 0x00, /* Collection Physical */
191 0x05, 0x09, /* Usage Page Button */
192 0x19, 0x01, /* Usage Minimum Button 1 */
193 0x29, 0x03, /* Usage Maximum Button 3 */
194 0x15, 0x00, /* Logical Minimum 0 */
195 0x25, 0x01, /* Logical Maximum 1 */
196 0x95, 0x03, /* Report Count 3 */
197 0x75, 0x01, /* Report Size 1 */
198 0x81, 0x02, /* Input (Data, Var, Abs) */
199 0x95, 0x01, /* Report Count 1 */
200 0x75, 0x05, /* Report Size 5 */
201 0x81, 0x01, /* Input (Cnst, Var, Abs) */
202 0x05, 0x01, /* Usage Page Generic Desktop */
203 0x09, 0x30, /* Usage X */
204 0x09, 0x31, /* Usage Y */
205 0x15, 0x00, /* Logical Minimum 0 */
206 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */
207 0x35, 0x00, /* Physical Minimum 0 */
208 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */
209 0x75, 0x10, /* Report Size 16 */
210 0x95, 0x02, /* Report Count 2 */
211 0x81, 0x02, /* Input (Data, Var, Abs) */
212 0x05, 0x01, /* Usage Page Generic Desktop */
213 0x09, 0x38, /* Usage Wheel */
214 0x15, 0x81, /* Logical Minimum -127 */
215 0x25, 0x7F, /* Logical Maximum 127 */
216 0x35, 0x00, /* Physical Minimum 0 (same as logical) */
217 0x45, 0x00, /* Physical Maximum 0 (same as logical) */
218 0x75, 0x08, /* Report Size 8 */
219 0x95, 0x01, /* Report Count 1 */
220 0x81, 0x02, /* Input (Data, Var, Rel) */
221 0xC0, /* End Collection */
222 0xC0, /* End Collection */
225 static void usb_mouse_event(void *opaque
,
226 int dx1
, int dy1
, int dz1
, int buttons_state
)
228 USBMouseState
*s
= opaque
;
233 s
->buttons_state
= buttons_state
;
236 static void usb_tablet_event(void *opaque
,
237 int x
, int y
, int dz
, int buttons_state
)
239 USBMouseState
*s
= opaque
;
244 s
->buttons_state
= buttons_state
;
247 static inline int int_clamp(int val
, int vmin
, int vmax
)
257 static int usb_mouse_poll(USBMouseState
*s
, uint8_t *buf
, int len
)
259 int dx
, dy
, dz
, b
, l
;
261 if (!s
->mouse_grabbed
) {
262 qemu_add_mouse_event_handler(usb_mouse_event
, s
, 0);
263 s
->mouse_grabbed
= 1;
266 dx
= int_clamp(s
->dx
, -128, 127);
267 dy
= int_clamp(s
->dy
, -128, 127);
268 dz
= int_clamp(s
->dz
, -128, 127);
275 if (s
->buttons_state
& MOUSE_EVENT_LBUTTON
)
277 if (s
->buttons_state
& MOUSE_EVENT_RBUTTON
)
279 if (s
->buttons_state
& MOUSE_EVENT_MBUTTON
)
293 static int usb_tablet_poll(USBMouseState
*s
, uint8_t *buf
, int len
)
297 if (!s
->mouse_grabbed
) {
298 qemu_add_mouse_event_handler(usb_tablet_event
, s
, 1);
299 s
->mouse_grabbed
= 1;
302 dz
= int_clamp(s
->dz
, -128, 127);
305 /* Appears we have to invert the wheel direction */
308 if (s
->buttons_state
& MOUSE_EVENT_LBUTTON
)
310 if (s
->buttons_state
& MOUSE_EVENT_RBUTTON
)
312 if (s
->buttons_state
& MOUSE_EVENT_MBUTTON
)
316 buf
[1] = s
->x
& 0xff;
318 buf
[3] = s
->y
& 0xff;
326 static void usb_mouse_handle_reset(USBDevice
*dev
)
328 USBMouseState
*s
= (USBMouseState
*)dev
;
335 s
->buttons_state
= 0;
338 static int usb_mouse_handle_control(USBDevice
*dev
, int request
, int value
,
339 int index
, int length
, uint8_t *data
)
341 USBMouseState
*s
= (USBMouseState
*)dev
;
345 case DeviceRequest
| USB_REQ_GET_STATUS
:
346 data
[0] = (1 << USB_DEVICE_SELF_POWERED
) |
347 (dev
->remote_wakeup
<< USB_DEVICE_REMOTE_WAKEUP
);
351 case DeviceOutRequest
| USB_REQ_CLEAR_FEATURE
:
352 if (value
== USB_DEVICE_REMOTE_WAKEUP
) {
353 dev
->remote_wakeup
= 0;
359 case DeviceOutRequest
| USB_REQ_SET_FEATURE
:
360 if (value
== USB_DEVICE_REMOTE_WAKEUP
) {
361 dev
->remote_wakeup
= 1;
367 case DeviceOutRequest
| USB_REQ_SET_ADDRESS
:
371 case DeviceRequest
| USB_REQ_GET_DESCRIPTOR
:
374 memcpy(data
, qemu_mouse_dev_descriptor
,
375 sizeof(qemu_mouse_dev_descriptor
));
376 ret
= sizeof(qemu_mouse_dev_descriptor
);
379 if (s
->kind
== USB_MOUSE
) {
380 memcpy(data
, qemu_mouse_config_descriptor
,
381 sizeof(qemu_mouse_config_descriptor
));
382 ret
= sizeof(qemu_mouse_config_descriptor
);
383 } else if (s
->kind
== USB_TABLET
) {
384 memcpy(data
, qemu_tablet_config_descriptor
,
385 sizeof(qemu_tablet_config_descriptor
));
386 ret
= sizeof(qemu_tablet_config_descriptor
);
390 switch(value
& 0xff) {
401 ret
= set_usb_string(data
, "1");
404 /* product description */
405 if (s
->kind
== USB_MOUSE
)
406 ret
= set_usb_string(data
, "QEMU USB Mouse");
407 else if (s
->kind
== USB_TABLET
)
408 ret
= set_usb_string(data
, "QEMU USB Tablet");
411 /* vendor description */
412 ret
= set_usb_string(data
, "QEMU " QEMU_VERSION
);
415 ret
= set_usb_string(data
, "HID Mouse");
418 ret
= set_usb_string(data
, "Endpoint1 Interrupt Pipe");
428 case DeviceRequest
| USB_REQ_GET_CONFIGURATION
:
432 case DeviceOutRequest
| USB_REQ_SET_CONFIGURATION
:
435 case DeviceRequest
| USB_REQ_GET_INTERFACE
:
439 case DeviceOutRequest
| USB_REQ_SET_INTERFACE
:
442 /* hid specific requests */
443 case InterfaceRequest
| USB_REQ_GET_DESCRIPTOR
:
446 if (s
->kind
== USB_MOUSE
) {
447 memcpy(data
, qemu_mouse_hid_report_descriptor
,
448 sizeof(qemu_mouse_hid_report_descriptor
));
449 ret
= sizeof(qemu_mouse_hid_report_descriptor
);
450 } else if (s
->kind
== USB_TABLET
) {
451 memcpy(data
, qemu_tablet_hid_report_descriptor
,
452 sizeof(qemu_tablet_hid_report_descriptor
));
453 ret
= sizeof(qemu_tablet_hid_report_descriptor
);
461 if (s
->kind
== USB_MOUSE
)
462 ret
= usb_mouse_poll(s
, data
, length
);
463 else if (s
->kind
== USB_TABLET
)
464 ret
= usb_tablet_poll(s
, data
, length
);
477 static int usb_mouse_handle_data(USBDevice
*dev
, USBPacket
*p
)
479 USBMouseState
*s
= (USBMouseState
*)dev
;
485 if (s
->kind
== USB_MOUSE
)
486 ret
= usb_mouse_poll(s
, p
->data
, p
->len
);
487 else if (s
->kind
== USB_TABLET
)
488 ret
= usb_tablet_poll(s
, p
->data
, p
->len
);
502 static void usb_mouse_handle_destroy(USBDevice
*dev
)
504 USBMouseState
*s
= (USBMouseState
*)dev
;
506 qemu_add_mouse_event_handler(NULL
, NULL
, 0);
510 USBDevice
*usb_tablet_init(void)
514 s
= qemu_mallocz(sizeof(USBMouseState
));
517 s
->dev
.speed
= USB_SPEED_FULL
;
518 s
->dev
.handle_packet
= usb_generic_handle_packet
;
520 s
->dev
.handle_reset
= usb_mouse_handle_reset
;
521 s
->dev
.handle_control
= usb_mouse_handle_control
;
522 s
->dev
.handle_data
= usb_mouse_handle_data
;
523 s
->dev
.handle_destroy
= usb_mouse_handle_destroy
;
524 s
->kind
= USB_TABLET
;
526 pstrcpy(s
->dev
.devname
, sizeof(s
->dev
.devname
), "QEMU USB Tablet");
528 return (USBDevice
*)s
;
531 USBDevice
*usb_mouse_init(void)
535 s
= qemu_mallocz(sizeof(USBMouseState
));
538 s
->dev
.speed
= USB_SPEED_FULL
;
539 s
->dev
.handle_packet
= usb_generic_handle_packet
;
541 s
->dev
.handle_reset
= usb_mouse_handle_reset
;
542 s
->dev
.handle_control
= usb_mouse_handle_control
;
543 s
->dev
.handle_data
= usb_mouse_handle_data
;
544 s
->dev
.handle_destroy
= usb_mouse_handle_destroy
;
547 pstrcpy(s
->dev
.devname
, sizeof(s
->dev
.devname
), "QEMU USB Mouse");
549 return (USBDevice
*)s
;