diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2018-08-29 17:21:55 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-09-17 21:34:52 -0700 |
commit | 3de0c0833737dd817753ade2159c378d949bf11f (patch) | |
tree | 0b6216cf1c14ef6f15b8c126c5d8bce3c47f5514 /util/usb_if.c | |
parent | c7629caecec639e3cd6a6f01afbe8d131f23d762 (diff) | |
download | chrome-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>
Diffstat (limited to 'util/usb_if.c')
-rw-r--r-- | util/usb_if.c | 165 |
1 files changed, 165 insertions, 0 deletions
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); +} |