* Linux host USB redirector
*
* Copyright (c) 2005 Fabrice Bellard
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
};
typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
- int vendor_id, int product_id,
+ int vendor_id, int product_id,
const char *product_name, int speed);
-static int usb_host_find_device(int *pbus_num, int *paddr,
+static int usb_host_find_device(int *pbus_num, int *paddr,
+ char *product_name, int product_name_size,
const char *devname);
//#define DEBUG
#define USBDEVFS_PATH "/proc/bus/usb"
+#define PRODUCT_NAME_SZ 32
typedef struct USBHostDevice {
USBDevice dev;
done by the host OS */
ioctl(s->fd, USBDEVFS_RESET);
#endif
-}
+}
+
+static void usb_host_handle_destroy(USBDevice *dev)
+{
+ USBHostDevice *s = (USBHostDevice *)dev;
+
+ if (s->fd >= 0)
+ close(s->fd);
+ qemu_free(s);
+}
static int usb_host_handle_control(USBDevice *dev,
int request,
}
}
-static int usb_host_handle_data(USBDevice *dev, int pid,
- uint8_t devep,
- uint8_t *data, int len)
+static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
{
USBHostDevice *s = (USBHostDevice *)dev;
struct usbdevfs_bulktransfer bt;
int ret;
+ uint8_t devep = p->devep;
/* XXX: optimize and handle all data types by looking at the
config descriptor */
- if (pid == USB_TOKEN_IN)
+ if (p->pid == USB_TOKEN_IN)
devep |= 0x80;
bt.ep = devep;
- bt.len = len;
+ bt.len = p->len;
bt.timeout = 50;
- bt.data = data;
+ bt.data = p->data;
ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
if (ret < 0) {
switch(errno) {
char buf[1024];
int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
int bus_num, addr;
+ char product_name[PRODUCT_NAME_SZ];
- if (usb_host_find_device(&bus_num, &addr, devname) < 0)
+ if (usb_host_find_device(&bus_num, &addr,
+ product_name, sizeof(product_name),
+ devname) < 0)
return NULL;
-
- snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
+
+ snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
bus_num, addr);
fd = open(buf, O_RDWR);
if (fd < 0) {
perror("read descr");
goto fail;
}
-
+
i = 0;
dev_descr_len = descr[0];
if (dev_descr_len > descr_len)
#ifdef USBDEVFS_DISCONNECT
/* earlier Linux 2.4 do not support that */
- ret = ioctl(fd, USBDEVFS_DISCONNECT);
- if (ret < 0 && errno != ENODATA) {
- perror("USBDEVFS_DISCONNECT");
- goto fail;
+ {
+ struct usbdevfs_ioctl ctrl;
+ ctrl.ioctl_code = USBDEVFS_DISCONNECT;
+ ctrl.ifno = 0;
+ ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl);
+ if (ret < 0 && errno != ENODATA) {
+ perror("USBDEVFS_DISCONNECT");
+ goto fail;
+ }
}
#endif
#ifdef DEBUG
printf("host USB device %d.%d grabbed\n", bus_num, addr);
-#endif
+#endif
dev = qemu_mallocz(sizeof(USBHostDevice));
if (!dev)
dev->dev.handle_reset = usb_host_handle_reset;
dev->dev.handle_control = usb_host_handle_control;
dev->dev.handle_data = usb_host_handle_data;
+ dev->dev.handle_destroy = usb_host_handle_destroy;
+
+ if (product_name[0] == '\0')
+ snprintf(dev->dev.devname, sizeof(dev->dev.devname),
+ "host:%s", devname);
+ else
+ pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
+ product_name);
+
return (USBDevice *)dev;
}
static int get_tag_value(char *buf, int buf_size,
- const char *str, const char *tag,
+ const char *str, const char *tag,
const char *stopchars)
{
const char *p;
int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
int ret;
char product_name[512];
-
+
f = fopen(USBDEVFS_PATH "/devices", "r");
if (!f) {
term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
if (strlen(line) > 0)
line[strlen(line) - 1] = '\0';
if (line[0] == 'T' && line[1] == ':') {
- if (device_count) {
- ret = func(opaque, bus_num, addr, class_id, vendor_id,
+ if (device_count && (vendor_id || product_id)) {
+ /* New device. Add the previously discovered device. */
+ ret = func(opaque, bus_num, addr, class_id, vendor_id,
product_id, product_name, speed);
if (ret)
goto the_end;
}
fail: ;
}
- if (device_count) {
- ret = func(opaque, bus_num, addr, class_id, vendor_id,
+ if (device_count && (vendor_id || product_id)) {
+ /* Add the last device. */
+ ret = func(opaque, bus_num, addr, class_id, vendor_id,
product_id, product_name, speed);
}
the_end:
int product_id;
int bus_num;
int addr;
+ char product_name[PRODUCT_NAME_SZ];
} FindDeviceState;
-static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
+static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
int class_id,
- int vendor_id, int product_id,
+ int vendor_id, int product_id,
const char *product_name, int speed)
{
FindDeviceState *s = opaque;
- if (vendor_id == s->vendor_id &&
- product_id == s->product_id) {
+ if ((vendor_id == s->vendor_id &&
+ product_id == s->product_id) ||
+ (bus_num == s->bus_num &&
+ addr == s->addr)) {
+ pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name);
s->bus_num = bus_num;
s->addr = addr;
return 1;
}
}
-/* the syntax is :
- 'bus.addr' (decimal numbers) or
+/* the syntax is :
+ 'bus.addr' (decimal numbers) or
'vendor_id:product_id' (hexa numbers) */
-static int usb_host_find_device(int *pbus_num, int *paddr,
+static int usb_host_find_device(int *pbus_num, int *paddr,
+ char *product_name, int product_name_size,
const char *devname)
{
const char *p;
if (p) {
*pbus_num = strtoul(devname, NULL, 0);
*paddr = strtoul(p + 1, NULL, 0);
+ fs.bus_num = *pbus_num;
+ fs.addr = *paddr;
+ ret = usb_host_scan(&fs, usb_host_find_device_scan);
+ if (ret)
+ pstrcpy(product_name, product_name_size, fs.product_name);
return 0;
}
p = strchr(devname, ':');
if (ret) {
*pbus_num = fs.bus_num;
*paddr = fs.addr;
+ pstrcpy(product_name, product_name_size, fs.product_name);
return 0;
}
}
}
void usb_info_device(int bus_num, int addr, int class_id,
- int vendor_id, int product_id,
+ int vendor_id, int product_id,
const char *product_name,
int speed)
{
const char *class_str, *speed_str;
switch(speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
+ case USB_SPEED_LOW:
+ speed_str = "1.5";
break;
- case USB_SPEED_FULL:
- speed_str = "12";
+ case USB_SPEED_FULL:
+ speed_str = "12";
break;
- case USB_SPEED_HIGH:
- speed_str = "480";
+ case USB_SPEED_HIGH:
+ speed_str = "480";
break;
default:
- speed_str = "?";
+ speed_str = "?";
break;
}
- term_printf(" Device %d.%d, speed %s Mb/s\n",
+ term_printf(" Device %d.%d, speed %s Mb/s\n",
bus_num, addr, speed_str);
class_str = usb_class_str(class_id);
- if (class_str)
+ if (class_str)
term_printf(" %s:", class_str);
else
term_printf(" Class %02x:", class_id);
term_printf("\n");
}
-static int usb_host_info_device(void *opaque, int bus_num, int addr,
+static int usb_host_info_device(void *opaque, int bus_num, int addr,
int class_id,
- int vendor_id, int product_id,
+ int vendor_id, int product_id,
const char *product_name,
int speed)
{