* [Qemu-devel] [PATCH 01/14] usb-linux: introduce a usb_linux_alt_setting function
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 02/14] usb-linux: Get the alt. setting from sysfs rather then asking the dev Gerd Hoffmann
` (13 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
The next patch in this series introduces multiple ways to get the
alt setting dependent upon usb_fs_type, it is cleaner to put this
into its own function.
Note that this patch also changes the assumed alt setting in case
of an error getting the alt setting to be 0 (a sane default) rather
then the interface numberwhich makes no sense.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 40 +++++++++++++++++++++++++---------------
1 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index 1f33c2c..353e1b1 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -823,13 +823,35 @@ usbdevfs:
return configuration;
}
+static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
+ uint8_t configuration, uint8_t interface)
+{
+ uint8_t alt_setting;
+ struct usb_ctrltransfer ct;
+ int ret;
+
+ ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
+ ct.bRequest = USB_REQ_GET_INTERFACE;
+ ct.wValue = 0;
+ ct.wIndex = interface;
+ ct.wLength = 1;
+ ct.data = &alt_setting;
+ ct.timeout = 50;
+ ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
+ if (ret < 0) {
+ /* Assume alt 0 on error */
+ return 0;
+ }
+
+ return alt_setting;
+}
+
/* returns 1 on problem encountered or 0 for success */
static int usb_linux_update_endp_table(USBHostDevice *s)
{
uint8_t *descriptors;
uint8_t devep, type, configuration, alt_interface;
- struct usb_ctrltransfer ct;
- int interface, ret, length, i;
+ int interface, length, i;
i = usb_linux_get_configuration(s);
if (i < 0)
@@ -858,19 +880,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
interface = descriptors[i + 2];
-
- ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
- ct.bRequest = USB_REQ_GET_INTERFACE;
- ct.wValue = 0;
- ct.wIndex = interface;
- ct.wLength = 1;
- ct.data = &alt_interface;
- ct.timeout = 50;
-
- ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
- if (ret < 0) {
- alt_interface = interface;
- }
+ alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
/* the current interface descriptor is the active interface
* and has endpoints */
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 02/14] usb-linux: Get the alt. setting from sysfs rather then asking the dev
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 01/14] usb-linux: introduce a usb_linux_alt_setting function Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 03/14] usb-linux: Add support for buffering iso usb packets Gerd Hoffmann
` (12 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
At least one device I have lies when receiving a USB_REQ_GET_INTERFACE,
always returning 0 even if the alternate setting is different. This is
likely caused because in practice this control message is never used as
the operating system's usb stack knows which alternate setting it has
told the device to get into, and thus this ctrl message does not get
tested by device manufacturers.
When usb_fs_type == USB_FS_SYS, the active alt. setting can be read directly
from sysfs, which allows using this device through qemu's usb redirection.
More in general it seems a good idea to not send needless control msg's to
devices, esp. as the code in question is called every time a set_interface
is done. Which happens multiple times during virtual machine startup, and
when device drivers are activating the usb device.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index 353e1b1..f4601e6 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -830,6 +830,24 @@ static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
struct usb_ctrltransfer ct;
int ret;
+ if (usb_fs_type == USB_FS_SYS) {
+ char device_name[64], line[1024];
+ int alt_setting;
+
+ sprintf(device_name, "%d-%d:%d.%d", s->bus_num, s->devpath,
+ (int)configuration, (int)interface);
+
+ if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
+ device_name)) {
+ goto usbdevfs;
+ }
+ if (sscanf(line, "%d", &alt_setting) != 1) {
+ goto usbdevfs;
+ }
+ return alt_setting;
+ }
+
+usbdevfs:
ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
ct.bRequest = USB_REQ_GET_INTERFACE;
ct.wValue = 0;
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 03/14] usb-linux: Add support for buffering iso usb packets
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 01/14] usb-linux: introduce a usb_linux_alt_setting function Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 02/14] usb-linux: Get the alt. setting from sysfs rather then asking the dev Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 04/14] usb-linux: Refuse packets for endpoints which are not in the usb descriptor Gerd Hoffmann
` (11 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
Currently we are submitting iso packets to the host one at a time, as we
receive them from the emulated host controller. This has 2 problems:
1) If we were fast enough to submit every packet in time for the next host host
controller usb frame, we would be generating 1000 hardware interrupts per
second on the host
2) We are not fast enough to submit every packet in time for the next host host
controller usb frame, causing us to not submit iso urbs in some usb frames
which causes devices with an endpoint with an interval of 1 ms (so every
frame) to loose data. This causes for example ubs-1.1 webcams to not work
properly (usb-2.0 is not supported at all atm).
This patch fixes both problems by changing the iso packet pass through handling
to buffer packets. This version only does so for iso input packets (webcams,
audio in) I'm working on a second patch extending this to iso output packets
(audio out).
This patch makes use of the linux batching of iso packets in one urb.
When an iso in packet gets received from the emulated host controller,
it immediately submits 3 urbs with 32 iso in packets each. This causes
the host to only get an hw interrupt every 32 packets dropping the
interrupt rate to 32 interrupts per second and gives it a queue of urbs
to work from once the first 32 iso in packets have been received to make sure
no packets are dropped.
Besides submitting a whole bunch or urbs as soon as the first urb is
received, effectively creating a buffer inside the kernel, this patch also
gets rid of the asynchroneous completion for iso in urbs. Instead they are
only marked as complete in the fd write callback (which usbfs uses to signal
complete urbs). These complete packets then get consumed by returning them
synchroneously to the emulated host controller when it submits an iso in
packet for the ep in question. When no complete packets are ready (which
happens when the stream is starting) a 0 length packet gets returned to
the emulated host controller.
With this patch I've several usb-1.1 webcams working well with usb pass
through, where as without this patch none of them work.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 226 insertions(+), 17 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index f4601e6..a68603d 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -92,9 +92,17 @@ static char *usb_host_device_path;
static int usb_fs_type;
/* endpoint association data */
+#define ISO_FRAME_DESC_PER_URB 32
+#define ISO_URB_COUNT 3
+
+typedef struct AsyncURB AsyncURB;
+
struct endp_data {
uint8_t type;
uint8_t halted;
+ AsyncURB *iso_urb;
+ int iso_urb_idx;
+ int max_packet_size;
};
enum {
@@ -175,19 +183,48 @@ static void set_halt(USBHostDevice *s, int ep)
s->endp_table[ep - 1].halted = 1;
}
+static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
+{
+ s->endp_table[ep - 1].iso_urb = iso_urb;
+}
+
+static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
+{
+ return s->endp_table[ep - 1].iso_urb;
+}
+
+static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
+{
+ s->endp_table[ep - 1].iso_urb_idx = i;
+}
+
+static int get_iso_urb_idx(USBHostDevice *s, int ep)
+{
+ return s->endp_table[ep - 1].iso_urb_idx;
+}
+
+static int get_max_packet_size(USBHostDevice *s, int ep)
+{
+ return s->endp_table[ep - 1].max_packet_size;
+}
+
/*
* Async URB state.
- * We always allocate one isoc descriptor even for bulk transfers
+ * We always allocate iso packet descriptors even for bulk transfers
* to simplify allocation and casts.
*/
-typedef struct AsyncURB
+struct AsyncURB
{
struct usbdevfs_urb urb;
- struct usbdevfs_iso_packet_desc isocpd;
+ struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
+ /* For regular async urbs */
USBPacket *packet;
USBHostDevice *hdev;
-} AsyncURB;
+
+ /* For buffered iso handling */
+ int iso_frame_idx; /* -1 means in flight */
+};
static AsyncURB *async_alloc(void)
{
@@ -244,11 +281,21 @@ static void async_complete(void *opaque)
return;
}
- p = aurb->packet;
-
DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aurb, aurb->urb.status, aurb->urb.actual_length);
+ /* If this is a buffered iso urb mark it as complete and don't do
+ anything else (it is handled further in usb_host_handle_iso_data) */
+ if (aurb->iso_frame_idx == -1) {
+ if (aurb->urb.status == -EPIPE) {
+ set_halt(s, aurb->urb.endpoint & 0xf);
+ }
+ aurb->iso_frame_idx = 0;
+ continue;
+ }
+
+ p = aurb->packet;
+
if (p) {
switch (aurb->urb.status) {
case 0:
@@ -415,34 +462,181 @@ static void usb_host_handle_destroy(USBDevice *dev)
static int usb_linux_update_endp_table(USBHostDevice *s);
+/* iso data is special, we need to keep enough urbs in flight to make sure
+ that the controller never runs out of them, otherwise the device will
+ likely suffer a buffer underrun / overrun. */
+static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
+{
+ AsyncURB *aurb;
+ int i, j, len = get_max_packet_size(s, ep);
+
+ aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb));
+ for (i = 0; i < ISO_URB_COUNT; i++) {
+ aurb[i].urb.endpoint = ep;
+ aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
+ aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length);
+ aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
+ aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
+ aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
+ for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
+ aurb[i].urb.iso_frame_desc[j].length = len;
+ if (in) {
+ aurb[i].urb.endpoint |= 0x80;
+ /* Mark as fully consumed (idle) */
+ aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
+ }
+ }
+ set_iso_urb(s, ep, aurb);
+
+ return aurb;
+}
+
+static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
+{
+ AsyncURB *aurb;
+ int i, ret, killed = 0, free = 1;
+
+ aurb = get_iso_urb(s, ep);
+ if (!aurb) {
+ return;
+ }
+
+ for (i = 0; i < ISO_URB_COUNT; i++) {
+ /* in flight? */
+ if (aurb[i].iso_frame_idx == -1) {
+ ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
+ if (ret < 0) {
+ printf("husb: discard isoc in urb failed errno %d\n", errno);
+ free = 0;
+ continue;
+ }
+ killed++;
+ }
+ }
+
+ /* Make sure any urbs we've killed are reaped before we free them */
+ if (killed) {
+ async_complete(s);
+ }
+
+ for (i = 0; i < ISO_URB_COUNT; i++) {
+ qemu_free(aurb[i].urb.buffer);
+ }
+
+ if (free)
+ qemu_free(aurb);
+ else
+ printf("husb: leaking iso urbs because of discard failure\n");
+ set_iso_urb(s, ep, NULL);
+}
+
+static int urb_status_to_usb_ret(int status)
+{
+ switch (status) {
+ case -EPIPE:
+ return USB_RET_STALL;
+ default:
+ return USB_RET_NAK;
+ }
+}
+
+static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p)
+{
+ AsyncURB *aurb;
+ int i, j, ret, len = 0;
+
+ aurb = get_iso_urb(s, p->devep);
+ if (!aurb) {
+ aurb = usb_host_alloc_iso(s, p->devep, 1);
+ }
+
+ i = get_iso_urb_idx(s, p->devep);
+ j = aurb[i].iso_frame_idx;
+ if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
+ /* Check urb status */
+ if (aurb[i].urb.status) {
+ len = urb_status_to_usb_ret(aurb[i].urb.status);
+ /* Move to the next urb */
+ aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
+ /* Check frame status */
+ } else if (aurb[i].urb.iso_frame_desc[j].status) {
+ len = urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status);
+ /* Check the frame fits */
+ } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
+ printf("husb: error received isoc data is larger then packet\n");
+ len = USB_RET_NAK;
+ /* All good copy data over */
+ } else {
+ len = aurb[i].urb.iso_frame_desc[j].actual_length;
+ memcpy(p->data,
+ aurb[i].urb.buffer +
+ j * aurb[i].urb.iso_frame_desc[0].length,
+ len);
+ }
+ aurb[i].iso_frame_idx++;
+ if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+ i = (i + 1) % ISO_URB_COUNT;
+ set_iso_urb_idx(s, p->devep, i);
+ }
+ }
+
+ /* (Re)-submit all fully consumed urbs */
+ for (i = 0; i < ISO_URB_COUNT; i++) {
+ if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+ ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
+ if (ret < 0) {
+ printf("husb error submitting isoc urb %d: %d\n", i, errno);
+ if (len == 0) {
+ switch(errno) {
+ case ETIMEDOUT:
+ len = USB_RET_NAK;
+ case EPIPE:
+ default:
+ len = USB_RET_STALL;
+ }
+ }
+ break;
+ }
+ aurb[i].iso_frame_idx = -1;
+ }
+ }
+
+ return len;
+}
+
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
{
struct usbdevfs_urb *urb;
AsyncURB *aurb;
int ret;
-
- aurb = async_alloc();
- aurb->hdev = s;
- aurb->packet = p;
-
- urb = &aurb->urb;
+ uint8_t ep;
if (p->pid == USB_TOKEN_IN) {
- urb->endpoint = p->devep | 0x80;
+ ep = p->devep | 0x80;
} else {
- urb->endpoint = p->devep;
+ ep = p->devep;
}
if (is_halted(s, p->devep)) {
- ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
+ ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
if (ret < 0) {
DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
- urb->endpoint, errno);
+ ep, errno);
return USB_RET_NAK;
}
clear_halt(s, p->devep);
}
+ if (is_isoc(s, p->devep) && p->pid == USB_TOKEN_IN)
+ return usb_host_handle_iso_data(s, p);
+
+ aurb = async_alloc();
+ aurb->hdev = s;
+ aurb->packet = p;
+
+ urb = &aurb->urb;
+
+ urb->endpoint = ep;
urb->buffer = p->data;
urb->buffer_length = p->len;
@@ -515,7 +709,13 @@ static int usb_host_set_config(USBHostDevice *s, int config)
static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
{
struct usbdevfs_setinterface si;
- int ret;
+ int i, ret;
+
+ for (i = 1; i < MAX_ENDPOINTS; i++) {
+ if (is_isoc(s, i)) {
+ usb_host_stop_n_free_iso(s, i);
+ }
+ }
si.interface = iface;
si.altsetting = alt;
@@ -927,6 +1127,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
break;
case 0x01:
type = USBDEVFS_URB_TYPE_ISO;
+ s->endp_table[(devep & 0xf) - 1].max_packet_size =
+ descriptors[i + 4] + (descriptors[i + 5] << 8);
break;
case 0x02:
type = USBDEVFS_URB_TYPE_BULK;
@@ -1049,12 +1251,19 @@ fail:
static int usb_host_close(USBHostDevice *dev)
{
+ int i;
+
if (dev->fd == -1) {
return -1;
}
qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
dev->closing = 1;
+ for (i = 1; i < MAX_ENDPOINTS; i++) {
+ if (is_isoc(dev, i)) {
+ usb_host_stop_n_free_iso(dev, i);
+ }
+ }
async_complete(dev);
dev->closing = 0;
usb_device_detach(&dev->dev);
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 04/14] usb-linux: Refuse packets for endpoints which are not in the usb descriptor
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (2 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 03/14] usb-linux: Add support for buffering iso usb packets Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 05/14] usb-linux: Refuse iso packets when max packet size is 0 (alt setting 0) Gerd Hoffmann
` (10 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
If an endpoint is not in the usb descriptor we've no idea what kind of
endpoint it is and thus how to handle it, refuse packages in this case.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index a68603d..6aef7a5 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -94,6 +94,7 @@ static int usb_fs_type;
/* endpoint association data */
#define ISO_FRAME_DESC_PER_URB 32
#define ISO_URB_COUNT 3
+#define INVALID_EP_TYPE 255
typedef struct AsyncURB AsyncURB;
@@ -168,6 +169,11 @@ static int is_isoc(USBHostDevice *s, int ep)
return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
}
+static int is_valid(USBHostDevice *s, int ep)
+{
+ return s->endp_table[ep - 1].type != INVALID_EP_TYPE;
+}
+
static int is_halted(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].halted;
@@ -611,6 +617,10 @@ static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
int ret;
uint8_t ep;
+ if (!is_valid(s, p->devep)) {
+ return USB_RET_NAK;
+ }
+
if (p->pid == USB_TOKEN_IN) {
ep = p->devep | 0x80;
} else {
@@ -1071,6 +1081,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
uint8_t devep, type, configuration, alt_interface;
int interface, length, i;
+ for (i = 0; i < MAX_ENDPOINTS; i++)
+ s->endp_table[i].type = INVALID_EP_TYPE;
+
i = usb_linux_get_configuration(s);
if (i < 0)
return 1;
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 05/14] usb-linux: Refuse iso packets when max packet size is 0 (alt setting 0)
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (3 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 04/14] usb-linux: Refuse packets for endpoints which are not in the usb descriptor Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 06/14] usb-linux: We only need to keep track of 15 endpoints Gerd Hoffmann
` (9 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
Refuse iso usb packets when then max packet size for the endpoint is 0,
this avoids an abort in usb_host_alloc_iso() caused by trying to qemu_malloc
a 0 bytes large buffer.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index 6aef7a5..4c42fe1 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -549,7 +549,11 @@ static int urb_status_to_usb_ret(int status)
static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p)
{
AsyncURB *aurb;
- int i, j, ret, len = 0;
+ int i, j, ret, max_packet_size, len = 0;
+
+ max_packet_size = get_max_packet_size(s, p->devep);
+ if (max_packet_size == 0)
+ return USB_RET_NAK;
aurb = get_iso_urb(s, p->devep);
if (!aurb) {
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 06/14] usb-linux: We only need to keep track of 15 endpoints
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (4 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 05/14] usb-linux: Refuse iso packets when max packet size is 0 (alt setting 0) Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 07/14] usb-linux: Add support for buffering iso out usb packets Gerd Hoffmann
` (8 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
Currently we reserve room for endpoint data for 16 endpoints, but given
that we only use endpoint data for endpoints 1-15, and always index the
array with the endpoint-number - 1, 15 is enough.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index 4c42fe1..4498b16 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -78,7 +78,7 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
#define USBPROCBUS_PATH "/proc/bus/usb"
#define PRODUCT_NAME_SZ 32
-#define MAX_ENDPOINTS 16
+#define MAX_ENDPOINTS 15
#define USBDEVBUS_PATH "/dev/bus/usb"
#define USBSYSBUS_PATH "/sys/bus/usb"
@@ -725,7 +725,7 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
struct usbdevfs_setinterface si;
int i, ret;
- for (i = 1; i < MAX_ENDPOINTS; i++) {
+ for (i = 1; i <= MAX_ENDPOINTS; i++) {
if (is_isoc(s, i)) {
usb_host_stop_n_free_iso(s, i);
}
@@ -1276,7 +1276,7 @@ static int usb_host_close(USBHostDevice *dev)
qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
dev->closing = 1;
- for (i = 1; i < MAX_ENDPOINTS; i++) {
+ for (i = 1; i <= MAX_ENDPOINTS; i++) {
if (is_isoc(dev, i)) {
usb_host_stop_n_free_iso(dev, i);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 07/14] usb-linux: Add support for buffering iso out usb packets
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (5 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 06/14] usb-linux: We only need to keep track of 15 endpoints Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 08/14] usb: control buffer fixes Gerd Hoffmann
` (7 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
Extend the iso buffering code to also buffer iso out packets, this
fixes for example using usb speakers with usb redirection.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 152 +++++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 101 insertions(+), 51 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index 4498b16..730eac2 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -101,8 +101,10 @@ typedef struct AsyncURB AsyncURB;
struct endp_data {
uint8_t type;
uint8_t halted;
+ uint8_t iso_started;
AsyncURB *iso_urb;
int iso_urb_idx;
+ int iso_buffer_used;
int max_packet_size;
};
@@ -189,6 +191,21 @@ static void set_halt(USBHostDevice *s, int ep)
s->endp_table[ep - 1].halted = 1;
}
+static int is_iso_started(USBHostDevice *s, int ep)
+{
+ return s->endp_table[ep - 1].iso_started;
+}
+
+static void clear_iso_started(USBHostDevice *s, int ep)
+{
+ s->endp_table[ep - 1].iso_started = 0;
+}
+
+static void set_iso_started(USBHostDevice *s, int ep)
+{
+ s->endp_table[ep - 1].iso_started = 1;
+}
+
static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
{
s->endp_table[ep - 1].iso_urb = iso_urb;
@@ -209,6 +226,16 @@ static int get_iso_urb_idx(USBHostDevice *s, int ep)
return s->endp_table[ep - 1].iso_urb_idx;
}
+static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
+{
+ s->endp_table[ep - 1].iso_buffer_used = i;
+}
+
+static int get_iso_buffer_used(USBHostDevice *s, int ep)
+{
+ return s->endp_table[ep - 1].iso_buffer_used;
+}
+
static int get_max_packet_size(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].max_packet_size;
@@ -534,6 +561,8 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
else
printf("husb: leaking iso urbs because of discard failure\n");
set_iso_urb(s, ep, NULL);
+ set_iso_urb_idx(s, ep, 0);
+ clear_iso_started(s, ep);
}
static int urb_status_to_usb_ret(int status)
@@ -546,10 +575,10 @@ static int urb_status_to_usb_ret(int status)
}
}
-static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p)
+static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
{
AsyncURB *aurb;
- int i, j, ret, max_packet_size, len = 0;
+ int i, j, ret, max_packet_size, offset, len = 0;
max_packet_size = get_max_packet_size(s, p->devep);
if (max_packet_size == 0)
@@ -557,57 +586,88 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p)
aurb = get_iso_urb(s, p->devep);
if (!aurb) {
- aurb = usb_host_alloc_iso(s, p->devep, 1);
+ aurb = usb_host_alloc_iso(s, p->devep, in);
}
i = get_iso_urb_idx(s, p->devep);
j = aurb[i].iso_frame_idx;
if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
- /* Check urb status */
- if (aurb[i].urb.status) {
- len = urb_status_to_usb_ret(aurb[i].urb.status);
- /* Move to the next urb */
- aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
- /* Check frame status */
- } else if (aurb[i].urb.iso_frame_desc[j].status) {
- len = urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status);
- /* Check the frame fits */
- } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
- printf("husb: error received isoc data is larger then packet\n");
- len = USB_RET_NAK;
- /* All good copy data over */
+ if (in) {
+ /* Check urb status */
+ if (aurb[i].urb.status) {
+ len = urb_status_to_usb_ret(aurb[i].urb.status);
+ /* Move to the next urb */
+ aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
+ /* Check frame status */
+ } else if (aurb[i].urb.iso_frame_desc[j].status) {
+ len = urb_status_to_usb_ret(
+ aurb[i].urb.iso_frame_desc[j].status);
+ /* Check the frame fits */
+ } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
+ printf("husb: received iso data is larger then packet\n");
+ len = USB_RET_NAK;
+ /* All good copy data over */
+ } else {
+ len = aurb[i].urb.iso_frame_desc[j].actual_length;
+ memcpy(p->data,
+ aurb[i].urb.buffer +
+ j * aurb[i].urb.iso_frame_desc[0].length,
+ len);
+ }
} else {
- len = aurb[i].urb.iso_frame_desc[j].actual_length;
- memcpy(p->data,
- aurb[i].urb.buffer +
- j * aurb[i].urb.iso_frame_desc[0].length,
- len);
+ len = p->len;
+ offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
+
+ /* Check the frame fits */
+ if (len > max_packet_size) {
+ printf("husb: send iso data is larger then max packet size\n");
+ return USB_RET_NAK;
+ }
+
+ /* All good copy data over */
+ memcpy(aurb[i].urb.buffer + offset, p->data, len);
+ aurb[i].urb.iso_frame_desc[j].length = len;
+ offset += len;
+ set_iso_buffer_used(s, p->devep, offset);
+
+ /* Start the stream once we have buffered enough data */
+ if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
+ set_iso_started(s, p->devep);
+ }
}
aurb[i].iso_frame_idx++;
if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
i = (i + 1) % ISO_URB_COUNT;
set_iso_urb_idx(s, p->devep, i);
}
+ } else {
+ if (in) {
+ set_iso_started(s, p->devep);
+ } else {
+ DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
+ }
}
- /* (Re)-submit all fully consumed urbs */
- for (i = 0; i < ISO_URB_COUNT; i++) {
- if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
- ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
- if (ret < 0) {
- printf("husb error submitting isoc urb %d: %d\n", i, errno);
- if (len == 0) {
- switch(errno) {
- case ETIMEDOUT:
- len = USB_RET_NAK;
- case EPIPE:
- default:
- len = USB_RET_STALL;
+ if (is_iso_started(s, p->devep)) {
+ /* (Re)-submit all fully consumed / filled urbs */
+ for (i = 0; i < ISO_URB_COUNT; i++) {
+ if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+ ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
+ if (ret < 0) {
+ printf("husb error submitting iso urb %d: %d\n", i, errno);
+ if (!in || len == 0) {
+ switch(errno) {
+ case ETIMEDOUT:
+ len = USB_RET_NAK;
+ case EPIPE:
+ default:
+ len = USB_RET_STALL;
+ }
}
+ break;
}
- break;
+ aurb[i].iso_frame_idx = -1;
}
- aurb[i].iso_frame_idx = -1;
}
}
@@ -641,8 +701,9 @@ static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
clear_halt(s, p->devep);
}
- if (is_isoc(s, p->devep) && p->pid == USB_TOKEN_IN)
- return usb_host_handle_iso_data(s, p);
+ if (is_isoc(s, p->devep)) {
+ return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
+ }
aurb = async_alloc();
aurb->hdev = s;
@@ -653,19 +714,8 @@ static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
urb->endpoint = ep;
urb->buffer = p->data;
urb->buffer_length = p->len;
-
- if (is_isoc(s, p->devep)) {
- /* Setup ISOC transfer */
- urb->type = USBDEVFS_URB_TYPE_ISO;
- urb->flags = USBDEVFS_URB_ISO_ASAP;
- urb->number_of_packets = 1;
- urb->iso_frame_desc[0].length = p->len;
- } else {
- /* Setup bulk transfer */
- urb->type = USBDEVFS_URB_TYPE_BULK;
- }
-
- urb->usercontext = s;
+ urb->type = USBDEVFS_URB_TYPE_BULK;
+ urb->usercontext = s;
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 08/14] usb: control buffer fixes
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (6 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 07/14] usb-linux: Add support for buffering iso out usb packets Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 09/14] uhci: switch to QTAILQ Gerd Hoffmann
` (6 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
Windows allows control transfers to pass up to 4k of data, so raise our
control buffer size to 4k. For control out transfers the usb core code copies
the control request data to a buffer before calling the device's handle_control
callback. Add a check for overflowing the buffer before copying the data.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb.c | 6 ++++++
hw/usb.h | 2 +-
2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/hw/usb.c b/hw/usb.c
index 82a6217..d8c0a75 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -93,6 +93,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
s->setup_len = ret;
s->setup_state = SETUP_STATE_DATA;
} else {
+ if (s->setup_len > sizeof(s->data_buf)) {
+ fprintf(stderr,
+ "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
+ s->setup_len, sizeof(s->data_buf));
+ return USB_RET_STALL;
+ }
if (s->setup_len == 0)
s->setup_state = SETUP_STATE_ACK;
else
diff --git a/hw/usb.h b/hw/usb.h
index d3d755d..22bb338 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -167,7 +167,7 @@ struct USBDevice {
int32_t state;
uint8_t setup_buf[8];
- uint8_t data_buf[1024];
+ uint8_t data_buf[4096];
int32_t remote_wakeup;
int32_t setup_state;
int32_t setup_len;
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 09/14] uhci: switch to QTAILQ
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (7 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 08/14] usb: control buffer fixes Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 10/14] uhci: keep uhci state pointer in async packet struct Gerd Hoffmann
` (5 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-uhci.c | 63 +++++++++++++-------------------------------------------
1 files changed, 15 insertions(+), 48 deletions(-)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 346db3e..2de0cf2 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -113,7 +113,7 @@ static void dump_data(const uint8_t *data, int len) {}
*/
typedef struct UHCIAsync {
USBPacket packet;
- struct UHCIAsync *next;
+ QTAILQ_ENTRY(UHCIAsync) next;
uint32_t td;
uint32_t token;
int8_t valid;
@@ -145,8 +145,7 @@ typedef struct UHCIState {
uint32_t pending_int_mask;
/* Active packets */
- UHCIAsync *async_pending;
- UHCIAsync *async_pool;
+ QTAILQ_HEAD(,UHCIAsync) async_pending;
uint8_t num_ports_vmstate;
} UHCIState;
@@ -172,7 +171,6 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
async->token = 0;
async->done = 0;
async->isoc = 0;
- async->next = NULL;
return async;
}
@@ -184,24 +182,12 @@ static void uhci_async_free(UHCIState *s, UHCIAsync *async)
static void uhci_async_link(UHCIState *s, UHCIAsync *async)
{
- async->next = s->async_pending;
- s->async_pending = async;
+ QTAILQ_INSERT_HEAD(&s->async_pending, async, next);
}
static void uhci_async_unlink(UHCIState *s, UHCIAsync *async)
{
- UHCIAsync *curr = s->async_pending;
- UHCIAsync **prev = &s->async_pending;
-
- while (curr) {
- if (curr == async) {
- *prev = curr->next;
- return;
- }
-
- prev = &curr->next;
- curr = curr->next;
- }
+ QTAILQ_REMOVE(&s->async_pending, async, next);
}
static void uhci_async_cancel(UHCIState *s, UHCIAsync *async)
@@ -220,11 +206,10 @@ static void uhci_async_cancel(UHCIState *s, UHCIAsync *async)
*/
static UHCIAsync *uhci_async_validate_begin(UHCIState *s)
{
- UHCIAsync *async = s->async_pending;
+ UHCIAsync *async;
- while (async) {
+ QTAILQ_FOREACH(async, &s->async_pending, next) {
async->valid--;
- async = async->next;
}
return NULL;
}
@@ -234,47 +219,30 @@ static UHCIAsync *uhci_async_validate_begin(UHCIState *s)
*/
static void uhci_async_validate_end(UHCIState *s)
{
- UHCIAsync *curr = s->async_pending;
- UHCIAsync **prev = &s->async_pending;
- UHCIAsync *next;
+ UHCIAsync *curr, *n;
- while (curr) {
+ QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
if (curr->valid > 0) {
- prev = &curr->next;
- curr = curr->next;
continue;
}
-
- next = curr->next;
-
- /* Unlink */
- *prev = next;
-
+ uhci_async_unlink(s, curr);
uhci_async_cancel(s, curr);
-
- curr = next;
}
}
static void uhci_async_cancel_all(UHCIState *s)
{
- UHCIAsync *curr = s->async_pending;
- UHCIAsync *next;
-
- while (curr) {
- next = curr->next;
+ UHCIAsync *curr, *n;
+ QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+ uhci_async_unlink(s, curr);
uhci_async_cancel(s, curr);
-
- curr = next;
}
-
- s->async_pending = NULL;
}
static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token)
{
- UHCIAsync *async = s->async_pending;
+ UHCIAsync *async;
UHCIAsync *match = NULL;
int count = 0;
@@ -291,7 +259,7 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
* If we ever do we'd want to optimize this algorithm.
*/
- while (async) {
+ QTAILQ_FOREACH(async, &s->async_pending, next) {
if (async->token == token) {
/* Good match */
match = async;
@@ -301,8 +269,6 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
break;
}
}
-
- async = async->next;
count++;
}
@@ -1137,6 +1103,7 @@ static int usb_uhci_common_initfn(UHCIState *s)
s->expire_time = qemu_get_clock_ns(vm_clock) +
(get_ticks_per_sec() / FRAME_TIMER_FREQ);
s->num_ports_vmstate = NB_PORTS;
+ QTAILQ_INIT(&s->async_pending);
qemu_register_reset(uhci_reset, s);
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 10/14] uhci: keep uhci state pointer in async packet struct.
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (8 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 09/14] uhci: switch to QTAILQ Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 11/14] ohci: get ohci state via container_of() Gerd Hoffmann
` (4 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-uhci.c | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 2de0cf2..2b63b3f 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -106,6 +106,8 @@ static void dump_data(const uint8_t *data, int len)
static void dump_data(const uint8_t *data, int len) {}
#endif
+typedef struct UHCIState UHCIState;
+
/*
* Pending async transaction.
* 'packet' must be the first field because completion
@@ -113,6 +115,7 @@ static void dump_data(const uint8_t *data, int len) {}
*/
typedef struct UHCIAsync {
USBPacket packet;
+ UHCIState *uhci;
QTAILQ_ENTRY(UHCIAsync) next;
uint32_t td;
uint32_t token;
@@ -127,7 +130,7 @@ typedef struct UHCIPort {
uint16_t ctrl;
} UHCIPort;
-typedef struct UHCIState {
+struct UHCIState {
PCIDevice dev;
USBBus bus;
uint16_t cmd; /* cmd register */
@@ -147,7 +150,7 @@ typedef struct UHCIState {
/* Active packets */
QTAILQ_HEAD(,UHCIAsync) async_pending;
uint8_t num_ports_vmstate;
-} UHCIState;
+};
typedef struct UHCI_TD {
uint32_t link;
@@ -166,6 +169,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
UHCIAsync *async = qemu_malloc(sizeof(UHCIAsync));
memset(&async->packet, 0, sizeof(async->packet));
+ async->uhci = s;
async->valid = 0;
async->td = 0;
async->token = 0;
@@ -830,8 +834,8 @@ done:
static void uhci_async_complete(USBPacket *packet, void *opaque)
{
- UHCIState *s = opaque;
- UHCIAsync *async = (UHCIAsync *) packet;
+ UHCIAsync *async = container_of(packet, UHCIAsync, packet);
+ UHCIState *s = async->uhci;
DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token);
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 11/14] ohci: get ohci state via container_of()
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (9 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 10/14] uhci: keep uhci state pointer in async packet struct Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 12/14] musb: get musb " Gerd Hoffmann
` (3 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-ohci.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 0ad4f55..7678cdb 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -577,7 +577,7 @@ static void ohci_process_lists(OHCIState *ohci, int completion);
static void ohci_async_complete_packet(USBPacket *packet, void *opaque)
{
- OHCIState *ohci = opaque;
+ OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
#ifdef DEBUG_PACKET
DPRINTF("Async packet complete\n");
#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 12/14] musb: get musb state via container_of()
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (10 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 11/14] ohci: get ohci state via container_of() Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 13/14] usb: move complete callback to port ops Gerd Hoffmann
` (2 subsequent siblings)
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-musb.c | 54 ++++++++++++++++++++++++++++++++++--------------------
1 files changed, 34 insertions(+), 20 deletions(-)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 15bc549..30148e7 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -267,7 +267,16 @@ static USBPortOps musb_port_ops = {
.detach = musb_detach,
};
-typedef struct {
+typedef struct MUSBPacket MUSBPacket;
+typedef struct MUSBEndPoint MUSBEndPoint;
+
+struct MUSBPacket {
+ USBPacket p;
+ MUSBEndPoint *ep;
+ int dir;
+};
+
+struct MUSBEndPoint {
uint16_t faddr[2];
uint8_t haddr[2];
uint8_t hport[2];
@@ -284,7 +293,7 @@ typedef struct {
int fifolen[2];
int fifostart[2];
int fifoaddr[2];
- USBPacket packey[2];
+ MUSBPacket packey[2];
int status[2];
int ext_size[2];
@@ -294,7 +303,7 @@ typedef struct {
MUSBState *musb;
USBCallback *delayed_cb[2];
QEMUTimer *intv_timer[2];
-} MUSBEndPoint;
+};
struct MUSBState {
qemu_irq *irqs;
@@ -321,7 +330,9 @@ struct MUSBState {
/* Duplicating the world since 2008!... probably we should have 32
* logical, single endpoints instead. */
MUSBEndPoint ep[16];
-} *musb_init(qemu_irq *irqs)
+};
+
+struct MUSBState *musb_init(qemu_irq *irqs)
{
MUSBState *s = qemu_mallocz(sizeof(*s));
int i;
@@ -488,14 +499,14 @@ static inline void musb_cb_tick0(void *opaque)
{
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- ep->delayed_cb[0](&ep->packey[0], opaque);
+ ep->delayed_cb[0](&ep->packey[0].p, opaque);
}
static inline void musb_cb_tick1(void *opaque)
{
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- ep->delayed_cb[1](&ep->packey[1], opaque);
+ ep->delayed_cb[1](&ep->packey[1].p, opaque);
}
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
@@ -587,17 +598,19 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->delayed_cb[dir] = cb;
cb = dir ? musb_schedule1_cb : musb_schedule0_cb;
- ep->packey[dir].pid = pid;
+ ep->packey[dir].p.pid = pid;
/* A wild guess on the FADDR semantics... */
- ep->packey[dir].devaddr = ep->faddr[idx];
- ep->packey[dir].devep = ep->type[idx] & 0xf;
- ep->packey[dir].data = (void *) ep->buf[idx];
- ep->packey[dir].len = len;
- ep->packey[dir].complete_cb = cb;
- ep->packey[dir].complete_opaque = ep;
+ ep->packey[dir].p.devaddr = ep->faddr[idx];
+ ep->packey[dir].p.devep = ep->type[idx] & 0xf;
+ ep->packey[dir].p.data = (void *) ep->buf[idx];
+ ep->packey[dir].p.len = len;
+ ep->packey[dir].p.complete_cb = cb;
+ ep->packey[dir].p.complete_opaque = ep;
+ ep->packey[dir].ep = ep;
+ ep->packey[dir].dir = dir;
if (s->port.dev)
- ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir]);
+ ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir].p);
else
ret = USB_RET_NODEV;
@@ -607,7 +620,7 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
}
ep->status[dir] = ret;
- usb_packet_complete(&ep->packey[dir]);
+ usb_packet_complete(&ep->packey[dir].p);
}
static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
@@ -821,14 +834,14 @@ static void musb_rx_req(MUSBState *s, int epnum)
/* If we already have a packet, which didn't fit into the
* 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
- if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
+ if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
(ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].len) {
+ ep->packey[1].p.len) {
TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
ep->fifostart[1] += ep->rxcount;
ep->fifolen[1] = 0;
- ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1]),
+ ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
ep->maxp[1]);
ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
@@ -866,10 +879,11 @@ static void musb_rx_req(MUSBState *s, int epnum)
#ifdef SETUPLEN_HACK
/* Why should *we* do that instead of Linux? */
if (!epnum) {
- if (ep->packey[0].devaddr == 2)
+ if (ep->packey[0].p.devaddr == 2) {
total = MIN(s->setup_len, 8);
- else
+ } else {
total = MIN(s->setup_len, 64);
+ }
s->setup_len -= total;
}
#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 13/14] usb: move complete callback to port ops
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (11 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 12/14] musb: get musb " Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-04 15:41 ` [Qemu-devel] [PATCH 14/14] usb: mass storage fix Gerd Hoffmann
2011-05-05 18:28 ` [Qemu-devel] [PULL] usb patch queue Anthony Liguori
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-hub.c | 14 ++++++++++++++
hw/usb-msd.c | 4 ++--
hw/usb-musb.c | 27 +++++++++------------------
hw/usb-ohci.c | 7 ++-----
hw/usb-uhci.c | 7 +++----
hw/usb.h | 7 +++----
usb-linux.c | 2 +-
7 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 3dd31ba..e0588f8 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -256,6 +256,19 @@ static void usb_hub_wakeup(USBDevice *dev)
}
}
+static void usb_hub_complete(USBDevice *dev, USBPacket *packet)
+{
+ USBHubState *s = dev->port->opaque;
+
+ /*
+ * Just pass it along upstream for now.
+ *
+ * If we ever inplement usb 2.0 split transactions this will
+ * become a little more complicated ...
+ */
+ usb_packet_complete(&s->dev, packet);
+}
+
static void usb_hub_handle_attach(USBDevice *dev)
{
USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
@@ -524,6 +537,7 @@ static USBPortOps usb_hub_port_ops = {
.attach = usb_hub_attach,
.detach = usb_hub_detach,
.wakeup = usb_hub_wakeup,
+ .complete = usb_hub_complete,
};
static int usb_hub_initfn(USBDevice *dev)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 947fd3f..93f4b78 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -241,7 +241,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
s->mode = USB_MSDM_CSW;
}
s->packet = NULL;
- usb_packet_complete(p);
+ usb_packet_complete(&s->dev, p);
} else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
@@ -257,7 +257,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
usb_packet_complete returns. */
DPRINTF("Packet complete %p\n", p);
s->packet = NULL;
- usb_packet_complete(p);
+ usb_packet_complete(&s->dev, p);
}
}
}
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 30148e7..b30caeb 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -261,10 +261,12 @@
static void musb_attach(USBPort *port);
static void musb_detach(USBPort *port);
+static void musb_schedule_cb(USBDevice *dev, USBPacket *p);
static USBPortOps musb_port_ops = {
.attach = musb_attach,
.detach = musb_detach,
+ .complete = musb_schedule_cb,
};
typedef struct MUSBPacket MUSBPacket;
@@ -511,9 +513,11 @@ static inline void musb_cb_tick1(void *opaque)
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
-static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir)
+static inline void musb_schedule_cb(USBDevice *dev, USBPacket *packey)
{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
+ MUSBPacket *p = container_of(packey, MUSBPacket, p);
+ MUSBEndPoint *ep = p->ep;
+ int dir = p->dir;
int timeout = 0;
if (ep->status[dir] == USB_RET_NAK)
@@ -521,25 +525,15 @@ static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir)
else if (ep->interrupt[dir])
timeout = 8;
else
- return musb_cb_tick(opaque);
+ return musb_cb_tick(ep);
if (!ep->intv_timer[dir])
- ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, opaque);
+ ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, ep);
qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) +
muldiv64(timeout, get_ticks_per_sec(), 8000));
}
-static void musb_schedule0_cb(USBPacket *packey, void *opaque)
-{
- return musb_schedule_cb(packey, opaque, 0);
-}
-
-static void musb_schedule1_cb(USBPacket *packey, void *opaque)
-{
- return musb_schedule_cb(packey, opaque, 1);
-}
-
static int musb_timeout(int ttype, int speed, int val)
{
#if 1
@@ -596,7 +590,6 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->type[idx] >> 6, ep->interval[idx]);
ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
ep->delayed_cb[dir] = cb;
- cb = dir ? musb_schedule1_cb : musb_schedule0_cb;
ep->packey[dir].p.pid = pid;
/* A wild guess on the FADDR semantics... */
@@ -604,8 +597,6 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->packey[dir].p.devep = ep->type[idx] & 0xf;
ep->packey[dir].p.data = (void *) ep->buf[idx];
ep->packey[dir].p.len = len;
- ep->packey[dir].p.complete_cb = cb;
- ep->packey[dir].p.complete_opaque = ep;
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
@@ -620,7 +611,7 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
}
ep->status[dir] = ret;
- usb_packet_complete(&ep->packey[dir].p);
+ usb_packet_complete(s->port.dev, &ep->packey[dir].p);
}
static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 7678cdb..8090c17 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -575,7 +575,7 @@ static void ohci_copy_iso_td(OHCIState *ohci,
static void ohci_process_lists(OHCIState *ohci, int completion);
-static void ohci_async_complete_packet(USBPacket *packet, void *opaque)
+static void ohci_async_complete_packet(USBDevice *dev, USBPacket *packet)
{
OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
#ifdef DEBUG_PACKET
@@ -748,8 +748,6 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
ohci->usb_packet.data = ohci->usb_buf;
ohci->usb_packet.len = len;
- ohci->usb_packet.complete_cb = ohci_async_complete_packet;
- ohci->usb_packet.complete_opaque = ohci;
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@@ -946,8 +944,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
ohci->usb_packet.data = ohci->usb_buf;
ohci->usb_packet.len = len;
- ohci->usb_packet.complete_cb = ohci_async_complete_packet;
- ohci->usb_packet.complete_opaque = ohci;
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@@ -1665,6 +1661,7 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
static USBPortOps ohci_port_ops = {
.attach = ohci_attach,
.detach = ohci_detach,
+ .complete = ohci_async_complete_packet,
};
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 2b63b3f..a65e0b3 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -642,7 +642,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
return ret;
}
-static void uhci_async_complete(USBPacket * packet, void *opaque);
+static void uhci_async_complete(USBDevice *dev, USBPacket *packet);
static void uhci_process_frame(UHCIState *s);
/* return -1 if fatal error (frame must be stopped)
@@ -795,8 +795,6 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
async->packet.devep = (td->token >> 15) & 0xf;
async->packet.data = async->buffer;
async->packet.len = max_len;
- async->packet.complete_cb = uhci_async_complete;
- async->packet.complete_opaque = s;
switch(pid) {
case USB_TOKEN_OUT:
@@ -832,7 +830,7 @@ done:
return len;
}
-static void uhci_async_complete(USBPacket *packet, void *opaque)
+static void uhci_async_complete(USBDevice *dev, USBPacket *packet)
{
UHCIAsync *async = container_of(packet, UHCIAsync, packet);
UHCIState *s = async->uhci;
@@ -1083,6 +1081,7 @@ static USBPortOps uhci_port_ops = {
.attach = uhci_attach,
.detach = uhci_detach,
.wakeup = uhci_wakeup,
+ .complete = uhci_async_complete,
};
static int usb_uhci_common_initfn(UHCIState *s)
diff --git a/hw/usb.h b/hw/usb.h
index 22bb338..7e46141 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -235,6 +235,7 @@ typedef struct USBPortOps {
void (*attach)(USBPort *port);
void (*detach)(USBPort *port);
void (*wakeup)(USBDevice *dev);
+ void (*complete)(USBDevice *dev, USBPacket *p);
} USBPortOps;
/* USB port on which a device can be connected */
@@ -259,8 +260,6 @@ struct USBPacket {
uint8_t *data;
int len;
/* Internal use by the USB layer. */
- USBCallback *complete_cb;
- void *complete_opaque;
USBCallback *cancel_cb;
void *cancel_opaque;
};
@@ -278,9 +277,9 @@ static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel,
/* Notify the controller that an async packet is complete. This should only
be called for packets previously deferred with usb_defer_packet, and
should never be called from within handle_packet. */
-static inline void usb_packet_complete(USBPacket *p)
+static inline void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
- p->complete_cb(p, p->complete_opaque);
+ dev->port->ops->complete(dev, p);
}
/* Cancel an active packet. The packed must have been deferred with
diff --git a/usb-linux.c b/usb-linux.c
index 730eac2..36a01ea 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -348,7 +348,7 @@ static void async_complete(void *opaque)
break;
}
- usb_packet_complete(p);
+ usb_packet_complete(&s->dev, p);
}
async_free(aurb);
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [Qemu-devel] [PATCH 14/14] usb: mass storage fix
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (12 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 13/14] usb: move complete callback to port ops Gerd Hoffmann
@ 2011-05-04 15:41 ` Gerd Hoffmann
2011-05-05 18:28 ` [Qemu-devel] [PULL] usb patch queue Anthony Liguori
14 siblings, 0 replies; 38+ messages in thread
From: Gerd Hoffmann @ 2011-05-04 15:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Initialize scsi_len with zero when starting a new request, so any
stuff leftover from the previous request is cleared out. This may
happen in case the data returned by the scsi command doesn't fit
into the buffer provided by the guest.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-msd.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 93f4b78..bd1c3a4 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -364,6 +364,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0;
+ s->scsi_len = 0;
s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
/* ??? Should check that USB and SCSI data transfer
directions match. */
--
1.7.1
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [Qemu-devel] [PULL] usb patch queue
2011-05-04 15:41 [Qemu-devel] [PULL] usb patch queue Gerd Hoffmann
` (13 preceding siblings ...)
2011-05-04 15:41 ` [Qemu-devel] [PATCH 14/14] usb: mass storage fix Gerd Hoffmann
@ 2011-05-05 18:28 ` Anthony Liguori
14 siblings, 0 replies; 38+ messages in thread
From: Anthony Liguori @ 2011-05-05 18:28 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel
On 05/04/2011 10:41 AM, Gerd Hoffmann wrote:
> Hi,
>
> The USB patch queue is back! I'm still busy catching up with the
> backlog, I know I didn't pick up everything from the list yet. If in
> doubt it doesn't hurt to resend usb related patches, with me being
> Cc'ed.
>
> This pull brings old stuff, most of the patches are several months old
> already. Finally the usb-host fixes from Hans are queued up for merge.
> Some async packet handling cleanups are in there to. Oh, and one more
> bugfix for the usb mass storage device.
>
> please pull,
> Gerd
Pulled. Thanks.
Regards,
Anthony Liguori
>
> The following changes since commit d2d979c628e4b2c4a3cb71a31841875795c79043:
>
> NBD: Avoid leaking a couple of strings when the NBD device is closed (2011-05-03 11:29:21 +0200)
>
> are available in the git repository at:
> git://git.kraxel.org/qemu usb.7.pull
>
> Gerd Hoffmann (6):
> uhci: switch to QTAILQ
> uhci: keep uhci state pointer in async packet struct.
> ohci: get ohci state via container_of()
> musb: get musb state via container_of()
> usb: move complete callback to port ops
> usb: mass storage fix
>
> Hans de Goede (8):
> usb-linux: introduce a usb_linux_alt_setting function
> usb-linux: Get the alt. setting from sysfs rather then asking the dev
> usb-linux: Add support for buffering iso usb packets
> usb-linux: Refuse packets for endpoints which are not in the usb descriptor
> usb-linux: Refuse iso packets when max packet size is 0 (alt setting 0)
> usb-linux: We only need to keep track of 15 endpoints
> usb-linux: Add support for buffering iso out usb packets
> usb: control buffer fixes
>
> hw/usb-hub.c | 14 ++
> hw/usb-msd.c | 5 +-
> hw/usb-musb.c | 75 ++++++-----
> hw/usb-ohci.c | 9 +-
> hw/usb-uhci.c | 82 ++++--------
> hw/usb.c | 6 +
> hw/usb.h | 9 +-
> usb-linux.c | 394 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
> 8 files changed, 445 insertions(+), 149 deletions(-)
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread