diff --git a/Makefile b/Makefile index 796d2f0..8183fbb 100644 --- a/Makefile +++ b/Makefile @@ -2,15 +2,17 @@ CC = gcc VERSION = 0.7 GITCOUNT = $(shell git rev-list HEAD --count) +UNAME = $(shell uname) CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"' LDFLAGS = -g OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o LIBS = -lusb-1.0 -# Mac OS X -#CFLAGS += -I/usr/local/opt/gettext/include -#LIBS += -L/usr/local/opt/gettext/lib -lintl +# Linux +ifeq ($(UNAME),Linux) + OBJS += hid-libusb.o +endif all: dmrconfig diff --git a/dfu-libusb.c b/dfu-libusb.c index b2fe9df..81ed570 100644 --- a/dfu-libusb.c +++ b/dfu-libusb.c @@ -291,11 +291,13 @@ const char *dfu_init(unsigned vid, unsigned pid) dev = libusb_open_device_with_vid_pid(ctx, vid, pid); if (!dev) { - fprintf(stderr, "Cannot find USB device %04x:%04x\n", - vid, pid); + if (trace_flag) { + fprintf(stderr, "Cannot find USB device %04x:%04x\n", + vid, pid); + } libusb_exit(ctx); ctx = 0; - exit(-1); + return 0; } if (libusb_kernel_driver_active(dev, 0)) { libusb_detach_kernel_driver(dev, 0); diff --git a/hid-libusb.c b/hid-libusb.c new file mode 100644 index 0000000..6e12448 --- /dev/null +++ b/hid-libusb.c @@ -0,0 +1,269 @@ +/* + * HID routines for Linux, via libusb-1.0. + * + * Copyright (C) 2018 Serge Vakulenko, KK6ABQ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "util.h" + +static libusb_context *ctx = NULL; // libusb context +static libusb_device_handle *dev; // libusb device +static unsigned char receive_buf[42]; // receive buffer +static volatile int nbytes_received = 0; // receive result + +#define HID_INTERFACE 0 // interface index +#define TIMEOUT_MSEC 500 // receive timeout + +// +// Callback function for asynchronous receive. +// Needs to fill the receive_buf and set nbytes_received. +// +static void read_callback(struct libusb_transfer *transfer) +{ + switch (transfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + //fprintf(stderr, "%s: Transfer complete, %d bytes\n", __func__, transfer->actual_length); + memcpy(receive_buf, transfer->buffer, transfer->actual_length); + nbytes_received = transfer->actual_length; + break; + + case LIBUSB_TRANSFER_CANCELLED: + //fprintf(stderr, "%s: Transfer cancelled\n", __func__); + nbytes_received = LIBUSB_ERROR_INTERRUPTED; + return; + + case LIBUSB_TRANSFER_NO_DEVICE: + //fprintf(stderr, "%s: No device\n", __func__); + nbytes_received = LIBUSB_ERROR_NO_DEVICE; + return; + + case LIBUSB_TRANSFER_TIMED_OUT: + //fprintf(stderr, "%s: Timeout (normal)\n", __func__); + nbytes_received = LIBUSB_ERROR_TIMEOUT; + break; + + default: + //fprintf(stderr, "%s: Unknown transfer code: %d\n", __func__, transfer->status); + nbytes_received = LIBUSB_ERROR_IO; + } +} + +// +// Write data to the device and receive reply. +// Return negative status on error. +// Return received byte count of success. +// On timeout, repeat the transaction. +// Need to use callback for receive interrupt transfer. +// +static int write_read(const unsigned char *data, unsigned length, unsigned char *reply, unsigned rlength) +{ + struct libusb_transfer *transfer = libusb_alloc_transfer(0); +again: + nbytes_received = 0; + libusb_fill_interrupt_transfer(transfer, dev, + LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN, + reply, rlength, read_callback, 0, TIMEOUT_MSEC); + libusb_submit_transfer(transfer); + + int result = libusb_control_transfer(dev, + LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, + 0x09/*HID Set_Report*/, (2/*HID output*/ << 8) | 0, + HID_INTERFACE, (unsigned char*)data, length, TIMEOUT_MSEC); + + if (result < 0) { + fprintf(stderr, "Error %d transmitting data via control transfer: %s\n", + result, libusb_strerror(result)); + libusb_cancel_transfer(transfer); + libusb_free_transfer(transfer); + return -1; + } + + while (nbytes_received == 0) { + result = libusb_handle_events(ctx); + if (result < 0) { + /* Break out of this loop only on fatal error.*/ + if (result != LIBUSB_ERROR_BUSY && + result != LIBUSB_ERROR_TIMEOUT && + result != LIBUSB_ERROR_OVERFLOW && + result != LIBUSB_ERROR_INTERRUPTED) { + fprintf(stderr, "Error %d receiving data via interrupt transfer: %s\n", + result, libusb_strerror(result)); + libusb_free_transfer(transfer); + return result; + } + } + } + + if (nbytes_received == LIBUSB_ERROR_TIMEOUT) { + //fprintf(stderr, "Timed out!\n"); + goto again; + } + libusb_free_transfer(transfer); + return nbytes_received; +} + +// +// Send a request to the device. +// Store the reply into the rdata[] array. +// Terminate in case of errors. +// +void hid_send_recv(const unsigned char *data, unsigned nbytes, unsigned char *rdata, unsigned rlength) +{ + unsigned char buf[42]; + unsigned char reply[42]; + unsigned k; + int reply_len; + + memset(buf, 0, sizeof(buf)); + buf[0] = 1; + buf[1] = 0; + buf[2] = nbytes; + buf[3] = nbytes >> 8; + if (nbytes > 0) + memcpy(buf+4, data, nbytes); + nbytes += 4; + + if (trace_flag > 0) { + fprintf(stderr, "---Send"); + for (k=0; k 0) { + fprintf(stderr, "---Recv"); + for (k=0; k