From 6b05089700bdd19d081583bb75e55ff865f29efe Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Fri, 28 Jun 2013 21:30:46 -0400 Subject: [PATCH 01/67] 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 42b73919180eebbb5930eacfaaafc62bdc8a3dae Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Fri, 28 Jun 2013 21:53:59 -0400 Subject: [PATCH 02/67] usb: Begin shuffling transfer management to usb_queue --- firmware/hackrf_usb/Makefile | 1 + firmware/hackrf_usb/hackrf_usb.c | 1 + firmware/hackrf_usb/usb.c | 43 ------------- firmware/hackrf_usb/usb.h | 10 --- firmware/hackrf_usb/usb_queue.c | 71 ++++++++++++++++++++++ firmware/hackrf_usb/usb_queue.h | 46 ++++++++++++++ firmware/hackrf_usb/usb_standard_request.c | 1 + 7 files changed, 120 insertions(+), 53 deletions(-) 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/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index a175ea3d..439f88cf 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" diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 02fb81c3..0487ef43 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -34,10 +34,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 +43,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 ) { @@ -543,41 +535,6 @@ 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 ) { diff --git a/firmware/hackrf_usb/usb.h b/firmware/hackrf_usb/usb.h index 94372e0c..7d64f358 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 ); diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c new file mode 100644 index 00000000..8be95a22 --- /dev/null +++ b/firmware/hackrf_usb/usb_queue.c @@ -0,0 +1,71 @@ +/* + * 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 "usb.h" + +usb_transfer_descriptor_t usb_td[12] ATTR_ALIGNED(64); + +#define USB_TD_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1)) + +usb_transfer_descriptor_t* usb_transfer_descriptor( + const uint_fast8_t endpoint_address +) { + return &usb_td[USB_TD_INDEX(endpoint_address)]; +} + +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); +} diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h new file mode 100644 index 00000000..f07b8146 --- /dev/null +++ b/firmware/hackrf_usb/usb_queue.h @@ -0,0 +1,46 @@ +/* + * 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" + +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_schedule( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length +); + +#endif//__USB_QUEUE_H__ diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index cfb58ee0..59991ef1 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 From e6bf90af23548684e247e1e674898e3a0053978a Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 2 Jul 2013 19:31:51 -0400 Subject: [PATCH 03/67] usb: Shuffle endpoint_schedule into endpoint_schedule_wait --- firmware/hackrf_usb/usb.c | 28 ++++++++++++++++++++++++++++ firmware/hackrf_usb/usb_queue.c | 28 +++++----------------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 0487ef43..c057b5c3 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -188,6 +188,34 @@ void usb_endpoint_prime( } } +void usb_endpoint_schedule_wait( + const usb_endpoint_t* const endpoint, + usb_transfer_descriptor_t* const td, + void* const data, + const uint32_t maximum_length +) { + // 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); +} + // 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 diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 8be95a22..5792bcae 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -40,30 +40,12 @@ void usb_endpoint_schedule( 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); + usb_endpoint_schedule_wait(endpoint, + usb_transfer_descriptor(endpoint->address), + data, + maximum_length); } - + void usb_endpoint_schedule_ack( const usb_endpoint_t* const endpoint ) { From 6142c828df49eebf4db418cb963dad964f20ab3b Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 2 Jul 2013 22:39:26 -0400 Subject: [PATCH 04/67] usb: Refactor queue management --- firmware/hackrf_usb/usb.c | 27 ++-- firmware/hackrf_usb/usb.h | 7 +- firmware/hackrf_usb/usb_queue.c | 139 +++++++++++++++++++-- firmware/hackrf_usb/usb_queue.h | 22 +++- firmware/hackrf_usb/usb_standard_request.c | 12 +- 5 files changed, 166 insertions(+), 41 deletions(-) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index c057b5c3..14a94397 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -188,38 +188,27 @@ void usb_endpoint_prime( } } +// 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, - void* const data, - const uint32_t maximum_length + 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->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); } -// 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( +// 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 +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.h b/firmware/hackrf_usb/usb.h index 7d64f358..a6fa6a92 100644 --- a/firmware/hackrf_usb/usb.h +++ b/firmware/hackrf_usb/usb.h @@ -82,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_queue.c b/firmware/hackrf_usb/usb_queue.c index 5792bcae..0fc833d1 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -22,32 +22,145 @@ #include #include +#include #include "usb.h" +#include "usb_queue.h" -usb_transfer_descriptor_t usb_td[12] ATTR_ALIGNED(64); +struct _usb_transfer_t { + struct _usb_transfer_t* next; + usb_transfer_descriptor_t td ATTR_ALIGNED(64); + unsigned int actual_length; + usb_endpoint_t* endpoint; + bool finished; + transfer_completion_cb completion_cb; +}; -#define USB_TD_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1)) +usb_transfer_t transfer_pool[16]; -usb_transfer_descriptor_t* usb_transfer_descriptor( - const uint_fast8_t endpoint_address -) { - return &usb_td[USB_TD_INDEX(endpoint_address)]; +// Available transfer list +usb_transfer_t* free_transfers; + +#define USB_ENDPOINT_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1)) + +// Pending transfer heads +usb_transfer_t* endpoint_transfers[12] = {}; + +void init_transfers() { + usb_transfer_t* t = &transfer_pool[0]; + free_transfers = t; + for (unsigned int i=0; i < sizeof(transfer_pool) / sizeof(usb_transfer_t); i++, t++) { + t->next = t+1; + } + t->next = NULL; } -void usb_endpoint_schedule( +static bool usb_endpoint_is_in(const uint_fast8_t endpoint_address) { + return (endpoint_address & 0x80) ? true : false; +} + +#if 0 +static usb_transfer_t* usb_transfer( + const uint_fast8_t endpoint_address +) { + return endpoint_transfers[USB_ENDPOINT_INDEX(endpoint_address)]; +} +#endif + +static void fill_in_transfer(usb_transfer_t* transfer, + void* const data, + const uint32_t maximum_length +) { + usb_transfer_descriptor_t* const td = &transfer->td; + + // Configure a transfer. + 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; +} + +static usb_transfer_t* allocate_transfer() +{ + while (free_transfers == NULL); + //disable_irqs(); // FIXME + usb_transfer_t* const transfer = free_transfers; + free_transfers = transfer->next; + //enable_irqs(); + transfer->finished = false; + return transfer; +} + +static void endpoint_add_transfer( + const usb_endpoint_t* const endpoint, + usb_transfer_t* const transfer +) { + uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); + //FIXME disable_irqs(); + usb_transfer_t* t = endpoint_transfers[index]; + transfer->next = NULL; + for (; t->next != NULL; t = t->next); + t->next = transfer; + //enable_irqs(); +} + +static usb_transfer_t* endpoint_pop_transfer( + const usb_endpoint_t* const endpoint +) { + uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); + //FIXME disable_irqs(); + usb_transfer_t* transfer = endpoint_transfers[index]; + endpoint_transfers[index] = transfer->next; + //enable_irqs(); + return transfer; +} + +void usb_transfer_schedule_wait( const usb_endpoint_t* const endpoint, void* const data, const uint32_t maximum_length ) { - usb_endpoint_schedule_wait(endpoint, - usb_transfer_descriptor(endpoint->address), - data, - maximum_length); + usb_transfer_t* const transfer = allocate_transfer(); + fill_in_transfer(transfer, data, maximum_length); + endpoint_add_transfer(endpoint, transfer); + usb_endpoint_schedule_wait(endpoint, &transfer->td); +} + +void usb_transfer_schedule_append( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length +) { + usb_transfer_t* const transfer = allocate_transfer(); + uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); + fill_in_transfer(transfer, data, maximum_length); + // TODO: disable_interrupts(); + usb_transfer_t* tail = endpoint_transfers[index]; + for (; tail->next != NULL; tail = tail->next); + endpoint_add_transfer(endpoint, transfer); + usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); + //enable_interrupts(); } -void usb_endpoint_schedule_ack( +void usb_transfer_schedule_ack( const usb_endpoint_t* const endpoint ) { - usb_endpoint_schedule(endpoint, 0, 0); + usb_transfer_schedule_wait(endpoint, 0, 0); +} + +void transfer_complete(const usb_endpoint_t* const endpoint) +{ + usb_transfer_t* transfer = endpoint_pop_transfer(endpoint); + unsigned int transferred = transfer->actual_length - transfer->td.total_bytes; + if (transfer->completion_cb) + transfer->completion_cb(transfer, transferred); + else if (usb_endpoint_is_in(transfer->endpoint->address)) + transfer->finished = true; } diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index f07b8146..5e10b33e 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -27,20 +27,38 @@ #include "usb_type.h" +typedef struct _usb_transfer_t usb_transfer_t; + +typedef void (*transfer_completion_cb)(struct _usb_transfer_t*, unsigned int); + void usb_endpoint_schedule( const usb_endpoint_t* const endpoint, void* const data, const uint32_t maximum_length ); -void usb_endpoint_schedule_ack( +void usb_transfer_schedule_wait( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length +); + +void usb_transfer_schedule_append( + const usb_endpoint_t* const endpoint, + void* const data, + const uint32_t maximum_length +); + +void usb_transfer_schedule_ack( const usb_endpoint_t* const endpoint ); -void usb_endpoint_schedule( +void usb_transfer_schedule( const usb_endpoint_t* const endpoint, void* const data, const uint32_t maximum_length ); +void init_transfers(void); + #endif//__USB_QUEUE_H__ diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index 59991ef1..db9a0940 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -115,12 +115,12 @@ 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_wait( endpoint->in, descriptor_data, (setup_length > descriptor_length) ? descriptor_length : setup_length ); - usb_endpoint_schedule_ack(endpoint->out); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } @@ -196,7 +196,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; } @@ -232,7 +232,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; @@ -266,8 +266,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_wait(endpoint->in, &endpoint->buffer, 1); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } else { return USB_REQUEST_STATUS_STALL; From f015fd7640a204f90a22bd3c8792e7df004c9956 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 13:38:59 -0400 Subject: [PATCH 05/67] usb: Things enumerate --- firmware/hackrf_usb/usb_queue.c | 18 ++++++++++++------ firmware/hackrf_usb/usb_queue.h | 6 +++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 0fc833d1..ed0e4a6e 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "usb.h" #include "usb_queue.h" @@ -46,10 +47,10 @@ usb_transfer_t* free_transfers; // Pending transfer heads usb_transfer_t* endpoint_transfers[12] = {}; -void init_transfers() { +void usb_queue_init() { usb_transfer_t* t = &transfer_pool[0]; free_transfers = t; - for (unsigned int i=0; i < sizeof(transfer_pool) / sizeof(usb_transfer_t); i++, t++) { + for (unsigned int i=0; i < sizeof(transfer_pool) / sizeof(usb_transfer_t) - 1; i++, t++) { t->next = t+1; } t->next = NULL; @@ -104,10 +105,14 @@ static void endpoint_add_transfer( ) { uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); //FIXME disable_irqs(); - usb_transfer_t* t = endpoint_transfers[index]; transfer->next = NULL; - for (; t->next != NULL; t = t->next); - t->next = transfer; + if (endpoint_transfers[index] != NULL) { + usb_transfer_t* t = endpoint_transfers[index]; + for (; t->next != NULL; t = t->next); + t->next = transfer; + } else { + endpoint_transfers[index] = transfer; + } //enable_irqs(); } @@ -117,6 +122,7 @@ static usb_transfer_t* endpoint_pop_transfer( uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); //FIXME disable_irqs(); usb_transfer_t* transfer = endpoint_transfers[index]; + assert(transfer != NULL); endpoint_transfers[index] = transfer->next; //enable_irqs(); return transfer; @@ -155,7 +161,7 @@ void usb_transfer_schedule_ack( usb_transfer_schedule_wait(endpoint, 0, 0); } -void transfer_complete(const usb_endpoint_t* const endpoint) +void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) { usb_transfer_t* transfer = endpoint_pop_transfer(endpoint); unsigned int transferred = transfer->actual_length - transfer->td.total_bytes; diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index 5e10b33e..3963f15d 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -59,6 +59,10 @@ void usb_transfer_schedule( const uint32_t maximum_length ); -void init_transfers(void); +void usb_queue_init(void); + +void usb_queue_transfer_complete( + usb_endpoint_t* const endpoint +); #endif//__USB_QUEUE_H__ From bd4e39d3796ec49c68bb06b5fd41cfddc8f300b3 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 14:08:46 -0400 Subject: [PATCH 06/67] usb_queue: Add completion_cb arguments --- firmware/hackrf_usb/usb_queue.c | 10 +++++++--- firmware/hackrf_usb/usb_queue.h | 6 ++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index ed0e4a6e..91511885 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -131,10 +131,12 @@ static usb_transfer_t* endpoint_pop_transfer( void usb_transfer_schedule_wait( const usb_endpoint_t* const endpoint, void* const data, - const uint32_t maximum_length + const uint32_t maximum_length, + const transfer_completion_cb completion_cb ) { usb_transfer_t* const transfer = allocate_transfer(); fill_in_transfer(transfer, data, maximum_length); + transfer->completion_cb = completion_cb; endpoint_add_transfer(endpoint, transfer); usb_endpoint_schedule_wait(endpoint, &transfer->td); } @@ -142,11 +144,13 @@ void usb_transfer_schedule_wait( void usb_transfer_schedule_append( const usb_endpoint_t* const endpoint, void* const data, - const uint32_t maximum_length + const uint32_t maximum_length, + const transfer_completion_cb completion_cb ) { usb_transfer_t* const transfer = allocate_transfer(); uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); fill_in_transfer(transfer, data, maximum_length); + transfer->completion_cb = completion_cb; // TODO: disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; for (; tail->next != NULL; tail = tail->next); @@ -158,7 +162,7 @@ void usb_transfer_schedule_append( void usb_transfer_schedule_ack( const usb_endpoint_t* const endpoint ) { - usb_transfer_schedule_wait(endpoint, 0, 0); + usb_transfer_schedule_wait(endpoint, 0, 0, NULL); } void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index 3963f15d..cec51fb3 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -40,13 +40,15 @@ void usb_endpoint_schedule( void usb_transfer_schedule_wait( const usb_endpoint_t* const endpoint, void* const data, - const uint32_t maximum_length + const uint32_t maximum_length, + const transfer_completion_cb completion_cb ); void usb_transfer_schedule_append( const usb_endpoint_t* const endpoint, void* const data, - const uint32_t maximum_length + const uint32_t maximum_length, + const transfer_completion_cb completion_cb ); void usb_transfer_schedule_ack( From c62798d31fa4114c3ae23bb43d5496fe7b134abd Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 14:18:06 -0400 Subject: [PATCH 07/67] usb_queue: Kill old declaration --- firmware/hackrf_usb/usb_queue.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index cec51fb3..1498be46 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -55,12 +55,6 @@ void usb_transfer_schedule_ack( const usb_endpoint_t* const endpoint ); -void usb_transfer_schedule( - const usb_endpoint_t* const endpoint, - void* const data, - const uint32_t maximum_length -); - void usb_queue_init(void); void usb_queue_transfer_complete( From dfdfad2bf018d38aa092ba813f7bb2ade3b06fbb Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 14:18:28 -0400 Subject: [PATCH 08/67] hackrf_usb: Port to usb_queue --- firmware/hackrf_usb/hackrf_usb.c | 76 +++++++++++----------- firmware/hackrf_usb/usb_standard_request.c | 5 +- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 439f88cf..ff952b69 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -353,7 +353,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; @@ -371,7 +371,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; } } @@ -390,8 +390,8 @@ 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_wait(endpoint->in, &endpoint->buffer, 2, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -408,7 +408,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; } } @@ -426,8 +426,8 @@ 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_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -443,7 +443,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; @@ -461,7 +461,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; @@ -482,8 +482,8 @@ 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_wait(endpoint->in, &endpoint->buffer, 2, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_STALL; @@ -501,7 +501,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; @@ -522,7 +522,7 @@ 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_wait(endpoint->out, &spiflash_buffer[0], len, NULL); w25q80bv_setup(); return USB_REQUEST_STATUS_OK; } @@ -535,7 +535,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; } @@ -566,7 +566,7 @@ 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_wait(endpoint->in, &spiflash_buffer[0], len, NULL); return USB_REQUEST_STATUS_OK; } } else if (stage == USB_TRANSFER_STAGE_DATA) @@ -580,7 +580,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 @@ -604,7 +604,7 @@ 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_wait(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len, NULL); return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { @@ -620,7 +620,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) @@ -642,7 +642,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 @@ -656,8 +656,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_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; } @@ -669,8 +669,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_wait(endpoint->in, version_string, length, NULL); + usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; } @@ -681,13 +681,13 @@ 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_wait(endpoint->out, &set_freq_params, sizeof(set_freq_params_t), 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; @@ -703,13 +703,13 @@ 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_wait(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t), 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; @@ -727,12 +727,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; @@ -777,8 +777,8 @@ 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_wait(endpoint->in, &read_partid_serialno, length, NULL); + usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; } @@ -789,8 +789,8 @@ usb_request_status_t usb_vendor_request_set_lna_gain( 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_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; @@ -802,8 +802,8 @@ 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_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; @@ -815,8 +815,8 @@ 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_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; @@ -828,7 +828,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; } diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index db9a0940..78ae7f3d 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -118,7 +118,8 @@ static usb_request_status_t usb_send_descriptor( usb_transfer_schedule_wait( endpoint->in, descriptor_data, - (setup_length > descriptor_length) ? descriptor_length : setup_length + (setup_length > descriptor_length) ? descriptor_length : setup_length, + NULL ); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; @@ -266,7 +267,7 @@ static usb_request_status_t usb_standard_request_get_configuration_setup( if( endpoint->device->configuration ) { endpoint->buffer[0] = endpoint->device->configuration->number; } - usb_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1); + usb_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } else { From ac29621a36d87171b23d16551b188a31a6ee8b37 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 14:32:04 -0400 Subject: [PATCH 09/67] usb_queue: Use typedef --- firmware/hackrf_usb/usb_queue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index 1498be46..74a6323d 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -29,7 +29,7 @@ typedef struct _usb_transfer_t usb_transfer_t; -typedef void (*transfer_completion_cb)(struct _usb_transfer_t*, unsigned int); +typedef void (*transfer_completion_cb)(usb_transfer_t*, unsigned int); void usb_endpoint_schedule( const usb_endpoint_t* const endpoint, From ee46cf1fc42603a1ef0e9badd85f982e8a65297c Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 14:51:41 -0400 Subject: [PATCH 10/67] usb_queue: Cleanup --- firmware/hackrf_usb/usb_queue.c | 39 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 91511885..38d00f3e 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -31,9 +31,8 @@ struct _usb_transfer_t { struct _usb_transfer_t* next; usb_transfer_descriptor_t td ATTR_ALIGNED(64); - unsigned int actual_length; + unsigned int maximum_length; usb_endpoint_t* endpoint; - bool finished; transfer_completion_cb completion_cb; }; @@ -56,25 +55,13 @@ void usb_queue_init() { t->next = NULL; } -static bool usb_endpoint_is_in(const uint_fast8_t endpoint_address) { - return (endpoint_address & 0x80) ? true : false; -} - -#if 0 -static usb_transfer_t* usb_transfer( - const uint_fast8_t endpoint_address -) { - return endpoint_transfers[USB_ENDPOINT_INDEX(endpoint_address)]; -} -#endif - static void fill_in_transfer(usb_transfer_t* transfer, void* const data, const uint32_t maximum_length ) { usb_transfer_descriptor_t* const td = &transfer->td; - // Configure a transfer. + // Configure the transfer. descriptor td->total_bytes = USB_TD_DTD_TOKEN_TOTAL_BYTES(maximum_length) | USB_TD_DTD_TOKEN_IOC @@ -86,8 +73,11 @@ static void fill_in_transfer(usb_transfer_t* transfer, 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; + + transfer->maximum_length = maximum_length; } +/* Allocate a transfer */ static usb_transfer_t* allocate_transfer() { while (free_transfers == NULL); @@ -95,10 +85,19 @@ static usb_transfer_t* allocate_transfer() usb_transfer_t* const transfer = free_transfers; free_transfers = transfer->next; //enable_irqs(); - transfer->finished = false; return transfer; } +/* Place a transfer in the free list */ +static void free_transfer(usb_transfer_t* const transfer) +{ + //disable_irqs(); // FIXME + transfer->next = free_transfers; + free_transfers = transfer; + //enable_irqs(); +} + +/* Add a transfer to the end of an endpoint's queue */ static void endpoint_add_transfer( const usb_endpoint_t* const endpoint, usb_transfer_t* const transfer @@ -116,6 +115,7 @@ static void endpoint_add_transfer( //enable_irqs(); } +/* Pop off the transfer at the top of an endpoint's queue */ static usb_transfer_t* endpoint_pop_transfer( const usb_endpoint_t* const endpoint ) { @@ -162,15 +162,14 @@ void usb_transfer_schedule_append( void usb_transfer_schedule_ack( const usb_endpoint_t* const endpoint ) { - usb_transfer_schedule_wait(endpoint, 0, 0, NULL); + usb_transfer_schedule_wait(endpoint, 0, 0, NULL); } void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) { usb_transfer_t* transfer = endpoint_pop_transfer(endpoint); - unsigned int transferred = transfer->actual_length - transfer->td.total_bytes; + unsigned int transferred = transfer->maximum_length - transfer->td.total_bytes; if (transfer->completion_cb) transfer->completion_cb(transfer, transferred); - else if (usb_endpoint_is_in(transfer->endpoint->address)) - transfer->finished = true; + free_transfer(transfer); } From ccfdd8350d73d50c8733a7fe18da23a85628a125 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 14:51:50 -0400 Subject: [PATCH 11/67] usb_request: Ensure control endpoint transfers get freed --- firmware/hackrf_usb/usb_request.c | 3 +++ 1 file changed, 3 insertions(+) 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); } From ecd9b2e73169691391fb4d19bdcb41f92fa79eec Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 16:23:30 -0400 Subject: [PATCH 12/67] usb_queue: Kill usb_transfer_schedule_wait --- firmware/hackrf_usb/usb_queue.c | 27 +++++++++------------------ firmware/hackrf_usb/usb_queue.h | 9 +-------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 38d00f3e..0aa3a3c3 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -128,20 +128,7 @@ static usb_transfer_t* endpoint_pop_transfer( return transfer; } -void usb_transfer_schedule_wait( - const usb_endpoint_t* const endpoint, - void* const data, - const uint32_t maximum_length, - const transfer_completion_cb completion_cb -) { - usb_transfer_t* const transfer = allocate_transfer(); - fill_in_transfer(transfer, data, maximum_length); - transfer->completion_cb = completion_cb; - endpoint_add_transfer(endpoint, transfer); - usb_endpoint_schedule_wait(endpoint, &transfer->td); -} - -void usb_transfer_schedule_append( +void usb_transfer_schedule( const usb_endpoint_t* const endpoint, void* const data, const uint32_t maximum_length, @@ -153,16 +140,20 @@ void usb_transfer_schedule_append( transfer->completion_cb = completion_cb; // TODO: disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; - for (; tail->next != NULL; tail = tail->next); - endpoint_add_transfer(endpoint, transfer); - usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); + if (tail == NULL) { + usb_endpoint_schedule_wait(endpoint, &transfer->td); + } else { + for (; tail->next != NULL; tail = tail->next); + endpoint_add_transfer(endpoint, transfer); + usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); + } //enable_interrupts(); } void usb_transfer_schedule_ack( const usb_endpoint_t* const endpoint ) { - usb_transfer_schedule_wait(endpoint, 0, 0, NULL); + usb_transfer_schedule(endpoint, 0, 0, NULL); } void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index 74a6323d..f6dc0203 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -37,14 +37,7 @@ void usb_endpoint_schedule( const uint32_t maximum_length ); -void usb_transfer_schedule_wait( - const usb_endpoint_t* const endpoint, - void* const data, - const uint32_t maximum_length, - const transfer_completion_cb completion_cb -); - -void usb_transfer_schedule_append( +void usb_transfer_schedule( const usb_endpoint_t* const endpoint, void* const data, const uint32_t maximum_length, From 96f8621ad99238f06f33d1dbec06e95513f5cc66 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 16:25:17 -0400 Subject: [PATCH 13/67] hackrf_usb: Port things away from schedule_wait --- firmware/hackrf_usb/hackrf_usb.c | 28 +++++++++++----------- firmware/hackrf_usb/usb_standard_request.c | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index ff952b69..14d1722b 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -390,7 +390,7 @@ 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_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 2, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 2, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } @@ -426,7 +426,7 @@ 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_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } @@ -482,7 +482,7 @@ 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_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 2, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 2, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } @@ -522,7 +522,7 @@ usb_request_status_t usb_vendor_request_write_spiflash( || ((addr + len) > W25Q80BV_NUM_BYTES)) { return USB_REQUEST_STATUS_STALL; } else { - usb_transfer_schedule_wait(endpoint->out, &spiflash_buffer[0], len, NULL); + usb_transfer_schedule(endpoint->out, &spiflash_buffer[0], len, NULL); w25q80bv_setup(); return USB_REQUEST_STATUS_OK; } @@ -566,7 +566,7 @@ usb_request_status_t usb_vendor_request_read_spiflash( { spiflash_buffer[i] = u8_addr_pt[i]; } - usb_transfer_schedule_wait(endpoint->in, &spiflash_buffer[0], len, NULL); + usb_transfer_schedule(endpoint->in, &spiflash_buffer[0], len, NULL); return USB_REQUEST_STATUS_OK; } } else if (stage == USB_TRANSFER_STAGE_DATA) @@ -604,7 +604,7 @@ 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_transfer_schedule_wait(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len, NULL); + usb_transfer_schedule(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len, NULL); return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { @@ -656,7 +656,7 @@ usb_request_status_t usb_vendor_request_read_board_id( { if (stage == USB_TRANSFER_STAGE_SETUP) { endpoint->buffer[0] = BOARD_ID; - usb_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL); usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; @@ -669,7 +669,7 @@ usb_request_status_t usb_vendor_request_read_version_string( if (stage == USB_TRANSFER_STAGE_SETUP) { length = (uint8_t)strlen(version_string); - usb_transfer_schedule_wait(endpoint->in, version_string, length, NULL); + usb_transfer_schedule(endpoint->in, version_string, length, NULL); usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; @@ -681,7 +681,7 @@ usb_request_status_t usb_vendor_request_set_freq( { if (stage == USB_TRANSFER_STAGE_SETUP) { - usb_transfer_schedule_wait(endpoint->out, &set_freq_params, sizeof(set_freq_params_t), NULL); + usb_transfer_schedule(endpoint->out, &set_freq_params, sizeof(set_freq_params_t), NULL); return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { @@ -703,7 +703,7 @@ usb_request_status_t usb_vendor_request_set_sample_rate_frac( { if (stage == USB_TRANSFER_STAGE_SETUP) { - usb_transfer_schedule_wait(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t), NULL); + usb_transfer_schedule(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t), NULL); return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { @@ -777,7 +777,7 @@ 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_transfer_schedule_wait(endpoint->in, &read_partid_serialno, length, NULL); + usb_transfer_schedule(endpoint->in, &read_partid_serialno, length, NULL); usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; @@ -789,7 +789,7 @@ usb_request_status_t usb_vendor_request_set_lna_gain( if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint8_t value = max2837_set_lna_gain(endpoint->setup.index); endpoint->buffer[0] = value; - usb_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } @@ -802,7 +802,7 @@ 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_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } @@ -815,7 +815,7 @@ 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_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index 78ae7f3d..43f2379f 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -115,7 +115,7 @@ 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_transfer_schedule_wait( + usb_transfer_schedule( endpoint->in, descriptor_data, (setup_length > descriptor_length) ? descriptor_length : setup_length, @@ -267,7 +267,7 @@ static usb_request_status_t usb_standard_request_get_configuration_setup( if( endpoint->device->configuration ) { endpoint->buffer[0] = endpoint->device->configuration->number; } - usb_transfer_schedule_wait(endpoint->in, &endpoint->buffer, 1, NULL); + usb_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } else { From af34a7a0416c5a8125bd99f39319e94d8c803e3f Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 16:35:26 -0400 Subject: [PATCH 14/67] usb: Use usb_endpoint_is_priming helper --- firmware/hackrf_usb/usb.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 14a94397..09e3d127 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -188,6 +188,17 @@ void usb_endpoint_prime( } } +static bool usb_endpoint_is_priming( + const usb_endpoint_t* const endpoint +) { + const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address); + if( usb_endpoint_is_in(endpoint->address) ) { + return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number); + } else { + 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( @@ -213,18 +224,13 @@ void usb_endpoint_schedule_append( 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; + if (usb_endpoint_is_priming(endpoint)) { + return; } USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW; @@ -237,18 +243,6 @@ void usb_endpoint_schedule_append( } } -/* -static bool usb_endpoint_is_priming( - const usb_endpoint_t* const endpoint -) { - const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address); - if( usb_endpoint_is_in(endpoint->address) ) { - return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number); - } else { - return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number); - } -} -*/ void usb_endpoint_flush( const usb_endpoint_t* const endpoint ) { From a88b2ad349429879205e0c47df21392911efea58 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 16:40:53 -0400 Subject: [PATCH 15/67] usb_queue: Transfer needs to be added to queue in both paths --- firmware/hackrf_usb/usb_queue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 0aa3a3c3..c0b5f7d7 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -139,13 +139,13 @@ void usb_transfer_schedule( fill_in_transfer(transfer, data, maximum_length); transfer->completion_cb = completion_cb; // TODO: disable_interrupts(); + endpoint_add_transfer(endpoint, transfer); usb_transfer_t* tail = endpoint_transfers[index]; if (tail == NULL) { usb_endpoint_schedule_wait(endpoint, &transfer->td); } else { - for (; tail->next != NULL; tail = tail->next); - endpoint_add_transfer(endpoint, transfer); - usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); + for (; tail->next != NULL; tail = tail->next); + usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); } //enable_interrupts(); } From 0d1ea071515eda1ff97fd0d21542fe4f7a606f29 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 16:41:39 -0400 Subject: [PATCH 16/67] usb: Check is_priming before loop --- firmware/hackrf_usb/usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 09e3d127..5a151aec 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -228,11 +228,11 @@ void usb_endpoint_schedule_append( tail_td->next_dtd_pointer = new_td; - do { - if (usb_endpoint_is_priming(endpoint)) { - return; - } + 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)); From eef6a0f0566e13289d08a8d7654316771c20fc06 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 16:51:18 -0400 Subject: [PATCH 17/67] usb_queue: Assert that transaction succeeded --- firmware/hackrf_usb/usb_queue.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index c0b5f7d7..10fd1ef8 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -160,6 +160,13 @@ void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) { usb_transfer_t* transfer = endpoint_pop_transfer(endpoint); unsigned int transferred = transfer->maximum_length - transfer->td.total_bytes; + uint8_t status = transfer->td.total_bytes; + if (status & USB_TD_DTD_TOKEN_STATUS_ACTIVE + || status & USB_TD_DTD_TOKEN_STATUS_HALTED + || status & USB_TD_DTD_TOKEN_STATUS_BUFFER_ERROR + || status & USB_TD_DTD_TOKEN_STATUS_TRANSACTION_ERROR) { + assert(0); + } if (transfer->completion_cb) transfer->completion_cb(transfer, transferred); free_transfer(transfer); From f36943df627acf58e00d0698c348a93b0e417043 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 16:51:48 -0400 Subject: [PATCH 18/67] usb: Whitespace cleanup --- firmware/hackrf_usb/usb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 5a151aec..a44d9164 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -90,25 +90,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() { From f3a36d06fd4befd0b8e99d96df30f697ce9a18ec Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 17:11:29 -0400 Subject: [PATCH 19/67] usb_queue: Add new transfer after finding tail --- firmware/hackrf_usb/usb_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 10fd1ef8..4dcd57c6 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -139,8 +139,8 @@ void usb_transfer_schedule( fill_in_transfer(transfer, data, maximum_length); transfer->completion_cb = completion_cb; // TODO: disable_interrupts(); - endpoint_add_transfer(endpoint, transfer); usb_transfer_t* tail = endpoint_transfers[index]; + endpoint_add_transfer(endpoint, transfer); if (tail == NULL) { usb_endpoint_schedule_wait(endpoint, &transfer->td); } else { From 2ad4cbe087eed22840015c708e8380b8584060d4 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 17:48:43 -0400 Subject: [PATCH 20/67] usb_queue: Fix calculation of transferred --- firmware/hackrf_usb/usb_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 4dcd57c6..853ace75 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -159,7 +159,8 @@ void usb_transfer_schedule_ack( void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) { usb_transfer_t* transfer = endpoint_pop_transfer(endpoint); - unsigned int transferred = transfer->maximum_length - transfer->td.total_bytes; + 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; uint8_t status = transfer->td.total_bytes; if (status & USB_TD_DTD_TOKEN_STATUS_ACTIVE || status & USB_TD_DTD_TOKEN_STATUS_HALTED From 1d9119fd8acf2b0c12501620dd2d826e9acb7867 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 17:48:55 -0400 Subject: [PATCH 21/67] usb: Ensure TERMINATE bit gets set --- firmware/hackrf_usb/usb.c | 3 ++- firmware/hackrf_usb/usb_queue.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index a44d9164..472e5eb5 100644 --- a/firmware/hackrf_usb/usb.c +++ b/firmware/hackrf_usb/usb.c @@ -218,7 +218,8 @@ void usb_endpoint_schedule_wait( // 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 +// 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, diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 853ace75..dc8ec2eb 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -137,6 +137,7 @@ void usb_transfer_schedule( usb_transfer_t* const transfer = allocate_transfer(); uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); fill_in_transfer(transfer, data, maximum_length); + transfer->td.next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; transfer->completion_cb = completion_cb; // TODO: disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; From 28fcb2a961dd2bdfcd114d8d01f4abc38a8a98d3 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 17:51:42 -0400 Subject: [PATCH 22/67] usb_queue: Merge fill_in_transfer into schedule --- firmware/hackrf_usb/usb_queue.c | 44 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index dc8ec2eb..64822840 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -54,28 +54,6 @@ void usb_queue_init() { } t->next = NULL; } - -static void fill_in_transfer(usb_transfer_t* transfer, - void* const data, - const uint32_t maximum_length -) { - usb_transfer_descriptor_t* const td = &transfer->td; - - // Configure the transfer. descriptor - 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; - - transfer->maximum_length = maximum_length; -} /* Allocate a transfer */ static usb_transfer_t* allocate_transfer() @@ -135,16 +113,36 @@ void usb_transfer_schedule( const transfer_completion_cb completion_cb ) { usb_transfer_t* const transfer = allocate_transfer(); + assert(transfer != NULL); + usb_transfer_descriptor_t* const td = &transfer->td; uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); - fill_in_transfer(transfer, data, maximum_length); + + // Configure the transfer descriptor + 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->td.next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; transfer->completion_cb = completion_cb; + // TODO: disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; endpoint_add_transfer(endpoint, transfer); if (tail == NULL) { + // The queue is currently empty, we need to re-prime usb_endpoint_schedule_wait(endpoint, &transfer->td); } else { + // The queue is currently running, try to append for (; tail->next != NULL; tail = tail->next); usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); } From 13589b86958143757eeed128b61118b20937f8f7 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 18:14:15 -0400 Subject: [PATCH 23/67] usb_queue: Ensure fields get set --- firmware/hackrf_usb/usb_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 64822840..7c7fa6f9 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -118,6 +118,7 @@ void usb_transfer_schedule( uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); // 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 @@ -132,8 +133,8 @@ void usb_transfer_schedule( // Fill in transfer fields transfer->maximum_length = maximum_length; - transfer->td.next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; transfer->completion_cb = completion_cb; + transfer->endpoint = endpoint; // TODO: disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; From f1fc4a6d73d40034b2bb457fc3a191be28b0ecb5 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 3 Jul 2013 19:11:26 -0400 Subject: [PATCH 24/67] usb_queue: Account for completion of multiple transfers --- firmware/hackrf_usb/usb_queue.c | 58 ++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 7c7fa6f9..1768b0a5 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -93,19 +93,6 @@ static void endpoint_add_transfer( //enable_irqs(); } -/* Pop off the transfer at the top of an endpoint's queue */ -static usb_transfer_t* endpoint_pop_transfer( - const usb_endpoint_t* const endpoint -) { - uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); - //FIXME disable_irqs(); - usb_transfer_t* transfer = endpoint_transfers[index]; - assert(transfer != NULL); - endpoint_transfers[index] = transfer->next; - //enable_irqs(); - return transfer; -} - void usb_transfer_schedule( const usb_endpoint_t* const endpoint, void* const data, @@ -134,12 +121,12 @@ void usb_transfer_schedule( // Fill in transfer fields transfer->maximum_length = maximum_length; transfer->completion_cb = completion_cb; - transfer->endpoint = endpoint; + transfer->endpoint = (usb_endpoint_t*) endpoint; // TODO: disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; endpoint_add_transfer(endpoint, transfer); - if (tail == NULL) { + if (1 || tail == NULL) { // The queue is currently empty, we need to re-prime usb_endpoint_schedule_wait(endpoint, &transfer->td); } else { @@ -156,19 +143,36 @@ void usb_transfer_schedule_ack( usb_transfer_schedule(endpoint, 0, 0, NULL); } +/* Called when an endpoint might have completed a transfer */ void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) { - usb_transfer_t* transfer = endpoint_pop_transfer(endpoint); - 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; - uint8_t status = transfer->td.total_bytes; - if (status & USB_TD_DTD_TOKEN_STATUS_ACTIVE - || status & USB_TD_DTD_TOKEN_STATUS_HALTED - || status & USB_TD_DTD_TOKEN_STATUS_BUFFER_ERROR - || status & USB_TD_DTD_TOKEN_STATUS_TRANSACTION_ERROR) { - assert(0); + uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); + usb_transfer_t* transfer = endpoint_transfers[index]; + + 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) { + assert(0); + } + + // Still not finished + if (status & USB_TD_DTD_TOKEN_STATUS_ACTIVE) + break; + + // 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, transferred); + + // Advance head and free + endpoint_transfers[index] = transfer->next; + usb_transfer_t* next = transfer->next; + free_transfer(transfer); + transfer = next; } - if (transfer->completion_cb) - transfer->completion_cb(transfer, transferred); - free_transfer(transfer); } From 63ce57b30632e0bbd92c8b74257806b0807bb9ba Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Thu, 4 Jul 2013 11:26:22 -0400 Subject: [PATCH 25/67] usb_queue: Clarify comment --- firmware/hackrf_usb/usb_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 1768b0a5..27053c35 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -169,7 +169,7 @@ void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) if (transfer->completion_cb) transfer->completion_cb(transfer, transferred); - // Advance head and free + // Advance head and free transfer endpoint_transfers[index] = transfer->next; usb_transfer_t* next = transfer->next; free_transfer(transfer); From b6f9a3699a544ca505c5bccb335733b90bb41ee9 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Thu, 4 Jul 2013 11:35:32 -0400 Subject: [PATCH 26/67] usb_queue: Kill assert reference --- firmware/hackrf_usb/usb_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 27053c35..ea9e6e69 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -156,7 +156,8 @@ void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) if ( status & USB_TD_DTD_TOKEN_STATUS_HALTED || status & USB_TD_DTD_TOKEN_STATUS_BUFFER_ERROR || status & USB_TD_DTD_TOKEN_STATUS_TRANSACTION_ERROR) { - assert(0); + // TODO: Uh oh, do something useful here + while (1); } // Still not finished From df97b6584bbd50c5bd225dea51618ff738953888 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Thu, 4 Jul 2013 11:53:09 -0400 Subject: [PATCH 27/67] hackrf_usb: Port to usb_queue --- firmware/hackrf_usb/hackrf_usb.c | 65 +++++--------------------------- 1 file changed, 10 insertions(+), 55 deletions(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 14d1722b..acfe0c53 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -50,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]; @@ -182,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, @@ -281,7 +234,7 @@ 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 }; usb_endpoint_t usb_endpoint_bulk_out = { @@ -290,7 +243,7 @@ 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 }; void baseband_streaming_disable() { @@ -307,8 +260,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); @@ -997,20 +948,24 @@ int main(void) { while( usb_bulk_buffer_offset < 16384 ); // Set up IN transfer of buffer 0. - usb_endpoint_schedule_no_int( + usb_transfer_schedule( (transceiver_mode == TRANSCEIVER_MODE_RX) ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, - &usb_td_bulk[0] + &usb_bulk_buffer[0x0000], + 0x4000, + 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( + usb_transfer_schedule( (transceiver_mode == TRANSCEIVER_MODE_RX) ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, - &usb_td_bulk[1] + &usb_bulk_buffer[0x4000], + 0x4000, + NULL ); } From dd81921650fab8bd5c4da28925a5f3ad3049e774 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Thu, 4 Jul 2013 13:36:25 -0400 Subject: [PATCH 28/67] usb_queue: Reduce transfer_pool size --- firmware/hackrf_usb/usb_queue.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index ea9e6e69..b68d3fc5 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -36,7 +36,8 @@ struct _usb_transfer_t { transfer_completion_cb completion_cb; }; -usb_transfer_t transfer_pool[16]; +usb_transfer_t transfer_pool[8]; +const unsigned int transfer_pool_size = sizeof(transfer_pool) / sizeof(usb_transfer_t); // Available transfer list usb_transfer_t* free_transfers; @@ -49,7 +50,7 @@ usb_transfer_t* endpoint_transfers[12] = {}; void usb_queue_init() { usb_transfer_t* t = &transfer_pool[0]; free_transfers = t; - for (unsigned int i=0; i < sizeof(transfer_pool) / sizeof(usb_transfer_t) - 1; i++, t++) { + for (unsigned int i=0; i < transfer_pool_size - 1; i++, t++) { t->next = t+1; } t->next = NULL; From abb0b3f928c70c9b4f8f107e0db661f7e734ba30 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Thu, 4 Jul 2013 14:01:32 -0400 Subject: [PATCH 29/67] hackrf_usb: Forgotten initialization --- firmware/hackrf_usb/hackrf_usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index acfe0c53..5ece18a6 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -918,6 +918,8 @@ int main(void) { enable_1v8_power(); cpu_clock_init(); + usb_queue_init(); + usb_set_configuration_changed_cb(usb_configuration_changed); usb_peripheral_reset(); usb_device_init(0, &usb_device); From 3e3a57e3ced46b6663ef97093d3d425509d50fbf Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Thu, 4 Jul 2013 15:30:15 -0400 Subject: [PATCH 30/67] hackrf_usb: Don't attempt to schedule transfers when OFF The endpoints are disabled so no good will come of this --- firmware/hackrf_usb/hackrf_usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 5ece18a6..348b9236 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -946,6 +946,9 @@ int main(void) { #endif while(true) { + if (transceiver_mode == TRANSCEIVER_MODE_OFF) + continue; + // Wait until buffer 0 is transmitted/received. while( usb_bulk_buffer_offset < 16384 ); From 5a70772295bb670215dd4d36fdf3e5985af99f71 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Thu, 4 Jul 2013 15:30:43 -0400 Subject: [PATCH 31/67] usb_queue: Enable transfer chaining Unfortunately this seems to be slightly broken. While hackrf_transfer streams fine, things fall apart when disabling streaming. Not sure why yet. --- firmware/hackrf_usb/usb_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index b68d3fc5..7492eb92 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -127,7 +127,7 @@ void usb_transfer_schedule( // TODO: disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; endpoint_add_transfer(endpoint, transfer); - if (1 || tail == NULL) { + if (tail == NULL) { // The queue is currently empty, we need to re-prime usb_endpoint_schedule_wait(endpoint, &transfer->td); } else { From 969647dbef657f254724cc185a956a6ca695a457 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Fri, 5 Jul 2013 11:15:23 -0400 Subject: [PATCH 32/67] usb_queue: Update queue before calling completion callback --- firmware/hackrf_usb/usb_queue.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 7492eb92..79e00095 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -165,6 +165,11 @@ void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) 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 + endpoint_transfers[index] = 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; @@ -172,8 +177,6 @@ void usb_queue_transfer_complete(usb_endpoint_t* const endpoint) transfer->completion_cb(transfer, transferred); // Advance head and free transfer - endpoint_transfers[index] = transfer->next; - usb_transfer_t* next = transfer->next; free_transfer(transfer); transfer = next; } From 8fdc22f8c8605fe576327b6ac61f0804fe18ee20 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 6 Jul 2013 17:00:23 -0400 Subject: [PATCH 33/67] usb-queue: Add flush utility --- firmware/hackrf_usb/usb_queue.c | 13 ++++++++++++- firmware/hackrf_usb/usb_queue.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 79e00095..b595b4e7 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -55,7 +55,7 @@ void usb_queue_init() { } t->next = NULL; } - + /* Allocate a transfer */ static usb_transfer_t* allocate_transfer() { @@ -93,6 +93,17 @@ static void endpoint_add_transfer( } //enable_irqs(); } + +void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint) +{ + uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); + //FIXME disable_irqs(); + while (endpoint_transfers[index]) { + usb_transfer_t * transfer = endpoint_transfers[index]; + endpoint_transfers[index] = transfer->next; + free_transfer(transfer); + } +} void usb_transfer_schedule( const usb_endpoint_t* const endpoint, diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index f6dc0203..90d59567 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -31,6 +31,8 @@ typedef struct _usb_transfer_t usb_transfer_t; typedef void (*transfer_completion_cb)(usb_transfer_t*, unsigned int); +void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint); + void usb_endpoint_schedule( const usb_endpoint_t* const endpoint, void* const data, From f12defebc65953a0d2c6860d8deeaf217681a323 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 6 Jul 2013 17:08:51 -0400 Subject: [PATCH 34/67] usb: Ensure endpoint queue is flushed on disable/init --- firmware/hackrf_usb/usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/hackrf_usb/usb.c b/firmware/hackrf_usb/usb.c index 472e5eb5..8a02eb0e 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 @@ -163,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); } @@ -248,6 +250,7 @@ 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 { From 9f2dca3e4e2c2aa042f6b94cc1fe308bc1e22bc0 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 6 Jul 2013 17:01:12 -0400 Subject: [PATCH 35/67] usb_standard_request: Always call configuration_changed_cb For reasons I don't entirely understand, bulk requests are suddenly ignored after a SET_CONFIGURATION request (even if the configuration did not change) unless the endpoints are reinitialized. This is done by configuration_changed_cb, therefore we call it for every request. --- firmware/hackrf_usb/usb_standard_request.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index 43f2379f..43c23ada 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -100,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; } From 14526cd1c278f7ee6709ad19cefa1ff937bbf5d5 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 6 Jul 2013 19:15:17 -0400 Subject: [PATCH 36/67] hackrf_usb: Be more careful in transceiver_mode check --- firmware/hackrf_usb/hackrf_usb.c | 35 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 348b9236..b04fb9ae 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -946,32 +946,33 @@ int main(void) { #endif while(true) { - if (transceiver_mode == TRANSCEIVER_MODE_OFF) - continue; - // Wait until buffer 0 is transmitted/received. while( usb_bulk_buffer_offset < 16384 ); // Set up IN transfer of buffer 0. - usb_transfer_schedule( - (transceiver_mode == TRANSCEIVER_MODE_RX) - ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, - &usb_bulk_buffer[0x0000], - 0x4000, - NULL - ); + if (transceiver_mode != TRANSCEIVER_MODE_OFF) { + usb_transfer_schedule( + (transceiver_mode == TRANSCEIVER_MODE_RX) + ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, + &usb_bulk_buffer[0x0000], + 0x4000, + NULL + ); + } // Wait until buffer 1 is transmitted/received. while( usb_bulk_buffer_offset >= 16384 ); // Set up IN transfer of buffer 1. - usb_transfer_schedule( - (transceiver_mode == TRANSCEIVER_MODE_RX) - ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, - &usb_bulk_buffer[0x4000], - 0x4000, - NULL - ); + if (transceiver_mode != TRANSCEIVER_MODE_OFF) { + usb_transfer_schedule( + (transceiver_mode == TRANSCEIVER_MODE_RX) + ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, + &usb_bulk_buffer[0x4000], + 0x4000, + NULL + ); + } } return 0; From 36cf222ef498258d1c0f81d63f66d3c810b255c3 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 6 Jul 2013 19:17:38 -0400 Subject: [PATCH 37/67] usb_queue: Add some interrupt disabling around critical sections --- firmware/hackrf_usb/usb_queue.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index b595b4e7..cb90959a 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -25,6 +25,8 @@ #include #include +#include + #include "usb.h" #include "usb_queue.h" @@ -60,20 +62,16 @@ void usb_queue_init() { static usb_transfer_t* allocate_transfer() { while (free_transfers == NULL); - //disable_irqs(); // FIXME usb_transfer_t* const transfer = free_transfers; free_transfers = transfer->next; - //enable_irqs(); return transfer; } /* Place a transfer in the free list */ static void free_transfer(usb_transfer_t* const transfer) { - //disable_irqs(); // FIXME transfer->next = free_transfers; free_transfers = transfer; - //enable_irqs(); } /* Add a transfer to the end of an endpoint's queue */ @@ -82,7 +80,6 @@ static void endpoint_add_transfer( usb_transfer_t* const transfer ) { uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); - //FIXME disable_irqs(); transfer->next = NULL; if (endpoint_transfers[index] != NULL) { usb_transfer_t* t = endpoint_transfers[index]; @@ -91,18 +88,18 @@ static void endpoint_add_transfer( } else { endpoint_transfers[index] = transfer; } - //enable_irqs(); } void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint) { uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); - //FIXME disable_irqs(); + cc_disable_interrupts(); while (endpoint_transfers[index]) { usb_transfer_t * transfer = endpoint_transfers[index]; endpoint_transfers[index] = transfer->next; free_transfer(transfer); } + cc_enable_interrupts(); } void usb_transfer_schedule( @@ -135,7 +132,7 @@ void usb_transfer_schedule( transfer->completion_cb = completion_cb; transfer->endpoint = (usb_endpoint_t*) endpoint; - // TODO: disable_interrupts(); + cc_disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; endpoint_add_transfer(endpoint, transfer); if (tail == NULL) { @@ -146,7 +143,7 @@ void usb_transfer_schedule( for (; tail->next != NULL; tail = tail->next); usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); } - //enable_interrupts(); + cc_enable_interrupts(); } void usb_transfer_schedule_ack( From d30d7309d9c09f6862239322d970033e3c07a352 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 6 Jul 2013 19:17:57 -0400 Subject: [PATCH 38/67] usb_queue: Mark queues as volatile --- firmware/hackrf_usb/usb_queue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index cb90959a..8253e0b6 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -42,12 +42,12 @@ usb_transfer_t transfer_pool[8]; const unsigned int transfer_pool_size = sizeof(transfer_pool) / sizeof(usb_transfer_t); // Available transfer list -usb_transfer_t* free_transfers; +usb_transfer_t* volatile free_transfers; #define USB_ENDPOINT_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1)) // Pending transfer heads -usb_transfer_t* endpoint_transfers[12] = {}; +usb_transfer_t* volatile endpoint_transfers[12] = {}; void usb_queue_init() { usb_transfer_t* t = &transfer_pool[0]; From a9f8103fec7c6a58472465b7147fe340517a489b Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 6 Jul 2013 19:21:12 -0400 Subject: [PATCH 39/67] hackrf_stop_rx: First set mode, then kill transfer thread Killing the transfer thread first means that the host stops polling the device for reads, causing the device to hang while scheduling the dTD --- host/libhackrf/src/hackrf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 7e36dc55..f03f19aa 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 result1; + return kill_transfer_thread(device); } int ADDCALL hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* tx_ctx) From df400eced6568a783456187356d3bfd9cfd48ec6 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 21:08:57 -0400 Subject: [PATCH 40/67] Bump libopencm3 --- firmware/libopencm3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/libopencm3 b/firmware/libopencm3 index 87690732..e0040d7c 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit 87690732661dd049657967d3951cb8f4674ede00 +Subproject commit e0040d7c82d174c3ef1c4d3e860aa2ab765a9ab7 From cce17c42fd16ed7cf74c9653ddaf06cd7fafd61c Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 21:24:13 -0400 Subject: [PATCH 41/67] libopencm3: Update --- firmware/hackrf_usb/usb_queue.c | 8 ++++---- firmware/libopencm3 | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 8253e0b6..0341150a 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -93,13 +93,13 @@ static void endpoint_add_transfer( void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint) { uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address); - cc_disable_interrupts(); + cm_disable_interrupts(); while (endpoint_transfers[index]) { usb_transfer_t * transfer = endpoint_transfers[index]; endpoint_transfers[index] = transfer->next; free_transfer(transfer); } - cc_enable_interrupts(); + cm_enable_interrupts(); } void usb_transfer_schedule( @@ -132,7 +132,7 @@ void usb_transfer_schedule( transfer->completion_cb = completion_cb; transfer->endpoint = (usb_endpoint_t*) endpoint; - cc_disable_interrupts(); + cm_disable_interrupts(); usb_transfer_t* tail = endpoint_transfers[index]; endpoint_add_transfer(endpoint, transfer); if (tail == NULL) { @@ -143,7 +143,7 @@ void usb_transfer_schedule( for (; tail->next != NULL; tail = tail->next); usb_endpoint_schedule_append(endpoint, &tail->td, &transfer->td); } - cc_enable_interrupts(); + cm_enable_interrupts(); } void usb_transfer_schedule_ack( diff --git a/firmware/libopencm3 b/firmware/libopencm3 index e0040d7c..0aabbbe3 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit e0040d7c82d174c3ef1c4d3e860aa2ab765a9ab7 +Subproject commit 0aabbbe366565d25f7cd817b57b2f2eab7f1911c From e23cc9bd6c5434f36dd7a3de7437c7316e97f265 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 21:25:31 -0400 Subject: [PATCH 42/67] usb_queue: Disable interrupts when allocating transfer --- firmware/hackrf_usb/usb_queue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 0341150a..ea6c2980 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -62,8 +62,10 @@ void usb_queue_init() { static usb_transfer_t* allocate_transfer() { while (free_transfers == NULL); + cm_disable_interrupts(); usb_transfer_t* const transfer = free_transfers; free_transfers = transfer->next; + cm_enable_interrupts(); return transfer; } From f50253eaa38ae33bf4dbda5050a22f48660a58f8 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 21:54:25 -0400 Subject: [PATCH 43/67] usb_queue: Use ldrex/strex to avoid disabling interrupts --- firmware/hackrf_usb/usb_queue.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index ea6c2980..683b3b96 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -26,6 +26,7 @@ #include #include +#include #include "usb.h" #include "usb_queue.h" @@ -61,19 +62,25 @@ void usb_queue_init() { /* Allocate a transfer */ static usb_transfer_t* allocate_transfer() { + bool aborted; + usb_transfer_t* transfer; while (free_transfers == NULL); - cm_disable_interrupts(); - usb_transfer_t* const transfer = free_transfers; - free_transfers = transfer->next; - cm_enable_interrupts(); + do { + transfer = (void *) __ldrex((uint32_t *) &free_transfers); + aborted = __strex((uint32_t) transfer->next, (uint32_t *) &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) { - transfer->next = free_transfers; - free_transfers = transfer; + bool aborted; + do { + transfer->next = (void *) __ldrex((uint32_t *) &free_transfers); + aborted = __strex((uint32_t) transfer, (uint32_t *) &free_transfers); + } while (aborted); } /* Add a transfer to the end of an endpoint's queue */ From bb69f655b11187b8cf61ac51ca37045c1b0017df Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 21:58:06 -0400 Subject: [PATCH 44/67] usb_queue: Use while instead of for --- firmware/hackrf_usb/usb_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_queue.c b/firmware/hackrf_usb/usb_queue.c index 683b3b96..afb6c7e8 100644 --- a/firmware/hackrf_usb/usb_queue.c +++ b/firmware/hackrf_usb/usb_queue.c @@ -92,7 +92,7 @@ static void endpoint_add_transfer( transfer->next = NULL; if (endpoint_transfers[index] != NULL) { usb_transfer_t* t = endpoint_transfers[index]; - for (; t->next != NULL; t = t->next); + while (t->next != NULL) t = t->next; t->next = transfer; } else { endpoint_transfers[index] = transfer; From b738cd52940090b58c642cf85223cb212185bcca Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 23:21:11 -0400 Subject: [PATCH 45/67] fix1 --- firmware/hackrf_usb/usb_standard_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index 43c23ada..9263a5bb 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -102,8 +102,8 @@ bool usb_set_configuration( 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; } From f6b41dbda50cbe58f953a6213d9806600ac5f799 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 23:21:18 -0400 Subject: [PATCH 46/67] fix2 --- firmware/hackrf_usb/usb_standard_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/hackrf_usb/usb_standard_request.c b/firmware/hackrf_usb/usb_standard_request.c index 9263a5bb..98e50142 100644 --- a/firmware/hackrf_usb/usb_standard_request.c +++ b/firmware/hackrf_usb/usb_standard_request.c @@ -121,7 +121,7 @@ static usb_request_status_t usb_send_descriptor( endpoint->in, descriptor_data, (setup_length > descriptor_length) ? descriptor_length : setup_length, - NULL + NULL ); usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; From 0e14a3840314a6f58739b0e4a32ea7c9ade58bd0 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 7 Jul 2013 23:22:34 -0400 Subject: [PATCH 47/67] fix3 --- host/libhackrf/src/hackrf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index f03f19aa..3fd8051c 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -1141,7 +1141,7 @@ int ADDCALL hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn cal int ADDCALL hackrf_stop_rx(hackrf_device* device) { - int result; + int result; result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF); if (result != HACKRF_SUCCESS) { From 3642fe9bc62033bfa5123c141854bcfe94d0f1e9 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Tue, 9 Jul 2013 20:57:37 -0400 Subject: [PATCH 48/67] usb_queue: Kill dead declaration --- firmware/hackrf_usb/usb_queue.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/firmware/hackrf_usb/usb_queue.h b/firmware/hackrf_usb/usb_queue.h index 90d59567..8c776d3e 100644 --- a/firmware/hackrf_usb/usb_queue.h +++ b/firmware/hackrf_usb/usb_queue.h @@ -33,12 +33,6 @@ typedef void (*transfer_completion_cb)(usb_transfer_t*, unsigned int); void usb_queue_flush_endpoint(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_transfer_schedule( const usb_endpoint_t* const endpoint, void* const data, From 5143456d6daf41345d60182f6c3bb4aba4576e79 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 6 Sep 2013 15:25:34 -0700 Subject: [PATCH 49/67] Update libopencm3 submodule commit. --- firmware/libopencm3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/libopencm3 b/firmware/libopencm3 index d7fdcefb..f92dbcdf 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit d7fdcefbd7565e59aaaf2dea99bee8e0157ff1d7 +Subproject commit f92dbcdf6028687f705c71134f51d5b4061daf7a From 5cad831075786e424549ebb35458afaa82d80b2d Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 6 Sep 2013 15:37:24 -0700 Subject: [PATCH 50/67] Fixed cut-and-paste oops in variable name. --- host/libhackrf/src/hackrf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 3fd8051c..47ff055a 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -1145,7 +1145,7 @@ int ADDCALL hackrf_stop_rx(hackrf_device* device) result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF); if (result != HACKRF_SUCCESS) { - return result2; + return result; } return kill_transfer_thread(device); } From 21ad0778d274e13ac16373373ceb310121c28a68 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 2 Sep 2013 19:40:29 -0400 Subject: [PATCH 51/67] 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 52/67] 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 53/67] 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 54/67] 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 55/67] 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 56/67] 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 57/67] 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 58/67] 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 59/67] 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 60/67] 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 61/67] 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 62/67] 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 63/67] 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 64/67] 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 65/67] 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 66/67] 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 \ From d13e80b5205163618107f377df633821f709fc17 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 16 Sep 2013 15:21:28 -0700 Subject: [PATCH 67/67] With bgamari's new USB configuration for CPLD, be sure to turn up CPU clock to maximum. --- firmware/hackrf_usb/hackrf_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 6a81b7ad..9dca7f4a 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -870,6 +870,7 @@ void usb_configuration_changed( gpio_set(PORT_LED1_3, PIN_LED1); } else if( device->configuration->number == 2 ) { // CPLD update configuration + cpu_clock_pll1_max_speed(); set_transceiver_mode(TRANSCEIVER_MODE_OFF); usb_endpoint_init(&usb_endpoint_bulk_out); start_cpld_update = true;