summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Daniel <cd@maintech.de>2012-05-26 22:19:49 +0200
committerChristian Daniel <cd@maintech.de>2012-05-26 22:19:49 +0200
commitf3f7a28cf80a99e99eec51cfe2a0013711bc0971 (patch)
treef7b36dae86e8e3dee38a845aced6150ed41270bb
parent65f6e41c566c7f1a19997015b243fa42d50e623e (diff)
add bulk mode and initial USB API
-rw-r--r--firmware/src/fast_source.c237
1 files changed, 232 insertions, 5 deletions
diff --git a/firmware/src/fast_source.c b/firmware/src/fast_source.c
index 9ebcf1d..a47576c 100644
--- a/firmware/src/fast_source.c
+++ b/firmware/src/fast_source.c
@@ -17,7 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
@@ -34,11 +33,18 @@
#include <usb/common/audio/AUDGenericRequest.h>
#include <usb/common/audio/AUDFeatureUnitRequest.h>
#include <usb/common/audio/AUDFeatureUnitDescriptor.h>
-
+#include <common.h>
#include <fast_source_descr.h>
#include <fast_source.h>
+#include <tuner_e4k.h>
+#include <si570.h>
+#include <osdr_fpga.h>
+
+#define OSMOSDR_CTRL_WRITE 0x07
+#define OSMOSDR_CTRL_READ 0x87
+
extern const USBDDriverDescriptors auddFastSourceDriverDescriptors;
unsigned char fastsource_interfaces[3];
static USBDDriver fast_source_driver;
@@ -87,6 +93,213 @@ static void fastsource_set_feat_cur_val(uint8_t entity, uint8_t channel,
USBD_Stall(0);
}
+static void handle_osmosdr_read(const USBGenericRequest* request)
+{
+ int len = USBGenericRequest_GetLength(request);
+ printf("OsmoSDR GET request: type:%d, request:%d, value:%d, index: %d, length: %d\n\r",
+ USBGenericRequest_GetType(request),
+ USBGenericRequest_GetRequest(request),
+ USBGenericRequest_GetValue(request),
+ USBGenericRequest_GetIndex(request),
+ len);
+ USBD_Stall(0);
+}
+
+static uint32_t read_bytewise32(const uint8_t* data)
+{
+ return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+}
+
+typedef struct Request_ {
+ uint16_t func;
+ uint16_t len;
+} Request;
+
+#define FUNC(group, function) ((group << 8) | function)
+
+#define GROUP_GENERAL 0x00
+#define GROUP_FPGA_V2 0x01
+#define GROUP_VCXO_SI570 0x02
+#define GROUP_TUNER_E4K 0x03
+
+const static Request g_writeRequests[] = {
+ // general api
+ { FUNC(GROUP_GENERAL, 0x00), 0 }, // init whatever
+ { FUNC(GROUP_GENERAL, 0x01), 0 }, // power down
+ { FUNC(GROUP_GENERAL, 0x02), 0 }, // power up
+
+ // fpga commands
+ { FUNC(GROUP_FPGA_V2, 0x00), 0 }, // fpga init
+ { FUNC(GROUP_FPGA_V2, 0x01), 5 }, // osdr_fpga_reg_write(uint8_t reg, uint32_t val)
+
+ // si570 vcxo commads
+ { FUNC(GROUP_VCXO_SI570, 0x00), 0 }, // si570_init()
+ { FUNC(GROUP_VCXO_SI570, 0x01), 16 }, // si570_reg_write
+ { FUNC(GROUP_VCXO_SI570, 0x02), 8 }, // si570_set_freq(uint32_t freq, int trim);
+
+ // e4000 tuner commands
+ { FUNC(GROUP_TUNER_E4K, 0x00), 0 }, // e4k_init()
+ { FUNC(GROUP_TUNER_E4K, 0x01), 0 }, // reg write
+ { FUNC(GROUP_TUNER_E4K, 0x02), 2 }, // e4k_if_gain_set(uint8_t stage, int8_t value)
+ { FUNC(GROUP_TUNER_E4K, 0x03), 1 }, // e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value)
+ { FUNC(GROUP_TUNER_E4K, 0x04), 1 }, // e4k_commonmode_set(int8_t value)
+ { FUNC(GROUP_TUNER_E4K, 0x05), 4 }, // e4k_tune_freq(uint32_t freq)
+ { FUNC(GROUP_TUNER_E4K, 0x06), 5 }, // e4k_if_filter_bw_set(enum e4k_if_filter filter, uint32_t bandwidth)
+ { FUNC(GROUP_TUNER_E4K, 0x07), 1 }, // e4k_if_filter_chan_enable(int on)
+ { FUNC(GROUP_TUNER_E4K, 0x08), 4 }, // e4k_manual_dc_offset(int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange)
+ { FUNC(GROUP_TUNER_E4K, 0x09), 0 }, // e4k_dc_offset_calibrate()
+ { FUNC(GROUP_TUNER_E4K, 0x0a), 0 }, // e4k_dc_offset_gen_table()
+ { FUNC(GROUP_TUNER_E4K, 0x0b), 4 }, // e4k_set_lna_gain(int32_t gain)
+ { FUNC(GROUP_TUNER_E4K, 0x0c), 1 }, // e4k_enable_manual_gain(uint8_t manual)
+ { FUNC(GROUP_TUNER_E4K, 0x0d), 4 }, // e4k_set_enh_gain(int32_t gain)
+};
+
+typedef struct WriteState_ {
+ uint8_t data[16];
+ uint16_t func;
+} WriteState;
+
+static WriteState g_writeState;
+extern struct e4k_state e4k;
+extern struct si570_ctx si570;
+
+static void finalize_write(void *pArg, unsigned char status, unsigned int transferred, unsigned int remaining)
+{
+ int res;
+
+ if((status != 0) ||(remaining != 0)) {
+ USBD_Stall(0);
+ return;
+ }
+
+ printf("Func: %04x ...", g_writeState.func);
+
+ switch(g_writeState.func) {
+ // general api
+ case FUNC(GROUP_GENERAL, 0x00): // init all
+ res = 0; // no op so far
+ break;
+ case FUNC(GROUP_GENERAL, 0x01): // power down
+ osdr_fpga_power(0);
+ sam3u_e4k_stby(&e4k, 1);
+ sam3u_e4k_power(&e4k, 0);
+ res = 0;
+ break;
+ case FUNC(GROUP_GENERAL, 0x02): // power up
+ osdr_fpga_power(1);
+ sam3u_e4k_power(&e4k, 1);
+ sam3u_e4k_stby(&e4k, 0);
+ res = 0;
+ break;
+
+ // fpga commands
+ case FUNC(GROUP_FPGA_V2, 0x00): // fpga init
+ res = 0; // no op so far
+ break;
+ case FUNC(GROUP_FPGA_V2, 0x01):
+ osdr_fpga_reg_write(g_writeState.data[0], read_bytewise32(g_writeState.data + 1));
+ res = 0;
+ break;
+
+ // si570 vcxo commands
+ case FUNC(GROUP_VCXO_SI570, 0x00): // si570_init()
+ res = si570_reinit(&si570);
+ break;
+ case FUNC(GROUP_VCXO_SI570, 0x01):
+ res = si570_reg_write(&si570, g_writeState.data[0], g_writeState.data[1], g_writeState.data + 2);
+ break;
+ case FUNC(GROUP_VCXO_SI570, 0x02):
+ res = si570_set_freq(&si570, read_bytewise32(g_writeState.data), read_bytewise32(g_writeState.data + 4));
+ break;
+
+ // e4000 tuner commands
+ case FUNC(GROUP_TUNER_E4K, 0x00):
+ res = e4k_init(&e4k);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x01): // reg write
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x02):
+ res = e4k_if_gain_set(&e4k, g_writeState.data[0], g_writeState.data[1]);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x03):
+ res = e4k_mixer_gain_set(&e4k, g_writeState.data[0]);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x04):
+ res = e4k_commonmode_set(&e4k, g_writeState.data[0]);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x05):
+ res = e4k_tune_freq(&e4k, read_bytewise32(g_writeState.data));
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x06):
+ res = e4k_if_filter_bw_set(&e4k, g_writeState.data[0], read_bytewise32(g_writeState.data + 1));
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x07):
+ res = e4k_if_filter_chan_enable(&e4k, g_writeState.data[0]);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x08):
+ res = e4k_manual_dc_offset(&e4k, g_writeState.data[0], g_writeState.data[1], g_writeState.data[2], g_writeState.data[3]);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x09):
+ res = e4k_dc_offset_calibrate(&e4k);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x0a):
+ res = e4k_dc_offset_gen_table(&e4k);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x0b):
+ res = e4k_set_lna_gain(&e4k, read_bytewise32(g_writeState.data));
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x0c):
+ res = e4k_enable_manual_gain(&e4k, g_writeState.data[0]);
+ break;
+ case FUNC(GROUP_TUNER_E4K, 0x0d):
+ res = e4k_set_enh_gain(&e4k, read_bytewise32(g_writeState.data));
+ break;
+
+ default:
+ res = -1;
+ break;
+ }
+
+ printf(" res: %d\n\r", res);
+
+ if(res == 0)
+ USBD_Write(0, 0, 0, 0, 0);
+ else USBD_Stall(0);
+}
+
+static void handle_osmosdr_write(const USBGenericRequest* request)
+{
+ uint16_t func = USBGenericRequest_GetValue(request);
+ int len = USBGenericRequest_GetLength(request);
+ int i;
+
+ printf("OsmoSDR SET request: type:%d, request:%d, value:%04x, index: %04x, length: %d\n\r",
+ USBGenericRequest_GetType(request),
+ USBGenericRequest_GetRequest(request),
+ USBGenericRequest_GetValue(request),
+ USBGenericRequest_GetIndex(request),
+ len);
+
+ for(i = 0; i < ARRAY_SIZE(g_writeRequests); i++) {
+ if(g_writeRequests[i].func == func)
+ break;
+ }
+ if(i == ARRAY_SIZE(g_writeRequests)) {
+ USBD_Stall(0);
+ return;
+ }
+ if(len != g_writeRequests[i].len) {
+ USBD_Stall(0);
+ return;
+ }
+
+ g_writeState.func = func;
+
+ if(len > 0)
+ USBD_Read(0, g_writeState.data, len, finalize_write, 0);
+ else finalize_write(NULL, 0, 0, 0);
+}
+
/* handler for EP0 (control) requests */
void fastsource_req_hdlr(const USBGenericRequest *request)
{
@@ -100,6 +313,13 @@ void fastsource_req_hdlr(const USBGenericRequest *request)
case USBGenericRequest_CLASS:
/* continue below */
break;
+ case USBGenericRequest_VENDOR:
+ if(USBGenericRequest_GetRequest(request) == OSMOSDR_CTRL_WRITE)
+ handle_osmosdr_write(request);
+ else if(USBGenericRequest_GetRequest(request) == OSMOSDR_CTRL_READ)
+ handle_osmosdr_read(request);
+ else USBD_Stall(0);
+ return;
default:
TRACE_WARNING("Unsupported request type %u\n\r",
USBGenericRequest_GetType(request));
@@ -140,6 +360,7 @@ void fastsource_req_hdlr(const USBGenericRequest *request)
USBD_Stall(0);
}
break;
+
default:
TRACE_WARNING("Unsupported request %u\n\r",
USBGenericRequest_GetIndex(request));
@@ -152,6 +373,7 @@ void fastsource_req_hdlr(const USBGenericRequest *request)
void fastsource_init(void)
{
memset(&usb_state, 0, sizeof(usb_state));
+ memset(fastsource_interfaces, 0x00, sizeof(fastsource_interfaces));
INIT_LLIST_HEAD(&usb_state.queue);
@@ -184,6 +406,7 @@ static void wr_compl_cb(void *arg, unsigned char status, unsigned int transferre
static int refill_dma(void)
{
struct req_ctx *rctx;
+ int res;
rctx = req_ctx_dequeue(&usb_state.queue);
if (!rctx) {
@@ -194,9 +417,9 @@ static int refill_dma(void)
req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_BUSY);
- if (USBD_Write(EP_NR, rctx->data, rctx->tot_len, wr_compl_cb,
- rctx) != USBD_STATUS_SUCCESS) {
- TRACE_WARNING("USB EP busy while re-filling USB DMA\n\r");
+ if ((res = USBD_Write(EP_NR, rctx->data, rctx->tot_len, wr_compl_cb, rctx)) != USBD_STATUS_SUCCESS) {
+ TRACE_WARNING("USB EP busy while re-filling USB DMA: %d\n\r", res);
+ req_ctx_set_state(rctx, RCTX_STATE_FREE);
usb_state.active = 0;
return -EBUSY;
}
@@ -208,6 +431,9 @@ static int refill_dma(void)
/* user API: requests us to start transmitting data via USB IN EP */
void fastsource_start(void)
{
+ if(USBD_GetState() != USBD_STATE_CONFIGURED)
+ return;
+
if (!usb_state.active) {
usb_state.active = 1;
refill_dma();
@@ -300,6 +526,7 @@ void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface,
unsigned char setting)
{
printf("USB_IF_CHANGED(%u, %u)\n\r", interface, setting);
+
if ((interface == AUDDLoopRecDriverDescriptors_STREAMINGIN)
&& (setting == 0))
LED_Clear(USBD_LEDOTHER);