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>
37 #include <dev/usb/usb.h>
40 /* This value has maximum potential at 16.
41 * You should also set hw.usb.debug to gain
45 #define UGEN_DEBUG_LEVEL 0
48 typedef int USBScanFunc(void *opaque
, int bus_num
, int addr
, int class_id
,
49 int vendor_id
, int product_id
,
50 const char *product_name
, int speed
);
51 static int usb_host_find_device(int *pbus_num
, int *paddr
,
54 typedef struct USBHostDevice
{
56 int ep_fd
[USB_MAX_ENDPOINTS
];
62 static int ensure_ep_open(USBHostDevice
*dev
, int ep
, int mode
)
67 /* Get the address for this endpoint */
70 if (dev
->ep_fd
[ep
] < 0) {
72 snprintf(buf
, sizeof(buf
) - 1, "%s.%d", dev
->devpath
, ep
);
74 snprintf(buf
, sizeof(buf
) - 1, "%s.%02d", dev
->devpath
, ep
);
76 /* Try to open it O_RDWR first for those devices which have in and out
77 * endpoints with the same address (eg 0x02 and 0x82)
79 fd
= open(buf
, O_RDWR
);
80 if (fd
< 0 && errno
== ENXIO
)
84 printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
85 buf
, strerror(errno
));
91 return dev
->ep_fd
[ep
];
94 static void ensure_eps_closed(USBHostDevice
*dev
)
101 while (epnum
< USB_MAX_ENDPOINTS
) {
102 if (dev
->ep_fd
[epnum
] >= 0) {
103 close(dev
->ep_fd
[epnum
]);
104 dev
->ep_fd
[epnum
] = -1;
110 static void usb_host_handle_reset(USBDevice
*dev
)
113 USBHostDevice
*s
= (USBHostDevice
*)dev
;
118 * -check device states against transfer requests
119 * and return appropriate response
121 static int usb_host_handle_control(USBDevice
*dev
,
128 USBHostDevice
*s
= (USBHostDevice
*)dev
;
129 struct usb_ctl_request req
;
130 struct usb_alt_interface aiface
;
131 int ret
, timeout
= 50;
133 if ((request
>> 8) == UT_WRITE_DEVICE
&&
134 (request
& 0xff) == UR_SET_ADDRESS
) {
136 /* specific SET_ADDRESS support */
139 } else if ((request
>> 8) == UT_WRITE_DEVICE
&&
140 (request
& 0xff) == UR_SET_CONFIG
) {
142 ensure_eps_closed(s
); /* can't do this without all eps closed */
144 ret
= ioctl(s
->devfd
, USB_SET_CONFIG
, &value
);
147 printf("handle_control: failed to set configuration - %s\n",
150 return USB_RET_STALL
;
154 } else if ((request
>> 8) == UT_WRITE_INTERFACE
&&
155 (request
& 0xff) == UR_SET_INTERFACE
) {
157 aiface
.uai_interface_index
= index
;
158 aiface
.uai_alt_no
= value
;
160 ensure_eps_closed(s
); /* can't do this without all eps closed */
161 ret
= ioctl(s
->devfd
, USB_SET_ALTINTERFACE
, &aiface
);
164 printf("handle_control: failed to set alternate interface - %s\n",
167 return USB_RET_STALL
;
172 req
.ucr_request
.bmRequestType
= request
>> 8;
173 req
.ucr_request
.bRequest
= request
& 0xff;
174 USETW(req
.ucr_request
.wValue
, value
);
175 USETW(req
.ucr_request
.wIndex
, index
);
176 USETW(req
.ucr_request
.wLength
, length
);
178 req
.ucr_flags
= USBD_SHORT_XFER_OK
;
180 ret
= ioctl(s
->devfd
, USB_SET_TIMEOUT
, &timeout
);
181 #if defined(__NetBSD__) || defined(__OpenBSD__)
182 if (ret
< 0 && errno
!= EINVAL
) {
187 printf("handle_control: setting timeout failed - %s\n",
192 ret
= ioctl(s
->devfd
, USB_DO_REQUEST
, &req
);
193 /* ugen returns EIO for usbd_do_request_ no matter what
194 * happens with the transfer */
197 printf("handle_control: error after request - %s\n",
200 return USB_RET_NAK
; // STALL
202 return req
.ucr_actlen
;
207 static int usb_host_handle_data(USBDevice
*dev
, USBPacket
*p
)
209 USBHostDevice
*s
= (USBHostDevice
*)dev
;
211 int one
= 1, shortpacket
= 0, timeout
= 50;
212 sigset_t new_mask
, old_mask
;
213 uint8_t devep
= p
->devep
;
215 /* protect data transfers from SIGALRM signal */
216 sigemptyset(&new_mask
);
217 sigaddset(&new_mask
, SIGALRM
);
218 sigprocmask(SIG_BLOCK
, &new_mask
, &old_mask
);
220 if (p
->pid
== USB_TOKEN_IN
) {
228 fd
= ensure_ep_open(s
, devep
, mode
);
230 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
231 return USB_RET_NODEV
;
234 if (ioctl(fd
, USB_SET_TIMEOUT
, &timeout
) < 0) {
236 printf("handle_data: failed to set timeout - %s\n",
242 if (ioctl(fd
, USB_SET_SHORT_XFER
, &one
) < 0) {
244 printf("handle_data: failed to set short xfer mode - %s\n",
247 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
251 if (p
->pid
== USB_TOKEN_IN
)
252 ret
= read(fd
, p
->data
, p
->len
);
254 ret
= write(fd
, p
->data
, p
->len
);
256 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
260 printf("handle_data: error after %s data - %s\n",
261 pid
== USB_TOKEN_IN
? "reading" : "writing", strerror(errno
));
268 return USB_RET_STALL
;
275 static void usb_host_handle_destroy(USBDevice
*opaque
)
277 USBHostDevice
*s
= (USBHostDevice
*)opaque
;
280 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
281 if (s
->ep_fd
[i
] >= 0)
292 USBDevice
*usb_host_device_open(const char *devname
)
294 struct usb_device_info bus_info
, dev_info
;
296 char ctlpath
[PATH_MAX
+ 1];
297 char buspath
[PATH_MAX
+ 1];
298 int bfd
, dfd
, bus
, address
, i
;
299 int ugendebug
= UGEN_DEBUG_LEVEL
;
301 if (usb_host_find_device(&bus
, &address
, devname
) < 0)
304 snprintf(buspath
, PATH_MAX
, "/dev/usb%d", bus
);
306 bfd
= open(buspath
, O_RDWR
);
309 printf("usb_host_device_open: failed to open usb bus - %s\n",
315 bus_info
.udi_addr
= address
;
316 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0) {
318 printf("usb_host_device_open: failed to grab bus information - %s\n",
325 snprintf(ctlpath
, PATH_MAX
, "/dev/%s", bus_info
.udi_devnames
[0]);
327 snprintf(ctlpath
, PATH_MAX
, "/dev/%s.00", bus_info
.udi_devnames
[0]);
330 dfd
= open(ctlpath
, O_RDWR
);
332 dfd
= open(ctlpath
, O_RDONLY
);
335 printf("usb_host_device_open: failed to open usb device %s - %s\n",
336 ctlpath
, strerror(errno
));
342 dev
= qemu_mallocz(sizeof(USBHostDevice
));
345 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0) {
347 printf("usb_host_device_open: failed to grab device info - %s\n",
353 if (dev_info
.udi_speed
== 1)
354 dev
->dev
.speed
= USB_SPEED_LOW
- 1;
356 dev
->dev
.speed
= USB_SPEED_FULL
- 1;
358 dev
->dev
.handle_packet
= usb_generic_handle_packet
;
360 dev
->dev
.handle_reset
= usb_host_handle_reset
;
361 dev
->dev
.handle_control
= usb_host_handle_control
;
362 dev
->dev
.handle_data
= usb_host_handle_data
;
363 dev
->dev
.handle_destroy
= usb_host_handle_destroy
;
365 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
366 pstrcpy(dev
->dev
.devname
, sizeof(dev
->dev
.devname
),
367 dev_info
.udi_product
);
369 snprintf(dev
->dev
.devname
, sizeof(dev
->dev
.devname
),
372 pstrcpy(dev
->devpath
, sizeof(dev
->devpath
), "/dev/");
373 pstrcat(dev
->devpath
, sizeof(dev
->devpath
), dev_info
.udi_devnames
[0]);
375 /* Mark the endpoints as not yet open */
376 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
379 ioctl(dfd
, USB_SETDEBUG
, &ugendebug
);
381 return (USBDevice
*)dev
;
388 static int usb_host_scan(void *opaque
, USBScanFunc
*func
)
390 struct usb_device_info bus_info
;
391 struct usb_device_info dev_info
;
392 uint16_t vendor_id
, product_id
, class_id
, speed
;
393 int bfd
, dfd
, bus
, address
;
394 char busbuf
[20], devbuf
[20], product_name
[256];
397 for (bus
= 0; bus
< 10; bus
++) {
399 snprintf(busbuf
, sizeof(busbuf
) - 1, "/dev/usb%d", bus
);
400 bfd
= open(busbuf
, O_RDWR
);
404 for (address
= 1; address
< 127; address
++) {
406 bus_info
.udi_addr
= address
;
407 if (ioctl(bfd
, USB_DEVICEINFO
, &bus_info
) < 0)
410 /* only list devices that can be used by generic layer */
411 if (strncmp(bus_info
.udi_devnames
[0], "ugen", 4) != 0)
415 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s", bus_info
.udi_devnames
[0]);
417 snprintf(devbuf
, sizeof(devbuf
) - 1, "/dev/%s.00", bus_info
.udi_devnames
[0]);
420 dfd
= open(devbuf
, O_RDONLY
);
423 printf("usb_host_scan: couldn't open device %s - %s\n", devbuf
,
429 if (ioctl(dfd
, USB_GET_DEVICEINFO
, &dev_info
) < 0)
430 printf("usb_host_scan: couldn't get device information for %s - %s\n",
431 devbuf
, strerror(errno
));
433 // XXX: might need to fixup endianess of word values before copying over
435 vendor_id
= dev_info
.udi_vendorNo
;
436 product_id
= dev_info
.udi_productNo
;
437 class_id
= dev_info
.udi_class
;
438 speed
= dev_info
.udi_speed
;
440 if (strncmp(dev_info
.udi_product
, "product", 7) != 0)
441 pstrcpy(product_name
, sizeof(product_name
),
442 dev_info
.udi_product
);
444 product_name
[0] = '\0';
446 ret
= func(opaque
, bus
, address
, class_id
, vendor_id
,
447 product_id
, product_name
, speed
);
462 typedef struct FindDeviceState
{
469 static int usb_host_find_device_scan(void *opaque
, int bus_num
, int addr
,
471 int vendor_id
, int product_id
,
472 const char *product_name
, int speed
)
474 FindDeviceState
*s
= opaque
;
475 if (vendor_id
== s
->vendor_id
&&
476 product_id
== s
->product_id
) {
477 s
->bus_num
= bus_num
;
487 'bus.addr' (decimal numbers) or
488 'vendor_id:product_id' (hexa numbers) */
489 static int usb_host_find_device(int *pbus_num
, int *paddr
,
496 p
= strchr(devname
, '.');
498 *pbus_num
= strtoul(devname
, NULL
, 0);
499 *paddr
= strtoul(p
+ 1, NULL
, 0);
502 p
= strchr(devname
, ':');
504 fs
.vendor_id
= strtoul(devname
, NULL
, 16);
505 fs
.product_id
= strtoul(p
+ 1, NULL
, 16);
506 ret
= usb_host_scan(&fs
, usb_host_find_device_scan
);
508 *pbus_num
= fs
.bus_num
;
516 /**********************/
517 /* USB host device info */
519 struct usb_class_info
{
521 const char *class_name
;
524 static const struct usb_class_info usb_class_info
[] = {
525 { USB_CLASS_AUDIO
, "Audio"},
526 { USB_CLASS_COMM
, "Communication"},
527 { USB_CLASS_HID
, "HID"},
528 { USB_CLASS_HUB
, "Hub" },
529 { USB_CLASS_PHYSICAL
, "Physical" },
530 { USB_CLASS_PRINTER
, "Printer" },
531 { USB_CLASS_MASS_STORAGE
, "Storage" },
532 { USB_CLASS_CDC_DATA
, "Data" },
533 { USB_CLASS_APP_SPEC
, "Application Specific" },
534 { USB_CLASS_VENDOR_SPEC
, "Vendor Specific" },
535 { USB_CLASS_STILL_IMAGE
, "Still Image" },
536 { USB_CLASS_CSCID
, "Smart Card" },
537 { USB_CLASS_CONTENT_SEC
, "Content Security" },
541 static const char *usb_class_str(uint8_t class)
543 const struct usb_class_info
*p
;
544 for (p
= usb_class_info
; p
->class != -1; p
++) {
545 if (p
->class == class)
548 return p
->class_name
;
551 static void usb_info_device(int bus_num
, int addr
, int class_id
,
552 int vendor_id
, int product_id
,
553 const char *product_name
,
556 const char *class_str
, *speed_str
;
573 term_printf(" Device %d.%d, speed %s Mb/s\n",
574 bus_num
, addr
, speed_str
);
575 class_str
= usb_class_str(class_id
);
577 term_printf(" %s:", class_str
);
579 term_printf(" Class %02x:", class_id
);
580 term_printf(" USB device %04x:%04x", vendor_id
, product_id
);
581 if (product_name
[0] != '\0')
582 term_printf(", %s", product_name
);
586 static int usb_host_info_device(void *opaque
, int bus_num
, int addr
,
588 int vendor_id
, int product_id
,
589 const char *product_name
,
592 usb_info_device(bus_num
, addr
, class_id
, vendor_id
, product_id
,
593 product_name
, speed
);
597 void usb_host_info(void)
599 usb_host_scan(NULL
, usb_host_info_device
);
603 int usb_host_device_close(const char *devname
)