Merge remote-tracking branch 'bgamari/usb' into bgamari_usb_merge

Conflicts:
	firmware/hackrf_usb/hackrf_usb.c
	firmware/hackrf_usb/usb.c
	firmware/hackrf_usb/usb_queue.c
	firmware/hackrf_usb/usb_queue.h
	firmware/hackrf_usb/usb_standard_request.c
This commit is contained in:
Jared Boone
2013-09-16 15:18:14 -07:00
14 changed files with 611 additions and 493 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

@ -50,10 +50,9 @@ 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;
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;
@ -191,9 +190,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,
};
@ -214,6 +227,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,
@ -223,6 +237,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
@ -236,6 +251,7 @@ usb_endpoint_t usb_endpoint_bulk_in = {
.setup_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,
@ -245,6 +261,7 @@ usb_endpoint_t usb_endpoint_bulk_out = {
.setup_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();
@ -343,7 +360,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_transfer_schedule(endpoint->in, &endpoint->buffer, 2, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
@ -379,7 +397,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_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
@ -435,7 +454,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_transfer_schedule(endpoint->in, &endpoint->buffer, 2, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
@ -475,7 +495,8 @@ usb_request_status_t usb_vendor_request_write_spiflash(
|| ((addr + len) > W25Q80BV_NUM_BYTES)) {
return USB_REQUEST_STATUS_STALL;
} else {
usb_transfer_schedule(endpoint->out, &spiflash_buffer[0], len, NULL);
usb_transfer_schedule_block(endpoint->out, &spiflash_buffer[0], len,
NULL, NULL);
w25q80bv_setup();
return USB_REQUEST_STATUS_OK;
}
@ -510,7 +531,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 */
@ -519,7 +540,8 @@ usb_request_status_t usb_vendor_request_read_spiflash(
{
spiflash_buffer[i] = u8_addr_pt[i];
}
usb_transfer_schedule(endpoint->in, &spiflash_buffer[0], len, NULL);
usb_transfer_schedule_block(endpoint->in, &spiflash_buffer[0], len,
NULL, NULL);
return USB_REQUEST_STATUS_OK;
}
} else if (stage == USB_TRANSFER_STAGE_DATA)
@ -542,74 +564,12 @@ 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(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len, 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)
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
endpoint->buffer[0] = BOARD_ID;
usb_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
}
return USB_REQUEST_STATUS_OK;
@ -622,7 +582,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(endpoint->in, version_string, length, NULL);
usb_transfer_schedule_block(endpoint->in, version_string, length, NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
}
return USB_REQUEST_STATUS_OK;
@ -634,7 +594,8 @@ usb_request_status_t usb_vendor_request_set_freq(
{
if (stage == USB_TRANSFER_STAGE_SETUP)
{
usb_transfer_schedule(endpoint->out, &set_freq_params, sizeof(set_freq_params_t), NULL);
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)
{
@ -656,7 +617,8 @@ usb_request_status_t usb_vendor_request_set_sample_rate_frac(
{
if (stage == USB_TRANSFER_STAGE_SETUP)
{
usb_transfer_schedule(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t), NULL);
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)
{
@ -730,19 +692,22 @@ 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(endpoint->in, &read_partid_serialno, length, NULL);
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_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
@ -755,7 +720,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_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
@ -768,7 +734,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_transfer_schedule(endpoint->in, &endpoint->buffer, 1, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
@ -800,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,
@ -838,13 +805,74 @@ 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
) {
if( device->configuration->number ) {
if( device->configuration->number == 1 ) {
// transceiver configuration
cpu_clock_pll1_max_speed();
set_transceiver_mode(transceiver_mode);
gpio_set(PORT_LED1_3, PIN_LED1);
} else if( device->configuration->number == 2 ) {
// CPLD update configuration
set_transceiver_mode(TRANSCEIVER_MODE_OFF);
usb_endpoint_init(&usb_endpoint_bulk_out);
start_cpld_update = true;
} else {
/* Configuration number equal 0 means usb bus reset. */
set_transceiver_mode(TRANSCEIVER_MODE_OFF);
@ -923,12 +951,17 @@ int main(void) {
enable_1v8_power();
cpu_clock_init();
usb_queue_init();
usb_set_configuration_changed_cb(usb_configuration_changed);
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);
@ -936,7 +969,7 @@ int main(void) {
usb_run(&usb_device);
ssp1_init();
ssp1_init();
ssp1_set_mode_max5864();
max5864_xcvr();
@ -950,34 +983,39 @@ int main(void) {
switchctrl = SWITCHCTRL_AMP_BYPASS;
#endif
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.
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
);
}
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_bulk_buffer[0x0000],
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) {
usb_transfer_schedule(
(transceiver_mode == TRANSCEIVER_MODE_RX)
? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out,
&usb_bulk_buffer[0x4000],
0x4000,
NULL
);
}
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_bulk_buffer[0x4000],
0x4000,
NULL, NULL
);
phase = 1;
}
}
return 0;

View File

@ -91,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() {
@ -205,7 +205,7 @@ static bool usb_endpoint_is_priming(
// 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
usb_transfer_descriptor_t* const td
) {
// Ensure that endpoint is ready to be primed.
// It may have been flushed due to an aborted transaction.
@ -213,7 +213,7 @@ void usb_endpoint_schedule_wait(
while( usb_endpoint_is_ready(endpoint) );
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
usb_endpoint_prime(endpoint, td);
}
@ -223,34 +223,34 @@ void usb_endpoint_schedule_wait(
// 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
const usb_endpoint_t* const endpoint,
usb_transfer_descriptor_t* const tail_td,
usb_transfer_descriptor_t* const new_td
) {
bool done;
bool done;
tail_td->next_dtd_pointer = new_td;
tail_td->next_dtd_pointer = new_td;
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));
USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW;
if(!done) {
usb_endpoint_prime(endpoint, new_td);
}
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);
usb_queue_flush_endpoint(endpoint);
if( usb_endpoint_is_in(endpoint->address) ) {
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FETB(1 << endpoint_number));
} else {
@ -556,7 +556,7 @@ static void usb_check_for_setup_events() {
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)
);

View File

@ -38,117 +38,191 @@
#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
0x02 // 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
0x02, // 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
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_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
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
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 +245,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,
@ -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

@ -31,43 +31,46 @@
#include "usb.h"
#include "usb_queue.h"
struct _usb_transfer_t {
struct _usb_transfer_t* next;
usb_transfer_descriptor_t td ATTR_ALIGNED(64);
unsigned int maximum_length;
usb_endpoint_t* endpoint;
transfer_completion_cb completion_cb;
};
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* volatile free_transfers;
usb_queue_t* endpoint_queues[12] = {};
#define USB_ENDPOINT_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
// Pending transfer heads
usb_transfer_t* volatile endpoint_transfers[12] = {};
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_transfer_t* t = &transfer_pool[0];
free_transfers = t;
for (unsigned int i=0; i < transfer_pool_size - 1; i++, t++) {
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()
{
static usb_transfer_t* allocate_transfer(
usb_queue_t* const queue
) {
bool aborted;
usb_transfer_t* transfer;
while (free_transfers == NULL);
if (queue->free_transfers == NULL)
return NULL;
do {
transfer = (void *) __ldrex((uint32_t *) &free_transfers);
aborted = __strex((uint32_t) transfer->next, (uint32_t *) &free_transfers);
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;
@ -76,51 +79,60 @@ static usb_transfer_t* allocate_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 *) &free_transfers);
aborted = __strex((uint32_t) transfer, (uint32_t *) &free_transfers);
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 */
static void endpoint_add_transfer(
const usb_endpoint_t* const endpoint,
/* 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
) {
uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address);
usb_queue_t* const queue = transfer->queue;
transfer->next = NULL;
if (endpoint_transfers[index] != NULL) {
usb_transfer_t* t = endpoint_transfers[index];
if (queue->active != NULL) {
usb_transfer_t* t = queue->active;
while (t->next != NULL) t = t->next;
t->next = transfer;
return t;
} else {
endpoint_transfers[index] = transfer;
queue->active = transfer;
return NULL;
}
}
void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint)
static void usb_queue_flush_queue(usb_queue_t* const queue)
{
uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address);
cm_disable_interrupts();
while (endpoint_transfers[index]) {
usb_transfer_t * transfer = endpoint_transfers[index];
endpoint_transfers[index] = transfer->next;
while (queue->active) {
usb_transfer_t* transfer = queue->active;
queue->active = transfer->next;
free_transfer(transfer);
}
cm_enable_interrupts();
}
void usb_transfer_schedule(
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
const transfer_completion_cb completion_cb,
void* const user_data
) {
usb_transfer_t* const transfer = allocate_transfer();
assert(transfer != NULL);
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;
uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address);
// Configure the transfer descriptor
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
@ -139,33 +151,48 @@ void usb_transfer_schedule(
// Fill in transfer fields
transfer->maximum_length = maximum_length;
transfer->completion_cb = completion_cb;
transfer->endpoint = (usb_endpoint_t*) endpoint;
transfer->user_data = user_data;
cm_disable_interrupts();
usb_transfer_t* tail = endpoint_transfers[index];
endpoint_add_transfer(endpoint, transfer);
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(endpoint, &transfer->td);
usb_endpoint_schedule_wait(queue->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);
usb_endpoint_schedule_append(queue->endpoint, &tail->td, &transfer->td);
}
cm_enable_interrupts();
return 0;
}
void usb_transfer_schedule_ack(
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
) {
usb_transfer_schedule(endpoint, 0, 0, NULL);
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)
{
uint_fast8_t index = USB_ENDPOINT_INDEX(endpoint->address);
usb_transfer_t* transfer = endpoint_transfers[index];
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;
@ -184,14 +211,14 @@ void usb_queue_transfer_complete(usb_endpoint_t* const endpoint)
// 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;
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, transferred);
transfer->completion_cb(transfer->user_data, transferred);
// Advance head and free transfer
free_transfer(transfer);

View File

@ -28,23 +28,60 @@
#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);
typedef void (*transfer_completion_cb)(usb_transfer_t*, 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);
void usb_transfer_schedule(
int usb_transfer_schedule(
const usb_endpoint_t* const endpoint,
void* const data,
const uint32_t maximum_length,
const transfer_completion_cb completion_cb
const transfer_completion_cb completion_cb,
void* const user_data
);
void usb_transfer_schedule_ack(
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(void);
void usb_queue_init(
usb_queue_t* const queue
);
void usb_queue_transfer_complete(
usb_endpoint_t* const endpoint

View File

@ -110,18 +110,19 @@ 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];
}
usb_transfer_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,
(uint8_t* const) descriptor_data,
(setup_length > descriptor_length) ? descriptor_length : setup_length,
NULL
NULL, NULL
);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
@ -140,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
) {
@ -150,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:
@ -161,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:
@ -269,7 +289,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(endpoint->in, &endpoint->buffer, 1, NULL);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
} else {

View File

@ -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 \

View File

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

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

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