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, int destroy)
328 USBMouseState *s = (USBMouseState *)dev;
331 qemu_add_mouse_event_handler(NULL, NULL, 0);
341 s->buttons_state = 0;
344 static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
345 int index, int length, uint8_t *data)
347 USBMouseState *s = (USBMouseState *)dev;
351 case DeviceRequest | USB_REQ_GET_STATUS:
352 data[0] = (1 << USB_DEVICE_SELF_POWERED) |
353 (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
357 case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
358 if (value == USB_DEVICE_REMOTE_WAKEUP) {
359 dev->remote_wakeup = 0;
365 case DeviceOutRequest | USB_REQ_SET_FEATURE:
366 if (value == USB_DEVICE_REMOTE_WAKEUP) {
367 dev->remote_wakeup = 1;
373 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
377 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
380 memcpy(data, qemu_mouse_dev_descriptor,
381 sizeof(qemu_mouse_dev_descriptor));
382 ret = sizeof(qemu_mouse_dev_descriptor);
385 if (s->kind == USB_MOUSE) {
386 memcpy(data, qemu_mouse_config_descriptor,
387 sizeof(qemu_mouse_config_descriptor));
388 ret = sizeof(qemu_mouse_config_descriptor);
389 } else if (s->kind == USB_TABLET) {
390 memcpy(data, qemu_tablet_config_descriptor,
391 sizeof(qemu_tablet_config_descriptor));
392 ret = sizeof(qemu_tablet_config_descriptor);
396 switch(value & 0xff) {
407 ret = set_usb_string(data, "1");
410 /* product description */
411 if (s->kind == USB_MOUSE)
412 ret = set_usb_string(data, "QEMU USB Mouse");
413 else if (s->kind == USB_TABLET)
414 ret = set_usb_string(data, "QEMU USB Tablet");
417 /* vendor description */
418 ret = set_usb_string(data, "QEMU " QEMU_VERSION);
421 ret = set_usb_string(data, "HID Mouse");
424 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
434 case DeviceRequest | USB_REQ_GET_CONFIGURATION:
438 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
441 case DeviceRequest | USB_REQ_GET_INTERFACE:
445 case DeviceOutRequest | USB_REQ_SET_INTERFACE:
448 /* hid specific requests */
449 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
452 if (s->kind == USB_MOUSE) {
453 memcpy(data, qemu_mouse_hid_report_descriptor,
454 sizeof(qemu_mouse_hid_report_descriptor));
455 ret = sizeof(qemu_mouse_hid_report_descriptor);
456 } else if (s->kind == USB_TABLET) {
457 memcpy(data, qemu_tablet_hid_report_descriptor,
458 sizeof(qemu_tablet_hid_report_descriptor));
459 ret = sizeof(qemu_tablet_hid_report_descriptor);
467 if (s->kind == USB_MOUSE)
468 ret = usb_mouse_poll(s, data, length);
469 else if (s->kind == USB_TABLET)
470 ret = usb_tablet_poll(s, data, length);
483 static int usb_mouse_handle_data(USBDevice *dev, int pid,
484 uint8_t devep, uint8_t *data, int len)
486 USBMouseState *s = (USBMouseState *)dev;
492 if (s->kind == USB_MOUSE)
493 ret = usb_mouse_poll(s, data, len);
494 else if (s->kind == USB_TABLET)
495 ret = usb_tablet_poll(s, data, len);
509 USBDevice *usb_tablet_init(void)
513 s = qemu_mallocz(sizeof(USBMouseState));
516 s->dev.speed = USB_SPEED_FULL;
517 s->dev.handle_packet = usb_generic_handle_packet;
519 s->dev.handle_reset = usb_mouse_handle_reset;
520 s->dev.handle_control = usb_mouse_handle_control;
521 s->dev.handle_data = usb_mouse_handle_data;
522 s->kind = USB_TABLET;
524 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
526 return (USBDevice *)s;
529 USBDevice *usb_mouse_init(void)
533 s = qemu_mallocz(sizeof(USBMouseState));
536 s->dev.speed = USB_SPEED_FULL;
537 s->dev.handle_packet = usb_generic_handle_packet;
539 s->dev.handle_reset = usb_mouse_handle_reset;
540 s->dev.handle_control = usb_mouse_handle_control;
541 s->dev.handle_data = usb_mouse_handle_data;
544 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
546 return (USBDevice *)s;