From c19537a1143d493897850576394f082914f39ef1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 9 Aug 2012 10:57:32 +0200 Subject: usb: async control xfer fixup Need to clear p->result after copying setup data using usb_packet_copy() because we'll reuse the USBPacket for the data transfer. Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index d55be87..8df9207 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1045,6 +1045,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, /* Note request is (bRequestType << 8) | bRequest */ trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); + assert(p->result == 0); switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: -- cgit v1.1 From 63587e31353b6652cadfcfb869f5692a2b69daeb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 6 Sep 2012 12:03:41 +0200 Subject: usb-host: allow emulated (non-async) control requests without USBPacket xhci needs this for USB_REQ_SET_ADDRESS due to the way usb addressing is handled by the xhci hardware. Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 8df9207..44f1a64 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, /* Note request is (bRequestType << 8) | bRequest */ trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); - assert(p->result == 0); switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: @@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, } /* The rest are asynchronous */ + assert(p && p->result == 0); if (length > sizeof(dev->data_buf)) { fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", -- cgit v1.1 From 6ba43f1f6b60159e731b1f37ffb53ab9ab59efa9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Oct 2012 18:14:09 +0200 Subject: usb: Move short-not-ok handling to the core After a short-not-ok packet ending short, we should not advance the queue. Move enforcing this to the core, rather then handling it in the hcd code. This may result in the queue now actually containing multiple input packets (which would not happen before), and this requires special handling in combination with pipelining, so disable pipleining for input endpoints (for now). Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 44f1a64..3a258b4 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1224,7 +1224,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s) usb_ep_set_type(&s->dev, pid, ep, type); usb_ep_set_ifnum(&s->dev, pid, ep, interface); if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) && - (type == USB_ENDPOINT_XFER_BULK)) { + (type == USB_ENDPOINT_XFER_BULK) && + (pid == USB_TOKEN_OUT)) { usb_ep_set_pipeline(&s->dev, pid, ep, true); } -- cgit v1.1 From 9a77a0f58923443913e1071ffb47b74c54566e70 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Nov 2012 17:15:01 +0100 Subject: usb: split packet result into actual_length + status Since with the ehci and xhci controllers a single packet can be larger then maxpacketsize, it is possible for the result of a single packet to be both having transferred some data as well as the transfer to have an error. An example would be an input transfer from a bulk endpoint successfully receiving 1 or more maxpacketsize packets from the device, followed by a packet signalling halt. While already touching all the devices and controllers handle_packet / handle_data / handle_control code, also change the return type of these functions to void, solely storing the status in the packet. To make the code paths for regular versus async packet handling more uniform. This patch unfortunately is somewhat invasive, since makeing the qemu usb core deal with this requires changes everywhere. This patch only prepares the usb core for this, all the hcd / device changes are done in such a way that there are no functional changes. This patch has been tested with uhci and ehci hcds, together with usb-audio, usb-hid and usb-storage devices, as well as with usb-redir redirection with a wide variety of real devices. Note that there is usually no need to directly set packet->actual_length form devices handle_data callback, as that is done by usb_packet_copy() Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 128 ++++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 59 deletions(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 3a258b4..ca3e24a 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -366,28 +366,29 @@ static void async_complete(void *opaque) if (p) { switch (aurb->urb.status) { case 0: - p->result += aurb->urb.actual_length; + p->actual_length = aurb->urb.actual_length; + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ break; case -EPIPE: set_halt(s, p->pid, p->ep->nr); - p->result = USB_RET_STALL; + p->status = USB_RET_STALL; break; case -EOVERFLOW: - p->result = USB_RET_BABBLE; + p->status = USB_RET_BABBLE; break; default: - p->result = USB_RET_IOERROR; + p->status = USB_RET_IOERROR; break; } if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); + trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); usb_generic_async_ctrl_complete(&s->dev, p); } else if (!aurb->more) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); + trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); usb_packet_complete(&s->dev, p); } } @@ -733,27 +734,31 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep) clear_iso_started(s, pid, ep); } -static int urb_status_to_usb_ret(int status) +static void urb_status_to_usb_ret(int status, USBPacket *p) { switch (status) { case -EPIPE: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; case -EOVERFLOW: - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + break; default: - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; } } -static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) +static void usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) { AsyncURB *aurb; - int i, j, ret, max_packet_size, offset, len = 0; + int i, j, max_packet_size, offset, len; uint8_t *buf; max_packet_size = p->ep->max_packet_size; - if (max_packet_size == 0) - return USB_RET_NAK; + if (max_packet_size == 0) { + p->status = USB_RET_NAK; + return; + } aurb = get_iso_urb(s, p->pid, p->ep->nr); if (!aurb) { @@ -766,18 +771,17 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) if (in) { /* Check urb status */ if (aurb[i].urb.status) { - len = urb_status_to_usb_ret(aurb[i].urb.status); + urb_status_to_usb_ret(aurb[i].urb.status, p); /* 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); + urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status, p); /* Check the frame fits */ } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->iov.size) { printf("husb: received iso data is larger then packet\n"); - len = USB_RET_BABBLE; + p->status = USB_RET_BABBLE; /* All good copy data over */ } else { len = aurb[i].urb.iso_frame_desc[j].actual_length; @@ -792,7 +796,8 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) /* 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; + p->status = USB_RET_NAK; + return; } /* All good copy data over */ @@ -823,17 +828,16 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) /* (Re)-submit all fully consumed / filled urbs */ for (i = 0; i < s->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) { + if (ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]) < 0) { perror("USBDEVFS_SUBMITURB"); - if (!in || len == 0) { + if (!in || p->status == USB_RET_SUCCESS) { switch(errno) { case ETIMEDOUT: - len = USB_RET_NAK; + p->status = USB_RET_NAK; break; case EPIPE: default: - len = USB_RET_STALL; + p->status = USB_RET_STALL; } } break; @@ -843,11 +847,9 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) } } } - - return len; } -static int usb_host_handle_data(USBDevice *dev, USBPacket *p) +static void usb_host_handle_data(USBDevice *dev, USBPacket *p) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); struct usbdevfs_urb *urb; @@ -862,7 +864,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) if (!is_valid(s, p->pid, p->ep->nr)) { trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + return; } if (p->pid == USB_TOKEN_IN) { @@ -877,13 +880,15 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) if (ret < 0) { perror("USBDEVFS_CLEAR_HALT"); trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + return; } clear_halt(s, p->pid, p->ep->nr); } if (is_isoc(s, p->pid, p->ep->nr)) { - return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); + usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); + return; } v = 0; @@ -933,17 +938,19 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) case ETIMEDOUT: trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; case EPIPE: default: trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_STALL); - return USB_RET_STALL; + p->status = USB_RET_STALL; } + return; } } while (rem > 0); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } static int ctrl_error(void) @@ -955,14 +962,13 @@ static int ctrl_error(void) } } -static int usb_host_set_address(USBHostDevice *s, int addr) +static void usb_host_set_address(USBHostDevice *s, int addr) { trace_usb_host_set_address(s->bus_num, s->addr, addr); s->dev.addr = addr; - return 0; } -static int usb_host_set_config(USBHostDevice *s, int config) +static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p) { int ret, first = 1; @@ -987,14 +993,15 @@ again: } if (ret < 0) { - return ctrl_error(); + p->status = ctrl_error(); + return; } usb_host_claim_interfaces(s, config); usb_linux_update_endp_table(s); - return 0; } -static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) +static void usb_host_set_interface(USBHostDevice *s, int iface, int alt, + USBPacket *p) { struct usbdevfs_setinterface si; int i, ret; @@ -1011,7 +1018,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) } if (iface >= USB_MAX_INTERFACES) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } si.interface = iface; @@ -1022,15 +1030,15 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) iface, alt, ret, errno); if (ret < 0) { - return ctrl_error(); + p->status = ctrl_error(); + return; } s->dev.altsetting[iface] = alt; usb_linux_update_endp_table(s); - return 0; } -static int usb_host_handle_control(USBDevice *dev, USBPacket *p, +static void 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); @@ -1048,19 +1056,19 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: - ret = usb_host_set_address(s, value); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_address(s, value); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = usb_host_set_config(s, value & 0xff); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_config(s, value & 0xff, p); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - ret = usb_host_set_interface(s, index, value); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_interface(s, index, value, p); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: if (value == 0) { /* clear halt */ @@ -1068,17 +1076,16 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index); clear_halt(s, pid, index & 0x0f); trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0); - return 0; + return; } } /* The rest are asynchronous */ - assert(p && p->result == 0); - 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; + p->status = USB_RET_STALL; + return; } aurb = async_alloc(s); @@ -1112,14 +1119,17 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, switch(errno) { case ETIMEDOUT: - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; case EPIPE: default: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; } + return; } - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } /* returns 1 on problem encountered or 0 for success */ -- cgit v1.1 From c06c68c928edd36eb56baa0d2db065bbec28af27 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 14 Nov 2012 15:51:18 +0100 Subject: usb-host: scan for usb devices when the vm starts Commit a844ed842d9a9d929645c09ae0f52f753d7a02e0 leads to usb-host detecting devices not right after qemu startup because the guest isn't running yet. Instead they are found on the first of the regular usb device poll runs. Which is too late for seabios to see them, so booting from usb sticks fails. Fix this by adding a vm state change handler which triggers a device scan when the vm is started. Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index ca3e24a..5bc77b2 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1738,6 +1738,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) } static QEMUTimer *usb_auto_timer; +static VMChangeStateEntry *usb_vmstate; static int usb_host_auto_scan(void *opaque, int bus_num, int addr, const char *port, @@ -1792,6 +1793,13 @@ static int usb_host_auto_scan(void *opaque, int bus_num, return 0; } +static void usb_host_vm_state(void *unused, int running, RunState state) +{ + if (running) { + usb_host_auto_check(unused); + } +} + static void usb_host_auto_check(void *unused) { struct USBHostDevice *s; @@ -1820,6 +1828,9 @@ static void usb_host_auto_check(void *unused) } } + if (!usb_vmstate) { + usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL); + } if (!usb_auto_timer) { usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL); if (!usb_auto_timer) { -- cgit v1.1 From 537e8f1aa838677c8efd5e0966e89c4b5423dd18 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 15 Nov 2012 09:23:30 +0100 Subject: usb: host-linux: Ignore parsing errors of the device descriptors The Linux is more tolerant here as well: Just stop parsing the device descriptors when an error is detected but do not reset what was found so far. This allows to run buggy devices with partially invalid descriptors. Signed-off-by: Jan Kiszka Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 5bc77b2..b17e1dc 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -135,7 +135,7 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f); static void usb_host_auto_check(void *unused); static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name); -static int usb_linux_update_endp_table(USBHostDevice *s); +static void usb_linux_update_endp_table(USBHostDevice *s); static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p) { @@ -1132,8 +1132,7 @@ static void usb_host_handle_control(USBDevice *dev, USBPacket *p, p->status = USB_RET_ASYNC; } -/* returns 1 on problem encountered or 0 for success */ -static int usb_linux_update_endp_table(USBHostDevice *s) +static void usb_linux_update_endp_table(USBHostDevice *s) { static const char *tname[] = { [USB_ENDPOINT_XFER_CONTROL] = "control", @@ -1159,23 +1158,23 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 2) { trace_usb_host_parse_error(s->bus_num, s->addr, "descriptor too short"); - goto error; + return; } if (i + d->bLength > s->descr_len) { trace_usb_host_parse_error(s->bus_num, s->addr, "descriptor too long"); - goto error; + return; } switch (d->bDescriptorType) { case 0: trace_usb_host_parse_error(s->bus_num, s->addr, "invalid descriptor type"); - goto error; + return; case USB_DT_DEVICE: if (d->bLength < 0x12) { trace_usb_host_parse_error(s->bus_num, s->addr, "device descriptor too short"); - goto error; + return; } v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo; p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo; @@ -1185,7 +1184,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x09) { trace_usb_host_parse_error(s->bus_num, s->addr, "config descriptor too short"); - goto error; + return; } configuration = d->u.config.bConfigurationValue; active = (configuration == s->dev.configuration); @@ -1196,7 +1195,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x09) { trace_usb_host_parse_error(s->bus_num, s->addr, "interface descriptor too short"); - goto error; + return; } interface = d->u.interface.bInterfaceNumber; altsetting = d->u.interface.bAlternateSetting; @@ -1209,7 +1208,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x07) { trace_usb_host_parse_error(s->bus_num, s->addr, "endpoint descriptor too short"); - goto error; + return; } devep = d->u.endpoint.bEndpointAddress; pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; @@ -1217,7 +1216,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (ep == 0) { trace_usb_host_parse_error(s->bus_num, s->addr, "invalid endpoint address"); - goto error; + return; } type = d->u.endpoint.bmAttributes & 0x3; @@ -1250,11 +1249,6 @@ static int usb_linux_update_endp_table(USBHostDevice *s) break; } } - return 0; - -error: - usb_ep_reset(&s->dev); - return 1; } /* @@ -1341,10 +1335,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, } usb_ep_init(&dev->dev); - ret = usb_linux_update_endp_table(dev); - if (ret) { - goto fail; - } + usb_linux_update_endp_table(dev); if (speed == -1) { struct usbdevfs_connectinfo ci; -- cgit v1.1 From 8c908fca584dbf47094b63f132bb49b82eaa3e19 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 15 Nov 2012 16:11:20 +0100 Subject: usb-host: update tracing Now that we have separate status and length fields in USBPacket update the completion tracepoint to log both. Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index b17e1dc..e3d394f 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -385,10 +385,12 @@ static void async_complete(void *opaque) } if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, aurb->urb.actual_length); usb_generic_async_ctrl_complete(&s->dev, p); } else if (!aurb->more) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, aurb->urb.actual_length); usb_packet_complete(&s->dev, p); } } @@ -863,8 +865,9 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p) p->ep->nr, p->iov.size); if (!is_valid(s, p->pid, p->ep->nr)) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); return; } @@ -879,8 +882,9 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p) ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg); if (ret < 0) { perror("USBDEVFS_CLEAR_HALT"); - trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); return; } clear_halt(s, p->pid, p->ep->nr); @@ -936,15 +940,15 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p) switch(errno) { case ETIMEDOUT: - trace_usb_host_req_complete(s->bus_num, s->addr, p, - USB_RET_NAK); p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); break; case EPIPE: default: - trace_usb_host_req_complete(s->bus_num, s->addr, p, - USB_RET_STALL); p->status = USB_RET_STALL; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); } return; } -- cgit v1.1 From 71e0aa3930e7ac2e039b175ffad222e3dc5b1813 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 15 Nov 2012 16:11:49 +0100 Subject: usb-host: fix splitted transfers USBPacket->actual_length wasn't updated correctly for USBPackets splitted into multiple urbs. Fix it. Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index e3d394f..aa77b77 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -366,8 +366,11 @@ static void async_complete(void *opaque) if (p) { switch (aurb->urb.status) { case 0: - p->actual_length = aurb->urb.actual_length; - p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + p->actual_length += aurb->urb.actual_length; + if (!aurb->more) { + /* Clear previous ASYNC status */ + p->status = USB_RET_SUCCESS; + } break; case -EPIPE: -- cgit v1.1 From be41efde3ca0372dbf7543e09ff473b4eec25057 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 17 Nov 2012 12:47:15 +0100 Subject: usb: Don't allow USB_RET_ASYNC for interrupt packets It is tempting to use USB_RET_ASYNC for interrupt packets, rather then the current NAK + polling approach, but this causes issues for migration, as an async completed packet will not getting written back to guest memory until the next poll time, and if a migration happens in between it will get lost! Make an exception for host devices, because: 1) host-linux actually uses async completion for interrupt endpoints 2) host devices don't migrate anyways Ideally we would convert host-linux.c to handle (input) interrupt endpoints in a buffered manner like it does for isoc endpoints, keeping multiple urbs submitted to ensure the devices timing requirements are met, as well as making its interrupt ep handling the same as other usb-devices. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index aa77b77..bdafb6b 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1476,6 +1476,7 @@ static int usb_host_initfn(USBDevice *dev) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); + dev->flags |= (1 << USB_DEV_FLAG_IS_HOST); dev->auto_attach = 0; s->fd = -1; s->hub_fd = -1; -- cgit v1.1 From 83c9089e73b81c69dc1ecdf859fa84d2c500fb5f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Dec 2012 18:19:49 +0100 Subject: monitor: move include files to include/monitor/ Signed-off-by: Paolo Bonzini --- hw/usb/host-linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index bdafb6b..5a56e99 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -32,7 +32,7 @@ #include "qemu-common.h" #include "qemu-timer.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "sysemu.h" #include "trace.h" -- cgit v1.1 From 1de7afc984b49af164e2619e6850b9732b173b34 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Dec 2012 18:20:00 +0100 Subject: misc: move include files to include/qemu/ Signed-off-by: Paolo Bonzini --- hw/usb/host-linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 5a56e99..9a8c26ce 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -31,7 +31,7 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "monitor/monitor.h" #include "sysemu.h" #include "trace.h" -- cgit v1.1 From 9c17d615a66ebd655871bf891ec0fe901ad8b332 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Dec 2012 18:20:04 +0100 Subject: softmmu: move include files to include/sysemu/ Signed-off-by: Paolo Bonzini --- hw/usb/host-linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/usb/host-linux.c') diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 9a8c26ce..669fbd2 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -33,7 +33,7 @@ #include "qemu-common.h" #include "qemu/timer.h" #include "monitor/monitor.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "trace.h" #include -- cgit v1.1