From: Andreas Winkelbauer <andreas.winkelbauer@gmx.at>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] usb devices with multiple configurations/interfaces
Date: Sat, 18 Aug 2007 19:34:21 +0200 [thread overview]
Message-ID: <46C72D9D.5000109@gmx.at> (raw)
[-- Attachment #1: Type: text/plain, Size: 497 bytes --]
Hi,
as the patch provided in [1] did not work for me when patching against
qemu-0.9.0 I created a new diff which should work with the official
qemu-0.9.0 sources.
So if you struggle with an error like "usb_host: only one interface
supported" this might help you out.
You can find some more information and also (S)RPM packages at [2].
Bye,
Andreas Winkelbauer
[1] http://lists.gnu.org/archive/html/qemu-devel/2007-06/msg00331.html
[2] http://stud4.tuwien.ac.at/~e0425650/html/linux-qemu.html
[-- Attachment #2: qemu-0.9.0-usb-multi-configs.patch --]
[-- Type: text/x-patch, Size: 7757 bytes --]
--- usb-linux.c 2007-08-16 14:55:02.000000000 +0200
+++ usb-linux.c 2007-08-16 14:54:37.000000000 +0200
@@ -46,8 +46,7 @@ typedef int USBScanFunc(void *opaque, in
static int usb_host_find_device(int *pbus_num, int *paddr,
char *product_name, int product_name_size,
const char *devname);
-
-//#define DEBUG
+#define DEBUG
#define USBDEVFS_PATH "/proc/bus/usb"
#define PRODUCT_NAME_SZ 32
@@ -55,8 +54,88 @@ static int usb_host_find_device(int *pbu
typedef struct USBHostDevice {
USBDevice dev;
int fd;
+ int configuration;
+ uint8_t descr[1024];
+ int descr_len;
} USBHostDevice;
+static int usb_host_update_interfaces(USBHostDevice *dev, int configuration)
+{
+ int dev_descr_len, config_descr_len;
+ int interface, nb_interfaces, nb_configurations;
+ int ret, i;
+
+ if (configuration == 0) // address state - ignore
+ return 1;
+
+ i = 0;
+ dev_descr_len = dev->descr[0];
+ if (dev_descr_len > dev->descr_len)
+ goto fail;
+ nb_configurations = dev->descr[17];
+
+ i += dev_descr_len;
+ while (i < dev->descr_len) {
+#ifdef DEBUG
+ printf("i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len,
+ dev->descr[i], dev->descr[i+1]);
+#endif
+ if (dev->descr[i+1] != USB_DT_CONFIG) {
+ i += dev->descr[i];
+ continue;
+ }
+ config_descr_len = dev->descr[i];
+
+ if (configuration == dev->descr[i + 5])
+ break;
+
+ i += config_descr_len;
+ }
+
+ if (i >= dev->descr_len) {
+ printf("usb_host: error - device has no matching configuration\n");
+ goto fail;
+ }
+ nb_interfaces = dev->descr[i + 4];
+
+#ifdef USBDEVFS_DISCONNECT
+ /* earlier Linux 2.4 do not support that */
+ {
+ struct usbdevfs_ioctl ctrl;
+ for (interface = 0; interface < nb_interfaces; interface++) {
+ ctrl.ioctl_code = USBDEVFS_DISCONNECT;
+ ctrl.ifno = interface;
+ ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
+ if (ret < 0 && errno != ENODATA) {
+ perror("USBDEVFS_DISCONNECT");
+ goto fail;
+ }
+ }
+ }
+#endif
+
+ /* XXX: only grab if all interfaces are free */
+ for (interface = 0; interface < nb_interfaces; interface++) {
+ ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
+ if (ret < 0) {
+ if (errno == EBUSY) {
+ fprintf(stderr, "usb_host: warning - device already grabbed\n");
+ } else {
+ perror("USBDEVFS_CLAIMINTERFACE");
+ }
+ fail:
+ return 0;
+ }
+ }
+
+#ifdef DEBUG
+ printf("usb_host: %d interfaces claimed for configuration %d\n", nb_interfaces,
+ configuration);
+#endif
+
+ return 1;
+}
+
static void usb_host_handle_reset(USBDevice *dev)
{
#if 0
@@ -85,13 +164,25 @@ static int usb_host_handle_control(USBDe
{
USBHostDevice *s = (USBHostDevice *)dev;
struct usb_ctrltransfer ct;
+ int intf_update_required = 0;
int ret;
if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
/* specific SET_ADDRESS support */
dev->addr = value;
return 0;
+ } else if (request == (DeviceOutRequest | USB_REQ_SET_CONFIGURATION)) {
+#ifdef DEBUG
+ printf("usb_host_handle_control: SET_CONFIGURATION request - config %d\n",
+ value & 0xff);
+#endif
+ if (s->configuration != (value & 0xff)) {
+ s->configuration = (value & 0xff);
+ intf_update_required = 1;
+ }
+ goto do_request;
} else {
+ do_request:
ct.bRequestType = request >> 8;
ct.bRequest = request;
ct.wValue = value;
@@ -108,6 +199,12 @@ static int usb_host_handle_control(USBDe
return USB_RET_STALL;
}
} else {
+ if (intf_update_required) {
+#ifdef DEBUG
+ printf("usb_host_handle_control: updating interfaces\n");
+#endif
+ usb_host_update_interfaces(s, value & 0xff);
+ }
return ret;
}
}
@@ -148,15 +245,17 @@ static int usb_host_handle_data(USBDevic
/* XXX: exclude high speed devices or implement EHCI */
USBDevice *usb_host_device_open(const char *devname)
{
- int fd, interface, ret, i;
- USBHostDevice *dev;
+ int fd = -1, ret;
+ USBHostDevice *dev = NULL;
struct usbdevfs_connectinfo ci;
- uint8_t descr[1024];
char buf[1024];
- int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
int bus_num, addr;
char product_name[PRODUCT_NAME_SZ];
+ dev = qemu_mallocz(sizeof(USBHostDevice));
+ if (!dev)
+ goto fail;
+
if (usb_host_find_device(&bus_num, &addr,
product_name, sizeof(product_name),
devname) < 0)
@@ -170,55 +269,29 @@ USBDevice *usb_host_device_open(const ch
return NULL;
}
- /* read the config description */
- descr_len = read(fd, descr, sizeof(descr));
- if (descr_len <= 0) {
- perror("read descr");
- goto fail;
- }
-
- i = 0;
- dev_descr_len = descr[0];
- if (dev_descr_len > descr_len)
- goto fail;
- i += dev_descr_len;
- config_descr_len = descr[i];
- if (i + config_descr_len > descr_len)
- goto fail;
- nb_interfaces = descr[i + 4];
- if (nb_interfaces != 1) {
- /* NOTE: currently we grab only one interface */
- fprintf(stderr, "usb_host: only one interface supported\n");
+ /* read the device description */
+ dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
+ if (dev->descr_len <= 0) {
+ perror("usb_host_update_interfaces: reading device data failed");
goto fail;
}
-#ifdef USBDEVFS_DISCONNECT
- /* earlier Linux 2.4 do not support that */
+#ifdef DEBUG
{
- 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;
- }
+ int x;
+ printf("=== begin dumping device descriptor data ===\n");
+ for (x = 0; x < dev->descr_len; x++)
+ printf("%02x ", dev->descr[x]);
+ printf("\n=== end dumping device descriptor data ===\n");
}
#endif
- /* XXX: only grab if all interfaces are free */
- interface = 0;
- ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
- if (ret < 0) {
- if (errno == EBUSY) {
- fprintf(stderr, "usb_host: device already grabbed\n");
- } else {
- perror("USBDEVFS_CLAIMINTERFACE");
- }
- fail:
- close(fd);
- return NULL;
- }
+ dev->fd = fd;
+ dev->configuration = 1;
+
+ // XXX - do something about initial configuration
+ if (!usb_host_update_interfaces(dev, 1))
+ goto fail;
ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
if (ret < 0) {
@@ -230,10 +303,6 @@ USBDevice *usb_host_device_open(const ch
printf("host USB device %d.%d grabbed\n", bus_num, addr);
#endif
- dev = qemu_mallocz(sizeof(USBHostDevice));
- if (!dev)
- goto fail;
- dev->fd = fd;
if (ci.slow)
dev->dev.speed = USB_SPEED_LOW;
else
@@ -253,6 +322,11 @@ USBDevice *usb_host_device_open(const ch
product_name);
return (USBDevice *)dev;
+fail:
+ if (dev)
+ qemu_free(dev);
+ close(fd);
+ return NULL;
}
static int get_tag_value(char *buf, int buf_size,
reply other threads:[~2007-08-18 17:35 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46C72D9D.5000109@gmx.at \
--to=andreas.winkelbauer@gmx.at \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.