qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Hans de Goede <hdegoede@redhat.com>
Subject: [Qemu-devel] [PATCH 07/18] usb-linux: use usb_generic_handle_packet()
Date: Mon, 23 May 2011 11:43:28 +0200	[thread overview]
Message-ID: <1306143819-30287-8-git-send-email-kraxel@redhat.com> (raw)
In-Reply-To: <1306143819-30287-1-git-send-email-kraxel@redhat.com>

From: Hans de Goede <hdegoede@redhat.com>

Make the linux usb host passthrough code use the usb_generic_handle_packet()
function, rather then the curent DYI code. This removes 200 lines of almost
identical code.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 hw/usb.c    |   41 +++++++++-
 hw/usb.h    |    1 +
 usb-linux.c |  269 ++++++-----------------------------------------------------
 3 files changed, 66 insertions(+), 245 deletions(-)

diff --git a/hw/usb.c b/hw/usb.c
index f503b7a..60027c6 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -63,9 +63,10 @@ void usb_wakeup(USBDevice *dev)
    protocol)
 */
 
-#define SETUP_STATE_IDLE 0
-#define SETUP_STATE_DATA 1
-#define SETUP_STATE_ACK  2
+#define SETUP_STATE_IDLE  0
+#define SETUP_STATE_SETUP 1
+#define SETUP_STATE_DATA  2
+#define SETUP_STATE_ACK   3
 
 static int do_token_setup(USBDevice *s, USBPacket *p)
 {
@@ -86,6 +87,10 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
     if (s->setup_buf[0] & USB_DIR_IN) {
         ret = s->info->handle_control(s, p, request, value, index,
                                       s->setup_len, s->data_buf);
+        if (ret == USB_RET_ASYNC) {
+             s->setup_state = SETUP_STATE_SETUP;
+             return USB_RET_ASYNC;
+        }
         if (ret < 0)
             return ret;
 
@@ -241,6 +246,36 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
     }
 }
 
+/* ctrl complete function for devices which use usb_generic_handle_packet and
+   may return USB_RET_ASYNC from their handle_control callback. Device code
+   which does this *must* call this function instead of the normal
+   usb_packet_complete to complete their async control packets. */
+void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
+{
+    if (p->len < 0) {
+        s->setup_state = SETUP_STATE_IDLE;
+    }
+
+    switch (s->setup_state) {
+    case SETUP_STATE_SETUP:
+        if (p->len < s->setup_len) {
+            s->setup_len = p->len;
+        }
+        s->setup_state = SETUP_STATE_DATA;
+        p->len = 8;
+        break;
+
+    case SETUP_STATE_ACK:
+        s->setup_state = SETUP_STATE_IDLE;
+        p->len = 0;
+        break;
+
+    default:
+        break;
+    }
+    usb_packet_complete(s, p);
+}
+
 /* XXX: fix overflow */
 int set_usb_string(uint8_t *buf, const char *str)
 {
diff --git a/hw/usb.h b/hw/usb.h
index b52fa34..c1d1014 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -294,6 +294,7 @@ static inline void usb_cancel_packet(USBPacket * p)
 void usb_attach(USBPort *port, USBDevice *dev);
 void usb_wakeup(USBDevice *dev);
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
+void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
 void usb_send_msg(USBDevice *dev, int msg);
 
diff --git a/usb-linux.c b/usb-linux.c
index 0ef1d26..84d3a8b 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -54,14 +54,6 @@ struct usb_ctrltransfer {
     void *data;
 };
 
-struct usb_ctrlrequest {
-    uint8_t bRequestType;
-    uint8_t bRequest;
-    uint16_t wValue;
-    uint16_t wIndex;
-    uint16_t wLength;
-};
-
 typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
                         int class_id, int vendor_id, int product_id,
                         const char *product_name, int speed);
@@ -108,26 +100,6 @@ struct endp_data {
     int max_packet_size;
 };
 
