summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/g/usb.c44
-rw-r--r--test/usb_test/Makefile34
-rw-r--r--test/usb_test/README2
-rw-r--r--test/usb_test/device_configuration.c172
4 files changed, 246 insertions, 6 deletions
diff --git a/chip/g/usb.c b/chip/g/usb.c
index 4912b0d7ad..de028935fe 100644
--- a/chip/g/usb.c
+++ b/chip/g/usb.c
@@ -217,7 +217,7 @@ const struct usb_config_descriptor USB_CONF_DESC(conf) = {
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0x0BAD, /* number of returned bytes, set at runtime */
.bNumInterfaces = USB_IFACE_COUNT,
- .bConfigurationValue = 1,
+ .bConfigurationValue = 1, /* Caution: hard-coded value */
.iConfiguration = USB_STR_VERSION,
.bmAttributes = 0x80, /* bus powered */
.bMaxPower = 250, /* MaxPower 500 mA */
@@ -306,6 +306,15 @@ static uint8_t ep0_in_buf[IN_BUF_SIZE];
static struct g_usb_desc ep0_in_desc[NUM_IN_PACKETS_AT_ONCE];
static struct g_usb_desc *cur_in_desc;
+/* Overall device state (USB 2.0 spec, section 9.1.1).
+ * We only need a few, though. */
+static enum {
+ DS_DEFAULT,
+ DS_ADDRESS,
+ DS_CONFIGURED,
+} device_state;
+static uint8_t configuration_value;
+
/* Reset all this to a good starting state. */
static void initialize_dma_buffers(void)
{
@@ -585,8 +594,9 @@ static int handle_setup_with_in_stage(enum table_case tc,
break;
}
case USB_REQ_GET_CONFIGURATION:
- /* TODO: We might need this to handle USB suspend properly */
- return -1;
+ data = &configuration_value;
+ len = sizeof(configuration_value);
+ break;
case USB_REQ_SYNCH_FRAME:
/* Unimplemented */
@@ -697,11 +707,25 @@ static int handle_setup_with_no_data_stage(enum table_case tc,
*/
GWRITE_FIELD(USB, DCFG, DEVADDR, set_addr);
print_later("SETAD 0x%02x (%d)", set_addr, set_addr, 0, 0, 0);
+ device_state = DS_ADDRESS;
break;
case USB_REQ_SET_CONFIGURATION:
- /* TODO: Sanity-check this? We only have one config, right? */
print_later("SETCFG 0x%x", req->wValue, 0, 0, 0, 0);
+ switch (req->wValue) {
+ case 0:
+ configuration_value = req->wValue;
+ device_state = DS_ADDRESS;
+ break;
+ case 1: /* Caution: Only one config descriptor TODAY */
+ /* TODO: All endpoints set to DATA0 toggle state */
+ configuration_value = req->wValue;
+ device_state = DS_CONFIGURED;
+ break;
+ default:
+ /* Nope. That's a paddlin. */
+ return -1;
+ }
break;
case USB_REQ_CLEAR_FEATURE:
@@ -836,7 +860,7 @@ static void ep0_interrupt(uint32_t intr_on_out, uint32_t intr_on_in)
/* I don't *think* we need to do this, unless we need
* to transfer more data. Customer support agrees and
* it shouldn't matter if the host is well-behaved, but
- * seems like we had issues without it.
+ * it seems like we had issues without it.
* TODO: Test this case until we know for sure. */
GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;
@@ -935,6 +959,10 @@ static void ep0_reset(void)
GWRITE_FIELD(USB, DCFG, DEVADDR, 0);
initialize_dma_buffers();
expect_setup_packet();
+ /* Clear our internal state */
+ device_state = DS_DEFAULT;
+ configuration_value = 0;
+
}
/****************************************************************************/
@@ -1040,6 +1068,7 @@ static void usb_early_suspend(void)
{
print_later("usb_early_suspend()", 0, 0, 0, 0, 0);
}
+
static void usb_suspend(void)
{
print_later("usb_suspend()", 0, 0, 0, 0, 0);
@@ -1147,6 +1176,9 @@ void usb_disconnect(void)
{
print_later("usb_disconnect()", 0, 0, 0, 0, 0);
GR_USB_DCTL |= DCTL_SFTDISCON;
+
+ device_state = DS_DEFAULT;
+ configuration_value = 0;
}
void usb_init(void)
@@ -1198,7 +1230,7 @@ void usb_init(void)
/* Global + DMA configuration */
/* TODO: What about the AHB Burst Length Field? It's 0 now. */
GR_USB_GAHBCFG = GAHBCFG_DMA_EN | GAHBCFG_GLB_INTR_EN |
- GAHBCFG_NP_TXF_EMP_LVL;
+ GAHBCFG_NP_TXF_EMP_LVL;
/* Be in disconnected state until we are ready */
usb_disconnect();
diff --git a/test/usb_test/Makefile b/test/usb_test/Makefile
new file mode 100644
index 0000000000..e18e4a7c3b
--- /dev/null
+++ b/test/usb_test/Makefile
@@ -0,0 +1,34 @@
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+PROGRAM := device_configuration
+SOURCE := $(PROGRAM).c
+LIBS :=
+LFLAGS :=
+CFLAGS := -std=gnu99 \
+ -g3 \
+ -O3 \
+ -Wall \
+ -Werror \
+ -Wpointer-arith \
+ -Wcast-align \
+ -Wcast-qual \
+ -Wundef \
+ -Wsign-compare \
+ -Wredundant-decls \
+ -Wmissing-declarations
+
+#
+# Add libusb-1.0 required flags
+#
+LIBS += $(shell pkg-config --libs libusb-1.0)
+CFLAGS += $(shell pkg-config --cflags libusb-1.0)
+
+$(PROGRAM): $(SOURCE) Makefile
+ gcc $(CFLAGS) $(SOURCE) $(LFLAGS) $(LIBS) -o $@
+
+.PHONY: clean
+
+clean:
+ rm -rf $(PROGRAM) *~
diff --git a/test/usb_test/README b/test/usb_test/README
new file mode 100644
index 0000000000..5d7af93f7e
--- /dev/null
+++ b/test/usb_test/README
@@ -0,0 +1,2 @@
+These tests need to be built and run by hand, unless/until we set up a lab
+with known devices attached to a test host.
diff --git a/test/usb_test/device_configuration.c b/test/usb_test/device_configuration.c
new file mode 100644
index 0000000000..69f889c2d3
--- /dev/null
+++ b/test/usb_test/device_configuration.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <libusb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Options */
+static uint16_t vid = 0x18d1; /* Google */
+static uint16_t pid = 0x5014; /* Cr50 */
+
+static char *progname;
+
+static void usage(int errs)
+{
+ printf("\nUsage: %s [vid:pid] [value]\n"
+ "\n"
+ "Set/Get the USB Device Configuration value\n"
+ "\n"
+ "The default vid:pid is %04x:%04x\n"
+ "\n", progname, vid, pid);
+
+ exit(!!errs);
+}
+
+/* Globals */
+struct libusb_device_handle *devh = 0;
+
+static void stupid_usb(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+
+ if (devh)
+ libusb_close(devh);
+
+ libusb_exit(NULL);
+
+ exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int r = 1;
+ int errorcnt = 0;
+ int do_set = 0;
+ uint16_t setval = 0;
+ uint8_t buf[80]; /* Arbitrary size */
+ int i;
+
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ opterr = 0; /* quiet, you */
+ while ((i = getopt(argc, argv, "")) != -1) {
+ switch (i) {
+ case 'h':
+ usage(errorcnt);
+ break;
+ case 0: /* auto-handled option */
+ break;
+ case '?':
+ if (optopt)
+ printf("Unrecognized option: -%c\n", optopt);
+ else
+ printf("Unrecognized option: %s\n",
+ argv[optind - 1]);
+ errorcnt++;
+ break;
+ case ':':
+ printf("Missing argument to %s\n", argv[optind - 1]);
+ errorcnt++;
+ break;
+ default:
+ printf("Internal error at %s:%d\n", __FILE__, __LINE__);
+ exit(1);
+ }
+ }
+
+ if (errorcnt)
+ usage(errorcnt);
+
+ if (optind < argc) {
+ uint16_t v, p;
+
+ if (2 == sscanf(argv[optind], "%hx:%hx", &v, &p)) {
+ vid = v;
+ pid = p;
+ optind++;
+ }
+ }
+
+ if (optind < argc) {
+ do_set = 1;
+ setval = atoi(argv[optind]);
+ }
+
+ r = libusb_init(NULL);
+ if (r) {
+ printf("libusb_init() returned 0x%x: %s\n",
+ r, libusb_error_name(r));
+ return 1;
+ }
+
+ devh = libusb_open_device_with_vid_pid(NULL, vid, pid);
+ if (!devh) {
+ perror(progname);
+ stupid_usb("Can't open device %04x:%04x\n", vid, pid);
+ }
+
+
+ /* Set config*/
+ if (do_set) {
+ printf("SetCfg %d\n", setval);
+ r = libusb_control_transfer(
+ devh,
+ 0x00, /* bmRequestType */
+ 0x09, /* bRequest */
+ setval, /* wValue */
+ 0x0000, /* wIndex */
+ NULL, /* data */
+ 0x0000, /* wLength */
+ 1000); /* timeout (ms) */
+
+ if (r < 0)
+ printf("transfer returned 0x%x %s\n",
+ r, libusb_error_name(r));
+ }
+
+ /* Get config */
+ memset(buf, 0, sizeof(buf));
+
+ r = libusb_control_transfer(
+ devh,
+ 0x80, /* bmRequestType */
+ 0x08, /* bRequest */
+ 0x0000, /* wValue */
+ 0x0000, /* wIndex */
+ buf, /* data */
+ 0x0001, /* wLength */
+ 1000); /* timeout (ms) */
+
+ if (r <= 0)
+ stupid_usb("GetCfg transfer() returned 0x%x %s\n",
+ r, libusb_error_name(r));
+
+ printf("GetCfg returned %d bytes:", r);
+ for (i = 0; i < r; i++)
+ printf(" 0x%02x", buf[i]);
+ printf("\n");
+
+ /* done */
+ if (devh)
+ libusb_close(devh);
+ libusb_exit(NULL);
+
+ return 0;
+}