usb gadget0: ctrl write/read loopback tests

This is based on linux's gadget0 intel loopback tests, and also github
pr: https://github.com/libopencm3/libopencm3/pull/592

Note that this captures the currently broken control loopback issues on
dwc_otg devices.

See https://github.com/libopencm3/libopencm3/issues/873 and all linked
issues.

Current status is passing on f3, f0, and failing on f4.
This commit is contained in:
Karl Palsson 2018-05-02 23:20:44 +00:00
parent ebcf197810
commit 42e43515c6
2 changed files with 65 additions and 3 deletions

View File

@ -3,6 +3,7 @@ import datetime
import random
import usb.core
import usb.util as uu
import random
import sys
import unittest
@ -25,6 +26,8 @@ GZ_REQ_SET_ALIGNED=3
GZ_REQ_SET_UNALIGNED=4
GZ_REQ_WRITE_LOOPBACK_BUFFER=10
GZ_REQ_READ_LOOPBACK_BUFFER=11
GZ_REQ_INTEL_WRITE=0x5b
GZ_REQ_INTEL_READ=0x5c
class find_by_serial(object):
def __init__(self, serial):
@ -83,6 +86,41 @@ class TestGadget0(unittest.TestCase):
# Note, this might not be as portable as we'd like.
self.assertIn("Pipe", e.strerror)
class TestIntelCompliance(unittest.TestCase):
"""
Part of intel's usb 2.0 compliance is writing and reading back control transfers
"""
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(self.cfg, "Config 2 should exist")
self.dev.set_configuration(self.cfg)
def tearDown(self):
uu.dispose_resources(self.dev)
def inner_t(self, mylen):
data = [random.randrange(255) for x in range(mylen)]
written = self.dev.ctrl_transfer(uu.CTRL_OUT | uu.CTRL_RECIPIENT_INTERFACE | uu.CTRL_TYPE_VENDOR, GZ_REQ_INTEL_WRITE, 0, 0, data)
self.assertEqual(written, len(data), "Should have written all bytes plz")
# now. in _theory_ I should be able to make a bulk transfer here and have it not "interfere"
# fixme - try this out?
read = self.dev.ctrl_transfer(uu.CTRL_IN | uu.CTRL_RECIPIENT_INTERFACE | uu.CTRL_TYPE_VENDOR, GZ_REQ_INTEL_READ, 0, 0, mylen)
self.assertEqual(mylen, len(read))
expected = array.array('B', [x for x in data])
self.assertEqual(expected, read, "should have read back what we wrote")
def test_ctrl_loopbacks(self):
self.inner_t(0)
self.inner_t(10)
self.inner_t(63)
self.inner_t(64)
self.inner_t(65)
self.inner_t(140)
self.inner_t(183)
class TestConfigSourceSink(unittest.TestCase):
"""

View File

@ -280,7 +280,6 @@ static enum usbd_request_return_codes gadget0_control_request(usbd_device *usbd_
(void) usbd_dev;
(void) complete;
(void) buf;
(void) len;
ER_DPRINTF("ctrl breq: %x, bmRT: %x, windex :%x, wlen: %x, wval :%x\n",
req->bRequest, req->bmRequestType, req->wIndex, req->wLength,
req->wValue);
@ -292,9 +291,31 @@ static enum usbd_request_return_codes gadget0_control_request(usbd_device *usbd_
state.pattern = req->wValue;
return USBD_REQ_HANDLED;
case INTEL_COMPLIANCE_WRITE:
/* accept correctly formed ctrl writes */
if (req->bmRequestType != (USB_REQ_TYPE_VENDOR|USB_REQ_TYPE_INTERFACE)) {
return USBD_REQ_NOTSUPP;
}
if (req->wValue || req->wIndex) {
return USBD_REQ_NOTSUPP;
}
if (req->wLength > sizeof(usbd_control_buffer)) {
return USBD_REQ_NOTSUPP;
}
/* ok, mark it as accepted. */
return USBD_REQ_HANDLED;
case INTEL_COMPLIANCE_READ:
ER_DPRINTF("unimplemented!");
return USBD_REQ_NOTSUPP;
if (req->bmRequestType != (USB_REQ_TYPE_IN|USB_REQ_TYPE_VENDOR|USB_REQ_TYPE_INTERFACE)) {
return USBD_REQ_NOTSUPP;
}
if (req->wValue || req->wIndex) {
return USBD_REQ_NOTSUPP;
}
if (req->wLength > sizeof(usbd_control_buffer)) {
return USBD_REQ_NOTSUPP;
}
/* ok, return what they left there earlier */
*len = req->wLength;
return USBD_REQ_HANDLED;
case GZ_REQ_SET_UNALIGNED:
state.test_unaligned = 1;
return USBD_REQ_HANDLED;
@ -316,6 +337,9 @@ static enum usbd_request_return_codes gadget0_control_request(usbd_device *usbd_
*len = req->wValue;
}
return USBD_REQ_HANDLED;
default:
ER_DPRINTF("Unhandled request!\n");
return USBD_REQ_NOTSUPP;
}
return USBD_REQ_NEXT_CALLBACK;
}