Merge branch 'refs/heads/bgamari_usb_merge' into jboone_refactor_20130906

Conflicts:
	firmware/hackrf_usb/hackrf_usb.c
This commit is contained in:
Jared Boone
2013-09-17 13:10:30 -07:00
17 changed files with 888 additions and 544 deletions

View File

@ -26,8 +26,9 @@
#include <libopencm3/lpc43xx/scu.h>
#include <stdint.h>
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;
}

View File

@ -24,9 +24,20 @@
#include <stdint.h>
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__

View File

@ -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 <libopencm3/lpc43xx/gpio.h>
//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
}

View File

@ -31,6 +31,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 \

View File

@ -41,6 +41,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"
@ -52,13 +53,9 @@
static volatile transceiver_mode_t transceiver_mode = TRANSCEIVER_MODE_OFF;
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];
uint16_t write_cpld_idx = 0;
static volatile bool start_cpld_update = false;
uint8_t cpld_xsvf_buffer[512];
volatile bool cpld_wait = false;
uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN];
char version_string[] = VERSION_STRING;
@ -77,50 +74,6 @@ typedef struct {
set_sample_r_params_t set_sample_r_params;
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,
@ -133,9 +86,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,
};
@ -156,6 +123,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,
@ -165,6 +133,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
@ -176,8 +145,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,
@ -185,8 +155,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();
@ -202,8 +173,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);
@ -255,7 +224,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;
@ -273,7 +242,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;
}
}
@ -292,8 +261,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;
@ -310,7 +280,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;
}
}
@ -328,8 +298,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;
@ -345,7 +316,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;
@ -363,7 +334,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;
@ -384,8 +355,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;
@ -403,7 +375,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;
@ -424,7 +396,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;
}
@ -437,7 +410,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;
}
@ -468,7 +441,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)
@ -482,69 +456,7 @@ usb_request_status_t usb_vendor_request_read_spiflash(
return USB_REQUEST_STATUS_STALL;
} else
{
usb_endpoint_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
} else
{
return USB_REQUEST_STATUS_OK;
}
}
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_endpoint_schedule(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len);
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_endpoint_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_endpoint_schedule_ack(endpoint->in);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
} else
@ -558,8 +470,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;
}
@ -571,8 +483,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;
}
@ -583,13 +495,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;
@ -605,13 +518,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;
@ -628,11 +542,11 @@ usb_request_status_t usb_vendor_request_set_amp_enable(
switch (endpoint->setup.value) {
case 0:
rf_path_set_lna(0);
usb_endpoint_schedule_ack(endpoint->in);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
case 1:
rf_path_set_lna(1);
usb_endpoint_schedule_ack(endpoint->in);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
default:
return USB_REQUEST_STATUS_STALL;
@ -677,20 +591,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;
@ -702,8 +619,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;
@ -715,8 +633,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;
@ -727,7 +646,7 @@ usb_request_status_t usb_vendor_request_set_if_freq(
) {
if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( set_freq_if((uint32_t)endpoint->setup.index * 1000 * 1000) ) {
usb_endpoint_schedule_ack(endpoint->in);
usb_transfer_schedule_ack(endpoint->in);
} else {
return USB_REQUEST_STATUS_STALL;
}
@ -749,7 +668,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,
@ -787,14 +706,75 @@ 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
) {
/* Reset transceiver to idle state until other commands are received */
set_transceiver_mode(TRANSCEIVER_MODE_OFF);
if( device->configuration->number ) {
if( device->configuration->number == 1 ) {
// transceiver configuration
cpu_clock_pll1_max_speed();
gpio_set(PORT_LED1_3, PIN_LED1);
} else if( device->configuration->number == 2 ) {
// CPLD update configuration
cpu_clock_pll1_max_speed();
usb_endpoint_init(&usb_endpoint_bulk_out);
start_cpld_update = true;
} else {
/* Configuration number equal 0 means usb bus reset. */
cpu_clock_pll1_low_speed();
@ -814,6 +794,11 @@ int main(void) {
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);
@ -833,26 +818,39 @@ int main(void) {
rf_path_init();
unsigned int phase = 0;
while(true) {
// Wait until buffer 0 is transmitted/received.
while( usb_bulk_buffer_offset < 16384 );
// Check whether we need to initiate a CPLD update
if (start_cpld_update)
cpld_update();
// Set up IN transfer of buffer 0.
usb_endpoint_schedule_no_int(
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,
&usb_td_bulk[0]
&usb_bulk_buffer[0x0000],
0x4000,
NULL, NULL
);
// Wait until buffer 1 is transmitted/received.
while( usb_bulk_buffer_offset >= 16384 );
phase = 0;
}
// Set up IN transfer of buffer 1.
usb_endpoint_schedule_no_int(
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,
&usb_td_bulk[1]
&usb_bulk_buffer[0x4000],
0x4000,
NULL, NULL
);
phase = 1;
}
}
return 0;

View File

@ -24,6 +24,7 @@
#include "usb.h"
#include "usb_type.h"
#include "usb_queue.h"
#include "usb_standard_request.h"
#include <libopencm3/lpc43xx/creg.h>
@ -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
) {
@ -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);
}
@ -195,7 +189,7 @@ void usb_endpoint_prime(
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PERB(1 << endpoint_number);
}
}
/*
static bool usb_endpoint_is_priming(
const usb_endpoint_t* const endpoint
) {
@ -206,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 {
@ -510,41 +550,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 ) {

View File

@ -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,4 +82,15 @@ void usb_endpoint_prime(
usb_transfer_descriptor_t* const first_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
);
#endif//__USB_H__

View File

@ -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
};
@ -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,81 @@ 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
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_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
@ -181,10 +255,44 @@ 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 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
};

View File

@ -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[];

View File

@ -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 <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <assert.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/sync.h>
#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;
}
}

View File

@ -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 <libopencm3/lpc43xx/usb.h>
#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__

View File

@ -21,6 +21,7 @@
#include "usb.h"
#include "usb_request.h"
#include "usb_queue.h"
#include <stdbool.h>
@ -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);
}

View File

@ -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,27 +100,31 @@ 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);
}
return true;
}
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];
}
usb_endpoint_schedule(
// 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,
(setup_length > descriptor_length) ? descriptor_length : setup_length
(uint8_t* const) descriptor_data,
(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;
}
@ -136,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
) {
@ -146,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:
@ -157,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:
@ -195,7 +219,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 +255,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 +289,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;

View File

@ -33,6 +33,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 \

View File

@ -93,7 +93,6 @@ 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];
while ((opt = getopt_long(argc, argv, "x:", long_options,
@ -168,10 +167,7 @@ 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 )
{
xfer_len = (length > PACKET_LEN) ? PACKET_LEN : length;
result = hackrf_cpld_write(device, xfer_len, pdata, total_length);
result = hackrf_cpld_write(device, pdata, total_length);
if (result != HACKRF_SUCCESS)
{
fprintf(stderr, "hackrf_cpld_write() failed: %s (%d)\n",
@ -180,11 +176,7 @@ int main(int argc, char** argv)
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);
}
printf("Write finished.\n");
printf("Please Power OFF/Disconnect the Jawbreaker.\n");
fflush(stdout);

View File

@ -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,27 +631,46 @@ 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(
int result = libusb_release_interface(device->usb_device, 0);
if (result != LIBUSB_SUCCESS) {
return HACKRF_ERROR_LIBUSB;
}
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 | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_CPLD_WRITE,
total_length,
0,
data,
length,
0
LIBUSB_ENDPOINT_OUT | 2,
&data[i],
chunk_size,
&transferred,
10000 // long timeout to allow for CPLD programming
);
if (result < length) {
if (result != LIBUSB_SUCCESS) {
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
return HACKRF_SUCCESS;
}
int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* value)
{
int result;
@ -1141,14 +1159,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)

View File

@ -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);