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)
{