blob: 622255c9e28d710bf51159c07fcbe99bfe494317 [file] [log] [blame]
bellardbb36d472005-11-05 14:22:28 +00001/*
2 * Linux host USB redirector
3 *
4 * Copyright (c) 2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
aliguori4b096fc2008-08-21 19:28:55 +00006 * Support for host device auto connect & disconnect
7 * Copyright (c) 2008 Max Krasnyansky
8 *
bellardbb36d472005-11-05 14:22:28 +00009 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
pbrook87ecb682007-11-17 17:14:51 +000027#include "qemu-common.h"
aliguori1f3870a2008-08-21 19:27:48 +000028#include "qemu-timer.h"
pbrook87ecb682007-11-17 17:14:51 +000029#include "hw/usb.h"
30#include "console.h"
bellardbb36d472005-11-05 14:22:28 +000031
32#if defined(__linux__)
33#include <dirent.h>
34#include <sys/ioctl.h>
35#include <linux/usbdevice_fs.h>
36#include <linux/version.h>
balrogb9dc0332007-10-04 22:47:34 +000037#include <signal.h>
bellardbb36d472005-11-05 14:22:28 +000038
39/* We redefine it to avoid version problems */
40struct usb_ctrltransfer {
41 uint8_t bRequestType;
42 uint8_t bRequest;
43 uint16_t wValue;
44 uint16_t wIndex;
45 uint16_t wLength;
46 uint32_t timeout;
47 void *data;
48};
49
bellarda594cfb2005-11-06 16:13:29 +000050typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
ths5fafdf22007-09-16 21:08:06 +000051 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000052 const char *product_name, int speed);
ths5fafdf22007-09-16 21:08:06 +000053static int usb_host_find_device(int *pbus_num, int *paddr,
bellard1f6e24e2006-06-26 21:00:51 +000054 char *product_name, int product_name_size,
bellarda594cfb2005-11-06 16:13:29 +000055 const char *devname);
bellardbb36d472005-11-05 14:22:28 +000056
bellarda594cfb2005-11-06 16:13:29 +000057//#define DEBUG
balrogb9dc0332007-10-04 22:47:34 +000058//#define DEBUG_ISOCH
59//#define USE_ASYNCIO
bellardbb36d472005-11-05 14:22:28 +000060
61#define USBDEVFS_PATH "/proc/bus/usb"
bellard1f6e24e2006-06-26 21:00:51 +000062#define PRODUCT_NAME_SZ 32
balrogb9dc0332007-10-04 22:47:34 +000063#define SIG_ISOCOMPLETE (SIGRTMIN+7)
64#define MAX_ENDPOINTS 16
bellardbb36d472005-11-05 14:22:28 +000065
balrogb9dc0332007-10-04 22:47:34 +000066struct sigaction sigact;
67
68/* endpoint association data */
69struct endp_data {
70 uint8_t type;
71};
72
aliguori4b096fc2008-08-21 19:28:55 +000073
74
balrogb9dc0332007-10-04 22:47:34 +000075/* FIXME: move USBPacket to PendingURB */
bellardbb36d472005-11-05 14:22:28 +000076typedef struct USBHostDevice {
77 USBDevice dev;
78 int fd;
balrog046833e2007-10-31 00:27:50 +000079 int pipe_fds[2];
balrogb9dc0332007-10-04 22:47:34 +000080 USBPacket *packet;
81 struct endp_data endp_table[MAX_ENDPOINTS];
82 int configuration;
83 uint8_t descr[1024];
84 int descr_len;
85 int urbs_ready;
aliguori4b096fc2008-08-21 19:28:55 +000086
aliguori1f3870a2008-08-21 19:27:48 +000087 QEMUTimer *timer;
aliguori4b096fc2008-08-21 19:28:55 +000088
89 /* Host side address */
90 int bus_num;
91 int addr;
92
93 struct USBHostDevice *next;
bellardbb36d472005-11-05 14:22:28 +000094} USBHostDevice;
95
aliguori4b096fc2008-08-21 19:28:55 +000096static USBHostDevice *hostdev_list;
97
98static void hostdev_link(USBHostDevice *dev)
99{
100 dev->next = hostdev_list;
101 hostdev_list = dev;
102}
103
104static void hostdev_unlink(USBHostDevice *dev)
105{
106 USBHostDevice *pdev = hostdev_list;
107 USBHostDevice **prev = &hostdev_list;
108
109 while (pdev) {
110 if (pdev == dev) {
111 *prev = dev->next;
112 return;
113 }
114
115 prev = &pdev->next;
116 pdev = pdev->next;
117 }
118}
119
120static USBHostDevice *hostdev_find(int bus_num, int addr)
121{
122 USBHostDevice *s = hostdev_list;
123 while (s) {
124 if (s->bus_num == bus_num && s->addr == addr)
125 return s;
126 s = s->next;
127 }
128 return NULL;
129}
130
balrogb9dc0332007-10-04 22:47:34 +0000131typedef struct PendingURB {
132 struct usbdevfs_urb *urb;
balrogb9dc0332007-10-04 22:47:34 +0000133 int status;
134 struct PendingURB *next;
135} PendingURB;
136
balrog4d043a02007-10-04 22:55:53 +0000137static PendingURB *pending_urbs = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000138
balrog4d043a02007-10-04 22:55:53 +0000139static int add_pending_urb(struct usbdevfs_urb *urb)
balrogb9dc0332007-10-04 22:47:34 +0000140{
141 PendingURB *purb = qemu_mallocz(sizeof(PendingURB));
142 if (purb) {
143 purb->urb = urb;
balrogb9dc0332007-10-04 22:47:34 +0000144 purb->status = 0;
145 purb->next = pending_urbs;
146 pending_urbs = purb;
147 return 1;
148 }
149 return 0;
150}
151
balrog4d043a02007-10-04 22:55:53 +0000152static int del_pending_urb(struct usbdevfs_urb *urb)
balrogb9dc0332007-10-04 22:47:34 +0000153{
154 PendingURB *purb = pending_urbs;
155 PendingURB *prev = NULL;
156
157 while (purb && purb->urb != urb) {
158 prev = purb;
159 purb = purb->next;
160 }
161
162 if (purb && purb->urb == urb) {
163 if (prev) {
164 prev->next = purb->next;
165 } else {
166 pending_urbs = purb->next;
167 }
168 qemu_free(purb);
169 return 1;
170 }
171 return 0;
172}
173
balrog4d043a02007-10-04 22:55:53 +0000174#ifdef USE_ASYNCIO
175static PendingURB *get_pending_urb(struct usbdevfs_urb *urb)
balrogb9dc0332007-10-04 22:47:34 +0000176{
177 PendingURB *purb = pending_urbs;
178
179 while (purb && purb->urb != urb) {
180 purb = purb->next;
181 }
182
183 if (purb && purb->urb == urb) {
184 return purb;
185 }
186 return NULL;
187}
balrog4d043a02007-10-04 22:55:53 +0000188#endif
balrogb9dc0332007-10-04 22:47:34 +0000189
190static int usb_host_update_interfaces(USBHostDevice *dev, int configuration)
191{
192 int dev_descr_len, config_descr_len;
193 int interface, nb_interfaces, nb_configurations;
194 int ret, i;
195
196 if (configuration == 0) /* address state - ignore */
197 return 1;
198
199 i = 0;
200 dev_descr_len = dev->descr[0];
201 if (dev_descr_len > dev->descr_len)
202 goto fail;
203 nb_configurations = dev->descr[17];
204
205 i += dev_descr_len;
206 while (i < dev->descr_len) {
207#ifdef DEBUG
208 printf("i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len,
209 dev->descr[i], dev->descr[i+1]);
210#endif
211 if (dev->descr[i+1] != USB_DT_CONFIG) {
212 i += dev->descr[i];
213 continue;
214 }
215 config_descr_len = dev->descr[i];
216
aliguori1f3870a2008-08-21 19:27:48 +0000217#ifdef DEBUG
218 printf("config #%d need %d\n", dev->descr[i + 5], configuration);
219#endif
220
221 if (configuration < 0 || configuration == dev->descr[i + 5])
balrogb9dc0332007-10-04 22:47:34 +0000222 break;
223
224 i += config_descr_len;
225 }
226
227 if (i >= dev->descr_len) {
228 printf("usb_host: error - device has no matching configuration\n");
229 goto fail;
230 }
231 nb_interfaces = dev->descr[i + 4];
232
233#ifdef USBDEVFS_DISCONNECT
234 /* earlier Linux 2.4 do not support that */
235 {
236 struct usbdevfs_ioctl ctrl;
237 for (interface = 0; interface < nb_interfaces; interface++) {
238 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
239 ctrl.ifno = interface;
240 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
241 if (ret < 0 && errno != ENODATA) {
242 perror("USBDEVFS_DISCONNECT");
243 goto fail;
244 }
245 }
246 }
247#endif
248
249 /* XXX: only grab if all interfaces are free */
250 for (interface = 0; interface < nb_interfaces; interface++) {
251 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
252 if (ret < 0) {
253 if (errno == EBUSY) {
254 fprintf(stderr,
255 "usb_host: warning - device already grabbed\n");
256 } else {
257 perror("USBDEVFS_CLAIMINTERFACE");
258 }
259 fail:
260 return 0;
261 }
262 }
263
264#ifdef DEBUG
265 printf("usb_host: %d interfaces claimed for configuration %d\n",
266 nb_interfaces, configuration);
267#endif
268
269 return 1;
270}
271
bellard059809e2006-07-19 18:06:15 +0000272static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000273{
274#if 0
275 USBHostDevice *s = (USBHostDevice *)dev;
276 /* USBDEVFS_RESET, but not the first time as it has already be
277 done by the host OS */
278 ioctl(s->fd, USBDEVFS_RESET);
279#endif
ths5fafdf22007-09-16 21:08:06 +0000280}
bellardbb36d472005-11-05 14:22:28 +0000281
bellard059809e2006-07-19 18:06:15 +0000282static void usb_host_handle_destroy(USBDevice *dev)
283{
284 USBHostDevice *s = (USBHostDevice *)dev;
285
aliguori1f3870a2008-08-21 19:27:48 +0000286 qemu_del_timer(s->timer);
287
aliguori4b096fc2008-08-21 19:28:55 +0000288 hostdev_unlink(s);
289
bellard059809e2006-07-19 18:06:15 +0000290 if (s->fd >= 0)
291 close(s->fd);
aliguori1f3870a2008-08-21 19:27:48 +0000292
bellard059809e2006-07-19 18:06:15 +0000293 qemu_free(s);
294}
295
balrogb9dc0332007-10-04 22:47:34 +0000296static int usb_linux_update_endp_table(USBHostDevice *s);
297
bellardbb36d472005-11-05 14:22:28 +0000298static int usb_host_handle_control(USBDevice *dev,
299 int request,
300 int value,
301 int index,
302 int length,
303 uint8_t *data)
304{
305 USBHostDevice *s = (USBHostDevice *)dev;
306 struct usb_ctrltransfer ct;
balrogb9dc0332007-10-04 22:47:34 +0000307 struct usbdevfs_setinterface si;
308 int intf_update_required = 0;
bellardbb36d472005-11-05 14:22:28 +0000309 int ret;
310
311 if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
312 /* specific SET_ADDRESS support */
313 dev->addr = value;
314 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000315 } else if (request == ((USB_RECIP_INTERFACE << 8) |
316 USB_REQ_SET_INTERFACE)) {
317 /* set alternate setting for the interface */
318 si.interface = index;
319 si.altsetting = value;
320 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
321 usb_linux_update_endp_table(s);
322 } else if (request == (DeviceOutRequest | USB_REQ_SET_CONFIGURATION)) {
323#ifdef DEBUG
324 printf("usb_host_handle_control: SET_CONFIGURATION request - "
325 "config %d\n", value & 0xff);
326#endif
327 if (s->configuration != (value & 0xff)) {
328 s->configuration = (value & 0xff);
329 intf_update_required = 1;
330 }
331 goto do_request;
bellardbb36d472005-11-05 14:22:28 +0000332 } else {
balrogb9dc0332007-10-04 22:47:34 +0000333 do_request:
bellardbb36d472005-11-05 14:22:28 +0000334 ct.bRequestType = request >> 8;
335 ct.bRequest = request;
336 ct.wValue = value;
337 ct.wIndex = index;
338 ct.wLength = length;
339 ct.timeout = 50;
340 ct.data = data;
341 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
balrogb9dc0332007-10-04 22:47:34 +0000342 }
343
344 if (ret < 0) {
345 switch(errno) {
346 case ETIMEDOUT:
347 return USB_RET_NAK;
348 default:
349 return USB_RET_STALL;
bellardbb36d472005-11-05 14:22:28 +0000350 }
balrogb9dc0332007-10-04 22:47:34 +0000351 } else {
352 if (intf_update_required) {
353#ifdef DEBUG
354 printf("usb_host_handle_control: updating interfaces\n");
355#endif
356 usb_host_update_interfaces(s, value & 0xff);
357 }
358 return ret;
359 }
bellardbb36d472005-11-05 14:22:28 +0000360}
361
balrogb9dc0332007-10-04 22:47:34 +0000362static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p);
363
pbrook4d611c92006-08-12 01:04:27 +0000364static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000365{
366 USBHostDevice *s = (USBHostDevice *)dev;
367 struct usbdevfs_bulktransfer bt;
368 int ret;
pbrook4d611c92006-08-12 01:04:27 +0000369 uint8_t devep = p->devep;
bellardbb36d472005-11-05 14:22:28 +0000370
balrogb9dc0332007-10-04 22:47:34 +0000371 if (s->endp_table[p->devep - 1].type == USBDEVFS_URB_TYPE_ISO) {
372 return usb_host_handle_isoch(dev, p);
373 }
374
bellardbb36d472005-11-05 14:22:28 +0000375 /* XXX: optimize and handle all data types by looking at the
376 config descriptor */
pbrook4d611c92006-08-12 01:04:27 +0000377 if (p->pid == USB_TOKEN_IN)
bellardbb36d472005-11-05 14:22:28 +0000378 devep |= 0x80;
379 bt.ep = devep;
pbrook4d611c92006-08-12 01:04:27 +0000380 bt.len = p->len;
bellardbb36d472005-11-05 14:22:28 +0000381 bt.timeout = 50;
pbrook4d611c92006-08-12 01:04:27 +0000382 bt.data = p->data;
bellardbb36d472005-11-05 14:22:28 +0000383 ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
384 if (ret < 0) {
385 switch(errno) {
386 case ETIMEDOUT:
387 return USB_RET_NAK;
388 case EPIPE:
389 default:
390#ifdef DEBUG
391 printf("handle_data: errno=%d\n", errno);
392#endif
393 return USB_RET_STALL;
394 }
395 } else {
396 return ret;
397 }
398}
399
balrog4d043a02007-10-04 22:55:53 +0000400#ifdef USE_ASYNCIO
balrog046833e2007-10-31 00:27:50 +0000401static void urb_completion_pipe_read(void *opaque)
balrog4d043a02007-10-04 22:55:53 +0000402{
balrog046833e2007-10-31 00:27:50 +0000403 USBHostDevice *s = opaque;
balrog4d043a02007-10-04 22:55:53 +0000404 USBPacket *p = s->packet;
balrog046833e2007-10-31 00:27:50 +0000405 PendingURB *pending_urb = NULL;
406 struct usbdevfs_urb *purb = NULL;
407 int len, ret;
balrogb9dc0332007-10-04 22:47:34 +0000408
balrog046833e2007-10-31 00:27:50 +0000409 len = read(s->pipe_fds[0], &pending_urb, sizeof(pending_urb));
410 if (len != sizeof(pending_urb)) {
411 printf("urb_completion: error reading pending_urb, len=%d\n", len);
412 return;
413 }
414
415 /* FIXME: handle pending_urb->status */
balrog4d043a02007-10-04 22:55:53 +0000416 del_pending_urb(pending_urb->urb);
417
418 if (!p) {
419 s->urbs_ready++;
420 return;
421 }
422
423 ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb);
424 if (ret < 0) {
balrog046833e2007-10-31 00:27:50 +0000425 printf("urb_completion: REAPURBNDELAY ioctl=%d errno=%d\n",
balrog4d043a02007-10-04 22:55:53 +0000426 ret, errno);
427 return;
428 }
429
430#ifdef DEBUG_ISOCH
431 if (purb == pending_urb->urb) {
balrog046833e2007-10-31 00:27:50 +0000432 printf("urb_completion: urb mismatch reaped=%p pending=%p\n",
balrog4d043a02007-10-04 22:55:53 +0000433 purb, urb);
434 }
435#endif
436
437 p->len = purb->actual_length;
438 usb_packet_complete(p);
439 qemu_free(purb);
440 s->packet = NULL;
441}
442
443static void isoch_done(int signum, siginfo_t *info, void *context)
444{
balrogb9dc0332007-10-04 22:47:34 +0000445 struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr;
446 USBHostDevice *s = (USBHostDevice *)urb->usercontext;
447 PendingURB *purb;
448
449 if (info->si_code != SI_ASYNCIO ||
450 info->si_signo != SIG_ISOCOMPLETE) {
451 return;
452 }
453
454 purb = get_pending_urb(urb);
455 if (purb) {
balrog046833e2007-10-31 00:27:50 +0000456 purb->status = info->si_errno;
457 write(s->pipe_fds[1], &purb, sizeof(purb));
balrogb9dc0332007-10-04 22:47:34 +0000458 }
459}
balrog4d043a02007-10-04 22:55:53 +0000460#endif
balrogb9dc0332007-10-04 22:47:34 +0000461
462static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p)
463{
464 USBHostDevice *s = (USBHostDevice *)dev;
465 struct usbdevfs_urb *urb, *purb = NULL;
466 int ret;
467 uint8_t devep = p->devep;
468
469 if (p->pid == USB_TOKEN_IN)
470 devep |= 0x80;
471
472 urb = qemu_mallocz(sizeof(struct usbdevfs_urb) +
473 sizeof(struct usbdevfs_iso_packet_desc));
474 if (!urb) {
475 printf("usb_host_handle_isoch: malloc failed\n");
476 return 0;
477 }
478
479 urb->type = USBDEVFS_URB_TYPE_ISO;
480 urb->endpoint = devep;
481 urb->status = 0;
482 urb->flags = USBDEVFS_URB_ISO_ASAP;
483 urb->buffer = p->data;
484 urb->buffer_length = p->len;
485 urb->actual_length = 0;
486 urb->start_frame = 0;
487 urb->error_count = 0;
488#ifdef USE_ASYNCIO
489 urb->signr = SIG_ISOCOMPLETE;
490#else
491 urb->signr = 0;
492#endif
493 urb->usercontext = s;
494 urb->number_of_packets = 1;
495 urb->iso_frame_desc[0].length = p->len;
496 urb->iso_frame_desc[0].actual_length = 0;
497 urb->iso_frame_desc[0].status = 0;
498 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
499 if (ret == 0) {
500 if (!add_pending_urb(urb)) {
501 printf("usb_host_handle_isoch: add_pending_urb failed %p\n", urb);
502 }
503 } else {
504 printf("usb_host_handle_isoch: SUBMITURB ioctl=%d errno=%d\n",
505 ret, errno);
506 qemu_free(urb);
507 switch(errno) {
508 case ETIMEDOUT:
509 return USB_RET_NAK;
510 case EPIPE:
511 default:
512 return USB_RET_STALL;
513 }
514 }
515#ifdef USE_ASYNCIO
516 /* FIXME: handle urbs_ready together with sync io
517 * workaround for injecting the signaled urbs into current frame */
518 if (s->urbs_ready > 0) {
519 ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb);
520 if (ret == 0) {
521 ret = purb->actual_length;
522 qemu_free(purb);
523 s->urbs_ready--;
524 }
525 return ret;
526 }
527 s->packet = p;
528 return USB_RET_ASYNC;
529#else
530 ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb);
531 if (ret == 0) {
532 if (del_pending_urb(purb)) {
533 ret = purb->actual_length;
534 qemu_free(purb);
535 } else {
536 printf("usb_host_handle_isoch: del_pending_urb failed %p\n", purb);
537 }
538 } else {
539#ifdef DEBUG_ISOCH
540 printf("usb_host_handle_isoch: REAPURBNDELAY ioctl=%d errno=%d\n",
541 ret, errno);
542#endif
543 }
544 return ret;
545#endif
546}
547
balrogb9dc0332007-10-04 22:47:34 +0000548/* returns 1 on problem encountered or 0 for success */
549static int usb_linux_update_endp_table(USBHostDevice *s)
550{
551 uint8_t *descriptors;
552 uint8_t devep, type, configuration, alt_interface;
553 struct usb_ctrltransfer ct;
554 int interface, ret, length, i;
555
556 ct.bRequestType = USB_DIR_IN;
557 ct.bRequest = USB_REQ_GET_CONFIGURATION;
558 ct.wValue = 0;
559 ct.wIndex = 0;
560 ct.wLength = 1;
561 ct.data = &configuration;
562 ct.timeout = 50;
563
564 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
565 if (ret < 0) {
566 perror("usb_linux_update_endp_table");
567 return 1;
568 }
569
570 /* in address state */
571 if (configuration == 0)
572 return 1;
573
574 /* get the desired configuration, interface, and endpoint descriptors
575 * from device description */
576 descriptors = &s->descr[18];
577 length = s->descr_len - 18;
578 i = 0;
579
580 if (descriptors[i + 1] != USB_DT_CONFIG ||
581 descriptors[i + 5] != configuration) {
582 printf("invalid descriptor data - configuration\n");
583 return 1;
584 }
585 i += descriptors[i];
586
587 while (i < length) {
588 if (descriptors[i + 1] != USB_DT_INTERFACE ||
589 (descriptors[i + 1] == USB_DT_INTERFACE &&
590 descriptors[i + 4] == 0)) {
591 i += descriptors[i];
592 continue;
593 }
594
595 interface = descriptors[i + 2];
596
597 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
598 ct.bRequest = USB_REQ_GET_INTERFACE;
599 ct.wValue = 0;
600 ct.wIndex = interface;
601 ct.wLength = 1;
602 ct.data = &alt_interface;
603 ct.timeout = 50;
604
605 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
606 if (ret < 0) {
607 perror("usb_linux_update_endp_table");
608 return 1;
609 }
610
611 /* the current interface descriptor is the active interface
612 * and has endpoints */
613 if (descriptors[i + 3] != alt_interface) {
614 i += descriptors[i];
615 continue;
616 }
617
618 /* advance to the endpoints */
619 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT)
620 i += descriptors[i];
621
622 if (i >= length)
623 break;
624
625 while (i < length) {
626 if (descriptors[i + 1] != USB_DT_ENDPOINT)
627 break;
628
629 devep = descriptors[i + 2];
630 switch (descriptors[i + 3] & 0x3) {
631 case 0x00:
632 type = USBDEVFS_URB_TYPE_CONTROL;
633 break;
634 case 0x01:
635 type = USBDEVFS_URB_TYPE_ISO;
636 break;
637 case 0x02:
638 type = USBDEVFS_URB_TYPE_BULK;
639 break;
640 case 0x03:
641 type = USBDEVFS_URB_TYPE_INTERRUPT;
642 break;
643 default:
644 printf("usb_host: malformed endpoint type\n");
645 type = USBDEVFS_URB_TYPE_BULK;
646 }
647 s->endp_table[(devep & 0xf) - 1].type = type;
648
649 i += descriptors[i];
650 }
651 }
652 return 0;
653}
654
aliguori1f3870a2008-08-21 19:27:48 +0000655static void usb_host_device_check(void *priv)
656{
657 USBHostDevice *s = priv;
658 struct usbdevfs_connectinfo ci;
659 int err;
660
661 err = ioctl(s->fd, USBDEVFS_CONNECTINFO, &ci);
662 if (err < 0) {
663 printf("usb device %d.%d disconnected\n", 0, s->dev.addr);
664 usb_device_del_addr(0, s->dev.addr);
665 return;
666 }
667
668 qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
669}
670
aliguori4b096fc2008-08-21 19:28:55 +0000671static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name)
bellardbb36d472005-11-05 14:22:28 +0000672{
balrogb9dc0332007-10-04 22:47:34 +0000673 int fd = -1, ret;
674 USBHostDevice *dev = NULL;
bellardbb36d472005-11-05 14:22:28 +0000675 struct usbdevfs_connectinfo ci;
bellarda594cfb2005-11-06 16:13:29 +0000676 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +0000677
678 dev = qemu_mallocz(sizeof(USBHostDevice));
679 if (!dev)
680 goto fail;
681
aliguori4b096fc2008-08-21 19:28:55 +0000682 dev->bus_num = bus_num;
683 dev->addr = addr;
684
aliguori1f3870a2008-08-21 19:27:48 +0000685 dev->timer = qemu_new_timer(rt_clock, usb_host_device_check, (void *) dev);
686 if (!dev->timer)
687 goto fail;
688
689#ifdef DEBUG
aliguori4b096fc2008-08-21 19:28:55 +0000690 printf("usb_host_device_open %d.%d\n", bus_num, addr);
aliguori1f3870a2008-08-21 19:27:48 +0000691#endif
692
ths5fafdf22007-09-16 21:08:06 +0000693 snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
bellarda594cfb2005-11-06 16:13:29 +0000694 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +0000695 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +0000696 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +0000697 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +0000698 goto fail;
bellardbb36d472005-11-05 14:22:28 +0000699 }
700
balrogb9dc0332007-10-04 22:47:34 +0000701 /* read the device description */
702 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
703 if (dev->descr_len <= 0) {
balrog046833e2007-10-31 00:27:50 +0000704 perror("usb_host_device_open: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +0000705 goto fail;
706 }
ths3b46e622007-09-17 08:09:54 +0000707
balrogb9dc0332007-10-04 22:47:34 +0000708#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +0000709 {
balrogb9dc0332007-10-04 22:47:34 +0000710 int x;
711 printf("=== begin dumping device descriptor data ===\n");
712 for (x = 0; x < dev->descr_len; x++)
713 printf("%02x ", dev->descr[x]);
714 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +0000715 }
716#endif
717
balrogb9dc0332007-10-04 22:47:34 +0000718 dev->fd = fd;
719 dev->configuration = 1;
720
721 /* XXX - do something about initial configuration */
aliguori1f3870a2008-08-21 19:27:48 +0000722 if (!usb_host_update_interfaces(dev, -1))
balrogb9dc0332007-10-04 22:47:34 +0000723 goto fail;
bellardbb36d472005-11-05 14:22:28 +0000724
725 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
726 if (ret < 0) {
balrog046833e2007-10-31 00:27:50 +0000727 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
bellardbb36d472005-11-05 14:22:28 +0000728 goto fail;
729 }
730
731#ifdef DEBUG
bellarda594cfb2005-11-06 16:13:29 +0000732 printf("host USB device %d.%d grabbed\n", bus_num, addr);
ths3b46e622007-09-17 08:09:54 +0000733#endif
bellardbb36d472005-11-05 14:22:28 +0000734
balrogb9dc0332007-10-04 22:47:34 +0000735 ret = usb_linux_update_endp_table(dev);
736 if (ret)
bellardbb36d472005-11-05 14:22:28 +0000737 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000738
bellardbb36d472005-11-05 14:22:28 +0000739 if (ci.slow)
740 dev->dev.speed = USB_SPEED_LOW;
741 else
742 dev->dev.speed = USB_SPEED_HIGH;
bellarda594cfb2005-11-06 16:13:29 +0000743 dev->dev.handle_packet = usb_generic_handle_packet;
bellardbb36d472005-11-05 14:22:28 +0000744
745 dev->dev.handle_reset = usb_host_handle_reset;
746 dev->dev.handle_control = usb_host_handle_control;
747 dev->dev.handle_data = usb_host_handle_data;
bellard059809e2006-07-19 18:06:15 +0000748 dev->dev.handle_destroy = usb_host_handle_destroy;
bellard1f6e24e2006-06-26 21:00:51 +0000749
aliguori4b096fc2008-08-21 19:28:55 +0000750 if (!prod_name || prod_name[0] == '\0')
bellard1f6e24e2006-06-26 21:00:51 +0000751 snprintf(dev->dev.devname, sizeof(dev->dev.devname),
aliguori4b096fc2008-08-21 19:28:55 +0000752 "host:%d.%d", bus_num, addr);
bellard1f6e24e2006-06-26 21:00:51 +0000753 else
754 pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
aliguori4b096fc2008-08-21 19:28:55 +0000755 prod_name);
bellard1f6e24e2006-06-26 21:00:51 +0000756
balrogb9dc0332007-10-04 22:47:34 +0000757#ifdef USE_ASYNCIO
758 /* set up the signal handlers */
759 sigemptyset(&sigact.sa_mask);
760 sigact.sa_sigaction = isoch_done;
761 sigact.sa_flags = SA_SIGINFO;
762 sigact.sa_restorer = 0;
763 ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL);
764 if (ret < 0) {
balrog046833e2007-10-31 00:27:50 +0000765 perror("usb_host_device_open: sigaction failed");
766 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000767 }
balrog046833e2007-10-31 00:27:50 +0000768
769 if (pipe(dev->pipe_fds) < 0) {
770 perror("usb_host_device_open: pipe creation failed");
771 goto fail;
772 }
773 fcntl(dev->pipe_fds[0], F_SETFL, O_NONBLOCK | O_ASYNC);
774 fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK);
775 qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev);
balrogb9dc0332007-10-04 22:47:34 +0000776#endif
aliguori1f3870a2008-08-21 19:27:48 +0000777
778 /* Start the timer to detect disconnect */
779 qemu_mod_timer(dev->timer, qemu_get_clock(rt_clock) + 1000);
780
aliguori4b096fc2008-08-21 19:28:55 +0000781 hostdev_link(dev);
782
balrogb9dc0332007-10-04 22:47:34 +0000783 dev->urbs_ready = 0;
bellarda594cfb2005-11-06 16:13:29 +0000784 return (USBDevice *)dev;
aliguori4b096fc2008-08-21 19:28:55 +0000785
balrogb9dc0332007-10-04 22:47:34 +0000786fail:
aliguori1f3870a2008-08-21 19:27:48 +0000787 if (dev) {
788 if (dev->timer)
789 qemu_del_timer(dev->timer);
balrogb9dc0332007-10-04 22:47:34 +0000790 qemu_free(dev);
aliguori1f3870a2008-08-21 19:27:48 +0000791 }
balrogb9dc0332007-10-04 22:47:34 +0000792 close(fd);
793 return NULL;
bellardbb36d472005-11-05 14:22:28 +0000794}
795
aliguori4b096fc2008-08-21 19:28:55 +0000796USBDevice *usb_host_device_open(const char *devname)
797{
798 int bus_num, addr;
799 char product_name[PRODUCT_NAME_SZ];
800
801 if (usb_host_find_device(&bus_num, &addr,
802 product_name, sizeof(product_name),
803 devname) < 0)
804 return NULL;
805
806 if (hostdev_find(bus_num, addr)) {
807 printf("host usb device %d.%d is already open\n", bus_num, addr);
808 return NULL;
809 }
810
811 return usb_host_device_open_addr(bus_num, addr, product_name);
812}
813
bellarda594cfb2005-11-06 16:13:29 +0000814static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +0000815 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +0000816 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +0000817{
bellarda594cfb2005-11-06 16:13:29 +0000818 const char *p;
819 char *q;
820 p = strstr(str, tag);
821 if (!p)
822 return -1;
823 p += strlen(tag);
824 while (isspace(*p))
825 p++;
826 q = buf;
827 while (*p != '\0' && !strchr(stopchars, *p)) {
828 if ((q - buf) < (buf_size - 1))
829 *q++ = *p;
830 p++;
831 }
832 *q = '\0';
833 return q - buf;
834}
bellardbb36d472005-11-05 14:22:28 +0000835
bellarda594cfb2005-11-06 16:13:29 +0000836static int usb_host_scan(void *opaque, USBScanFunc *func)
837{
838 FILE *f;
839 char line[1024];
840 char buf[1024];
841 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
842 int ret;
843 char product_name[512];
ths3b46e622007-09-17 08:09:54 +0000844
bellarda594cfb2005-11-06 16:13:29 +0000845 f = fopen(USBDEVFS_PATH "/devices", "r");
846 if (!f) {
847 term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
848 return 0;
849 }
850 device_count = 0;
851 bus_num = addr = speed = class_id = product_id = vendor_id = 0;
852 ret = 0;
bellardbb36d472005-11-05 14:22:28 +0000853 for(;;) {
bellarda594cfb2005-11-06 16:13:29 +0000854 if (fgets(line, sizeof(line), f) == NULL)
bellardbb36d472005-11-05 14:22:28 +0000855 break;
bellarda594cfb2005-11-06 16:13:29 +0000856 if (strlen(line) > 0)
857 line[strlen(line) - 1] = '\0';
858 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +0000859 if (device_count && (vendor_id || product_id)) {
860 /* New device. Add the previously discovered device. */
ths5fafdf22007-09-16 21:08:06 +0000861 ret = func(opaque, bus_num, addr, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +0000862 product_id, product_name, speed);
863 if (ret)
864 goto the_end;
865 }
866 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
867 goto fail;
868 bus_num = atoi(buf);
869 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
870 goto fail;
871 addr = atoi(buf);
872 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
873 goto fail;
874 if (!strcmp(buf, "480"))
875 speed = USB_SPEED_HIGH;
876 else if (!strcmp(buf, "1.5"))
877 speed = USB_SPEED_LOW;
878 else
879 speed = USB_SPEED_FULL;
880 product_name[0] = '\0';
881 class_id = 0xff;
882 device_count++;
883 product_id = 0;
884 vendor_id = 0;
885 } else if (line[0] == 'P' && line[1] == ':') {
886 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
887 goto fail;
888 vendor_id = strtoul(buf, NULL, 16);
889 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
890 goto fail;
891 product_id = strtoul(buf, NULL, 16);
892 } else if (line[0] == 'S' && line[1] == ':') {
893 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
894 goto fail;
895 pstrcpy(product_name, sizeof(product_name), buf);
896 } else if (line[0] == 'D' && line[1] == ':') {
897 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
898 goto fail;
899 class_id = strtoul(buf, NULL, 16);
900 }
901 fail: ;
902 }
pbrook38ca0f62006-03-11 18:03:38 +0000903 if (device_count && (vendor_id || product_id)) {
904 /* Add the last device. */
ths5fafdf22007-09-16 21:08:06 +0000905 ret = func(opaque, bus_num, addr, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +0000906 product_id, product_name, speed);
907 }
908 the_end:
909 fclose(f);
910 return ret;
911}
912
aliguori4b096fc2008-08-21 19:28:55 +0000913struct USBAutoFilter {
914 struct USBAutoFilter *next;
915 int bus_num;
916 int addr;
917 int vendor_id;
918 int product_id;
919};
920
921static QEMUTimer *usb_auto_timer;
922static struct USBAutoFilter *usb_auto_filter;
923
924static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
925 int class_id, int vendor_id, int product_id,
926 const char *product_name, int speed)
927{
928 struct USBAutoFilter *f;
929 struct USBDevice *dev;
930
931 /* Ignore hubs */
932 if (class_id == 9)
933 return 0;
934
935 for (f = usb_auto_filter; f; f = f->next) {
936 // printf("Auto match: bus_num %d addr %d vid %d pid %d\n",
937 // bus_num, addr, vendor_id, product_id);
938
939 if (f->bus_num >= 0 && f->bus_num != bus_num)
940 continue;
941
942 if (f->addr >= 0 && f->addr != addr)
943 continue;
944
945 if (f->vendor_id >= 0 && f->vendor_id != vendor_id)
946 continue;
947
948 if (f->product_id >= 0 && f->product_id != product_id)
949 continue;
950
951 /* We got a match */
952
953 /* Allredy attached ? */
954 if (hostdev_find(bus_num, addr))
955 return 0;
956
957 printf("Auto open: bus_num %d addr %d\n", bus_num, addr);
958
959 dev = usb_host_device_open_addr(bus_num, addr, product_name);
960 if (dev)
961 usb_device_add_dev(dev);
962 }
963
964 return 0;
965}
966
967static void usb_host_auto_timer(void *unused)
968{
969 usb_host_scan(NULL, usb_host_auto_scan);
970 qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
971}
972
973/*
974 * Add autoconnect filter
975 * -1 means 'any' (device, vendor, etc)
976 */
977static void usb_host_auto_add(int bus_num, int addr, int vendor_id, int product_id)
978{
979 struct USBAutoFilter *f = qemu_mallocz(sizeof(*f));
980 if (!f) {
981 printf("Failed to allocate auto filter\n");
982 return;
983 }
984
985 f->bus_num = bus_num;
986 f->addr = addr;
987 f->vendor_id = vendor_id;
988 f->product_id = product_id;
989
990 if (!usb_auto_filter) {
991 /*
992 * First entry. Init and start the monitor.
993 * Right now we're using timer to check for new devices.
994 * If this turns out to be too expensive we can move that into a
995 * separate thread.
996 */
997 usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_timer, NULL);
998 if (!usb_auto_timer) {
999 printf("Failed to allocate timer\n");
1000 qemu_free(f);
1001 return;
1002 }
1003
1004 /* Check for new devices every two seconds */
1005 qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
1006 }
1007
1008 printf("Auto filter: bus_num %d addr %d vid %d pid %d\n",
1009 bus_num, addr, vendor_id, product_id);
1010
1011 f->next = usb_auto_filter;
1012 usb_auto_filter = f;
1013}
1014
bellarda594cfb2005-11-06 16:13:29 +00001015typedef struct FindDeviceState {
1016 int vendor_id;
1017 int product_id;
1018 int bus_num;
1019 int addr;
bellard1f6e24e2006-06-26 21:00:51 +00001020 char product_name[PRODUCT_NAME_SZ];
bellarda594cfb2005-11-06 16:13:29 +00001021} FindDeviceState;
1022
ths5fafdf22007-09-16 21:08:06 +00001023static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
bellarda594cfb2005-11-06 16:13:29 +00001024 int class_id,
ths5fafdf22007-09-16 21:08:06 +00001025 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001026 const char *product_name, int speed)
1027{
1028 FindDeviceState *s = opaque;
bellard1f6e24e2006-06-26 21:00:51 +00001029 if ((vendor_id == s->vendor_id &&
1030 product_id == s->product_id) ||
1031 (bus_num == s->bus_num &&
1032 addr == s->addr)) {
1033 pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name);
bellarda594cfb2005-11-06 16:13:29 +00001034 s->bus_num = bus_num;
1035 s->addr = addr;
1036 return 1;
1037 } else {
1038 return 0;
1039 }
1040}
1041
ths5fafdf22007-09-16 21:08:06 +00001042/* the syntax is :
1043 'bus.addr' (decimal numbers) or
bellarda594cfb2005-11-06 16:13:29 +00001044 'vendor_id:product_id' (hexa numbers) */
ths5fafdf22007-09-16 21:08:06 +00001045static int usb_host_find_device(int *pbus_num, int *paddr,
bellard1f6e24e2006-06-26 21:00:51 +00001046 char *product_name, int product_name_size,
bellarda594cfb2005-11-06 16:13:29 +00001047 const char *devname)
1048{
1049 const char *p;
1050 int ret;
1051 FindDeviceState fs;
1052
1053 p = strchr(devname, '.');
1054 if (p) {
1055 *pbus_num = strtoul(devname, NULL, 0);
aliguori4b096fc2008-08-21 19:28:55 +00001056
1057 if (*(p + 1) == '*') {
1058 usb_host_auto_add(*pbus_num, -1, -1, -1);
1059 return -1;
1060 }
1061
bellarda594cfb2005-11-06 16:13:29 +00001062 *paddr = strtoul(p + 1, NULL, 0);
bellard1f6e24e2006-06-26 21:00:51 +00001063 fs.bus_num = *pbus_num;
1064 fs.addr = *paddr;
1065 ret = usb_host_scan(&fs, usb_host_find_device_scan);
1066 if (ret)
1067 pstrcpy(product_name, product_name_size, fs.product_name);
bellarda594cfb2005-11-06 16:13:29 +00001068 return 0;
1069 }
1070 p = strchr(devname, ':');
1071 if (p) {
1072 fs.vendor_id = strtoul(devname, NULL, 16);
aliguori4b096fc2008-08-21 19:28:55 +00001073
1074 if (*(p + 1) == '*') {
1075 usb_host_auto_add(-1, -1, fs.vendor_id, -1);
1076 return -1;
1077 }
1078
bellarda594cfb2005-11-06 16:13:29 +00001079 fs.product_id = strtoul(p + 1, NULL, 16);
1080 ret = usb_host_scan(&fs, usb_host_find_device_scan);
1081 if (ret) {
1082 *pbus_num = fs.bus_num;
1083 *paddr = fs.addr;
bellard1f6e24e2006-06-26 21:00:51 +00001084 pstrcpy(product_name, product_name_size, fs.product_name);
bellarda594cfb2005-11-06 16:13:29 +00001085 return 0;
bellardbb36d472005-11-05 14:22:28 +00001086 }
1087 }
bellarda594cfb2005-11-06 16:13:29 +00001088 return -1;
bellardbb36d472005-11-05 14:22:28 +00001089}
1090
bellarda594cfb2005-11-06 16:13:29 +00001091/**********************/
1092/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001093
bellarda594cfb2005-11-06 16:13:29 +00001094struct usb_class_info {
1095 int class;
1096 const char *class_name;
1097};
1098
1099static const struct usb_class_info usb_class_info[] = {
1100 { USB_CLASS_AUDIO, "Audio"},
1101 { USB_CLASS_COMM, "Communication"},
1102 { USB_CLASS_HID, "HID"},
1103 { USB_CLASS_HUB, "Hub" },
1104 { USB_CLASS_PHYSICAL, "Physical" },
1105 { USB_CLASS_PRINTER, "Printer" },
1106 { USB_CLASS_MASS_STORAGE, "Storage" },
1107 { USB_CLASS_CDC_DATA, "Data" },
1108 { USB_CLASS_APP_SPEC, "Application Specific" },
1109 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1110 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001111 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001112 { USB_CLASS_CONTENT_SEC, "Content Security" },
1113 { -1, NULL }
1114};
1115
1116static const char *usb_class_str(uint8_t class)
1117{
1118 const struct usb_class_info *p;
1119 for(p = usb_class_info; p->class != -1; p++) {
1120 if (p->class == class)
bellardbb36d472005-11-05 14:22:28 +00001121 break;
bellardbb36d472005-11-05 14:22:28 +00001122 }
bellarda594cfb2005-11-06 16:13:29 +00001123 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001124}
1125
pbrook9596ebb2007-11-18 01:44:38 +00001126static void usb_info_device(int bus_num, int addr, int class_id,
1127 int vendor_id, int product_id,
1128 const char *product_name,
1129 int speed)
bellardbb36d472005-11-05 14:22:28 +00001130{
bellarda594cfb2005-11-06 16:13:29 +00001131 const char *class_str, *speed_str;
1132
1133 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001134 case USB_SPEED_LOW:
1135 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001136 break;
ths5fafdf22007-09-16 21:08:06 +00001137 case USB_SPEED_FULL:
1138 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001139 break;
ths5fafdf22007-09-16 21:08:06 +00001140 case USB_SPEED_HIGH:
1141 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001142 break;
1143 default:
ths5fafdf22007-09-16 21:08:06 +00001144 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001145 break;
bellardbb36d472005-11-05 14:22:28 +00001146 }
bellarda594cfb2005-11-06 16:13:29 +00001147
ths5fafdf22007-09-16 21:08:06 +00001148 term_printf(" Device %d.%d, speed %s Mb/s\n",
bellarda594cfb2005-11-06 16:13:29 +00001149 bus_num, addr, speed_str);
1150 class_str = usb_class_str(class_id);
ths5fafdf22007-09-16 21:08:06 +00001151 if (class_str)
bellarda594cfb2005-11-06 16:13:29 +00001152 term_printf(" %s:", class_str);
1153 else
1154 term_printf(" Class %02x:", class_id);
1155 term_printf(" USB device %04x:%04x", vendor_id, product_id);
1156 if (product_name[0] != '\0')
1157 term_printf(", %s", product_name);
1158 term_printf("\n");
1159}
1160
ths5fafdf22007-09-16 21:08:06 +00001161static int usb_host_info_device(void *opaque, int bus_num, int addr,
bellarda594cfb2005-11-06 16:13:29 +00001162 int class_id,
ths5fafdf22007-09-16 21:08:06 +00001163 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001164 const char *product_name,
1165 int speed)
1166{
1167 usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
1168 product_name, speed);
1169 return 0;
1170}
1171
1172void usb_host_info(void)
1173{
1174 usb_host_scan(NULL, usb_host_info_device);
bellardbb36d472005-11-05 14:22:28 +00001175}
1176
aliguori4b096fc2008-08-21 19:28:55 +00001177
1178
1179
bellardbb36d472005-11-05 14:22:28 +00001180#else
1181
bellarda594cfb2005-11-06 16:13:29 +00001182void usb_host_info(void)
1183{
1184 term_printf("USB host devices not supported\n");
1185}
1186
bellardbb36d472005-11-05 14:22:28 +00001187/* XXX: modify configure to compile the right host driver */
bellarda594cfb2005-11-06 16:13:29 +00001188USBDevice *usb_host_device_open(const char *devname)
bellardbb36d472005-11-05 14:22:28 +00001189{
1190 return NULL;
1191}
1192
1193#endif