Commit 59ae540c3dbd1ab3fb004e85eaf3aa4f3520a308
1 parent
92414fdc
added virtual USB mouse support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1599 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
373 additions
and
8 deletions
Makefile.target
@@ -294,7 +294,8 @@ ifeq ($(TARGET_BASE_ARCH), i386) | @@ -294,7 +294,8 @@ ifeq ($(TARGET_BASE_ARCH), i386) | ||
294 | # Hardware support | 294 | # Hardware support |
295 | VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) | 295 | VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) |
296 | VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o | 296 | VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o |
297 | -VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o usb.o usb-uhci.o usb-linux.o | 297 | +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o |
298 | +VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o | ||
298 | DEFINES += -DHAS_AUDIO | 299 | DEFINES += -DHAS_AUDIO |
299 | endif | 300 | endif |
300 | ifeq ($(TARGET_BASE_ARCH), ppc) | 301 | ifeq ($(TARGET_BASE_ARCH), ppc) |
hw/pc.c
@@ -622,24 +622,31 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | @@ -622,24 +622,31 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | ||
622 | 622 | ||
623 | if (pci_enabled && usb_enabled) { | 623 | if (pci_enabled && usb_enabled) { |
624 | USBPort *usb_root_ports[2]; | 624 | USBPort *usb_root_ports[2]; |
625 | - USBDevice *usb_hub; | 625 | + USBDevice *usb_dev; |
626 | usb_uhci_init(pci_bus, usb_root_ports); | 626 | usb_uhci_init(pci_bus, usb_root_ports); |
627 | #if 0 | 627 | #if 0 |
628 | { | 628 | { |
629 | USBPort *usb_hub1_ports[4]; | 629 | USBPort *usb_hub1_ports[4]; |
630 | USBPort *usb_hub2_ports[2]; | 630 | USBPort *usb_hub2_ports[2]; |
631 | /* test: we simulate a USB hub */ | 631 | /* test: we simulate a USB hub */ |
632 | - usb_hub = usb_hub_init(usb_hub1_ports, 4); | ||
633 | - usb_attach(usb_root_ports[0], usb_hub); | 632 | + usb_dev = usb_hub_init(usb_hub1_ports, 4); |
633 | + usb_attach(usb_root_ports[0], usb_dev); | ||
634 | 634 | ||
635 | /* test: we simulate a USB hub */ | 635 | /* test: we simulate a USB hub */ |
636 | - usb_hub = usb_hub_init(usb_hub2_ports, 2); | ||
637 | - usb_attach(usb_hub1_ports[0], usb_hub); | 636 | + usb_dev = usb_hub_init(usb_hub2_ports, 2); |
637 | + usb_attach(usb_hub1_ports[0], usb_dev); | ||
638 | } | 638 | } |
639 | #endif | 639 | #endif |
640 | +#if 0 | ||
641 | + /* USB mouse */ | ||
642 | + usb_dev = usb_mouse_init(); | ||
643 | + usb_attach(usb_root_ports[0], usb_dev); | ||
644 | +#endif | ||
645 | +#if 1 | ||
640 | /* simulated hub with the host USB devices connected to it */ | 646 | /* simulated hub with the host USB devices connected to it */ |
641 | - usb_hub = usb_host_hub_init(); | ||
642 | - usb_attach(usb_root_ports[0], usb_hub); | 647 | + usb_dev = usb_host_hub_init(); |
648 | + usb_attach(usb_root_ports[0], usb_dev); | ||
649 | +#endif | ||
643 | } | 650 | } |
644 | 651 | ||
645 | /* must be done after all PCI devices are instanciated */ | 652 | /* must be done after all PCI devices are instanciated */ |
hw/usb-hid.c
0 → 100644
1 | +/* | ||
2 | + * QEMU USB HID devices | ||
3 | + * | ||
4 | + * Copyright (c) 2005 Fabrice Bellard | ||
5 | + * | ||
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: | ||
12 | + * | ||
13 | + * The above copyright notice and this permission notice shall be included in | ||
14 | + * all copies or substantial portions of the Software. | ||
15 | + * | ||
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 | ||
22 | + * THE SOFTWARE. | ||
23 | + */ | ||
24 | +#include "vl.h" | ||
25 | + | ||
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 | ||
32 | + | ||
33 | +typedef struct USBMouseState { | ||
34 | + USBDevice dev; | ||
35 | + int dx, dy, dz, buttons_state; | ||
36 | +} USBMouseState; | ||
37 | + | ||
38 | +/* mostly the same values as the Bochs USB Mouse device */ | ||
39 | +static const uint8_t qemu_mouse_dev_descriptor[] = { | ||
40 | + 0x12, /* u8 bLength; */ | ||
41 | + 0x01, /* u8 bDescriptorType; Device */ | ||
42 | + 0x10, 0x00, /* u16 bcdUSB; v1.0 */ | ||
43 | + | ||
44 | + 0x00, /* u8 bDeviceClass; */ | ||
45 | + 0x00, /* u8 bDeviceSubClass; */ | ||
46 | + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ | ||
47 | + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ | ||
48 | + | ||
49 | + 0x27, 0x06, /* u16 idVendor; */ | ||
50 | + 0x01, 0x00, /* u16 idProduct; */ | ||
51 | + 0x00, 0x00, /* u16 bcdDevice */ | ||
52 | + | ||
53 | + 0x03, /* u8 iManufacturer; */ | ||
54 | + 0x02, /* u8 iProduct; */ | ||
55 | + 0x01, /* u8 iSerialNumber; */ | ||
56 | + 0x01 /* u8 bNumConfigurations; */ | ||
57 | +}; | ||
58 | + | ||
59 | +static const uint8_t qemu_mouse_config_descriptor[] = { | ||
60 | + /* one configuration */ | ||
61 | + 0x09, /* u8 bLength; */ | ||
62 | + 0x02, /* u8 bDescriptorType; Configuration */ | ||
63 | + 0x22, 0x00, /* u16 wTotalLength; */ | ||
64 | + 0x01, /* u8 bNumInterfaces; (1) */ | ||
65 | + 0x01, /* u8 bConfigurationValue; */ | ||
66 | + 0x04, /* u8 iConfiguration; */ | ||
67 | + 0xa0, /* u8 bmAttributes; | ||
68 | + Bit 7: must be set, | ||
69 | + 6: Self-powered, | ||
70 | + 5: Remote wakeup, | ||
71 | + 4..0: resvd */ | ||
72 | + 50, /* u8 MaxPower; */ | ||
73 | + | ||
74 | + /* USB 1.1: | ||
75 | + * USB 2.0, single TT organization (mandatory): | ||
76 | + * one interface, protocol 0 | ||
77 | + * | ||
78 | + * USB 2.0, multiple TT organization (optional): | ||
79 | + * two interfaces, protocols 1 (like single TT) | ||
80 | + * and 2 (multiple TT mode) ... config is | ||
81 | + * sometimes settable | ||
82 | + * NOT IMPLEMENTED | ||
83 | + */ | ||
84 | + | ||
85 | + /* one interface */ | ||
86 | + 0x09, /* u8 if_bLength; */ | ||
87 | + 0x04, /* u8 if_bDescriptorType; Interface */ | ||
88 | + 0x00, /* u8 if_bInterfaceNumber; */ | ||
89 | + 0x00, /* u8 if_bAlternateSetting; */ | ||
90 | + 0x01, /* u8 if_bNumEndpoints; */ | ||
91 | + 0x03, /* u8 if_bInterfaceClass; */ | ||
92 | + 0x01, /* u8 if_bInterfaceSubClass; */ | ||
93 | + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ | ||
94 | + 0x05, /* u8 if_iInterface; */ | ||
95 | + | ||
96 | + /* one endpoint (status change endpoint) */ | ||
97 | + 0x07, /* u8 ep_bLength; */ | ||
98 | + 0x05, /* u8 ep_bDescriptorType; Endpoint */ | ||
99 | + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ | ||
100 | + 0x03, /* u8 ep_bmAttributes; Interrupt */ | ||
101 | + 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ | ||
102 | + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ | ||
103 | + | ||
104 | + /* HID descriptor */ | ||
105 | + 0x09, /* u8 bLength; */ | ||
106 | + 0x21, /* u8 bDescriptorType; */ | ||
107 | + 0x01, 0x00, /* u16 HID_class */ | ||
108 | + 0x00, /* u8 country_code */ | ||
109 | + 0x01, /* u8 num_descriptors */ | ||
110 | + 0x22, /* u8 type; Report */ | ||
111 | + 50, 0, /* u16 len */ | ||
112 | +}; | ||
113 | + | ||
114 | +static const uint8_t qemu_mouse_hid_report_descriptor[] = { | ||
115 | + 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, | ||
116 | + 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, | ||
117 | + 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, | ||
118 | + 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, | ||
119 | + 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, | ||
120 | + 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, | ||
121 | + 0xC0, 0xC0, | ||
122 | +}; | ||
123 | + | ||
124 | +static void usb_mouse_event(void *opaque, | ||
125 | + int dx1, int dy1, int dz1, int buttons_state) | ||
126 | +{ | ||
127 | + USBMouseState *s = opaque; | ||
128 | + | ||
129 | + s->dx += dx1; | ||
130 | + s->dy += dy1; | ||
131 | + s->dz += dz1; | ||
132 | + s->buttons_state = buttons_state; | ||
133 | +} | ||
134 | + | ||
135 | +static inline int int_clamp(int val, int vmin, int vmax) | ||
136 | +{ | ||
137 | + if (val < vmin) | ||
138 | + return vmin; | ||
139 | + else if (val > vmax) | ||
140 | + return vmax; | ||
141 | + else | ||
142 | + return val; | ||
143 | +} | ||
144 | + | ||
145 | +static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | ||
146 | +{ | ||
147 | + int dx, dy, dz, b, l; | ||
148 | + | ||
149 | + dx = int_clamp(s->dx, -128, 127); | ||
150 | + dy = int_clamp(s->dy, -128, 127); | ||
151 | + dz = int_clamp(s->dz, -128, 127); | ||
152 | + | ||
153 | + s->dx -= dx; | ||
154 | + s->dy -= dy; | ||
155 | + s->dz -= dz; | ||
156 | + | ||
157 | + b = 0; | ||
158 | + if (s->buttons_state & MOUSE_EVENT_LBUTTON) | ||
159 | + b |= 0x01; | ||
160 | + if (s->buttons_state & MOUSE_EVENT_RBUTTON) | ||
161 | + b |= 0x02; | ||
162 | + if (s->buttons_state & MOUSE_EVENT_MBUTTON) | ||
163 | + b |= 0x04; | ||
164 | + | ||
165 | + buf[0] = b; | ||
166 | + buf[1] = dx; | ||
167 | + buf[2] = dy; | ||
168 | + l = 3; | ||
169 | + if (len >= 4) { | ||
170 | + buf[3] = dz; | ||
171 | + l = 4; | ||
172 | + } | ||
173 | + return l; | ||
174 | +} | ||
175 | + | ||
176 | +static void usb_mouse_handle_reset(USBDevice *dev) | ||
177 | +{ | ||
178 | + USBMouseState *s = (USBMouseState *)dev; | ||
179 | + | ||
180 | + s->dx = 0; | ||
181 | + s->dy = 0; | ||
182 | + s->dz = 0; | ||
183 | + s->buttons_state = 0; | ||
184 | +} | ||
185 | + | ||
186 | +static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | ||
187 | + int index, int length, uint8_t *data) | ||
188 | +{ | ||
189 | + USBMouseState *s = (USBMouseState *)dev; | ||
190 | + int ret; | ||
191 | + | ||
192 | + switch(request) { | ||
193 | + case DeviceRequest | USB_REQ_GET_STATUS: | ||
194 | + data[0] = (1 << USB_DEVICE_SELF_POWERED) | | ||
195 | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); | ||
196 | + data[1] = 0x00; | ||
197 | + ret = 2; | ||
198 | + break; | ||
199 | + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: | ||
200 | + if (value == USB_DEVICE_REMOTE_WAKEUP) { | ||
201 | + dev->remote_wakeup = 0; | ||
202 | + } else { | ||
203 | + goto fail; | ||
204 | + } | ||
205 | + ret = 0; | ||
206 | + break; | ||
207 | + case DeviceOutRequest | USB_REQ_SET_FEATURE: | ||
208 | + if (value == USB_DEVICE_REMOTE_WAKEUP) { | ||
209 | + dev->remote_wakeup = 1; | ||
210 | + } else { | ||
211 | + goto fail; | ||
212 | + } | ||
213 | + ret = 0; | ||
214 | + break; | ||
215 | + case DeviceOutRequest | USB_REQ_SET_ADDRESS: | ||
216 | + dev->addr = value; | ||
217 | + ret = 0; | ||
218 | + break; | ||
219 | + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: | ||
220 | + switch(value >> 8) { | ||
221 | + case USB_DT_DEVICE: | ||
222 | + memcpy(data, qemu_mouse_dev_descriptor, | ||
223 | + sizeof(qemu_mouse_dev_descriptor)); | ||
224 | + ret = sizeof(qemu_mouse_dev_descriptor); | ||
225 | + break; | ||
226 | + case USB_DT_CONFIG: | ||
227 | + memcpy(data, qemu_mouse_config_descriptor, | ||
228 | + sizeof(qemu_mouse_config_descriptor)); | ||
229 | + ret = sizeof(qemu_mouse_config_descriptor); | ||
230 | + break; | ||
231 | + case USB_DT_STRING: | ||
232 | + switch(value & 0xff) { | ||
233 | + case 0: | ||
234 | + /* language ids */ | ||
235 | + data[0] = 4; | ||
236 | + data[1] = 3; | ||
237 | + data[2] = 0x09; | ||
238 | + data[3] = 0x04; | ||
239 | + ret = 4; | ||
240 | + break; | ||
241 | + case 1: | ||
242 | + /* serial number */ | ||
243 | + ret = set_usb_string(data, "1"); | ||
244 | + break; | ||
245 | + case 2: | ||
246 | + /* product description */ | ||
247 | + ret = set_usb_string(data, "QEMU USB Mouse"); | ||
248 | + break; | ||
249 | + case 3: | ||
250 | + /* vendor description */ | ||
251 | + ret = set_usb_string(data, "QEMU " QEMU_VERSION); | ||
252 | + break; | ||
253 | + case 4: | ||
254 | + ret = set_usb_string(data, "HID Mouse"); | ||
255 | + break; | ||
256 | + case 5: | ||
257 | + ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); | ||
258 | + break; | ||
259 | + default: | ||
260 | + goto fail; | ||
261 | + } | ||
262 | + break; | ||
263 | + default: | ||
264 | + goto fail; | ||
265 | + } | ||
266 | + break; | ||
267 | + case DeviceRequest | USB_REQ_GET_CONFIGURATION: | ||
268 | + data[0] = 1; | ||
269 | + ret = 1; | ||
270 | + break; | ||
271 | + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: | ||
272 | + ret = 0; | ||
273 | + break; | ||
274 | + case DeviceRequest | USB_REQ_GET_INTERFACE: | ||
275 | + data[0] = 0; | ||
276 | + ret = 1; | ||
277 | + break; | ||
278 | + case DeviceOutRequest | USB_REQ_SET_INTERFACE: | ||
279 | + ret = 0; | ||
280 | + break; | ||
281 | + /* hid specific requests */ | ||
282 | + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: | ||
283 | + switch(value >> 8) { | ||
284 | + case 0x22: | ||
285 | + memcpy(data, qemu_mouse_hid_report_descriptor, | ||
286 | + sizeof(qemu_mouse_hid_report_descriptor)); | ||
287 | + ret = sizeof(qemu_mouse_hid_report_descriptor); | ||
288 | + break; | ||
289 | + default: | ||
290 | + goto fail; | ||
291 | + } | ||
292 | + break; | ||
293 | + case GET_REPORT: | ||
294 | + ret = usb_mouse_poll(s, data, length); | ||
295 | + break; | ||
296 | + case SET_IDLE: | ||
297 | + ret = 0; | ||
298 | + break; | ||
299 | + default: | ||
300 | + fail: | ||
301 | + ret = USB_RET_STALL; | ||
302 | + break; | ||
303 | + } | ||
304 | + return ret; | ||
305 | +} | ||
306 | + | ||
307 | +static int usb_mouse_handle_data(USBDevice *dev, int pid, | ||
308 | + uint8_t devep, uint8_t *data, int len) | ||
309 | +{ | ||
310 | + USBMouseState *s = (USBMouseState *)dev; | ||
311 | + int ret; | ||
312 | + | ||
313 | + switch(pid) { | ||
314 | + case USB_TOKEN_IN: | ||
315 | + if (devep == 1) { | ||
316 | + ret = usb_mouse_poll(s, data, len); | ||
317 | + } else { | ||
318 | + goto fail; | ||
319 | + } | ||
320 | + break; | ||
321 | + case USB_TOKEN_OUT: | ||
322 | + default: | ||
323 | + fail: | ||
324 | + ret = USB_RET_STALL; | ||
325 | + break; | ||
326 | + } | ||
327 | + return ret; | ||
328 | +} | ||
329 | + | ||
330 | +USBDevice *usb_mouse_init(void) | ||
331 | +{ | ||
332 | + USBMouseState *s; | ||
333 | + | ||
334 | + s = qemu_mallocz(sizeof(USBMouseState)); | ||
335 | + if (!s) | ||
336 | + return NULL; | ||
337 | + s->dev.speed = USB_SPEED_FULL; | ||
338 | + s->dev.handle_packet = usb_generic_handle_packet; | ||
339 | + | ||
340 | + s->dev.handle_reset = usb_mouse_handle_reset; | ||
341 | + s->dev.handle_control = usb_mouse_handle_control; | ||
342 | + s->dev.handle_data = usb_mouse_handle_data; | ||
343 | + | ||
344 | + qemu_add_mouse_event_handler(usb_mouse_event, s); | ||
345 | + | ||
346 | + return (USBDevice *)s; | ||
347 | +} |
hw/usb.h
@@ -64,6 +64,13 @@ | @@ -64,6 +64,13 @@ | ||
64 | 64 | ||
65 | #define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) | 65 | #define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) |
66 | #define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) | 66 | #define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) |
67 | +#define InterfaceRequest \ | ||
68 | + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) | ||
69 | +#define InterfaceOutRequest \ | ||
70 | + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) | ||
71 | +#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) | ||
72 | +#define EndpointOutRequest \ | ||
73 | + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) | ||
67 | 74 | ||
68 | #define USB_REQ_GET_STATUS 0x00 | 75 | #define USB_REQ_GET_STATUS 0x00 |
69 | #define USB_REQ_CLEAR_FEATURE 0x01 | 76 | #define USB_REQ_CLEAR_FEATURE 0x01 |
@@ -137,3 +144,6 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); | @@ -137,3 +144,6 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); | ||
137 | 144 | ||
138 | /* usb-linux.c */ | 145 | /* usb-linux.c */ |
139 | USBDevice *usb_host_hub_init(void); | 146 | USBDevice *usb_host_hub_init(void); |
147 | + | ||
148 | +/* usb-hid.c */ | ||
149 | +USBDevice *usb_mouse_init(void); |