2 * BSD host USB redirector
4 * Copyright (c) 2006 Lonnie Mendez
5 * Portions of code and concepts borrowed from
6 * usb-linux.c and libusb's bsd.c and are copyright their respective owners.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include "qemu-common.h"
31 /* usb.h declares these */
36 #include <sys/ioctl.h>
38 #include <dev/usb/usb.h>
40 #include <bus/usb/usb.h>
44 /* This value has maximum potential at 16.
45 * You should also set hw.usb.debug to gain
49 #define UGEN_DEBUG_LEVEL 0
52 typedef int USBScanFunc(void *opaque
, int bus_num
, int addr
, int class_id
,
53 int vendor_id
, int product_id
,
54 const char *product_name
, int speed
);
55 static int usb_host_find_device(int *pbus_num
, int *paddr
,
58 typedef struct USBHostDevice
{
60 int ep_fd
[USB_MAX_ENDPOINTS
];
67 static int ensure_ep_open(USBHostDevice
*dev
, int ep
, int mode
)
72 /* Get the address for this endpoint */
75 if (dev
->ep_fd
[ep
] < 0) {
76 #if defined(__FreeBSD__) || defined(__DragonFly__)
77 snprintf(buf
, sizeof(buf
) - 1, "%s.%d", dev
->devpath
, ep
);
79 snprintf(buf
, sizeof(buf
) - 1, "%s.%02d", dev
->devpath
, ep
);
81 /* Try to open it O_RDWR first for those devices which have in and out
82 * endpoints with the same address (eg 0x02 and 0x82)
84 fd
= open(buf
, O_RDWR
);
85 if (fd
< 0 && errno
== ENXIO
)
89 printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
90 buf
, strerror(errno
));
96 return dev
->ep_fd
[ep
];
99 static void ensure_eps_closed(USBHostDevice
*dev
)
106 while (epnum
< USB_MAX_ENDPOINTS
) {
107 if (dev
->ep_fd
[epnum
] >= 0) {
108 close(dev
->ep_fd
[epnum
]);
109 dev
->ep_fd
[epnum
] = -1;
116 static void usb_host_handle_reset(USBDevice
*dev
)
119 USBHostDevice
*s
= (USBHostDevice
*)dev
;
125 * -check device states against transfer requests
126 * and return appropriate response
128 static int usb_host_handle_control(USBDevice
*dev
,
135 USBHostDevice
*s
= (USBHostDevice
*)dev
;
136 struct usb_ctl_request req
;
137 struct usb_alt_interface aiface
;
138 int ret
, timeout
= 50;
140 if ((request
>> 8) == UT_WRITE_DEVICE
&&
141 (request
& 0xff) == UR_SET_ADDRESS
) {
143 /* specific SET_ADDRESS support */
146 } else if ((request
>> 8) == UT_WRITE_DEVICE
&&
147 (request
& 0xff) == UR_SET_CONFIG
) {
149 ensure_eps_closed(s
); /* can't do this without all eps closed */
151 ret
= ioctl(s
->devfd
, USB_SET_CONFIG
, &value
);
154 printf("handle_control: failed to set configuration - %s\n",
157 return USB_RET_STALL
;
161 } else if ((request
>> 8) == UT_WRITE_INTERFACE
&&
162 (request
& 0xff) == UR_SET_INTERFACE
) {
164 aiface
.uai_interface_index
= index
;
165 aiface
.uai_alt_no
= value
;
167 ensure_eps_closed(s
); /* can't do this without all eps closed */
168 ret
= ioctl(s
->devfd
, USB_SET_ALTINTERFACE
, &aiface
);
171 printf("handle_control: failed to set alternate interface - %s\n",
174 return USB_RET_STALL
;
179 req
.ucr_request
.bmRequestType
= request
>> 8;
180 req
.ucr_request
.bRequest
= request
& 0xff;
181 USETW(req
.ucr_request
.wValue
, value
);
182 USETW(req
.ucr_request
.wIndex
, index
);
183 USETW(req
.ucr_request
.wLength
, length
);
185 req
.ucr_flags
= USBD_SHORT_XFER_OK
;
187 ret
= ioctl(s
->devfd
, USB_SET_TIMEOUT
, &timeout
);
188 #if defined(__NetBSD__) || defined(__OpenBSD__)
189 if (ret
< 0 && errno
!= EINVAL
) {
194 printf("handle_control: setting timeout failed - %s\n",
199 ret
= ioctl(s
->devfd
, USB_DO_REQUEST
, &req
);
200 /* ugen returns EIO for usbd_do_request_ no matter what
201 * happens with the transfer */
204 printf("handle_control: error after request - %s\n",
207 return USB_RET_NAK
; // STALL
209 return req
.ucr_actlen
;
214 static int usb_host_handle_data(USBDevice
*dev
, USBPacket
*p
)
216 USBHostDevice
*s
= (USBHostDevice
*)dev
;
218 int one
= 1, shortpacket
= 0, timeout
= 50;
219 sigset_t new_mask
, old_mask
;
220 uint8_t devep
= p
->devep
;
222 /* protect data transfers from SIGALRM signal */
223 sigemptyset(&new_mask
);
224 sigaddset(&new_mask
, SIGALRM
);
225 sigprocmask(SIG_BLOCK
, &new_mask
, &old_mask
);
227 if (p
->pid
== USB_TOKEN_IN
) {
235 fd
= ensure_ep_open(s
, devep
, mode
);
237 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
238 return USB_RET_NODEV
;
241 if (ioctl(fd
, USB_SET_TIMEOUT
, &timeout
) < 0) {
243 printf("handle_data: failed to set timeout - %s\n",
249 if (ioctl(fd
, USB_SET_SHORT_XFER
, &one
) < 0) {
251 printf("handle_data: failed to set short xfer mode - %s\n",
254 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
258 if (p
->pid
== USB_TOKEN_IN
)
259 ret
= read(fd
, p
->data
, p
->len
);
261 ret
= write(fd
, p
->data
, p
->len
);
263 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
267 printf("handle_data: error after %s data - %s\n",
268 pid
== USB_TOKEN_IN
? "reading" : "writing", strerror(errno
));
275 return USB_RET_STALL
;
283 static void usb_host_handle_destroy(USBDevice
*opaque
)
285 USBHostDevice
*s
= (USBHostDevice
*)opaque
;
288 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
289 if (s
->ep_fd
[i
] >= 0)
300 static int usb_host_initfn(USBDevice
*dev
)
305 USBDevice
*usb_host_device_open(const char *devname
)
307 struct usb_device_info bus_info
, dev_info
;
309 USBHostDevice
*dev
, *ret
= NULL
;
310 char ctlpath
[PATH_MAX
+ 1];
311 char buspath
[PATH_MAX
+ 1];
312 int bfd
, dfd
, bus
, address
, i
;
313 int ugendebug
= UGEN_DEBUG_LEVEL
;
315 if (usb_host_find_device(&bus
, &address
, devname
) < 0) {
319 snprintf(buspath
, PATH_MAX
, "/dev/usb%d", bus
);
321 bfd
= open(buspath
, O_RDWR
);
324 printf("usb_host_device_open: failed to open usb bus - %s\n",
330 bus_info
.udi_addr
= address
;
331 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0) {
333 printf("usb_host_device_open: failed to grab bus information - %s\n",
339 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
340 snprintf(ctlpath
, PATH_MAX
, "/dev/%s", bus_info
.udi_devnames
[0]);
342 snprintf(ctlpath
, PATH_MAX
, "/dev/%s.00", bus_info
.udi_devnames
[0]);
345 dfd
= open(ctlpath
, O_RDWR
);
347 dfd
= open(ctlpath
, O_RDONLY
);
350 printf("usb_host_device_open: failed to open usb device %s - %s\n",
351 ctlpath
, strerror(errno
));
357 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0) {
359 printf("usb_host_device_open: failed to grab device info - %s\n",
365 d
= usb_create(NULL
/* FIXME */, "usb-host");
366 dev
= DO_UPCAST(USBHostDevice
, dev
, d
);
368 if (dev_info
.udi_speed
== 1) {
369 dev
->dev
.speed
= USB_SPEED_LOW
- 1;
371 dev
->dev
.speed
= USB_SPEED_FULL
- 1;
374 if (strncmp(dev_info
.udi_product
, "product", 7) != 0) {
375 pstrcpy(dev
->dev
.product_desc
, sizeof(dev
->dev
.product_desc
),
376 dev_info
.udi_product
);
378 snprintf(dev
->dev
.product_desc
, sizeof(dev
->dev
.product_desc
),
382 pstrcpy(dev
->devpath
, sizeof(dev
->devpath
), "/dev/");
383 pstrcat(dev
->devpath
, sizeof(dev
->devpath
), dev_info
.udi_devnames
[0]);
385 /* Mark the endpoints as not yet open */
386 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++) {
390 ioctl(dfd
, USB_SETDEBUG
, &ugendebug
);
392 ret
= (USBDevice
*)dev
;
402 static struct USBDeviceInfo usb_host_dev_info
= {
403 .product_desc
= "USB Host Device",
404 .qdev
.name
= "usb-host",
405 .qdev
.size
= sizeof(USBHostDevice
),
406 .init
= usb_host_initfn
,
407 .handle_packet
= usb_generic_handle_packet
,
408 .handle_reset
= usb_host_handle_reset
,
410 .handle_control
= usb_host_handle_control
,
411 .handle_data
= usb_host_handle_data
,
413 .handle_destroy
= usb_host_handle_destroy
,
416 static void usb_host_register_devices(void)
418 usb_qdev_register(&usb_host_dev_info
);
420 device_init(usb_host_register_devices
)
422 static int usb_host_scan(void *opaque
, USBScanFunc
*func
)
424 struct usb_device_info bus_info
;
425 struct usb_device_info dev_info
;
426 uint16_t vendor_id
, product_id
, class_id
, speed
;
427 int bfd
, dfd
, bus
, address
;
428 char busbuf
[20], devbuf
[20], product_name
[256];
431 for (bus
= 0; bus
< 10; bus
++) {
433 snprintf(busbuf
, sizeof(busbuf
) - 1, "/dev/usb%d", bus
);
434 bfd
= open(busbuf
, O_RDWR
);
438 for (address
= 1; address
< 127; address
++) {
440 bus_info
.udi_addr
= address
;
441 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0)
444 /* only list devices that can be used by generic layer */
445 if (strncmp(bus_info
.udi_devnames
[0], "ugen", 4) != 0)
448 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
449 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s", bus_info
.udi_devnames
[0]);
451 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s.00", bus_info
.udi_devnames
[0]);
454 dfd
= open(devbuf
, O_RDONLY
);
457 printf("usb_host_scan: couldn't open device %s - %s\n", devbuf
,
463 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0)
464 printf("usb_host_scan: couldn't get device information for %s - %s\n",
465 devbuf
, strerror(errno
));
467 /* XXX: might need to fixup endianness of word values before copying over */
469 vendor_id
= dev_info
.udi_vendorNo
;
470 product_id
= dev_info
.udi_productNo
;
471 class_id
= dev_info
.udi_class
;
472 speed
= dev_info
.udi_speed
;
474 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
475 pstrcpy(product_name
, sizeof(product_name
),
476 dev_info
.udi_product
);
478 product_name
[0] = '\0';
480 ret
= func(opaque
, bus
, address
, class_id
, vendor_id
,
481 product_id
, product_name
, speed
);
496 typedef struct FindDeviceState
{
503 static int usb_host_find_device_scan(void *opaque
, int bus_num
, int addr
,
505 int vendor_id
, int product_id
,
506 const char *product_name
, int speed
)
508 FindDeviceState
*s
= opaque
;
509 if (vendor_id
== s
->vendor_id
&&
510 product_id
== s
->product_id
) {
511 s
->bus_num
= bus_num
;
521 'bus.addr' (decimal numbers) or
522 'vendor_id:product_id' (hexa numbers) */
523 static int usb_host_find_device(int *pbus_num
, int *paddr
,
530 p
= strchr(devname
, '.');
532 *pbus_num
= strtoul(devname
, NULL
, 0);
533 *paddr
= strtoul(p
+ 1, NULL
, 0);
536 p
= strchr(devname
, ':');
538 fs
.vendor_id
= strtoul(devname
, NULL
, 16);
539 fs
.product_id
= strtoul(p
+ 1, NULL
, 16);
540 ret
= usb_host_scan(&fs
, usb_host_find_device_scan
);
542 *pbus_num
= fs
.bus_num
;
550 /**********************/
551 /* USB host device info */
553 struct usb_class_info
{
555 const char *class_name
;
558 static const struct usb_class_info usb_class_info
[] = {
559 { USB_CLASS_AUDIO
, "Audio"},
560 { USB_CLASS_COMM
, "Communication"},
561 { USB_CLASS_HID
, "HID"},
562 { USB_CLASS_HUB
, "Hub" },
563 { USB_CLASS_PHYSICAL
, "Physical" },
564 { USB_CLASS_PRINTER
, "Printer" },
565 { USB_CLASS_MASS_STORAGE
, "Storage" },
566 { USB_CLASS_CDC_DATA
, "Data" },
567 { USB_CLASS_APP_SPEC
, "Application Specific" },
568 { USB_CLASS_VENDOR_SPEC
, "Vendor Specific" },
569 { USB_CLASS_STILL_IMAGE
, "Still Image" },
570 { USB_CLASS_CSCID
, "Smart Card" },
571 { USB_CLASS_CONTENT_SEC
, "Content Security" },
575 static const char *usb_class_str(uint8_t class)
577 const struct usb_class_info
*p
;
578 for (p
= usb_class_info
; p
->class != -1; p
++) {
579 if (p
->class == class)
582 return p
->class_name
;
585 static void usb_info_device(Monitor
*mon
, int bus_num
, int addr
, int class_id
,
586 int vendor_id
, int product_id
,
587 const char *product_name
,
590 const char *class_str
, *speed_str
;
607 monitor_printf(mon
, " Device %d.%d, speed %s Mb/s\n",
608 bus_num
, addr
, speed_str
);
609 class_str
= usb_class_str(class_id
);
611 monitor_printf(mon
, " %s:", class_str
);
613 monitor_printf(mon
, " Class %02x:", class_id
);
614 monitor_printf(mon
, " USB device %04x:%04x", vendor_id
, product_id
);
615 if (product_name
[0] != '\0')
616 monitor_printf(mon
, ", %s", product_name
);
617 monitor_printf(mon
, "\n");
620 static int usb_host_info_device(void *opaque
,
621 int bus_num
, int addr
,
623 int vendor_id
, int product_id
,
624 const char *product_name
,
627 Monitor
*mon
= opaque
;
629 usb_info_device(mon
, bus_num
, addr
, class_id
, vendor_id
, product_id
,
630 product_name
, speed
);
634 void usb_host_info(Monitor
*mon
)
636 usb_host_scan(mon
, usb_host_info_device
);
640 int usb_host_device_close(const char *devname
)