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
;
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)
318 snprintf(buspath
, PATH_MAX
, "/dev/usb%d", bus
);
320 bfd
= open(buspath
, O_RDWR
);
323 printf("usb_host_device_open: failed to open usb bus - %s\n",
329 bus_info
.udi_addr
= address
;
330 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0) {
332 printf("usb_host_device_open: failed to grab bus information - %s\n",
338 #if defined(__FreeBSD__) || defined(__DragonFly__)
339 snprintf(ctlpath
, PATH_MAX
, "/dev/%s", bus_info
.udi_devnames
[0]);
341 snprintf(ctlpath
, PATH_MAX
, "/dev/%s.00", bus_info
.udi_devnames
[0]);
344 dfd
= open(ctlpath
, O_RDWR
);
346 dfd
= open(ctlpath
, O_RDONLY
);
349 printf("usb_host_device_open: failed to open usb device %s - %s\n",
350 ctlpath
, strerror(errno
));
356 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0) {
358 printf("usb_host_device_open: failed to grab device info - %s\n",
364 d
= usb_create(NULL
/* FIXME */, "USB Host Device");
365 dev
= DO_UPCAST(USBHostDevice
, dev
, d
);
367 if (dev_info
.udi_speed
== 1)
368 dev
->dev
.speed
= USB_SPEED_LOW
- 1;
370 dev
->dev
.speed
= USB_SPEED_FULL
- 1;
372 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
373 pstrcpy(dev
->dev
.devname
, sizeof(dev
->dev
.devname
),
374 dev_info
.udi_product
);
376 snprintf(dev
->dev
.devname
, sizeof(dev
->dev
.devname
),
379 pstrcpy(dev
->devpath
, sizeof(dev
->devpath
), "/dev/");
380 pstrcat(dev
->devpath
, sizeof(dev
->devpath
), dev_info
.udi_devnames
[0]);
382 /* Mark the endpoints as not yet open */
383 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
386 ioctl(dfd
, USB_SETDEBUG
, &ugendebug
);
388 return (USBDevice
*)dev
;
395 static struct USBDeviceInfo usb_host_dev_info
= {
396 .qdev
.name
= "USB Host Device",
397 .qdev
.size
= sizeof(USBHostDevice
),
398 .init
= usb_host_initfn
,
399 .handle_packet
= usb_generic_handle_packet
,
400 .handle_reset
= usb_host_handle_reset
,
402 .handle_control
= usb_host_handle_control
,
403 .handle_data
= usb_host_handle_data
,
405 .handle_destroy
= usb_host_handle_destroy
,
408 static void usb_host_register_devices(void)
410 usb_qdev_register(&usb_host_dev_info
);
412 device_init(usb_host_register_devices
)
414 static int usb_host_scan(void *opaque
, USBScanFunc
*func
)
416 struct usb_device_info bus_info
;
417 struct usb_device_info dev_info
;
418 uint16_t vendor_id
, product_id
, class_id
, speed
;
419 int bfd
, dfd
, bus
, address
;
420 char busbuf
[20], devbuf
[20], product_name
[256];
423 for (bus
= 0; bus
< 10; bus
++) {
425 snprintf(busbuf
, sizeof(busbuf
) - 1, "/dev/usb%d", bus
);
426 bfd
= open(busbuf
, O_RDWR
);
430 for (address
= 1; address
< 127; address
++) {
432 bus_info
.udi_addr
= address
;
433 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0)
436 /* only list devices that can be used by generic layer */
437 if (strncmp(bus_info
.udi_devnames
[0], "ugen", 4) != 0)
440 #if defined(__FreeBSD__) || defined(__DragonFly__)
441 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s", bus_info
.udi_devnames
[0]);
443 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s.00", bus_info
.udi_devnames
[0]);
446 dfd
= open(devbuf
, O_RDONLY
);
449 printf("usb_host_scan: couldn't open device %s - %s\n", devbuf
,
455 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0)
456 printf("usb_host_scan: couldn't get device information for %s - %s\n",
457 devbuf
, strerror(errno
));
459 // XXX: might need to fixup endianess of word values before copying over
461 vendor_id
= dev_info
.udi_vendorNo
;
462 product_id
= dev_info
.udi_productNo
;
463 class_id
= dev_info
.udi_class
;
464 speed
= dev_info
.udi_speed
;
466 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
467 pstrcpy(product_name
, sizeof(product_name
),
468 dev_info
.udi_product
);
470 product_name
[0] = '\0';
472 ret
= func(opaque
, bus
, address
, class_id
, vendor_id
,
473 product_id
, product_name
, speed
);
488 typedef struct FindDeviceState
{
495 static int usb_host_find_device_scan(void *opaque
, int bus_num
, int addr
,
497 int vendor_id
, int product_id
,
498 const char *product_name
, int speed
)
500 FindDeviceState
*s
= opaque
;
501 if (vendor_id
== s
->vendor_id
&&
502 product_id
== s
->product_id
) {
503 s
->bus_num
= bus_num
;
513 'bus.addr' (decimal numbers) or
514 'vendor_id:product_id' (hexa numbers) */
515 static int usb_host_find_device(int *pbus_num
, int *paddr
,
522 p
= strchr(devname
, '.');
524 *pbus_num
= strtoul(devname
, NULL
, 0);
525 *paddr
= strtoul(p
+ 1, NULL
, 0);
528 p
= strchr(devname
, ':');
530 fs
.vendor_id
= strtoul(devname
, NULL
, 16);
531 fs
.product_id
= strtoul(p
+ 1, NULL
, 16);
532 ret
= usb_host_scan(&fs
, usb_host_find_device_scan
);
534 *pbus_num
= fs
.bus_num
;
542 /**********************/
543 /* USB host device info */
545 struct usb_class_info
{
547 const char *class_name
;
550 static const struct usb_class_info usb_class_info
[] = {
551 { USB_CLASS_AUDIO
, "Audio"},
552 { USB_CLASS_COMM
, "Communication"},
553 { USB_CLASS_HID
, "HID"},
554 { USB_CLASS_HUB
, "Hub" },
555 { USB_CLASS_PHYSICAL
, "Physical" },
556 { USB_CLASS_PRINTER
, "Printer" },
557 { USB_CLASS_MASS_STORAGE
, "Storage" },
558 { USB_CLASS_CDC_DATA
, "Data" },
559 { USB_CLASS_APP_SPEC
, "Application Specific" },
560 { USB_CLASS_VENDOR_SPEC
, "Vendor Specific" },
561 { USB_CLASS_STILL_IMAGE
, "Still Image" },
562 { USB_CLASS_CSCID
, "Smart Card" },
563 { USB_CLASS_CONTENT_SEC
, "Content Security" },
567 static const char *usb_class_str(uint8_t class)
569 const struct usb_class_info
*p
;
570 for (p
= usb_class_info
; p
->class != -1; p
++) {
571 if (p
->class == class)
574 return p
->class_name
;
577 static void usb_info_device(Monitor
*mon
, int bus_num
, int addr
, int class_id
,
578 int vendor_id
, int product_id
,
579 const char *product_name
,
582 const char *class_str
, *speed_str
;
599 monitor_printf(mon
, " Device %d.%d, speed %s Mb/s\n",
600 bus_num
, addr
, speed_str
);
601 class_str
= usb_class_str(class_id
);
603 monitor_printf(mon
, " %s:", class_str
);
605 monitor_printf(mon
, " Class %02x:", class_id
);
606 monitor_printf(mon
, " USB device %04x:%04x", vendor_id
, product_id
);
607 if (product_name
[0] != '\0')
608 monitor_printf(mon
, ", %s", product_name
);
609 monitor_printf(mon
, "\n");
612 static int usb_host_info_device(void *opaque
,
613 int bus_num
, int addr
,
615 int vendor_id
, int product_id
,
616 const char *product_name
,
619 Monitor
*mon
= opaque
;
621 usb_info_device(mon
, bus_num
, addr
, class_id
, vendor_id
, product_id
,
622 product_name
, speed
);
626 void usb_host_info(Monitor
*mon
)
628 usb_host_scan(mon
, usb_host_info_device
);
632 int usb_host_device_close(const char *devname
)