From dd022fcb4416bb4a3021f24d34540473c07ee4a9 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 25 Apr 2020 14:39:53 +0200 Subject: [PATCH] platforms/pc: Add common usb utilities. --- src/platforms/hosted/Makefile.inc | 2 +- src/platforms/pc/cl_utils.h | 1 + src/platforms/pc/libusb_utils.c | 144 ++++++++++++++++++++++++++++++ src/platforms/pc/libusb_utils.h | 41 +++++++++ src/platforms/pc/serial_unix.c | 2 +- src/platforms/pc/serial_win.c | 1 - 6 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 src/platforms/pc/libusb_utils.c create mode 100644 src/platforms/pc/libusb_utils.h diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index fc00abe2..d11199fa 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -8,5 +8,5 @@ else ifneq (, $(findstring cygwin, $(SYS))) LDFLAGS += -lws2_32 endif VPATH += platforms/pc -SRC += timing.c cl_utils.c utils.c +SRC += timing.c cl_utils.c utils.c libusb_utils.c PC_HOSTED = 1 diff --git a/src/platforms/pc/cl_utils.h b/src/platforms/pc/cl_utils.h index f25bd3ff..676fbfb2 100644 --- a/src/platforms/pc/cl_utils.h +++ b/src/platforms/pc/cl_utils.h @@ -53,6 +53,7 @@ typedef struct BMP_CL_OPTIONS_s { char *opt_idstring; }BMP_CL_OPTIONS_t; +extern int cl_debuglevel; void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv); int cl_execute(BMP_CL_OPTIONS_t *opt); int serial_open(BMP_CL_OPTIONS_t *opt); diff --git a/src/platforms/pc/libusb_utils.c b/src/platforms/pc/libusb_utils.c new file mode 100644 index 00000000..26c95a02 --- /dev/null +++ b/src/platforms/pc/libusb_utils.c @@ -0,0 +1,144 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "general.h" +#include "cl_utils.h" +#include + +static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans) +{ + struct trans_ctx * const ctx = trans->user_data; + + if (trans->status != LIBUSB_TRANSFER_COMPLETED) + { + fprintf(stderr, "on_trans_done: "); + if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) { + fprintf(stderr, " Timeout\n"); + } else if (trans->status == LIBUSB_TRANSFER_CANCELLED) { + fprintf(stderr, " cancelled\n"); + } else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) { + fprintf(stderr, " no device\n"); + } else { + fprintf(stderr, " unknown\n"); + } + ctx->flags |= TRANS_FLAGS_HAS_ERROR; + } + ctx->flags |= TRANS_FLAGS_IS_DONE; +} + +static int submit_wait(usb_link_t *link, struct libusb_transfer *trans) { + struct trans_ctx trans_ctx; + enum libusb_error error; + + trans_ctx.flags = 0; + + /* brief intrusion inside the libusb interface */ + trans->callback = on_trans_done; + trans->user_data = &trans_ctx; + + if ((error = libusb_submit_transfer(trans))) { + fprintf(stderr, "libusb_submit_transfer(%d): %s\n", error, + libusb_strerror(error)); + exit(-1); + } + + uint32_t start_time = platform_time_ms(); + while (trans_ctx.flags == 0) { + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + if (libusb_handle_events_timeout(link->ul_libusb_ctx, &timeout)) { + fprintf(stderr, "libusb_handle_events()\n"); + return -1; + } + uint32_t now = platform_time_ms(); + if (now - start_time > 1000) { + libusb_cancel_transfer(trans); + fprintf(stderr, "libusb_handle_events() timeout\n"); + return -1; + } + } + if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) { + fprintf(stderr, "libusb_handle_events() | has_error\n"); + return -1; + } + + return 0; +} + +/* One USB transaction */ +int send_recv(usb_link_t *link, + uint8_t *txbuf, size_t txsize, + uint8_t *rxbuf, size_t rxsize) +{ + int res = 0; + if( txsize) { + int txlen = txsize; + libusb_fill_bulk_transfer(link->req_trans, + link->ul_libusb_device_handle, + link->ep_tx | LIBUSB_ENDPOINT_OUT, + txbuf, txlen, + NULL, NULL, 0); + if (cl_debuglevel > 0) { + int i = 0; + printf(" Send (%3d): ", txlen); + for (; i < txlen; i++) { + printf("%02x", txbuf[i]); + if ((i & 7) == 7) + printf("."); + if ((i & 31) == 31) + printf("\n "); + } + if (!(i & 31)) + printf("\n"); + } + if (submit_wait(link, link->req_trans)) { + libusb_clear_halt(link->ul_libusb_device_handle, link->ep_tx); + return -1; + } + } + /* send_only */ + if (rxsize != 0) { + /* read the response */ + libusb_fill_bulk_transfer(link->rep_trans, link->ul_libusb_device_handle, + link->ep_rx | LIBUSB_ENDPOINT_IN, + rxbuf, rxsize, NULL, NULL, 0); + + if (submit_wait(link, link->rep_trans)) { + DEBUG("clear 1\n"); + libusb_clear_halt(link->ul_libusb_device_handle, link->ep_rx); + return -1; + } + res = link->rep_trans->actual_length; + if (res >0) { + int i; + uint8_t *p = rxbuf; + if (cl_debuglevel > 0) { + printf(" Rec (%zu/%d)", rxsize, res); + for (i = 0; i < res && i < 32 ; i++) { + if ( i && ((i & 7) == 0)) + printf("."); + printf("%02x", p[i]); + } + } + } + } + if (cl_debuglevel > 0) + printf("\n"); + return res; +} diff --git a/src/platforms/pc/libusb_utils.h b/src/platforms/pc/libusb_utils.h new file mode 100644 index 00000000..8f6d868c --- /dev/null +++ b/src/platforms/pc/libusb_utils.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#if !defined(__LIBUSB_UTILS_H) +#define __LIBUSB_UTILS_H +#include + +struct trans_ctx { +#define TRANS_FLAGS_IS_DONE (1 << 0) +#define TRANS_FLAGS_HAS_ERROR (1 << 1) + volatile unsigned long flags; +}; + +typedef struct { + libusb_context *ul_libusb_ctx; + libusb_device_handle *ul_libusb_device_handle; + unsigned char ep_tx; + unsigned char ep_rx; + struct libusb_transfer* req_trans; + struct libusb_transfer* rep_trans; + void *priv; +} usb_link_t; + +int send_recv(usb_link_t *link, uint8_t *txbuf, size_t txsize, + uint8_t *rxbuf, size_t rxsize); +#endif diff --git a/src/platforms/pc/serial_unix.c b/src/platforms/pc/serial_unix.c index cc186578..214bcc1d 100644 --- a/src/platforms/pc/serial_unix.c +++ b/src/platforms/pc/serial_unix.c @@ -31,7 +31,7 @@ #include "cl_utils.h" static int fd; /* File descriptor for connection to GDB remote */ -extern int cl_debuglevel; + /* A nice routine grabbed from * https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c */ diff --git a/src/platforms/pc/serial_win.c b/src/platforms/pc/serial_win.c index a39d1a1a..f9da89fc 100644 --- a/src/platforms/pc/serial_win.c +++ b/src/platforms/pc/serial_win.c @@ -24,7 +24,6 @@ #include "cl_utils.h" HANDLE hComm; -extern int cl_debuglevel; int serial_open(BMP_CL_OPTIONS_t *opt) {