-enum {
-    CTRL_STATE_IDLE = 0,
-    CTRL_STATE_SETUP,
-    CTRL_STATE_DATA,
-    CTRL_STATE_ACK
-};
-
-/*
- * Control transfer state.
- * Note that 'buffer' _must_ follow 'req' field because
- * we need contiguous buffer when we submit control URB.
- */
-struct ctrl_struct {
-    uint16_t len;
-    uint16_t offset;
-    uint8_t  state;
-    struct   usb_ctrlrequest req;
-    uint8_t  buffer[8192];
-};
-
 struct USBAutoFilter {
     uint32_t bus_num;
     uint32_t addr;
@@ -146,7 +118,6 @@ typedef struct USBHostDevice {
     int       closing;
     Notifier  exit;
 
-    struct ctrl_struct ctrl;
     struct endp_data endp_table[MAX_ENDPOINTS];
 
     /* Host side address */
@@ -269,26 +240,6 @@ static void async_free(AsyncURB *aurb)
     qemu_free(aurb);
 }
 
-static void async_complete_ctrl(USBHostDevice *s, USBPacket *p)
-{
-    switch(s->ctrl.state) {
-    case CTRL_STATE_SETUP:
-        if (p->len < s->ctrl.len)
-            s->ctrl.len = p->len;
-        s->ctrl.state = CTRL_STATE_DATA;
-        p->len = 8;
-        break;
-
-    case CTRL_STATE_ACK:
-        s->ctrl.state = CTRL_STATE_IDLE;
-        p->len = 0;
-        break;
-
-    default:
-        break;
-    }
-}
-
 static void async_complete(void *opaque)
 {
     USBHostDevice *s = opaque;
@@ -333,9 +284,6 @@ static void async_complete(void *opaque)
             switch (aurb->urb.status) {
             case 0:
                 p->len = aurb->urb.actual_length;
-                if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
-                    async_complete_ctrl(s, p);
-                }
                 break;
 
             case -EPIPE:
@@ -348,7 +296,11 @@ static void async_complete(void *opaque)
                 break;
             }
 
-            usb_packet_complete(&s->dev, p);
+            if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
+                usb_generic_async_ctrl_complete(&s->dev, p);
+            } else {
+                usb_packet_complete(&s->dev, p);
+            }
         }
 
         async_free(aurb);
@@ -675,8 +627,9 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
     return len;
 }
 
-static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
+static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
 {
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     struct usbdevfs_urb *urb;
     AsyncURB *aurb;
     int ret;
@@ -796,45 +749,39 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
     return 0;
 }
 
-static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
+static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     struct usbdevfs_urb *urb;
     AsyncURB *aurb;
-    int ret, value, index;
-    int buffer_len;
+    int ret;
 
     /*
      * Process certain standard device requests.
      * These are infrequent and are processed synchronously.
      */
-    value = le16_to_cpu(s->ctrl.req.wValue);
-    index = le16_to_cpu(s->ctrl.req.wIndex);
 
+    /* Note request is (bRequestType << 8) | bRequest */
     DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
-            s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index,
-            s->ctrl.len);
+            request >> 8, request & 0xff, value, index, length);
 
-    if (s->ctrl.req.bRequestType == 0) {
-        switch (s->ctrl.req.bRequest) {
-        case USB_REQ_SET_ADDRESS:
-            return usb_host_set_address(s, value);
+    switch (request) {
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        return usb_host_set_address(s, value);
 
-        case USB_REQ_SET_CONFIGURATION:
-            return usb_host_set_config(s, value & 0xff);
-        }
-    }
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        return usb_host_set_config(s, value & 0xff);
 
-    if (s->ctrl.req.bRequestType == 1 &&
-                  s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) {
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
         return usb_host_set_interface(s, index, value);
     }
 
     /* The rest are asynchronous */
 
-    buffer_len = 8 + s->ctrl.len;
-    if (buffer_len > sizeof(s->ctrl.buffer)) {
-        fprintf(stderr, "husb: ctrl buffer too small (%u > %zu)\n",
-                buffer_len, sizeof(s->ctrl.buffer));
+    if (length > sizeof(dev->data_buf)) {
+        fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
+                length, sizeof(dev->data_buf));
         return USB_RET_STALL;
     }
 
@@ -853,8 +800,8 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
     urb->type     = USBDEVFS_URB_TYPE_CONTROL;
     urb->endpoint = p->devep;
 
-    urb->buffer        = &s->ctrl.req;
-    urb->buffer_length = buffer_len;
+    urb->buffer        = &dev->setup_buf;
+    urb->buffer_length = length + 8;
 
     urb->usercontext = s;
 
@@ -879,170 +826,6 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
     return USB_RET_ASYNC;
 }
 
