From patchwork Wed Feb 2 18:18:40 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 81505 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 7B524B70E9 for ; Thu, 3 Feb 2011 05:10:35 +1100 (EST) Received: from localhost ([127.0.0.1]:35461 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PkhA0-0003zM-3M for incoming@patchwork.ozlabs.org; Wed, 02 Feb 2011 13:10:32 -0500 Received: from [140.186.70.92] (port=39881 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Pkh87-0003v7-Um for qemu-devel@nongnu.org; Wed, 02 Feb 2011 13:08:37 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Pkh83-0006oU-Hb for qemu-devel@nongnu.org; Wed, 02 Feb 2011 13:08:35 -0500 Received: from mx1.redhat.com ([209.132.183.28]:12882) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Pkh83-0006nL-4N for qemu-devel@nongnu.org; Wed, 02 Feb 2011 13:08:31 -0500 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p12I8Thh027494 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 2 Feb 2011 13:08:29 -0500 Received: from shalem.localdomain (vpn1-4-142.ams2.redhat.com [10.36.4.142]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p12I8PPI017829; Wed, 2 Feb 2011 13:08:28 -0500 From: Hans de Goede To: qemu-devel@nongnu.org Date: Wed, 2 Feb 2011 19:18:40 +0100 Message-Id: <1296670721-2709-2-git-send-email-hdegoede@redhat.com> In-Reply-To: <1296670721-2709-1-git-send-email-hdegoede@redhat.com> References: <1296670721-2709-1-git-send-email-hdegoede@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: spice-devel@lists.freedesktop.org, Gerd Hoffmann , Hans de Goede Subject: [Qemu-devel] [PATCH 2/3] usb-linux: use usb_generic_handle_packet() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 895ad07..560b3e4 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; @@ -235,6 +240,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(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 c06000a..412ce02 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -293,6 +293,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 3ef8198..950e439 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 contigious 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(p); + if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { + usb_generic_async_ctrl_complete(&s->dev, p); + } else { + usb_packet_complete(p); + } } async_free(aurb); @@ -673,8 +625,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; @@ -794,45 +747,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; } @@ -851,8 +798,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; @@ -877,170 +824,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; @@ -1366,7 +1149,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",