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>
43 /* This value has maximum potential at 16.
44 * You should also set hw.usb.debug to gain
48 #define UGEN_DEBUG_LEVEL 0
51 typedef int USBScanFunc(void *opaque
, int bus_num
, int addr
, int class_id
,
52 int vendor_id
, int product_id
,
53 const char *product_name
, int speed
);
54 static int usb_host_find_device(int *pbus_num
, int *paddr
,
57 typedef struct USBHostDevice
{
59 int ep_fd
[USB_MAX_ENDPOINTS
];
65 static int ensure_ep_open(USBHostDevice
*dev
, int ep
, int mode
)
70 /* Get the address for this endpoint */
73 if (dev
->ep_fd
[ep
] < 0) {
74 #if defined(__FreeBSD__) || defined(__DragonFly__)
75 snprintf(buf
, sizeof(buf
) - 1, "%s.%d", dev
->devpath
, ep
);
77 snprintf(buf
, sizeof(buf
) - 1, "%s.%02d", dev
->devpath
, ep
);
79 /* Try to open it O_RDWR first for those devices which have in and out
80 * endpoints with the same address (eg 0x02 and 0x82)
82 fd
= open(buf
, O_RDWR
);
83 if (fd
< 0 && errno
== ENXIO
)
87 printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
88 buf
, strerror(errno
));
94 return dev
->ep_fd
[ep
];
97 static void ensure_eps_closed(USBHostDevice
*dev
)
104 while (epnum
< USB_MAX_ENDPOINTS
) {
105 if (dev
->ep_fd
[epnum
] >= 0) {
106 close(dev
->ep_fd
[epnum
]);
107 dev
->ep_fd
[epnum
] = -1;
113 static void usb_host_handle_reset(USBDevice
*dev
)
116 USBHostDevice
*s
= (USBHostDevice
*)dev
;
121 * -check device states against transfer requests
122 * and return appropriate response
124 static int usb_host_handle_control(USBDevice
*dev
,
132 USBHostDevice
*s
= (USBHostDevice
*)dev
;
133 struct usb_ctl_request req
;
134 struct usb_alt_interface aiface
;
135 int ret
, timeout
= 50;
137 if ((request
>> 8) == UT_WRITE_DEVICE
&&
138 (request
& 0xff) == UR_SET_ADDRESS
) {
140 /* specific SET_ADDRESS support */
143 } else if ((request
>> 8) == UT_WRITE_DEVICE
&&
144 (request
& 0xff) == UR_SET_CONFIG
) {
146 ensure_eps_closed(s
); /* can't do this without all eps closed */
148 ret
= ioctl(s
->devfd
, USB_SET_CONFIG
, &value
);
151 printf("handle_control: failed to set configuration - %s\n",
154 return USB_RET_STALL
;
158 } else if ((request
>> 8) == UT_WRITE_INTERFACE
&&
159 (request
& 0xff) == UR_SET_INTERFACE
) {
161 aiface
.uai_interface_index
= index
;
162 aiface
.uai_alt_no
= value
;
164 ensure_eps_closed(s
); /* can't do this without all eps closed */
165 ret
= ioctl(s
->devfd
, USB_SET_ALTINTERFACE
, &aiface
);
168 printf("handle_control: failed to set alternate interface - %s\n",
171 return USB_RET_STALL
;
176 req
.ucr_request
.bmRequestType
= request
>> 8;
177 req
.ucr_request
.bRequest
= request
& 0xff;
178 USETW(req
.ucr_request
.wValue
, value
);
179 USETW(req
.ucr_request
.wIndex
, index
);
180 USETW(req
.ucr_request
.wLength
, length
);
182 req
.ucr_flags
= USBD_SHORT_XFER_OK
;
184 ret
= ioctl(s
->devfd
, USB_SET_TIMEOUT
, &timeout
);
185 #if defined(__NetBSD__) || defined(__OpenBSD__)
186 if (ret
< 0 && errno
!= EINVAL
) {
191 printf("handle_control: setting timeout failed - %s\n",
196 ret
= ioctl(s
->devfd
, USB_DO_REQUEST
, &req
);
197 /* ugen returns EIO for usbd_do_request_ no matter what
198 * happens with the transfer */
201 printf("handle_control: error after request - %s\n",
204 return USB_RET_NAK
; // STALL
206 return req
.ucr_actlen
;
211 static int usb_host_handle_data(USBDevice
*dev
, USBPacket
*p
)
213 USBHostDevice
*s
= (USBHostDevice
*)dev
;
215 int one
= 1, shortpacket
= 0, timeout
= 50;
216 sigset_t new_mask
, old_mask
;
217 uint8_t devep
= p
->devep
;
219 /* protect data transfers from SIGALRM signal */
220 sigemptyset(&new_mask
);
221 sigaddset(&new_mask
, SIGALRM
);
222 sigprocmask(SIG_BLOCK
, &new_mask
, &old_mask
);
224 if (p
->pid
== USB_TOKEN_IN
) {
232 fd
= ensure_ep_open(s
, devep
, mode
);
234 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
235 return USB_RET_NODEV
;
238 if (ioctl(fd
, USB_SET_TIMEOUT
, &timeout
) < 0) {
240 printf("handle_data: failed to set timeout - %s\n",
246 if (ioctl(fd
, USB_SET_SHORT_XFER
, &one
) < 0) {
248 printf("handle_data: failed to set short xfer mode - %s\n",
251 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
255 if (p
->pid
== USB_TOKEN_IN
)
256 ret
= readv(fd
, p
->iov
.iov
, p
->iov
.niov
);
258 ret
= writev(fd
, p
->iov
.iov
, p
->iov
.niov
);
260 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
264 printf("handle_data: error after %s data - %s\n",
265 pid
== USB_TOKEN_IN
? "reading" : "writing", strerror(errno
));
272 return USB_RET_STALL
;
279 static void usb_host_handle_destroy(USBDevice
*opaque
)
281 USBHostDevice
*s
= (USBHostDevice
*)opaque
;
284 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
285 if (s
->ep_fd
[i
] >= 0)
296 static int usb_host_initfn(USBDevice
*dev
)
301 USBDevice
*usb_host_device_open(const char *devname
)
303 struct usb_device_info bus_info
, dev_info
;
304 USBDevice
*d
= NULL
, *ret
= NULL
;
306 char ctlpath
[PATH_MAX
+ 1];
307 char buspath
[PATH_MAX
+ 1];
308 int bfd
, dfd
, bus
, address
, i
;
309 int ugendebug
= UGEN_DEBUG_LEVEL
;
311 if (usb_host_find_device(&bus
, &address
, devname
) < 0) {
315 snprintf(buspath
, PATH_MAX
, "/dev/usb%d", bus
);
317 bfd
= open(buspath
, O_RDWR
);
320 printf("usb_host_device_open: failed to open usb bus - %s\n",
326 bus_info
.udi_addr
= address
;
327 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0) {
329 printf("usb_host_device_open: failed to grab bus information - %s\n",
335 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
336 snprintf(ctlpath
, PATH_MAX
, "/dev/%s", bus_info
.udi_devnames
[0]);
338 snprintf(ctlpath
, PATH_MAX
, "/dev/%s.00", bus_info
.udi_devnames
[0]);
341 dfd
= open(ctlpath
, O_RDWR
);
343 dfd
= open(ctlpath
, O_RDONLY
);
346 printf("usb_host_device_open: failed to open usb device %s - %s\n",
347 ctlpath
, strerror(errno
));
353 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0) {
355 printf("usb_host_device_open: failed to grab device info - %s\n",
361 d
= usb_create(NULL
/* FIXME */, "usb-host");
362 dev
= DO_UPCAST(USBHostDevice
, dev
, d
);
364 if (dev_info
.udi_speed
== 1) {
365 dev
->dev
.speed
= USB_SPEED_LOW
- 1;
366 dev
->dev
.speedmask
= USB_SPEED_MASK_LOW
;
368 dev
->dev
.speed
= USB_SPEED_FULL
- 1;
369 dev
->dev
.speedmask
= USB_SPEED_MASK_FULL
;
372 if (strncmp(dev_info
.udi_product
, "product", 7) != 0) {
373 pstrcpy(dev
->dev
.product_desc
, sizeof(dev
->dev
.product_desc
),
374 dev_info
.udi_product
);
376 snprintf(dev
->dev
.product_desc
, sizeof(dev
->dev
.product_desc
),
380 pstrcpy(dev
->devpath
, sizeof(dev
->devpath
), "/dev/");
381 pstrcat(dev
->devpath
, sizeof(dev
->devpath
), dev_info
.udi_devnames
[0]);
383 /* Mark the endpoints as not yet open */
384 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++) {
388 ioctl(dfd
, USB_SETDEBUG
, &ugendebug
);
390 ret
= (USBDevice
*)dev
;
400 static void usb_host_class_initfn(ObjectClass
*klass
, void *data
)
402 USBDeviceClass
*uc
= USB_DEVICE_CLASS(klass
);
404 uc
->product_desc
= "USB Host Device";
405 uc
->init
= usb_host_initfn
;
406 uc
->handle_packet
= usb_generic_handle_packet
;
407 uc
->handle_reset
= usb_host_handle_reset
;
408 uc
->handle_control
= usb_host_handle_control
;
409 uc
->handle_data
= usb_host_handle_data
;
410 uc
->handle_destroy
= usb_host_handle_destroy
;
413 static TypeInfo usb_host_dev_info
= {
415 .parent
= TYPE_USB_DEVICE
,
416 .instance_size
= sizeof(USBHostDevice
),
417 .class_init
= usb_host_class_initfn
,
420 static void usb_host_register_devices(void)
422 type_register_static(&usb_host_dev_info
);
424 device_init(usb_host_register_devices
)
426 static int usb_host_scan(void *opaque
, USBScanFunc
*func
)
428 struct usb_device_info bus_info
;
429 struct usb_device_info dev_info
;
430 uint16_t vendor_id
, product_id
, class_id
, speed
;
431 int bfd
, dfd
, bus
, address
;
432 char busbuf
[20], devbuf
[20], product_name
[256];
435 for (bus
= 0; bus
< 10; bus
++) {
437 snprintf(busbuf
, sizeof(busbuf
) - 1, "/dev/usb%d", bus
);
438 bfd
= open(busbuf
, O_RDWR
);
442 for (address
= 1; address
< 127; address
++) {
444 bus_info
.udi_addr
= address
;
445 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0)
448 /* only list devices that can be used by generic layer */
449 if (strncmp(bus_info
.udi_devnames
[0], "ugen", 4) != 0)
452 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
453 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s", bus_info
.udi_devnames
[0]);
455 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s.00", bus_info
.udi_devnames
[0]);
458 dfd
= open(devbuf
, O_RDONLY
);
461 printf("usb_host_scan: couldn't open device %s - %s\n", devbuf
,
467 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0)
468 printf("usb_host_scan: couldn't get device information for %s - %s\n",
469 devbuf
, strerror(errno
));
471 /* XXX: might need to fixup endianness of word values before copying over */
473 vendor_id
= dev_info
.udi_vendorNo
;
474 product_id
= dev_info
.udi_productNo
;
475 class_id
= dev_info
.udi_class
;
476 speed
= dev_info
.udi_speed
;
478 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
479 pstrcpy(product_name
, sizeof(product_name
),
480 dev_info
.udi_product
);
482 product_name
[0] = '\0';
484 ret
= func(opaque
, bus
, address
, class_id
, vendor_id
,
485 product_id
, product_name
, speed
);
500 typedef struct FindDeviceState
{
507 static int usb_host_find_device_scan(void *opaque
, int bus_num
, int addr
,
509 int vendor_id
, int product_id
,
510 const char *product_name
, int speed
)
512 FindDeviceState
*s
= opaque
;
513 if (vendor_id
== s
->vendor_id
&&
514 product_id
== s
->product_id
) {
515 s
->bus_num
= bus_num
;
525 'bus.addr' (decimal numbers) or
526 'vendor_id:product_id' (hexa numbers) */
527 static int usb_host_find_device(int *pbus_num
, int *paddr
,
534 p
= strchr(devname
, '.');
536 *pbus_num
= strtoul(devname
, NULL
, 0);
537 *paddr
= strtoul(p
+ 1, NULL
, 0);
540 p
= strchr(devname
, ':');
542 fs
.vendor_id
= strtoul(devname
, NULL
, 16);
543 fs
.product_id
= strtoul(p
+ 1, NULL
, 16);
544 ret
= usb_host_scan(&fs
, usb_host_find_device_scan
);
546 *pbus_num
= fs
.bus_num
;
554 /**********************/
555 /* USB host device info */
557 struct usb_class_info
{
559 const char *class_name
;
562 static const struct usb_class_info usb_class_info
[] = {
563 { USB_CLASS_AUDIO
, "Audio"},
564 { USB_CLASS_COMM
, "Communication"},
565 { USB_CLASS_HID
, "HID"},
566 { USB_CLASS_HUB
, "Hub" },
567 { USB_CLASS_PHYSICAL
, "Physical" },
568 { USB_CLASS_PRINTER
, "Printer" },
569 { USB_CLASS_MASS_STORAGE
, "Storage" },
570 { USB_CLASS_CDC_DATA
, "Data" },
571 { USB_CLASS_APP_SPEC
, "Application Specific" },
572 { USB_CLASS_VENDOR_SPEC
, "Vendor Specific" },
573 { USB_CLASS_STILL_IMAGE
, "Still Image" },
574 { USB_CLASS_CSCID
, "Smart Card" },
575 { USB_CLASS_CONTENT_SEC
, "Content Security" },
579 static const char *usb_class_str(uint8_t class)
581 const struct usb_class_info
*p
;
582 for (p
= usb_class_info
; p
->class != -1; p
++) {
583 if (p
->class == class)
586 return p
->class_name
;
589 static void usb_info_device(Monitor
*mon
, int bus_num
, int addr
, int class_id
,
590 int vendor_id
, int product_id
,
591 const char *product_name
,
594 const char *class_str
, *speed_str
;
611 monitor_printf(mon
, " Device %d.%d, speed %s Mb/s\n",
612 bus_num
, addr
, speed_str
);
613 class_str
= usb_class_str(class_id
);
615 monitor_printf(mon
, " %s:", class_str
);
617 monitor_printf(mon
, " Class %02x:", class_id
);
618 monitor_printf(mon
, " USB device %04x:%04x", vendor_id
, product_id
);
619 if (product_name
[0] != '\0')
620 monitor_printf(mon
, ", %s", product_name
);
621 monitor_printf(mon
, "\n");
624 static int usb_host_info_device(void *opaque
,
625 int bus_num
, int addr
,
627 int vendor_id
, int product_id
,
628 const char *product_name
,
631 Monitor
*mon
= opaque
;
633 usb_info_device(mon
, bus_num
, addr
, class_id
, vendor_id
, product_id
,
634 product_name
, speed
);
638 void usb_host_info(Monitor
*mon
)
640 usb_host_scan(mon
, usb_host_info_device
);
644 int usb_host_device_close(const char *devname
)