-static int do_token_setup(USBDevice *dev, USBPacket *p)
-{
-    USBHostDevice *s = (USBHostDevice *) dev;
-    int ret = 0;
-
-    if (p->len != 8) {
-        return USB_RET_STALL;
-    }
-
-    memcpy(&s->ctrl.req, p->data, 8);
-    s->ctrl.len    = le16_to_cpu(s->ctrl.req.wLength);
-    s->ctrl.offset = 0;
-    s->ctrl.state  = CTRL_STATE_SETUP;
-
-    if (s->ctrl.req.bRequestType & USB_DIR_IN) {
-        ret = usb_host_handle_control(s, p);
-        if (ret < 0) {
-            return ret;
-        }
-
-        if (ret < s->ctrl.len) {
-            s->ctrl.len = ret;
-        }
-        s->ctrl.state = CTRL_STATE_DATA;
-    } else {
-        if (s->ctrl.len == 0) {
-            s->ctrl.state = CTRL_STATE_ACK;
-        } else {
-            s->ctrl.state = CTRL_STATE_DATA;
-        }
-    }
-
-    return ret;
-}
-
-static int do_token_in(USBDevice *dev, USBPacket *p)
-{
-    USBHostDevice *s = (USBHostDevice *) dev;
-    int ret = 0;
-
-    if (p->devep != 0) {
-        return usb_host_handle_data(s, p);
-    }
-
-    switch(s->ctrl.state) {
-    case CTRL_STATE_ACK:
-        if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
-            ret = usb_host_handle_control(s, p);
-            if (ret == USB_RET_ASYNC) {
-                return USB_RET_ASYNC;
-            }
-            s->ctrl.state = CTRL_STATE_IDLE;
-            return ret > 0 ? 0 : ret;
-        }
-
-        return 0;
-
-    case CTRL_STATE_DATA:
-        if (s->ctrl.req.bRequestType & USB_DIR_IN) {
-            int len = s->ctrl.len - s->ctrl.offset;
-            if (len > p->len) {
-                len = p->len;
-            }
-            memcpy(p->data, s->ctrl.buffer + s->ctrl.offset, len);
-            s->ctrl.offset += len;
-            if (s->ctrl.offset >= s->ctrl.len) {
-                s->ctrl.state = CTRL_STATE_ACK;
-            }
-            return len;
-        }
-
-        s->ctrl.state = CTRL_STATE_IDLE;
-        return USB_RET_STALL;
-
-    default:
-        return USB_RET_STALL;
-    }
-}
-
-static int do_token_out(USBDevice *dev, USBPacket *p)
-{
-    USBHostDevice *s = (USBHostDevice *) dev;
-
-    if (p->devep != 0) {
-        return usb_host_handle_data(s, p);
-    }
-
-    switch(s->ctrl.state) {
-    case CTRL_STATE_ACK:
-        if (s->ctrl.req.bRequestType & USB_DIR_IN) {
-            s->ctrl.state = CTRL_STATE_IDLE;
-            /* transfer OK */
-        } else {
-            /* ignore additional output */
-        }
-        return 0;
-
-    case CTRL_STATE_DATA:
-        if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
-            int len = s->ctrl.len - s->ctrl.offset;
-            if (len > p->len) {
-                len = p->len;
-            }
-            memcpy(s->ctrl.buffer + s->ctrl.offset, p->data, len);
-            s->ctrl.offset += len;
-            if (s->ctrl.offset >= s->ctrl.len) {
-                s->ctrl.state = CTRL_STATE_ACK;
-            }
-            return len;
-        }
-
-        s->ctrl.state = CTRL_STATE_IDLE;
-        return USB_RET_STALL;
-
-    default:
-        return USB_RET_STALL;
-    }
-}
-
-/*
- * Packet handler.
- * Called by the HC (host controller).
- *
- * Returns length of the transaction or one of the USB_RET_XXX codes.
- */
-static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
-{
-    switch(p->pid) {
-    case USB_MSG_ATTACH:
-        s->state = USB_STATE_ATTACHED;
-        return 0;
-
-    case USB_MSG_DETACH:
-        s->state = USB_STATE_NOTATTACHED;
-        return 0;
-
-    case USB_MSG_RESET:
-        s->remote_wakeup = 0;
-        s->addr = 0;
-        s->state = USB_STATE_DEFAULT;
-        s->info->handle_reset(s);
-        return 0;
-    }
-
-    /* Rest of the PIDs must match our address */
-    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) {
-        return USB_RET_NODEV;
-    }
-
-    switch (p->pid) {
-    case USB_TOKEN_SETUP:
-        return do_token_setup(s, p);
-
-    case USB_TOKEN_IN:
-        return do_token_in(s, p);
-
-    case USB_TOKEN_OUT:
-        return do_token_out(s, p);
-
-    default:
-        return USB_RET_STALL;
-    }
-}
-
 static int usb_linux_get_configuration(USBHostDevice *s)
 {
     uint8_t configuration;
@@ -1368,7 +1151,9 @@ static struct USBDeviceInfo usb_host_dev_info = {
     .qdev.name      = "usb-host",
     .qdev.size      = sizeof(USBHostDevice),
     .init           = usb_host_initfn,
-    .handle_packet  = usb_host_handle_packet,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_data    = usb_host_handle_data,
+    .handle_control = usb_host_handle_control,
     .handle_reset   = usb_host_handle_reset,
     .handle_destroy = usb_host_handle_destroy,
     .usbdevice_name = "host",
-- 
1.7.1

  parent reply	other threads:[~2011-05-23  9:44 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-23  9:43 [Qemu-devel] [PULL] usb patch queue: initial usb 2.0 support Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 01/18] usb: Add Interface Association Descriptor descriptor type Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 02/18] usb: update config descriptors to identify number of interfaces Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 03/18] usb: remove fallback to bNumInterfaces if no .nif Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 04/18] usb: add support for "grouped" interfaces and the Interface Association Descriptor Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 05/18] Bug #757654: UHCI fails to signal stall response patch Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 06/18] usb: Pass the packet to the device's handle_control callback Gerd Hoffmann
