From 21ad0778d274e13ac16373373ceb310121c28a68 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 2 Sep 2013 19:40:29 -0400 Subject: [PATCH 01/16] usb_descriptor: Fix whitespace --- firmware/hackrf_usb/usb_descriptor.c | 188 +++++++++++++-------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index e27218bb..d0a9e9d8 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -38,117 +38,117 @@ #define USB_STRING_LANGID (0x0409) uint8_t usb_descriptor_device[] = { - 18, // bLength - USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType - USB_WORD(0x0200), // bcdUSB - 0x00, // bDeviceClass - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - USB_MAX_PACKET0, // bMaxPacketSize0 - USB_WORD(USB_VENDOR_ID), // idVendor - USB_WORD(USB_PRODUCT_ID), // idProduct - USB_WORD(0x0100), // bcdDevice - 0x01, // iManufacturer - 0x02, // iProduct - 0x00, // iSerialNumber - 0x01 // bNumConfigurations + 18, // bLength + USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType + USB_WORD(0x0200), // bcdUSB + 0x00, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + USB_MAX_PACKET0, // bMaxPacketSize0 + USB_WORD(USB_VENDOR_ID), // idVendor + USB_WORD(USB_PRODUCT_ID), // idProduct + USB_WORD(0x0100), // bcdDevice + 0x01, // iManufacturer + 0x02, // iProduct + 0x00, // iSerialNumber + 0x01 // bNumConfigurations }; uint8_t usb_descriptor_device_qualifier[] = { - 10, // bLength - USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, // bDescriptorType - USB_WORD(0x0200), // bcdUSB - 0x00, // bDeviceClass - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - 64, // bMaxPacketSize0 - 0x01, // bNumOtherSpeedConfigurations - 0x00 // bReserved + 10, // bLength + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, // bDescriptorType + USB_WORD(0x0200), // bcdUSB + 0x00, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 64, // bMaxPacketSize0 + 0x01, // bNumOtherSpeedConfigurations + 0x00 // bReserved }; uint8_t usb_descriptor_configuration_full_speed[] = { - 9, // bLength - USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType - USB_WORD(32), // wTotalLength - 0x01, // bNumInterfaces - 0x01, // bConfigurationValue - 0x00, // iConfiguration - 0x80, // bmAttributes: USB-powered - 250, // bMaxPower: 500mA - - 9, // bLength - USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType - 0x00, // bInterfaceNumber - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints - 0xFF, // bInterfaceClass: vendor-specific - 0xFF, // bInterfaceSubClass - 0xFF, // bInterfaceProtocol: vendor-specific - 0x00, // iInterface - - 7, // bLength - USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType - USB_BULK_IN_EP_ADDR, // bEndpointAddress - 0x02, // bmAttributes: BULK - USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize - 0x00, // bInterval: no NAK - - 7, // bLength - USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType - USB_BULK_OUT_EP_ADDR, // bEndpointAddress - 0x02, // bmAttributes: BULK - USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize - 0x00, // bInterval: no NAK + 9, // bLength + USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType + USB_WORD(32), // wTotalLength + 0x01, // bNumInterfaces + 0x01, // bConfigurationValue + 0x00, // iConfiguration + 0x80, // bmAttributes: USB-powered + 250, // bMaxPower: 500mA + + 9, // bLength + USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0xFF, // bInterfaceClass: vendor-specific + 0xFF, // bInterfaceSubClass + 0xFF, // bInterfaceProtocol: vendor-specific + 0x00, // iInterface + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_IN_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_OUT_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize + 0x00, // bInterval: no NAK 0, // TERMINATOR }; uint8_t usb_descriptor_configuration_high_speed[] = { - 9, // bLength - USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType - USB_WORD(32), // wTotalLength - 0x01, // bNumInterfaces - 0x01, // bConfigurationValue - 0x00, // iConfiguration - 0x80, // bmAttributes: USB-powered - 250, // bMaxPower: 500mA - - 9, // bLength - USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType - 0x00, // bInterfaceNumber - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints - 0xFF, // bInterfaceClass: vendor-specific - 0xFF, // bInterfaceSubClass - 0xFF, // bInterfaceProtocol: vendor-specific - 0x00, // iInterface - - 7, // bLength - USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType - USB_BULK_IN_EP_ADDR, // bEndpointAddress - 0x02, // bmAttributes: BULK - USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize - 0x00, // bInterval: no NAK - - 7, // bLength - USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType - USB_BULK_OUT_EP_ADDR, // bEndpointAddress - 0x02, // bmAttributes: BULK - USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize - 0x00, // bInterval: no NAK + 9, // bLength + USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType + USB_WORD(32), // wTotalLength + 0x01, // bNumInterfaces + 0x01, // bConfigurationValue + 0x00, // iConfiguration + 0x80, // bmAttributes: USB-powered + 250, // bMaxPower: 500mA + + 9, // bLength + USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0xFF, // bInterfaceClass: vendor-specific + 0xFF, // bInterfaceSubClass + 0xFF, // bInterfaceProtocol: vendor-specific + 0x00, // iInterface + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_IN_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_OUT_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize + 0x00, // bInterval: no NAK 0, // TERMINATOR }; uint8_t usb_descriptor_string_languages[] = { - 0x04, // bLength - USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType - USB_WORD(USB_STRING_LANGID), // wLANGID + 0x04, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + USB_WORD(USB_STRING_LANGID), // wLANGID }; uint8_t usb_descriptor_string_manufacturer[] = { - 40, // bLength - USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + 40, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType 'G', 0x00, 'r', 0x00, 'e', 0x00, @@ -171,8 +171,8 @@ uint8_t usb_descriptor_string_manufacturer[] = { }; uint8_t usb_descriptor_string_product[] = { - 14, // bLength - USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + 14, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType 'H', 0x00, 'a', 0x00, 'c', 0x00, From 1a448900954da1d51d80cd6b2879402e1218fcc8 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 12:47:08 -0400 Subject: [PATCH 02/16] usb_descriptor: Add description strings for configurations --- firmware/hackrf_usb/usb_descriptor.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index d0a9e9d8..c9f26ce7 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -72,7 +72,7 @@ uint8_t usb_descriptor_configuration_full_speed[] = { USB_WORD(32), // wTotalLength 0x01, // bNumInterfaces 0x01, // bConfigurationValue - 0x00, // iConfiguration + 0x03, // iConfiguration 0x80, // bmAttributes: USB-powered 250, // bMaxPower: 500mA @@ -109,7 +109,7 @@ uint8_t usb_descriptor_configuration_high_speed[] = { USB_WORD(32), // wTotalLength 0x01, // bNumInterfaces 0x01, // bConfigurationValue - 0x00, // iConfiguration + 0x03, // iConfiguration 0x80, // bmAttributes: USB-powered 250, // bMaxPower: 500mA @@ -181,10 +181,27 @@ uint8_t usb_descriptor_string_product[] = { 'F', 0x00, }; +uint8_t usb_descriptor_string_config1_description[] = { + 24, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + 'T', 0x00, + 'r', 0x00, + 'a', 0x00, + 'n', 0x00, + 's', 0x00, + 'c', 0x00, + 'e', 0x00, + 'i', 0x00, + 'v', 0x00, + 'e', 0x00, + 'r', 0x00, +}; + uint8_t* const usb_descriptor_strings[] = { usb_descriptor_string_languages, usb_descriptor_string_manufacturer, usb_descriptor_string_product, + usb_descriptor_string_config1_description, 0, // TERMINATOR }; From 24d5a5c4f1fae6d88b7c1569faa40c097b1299b9 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Fri, 28 Jun 2013 21:30:46 -0400 Subject: [PATCH 03/16] usb: Add usb_endpoint_append_td This implements the procedure for adding a TD to the end of an active queue described in UM10503 Section 23.10.11.3. --- firmware/hackrf_usb/usb.c | 33 +++++++++++++++++++++++++++++++++ firmware/hackrf_usb/usb.h | 6 ++++++ 2 files changed, 39 insertions(+) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 8396e1bf..02fb81c3 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -195,6 +195,39 @@ void usb_endpoint_prime( USB0_ENDPTPRIME = USB0_ENDPTPRIME_PERB(1 << endpoint_number); } } + +// Schedule an already filled-up transfer descriptor for execution on +// the given endpoint. Note that this requires that one knows the tail +// of the endpoint's TD queue +void usb_endpoint_append_td( + const usb_endpoint_t* const endpoint, + usb_transfer_descriptor_t* const tail_td, + usb_transfer_descriptor_t* const new_td +) { + const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address); + bool done; + + tail_td->next_dtd_pointer = new_td; + + do { + if( usb_endpoint_is_in(endpoint->address) ) { + if (USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number) ) + return; + } else { + if (USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number) ) + return; + } + + USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW; + done = usb_endpoint_is_ready(endpoint); + } while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW)); + + USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW; + if(!done) { + usb_endpoint_prime(endpoint, new_td); + } +} + /* static bool usb_endpoint_is_priming( const usb_endpoint_t* const endpoint diff --git a/firmware/hackrf_usb/usb.h b/firmware/hackrf_usb/usb.h index 4b1d50f4..94372e0c 100644 --- a/firmware/hackrf_usb/usb.h +++ b/firmware/hackrf_usb/usb.h @@ -92,4 +92,10 @@ void usb_endpoint_prime( usb_transfer_descriptor_t* const first_td ); +void usb_endpoint_append_td( + const usb_endpoint_t* const endpoint, + usb_transfer_descriptor_t* const tail_td, + usb_transfer_descriptor_t* const new_td +); + #endif//__USB_H__ From 500aa5888c2ffef1540c2b15c7f2fd3d8d10cbb7 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 2 Sep 2013 19:22:27 -0400 Subject: [PATCH 04/16] usb_queue: Introduce queue management --- firmware/hackrf_usb/Makefile | 1 + firmware/hackrf_usb/usb_queue.c | 227 ++++++++++++++++++++++++++++++++ firmware/hackrf_usb/usb_queue.h | 90 +++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 firmware/hackrf_usb/usb_queue.c create mode 100644 firmware/hackrf_usb/usb_queue.h diff --git a/firmware/hackrf_usb/Makefile b/firmware/hackrf_usb/Makefile index 3d2b4d53..20a97295 100644 --- a/firmware/hackrf_usb/Makefile +++ b/firmware/hackrf_usb/Makefile @@ -27,6 +27,7 @@ SRC = $(BINARY).c \ usb_request.c \ usb_standard_request.c \ usb_descriptor.c \ + usb_queue.c \ ../common/fault_handler.c \ ../common/hackrf_core.c \ ../common/sgpio.c \ diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c new file mode 100644 index 00000000..1b79e829 --- /dev/null +++ b/firmware/hackrf_usb/usb_queue.c @@ -0,0 +1,227 @@ +/* + * Copyright 2012 Jared Boone + * Copyright 2013 Ben Gamari + * + * This file is part of HackRF. + * + * 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 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include + +#include "usb.h" +#include "usb_queue.h" + +usb_queue_t* endpoint_queues[12] = {}; + +#define USB_ENDPOINT_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1)) + +static usb_queue_t* endpoint_queue( + const usb_endpoint_t* const endpoint +) { + uint32_t index = USB_ENDPOINT_INDEX(endpoint->address); + if (endpoint_queues[index] == NULL) while (1); + return endpoint_queues[index]; +} + +void usb_queue_init( + usb_queue_t* const queue +) { + uint32_t index = USB_ENDPOINT_INDEX(queue->endpoint->address); + if (endpoint_queues[index] != NULL) while (1); + endpoint_queues[index] = queue; + + usb_transfer_t* t = queue->free_transfers; + for (unsigned int i=0; i < queue->pool_size - 1; i++, t++) { + t->next = t+1; + t->queue = queue; + } + t->next = NULL; + t->queue = queue; +} + +/* Allocate a transfer */ +static usb_transfer_t* allocate_transfer( + usb_queue_t* const queue +) { + bool aborted; + usb_transfer_t* transfer; + if (queue->free_transfers == NULL) + return NULL; + + do { + transfer = (void *) __ldrex((uint32_t *) &queue->free_transfers); + aborted = __strex((uint32_t) transfer->next, (uint32_t *) &queue->free_transfers); + } while (aborted); + transfer->next = NULL; + return transfer; +} + +/* Place a transfer in the free list */ +static void free_transfer(usb_transfer_t* const transfer) +{ + usb_queue_t* const queue = transfer->queue; + bool aborted; + do { + transfer->next = (void *) __ldrex((uint32_t *) &queue->free_transfers); + aborted = __strex((uint32_t) transfer, (uint32_t *) &queue->free_transfers); + } while (aborted); +} + +/* Add a transfer to the end of an endpoint's queue. Returns the old + * tail or NULL is the queue was empty + */ +static usb_transfer_t* endpoint_queue_transfer( + usb_transfer_t* const transfer +) { + usb_queue_t* const queue = transfer->queue; + transfer->next = NULL; + if (queue->active != NULL) { + usb_transfer_t* t = queue->active; + while (t->next != NULL) t = t->next; + t->next = transfer; + return t; + } else { + queue->active = transfer; + return NULL; + } +} + +static void usb_queue_flush_queue(usb_queue_t* const queue) +{ + cm_disable_interrupts(); + while (queue->active) { + usb_transfer_t* transfer = queue->active; + queue->active = transfer->next; + free_transfer(transfer); + } + cm_enable_interrupts(); +} + +void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint) +{ + usb_queue_flush_queue(endpoint_queue(endpoint)); +} + +int usb_transfer_schedule( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length, + const transfer_completion_cb completion_cb, + void* const user_data +) { + usb_queue_t* const queue = endpoint_queue(endpoint); + usb_transfer_t* const transfer = allocate_transfer(queue); + if (transfer == NULL) return -1; + usb_transfer_descriptor_t* const td = &transfer->td; + + // Configure the transfer descriptor + td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; + td->total_bytes = + USB_TD_DTD_TOKEN_TOTAL_BYTES(maximum_length) + | USB_TD_DTD_TOKEN_IOC + | USB_TD_DTD_TOKEN_MULTO(0) + | USB_TD_DTD_TOKEN_STATUS_ACTIVE + ; + td->buffer_pointer_page[0] = (uint32_t)data; + td->buffer_pointer_page[1] = ((uint32_t)data + 0x1000) & 0xfffff000; + td->buffer_pointer_page[2] = ((uint32_t)data + 0x2000) & 0xfffff000; + td->buffer_pointer_page[3] = ((uint32_t)data + 0x3000) & 0xfffff000; + td->buffer_pointer_page[4] = ((uint32_t)data + 0x4000) & 0xfffff000; + + // Fill in transfer fields + transfer->maximum_length = maximum_length; + transfer->completion_cb = completion_cb; + transfer->user_data = user_data; + + cm_disable_interrupts(); + usb_transfer_t* tail = endpoint_queue_transfer(transfer); + if (tail == NULL) { + // The queue is currently empty, we need to re-prime + usb_endpoint_schedule_wait(queue->endpoint, &transfer->td); + } else { + // The queue is currently running, try to append + usb_endpoint_schedule_append(queue->endpoint, &tail->td, &transfer->td); + } + cm_enable_interrupts(); + return 0; +} + +int usb_transfer_schedule_block( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length, + const transfer_completion_cb completion_cb, + void* const user_data +) { + int ret; + do { + ret = usb_transfer_schedule(endpoint, data, maximum_length, + completion_cb, user_data); + } while (ret == -1); + return 0; +} + +int usb_transfer_schedule_ack( + const usb_endpoint_t* const endpoint +) { + return usb_transfer_schedule_block(endpoint, 0, 0, NULL, NULL); +} + +/* Called when an endpoint might have completed a transfer */ +void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) +{ + usb_queue_t* const queue = endpoint_queue(endpoint); + if (queue == NULL) while(1); // Uh oh + usb_transfer_t* transfer = queue->active; + + while (transfer != NULL) { + uint8_t status = transfer->td.total_bytes; + + // Check for failures + if ( status & USB_TD_DTD_TOKEN_STATUS_HALTED + || status & USB_TD_DTD_TOKEN_STATUS_BUFFER_ERROR + || status & USB_TD_DTD_TOKEN_STATUS_TRANSACTION_ERROR) { + // TODO: Uh oh, do something useful here + while (1); + } + + // Still not finished + if (status & USB_TD_DTD_TOKEN_STATUS_ACTIVE) + break; + + // Advance the head. We need to do this before invoking the completion + // callback as it might attempt to schedule a new transfer + queue->active = transfer->next; + usb_transfer_t* next = transfer->next; + + // Invoke completion callback + unsigned int total_bytes = (transfer->td.total_bytes & USB_TD_DTD_TOKEN_TOTAL_BYTES_MASK) >> USB_TD_DTD_TOKEN_TOTAL_BYTES_SHIFT; + unsigned int transferred = transfer->maximum_length - total_bytes; + if (transfer->completion_cb) + transfer->completion_cb(transfer->user_data, transferred); + + // Advance head and free transfer + free_transfer(transfer); + transfer = next; + } +} diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h new file mode 100644 index 00000000..2332022c --- /dev/null +++ b/firmware/hackrf_usb/usb_queue.h @@ -0,0 +1,90 @@ +/* + * Copyright 2012 Jared Boone + * Copyright 2013 Ben Gamari + * + * This file is part of HackRF. + * + * 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 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __USB_QUEUE_H__ +#define __USB_QUEUE_H__ + +#include + +#include "usb_type.h" + +typedef struct _usb_transfer_t usb_transfer_t; +typedef struct _usb_queue_t usb_queue_t; +typedef void (*transfer_completion_cb)(void*, unsigned int); + +// This is an opaque datatype. Thou shall not touch these members. +struct _usb_transfer_t { + struct _usb_transfer_t* next; + usb_transfer_descriptor_t td ATTR_ALIGNED(64); + unsigned int maximum_length; + struct _usb_queue_t* queue; + transfer_completion_cb completion_cb; + void* user_data; +}; + +// This is an opaque datatype. Thou shall not touch these members. +struct _usb_queue_t { + struct usb_endpoint_t* endpoint; + const unsigned int pool_size; + usb_transfer_t* volatile free_transfers; + usb_transfer_t* volatile active; +}; + +#define USB_DEFINE_QUEUE(endpoint_name, _pool_size) \ + struct _usb_transfer_t endpoint_name##_transfers[_pool_size]; \ + struct _usb_queue_t endpoint_name##_queue = { \ + .endpoint = &endpoint_name, \ + .free_transfers = endpoint_name##_transfers, \ + .pool_size = _pool_size \ + }; + +void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint); + +int usb_transfer_schedule( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length, + const transfer_completion_cb completion_cb, + void* const user_data +); + +int usb_transfer_schedule_block( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length, + const transfer_completion_cb completion_cb, + void* const user_data +); + +int usb_transfer_schedule_ack( + const usb_endpoint_t* const endpoint +); + +void usb_queue_init( + usb_queue_t* const queue +); + +void usb_queue_transfer_complete( + usb_endpoint_t* const endpoint +); + +#endif//__USB_QUEUE_H__ From 693c26213476f10ddecfe115563ad1b3b04f5227 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 13:54:25 -0400 Subject: [PATCH 05/16] libhackrf: Stop streaming before killing transfer thread --- host/libhackrf/src/hackrf.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 7e36dc55..47ff055a 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -1141,14 +1141,13 @@ int ADDCALL hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn cal int ADDCALL hackrf_stop_rx(hackrf_device* device) { - int result1, result2; - result1 = kill_transfer_thread(device); - result2 = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF); - if (result2 != HACKRF_SUCCESS) + int result; + result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF); + if (result != HACKRF_SUCCESS) { - return result2; + return result; } - return result1; + return kill_transfer_thread(device); } int ADDCALL hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* tx_ctx) From 4773ee5a53bf1767185a45ae0c8a423c81e59eec Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 13:54:56 -0400 Subject: [PATCH 06/16] hackrf_usb: Port to use usb_queue --- firmware/hackrf_usb/hackrf_usb.c | 189 ++++++++++----------- firmware/hackrf_usb/usb.c | 138 ++++++--------- firmware/hackrf_usb/usb.h | 17 +- firmware/hackrf_usb/usb_request.c | 3 + firmware/hackrf_usb/usb_standard_request.c | 22 ++- firmware/libopencm3 | 2 +- 6 files changed, 164 insertions(+), 207 deletions(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index a175ea3d..f077a014 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -39,6 +39,7 @@ #include "usb.h" #include "usb_type.h" +#include "usb_queue.h" #include "usb_request.h" #include "usb_descriptor.h" #include "usb_standard_request.h" @@ -49,9 +50,6 @@ uint8_t* const usb_bulk_buffer = (uint8_t*)0x20004000; static volatile uint32_t usb_bulk_buffer_offset = 0; static const uint32_t usb_bulk_buffer_mask = 32768 - 1; -usb_transfer_descriptor_t usb_td_bulk[2] ATTR_ALIGNED(64); -const uint_fast8_t usb_td_bulk_count = sizeof(usb_td_bulk) / sizeof(usb_td_bulk[0]); - /* TODO remove this big buffer and use streaming for CPLD */ #define CPLD_XSVF_MAX_LEN (65536) uint8_t cpld_xsvf_buffer[CPLD_XSVF_MAX_LEN]; @@ -181,50 +179,6 @@ bool set_freq(uint32_t freq_mhz, uint32_t freq_hz) return success; } -static void usb_init_buffers_bulk() { - usb_td_bulk[0].next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; - usb_td_bulk[0].total_bytes - = USB_TD_DTD_TOKEN_TOTAL_BYTES(16384) - | USB_TD_DTD_TOKEN_MULTO(0) - ; - usb_td_bulk[0].buffer_pointer_page[0] = (uint32_t)&usb_bulk_buffer[0x0000]; - usb_td_bulk[0].buffer_pointer_page[1] = (uint32_t)&usb_bulk_buffer[0x1000]; - usb_td_bulk[0].buffer_pointer_page[2] = (uint32_t)&usb_bulk_buffer[0x2000]; - usb_td_bulk[0].buffer_pointer_page[3] = (uint32_t)&usb_bulk_buffer[0x3000]; - usb_td_bulk[0].buffer_pointer_page[4] = (uint32_t)&usb_bulk_buffer[0x4000]; - - usb_td_bulk[1].next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; - usb_td_bulk[1].total_bytes - = USB_TD_DTD_TOKEN_TOTAL_BYTES(16384) - | USB_TD_DTD_TOKEN_MULTO(0) - ; - usb_td_bulk[1].buffer_pointer_page[0] = (uint32_t)&usb_bulk_buffer[0x4000]; - usb_td_bulk[1].buffer_pointer_page[1] = (uint32_t)&usb_bulk_buffer[0x5000]; - usb_td_bulk[1].buffer_pointer_page[2] = (uint32_t)&usb_bulk_buffer[0x6000]; - usb_td_bulk[1].buffer_pointer_page[3] = (uint32_t)&usb_bulk_buffer[0x7000]; - usb_td_bulk[1].buffer_pointer_page[4] = (uint32_t)&usb_bulk_buffer[0x8000]; -} - -void usb_endpoint_schedule_no_int( - const usb_endpoint_t* const endpoint, - usb_transfer_descriptor_t* const td -) { - // Ensure that endpoint is ready to be primed. - // It may have been flushed due to an aborted transaction. - // TODO: This should be preceded by a flush? - while( usb_endpoint_is_ready(endpoint) ); - - // Configure a transfer. - td->total_bytes = - USB_TD_DTD_TOKEN_TOTAL_BYTES(16384) - /*| USB_TD_DTD_TOKEN_IOC*/ - | USB_TD_DTD_TOKEN_MULTO(0) - | USB_TD_DTD_TOKEN_STATUS_ACTIVE - ; - - usb_endpoint_prime(endpoint, td); -} - usb_configuration_t usb_configuration_high_speed = { .number = 1, .speed = USB_SPEED_HIGH, @@ -260,6 +214,7 @@ usb_endpoint_t usb_endpoint_control_out = { .setup_complete = usb_setup_complete, .transfer_complete = usb_control_out_complete, }; +USB_DEFINE_QUEUE(usb_endpoint_control_out, 4); usb_endpoint_t usb_endpoint_control_in = { .address = 0x80, @@ -269,6 +224,7 @@ usb_endpoint_t usb_endpoint_control_in = { .setup_complete = 0, .transfer_complete = usb_control_in_complete, }; +static USB_DEFINE_QUEUE(usb_endpoint_control_in, 4); // NOTE: Endpoint number for IN and OUT are different. I wish I had some // evidence that having BULK IN and OUT on separate endpoint numbers was @@ -280,8 +236,9 @@ usb_endpoint_t usb_endpoint_bulk_in = { .in = &usb_endpoint_bulk_in, .out = 0, .setup_complete = 0, - .transfer_complete = 0, + .transfer_complete = usb_queue_transfer_complete }; +static USB_DEFINE_QUEUE(usb_endpoint_bulk_in, 4); usb_endpoint_t usb_endpoint_bulk_out = { .address = 0x02, @@ -289,8 +246,9 @@ usb_endpoint_t usb_endpoint_bulk_out = { .in = 0, .out = &usb_endpoint_bulk_out, .setup_complete = 0, - .transfer_complete = 0, + .transfer_complete = usb_queue_transfer_complete }; +static USB_DEFINE_QUEUE(usb_endpoint_bulk_out, 4); void baseband_streaming_disable() { sgpio_cpld_stream_disable(); @@ -306,8 +264,6 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { transceiver_mode = new_transceiver_mode; - usb_init_buffers_bulk(); - if( transceiver_mode == TRANSCEIVER_MODE_RX ) { gpio_clear(PORT_LED1_3, PIN_LED3); gpio_set(PORT_LED1_3, PIN_LED2); @@ -339,7 +295,7 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { nvic_enable_irq(NVIC_SGPIO_IRQ); SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A); - sgpio_cpld_stream_enable(); + sgpio_cpld_stream_enable(); } usb_request_status_t usb_vendor_request_set_transceiver_mode( @@ -352,7 +308,7 @@ usb_request_status_t usb_vendor_request_set_transceiver_mode( case TRANSCEIVER_MODE_RX: case TRANSCEIVER_MODE_TX: set_transceiver_mode(endpoint->setup.value); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; default: return USB_REQUEST_STATUS_STALL; @@ -370,7 +326,7 @@ usb_request_status_t usb_vendor_request_write_max2837( if( endpoint->setup.index < MAX2837_NUM_REGS ) { if( endpoint->setup.value < MAX2837_DATA_REGS_MAX_VALUE ) { max2837_reg_write(endpoint->setup.index, endpoint->setup.value); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } } @@ -389,8 +345,9 @@ usb_request_status_t usb_vendor_request_read_max2837( const uint16_t value = max2837_reg_read(endpoint->setup.index); endpoint->buffer[0] = value & 0xff; endpoint->buffer[1] = value >> 8; - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 2); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -407,7 +364,7 @@ usb_request_status_t usb_vendor_request_write_si5351c( if( endpoint->setup.index < 256 ) { if( endpoint->setup.value < 256 ) { si5351c_write_single(endpoint->setup.index, endpoint->setup.value); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } } @@ -425,8 +382,9 @@ usb_request_status_t usb_vendor_request_read_si5351c( if( endpoint->setup.index < 256 ) { const uint8_t value = si5351c_read_single(endpoint->setup.index); endpoint->buffer[0] = value; - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -442,7 +400,7 @@ usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth( if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint32_t bandwidth = (endpoint->setup.index << 16) | endpoint->setup.value; if( baseband_filter_bandwidth_set(bandwidth) ) { - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -460,7 +418,7 @@ usb_request_status_t usb_vendor_request_write_rffc5071( if( endpoint->setup.index < RFFC5071_NUM_REGS ) { rffc5071_reg_write(endpoint->setup.index, endpoint->setup.value); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -481,8 +439,9 @@ usb_request_status_t usb_vendor_request_read_rffc5071( value = rffc5071_reg_read(endpoint->setup.index); endpoint->buffer[0] = value & 0xff; endpoint->buffer[1] = value >> 8; - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 2); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -500,7 +459,7 @@ usb_request_status_t usb_vendor_request_erase_spiflash( w25q80bv_setup(); /* only chip erase is implemented */ w25q80bv_chip_erase(); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); //FIXME probably should undo w25q80bv_setup() } return USB_REQUEST_STATUS_OK; @@ -521,7 +480,8 @@ usb_request_status_t usb_vendor_request_write_spiflash( || ((addr + len) > W25Q80BV_NUM_BYTES)) { return USB_REQUEST_STATUS_STALL; } else { - usb_endpoint_schedule(endpoint->out, &spiflash_buffer[0], len); + usb_transfer_schedule_block(endpoint->out, &spiflash_buffer[0], len, + NULL, NULL); w25q80bv_setup(); return USB_REQUEST_STATUS_OK; } @@ -534,7 +494,7 @@ usb_request_status_t usb_vendor_request_write_spiflash( return USB_REQUEST_STATUS_STALL; } else { w25q80bv_program(addr, len, &spiflash_buffer[0]); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); //FIXME probably should undo w25q80bv_setup() return USB_REQUEST_STATUS_OK; } @@ -556,7 +516,7 @@ usb_request_status_t usb_vendor_request_read_spiflash( addr = (endpoint->setup.value << 16) | endpoint->setup.index; len = endpoint->setup.length; if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) - || ((addr + len) > W25Q80BV_NUM_BYTES)) { + || ((addr + len) > W25Q80BV_NUM_BYTES)) { return USB_REQUEST_STATUS_STALL; } else { /* TODO flush SPIFI "cache" before to read the SPIFI memory */ @@ -565,7 +525,8 @@ usb_request_status_t usb_vendor_request_read_spiflash( { spiflash_buffer[i] = u8_addr_pt[i]; } - usb_endpoint_schedule(endpoint->in, &spiflash_buffer[0], len); + usb_transfer_schedule_block(endpoint->in, &spiflash_buffer[0], len, + NULL, NULL); return USB_REQUEST_STATUS_OK; } } else if (stage == USB_TRANSFER_STAGE_DATA) @@ -579,7 +540,7 @@ usb_request_status_t usb_vendor_request_read_spiflash( return USB_REQUEST_STATUS_STALL; } else { - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } } else @@ -603,7 +564,8 @@ usb_request_status_t usb_vendor_request_write_cpld( // len is limited to 64KB 16bits no overflow can happen total_len = endpoint->setup.value; len = endpoint->setup.length; - usb_endpoint_schedule(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len); + usb_transfer_schedule_block(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len, + NULL, NULL); return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { @@ -619,7 +581,7 @@ usb_request_status_t usb_vendor_request_write_cpld( // TO FIX ACK shall be not delayed so much as cpld prog can take up to 5s. if(error == 0) { - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); /* blink LED1, LED2, and LED3 on success */ while (1) @@ -641,7 +603,7 @@ usb_request_status_t usb_vendor_request_write_cpld( } }else { - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } } else @@ -655,8 +617,8 @@ usb_request_status_t usb_vendor_request_read_board_id( { if (stage == USB_TRANSFER_STAGE_SETUP) { endpoint->buffer[0] = BOARD_ID; - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; } @@ -668,8 +630,8 @@ usb_request_status_t usb_vendor_request_read_version_string( if (stage == USB_TRANSFER_STAGE_SETUP) { length = (uint8_t)strlen(version_string); - usb_endpoint_schedule(endpoint->in, version_string, length); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, version_string, length, NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; } @@ -680,13 +642,14 @@ usb_request_status_t usb_vendor_request_set_freq( { if (stage == USB_TRANSFER_STAGE_SETUP) { - usb_endpoint_schedule(endpoint->out, &set_freq_params, sizeof(set_freq_params_t)); + usb_transfer_schedule_block(endpoint->out, &set_freq_params, sizeof(set_freq_params_t), + NULL, NULL); return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { if( set_freq(set_freq_params.freq_mhz, set_freq_params.freq_hz) ) { - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -702,13 +665,14 @@ usb_request_status_t usb_vendor_request_set_sample_rate_frac( { if (stage == USB_TRANSFER_STAGE_SETUP) { - usb_endpoint_schedule(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t)); + usb_transfer_schedule_block(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t), + NULL, NULL); return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { if( sample_rate_frac_set(set_sample_r_params.freq_hz * 2, set_sample_r_params.divider ) ) { - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -726,12 +690,12 @@ usb_request_status_t usb_vendor_request_set_amp_enable( case 0: switchctrl |= SWITCHCTRL_AMP_BYPASS; update_switches(); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; case 1: switchctrl &= ~SWITCHCTRL_AMP_BYPASS; update_switches(); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; default: return USB_REQUEST_STATUS_STALL; @@ -776,20 +740,23 @@ usb_request_status_t usb_vendor_request_read_partid_serialno( read_partid_serialno.serial_no[3] = iap_cmd_res.status_res.iap_result[3]; length = (uint8_t)sizeof(read_partid_serialno_t); - usb_endpoint_schedule(endpoint->in, &read_partid_serialno, length); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &read_partid_serialno, length, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_set_lna_gain( - usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage) { if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint8_t value = max2837_set_lna_gain(endpoint->setup.index); endpoint->buffer[0] = value; - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; @@ -801,8 +768,9 @@ usb_request_status_t usb_vendor_request_set_vga_gain( if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint8_t value = max2837_set_vga_gain(endpoint->setup.index); endpoint->buffer[0] = value; - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; @@ -814,8 +782,9 @@ usb_request_status_t usb_vendor_request_set_txvga_gain( if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint8_t value = max2837_set_txvga_gain(endpoint->setup.index); endpoint->buffer[0] = value; - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; @@ -827,7 +796,7 @@ usb_request_status_t usb_vendor_request_set_if_freq( if( stage == USB_TRANSFER_STAGE_SETUP ) { MAX2837_FREQ_NOMINAL_HZ = (uint32_t)endpoint->setup.index * 1000 * 1000; set_freq(freq_mhz_cache, freq_hz_cache); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); } return USB_REQUEST_STATUS_OK; } @@ -966,10 +935,16 @@ int main(void) { enable_1v8_power(); cpu_clock_init(); + usb_set_configuration_changed_cb(usb_configuration_changed); usb_peripheral_reset(); usb_device_init(0, &usb_device); + usb_queue_init(&usb_endpoint_control_out_queue); + usb_queue_init(&usb_endpoint_control_in_queue); + usb_queue_init(&usb_endpoint_bulk_out_queue); + usb_queue_init(&usb_endpoint_bulk_in_queue); + usb_endpoint_init(&usb_endpoint_control_out); usb_endpoint_init(&usb_endpoint_control_in); @@ -977,7 +952,7 @@ int main(void) { usb_run(&usb_device); - ssp1_init(); + ssp1_init(); ssp1_set_mode_max5864(); max5864_xcvr(); @@ -996,21 +971,29 @@ int main(void) { while( usb_bulk_buffer_offset < 16384 ); // Set up IN transfer of buffer 0. - usb_endpoint_schedule_no_int( - (transceiver_mode == TRANSCEIVER_MODE_RX) - ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, - &usb_td_bulk[0] - ); + if (transceiver_mode != TRANSCEIVER_MODE_OFF) { + usb_transfer_schedule_block( + (transceiver_mode == TRANSCEIVER_MODE_RX) + ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, + &usb_bulk_buffer[0x0000], + 0x4000, + NULL, NULL + ); + } // Wait until buffer 1 is transmitted/received. while( usb_bulk_buffer_offset >= 16384 ); // Set up IN transfer of buffer 1. - usb_endpoint_schedule_no_int( - (transceiver_mode == TRANSCEIVER_MODE_RX) - ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, - &usb_td_bulk[1] - ); + if (transceiver_mode != TRANSCEIVER_MODE_OFF) { + usb_transfer_schedule_block( + (transceiver_mode == TRANSCEIVER_MODE_RX) + ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, + &usb_bulk_buffer[0x4000], + 0x4000, + NULL, NULL + ); + } } return 0; diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 02fb81c3..3444e1c2 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -24,6 +24,7 @@ #include "usb.h" #include "usb_type.h" +#include "usb_queue.h" #include "usb_standard_request.h" #include @@ -34,10 +35,8 @@ usb_device_t* usb_device_usb0 = 0; usb_queue_head_t usb_qh[12] ATTR_ALIGNED(2048); -usb_transfer_descriptor_t usb_td[12] ATTR_ALIGNED(64); #define USB_QH_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1)) -#define USB_TD_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1)) usb_queue_head_t* usb_queue_head( const uint_fast8_t endpoint_address @@ -45,12 +44,6 @@ usb_queue_head_t* usb_queue_head( return &usb_qh[USB_QH_INDEX(endpoint_address)]; } -usb_transfer_descriptor_t* usb_transfer_descriptor( - const uint_fast8_t endpoint_address -) { - return &usb_td[USB_TD_INDEX(endpoint_address)]; -} - static usb_endpoint_t* usb_endpoint_from_address( const uint_fast8_t endpoint_address ) { @@ -98,25 +91,25 @@ static void usb_clear_all_pending_interrupts() { static void usb_wait_for_endpoint_priming_to_finish(const uint32_t mask) { // Wait until controller has parsed new transfer descriptors and prepared // receive buffers. - while( USB0_ENDPTPRIME & mask ); + while( USB0_ENDPTPRIME & mask ); } static void usb_flush_endpoints(const uint32_t mask) { // Clear any primed buffers. If a packet is in progress, that transfer // will continue until completion. - USB0_ENDPTFLUSH = mask; + USB0_ENDPTFLUSH = mask; } static void usb_wait_for_endpoint_flushing_to_finish(const uint32_t mask) { // Wait until controller has flushed all endpoints / cleared any primed // buffers. - while( USB0_ENDPTFLUSH & mask ); + while( USB0_ENDPTFLUSH & mask ); } static void usb_flush_primed_endpoints(const uint32_t mask) { - usb_wait_for_endpoint_priming_to_finish(mask); + usb_wait_for_endpoint_priming_to_finish(mask); usb_flush_endpoints(mask); - usb_wait_for_endpoint_flushing_to_finish(mask); + usb_wait_for_endpoint_flushing_to_finish(mask); } static void usb_flush_all_primed_endpoints() { @@ -171,6 +164,7 @@ void usb_endpoint_disable( } else { USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_RXE); } + usb_queue_flush_endpoint(endpoint); usb_endpoint_clear_pending_interrupts(endpoint); usb_endpoint_flush(endpoint); } @@ -196,39 +190,6 @@ void usb_endpoint_prime( } } -// Schedule an already filled-up transfer descriptor for execution on -// the given endpoint. Note that this requires that one knows the tail -// of the endpoint's TD queue -void usb_endpoint_append_td( - const usb_endpoint_t* const endpoint, - usb_transfer_descriptor_t* const tail_td, - usb_transfer_descriptor_t* const new_td -) { - const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address); - bool done; - - tail_td->next_dtd_pointer = new_td; - - do { - if( usb_endpoint_is_in(endpoint->address) ) { - if (USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number) ) - return; - } else { - if (USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number) ) - return; - } - - USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW; - done = usb_endpoint_is_ready(endpoint); - } while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW)); - - USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW; - if(!done) { - usb_endpoint_prime(endpoint, new_td); - } -} - -/* static bool usb_endpoint_is_priming( const usb_endpoint_t* const endpoint ) { @@ -239,11 +200,57 @@ static bool usb_endpoint_is_priming( return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number); } } -*/ + +// Schedule an already filled-in transfer descriptor for execution on +// the given endpoint, waiting until the endpoint has finished. +void usb_endpoint_schedule_wait( + const usb_endpoint_t* const endpoint, + usb_transfer_descriptor_t* const td +) { + // Ensure that endpoint is ready to be primed. + // It may have been flushed due to an aborted transaction. + // TODO: This should be preceded by a flush? + while( usb_endpoint_is_ready(endpoint) ); + + td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; + + usb_endpoint_prime(endpoint, td); +} + +// Schedule an already filled-in transfer descriptor for execution on +// the given endpoint, appending to the end of the endpoint's queue if +// there are pending TDs. Note that this requires that one knows the +// tail of the endpoint's TD queue. Moreover, the user is responsible +// for setting the TERMINATE bit of next_dtd_pointer if needed. +void usb_endpoint_schedule_append( + const usb_endpoint_t* const endpoint, + usb_transfer_descriptor_t* const tail_td, + usb_transfer_descriptor_t* const new_td +) { + bool done; + + tail_td->next_dtd_pointer = new_td; + + if (usb_endpoint_is_priming(endpoint)) { + return; + } + + do { + USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW; + done = usb_endpoint_is_ready(endpoint); + } while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW)); + + USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW; + if(!done) { + usb_endpoint_prime(endpoint, new_td); + } +} + void usb_endpoint_flush( const usb_endpoint_t* const endpoint ) { const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address); + usb_queue_flush_endpoint(endpoint); if( usb_endpoint_is_in(endpoint->address) ) { usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FETB(1 << endpoint_number)); } else { @@ -543,48 +550,13 @@ void usb_endpoint_init( usb_endpoint_enable(endpoint); } -void usb_endpoint_schedule( - const usb_endpoint_t* const endpoint, - void* const data, - const uint32_t maximum_length -) { - usb_transfer_descriptor_t* const td = usb_transfer_descriptor(endpoint->address); - - // Ensure that endpoint is ready to be primed. - // It may have been flushed due to an aborted transaction. - // TODO: This should be preceded by a flush? - while( usb_endpoint_is_ready(endpoint) ); - - // Configure a transfer. - td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; - td->total_bytes = - USB_TD_DTD_TOKEN_TOTAL_BYTES(maximum_length) - | USB_TD_DTD_TOKEN_IOC - | USB_TD_DTD_TOKEN_MULTO(0) - | USB_TD_DTD_TOKEN_STATUS_ACTIVE - ; - td->buffer_pointer_page[0] = (uint32_t)data; - td->buffer_pointer_page[1] = ((uint32_t)data + 0x1000) & 0xfffff000; - td->buffer_pointer_page[2] = ((uint32_t)data + 0x2000) & 0xfffff000; - td->buffer_pointer_page[3] = ((uint32_t)data + 0x3000) & 0xfffff000; - td->buffer_pointer_page[4] = ((uint32_t)data + 0x4000) & 0xfffff000; - - usb_endpoint_prime(endpoint, td); -} - -void usb_endpoint_schedule_ack( - const usb_endpoint_t* const endpoint -) { - usb_endpoint_schedule(endpoint, 0, 0); -} - static void usb_check_for_setup_events() { const uint32_t endptsetupstat = usb_get_endpoint_setup_status(); if( endptsetupstat ) { for( uint_fast8_t i=0; i<6; i++ ) { const uint32_t endptsetupstat_bit = USB0_ENDPTSETUPSTAT_ENDPTSETUPSTAT(1 << i); if( endptsetupstat & endptsetupstat_bit ) { - usb_endpoint_t* const endpoint = + usb_endpoint_t* const endpoint = usb_endpoint_from_address( usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i) ); diff --git a/firmware/hackrf_usb/usb.h b/firmware/hackrf_usb/usb.h index 94372e0c..a6fa6a92 100644 --- a/firmware/hackrf_usb/usb.h +++ b/firmware/hackrf_usb/usb.h @@ -61,16 +61,6 @@ void usb_endpoint_init( const usb_endpoint_t* const endpoint ); -void usb_endpoint_schedule( - const usb_endpoint_t* const endpoint, - void* const data, - const uint32_t maximum_length -); - -void usb_endpoint_schedule_ack( - const usb_endpoint_t* const endpoint -); - void usb_endpoint_stall( const usb_endpoint_t* const endpoint ); @@ -92,7 +82,12 @@ void usb_endpoint_prime( usb_transfer_descriptor_t* const first_td ); -void usb_endpoint_append_td( +void usb_endpoint_schedule_wait( + const usb_endpoint_t* const endpoint, + usb_transfer_descriptor_t* const td +); + +void usb_endpoint_schedule_append( const usb_endpoint_t* const endpoint, usb_transfer_descriptor_t* const tail_td, usb_transfer_descriptor_t* const new_td diff --git a/firmware/hackrf_usb/usb_request.c b/firmware/hackrf_usb/usb_request.c index 25132fd4..f9226c7f 100644 --- a/firmware/hackrf_usb/usb_request.c +++ b/firmware/hackrf_usb/usb_request.c @@ -21,6 +21,7 @@ #include "usb.h" #include "usb_request.h" +#include "usb_queue.h" #include @@ -75,6 +76,7 @@ void usb_control_out_complete( } else { usb_request(endpoint, USB_TRANSFER_STAGE_DATA); } + usb_queue_transfer_complete(endpoint); } void usb_control_in_complete( @@ -87,5 +89,6 @@ void usb_control_in_complete( } else { usb_request(endpoint, USB_TRANSFER_STAGE_STATUS); } + usb_queue_transfer_complete(endpoint); } diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index cfb58ee0..6f589b3c 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -27,6 +27,7 @@ #include "usb.h" #include "usb_type.h" #include "usb_descriptor.h" +#include "usb_queue.h" const uint8_t* usb_endpoint_descriptor( const usb_endpoint_t* const endpoint @@ -99,9 +100,11 @@ bool usb_set_configuration( if( new_configuration != device->configuration ) { // Configuration changed. device->configuration = new_configuration; - if (usb_configuration_changed_cb) - usb_configuration_changed_cb(device); } + + if (usb_configuration_changed_cb) + usb_configuration_changed_cb(device); + return true; } @@ -114,12 +117,13 @@ static usb_request_status_t usb_send_descriptor( if( descriptor_data[1] == USB_DESCRIPTOR_TYPE_CONFIGURATION ) { descriptor_length = (descriptor_data[3] << 8) | descriptor_data[2]; } - usb_endpoint_schedule( + usb_transfer_schedule_block( endpoint->in, descriptor_data, - (setup_length > descriptor_length) ? descriptor_length : setup_length + (setup_length > descriptor_length) ? descriptor_length : setup_length, + NULL, NULL ); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } @@ -195,7 +199,7 @@ static usb_request_status_t usb_standard_request_set_address_setup( usb_endpoint_t* const endpoint ) { usb_set_address_deferred(endpoint->device, endpoint->setup.value_l); - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } @@ -231,7 +235,7 @@ static usb_request_status_t usb_standard_request_set_configuration_setup( // TODO: Should this be done immediately? usb_set_address_immediate(endpoint->device, 0); } - usb_endpoint_schedule_ack(endpoint->in); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } else { return USB_REQUEST_STATUS_STALL; @@ -265,8 +269,8 @@ static usb_request_status_t usb_standard_request_get_configuration_setup( if( endpoint->device->configuration ) { endpoint->buffer[0] = endpoint->device->configuration->number; } - usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } else { return USB_REQUEST_STATUS_STALL; diff --git a/firmware/libopencm3 b/firmware/libopencm3 index d7fdcefb..f04d6dd8 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit d7fdcefbd7565e59aaaf2dea99bee8e0157ff1d7 +Subproject commit f04d6dd82bf3cf89f55c3a85c4384d9375c34469 From 34fabad121a30c476e64c5cd6588cf55660bfe14 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 22:28:40 -0400 Subject: [PATCH 07/16] usb_standard_request: Sent descriptors can be const --- firmware/hackrf_usb/usb_standard_request.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index 6f589b3c..e6fd8974 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -110,16 +110,17 @@ bool usb_set_configuration( static usb_request_status_t usb_send_descriptor( usb_endpoint_t* const endpoint, - uint8_t* const descriptor_data + const uint8_t* const descriptor_data ) { const uint32_t setup_length = endpoint->setup.length; uint32_t descriptor_length = descriptor_data[0]; if( descriptor_data[1] == USB_DESCRIPTOR_TYPE_CONFIGURATION ) { descriptor_length = (descriptor_data[3] << 8) | descriptor_data[2]; } + // We cast the const away but this shouldn't be a problem as this is a write transfer usb_transfer_schedule_block( endpoint->in, - descriptor_data, + (uint8_t* const) descriptor_data, (setup_length > descriptor_length) ? descriptor_length : setup_length, NULL, NULL ); From 8e897be9757aed03aafca3ef566b500fe4d2c836 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 22:29:56 -0400 Subject: [PATCH 08/16] usb_standard_request: Multiple config support GET_DESCRIPTOR would only return one configurations. This fixes that. --- firmware/hackrf_usb/usb_standard_request.c | 27 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index e6fd8974..fafc5c55 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -141,6 +141,25 @@ static usb_request_status_t usb_send_descriptor_string( return USB_REQUEST_STATUS_STALL; } +static usb_request_status_t usb_send_descriptor_config( + usb_endpoint_t* const endpoint, + usb_speed_t speed, + const uint8_t config_num +) { + usb_configuration_t** config = *(endpoint->device->configurations); + unsigned int i = 0; + for( ; *config != NULL; config++ ) { + if( (*config)->speed == speed) { + if (i == config_num) { + return usb_send_descriptor(endpoint, (*config)->descriptor); + } else { + i++; + } + } + } + return USB_REQUEST_STATUS_STALL; +} + static usb_request_status_t usb_standard_request_get_descriptor_setup( usb_endpoint_t* const endpoint ) { @@ -151,9 +170,9 @@ static usb_request_status_t usb_standard_request_get_descriptor_setup( case USB_DESCRIPTOR_TYPE_CONFIGURATION: // TODO: Duplicated code. Refactor. if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) { - return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); + return usb_send_descriptor_config(endpoint, USB_SPEED_HIGH, endpoint->setup.value_l); } else { - return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); + return usb_send_descriptor_config(endpoint, USB_SPEED_FULL, endpoint->setup.value_l); } case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: @@ -162,9 +181,9 @@ static usb_request_status_t usb_standard_request_get_descriptor_setup( case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION: // TODO: Duplicated code. Refactor. if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) { - return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); + return usb_send_descriptor_config(endpoint, USB_SPEED_FULL, endpoint->setup.value_l); } else { - return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); + return usb_send_descriptor_config(endpoint, USB_SPEED_HIGH, endpoint->setup.value_l); } case USB_DESCRIPTOR_TYPE_STRING: From d2b2b1199840aeac3ac75cf809872d55d1591456 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 9 Jul 2013 19:05:00 -0400 Subject: [PATCH 09/16] xapp058/ports: Clean up comments and dead code It's still not pretty but it's an improvement --- firmware/common/xapp058/ports.c | 143 -------------------------------- 1 file changed, 143 deletions(-) diff --git a/firmware/common/xapp058/ports.c b/firmware/common/xapp058/ports.c index 3c7c6e44..029ee0ca 100644 --- a/firmware/common/xapp058/ports.c +++ b/firmware/common/xapp058/ports.c @@ -10,18 +10,11 @@ /* Add print in setPort for xapp058_example.exe.*/ /*******************************************************/ #include "ports.h" -/*#include "prgispx.h"*/ -//#include "stdio.h" #include "hackrf_core.h" #include "cpld_jtag.h" #include -//extern FILE *in; -//static int g_iTCK = 0; /* For xapp058_example .exe */ -//static int g_iTMS = 0; /* For xapp058_example .exe */ -//static int g_iTDI = 0; /* For xapp058_example .exe */ - void delay_jtag(uint32_t duration) { #define DIVISOR (1024) @@ -43,94 +36,10 @@ void delay_jtag(uint32_t duration) __asm__("nop"); } - -#ifdef WIN95PP -#include "conio.h" - -#define DATA_OFFSET (unsigned short) 0 -#define STATUS_OFFSET (unsigned short) 1 -#define CONTROL_OFFSET (unsigned short) 2 - -typedef union outPortUnion { - unsigned char value; - struct opBitsStr { - unsigned char tdi:1; - unsigned char tck:1; - unsigned char tms:1; - unsigned char zero:1; - unsigned char one:1; - unsigned char bit5:1; - unsigned char bit6:1; - unsigned char bit7:1; - } bits; -} outPortType; - -typedef union inPortUnion { - unsigned char value; - struct ipBitsStr { - unsigned char bit0:1; - unsigned char bit1:1; - unsigned char bit2:1; - unsigned char bit3:1; - unsigned char tdo:1; - unsigned char bit5:1; - unsigned char bit6:1; - unsigned char bit7:1; - } bits; -} inPortType; - -static inPortType in_word; -static outPortType out_word; -static unsigned short base_port = 0x378; -static int once = 0; -#endif - - -/*BYTE *xsvf_data=0;*/ - - /* setPort: Implement to set the named JTAG signal (p) to the new value (v).*/ /* if in debugging mode, then just set the variables */ void setPort(short p,short val) { -#ifdef WIN95PP - /* Old Win95 example that is similar to a GPIO register implementation. - The old Win95 example maps individual bits of the - 8-bit register (out_word) to the JTAG signals: TCK, TMS, TDI. - */ - - /* Initialize static out_word register bits just once */ - if (once == 0) { - out_word.bits.one = 1; - out_word.bits.zero = 0; - once = 1; - } - - /* Update the local out_word copy of the JTAG signal to the new value. */ - if (p==TMS) - out_word.bits.tms = (unsigned char) val; - if (p==TDI) - out_word.bits.tdi = (unsigned char) val; - if (p==TCK) { - out_word.bits.tck = (unsigned char) val; - (void) _outp( (unsigned short) (base_port + 0), out_word.value ); - /* To save HW write cycles, this example only writes the local copy - of the JTAG signal values to the HW register when TCK changes. */ - } -#endif - /* Printing code for the xapp058_example.exe. You must set the specified - JTAG signal (p) to the new value (v). See the above, old Win95 code - as an implementation example. */ -/* - if (p==TMS) - g_iTMS = val; - if (p==TDI) - g_iTDI = val; - if (p==TCK) { - g_iTCK = val; - printf( "TCK = %d; TMS = %d; TDI = %d\n", g_iTCK, g_iTMS, g_iTDI ); - } -*/ if (p==TMS) { if (val) gpio_set(PORT_CPLD_TMS, PIN_CPLD_TMS); @@ -167,9 +76,6 @@ void pulseClock() /* read in a byte of data from the prom */ void readByte(unsigned char *data) { - /* pretend reading using a file */ - //*data = (unsigned char)fgetc( in ); - /**data=*xsvf_data++;*/ *data = cpld_jtag_get_next_byte(); } @@ -177,20 +83,6 @@ void readByte(unsigned char *data) /* read the TDO bit from port */ unsigned char readTDOBit() { -#ifdef WIN95PP - /* Old Win95 example that is similar to a GPIO register implementation. - The old Win95 reads the hardware input register and extracts the TDO - value from the bit within the register that is assigned to the - physical JTAG TDO signal. - */ - in_word.value = (unsigned char) _inp( (unsigned short) (base_port + STATUS_OFFSET) ); - if (in_word.bits.tdo == 0x1) { - return( (unsigned char) 1 ); - } -#endif - /* You must return the current value of the JTAG TDO signal. */ - //return( (unsigned char) 0 ); - delay_jtag(2000); return CPLD_TDO_STATE; } @@ -218,39 +110,4 @@ void waitTime(long microsec) { pulseClock(); } - -#if 0 - /* Alternate implementation */ - /* For systems with TCK rates << 1 MHz; Consider this implementation. */ - /* This implementation does not work with Spartan-3AN or indirect flash - programming. */ - if ( microsec >= 50L ) - { - /* Make sure TCK is low during wait for XC18V00/XCFxxS */ - /* Or, a running TCK implementation as shown above is an OK alternate */ - setPort( TCK, 0 ); - - /* Use Windows Sleep(). Round up to the nearest millisec */ - _sleep( ( microsec + 999L ) / 1000L ); - } - else /* Satisfy FPGA JTAG configuration, startup TCK cycles */ - { - for ( i = 0; i < microsec; ++i ) - { - pulseClock(); - } - } -#endif - -#if 0 - /* Alternate implementation */ - /* This implementation is valid for only XC9500/XL/XV, CoolRunner/II CPLDs, - XC18V00 PROMs, or Platform Flash XCFxxS/XCFxxP PROMs. - This implementation does not work with FPGAs JTAG configuration. */ - /* Make sure TCK is low during wait for XC18V00/XCFxxS PROMs */ - /* Or, a running TCK implementation as shown above is an OK alternate */ - setPort( TCK, 0 ); - /* Use Windows Sleep(). Round up to the nearest millisec */ - _sleep( ( microsec + 999L ) / 1000L ); -#endif } From dc9c6c9667388b04ec126f5ccd58cb93007df6d1 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 2 Sep 2013 19:44:22 -0400 Subject: [PATCH 10/16] cpld: Stream CPLD data from host Previously CPLD programming involved a large 64kbyte buffer into which the the entire bitstream would be completely downloaded, and at which point the programming process would commence. This is needlessly wasteful of memory. Moreover, it could lead to USB timeouts as the firmware needs to wait the entire duration of the programming process before returning an ACK to the host after the final SETUP data phase packet. Instead, we now receive 512 byte chunks of the bitstream and stream them to the CPLD one at a time. We wait for each packet to be streamed out to the CPLD before ACKing the packet to prevent active data being overwritten. --- firmware/common/cpld_jtag.c | 28 +++-- firmware/common/cpld_jtag.h | 15 ++- firmware/hackrf_usb/hackrf_usb.c | 149 ++++++++++++++------------- firmware/hackrf_usb/usb_descriptor.c | 95 ++++++++++++++++- firmware/hackrf_usb/usb_descriptor.h | 2 + 5 files changed, 205 insertions(+), 84 deletions(-) diff --git a/firmware/common/cpld_jtag.c b/firmware/common/cpld_jtag.c index ddeb13d9..50430fee 100644 --- a/firmware/common/cpld_jtag.c +++ b/firmware/common/cpld_jtag.c @@ -26,8 +26,9 @@ #include #include -uint32_t xsvf_len; -unsigned char* xsvf_data; +static refill_buffer_cb refill_buffer; +static uint32_t xsvf_buffer_len, xsvf_pos; +static unsigned char* xsvf_buffer; void cpld_jtag_setup(void) { scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); @@ -58,11 +59,16 @@ void cpld_jtag_release(void) { } /* return 0 if success else return error code see xsvfExecute() */ -int cpld_jtag_program(const uint32_t len, unsigned char* const data) { +int cpld_jtag_program( + const uint32_t buffer_length, + unsigned char* const buffer, + refill_buffer_cb refill +) { int error; cpld_jtag_setup(); - xsvf_data = data; - xsvf_len = len; + xsvf_buffer = buffer; + xsvf_buffer_len = buffer_length; + refill_buffer = refill; error = xsvfExecute(); cpld_jtag_release(); @@ -71,12 +77,12 @@ int cpld_jtag_program(const uint32_t len, unsigned char* const data) { /* this gets called by the XAPP058 code */ unsigned char cpld_jtag_get_next_byte(void) { - unsigned char byte = *xsvf_data; - - if (xsvf_len > 1) { - xsvf_data++; - xsvf_len--; - } + if (xsvf_pos == xsvf_buffer_len) { + refill_buffer(); + xsvf_pos = 0; + } + unsigned char byte = xsvf_buffer[xsvf_pos]; + xsvf_pos++; return byte; } diff --git a/firmware/common/cpld_jtag.h b/firmware/common/cpld_jtag.h index ed42d782..56f55a2a 100644 --- a/firmware/common/cpld_jtag.h +++ b/firmware/common/cpld_jtag.h @@ -24,9 +24,20 @@ #include +typedef void (*refill_buffer_cb)(void); + void cpld_jtag_release(void); -/* return 0 if success else return error code see xsvfExecute() see micro.h */ -int cpld_jtag_program(const uint32_t len, unsigned char* const data); + +/* Return 0 if success else return error code see xsvfExecute() see micro.h. + * + * We expect the buffer to be initially full of data. After the entire + * contents of the buffer has been streamed to the CPLD the given + * refill_buffer callback will be called. */ +int cpld_jtag_program( + const uint32_t buffer_length, + unsigned char* const buffer, + refill_buffer_cb refill +); unsigned char cpld_jtag_get_next_byte(void); #endif//__CPLD_JTAG_H__ diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index f077a014..2a14b5e8 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -50,10 +50,11 @@ uint8_t* const usb_bulk_buffer = (uint8_t*)0x20004000; static volatile uint32_t usb_bulk_buffer_offset = 0; static const uint32_t usb_bulk_buffer_mask = 32768 - 1; -/* TODO remove this big buffer and use streaming for CPLD */ -#define CPLD_XSVF_MAX_LEN (65536) -uint8_t cpld_xsvf_buffer[CPLD_XSVF_MAX_LEN]; -uint16_t write_cpld_idx = 0; +usb_transfer_descriptor_t usb_td_bulk[2] ATTR_ALIGNED(64); +const uint_fast8_t usb_td_bulk_count = sizeof(usb_td_bulk) / sizeof(usb_td_bulk[0]); + +uint8_t cpld_xsvf_buffer[512]; +volatile bool cpld_wait = false; uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN]; char version_string[] = VERSION_STRING; @@ -191,9 +192,23 @@ usb_configuration_t usb_configuration_full_speed = { .descriptor = usb_descriptor_configuration_full_speed, }; +usb_configuration_t usb_configuration_cpld_update_full_speed = { + .number = 2, + .speed = USB_SPEED_FULL, + .descriptor = usb_descriptor_configuration_cpld_update_full_speed, +}; + +usb_configuration_t usb_configuration_cpld_update_high_speed = { + .number = 2, + .speed = USB_SPEED_HIGH, + .descriptor = usb_descriptor_configuration_cpld_update_high_speed, +}; + usb_configuration_t* usb_configurations[] = { &usb_configuration_high_speed, &usb_configuration_full_speed, + &usb_configuration_cpld_update_full_speed, + &usb_configuration_cpld_update_high_speed, 0, }; @@ -549,69 +564,6 @@ usb_request_status_t usb_vendor_request_read_spiflash( } } -usb_request_status_t usb_vendor_request_write_cpld( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage) -{ - int error, i; - uint16_t total_len; - uint16_t len; - #define WAIT_LOOP_DELAY (6000000) - #define ALL_LEDS (PIN_LED1|PIN_LED2|PIN_LED3) - - if (stage == USB_TRANSFER_STAGE_SETUP) - { - // len is limited to 64KB 16bits no overflow can happen - total_len = endpoint->setup.value; - len = endpoint->setup.length; - usb_transfer_schedule_block(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len, - NULL, NULL); - return USB_REQUEST_STATUS_OK; - } else if (stage == USB_TRANSFER_STAGE_DATA) - { - // len is limited to 64KB 16bits no overflow can happen - total_len = endpoint->setup.value; - len = endpoint->setup.length; - write_cpld_idx = write_cpld_idx + len; - // Check if all bytes received and write CPLD - if(write_cpld_idx == total_len) - { - write_cpld_idx = 0; - error = cpld_jtag_program(total_len, &cpld_xsvf_buffer[write_cpld_idx]); - // TO FIX ACK shall be not delayed so much as cpld prog can take up to 5s. - if(error == 0) - { - usb_transfer_schedule_ack(endpoint->in); - - /* blink LED1, LED2, and LED3 on success */ - while (1) - { - gpio_set(PORT_LED1_3, ALL_LEDS); /* LEDs on */ - for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ - __asm__("nop"); - gpio_clear(PORT_LED1_3, ALL_LEDS); /* LEDs off */ - for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ - __asm__("nop"); - } - return USB_REQUEST_STATUS_OK; - }else - { - /* LED3 (Red) steady on error */ - gpio_set(PORT_LED1_3, PIN_LED3); /* LEDs on */ - while (1); - return USB_REQUEST_STATUS_STALL; - } - }else - { - usb_transfer_schedule_ack(endpoint->in); - return USB_REQUEST_STATUS_OK; - } - } else - { - return USB_REQUEST_STATUS_OK; - } -} - usb_request_status_t usb_vendor_request_read_board_id( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { @@ -815,7 +767,7 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_erase_spiflash, usb_vendor_request_write_spiflash, usb_vendor_request_read_spiflash, - usb_vendor_request_write_cpld, + NULL, // used to be write_cpld usb_vendor_request_read_board_id, usb_vendor_request_read_version_string, usb_vendor_request_set_freq, @@ -853,13 +805,72 @@ const usb_request_handlers_t usb_request_handlers = { .reserved = 0, }; +static void cpld_buffer_refilled(void* user_data, unsigned int length) +{ + cpld_wait = false; +} + +static void refill_cpld_buffer(void) +{ + cpld_wait = true; + usb_transfer_schedule( + &usb_endpoint_bulk_out, + cpld_xsvf_buffer, + sizeof(cpld_xsvf_buffer), + cpld_buffer_refilled, + NULL + ); + + // Wait until transfer finishes + while (cpld_wait); +} + +static void cpld_update(void) +{ + #define WAIT_LOOP_DELAY (6000000) + #define ALL_LEDS (PIN_LED1|PIN_LED2|PIN_LED3) + int i; + int error; + + usb_queue_flush_endpoint(&usb_endpoint_bulk_in); + usb_queue_flush_endpoint(&usb_endpoint_bulk_out); + + refill_cpld_buffer(); + + error = cpld_jtag_program(sizeof(cpld_xsvf_buffer), + cpld_xsvf_buffer, + refill_cpld_buffer); + if(error == 0) + { + /* blink LED1, LED2, and LED3 on success */ + while (1) + { + gpio_set(PORT_LED1_3, ALL_LEDS); /* LEDs on */ + for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ + __asm__("nop"); + gpio_clear(PORT_LED1_3, ALL_LEDS); /* LEDs off */ + for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ + __asm__("nop"); + } + }else + { + /* LED3 (Red) steady on error */ + gpio_set(PORT_LED1_3, PIN_LED3); /* LEDs on */ + while (1); + } +} + void usb_configuration_changed( usb_device_t* const device ) { set_transceiver_mode(transceiver_mode); - if( device->configuration->number ) { + if( device->configuration->number == 1 ) { + // transceiver mode gpio_set(PORT_LED1_3, PIN_LED1); + } else if( device->configuration->number == 2 ) { + // CPLD update mode + cpld_update(); } else { gpio_clear(PORT_LED1_3, PIN_LED1); } diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index c9f26ce7..d97e1973 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -51,7 +51,7 @@ uint8_t usb_descriptor_device[] = { 0x01, // iManufacturer 0x02, // iProduct 0x00, // iSerialNumber - 0x01 // bNumConfigurations + 0x02 // bNumConfigurations }; uint8_t usb_descriptor_device_qualifier[] = { @@ -62,7 +62,7 @@ uint8_t usb_descriptor_device_qualifier[] = { 0x00, // bDeviceSubClass 0x00, // bDeviceProtocol 64, // bMaxPacketSize0 - 0x01, // bNumOtherSpeedConfigurations + 0x02, // bNumOtherSpeedConfigurations 0x00 // bReserved }; @@ -140,6 +140,80 @@ uint8_t usb_descriptor_configuration_high_speed[] = { 0, // TERMINATOR }; +uint8_t usb_descriptor_configuration_cpld_update_full_speed[] = { + 9, // bLength + USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType + USB_WORD(32), // wTotalLength + 0x01, // bNumInterfaces + 0x02, // bConfigurationValue + 0x04, // iConfiguration + 0x80, // bmAttributes: USB-powered + 250, // bMaxPower: 500mA + + 9, // bLength + USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0xFF, // bInterfaceClass: vendor-specific + 0xFF, // bInterfaceSubClass + 0xFF, // bInterfaceProtocol: vendor-specific + 0x00, // iInterface + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_IN_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_OUT_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 0, // TERMINATOR +}; + +uint8_t usb_descriptor_configuration_cpld_update_high_speed[] = { + 9, // bLength + USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType + USB_WORD(32), // wTotalLength + 0x01, // bNumInterfaces + 0x02, // bConfigurationValue + 0x04, // iConfiguration + 0x80, // bmAttributes: USB-powered + 250, // bMaxPower: 500mA + + 9, // bLength + USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0xFF, // bInterfaceClass: vendor-specific + 0xFF, // bInterfaceSubClass + 0xFF, // bInterfaceProtocol: vendor-specific + 0x00, // iInterface + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_IN_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_OUT_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 0, // TERMINATOR +}; + uint8_t usb_descriptor_string_languages[] = { 0x04, // bLength USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType @@ -197,11 +271,28 @@ uint8_t usb_descriptor_string_config1_description[] = { 'r', 0x00, }; +uint8_t usb_descriptor_string_config2_description[] = { + 24, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + 'C', 0x00, + 'P', 0x00, + 'L', 0x00, + 'D', 0x00, + ' ', 0x00, + 'u', 0x00, + 'p', 0x00, + 'd', 0x00, + 'a', 0x00, + 't', 0x00, + 'e', 0x00, +}; + uint8_t* const usb_descriptor_strings[] = { usb_descriptor_string_languages, usb_descriptor_string_manufacturer, usb_descriptor_string_product, usb_descriptor_string_config1_description, + usb_descriptor_string_config2_description, 0, // TERMINATOR }; diff --git a/firmware/hackrf_usb/usb_descriptor.h b/firmware/hackrf_usb/usb_descriptor.h index a1676f04..11e274a7 100644 --- a/firmware/hackrf_usb/usb_descriptor.h +++ b/firmware/hackrf_usb/usb_descriptor.h @@ -25,6 +25,8 @@ extern uint8_t usb_descriptor_device[]; extern uint8_t usb_descriptor_device_qualifier[]; extern uint8_t usb_descriptor_configuration_full_speed[]; extern uint8_t usb_descriptor_configuration_high_speed[]; +extern uint8_t usb_descriptor_configuration_cpld_update_full_speed[]; +extern uint8_t usb_descriptor_configuration_cpld_update_high_speed[]; extern uint8_t usb_descriptor_string_languages[]; extern uint8_t usb_descriptor_string_manufacturer[]; extern uint8_t usb_descriptor_string_product[]; From 3ba8d33de897c222367b68de080ffdb9baaaa95f Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 23:47:18 -0400 Subject: [PATCH 11/16] hackrf: Enter cpld_update from main loop Otherwise we never respond to SET_CONFIGURATION --- firmware/hackrf_usb/hackrf_usb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 2a14b5e8..68b2b86d 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -53,6 +53,7 @@ static const uint32_t usb_bulk_buffer_mask = 32768 - 1; usb_transfer_descriptor_t usb_td_bulk[2] ATTR_ALIGNED(64); const uint_fast8_t usb_td_bulk_count = sizeof(usb_td_bulk) / sizeof(usb_td_bulk[0]); +static volatile bool start_cpld_update = false; uint8_t cpld_xsvf_buffer[512]; volatile bool cpld_wait = false; @@ -870,7 +871,7 @@ void usb_configuration_changed( gpio_set(PORT_LED1_3, PIN_LED1); } else if( device->configuration->number == 2 ) { // CPLD update mode - cpld_update(); + start_cpld_update = true; } else { gpio_clear(PORT_LED1_3, PIN_LED1); } @@ -978,6 +979,10 @@ int main(void) { #endif while(true) { + // Check whether we need to initiate a CPLD update + if (start_cpld_update) + cpld_update(); + // Wait until buffer 0 is transmitted/received. while( usb_bulk_buffer_offset < 16384 ); From 64ef3f71c04644809731e07ae9d06e33c6a9d41f Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 9 Sep 2013 00:53:41 -0400 Subject: [PATCH 12/16] hackrf_usb: Make main loop non-blocking --- firmware/hackrf_usb/hackrf_usb.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 68b2b86d..1ba0b9be 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -978,16 +978,16 @@ int main(void) { switchctrl = SWITCHCTRL_AMP_BYPASS; #endif + unsigned int phase = 0; while(true) { // Check whether we need to initiate a CPLD update if (start_cpld_update) cpld_update(); - // Wait until buffer 0 is transmitted/received. - while( usb_bulk_buffer_offset < 16384 ); - // Set up IN transfer of buffer 0. - if (transceiver_mode != TRANSCEIVER_MODE_OFF) { + if ( usb_bulk_buffer_offset >= 16384 + && phase == 1 + && transceiver_mode != TRANSCEIVER_MODE_OFF) { usb_transfer_schedule_block( (transceiver_mode == TRANSCEIVER_MODE_RX) ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, @@ -995,13 +995,13 @@ int main(void) { 0x4000, NULL, NULL ); + phase = 0; } - // Wait until buffer 1 is transmitted/received. - while( usb_bulk_buffer_offset >= 16384 ); - // Set up IN transfer of buffer 1. - if (transceiver_mode != TRANSCEIVER_MODE_OFF) { + if ( usb_bulk_buffer_offset < 16384 + && phase == 0 + && transceiver_mode != TRANSCEIVER_MODE_OFF) { usb_transfer_schedule_block( (transceiver_mode == TRANSCEIVER_MODE_RX) ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, @@ -1009,6 +1009,7 @@ int main(void) { 0x4000, NULL, NULL ); + phase = 1; } } From 67a181ac365c8da3659b81c8f300020a5ba5d113 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 9 Sep 2013 00:54:24 -0400 Subject: [PATCH 13/16] hackrf_usb: Update transceiver_mode on all configuration changes --- firmware/hackrf_usb/hackrf_usb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 1ba0b9be..e7a487eb 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -864,15 +864,17 @@ static void cpld_update(void) void usb_configuration_changed( usb_device_t* const device ) { - set_transceiver_mode(transceiver_mode); - if( device->configuration->number == 1 ) { - // transceiver mode + // transceiver configuration + set_transceiver_mode(transceiver_mode); gpio_set(PORT_LED1_3, PIN_LED1); } else if( device->configuration->number == 2 ) { - // CPLD update mode + // CPLD update configuration + set_transceiver_mode(TRANSCEIVER_MODE_OFF); + usb_endpoint_init(&usb_endpoint_bulk_out); start_cpld_update = true; } else { + set_transceiver_mode(TRANSCEIVER_MODE_OFF); gpio_clear(PORT_LED1_3, PIN_LED1); } }; From d21d6165764feca4e20a2c61a4a94b5132a2b107 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 13:43:29 -0400 Subject: [PATCH 14/16] libhackrf: Rework hackrf_cpld_write to use new firmware interface We now use a separate USB configuration for CPLD updates. To avoid misuse of the interface, hackrf_cpld_write is now a one-shot call, expecting the entire CPLD buffer. The library will then take care that the device is placed in the CPLD update configuration and the entire buffer uploaded. Unfortunately, this means that users of the interface will have substantially fewer opportunities to provide status updates to the user. --- host/libhackrf/src/hackrf.c | 52 +++++++++++++++++++++++++------------ host/libhackrf/src/hackrf.h | 5 ++-- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 47ff055a..ea5596e4 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -55,7 +55,6 @@ typedef enum { HACKRF_VENDOR_REQUEST_SPIFLASH_ERASE = 10, HACKRF_VENDOR_REQUEST_SPIFLASH_WRITE = 11, HACKRF_VENDOR_REQUEST_SPIFLASH_READ = 12, - HACKRF_VENDOR_REQUEST_CPLD_WRITE = 13, HACKRF_VENDOR_REQUEST_BOARD_ID_READ = 14, HACKRF_VENDOR_REQUEST_VERSION_STRING_READ = 15, HACKRF_VENDOR_REQUEST_SET_FREQ = 16, @@ -632,25 +631,44 @@ int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address, } } -int ADDCALL hackrf_cpld_write(hackrf_device* device, const uint16_t length, - unsigned char* const data, const uint16_t total_length) +int ADDCALL hackrf_cpld_write(hackrf_device* device, + unsigned char* const data, const unsigned int total_length) { - int result = libusb_control_transfer( - device->usb_device, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, - HACKRF_VENDOR_REQUEST_CPLD_WRITE, - total_length, - 0, - data, - length, - 0 - ); - - if (result < length) { + int result = libusb_release_interface(device->usb_device, 0); + if (result != LIBUSB_SUCCESS) { return HACKRF_ERROR_LIBUSB; - } else { - return HACKRF_SUCCESS; } + + result = libusb_set_configuration(device->usb_device, 2); + if (result != LIBUSB_SUCCESS) { + return HACKRF_ERROR_LIBUSB; + } + + result = libusb_claim_interface(device->usb_device, 0); + if (result != LIBUSB_SUCCESS) { + return HACKRF_ERROR_LIBUSB; + } + + const unsigned int chunk_size = 512; + unsigned int i; + int transferred = 0; + for (i = 0; i < total_length; i += chunk_size) + { + result = libusb_bulk_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | 2, + &data[i], + chunk_size, + &transferred, + 10000 // long timeout to allow for CPLD programming + ); + + if (result != LIBUSB_SUCCESS) { + return HACKRF_ERROR_LIBUSB; + } + } + + return HACKRF_SUCCESS; } int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* value) diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 08317ec2..8c127839 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -121,8 +121,9 @@ extern ADDAPI int ADDCALL hackrf_spiflash_erase(hackrf_device* device); extern ADDAPI int ADDCALL hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* const data); extern ADDAPI int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* data); -extern ADDAPI int ADDCALL hackrf_cpld_write(hackrf_device* device, const uint16_t length, - unsigned char* const data, const uint16_t total_length); +/* device will need to be reset after hackrf_cpld_write */ +extern ADDAPI int ADDCALL hackrf_cpld_write(hackrf_device* device, + unsigned char* const data, const unsigned int total_length); extern ADDAPI int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* value); extern ADDAPI int ADDCALL hackrf_version_string_read(hackrf_device* device, char* version, uint8_t length); From b3f6134fc105703d142b15660783945f2eb3dc65 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 8 Sep 2013 13:46:03 -0400 Subject: [PATCH 15/16] hackrf_cpldjtag: Update for new hackrf_cpld_write interface --- host/hackrf-tools/src/hackrf_cpldjtag.c | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_cpldjtag.c b/host/hackrf-tools/src/hackrf_cpldjtag.c index fe3bce23..d032812b 100644 --- a/host/hackrf-tools/src/hackrf_cpldjtag.c +++ b/host/hackrf-tools/src/hackrf_cpldjtag.c @@ -93,8 +93,7 @@ int main(int argc, char** argv) int option_index = 0; FILE* fd = NULL; ssize_t bytes_read; - uint16_t xfer_len = 0; - uint8_t* pdata = &data[0]; + uint8_t* pdata = &data[0]; while ((opt = getopt_long(argc, argv, "x:", long_options, &option_index)) != EOF) { @@ -127,20 +126,20 @@ int main(int argc, char** argv) { fprintf(stderr, "Failed to open file: %s\n", path); return EXIT_FAILURE; - } + } /* Get size of the file */ fseek(fd, 0, SEEK_END); /* Not really portable but work on major OS Linux/Win32 */ length = ftell(fd); /* Move to start */ rewind(fd); - printf("File size %d bytes.\n", length); + printf("File size %d bytes.\n", length); if (length > MAX_XSVF_LENGTH) { fprintf(stderr, "XSVF file too large.\n"); usage(); return EXIT_FAILURE; } - + total_length = length; bytes_read = fread(data, 1, total_length, fd); if (bytes_read != total_length) @@ -168,27 +167,20 @@ int main(int argc, char** argv) printf("LED1/2/3 blinking means CPLD program success.\nLED3/RED steady means error.\n"); printf("Wait message 'Write finished' or in case of LED3/RED steady, Power OFF/Disconnect the Jawbreaker.\n"); - while( length ) + result = hackrf_cpld_write(device, pdata, total_length); + if (result != HACKRF_SUCCESS) { - xfer_len = (length > PACKET_LEN) ? PACKET_LEN : length; - result = hackrf_cpld_write(device, xfer_len, pdata, total_length); - if (result != HACKRF_SUCCESS) - { - fprintf(stderr, "hackrf_cpld_write() failed: %s (%d)\n", - hackrf_error_name(result), result); - fclose(fd); - fd = NULL; - return EXIT_FAILURE; - } - pdata += xfer_len; - length -= xfer_len; - printf("hackrf_cpld_write() Writing %d bytes, remaining %d bytes.\n", - xfer_len, length); + fprintf(stderr, "hackrf_cpld_write() failed: %s (%d)\n", + hackrf_error_name(result), result); + fclose(fd); + fd = NULL; + return EXIT_FAILURE; } + printf("Write finished.\n"); printf("Please Power OFF/Disconnect the Jawbreaker.\n"); fflush(stdout); - + result = hackrf_close(device); if( result != HACKRF_SUCCESS ) { From 4cd7662f7c98bfbc54df168003a657169d75be63 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 15 Sep 2013 18:29:33 -0400 Subject: [PATCH 16/16] hackrf_usb_rom_to_ram: Add usb_queue to Makefile --- firmware/hackrf_usb_rom_to_ram/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/hackrf_usb_rom_to_ram/Makefile b/firmware/hackrf_usb_rom_to_ram/Makefile index 0d2ea0e2..460d2f6c 100644 --- a/firmware/hackrf_usb_rom_to_ram/Makefile +++ b/firmware/hackrf_usb_rom_to_ram/Makefile @@ -29,6 +29,7 @@ SRC = hackrf_usb.c \ usb_request.c \ usb_standard_request.c \ usb_descriptor.c \ + usb_queue.c \ ../common/fault_handler.c \ ../common/hackrf_core.c \ ../common/sgpio.c \