Line 0
Link Here
|
|
|
1 |
Index: qemu/configure |
2 |
@@ -122,6 +122,7 @@ |
3 |
*) |
4 |
oss="yes" |
5 |
linux="yes" |
6 |
+usb="linux" |
7 |
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then |
8 |
kqemu="yes" |
9 |
fi |
10 |
@@ -131,6 +132,7 @@ |
11 |
if [ "$bsd" = "yes" ] ; then |
12 |
if [ ! "$darwin" = "yes" ] ; then |
13 |
make="gmake" |
14 |
+ usb="bsd" |
15 |
fi |
16 |
fi |
17 |
|
18 |
@@ -656,6 +675,19 @@ |
19 |
echo "#define _BSD 1" >> $config_h |
20 |
fi |
21 |
|
22 |
+# USB host support |
23 |
+case "$usb" in |
24 |
+linux) |
25 |
+ echo "HOST_USB=linux" >> $conig_mak |
26 |
+;; |
27 |
+bsd) |
28 |
+ echo "HOST_USB=bsd" >> $config_mak |
29 |
+;; |
30 |
+*) |
31 |
+ echo "HOST_USB=stub" >> $config_mak |
32 |
+;; |
33 |
+esac |
34 |
+ |
35 |
for target in $target_list; do |
36 |
|
37 |
target_dir="$target" |
38 |
Index: qemu/Makefile.target |
39 |
@@ -303,7 +303,7 @@ |
40 |
endif |
41 |
|
42 |
# USB layer |
43 |
-VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o |
44 |
+VL_OBJS+= usb.o usb-uhci.o usb-$(HOST_USB).o usb-hid.o |
45 |
|
46 |
ifeq ($(TARGET_BASE_ARCH), i386) |
47 |
# Hardware support |
48 |
Index: qemu/usb-stub.c |
49 |
@@ -0,0 +1,11 @@ |
50 |
+#include "vl.h" |
51 |
+ |
52 |
+void usb_host_info(void) |
53 |
+{ |
54 |
+ term_printf("USB host devices not supported\n"); |
55 |
+} |
56 |
+ |
57 |
+USBDevice *usb_host_device_open(const char *devname) |
58 |
+{ |
59 |
+ return NULL; |
60 |
+} |
61 |
Index: qemu/usb-bsd.c |
62 |
@@ -0,0 +1,592 @@ |
63 |
+/* |
64 |
+ * BSD host USB redirector |
65 |
+ * |
66 |
+ * Copyright (c) 2005 Lonnie Mendez |
67 |
+ * Portions of code and concepts borrowed from |
68 |
+ * usb-linux.c and libusb's bsd.c and are copyright their respective owners. |
69 |
+ * |
70 |
+ * Permission is hereby granted, free of charge, to any person obtaining a copy |
71 |
+ * of this software and associated documentation files (the "Software"), to deal |
72 |
+ * in the Software without restriction, including without limitation the rights |
73 |
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
74 |
+ * copies of the Software, and to permit persons to whom the Software is |
75 |
+ * furnished to do so, subject to the following conditions: |
76 |
+ * |
77 |
+ * The above copyright notice and this permission notice shall be included in |
78 |
+ * all copies or substantial portions of the Software. |
79 |
+ * |
80 |
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
81 |
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
82 |
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
83 |
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
84 |
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
85 |
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
86 |
+ * THE SOFTWARE. |
87 |
+ */ |
88 |
+ |
89 |
+#include "vl.h" |
90 |
+ |
91 |
+/* usb.h declares these */ |
92 |
+#undef USB_SPEED_HIGH |
93 |
+#undef USB_SPEED_FULL |
94 |
+#undef USB_SPEED_LOW |
95 |
+ |
96 |
+#include <sys/ioctl.h> |
97 |
+#include <dev/usb/usb.h> |
98 |
+#include <signal.h> |
99 |
+ |
100 |
+/* This value has maximum potential at 16. |
101 |
+ * You should also set hw.usb.debug to gain |
102 |
+ * more detailed view. |
103 |
+ */ |
104 |
+//#define DEBUG |
105 |
+#define UGEN_DEBUG_LEVEL 0 |
106 |
+ |
107 |
+ |
108 |
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, |
109 |
+ int vendor_id, int product_id, |
110 |
+ const char *product_name, int speed); |
111 |
+static int usb_host_find_device(int *pbus_num, int *paddr, |
112 |
+ const char *devname); |
113 |
+ |
114 |
+typedef struct USBHostDevice { |
115 |
+ USBDevice dev; |
116 |
+ int ep_fd[USB_MAX_ENDPOINTS]; |
117 |
+ int devfd; |
118 |
+ char devpath[32]; |
119 |
+} USBHostDevice; |
120 |
+ |
121 |
+ |
122 |
+static int ensure_ep_open(USBHostDevice *dev, int ep, int mode) |
123 |
+{ |
124 |
+ char buf[32]; |
125 |
+ int fd; |
126 |
+ |
127 |
+ /* Get the address for this endpoint */ |
128 |
+ ep = UE_GET_ADDR(ep); |
129 |
+ |
130 |
+ if (dev->ep_fd[ep] < 0) { |
131 |
+#if __FreeBSD__ |
132 |
+ snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->devpath, ep); |
133 |
+#else |
134 |
+ snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->devpath, ep); |
135 |
+#endif |
136 |
+ /* Try to open it O_RDWR first for those devices which have in and out |
137 |
+ * endpoints with the same address (eg 0x02 and 0x82) |
138 |
+ */ |
139 |
+ fd = open(buf, O_RDWR); |
140 |
+ if (fd < 0 && errno == ENXIO) |
141 |
+ fd = open(buf, mode); |
142 |
+ if (fd < 0) { |
143 |
+#ifdef DEBUG |
144 |
+ printf("ensure_ep_open: failed to open device endpoint %s: %s\n", |
145 |
+ buf, strerror(errno)); |
146 |
+#endif |
147 |
+ } |
148 |
+ dev->ep_fd[ep] = fd; |
149 |
+ } |
150 |
+ |
151 |
+ return dev->ep_fd[ep]; |
152 |
+} |
153 |
+ |
154 |
+static void ensure_eps_closed(USBHostDevice *dev) |
155 |
+{ |
156 |
+ int epnum = 1; |
157 |
+ |
158 |
+ if (!dev) |
159 |
+ return; |
160 |
+ |
161 |
+ while (epnum < USB_MAX_ENDPOINTS) { |
162 |
+ if (dev->ep_fd[epnum] >= 0) { |
163 |
+ close(dev->ep_fd[epnum]); |
164 |
+ dev->ep_fd[epnum] = -1; |
165 |
+ } |
166 |
+ epnum++; |
167 |
+ } |
168 |
+} |
169 |
+ |
170 |
+static void usb_host_handle_reset(USBDevice *dev) |
171 |
+{ |
172 |
+#if 0 |
173 |
+ USBHostDevice *s = (USBHostDevice *)dev; |
174 |
+#endif |
175 |
+} |
176 |
+ |
177 |
+/* XXX: |
178 |
+ * -check device states against transfer requests |
179 |
+ * and return appropriate response |
180 |
+ */ |
181 |
+static int usb_host_handle_control(USBDevice *dev, |
182 |
+ int request, |
183 |
+ int value, |
184 |
+ int index, |
185 |
+ int length, |
186 |
+ uint8_t *data) |
187 |
+{ |
188 |
+ USBHostDevice *s = (USBHostDevice *)dev; |
189 |
+ struct usb_ctl_request req; |
190 |
+ struct usb_alt_interface aiface; |
191 |
+ int ret, timeout = 50; |
192 |
+ |
193 |
+ if ((request >> 8) == UT_WRITE_DEVICE && |
194 |
+ (request & 0xff) == UR_SET_ADDRESS) { |
195 |
+ |
196 |
+ /* specific SET_ADDRESS support */ |
197 |
+ dev->addr = value; |
198 |
+ return 0; |
199 |
+ } else if ((request >> 8) == UT_WRITE_DEVICE && |
200 |
+ (request & 0xff) == UR_SET_CONFIG) { |
201 |
+ |
202 |
+ ensure_eps_closed(s); /* can't do this without all eps closed */ |
203 |
+ |
204 |
+ ret = ioctl(s->devfd, USB_SET_CONFIG, &value); |
205 |
+ if (ret < 0) { |
206 |
+#ifdef DEBUG |
207 |
+ printf("handle_control: failed to set configuration - %s\n", |
208 |
+ strerror(errno)); |
209 |
+#endif |
210 |
+ return USB_RET_STALL; |
211 |
+ } |
212 |
+ |
213 |
+ return 0; |
214 |
+ } else if ((request >> 8) == UT_WRITE_INTERFACE && |
215 |
+ (request & 0xff) == UR_SET_INTERFACE) { |
216 |
+ |
217 |
+ aiface.uai_interface_index = index; |
218 |
+ aiface.uai_alt_no = value; |
219 |
+ |
220 |
+ ensure_eps_closed(s); /* can't do this without all eps closed */ |
221 |
+ ret = ioctl(s->devfd, USB_SET_ALTINTERFACE, &aiface); |
222 |
+ if (ret < 0) { |
223 |
+#ifdef DEBUG |
224 |
+ printf("handle_control: failed to set alternate interface - %s\n", |
225 |
+ strerror(errno)); |
226 |
+#endif |
227 |
+ return USB_RET_STALL; |
228 |
+ } |
229 |
+ |
230 |
+ return 0; |
231 |
+ } else { |
232 |
+ req.ucr_request.bmRequestType = request >> 8; |
233 |
+ req.ucr_request.bRequest = request & 0xff; |
234 |
+ USETW(req.ucr_request.wValue, value); |
235 |
+ USETW(req.ucr_request.wIndex, index); |
236 |
+ USETW(req.ucr_request.wLength, length); |
237 |
+ req.ucr_data = data; |
238 |
+ req.ucr_flags = USBD_SHORT_XFER_OK; |
239 |
+ |
240 |
+ ret = ioctl(s->devfd, USB_SET_TIMEOUT, &timeout); |
241 |
+#if (__NetBSD__ || __OpenBSD__) |
242 |
+ if (ret < 0 && errno != EINVAL) { |
243 |
+#else |
244 |
+ if (ret < 0) { |
245 |
+#endif |
246 |
+#ifdef DEBUG |
247 |
+ printf("handle_control: setting timeout failed - %s\n", |
248 |
+ strerror(errno)); |
249 |
+#endif |
250 |
+ } |
251 |
+ |
252 |
+ ret = ioctl(s->devfd, USB_DO_REQUEST, &req); |
253 |
+ /* ugen returns EIO for usbd_do_request_ no matter what |
254 |
+ * happens with the transfer */ |
255 |
+ if (ret < 0) { |
256 |
+#ifdef DEBUG |
257 |
+ printf("handle_control: error after request - %s\n", |
258 |
+ strerror(errno)); |
259 |
+#endif |
260 |
+ return USB_RET_NAK; // STALL |
261 |
+ } else { |
262 |
+ return req.ucr_actlen; |
263 |
+ } |
264 |
+ } |
265 |
+} |
266 |
+ |
267 |
+static int usb_host_handle_data(USBDevice *dev, int pid, |
268 |
+ uint8_t devep, |
269 |
+ uint8_t *data, int len) |
270 |
+{ |
271 |
+ USBHostDevice *s = (USBHostDevice *)dev; |
272 |
+ int ret, fd, mode; |
273 |
+ int one = 1, shortpacket = 0, timeout = 50; |
274 |
+ sigset_t new_mask, old_mask; |
275 |
+ |
276 |
+ /* protect data transfers from SIGALRM signal */ |
277 |
+ sigemptyset(&new_mask); |
278 |
+ sigaddset(&new_mask, SIGALRM); |
279 |
+ sigprocmask(SIG_BLOCK, &new_mask, &old_mask); |
280 |
+ |
281 |
+ /* XXX: optimize and handle all data types by looking at the |
282 |
+ config descriptor */ |
283 |
+ if (pid == USB_TOKEN_IN) { |
284 |
+ devep |= 0x80; |
285 |
+ mode = O_RDONLY; |
286 |
+ shortpacket = 1; |
287 |
+ } else { |
288 |
+ mode = O_WRONLY; |
289 |
+ } |
290 |
+ |
291 |
+ fd = ensure_ep_open(s, devep, mode); |
292 |
+ if (fd < 0) { |
293 |
+ sigprocmask(SIG_SETMASK, &old_mask, NULL); |
294 |
+ return USB_RET_NODEV; |
295 |
+ } |
296 |
+ |
297 |
+ if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) { |
298 |
+#ifdef DEBUG |
299 |
+ printf("handle_data: failed to set timeout - %s\n", |
300 |
+ strerror(errno)); |
301 |
+#endif |
302 |
+ } |
303 |
+ |
304 |
+ if (shortpacket) { |
305 |
+ if (ioctl(fd, USB_SET_SHORT_XFER, &one) < 0) { |
306 |
+#ifdef DEBUG |
307 |
+ printf("handle_data: failed to set short xfer mode - %s\n", |
308 |
+ strerror(errno)); |
309 |
+#endif |
310 |
+ sigprocmask(SIG_SETMASK, &old_mask, NULL); |
311 |
+ } |
312 |
+ } |
313 |
+ |
314 |
+ if (pid == USB_TOKEN_IN) |
315 |
+ ret = read(fd, data, len); |
316 |
+ else |
317 |
+ ret = write(fd, data, len); |
318 |
+ |
319 |
+ sigprocmask(SIG_SETMASK, &old_mask, NULL); |
320 |
+ |
321 |
+ if (ret < 0) { |
322 |
+#ifdef DEBUG |
323 |
+ printf("handle_data: error after %s data - %s\n", |
324 |
+ pid == USB_TOKEN_IN ? "reading" : "writing", strerror(errno)); |
325 |
+#endif |
326 |
+ switch(errno) { |
327 |
+ case ETIMEDOUT: |
328 |
+ case EINTR: |
329 |
+ return USB_RET_NAK; |
330 |
+ default: |
331 |
+ return USB_RET_STALL; |
332 |
+ } |
333 |
+ } else { |
334 |
+ return ret; |
335 |
+ } |
336 |
+} |
337 |
+ |
338 |
+USBDevice *usb_host_device_open(const char *devname) |
339 |
+{ |
340 |
+ struct usb_device_info bus_info, dev_info; |
341 |
+ USBHostDevice *dev; |
342 |
+ char ctlpath[PATH_MAX + 1]; |
343 |
+ char buspath[PATH_MAX + 1]; |
344 |
+ int bfd, dfd, bus, address, i; |
345 |
+ int ugendebug = UGEN_DEBUG_LEVEL; |
346 |
+ |
347 |
+ if (usb_host_find_device(&bus, &address, devname) < 0) |
348 |
+ return NULL; |
349 |
+ |
350 |
+ snprintf(buspath, PATH_MAX, "/dev/usb%d", bus); |
351 |
+ |
352 |
+ bfd = open(buspath, O_RDWR); |
353 |
+ if (bfd < 0) { |
354 |
+#ifdef DEBUG |
355 |
+ printf("usb_host_device_open: failed to open usb bus - %s\n", |
356 |
+ strerror(errno)); |
357 |
+#endif |
358 |
+ return NULL; |
359 |
+ } |
360 |
+ |
361 |
+ bus_info.udi_addr = address; |
362 |
+ if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0) { |
363 |
+#ifdef DEBUG |
364 |
+ printf("usb_host_device_open: failed to grab bus information - %s\n", |
365 |
+ strerror(errno)); |
366 |
+#endif |
367 |
+ return NULL; |
368 |
+ } |
369 |
+ |
370 |
+#if __FreeBSD__ |
371 |
+ snprintf(ctlpath, PATH_MAX, "/dev/%s", bus_info.udi_devnames[0]); |
372 |
+#else |
373 |
+ snprintf(ctlpath, PATH_MAX, "/dev/%s.00", bus_info.udi_devnames[0]); |
374 |
+#endif |
375 |
+ |
376 |
+ dfd = open(ctlpath, O_RDWR); |
377 |
+ if (dfd < 0) { |
378 |
+ dfd = open(ctlpath, O_RDONLY); |
379 |
+ if (dfd < 0) { |
380 |
+#ifdef DEBUG |
381 |
+ printf("usb_host_device_open: failed to open usb device %s - %s\n", |
382 |
+ ctlpath, strerror(errno)); |
383 |
+#endif |
384 |
+ } |
385 |
+ } |
386 |
+ |
387 |
+ if (dfd >= 0) { |
388 |
+ dev = qemu_mallocz(sizeof(USBHostDevice)); |
389 |
+ if (!dev) |
390 |
+ goto fail; |
391 |
+ dev->devfd = dfd; |
392 |
+ |
393 |
+ if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) { |
394 |
+#ifdef DEBUG |
395 |
+ printf("usb_host_device_open: failed to grab device info - %s\n", |
396 |
+ strerror(errno)); |
397 |
+#endif |
398 |
+ goto fail; |
399 |
+ } |
400 |
+ |
401 |
+ if (dev_info.udi_speed == 1) |
402 |
+ dev->dev.speed = USB_SPEED_LOW - 1; |
403 |
+ else |
404 |
+ dev->dev.speed = USB_SPEED_FULL - 1; |
405 |
+ |
406 |
+ dev->dev.handle_packet = usb_generic_handle_packet; |
407 |
+ |
408 |
+ dev->dev.handle_reset = usb_host_handle_reset; |
409 |
+ dev->dev.handle_control = usb_host_handle_control; |
410 |
+ dev->dev.handle_data = usb_host_handle_data; |
411 |
+ |
412 |
+ strcpy(dev->devpath, "/dev/"); |
413 |
+ strcat(dev->devpath, dev_info.udi_devnames[0]); |
414 |
+ |
415 |
+ /* Mark the endpoints as not yet open */ |
416 |
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) |
417 |
+ dev->ep_fd[i] = -1; |
418 |
+ |
419 |
+ ioctl(dfd, USB_SETDEBUG, &ugendebug); |
420 |
+ |
421 |
+ return (USBDevice *)dev; |
422 |
+ } |
423 |
+ |
424 |
+fail: |
425 |
+ return NULL; |
426 |
+} |
427 |
+ |
428 |
+void usb_host_device_close(USBDevice *opaque) |
429 |
+{ |
430 |
+ USBHostDevice *s = (USBHostDevice *)opaque; |
431 |
+ int i; |
432 |
+ |
433 |
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) |
434 |
+ if (s->ep_fd[i] >= 0) |
435 |
+ close(s->ep_fd[i]); |
436 |
+ |
437 |
+ if (s->devfd < 0) |
438 |
+ return; |
439 |
+ |
440 |
+ close(s->devfd); |
441 |
+} |
442 |
+ |
443 |
+static int usb_host_scan(void *opaque, USBScanFunc *func) |
444 |
+{ |
445 |
+ struct usb_device_info bus_info; |
446 |
+ struct usb_device_info dev_info; |
447 |
+ uint16_t vendor_id, product_id, class_id, speed; |
448 |
+ int bfd, dfd, bus, address; |
449 |
+ char busbuf[20], devbuf[20], product_name[256]; |
450 |
+ int ret = 0; |
451 |
+ |
452 |
+ for (bus = 0; bus < 10; bus++) { |
453 |
+ |
454 |
+ snprintf(busbuf, sizeof(busbuf) - 1, "/dev/usb%d", bus); |
455 |
+ bfd = open(busbuf, O_RDWR); |
456 |
+ if (bfd < 0) |
457 |
+ continue; |
458 |
+ |
459 |
+ for (address = 1; address < 127; address++) { |
460 |
+ |
461 |
+ bus_info.udi_addr = address; |
462 |
+ if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0) |
463 |
+ continue; |
464 |
+ |
465 |
+ /* only list devices that can be used by generic layer */ |
466 |
+ if (strncmp(bus_info.udi_devnames[0], "ugen", 4) != 0) |
467 |
+ continue; |
468 |
+ |
469 |
+#if __FreeBSD__ |
470 |
+ snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s", bus_info.udi_devnames[0]); |
471 |
+#else |
472 |
+ snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s.00", bus_info.udi_devnames[0]); |
473 |
+#endif |
474 |
+ |
475 |
+ dfd = open(devbuf, O_RDONLY); |
476 |
+ if (dfd < 0) { |
477 |
+#ifdef DEBUG |
478 |
+ printf("usb_host_scan: couldn't open device %s - %s\n", devbuf, |
479 |
+ strerror(errno)); |
480 |
+#endif |
481 |
+ continue; |
482 |
+ } |
483 |
+ |
484 |
+ if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) |
485 |
+ printf("usb_host_scan: couldn't get device information for %s - %s\n", |
486 |
+ devbuf, strerror(errno)); |
487 |
+ |
488 |
+ // XXX: might need to fixup endianess of word values before copying over |
489 |
+ |
490 |
+ vendor_id = dev_info.udi_vendorNo; |
491 |
+ product_id = dev_info.udi_productNo; |
492 |
+ class_id = dev_info.udi_class; |
493 |
+ speed = dev_info.udi_speed; |
494 |
+ |
495 |
+ if (strncmp(dev_info.udi_product, "product", 7) != 0) |
496 |
+ strcpy(product_name, dev_info.udi_product); |
497 |
+ else |
498 |
+ product_name[0] = '\0'; |
499 |
+ |
500 |
+ ret = func(opaque, bus, address, class_id, vendor_id, |
501 |
+ product_id, product_name, speed); |
502 |
+ |
503 |
+ close(dfd); |
504 |
+ |
505 |
+ if (ret) |
506 |
+ goto the_end; |
507 |
+ } |
508 |
+ |
509 |
+ close(bfd); |
510 |
+ } |
511 |
+ |
512 |
+the_end: |
513 |
+ return ret; |
514 |
+} |
515 |
+ |
516 |
+typedef struct FindDeviceState { |
517 |
+ int vendor_id; |
518 |
+ int product_id; |
519 |
+ int bus_num; |
520 |
+ int addr; |
521 |
+} FindDeviceState; |
522 |
+ |
523 |
+static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, |
524 |
+ int class_id, |
525 |
+ int vendor_id, int product_id, |
526 |
+ const char *product_name, int speed) |
527 |
+{ |
528 |
+ FindDeviceState *s = opaque; |
529 |
+ if (vendor_id == s->vendor_id && |
530 |
+ product_id == s->product_id) { |
531 |
+ s->bus_num = bus_num; |
532 |
+ s->addr = addr; |
533 |
+ return 1; |
534 |
+ } else { |
535 |
+ return 0; |
536 |
+ } |
537 |
+} |
538 |
+ |
539 |
+ |
540 |
+/* the syntax is : |
541 |
+ 'bus.addr' (decimal numbers) or |
542 |
+ 'vendor_id:product_id' (hexa numbers) */ |
543 |
+static int usb_host_find_device(int *pbus_num, int *paddr, |
544 |
+ const char *devname) |
545 |
+{ |
546 |
+ const char *p; |
547 |
+ int ret; |
548 |
+ FindDeviceState fs; |
549 |
+ |
550 |
+ p = strchr(devname, '.'); |
551 |
+ if (p) { |
552 |
+ *pbus_num = strtoul(devname, NULL, 0); |
553 |
+ *paddr = strtoul(p + 1, NULL, 0); |
554 |
+ return 0; |
555 |
+ } |
556 |
+ p = strchr(devname, ':'); |
557 |
+ if (p) { |
558 |
+ fs.vendor_id = strtoul(devname, NULL, 16); |
559 |
+ fs.product_id = strtoul(p + 1, NULL, 16); |
560 |
+ ret = usb_host_scan(&fs, usb_host_find_device_scan); |
561 |
+ if (ret) { |
562 |
+ *pbus_num = fs.bus_num; |
563 |
+ *paddr = fs.addr; |
564 |
+ return 0; |
565 |
+ } |
566 |
+ } |
567 |
+ return -1; |
568 |
+} |
569 |
+ |
570 |
+/**********************/ |
571 |
+/* USB host device info */ |
572 |
+ |
573 |
+struct usb_class_info { |
574 |
+ int class; |
575 |
+ const char *class_name; |
576 |
+}; |
577 |
+ |
578 |
+static const struct usb_class_info usb_class_info[] = { |
579 |
+ { USB_CLASS_AUDIO, "Audio"}, |
580 |
+ { USB_CLASS_COMM, "Communication"}, |
581 |
+ { USB_CLASS_HID, "HID"}, |
582 |
+ { USB_CLASS_HUB, "Hub" }, |
583 |
+ { USB_CLASS_PHYSICAL, "Physical" }, |
584 |
+ { USB_CLASS_PRINTER, "Printer" }, |
585 |
+ { USB_CLASS_MASS_STORAGE, "Storage" }, |
586 |
+ { USB_CLASS_CDC_DATA, "Data" }, |
587 |
+ { USB_CLASS_APP_SPEC, "Application Specific" }, |
588 |
+ { USB_CLASS_VENDOR_SPEC, "Vendor Specific" }, |
589 |
+ { USB_CLASS_STILL_IMAGE, "Still Image" }, |
590 |
+ { USB_CLASS_CSCID, "Smart Card" }, |
591 |
+ { USB_CLASS_CONTENT_SEC, "Content Security" }, |
592 |
+ { -1, NULL } |
593 |
+}; |
594 |
+ |
595 |
+static const char *usb_class_str(uint8_t class) |
596 |
+{ |
597 |
+ const struct usb_class_info *p; |
598 |
+ for (p = usb_class_info; p->class != -1; p++) { |
599 |
+ if (p->class == class) |
600 |
+ break; |
601 |
+ } |
602 |
+ return p->class_name; |
603 |
+} |
604 |
+ |
605 |
+void usb_info_device(int bus_num, int addr, int class_id, |
606 |
+ int vendor_id, int product_id, |
607 |
+ const char *product_name, |
608 |
+ int speed) |
609 |
+{ |
610 |
+ const char *class_str, *speed_str; |
611 |
+ |
612 |
+ switch(speed) { |
613 |
+ case USB_SPEED_LOW: |
614 |
+ speed_str = "1.5"; |
615 |
+ break; |
616 |
+ case USB_SPEED_FULL: |
617 |
+ speed_str = "12"; |
618 |
+ break; |
619 |
+ case USB_SPEED_HIGH: |
620 |
+ speed_str = "480"; |
621 |
+ break; |
622 |
+ default: |
623 |
+ speed_str = "?"; |
624 |
+ break; |
625 |
+ } |
626 |
+ |
627 |
+ term_printf(" Device %d.%d, speed %s Mb/s\n", |
628 |
+ bus_num, addr, speed_str); |
629 |
+ class_str = usb_class_str(class_id); |
630 |
+ if (class_str) |
631 |
+ term_printf(" %s:", class_str); |
632 |
+ else |
633 |
+ term_printf(" Class %02x:", class_id); |
634 |
+ term_printf(" USB device %04x:%04x", vendor_id, product_id); |
635 |
+ if (product_name[0] != '\0') |
636 |
+ term_printf(", %s", product_name); |
637 |
+ term_printf("\n"); |
638 |
+} |
639 |
+ |
640 |
+static int usb_host_info_device(void *opaque, int bus_num, int addr, |
641 |
+ int class_id, |
642 |
+ int vendor_id, int product_id, |
643 |
+ const char *product_name, |
644 |
+ int speed) |
645 |
+{ |
646 |
+ usb_info_device(bus_num, addr, class_id, vendor_id, product_id, |
647 |
+ product_name, speed); |
648 |
+ return 0; |
649 |
+} |
650 |
+ |
651 |
+void usb_host_info(void) |
652 |
+{ |
653 |
+ usb_host_scan(NULL, usb_host_info_device); |
654 |
+} |
655 |
Index: qemu/vl.c |
656 |
@@ -2820,10 +2822,12 @@ |
657 |
dev = usb_host_device_open(p); |
658 |
if (!dev) |
659 |
return -1; |
660 |
+ dev->isproxied = 1; |
661 |
} else if (!strcmp(devname, "mouse")) { |
662 |
dev = usb_mouse_init(); |
663 |
if (!dev) |
664 |
return -1; |
665 |
+ dev->isproxied = 0; |
666 |
} else { |
667 |
return -1; |
668 |
} |
669 |
@@ -2852,6 +2856,8 @@ |
670 |
if (dev && dev->addr == addr) |
671 |
break; |
672 |
} |
673 |
+ if (dev && dev->isproxied) |
674 |
+ usb_host_device_close(dev); |
675 |
if (i == MAX_VM_USB_PORTS) |
676 |
return -1; |
677 |
usb_attach(vm_usb_ports[i], NULL); |
678 |
Index: qemu/hw/usb.h |
679 |
@@ -135,6 +146,8 @@ |
680 |
int setup_state; |
681 |
int setup_len; |
682 |
int setup_index; |
683 |
+ |
684 |
+ int isproxied; |
685 |
}; |
686 |
|
687 |
/* USB port on which a device can be connected */ |
688 |
@@ -157,8 +170,9 @@ |
689 |
/* usb-uhci.c */ |
690 |
void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); |
691 |
|
692 |
-/* usb-linux.c */ |
693 |
+/* host proxy functions */ |
694 |
USBDevice *usb_host_device_open(const char *devname); |
695 |
+void usb_host_device_close(USBDevice *dev); |
696 |
void usb_host_info(void); |
697 |
|
698 |
/* usb-hid.c */ |
699 |
Index: qemu/usb-linux.c |
700 |
@@ -23,7 +23,6 @@ |
701 |
*/ |
702 |
#include "vl.h" |
703 |
|
704 |
-#if defined(__linux__) |
705 |
#include <dirent.h> |
706 |
#include <sys/ioctl.h> |
707 |
#include <linux/usbdevice_fs.h> |
708 |
@@ -255,6 +254,14 @@ |
709 |
return q - buf; |
710 |
} |
711 |
|
712 |
+void usb_host_device_close(USBDevice *opaque) |
713 |
+{ |
714 |
+ USBHostDevice *s = (USBHostDevice *)opaque; |
715 |
+ |
716 |
+ if (s->fd >= 0) |
717 |
+ close(s->fd); |
718 |
+} |
719 |
+ |
720 |
static int usb_host_scan(void *opaque, USBScanFunc *func) |
721 |
{ |
722 |
FILE *f; |
723 |
@@ -468,18 +475,3 @@ |
724 |
{ |
725 |
usb_host_scan(NULL, usb_host_info_device); |
726 |
} |
727 |
- |
728 |
-#else |
729 |
- |
730 |
-void usb_host_info(void) |
731 |
-{ |
732 |
- term_printf("USB host devices not supported\n"); |
733 |
-} |
734 |
- |
735 |
-/* XXX: modify configure to compile the right host driver */ |
736 |
-USBDevice *usb_host_device_open(const char *devname) |
737 |
-{ |
738 |
- return NULL; |
739 |
-} |
740 |
- |
741 |
-#endif |