2011-05-23  9:43 ` Gerd Hoffmann [this message]
2011-05-23  9:43 ` [Qemu-devel] [PATCH 08/18] usb-linux: fix device path aka physical port handling Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 09/18] usb-linux: add hostport property Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 10/18] usb-linux: track aurbs in list Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 11/18] usb-linux: walk async urb list in cancel Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 12/18] usb-linux: split large xfers Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 13/18] usb-linux: fix max_packet_size for highspeed Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 14/18] usb-storage: don't call usb_packet_complete twice Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 15/18] usb: add usb_handle_packet Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 16/18] usb: keep track of packet owner Gerd Hoffmann
2011-05-23  9:43 ` [Qemu-devel] [PATCH 17/18] usb: move cancel callback to USBDeviceInfo Gerd Hoffmann
2011-05-23 14:04   ` Hans de Goede
2011-05-23 14:34     ` Gerd Hoffmann
2011-05-23 14:53       ` Gerd Hoffmann
2011-05-23 17:31         ` Hans de Goede
2011-05-23 17:30       ` Hans de Goede
2011-05-23  9:43 ` [Qemu-devel] [PATCH 18/18] usb: add ehci adapter Gerd Hoffmann
2011-05-23 19:25   ` Blue Swirl
2011-05-24 15:45   ` Erik Rull
2011-05-26 10:13 ` [Qemu-devel] [PULL] usb patch queue: initial usb 2.0 support Gerd Hoffmann
2011-05-31 13:37   ` Anthony Liguori
  -- strict thread matches above, loose matches on Subject: below --
2011-05-16 19:56 [Qemu-devel] [PATCH 00/18] usb patch queue: add usb 2.0 Gerd Hoffmann
2011-05-16 19:56 ` [Qemu-devel] [PATCH 07/18] usb-linux: use usb_generic_handle_packet() Gerd Hoffmann

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=1306143819-30287-8-git-send-email-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=hdegoede@redhat.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).