summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2014-03-20 18:05:23 +0100
committerPeter Wu <peter@lekensteyn.nl>2014-03-20 18:05:23 +0100
commit01b3362c1465ffcaa770cfcd64f0f609ee75d1aa (patch)
treebe3e8976b176c7e9de6f994a3dd607695f304bfc /hw
parent37f78fd8e2c17ac63ba5fcbd9b3d0e616e921606 (diff)
downloadqemu-01b3362c1465ffcaa770cfcd64f0f609ee75d1aa.tar.gz
usbdump: support xhci
The XHCI HCD sends an OUT packet which was unexpected by the usbdump code. That was the case because the core USB code that was normally calling handle_control only called when the full data was received from the host (from the Status stage, with PID == USB_TOKEN_IN). Then there is also the do_parameter function as used by XHCI that was not really handled. Fix this by allowing OUT tokens, also document why this is necessary. Signed-off-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'hw')
-rw-r--r--hw/usb/dump.c27
-rw-r--r--hw/usb/dump.h6
2 files changed, 23 insertions, 10 deletions
diff --git a/hw/usb/dump.c b/hw/usb/dump.c
index b0209c1f02..3f2fef1b1e 100644
--- a/hw/usb/dump.c
+++ b/hw/usb/dump.c
@@ -298,11 +298,17 @@ void usb_dump_submit(UsbDumpState *s, const USBPacket *p)
}
if (ep_type == USB_ENDPOINT_XFER_CONTROL) {
- /* PID is IN because this is the status stage for OUT, it cannot get
- * called for OUT (that would be the data packet themselves) */
- assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_SETUP);
-
- if (pid == USB_TOKEN_IN) {
+ /**
+ * Two moments where an out transfer happens.
+ * (1) Via the normal do_token_setup()/do_token_out()/do_token_in()
+ * sequence. As handle_control() is only called in do_token_in()
+ * (the status stage), the PID will be IN.
+ * (2) Via do_parameter (as used by XHCI), all setup/data/status stages
+ * are done at once, and the PID will be OUT.
+ * (3) Via xhci_address_slot(), the PID will be OUT. As there is no
+ * data, this case does not really provide data.
+ */
+ if (pid == USB_TOKEN_IN || (pid == USB_TOKEN_OUT && p->parameter)) {
/* ctrl: device should set data in setup stage */
datalen = dev->setup_len;
}
@@ -332,9 +338,14 @@ void usb_dump_complete(UsbDumpState *s, const USBPacket *p)
}
if (ep_type == USB_ENDPOINT_XFER_CONTROL) {
- assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_SETUP);
-
- if (pid == USB_TOKEN_SETUP) {
+ /* Two modes of operation where data is available:
+ * (1) Via the normal do_token_setup() sequence. Data is provided by the
+ * device, but since handle_control() is called in do_token_setup(),
+ * the PID will be SETUP.
+ * (2) Via do_parameter (as used by XHCI), all setup/data/status stages
+ * are done at once, and the PID will be IN when data was requested.
+ */
+ if (pid == USB_TOKEN_SETUP || (pid == USB_TOKEN_IN && p->parameter)) {
/* this was an IN request, data is now available. */
assert(dev->setup_buf[0] & USB_DIR_IN);
datalen = p->actual_length;
diff --git a/hw/usb/dump.h b/hw/usb/dump.h
index 247016f259..7e81aaa043 100644
--- a/hw/usb/dump.h
+++ b/hw/usb/dump.h
@@ -36,7 +36,8 @@ typedef struct UsbDumpState UsbDumpState;
* - IN: setup_len > 0 (data): callback for OUT
* - (same code path: IN: setup_len == 0 (!data): Called iff dir is OUT
* (otherwise BROKEN!))
- * - Note: never called in OUT.
+ * - Note: never called in OUT (via do_token_out), but do_parameter may call
+ * with OUT as does XHCI.
*
* Possible combinations (^X,Y = handle_ctrl called, X and Y are Submission or
* Callback where X is called before processing the data in handle_ctrl, and Y
@@ -52,6 +53,7 @@ typedef struct UsbDumpState UsbDumpState;
* - setup(setup_len == 0, IN) / status^SC,(IN) - Same as above (with
* status(IN)), but there is no data for both submission and callback.
* - setup(setup_len == 0, OUT) / status(OUT) (BROKEN!)
+ * - NOTE: do_parameter() is not taken into account in the above description.
*
* handle_data is called for all non-EP0 transfers. PID is either IN or OUT.
* Sequence for the PID cases (interrupt):
@@ -72,7 +74,7 @@ typedef struct UsbDumpState UsbDumpState;
* --------+---+---+
*
* Control: DONE
- * Int: IN PROGRESS
+ * Int: DONE
* Bulk: TODO
* Isoc: TODO
*/