summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2018-08-29 17:21:55 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-09-17 21:34:52 -0700
commit3de0c0833737dd817753ade2159c378d949bf11f (patch)
tree0b6216cf1c14ef6f15b8c126c5d8bce3c47f5514
parentc7629caecec639e3cd6a6f01afbe8d131f23d762 (diff)
downloadchrome-ec-3de0c0833737dd817753ade2159c378d949bf11f.tar.gz
gsctool: refactor USB interface
Communications with Cr50 exposed USB endpoints could be needed by other utilities, in particular, ./util/iteflash when it is extended to operate over Cr50. This patch moves USB interface functions into a separate file in the ./util directory and makes USB endpoint coordinates run time variables, so that the user of the interface can connect to various endpoints. Some refactoring is required to allow using the generic USB transfer function. BRANCH=none BUG=b:75976718 TEST=verified that gsctool still operates properly - updated a Cr50, read Cr50 version number, etc. Change-Id: I3d77a93932f5395fff0f5823f0dd79e1d1d670c8 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1198345 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--extra/usb_updater/Makefile4
-rw-r--r--extra/usb_updater/gsctool.c179
-rw-r--r--extra/usb_updater/gsctool.h7
-rw-r--r--util/usb_if.c165
-rw-r--r--util/usb_if.h51
5 files changed, 235 insertions, 171 deletions
diff --git a/extra/usb_updater/Makefile b/extra/usb_updater/Makefile
index 01608ae1ea..fd616ec81f 100644
--- a/extra/usb_updater/Makefile
+++ b/extra/usb_updater/Makefile
@@ -32,6 +32,8 @@ LIBS += $(shell $(PKG_CONFIG) --libs libusb-1.0)
CFLAGS += $(shell $(PKG_CONFIG) --cflags libusb-1.0)
CFLAGS += -I../../include -I../../util -I../../fuzz -I../../test
+VPATH = ../../util
+
BOARD := cr50
LIBS_g = $(shell $(PKG_CONFIG) --libs libcrypto)
CFLAGS_g = $(shell $(PKG_CONFIG) --cflags libcrypto)
@@ -41,7 +43,7 @@ LIBS_common = -lfmap
all: $(PROGRAMS)
-GSCTOOL_SOURCES := gsctool.c desc_parser.c verify_ro.c
+GSCTOOL_SOURCES := gsctool.c desc_parser.c usb_if.c verify_ro.c
GSCTOOL_OBJS := $(patsubst %.c,%.o,$(GSCTOOL_SOURCES))
DEPS := $(patsubst %.c,%.d,$(GSCTOOL_SOURCES))
diff --git a/extra/usb_updater/gsctool.c b/extra/usb_updater/gsctool.c
index 32e570f7d4..1f53adde16 100644
--- a/extra/usb_updater/gsctool.c
+++ b/extra/usb_updater/gsctool.c
@@ -491,8 +491,7 @@ static int tpm_send_pkt(struct transfer_descriptor *td, unsigned int digest,
/* Release USB device and return error to the OS. */
static void shut_down(struct usb_endpoint *uep)
{
- libusb_close(uep->devh);
- libusb_exit(NULL);
+ usb_shut_down(uep);
exit(update_error);
}
@@ -592,120 +591,6 @@ static uint8_t *get_file_or_die(const char *filename, size_t *len_ptr)
return data;
}
-#define USB_ERROR(m, r) \
- fprintf(stderr, "%s:%d, %s returned %d (%s)\n", __FILE__, __LINE__, \
- m, r, libusb_strerror(r))
-
-/*
- * Actual USB transfer function, the 'allow_less' flag indicates that the
- * valid response could be shortef than allotted memory, the 'rxed_count'
- * pointer, if provided along with 'allow_less' lets the caller know how mavy
- * bytes were received.
- */
-static void do_xfer(struct usb_endpoint *uep, void *outbuf, int outlen,
- void *inbuf, int inlen, int allow_less,
- size_t *rxed_count)
-{
-
- int r, actual;
-
- /* Send data out */
- if (outbuf && outlen) {
- actual = 0;
- r = libusb_bulk_transfer(uep->devh, uep->ep_num,
- outbuf, outlen,
- &actual, 1000);
- if (r < 0) {
- USB_ERROR("libusb_bulk_transfer", r);
- exit(update_error);
- }
- if (actual != outlen) {
- fprintf(stderr, "%s:%d, only sent %d/%d bytes\n",
- __FILE__, __LINE__, actual, outlen);
- shut_down(uep);
- }
- }
-
- /* Read reply back */
- if (inbuf && inlen) {
-
- actual = 0;
- r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80,
- inbuf, inlen,
- &actual, 1000);
- if (r < 0) {
- USB_ERROR("libusb_bulk_transfer", r);
- exit(update_error);
- }
- if ((actual != inlen) && !allow_less) {
- fprintf(stderr, "%s:%d, only received %d/%d bytes\n",
- __FILE__, __LINE__, actual, inlen);
- shut_down(uep);
- }
-
- if (rxed_count)
- *rxed_count = actual;
- }
-}
-
-static void xfer(struct usb_endpoint *uep, void *outbuf,
- size_t outlen, void *inbuf, size_t inlen)
-{
- do_xfer(uep, outbuf, outlen, inbuf, inlen, 0, NULL);
-}
-
-/* Return 0 on error, since it's never gonna be EP 0 */
-static int find_endpoint(const struct libusb_interface_descriptor *iface,
- struct usb_endpoint *uep)
-{
- const struct libusb_endpoint_descriptor *ep;
-
- if (iface->bInterfaceClass == 255 &&
- iface->bInterfaceSubClass == SUBCLASS &&
- iface->bInterfaceProtocol == PROTOCOL &&
- iface->bNumEndpoints) {
- ep = &iface->endpoint[0];
- uep->ep_num = ep->bEndpointAddress & 0x7f;
- uep->chunk_len = ep->wMaxPacketSize;
- return 1;
- }
-
- return 0;
-}
-
-/* Return -1 on error */
-static int find_interface(struct usb_endpoint *uep)
-{
- int iface_num = -1;
- int r, i, j;
- struct libusb_device *dev;
- struct libusb_config_descriptor *conf = 0;
- const struct libusb_interface *iface0;
- const struct libusb_interface_descriptor *iface;
-
- dev = libusb_get_device(uep->devh);
- r = libusb_get_active_config_descriptor(dev, &conf);
- if (r < 0) {
- USB_ERROR("libusb_get_active_config_descriptor", r);
- goto out;
- }
-
- for (i = 0; i < conf->bNumInterfaces; i++) {
- iface0 = &conf->interface[i];
- for (j = 0; j < iface0->num_altsetting; j++) {
- iface = &iface0->altsetting[j];
- if (find_endpoint(iface, uep)) {
- iface_num = i;
- goto out;
- }
- }
- }
-
-out:
- libusb_free_config_descriptor(conf);
- return iface_num;
-}
-
/* Returns true if parsed. */
static int parse_vidpid(const char *input, uint16_t *vid_ptr, uint16_t *pid_ptr)
{
@@ -729,56 +614,19 @@ static int parse_vidpid(const char *input, uint16_t *vid_ptr, uint16_t *pid_ptr)
return 1;
}
-
-static void usb_findit(uint16_t vid, uint16_t pid, struct usb_endpoint *uep)
-{
- int iface_num, r;
-
- memset(uep, 0, sizeof(*uep));
-
- r = libusb_init(NULL);
- if (r < 0) {
- USB_ERROR("libusb_init", r);
- exit(update_error);
- }
-
- printf("open_device %04x:%04x\n", vid, pid);
- /* NOTE: This doesn't handle multiple matches! */
- uep->devh = libusb_open_device_with_vid_pid(NULL, vid, pid);
- if (!uep->devh) {
- fprintf(stderr, "Can't find device\n");
- exit(update_error);
- }
-
- iface_num = find_interface(uep);
- if (iface_num < 0) {
- fprintf(stderr, "USB FW update not supported by that device\n");
- shut_down(uep);
- }
- if (!uep->chunk_len) {
- fprintf(stderr, "wMaxPacketSize isn't valid\n");
- shut_down(uep);
- }
-
- printf("found interface %d endpoint %d, chunk_len %d\n",
- iface_num, uep->ep_num, uep->chunk_len);
-
- libusb_set_auto_detach_kernel_driver(uep->devh, 1);
- r = libusb_claim_interface(uep->devh, iface_num);
- if (r < 0) {
- USB_ERROR("libusb_claim_interface", r);
- shut_down(uep);
- }
-
- printf("READY\n-------\n");
-}
-
struct update_pdu {
uint32_t block_size; /* Total block size, include this field's size. */
struct upgrade_command cmd;
/* The actual payload goes here. */
};
+static void do_xfer(struct usb_endpoint *uep, void *outbuf, int outlen,
+ void *inbuf, int inlen, int allow_less, size_t *rxed_count)
+{
+ if (usb_trx(uep, outbuf, outlen, inbuf, inlen, allow_less, rxed_count))
+ shut_down(uep);
+}
+
static int transfer_block(struct usb_endpoint *uep, struct update_pdu *updu,
uint8_t *transfer_data_ptr, size_t payload_size)
{
@@ -788,14 +636,14 @@ static int transfer_block(struct usb_endpoint *uep, struct update_pdu *updu,
int r;
/* First send the header. */
- xfer(uep, updu, sizeof(*updu), NULL, 0);
+ do_xfer(uep, updu, sizeof(*updu), NULL, 0, 0, NULL);
/* Now send the block, chunk by chunk. */
for (transfer_size = 0; transfer_size < payload_size;) {
int chunk_size;
chunk_size = MIN(uep->chunk_len, payload_size - transfer_size);
- xfer(uep, transfer_data_ptr, chunk_size, NULL, 0);
+ do_xfer(uep, transfer_data_ptr, chunk_size, NULL, 0, 0, NULL);
transfer_data_ptr += chunk_size;
transfer_size += chunk_size;
}
@@ -1198,7 +1046,7 @@ static void send_done(struct usb_endpoint *uep)
/* Send stop request, ignoring reply. */
out = htobe32(UPGRADE_DONE);
- xfer(uep, &out, sizeof(out), &out, 1);
+ do_xfer(uep, &out, sizeof(out), &out, 1, 0, NULL);
}
/* Returns number of successfully transmitted image sections. */
@@ -2268,7 +2116,10 @@ int main(int argc, char *argv[])
}
if (td.ep_type == usb_xfer) {
- usb_findit(vid, pid, &td.uep);
+ if (usb_findit(vid, pid, USB_SUBCLASS_GOOGLE_CR50,
+ USB_PROTOCOL_GOOGLE_CR50_NON_HC_FW_UPDATE,
+ &td.uep))
+ exit(update_error);
} else if (td.ep_type == dev_xfer) {
td.tpm_fd = open("/dev/tpm0", O_RDWR);
if (td.tpm_fd < 0) {
diff --git a/extra/usb_updater/gsctool.h b/extra/usb_updater/gsctool.h
index 707ddfde87..1ac23b53bc 100644
--- a/extra/usb_updater/gsctool.h
+++ b/extra/usb_updater/gsctool.h
@@ -10,12 +10,7 @@
#include <stdint.h>
#include <sys/types.h>
-/* This describes USB endpoint used to communicate with Cr50. */
-struct usb_endpoint {
- struct libusb_device_handle *devh;
- uint8_t ep_num;
- int chunk_len;
-};
+#include "usb_if.h"
/*
* gsctool uses this structure to keep information about the communications
diff --git a/util/usb_if.c b/util/usb_if.c
new file mode 100644
index 0000000000..744faf2b16
--- /dev/null
+++ b/util/usb_if.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2018 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "usb_if.h"
+
+/* Return 0 on error, since it's never gonna be EP 0 */
+static int find_endpoint(const struct libusb_interface_descriptor *iface,
+ uint16_t subclass,
+ uint16_t protocol,
+ struct usb_endpoint *uep)
+{
+ const struct libusb_endpoint_descriptor *ep;
+
+ if (iface->bInterfaceClass == 255 &&
+ iface->bInterfaceSubClass == subclass &&
+ iface->bInterfaceProtocol == protocol &&
+ iface->bNumEndpoints) {
+ ep = &iface->endpoint[0];
+ uep->ep_num = ep->bEndpointAddress & 0x7f;
+ uep->chunk_len = ep->wMaxPacketSize;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return -1 on error */
+static int find_interface(uint16_t subclass,
+ uint16_t protocol,
+ struct usb_endpoint *uep)
+{
+ int iface_num = -1;
+ int r, i, j;
+ struct libusb_device *dev;
+ struct libusb_config_descriptor *conf = 0;
+ const struct libusb_interface *iface0;
+ const struct libusb_interface_descriptor *iface;
+
+ dev = libusb_get_device(uep->devh);
+ r = libusb_get_active_config_descriptor(dev, &conf);
+ if (r < 0) {
+ USB_ERROR("libusb_get_active_config_descriptor", r);
+ goto out;
+ }
+
+ for (i = 0; i < conf->bNumInterfaces; i++) {
+ iface0 = &conf->interface[i];
+ for (j = 0; j < iface0->num_altsetting; j++) {
+ iface = &iface0->altsetting[j];
+ if (find_endpoint(iface, subclass, protocol, uep)) {
+ iface_num = i;
+ goto out;
+ }
+ }
+ }
+
+out:
+ libusb_free_config_descriptor(conf);
+ return iface_num;
+}
+
+int usb_findit(uint16_t vid, uint16_t pid, uint16_t subclass,
+ uint16_t protocol, struct usb_endpoint *uep)
+{
+ int iface_num, r;
+
+ memset(uep, 0, sizeof(*uep));
+
+ r = libusb_init(NULL);
+ if (r < 0) {
+ USB_ERROR("libusb_init", r);
+ return -1;
+ }
+
+ printf("open_device %04x:%04x\n", vid, pid);
+ /* NOTE: This doesn't handle multiple matches! */
+ uep->devh = libusb_open_device_with_vid_pid(NULL, vid, pid);
+ if (!uep->devh) {
+ fprintf(stderr, "Can't find device\n");
+ return -1;
+ }
+
+ iface_num = find_interface(subclass, protocol, uep);
+ if (iface_num < 0) {
+ fprintf(stderr, "USB FW update not supported by that device\n");
+ usb_shut_down(uep);
+ }
+ if (!uep->chunk_len) {
+ fprintf(stderr, "wMaxPacketSize isn't valid\n");
+ usb_shut_down(uep);
+ }
+
+ printf("found interface %d endpoint %d, chunk_len %d\n",
+ iface_num, uep->ep_num, uep->chunk_len);
+
+ libusb_set_auto_detach_kernel_driver(uep->devh, 1);
+ r = libusb_claim_interface(uep->devh, iface_num);
+ if (r < 0) {
+ USB_ERROR("libusb_claim_interface", r);
+ usb_shut_down(uep);
+ }
+
+ printf("READY\n-------\n");
+ return 0;
+}
+
+int usb_trx(struct usb_endpoint *uep, void *outbuf, int outlen,
+ void *inbuf, int inlen, int allow_less, size_t *rxed_count)
+{
+
+ int r, actual;
+
+ /* Send data out */
+ if (outbuf && outlen) {
+ actual = 0;
+ r = libusb_bulk_transfer(uep->devh, uep->ep_num,
+ outbuf, outlen,
+ &actual, 1000);
+ if (r < 0) {
+ USB_ERROR("libusb_bulk_transfer", r);
+ return -1;
+ }
+ if (actual != outlen) {
+ fprintf(stderr, "%s:%d, only sent %d/%d bytes\n",
+ __FILE__, __LINE__, actual, outlen);
+ usb_shut_down(uep);
+ }
+ }
+
+ /* Read reply back */
+ if (inbuf && inlen) {
+
+ actual = 0;
+ r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80,
+ inbuf, inlen,
+ &actual, 1000);
+ if (r < 0) {
+ USB_ERROR("libusb_bulk_transfer", r);
+ return -1;
+ }
+ if ((actual != inlen) && !allow_less) {
+ fprintf(stderr, "%s:%d, only received %d/%d bytes\n",
+ __FILE__, __LINE__, actual, inlen);
+ usb_shut_down(uep);
+ }
+
+ if (rxed_count)
+ *rxed_count = actual;
+ }
+
+ return 0;
+}
+
+void usb_shut_down(struct usb_endpoint *uep)
+{
+ libusb_close(uep->devh);
+ libusb_exit(NULL);
+}
diff --git a/util/usb_if.h b/util/usb_if.h
new file mode 100644
index 0000000000..220564d2a3
--- /dev/null
+++ b/util/usb_if.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef __EC_EXTRA_USB_UPDATER_USB_IF_H
+#define __EC_EXTRA_USB_UPDATER_USB_IF_H
+
+#include <libusb.h>
+
+/* This describes USB endpoint used to communicate with Cr50. */
+struct usb_endpoint {
+ struct libusb_device_handle *devh;
+ uint8_t ep_num;
+ int chunk_len;
+};
+
+/*
+ * Find the requested USB endpoint, as determined by vid, pid, subclass and
+ * protocol parameters. If found, fill up the uep structure. If succeeded,
+ * usb_shut_down() must be invoked before program exits.
+ *
+ * Return 0 on success, -1 on failure.
+ */
+int usb_findit(uint16_t vid, uint16_t pid, uint16_t subclass,
+ uint16_t protocol, struct usb_endpoint *uep);
+
+/*
+ * Actual USB transfer function, the 'allow_less' flag indicates that the
+ * valid response could be shorter than allotted memory, the 'rxed_count'
+ * pointer, if provided along with 'allow_less', lets the caller know how many
+ * bytes were received.
+ */
+int usb_trx(struct usb_endpoint *uep, void *outbuf, int outlen,
+ void *inbuf, int inlen, int allow_less,
+ size_t *rxed_count);
+
+/*
+ * This function should be called for graceful tear down of the USB interface
+ * when the program exits, either normally or due to error. This is required
+ * only after USB connection was established, i.e. after successful invocation
+ * of usb_findit().
+ */
+void usb_shut_down(struct usb_endpoint *uep);
+
+#define USB_ERROR(m, r) \
+ fprintf(stderr, "%s:%d, %s returned %d (%s)\n", __FILE__, __LINE__, \
+ m, r, libusb_strerror(r))
+
+#endif /* ! __EC_EXTRA_USB_UPDATER_USB_IF_H */