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
];
66 static int ensure_ep_open(USBHostDevice
*dev
, int ep
, int mode
)
71 /* Get the address for this endpoint */
74 if (dev
->ep_fd
[ep
] < 0) {
75 #if defined(__FreeBSD__) || defined(__DragonFly__)
76 snprintf(buf
, sizeof(buf
) - 1, "%s.%d", dev
->devpath
, ep
);
78 snprintf(buf
, sizeof(buf
) - 1, "%s.%02d", dev
->devpath
, ep
);
80 /* Try to open it O_RDWR first for those devices which have in and out
81 * endpoints with the same address (eg 0x02 and 0x82)
83 fd
= open(buf
, O_RDWR
);
84 if (fd
< 0 && errno
== ENXIO
)
88 printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
89 buf
, strerror(errno
));
95 return dev
->ep_fd
[ep
];
98 static void ensure_eps_closed(USBHostDevice
*dev
)
105 while (epnum
< USB_MAX_ENDPOINTS
) {
106 if (dev
->ep_fd
[epnum
] >= 0) {
107 close(dev
->ep_fd
[epnum
]);
108 dev
->ep_fd
[epnum
] = -1;
114 static void usb_host_handle_reset(USBDevice
*dev
)
117 USBHostDevice
*s
= (USBHostDevice
*)dev
;
122 * -check device states against transfer requests
123 * and return appropriate response
125 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
= read(fd
, p
->data
, p
->len
);
258 ret
= write(fd
, p
->data
, p
->len
);
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 USBDevice
*usb_host_device_open(const char *devname
)
298 struct usb_device_info bus_info
, dev_info
;
300 char ctlpath
[PATH_MAX
+ 1];
301 char buspath
[PATH_MAX
+ 1];
302 int bfd
, dfd
, bus
, address
, i
;
303 int ugendebug
= UGEN_DEBUG_LEVEL
;
305 if (usb_host_find_device(&bus
, &address
, devname
) < 0)
308 snprintf(buspath
, PATH_MAX
, "/dev/usb%d", bus
);
310 bfd
= open(buspath
, O_RDWR
);
313 printf("usb_host_device_open: failed to open usb bus - %s\n",
319 bus_info
.udi_addr
= address
;
320 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0) {
322 printf("usb_host_device_open: failed to grab bus information - %s\n",
328 #if defined(__FreeBSD__) || defined(__DragonFly__)
329 snprintf(ctlpath
, PATH_MAX
, "/dev/%s", bus_info
.udi_devnames
[0]);
331 snprintf(ctlpath
, PATH_MAX
, "/dev/%s.00", bus_info
.udi_devnames
[0]);
334 dfd
= open(ctlpath
, O_RDWR
);
336 dfd
= open(ctlpath
, O_RDONLY
);
339 printf("usb_host_device_open: failed to open usb device %s - %s\n",
340 ctlpath
, strerror(errno
));
346 dev
= qemu_mallocz(sizeof(USBHostDevice
));
349 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0) {
351 printf("usb_host_device_open: failed to grab device info - %s\n",
357 if (dev_info
.udi_speed
== 1)
358 dev
->dev
.speed
= USB_SPEED_LOW
- 1;
360 dev
->dev
.speed
= USB_SPEED_FULL
- 1;
362 dev
->dev
.handle_packet
= usb_generic_handle_packet
;
364 dev
->dev
.handle_reset
= usb_host_handle_reset
;
365 dev
->dev
.handle_control
= usb_host_handle_control
;
366 dev
->dev
.handle_data
= usb_host_handle_data
;
367 dev
->dev
.handle_destroy
= usb_host_handle_destroy
;
369 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
370 pstrcpy(dev
->dev
.devname
, sizeof(dev
->dev
.devname
),
371 dev_info
.udi_product
);
373 snprintf(dev
->dev
.devname
, sizeof(dev
->dev
.devname
),
376 pstrcpy(dev
->devpath
, sizeof(dev
->devpath
), "/dev/");
377 pstrcat(dev
->devpath
, sizeof(dev
->devpath
), dev_info
.udi_devnames
[0]);
379 /* Mark the endpoints as not yet open */
380 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
383 ioctl(dfd
, USB_SETDEBUG
, &ugendebug
);
385 return (USBDevice
*)dev
;
392 static int usb_host_scan(void *opaque
, USBScanFunc
*func
)
394 struct usb_device_info bus_info
;
395 struct usb_device_info dev_info
;
396 uint16_t vendor_id
, product_id
, class_id
, speed
;
397 int bfd
, dfd
, bus
, address
;
398 char busbuf
[20], devbuf
[20], product_name
[256];
401 for (bus
= 0; bus
< 10; bus
++) {
403 snprintf(busbuf
, sizeof(busbuf
) - 1, "/dev/usb%d", bus
);
404 bfd
= open(busbuf
, O_RDWR
);
408 for (address
= 1; address
< 127; address
++) {
410 bus_info
.udi_addr
= address
;
411 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0)
414 /* only list devices that can be used by generic layer */
415 if (strncmp(bus_info
.udi_devnames
[0], "ugen", 4) != 0)
418 #if defined(__FreeBSD__) || defined(__DragonFly__)
419 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s", bus_info
.udi_devnames
[0]);
421 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s.00", bus_info
.udi_devnames
[0]);
424 dfd
= open(devbuf
, O_RDONLY
);
427 printf("usb_host_scan: couldn't open device %s - %s\n", devbuf
,
433 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0)
434 printf("usb_host_scan: couldn't get device information for %s - %s\n",
435 devbuf
, strerror(errno
));
437 // XXX: might need to fixup endianess of word values before copying over
439 vendor_id
= dev_info
.udi_vendorNo
;
440 product_id
= dev_info
.udi_productNo
;
441 class_id
= dev_info
.udi_class
;
442 speed
= dev_info
.udi_speed
;
444 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
445 pstrcpy(product_name
, sizeof(product_name
),
446 dev_info
.udi_product
);
448 product_name
[0] = '\0';
450 ret
= func(opaque
, bus
, address
, class_id
, vendor_id
,
451 product_id
, product_name
, speed
);
466 typedef struct FindDeviceState
{
473 static int usb_host_find_device_scan(void *opaque
, int bus_num
, int addr
,
475 int vendor_id
, int product_id
,
476 const char *product_name
, int speed
)
478 FindDeviceState
*s
= opaque
;
479 if (vendor_id
== s
->vendor_id
&&
480 product_id
== s
->product_id
) {
481 s
->bus_num
= bus_num
;
491 'bus.addr' (decimal numbers) or
492 'vendor_id:product_id' (hexa numbers) */
493 static int usb_host_find_device(int *pbus_num
, int *paddr
,
500 p
= strchr(devname
, '.');
502 *pbus_num
= strtoul(devname
, NULL
, 0);
503 *paddr
= strtoul(p
+ 1, NULL
, 0);
506 p
= strchr(devname
, ':');
508 fs
.vendor_id
= strtoul(devname
, NULL
, 16);
509 fs
.product_id
= strtoul(p
+ 1, NULL
, 16);
510 ret
= usb_host_scan(&fs
, usb_host_find_device_scan
);
512 *pbus_num
= fs
.bus_num
;
520 /**********************/
521 /* USB host device info */
523 struct usb_class_info
{
525 const char *class_name
;
528 static const struct usb_class_info usb_class_info
[] = {
529 { USB_CLASS_AUDIO
, "Audio"},
530 { USB_CLASS_COMM
, "Communication"},
531 { USB_CLASS_HID
, "HID"},
532 { USB_CLASS_HUB
, "Hub" },
533 { USB_CLASS_PHYSICAL
, "Physical" },
534 { USB_CLASS_PRINTER
, "Printer" },
535 { USB_CLASS_MASS_STORAGE
, "Storage" },
536 { USB_CLASS_CDC_DATA
, "Data" },
537 { USB_CLASS_APP_SPEC
, "Application Specific" },
538 { USB_CLASS_VENDOR_SPEC
, "Vendor Specific" },
539 { USB_CLASS_STILL_IMAGE
, "Still Image" },
540 { USB_CLASS_CSCID
, "Smart Card" },
541 { USB_CLASS_CONTENT_SEC
, "Content Security" },
545 static const char *usb_class_str(uint8_t class)
547 const struct usb_class_info
*p
;
548 for (p
= usb_class_info
; p
->class != -1; p
++) {
549 if (p
->class == class)
552 return p
->class_name
;
555 static void usb_info_device(Monitor
*mon
, int bus_num
, int addr
, int class_id
,
556 int vendor_id
, int product_id
,
557 const char *product_name
,
560 const char *class_str
, *speed_str
;
577 monitor_printf(mon
, " Device %d.%d, speed %s Mb/s\n",
578 bus_num
, addr
, speed_str
);
579 class_str
= usb_class_str(class_id
);
581 monitor_printf(mon
, " %s:", class_str
);
583 monitor_printf(mon
, " Class %02x:", class_id
);
584 monitor_printf(mon
, " USB device %04x:%04x", vendor_id
, product_id
);
585 if (product_name
[0] != '\0')
586 monitor_printf(mon
, ", %s", product_name
);
587 monitor_printf(mon
, "\n");
590 static int usb_host_info_device(void *opaque
,
591 int bus_num
, int addr
,
593 int vendor_id
, int product_id
,
594 const char *product_name
,
597 Monitor
*mon
= opaque
;
599 usb_info_device(mon
, bus_num
, addr
, class_id
, vendor_id
, product_id
,
600 product_name
, speed
);
604 void usb_host_info(Monitor
*mon
)
606 usb_host_scan(mon
, usb_host_info_device
);
610 int usb_host_device_close(const char *devname
)