Merge branch 'refs/heads/bgamari_usb_merge' into jboone_refactor_20130906
Conflicts: firmware/hackrf_usb/hackrf_usb.c
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
@ -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__
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
@ -459,7 +432,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 */
|
||||
@ -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,7 +456,7 @@ usb_request_status_t usb_vendor_request_read_spiflash(
|
||||
return USB_REQUEST_STATUS_STALL;
|
||||
} else
|
||||
{
|
||||
usb_endpoint_schedule_ack(endpoint->out);
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
} else
|
||||
@ -491,75 +465,13 @@ 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_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);
|
||||
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_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);
|
||||
|
||||
@ -821,7 +806,7 @@ int main(void) {
|
||||
|
||||
usb_run(&usb_device);
|
||||
|
||||
ssp1_init();
|
||||
ssp1_init();
|
||||
ssp1_set_mode_max5864();
|
||||
max5864_xcvr();
|
||||
|
||||
@ -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(
|
||||
(transceiver_mode == TRANSCEIVER_MODE_RX)
|
||||
? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out,
|
||||
&usb_td_bulk[0]
|
||||
);
|
||||
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.
|
||||
usb_endpoint_schedule_no_int(
|
||||
(transceiver_mode == TRANSCEIVER_MODE_RX)
|
||||
? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out,
|
||||
&usb_td_bulk[1]
|
||||
);
|
||||
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;
|
||||
|
@ -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
|
||||
) {
|
||||
@ -98,25 +91,25 @@ static void usb_clear_all_pending_interrupts() {
|
||||
static void usb_wait_for_endpoint_priming_to_finish(const uint32_t mask) {
|
||||
// Wait until controller has parsed new transfer descriptors and prepared
|
||||
// receive buffers.
|
||||
while( USB0_ENDPTPRIME & mask );
|
||||
while( USB0_ENDPTPRIME & mask );
|
||||
}
|
||||
|
||||
static void usb_flush_endpoints(const uint32_t mask) {
|
||||
// Clear any primed buffers. If a packet is in progress, that transfer
|
||||
// will continue until completion.
|
||||
USB0_ENDPTFLUSH = mask;
|
||||
USB0_ENDPTFLUSH = mask;
|
||||
}
|
||||
|
||||
static void usb_wait_for_endpoint_flushing_to_finish(const uint32_t mask) {
|
||||
// Wait until controller has flushed all endpoints / cleared any primed
|
||||
// buffers.
|
||||
while( USB0_ENDPTFLUSH & mask );
|
||||
while( USB0_ENDPTFLUSH & mask );
|
||||
}
|
||||
|
||||
static void usb_flush_primed_endpoints(const uint32_t mask) {
|
||||
usb_wait_for_endpoint_priming_to_finish(mask);
|
||||
usb_wait_for_endpoint_priming_to_finish(mask);
|
||||
usb_flush_endpoints(mask);
|
||||
usb_wait_for_endpoint_flushing_to_finish(mask);
|
||||
usb_wait_for_endpoint_flushing_to_finish(mask);
|
||||
}
|
||||
|
||||
static void usb_flush_all_primed_endpoints() {
|
||||
@ -171,6 +164,7 @@ void usb_endpoint_disable(
|
||||
} else {
|
||||
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_RXE);
|
||||
}
|
||||
usb_queue_flush_endpoint(endpoint);
|
||||
usb_endpoint_clear_pending_interrupts(endpoint);
|
||||
usb_endpoint_flush(endpoint);
|
||||
}
|
||||
@ -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,48 +550,13 @@ void usb_endpoint_init(
|
||||
usb_endpoint_enable(endpoint);
|
||||
}
|
||||
|
||||
void usb_endpoint_schedule(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
void* const data,
|
||||
const uint32_t maximum_length
|
||||
) {
|
||||
usb_transfer_descriptor_t* const td = usb_transfer_descriptor(endpoint->address);
|
||||
|
||||
// Ensure that endpoint is ready to be primed.
|
||||
// It may have been flushed due to an aborted transaction.
|
||||
// TODO: This should be preceded by a flush?
|
||||
while( usb_endpoint_is_ready(endpoint) );
|
||||
|
||||
// Configure a transfer.
|
||||
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||
td->total_bytes =
|
||||
USB_TD_DTD_TOKEN_TOTAL_BYTES(maximum_length)
|
||||
| USB_TD_DTD_TOKEN_IOC
|
||||
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||
| USB_TD_DTD_TOKEN_STATUS_ACTIVE
|
||||
;
|
||||
td->buffer_pointer_page[0] = (uint32_t)data;
|
||||
td->buffer_pointer_page[1] = ((uint32_t)data + 0x1000) & 0xfffff000;
|
||||
td->buffer_pointer_page[2] = ((uint32_t)data + 0x2000) & 0xfffff000;
|
||||
td->buffer_pointer_page[3] = ((uint32_t)data + 0x3000) & 0xfffff000;
|
||||
td->buffer_pointer_page[4] = ((uint32_t)data + 0x4000) & 0xfffff000;
|
||||
|
||||
usb_endpoint_prime(endpoint, td);
|
||||
}
|
||||
|
||||
void usb_endpoint_schedule_ack(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
usb_endpoint_schedule(endpoint, 0, 0);
|
||||
}
|
||||
|
||||
static void usb_check_for_setup_events() {
|
||||
const uint32_t endptsetupstat = usb_get_endpoint_setup_status();
|
||||
if( endptsetupstat ) {
|
||||
for( uint_fast8_t i=0; i<6; i++ ) {
|
||||
const uint32_t endptsetupstat_bit = USB0_ENDPTSETUPSTAT_ENDPTSETUPSTAT(1 << i);
|
||||
if( endptsetupstat & endptsetupstat_bit ) {
|
||||
usb_endpoint_t* const endpoint =
|
||||
usb_endpoint_t* const endpoint =
|
||||
usb_endpoint_from_address(
|
||||
usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
|
||||
);
|
||||
|
@ -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__
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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[];
|
||||
|
227
firmware/hackrf_usb/usb_queue.c
Normal file
227
firmware/hackrf_usb/usb_queue.c
Normal 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;
|
||||
}
|
||||
}
|
90
firmware/hackrf_usb/usb_queue.h
Normal file
90
firmware/hackrf_usb/usb_queue.h
Normal 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__
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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 \
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user