Project

General

Profile

Download (17.1 KB) Statistics
| Branch: | Tag: | Revision:
1 e81bf0ed Harald Welte
2
/* (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
3
 *
4
 * All Rights Reserved
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
#include <stdlib.h>
21
#include <stdint.h>
22
#include <errno.h>
23
24
#include <board.h>
25
#include <utility/trace.h>
26
#include <utility/led.h>
27
28
#include <usb/common/core/USBGenericRequest.h>
29
#include <usb/device/core/USBD.h>
30
#include <usb/device/core/USBDDriver.h>
31
#include <usb/device/core/USBDDriverDescriptors.h>
32
#include <usb/device/core/USBDCallbacks.h>
33
#include <usb/common/audio/AUDGenericRequest.h>
34
#include <usb/common/audio/AUDFeatureUnitRequest.h>
35 b6697b17 Harald Welte
#include <usb/common/audio/AUDFeatureUnitDescriptor.h>
36 f3f7a28c Christian Daniel
#include <common.h>
37 e81bf0ed Harald Welte
38
#include <fast_source_descr.h>
39
#include <fast_source.h>
40
41 f3f7a28c Christian Daniel
#include <tuner_e4k.h>
42
#include <si570.h>
43
#include <osdr_fpga.h>
44
45
#define OSMOSDR_CTRL_WRITE 0x07
46
#define OSMOSDR_CTRL_READ 0x87
47
48 e81bf0ed Harald Welte
extern const USBDDriverDescriptors auddFastSourceDriverDescriptors;
49 d7cc6950 Harald Welte
unsigned char fastsource_interfaces[3];
50 e81bf0ed Harald Welte
static USBDDriver fast_source_driver;
51
52 6d95768e Harald Welte
struct rctx_stats {
53
	uint32_t total;		/* total number of samples */
54
	uint32_t sum_ffff;	/* samples with I+Q = 0xffff */
55
	uint32_t sum_fffe;	/* samples with I+Q = 0xfffe */
56
	uint32_t sum_other;	/* samples with I+Q = something else */
57
58
	uint32_t delta_1;	/* delta of last I to current I == 1 */
59
	uint32_t delta_2;
60
	uint32_t delta_3;
61
	uint32_t delta_other;
62
};
63
64 e81bf0ed Harald Welte
struct usb_state {
65
	struct llist_head queue;
66
	int active;
67 b6697b17 Harald Welte
	uint8_t muted;
68 6d95768e Harald Welte
#ifdef FPGA_TEST_STATS
69
	struct rctx_stats stats;
70
#endif
71 e81bf0ed Harald Welte
};
72
static struct usb_state usb_state;
73
74
#define EP_NR 6
75
76
static void fastsource_get_feat_cur_val(uint8_t entity, uint8_t channel,
77
				   uint8_t control, uint8_t length)
78
{
79 b6697b17 Harald Welte
	TRACE_INFO("get_feat(E%u, CN%u, CS%u, L%u) ", entity, channel, control, length);
80
	if (channel == 0 && control == AUDFeatureUnitDescriptor_MUTE && length == 1)
81
		USBD_Write(0, &usb_state.muted, sizeof(usb_state.muted), 0, 0);
82
	else
83
		USBD_Stall(0);
84 e81bf0ed Harald Welte
}
85
86
static void fastsource_set_feat_cur_val(uint8_t entity, uint8_t channel,
87
				   uint8_t control, uint8_t length)
88
{
89 b6697b17 Harald Welte
	TRACE_INFO("set_feat(E%u, CO%u, CH%u, L%u) ", entity, channel, control, length);
90
	if (channel == 0 && control == AUDFeatureUnitDescriptor_MUTE && length == 1)
91
		USBD_Read(0, &usb_state.muted, sizeof(usb_state.muted), 0, 0);
92
	else
93
		USBD_Stall(0);
94 e81bf0ed Harald Welte
}
95
96 f3f7a28c Christian Daniel
static void handle_osmosdr_read(const USBGenericRequest* request)
97
{
98
	int len = USBGenericRequest_GetLength(request);
99
	printf("OsmoSDR GET request: type:%d, request:%d, value:%d, index: %d, length: %d\n\r",
100
		USBGenericRequest_GetType(request),
101
		USBGenericRequest_GetRequest(request),
102
		USBGenericRequest_GetValue(request),
103
		USBGenericRequest_GetIndex(request),
104
		len);
105
	USBD_Stall(0);
106
}
107
108
static uint32_t read_bytewise32(const uint8_t* data)
109
{
110
	return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
111
}
112
113 35355c70 Christian Daniel
static uint16_t read_bytewise16(const uint8_t* data)
114
{
115
	return (data[0] << 8) | data[1];
116
}
117
118 f3f7a28c Christian Daniel
typedef struct Request_ {
119
	uint16_t func;
120
	uint16_t len;
121
} Request;
122
123
#define FUNC(group, function) ((group << 8) | function)
124
125
#define GROUP_GENERAL 0x00
126
#define GROUP_FPGA_V2 0x01
127
#define GROUP_VCXO_SI570 0x02
128
#define GROUP_TUNER_E4K 0x03
129
130
const static Request g_writeRequests[] = {
131
	// general api
132
	{ FUNC(GROUP_GENERAL, 0x00), 0 }, // init whatever
133
	{ FUNC(GROUP_GENERAL, 0x01), 0 }, // power down
134
	{ FUNC(GROUP_GENERAL, 0x02), 0 }, // power up
135
136
	// fpga commands
137
	{ FUNC(GROUP_FPGA_V2, 0x00), 0 }, // fpga init
138
	{ FUNC(GROUP_FPGA_V2, 0x01), 5 }, // osdr_fpga_reg_write(uint8_t reg, uint32_t val)
139 35355c70 Christian Daniel
	{ FUNC(GROUP_FPGA_V2, 0x02), 1 }, // osdr_fpga_set_decimation(uint8_t val)
140
	{ FUNC(GROUP_FPGA_V2, 0x03), 1 }, // osdr_fpga_set_iq_swap(uint8_t val)
141
	{ FUNC(GROUP_FPGA_V2, 0x04), 4 }, // osdr_fpga_set_iq_gain(uint16_t igain, uint16_t qgain)
142
	{ FUNC(GROUP_FPGA_V2, 0x05), 4 }, // osdr_fpga_set_iq_ofs(int16_t iofs, int16_t qofs)
143 f3f7a28c Christian Daniel
144
	// si570 vcxo commads
145
	{ FUNC(GROUP_VCXO_SI570, 0x00), 0 }, // si570_init()
146
	{ FUNC(GROUP_VCXO_SI570, 0x01), 16 }, // si570_reg_write
147
	{ FUNC(GROUP_VCXO_SI570, 0x02), 8 }, // si570_set_freq(uint32_t freq, int trim);
148
149
	// e4000 tuner commands
150
	{ FUNC(GROUP_TUNER_E4K, 0x00), 0 }, // e4k_init()
151
	{ FUNC(GROUP_TUNER_E4K, 0x01), 0 }, // reg write
152 35355c70 Christian Daniel
	{ FUNC(GROUP_TUNER_E4K, 0x02), 5 }, // e4k_if_gain_set(uint8_t stage, int8_t value)
153 f3f7a28c Christian Daniel
	{ FUNC(GROUP_TUNER_E4K, 0x03), 1 }, // e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value)
154
	{ FUNC(GROUP_TUNER_E4K, 0x04), 1 }, // e4k_commonmode_set(int8_t value)
155
	{ FUNC(GROUP_TUNER_E4K, 0x05), 4 }, // e4k_tune_freq(uint32_t freq)
156
	{ FUNC(GROUP_TUNER_E4K, 0x06), 5 }, // e4k_if_filter_bw_set(enum e4k_if_filter filter, uint32_t bandwidth)
157
	{ FUNC(GROUP_TUNER_E4K, 0x07), 1 }, // e4k_if_filter_chan_enable(int on)
158
	{ FUNC(GROUP_TUNER_E4K, 0x08), 4 }, // e4k_manual_dc_offset(int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange)
159
	{ FUNC(GROUP_TUNER_E4K, 0x09), 0 }, // e4k_dc_offset_calibrate()
160
	{ FUNC(GROUP_TUNER_E4K, 0x0a), 0 }, // e4k_dc_offset_gen_table()
161
	{ FUNC(GROUP_TUNER_E4K, 0x0b), 4 }, // e4k_set_lna_gain(int32_t gain)
162
	{ FUNC(GROUP_TUNER_E4K, 0x0c), 1 }, // e4k_enable_manual_gain(uint8_t manual)
163
	{ FUNC(GROUP_TUNER_E4K, 0x0d), 4 }, // e4k_set_enh_gain(int32_t gain)
164
};
165
166
typedef struct WriteState_ {
167
	uint8_t data[16];
168
	uint16_t func;
169
} WriteState;
170
171
static WriteState g_writeState;
172
extern struct e4k_state e4k;
173
extern struct si570_ctx si570;
174
175
static void finalize_write(void *pArg, unsigned char status, unsigned int transferred, unsigned int remaining)
176
{
177
	int res;
178
179
	if((status != 0) ||(remaining != 0)) {
180
		USBD_Stall(0);
181
		return;
182
	}
183
184
	printf("Func: %04x ...", g_writeState.func);
185
186
	switch(g_writeState.func) {
187
		// general api
188
		case FUNC(GROUP_GENERAL, 0x00): // init all
189 83ebd2b3 Christian Daniel
			printf("general_init()");
190 f3f7a28c Christian Daniel
			res = 0; // no op so far
191
			break;
192
		case FUNC(GROUP_GENERAL, 0x01): // power down
193 83ebd2b3 Christian Daniel
			printf("general_power_down()");
194 f3f7a28c Christian Daniel
			osdr_fpga_power(0);
195
			sam3u_e4k_stby(&e4k, 1);
196
			sam3u_e4k_power(&e4k, 0);
197
			res = 0;
198
			break;
199
		case FUNC(GROUP_GENERAL, 0x02): // power up
200 83ebd2b3 Christian Daniel
			printf("general_power_up()");
201 f3f7a28c Christian Daniel
			osdr_fpga_power(1);
202
			sam3u_e4k_power(&e4k, 1);
203
			sam3u_e4k_stby(&e4k, 0);
204
			res = 0;
205
			break;
206
207
		// fpga commands
208
		case FUNC(GROUP_FPGA_V2, 0x00): // fpga init
209 83ebd2b3 Christian Daniel
			printf("fpga_v2_init()");
210 f3f7a28c Christian Daniel
			res = 0; // no op so far
211
			break;
212
		case FUNC(GROUP_FPGA_V2, 0x01):
213 83ebd2b3 Christian Daniel
			printf("fpga_v2_reg_write()");
214 f3f7a28c Christian Daniel
			osdr_fpga_reg_write(g_writeState.data[0], read_bytewise32(g_writeState.data + 1));
215
			res = 0;
216
			break;
217 35355c70 Christian Daniel
		case FUNC(GROUP_FPGA_V2, 0x02):
218
			printf("osdr_fpga_set_decimation()");
219
			osdr_fpga_set_decimation(g_writeState.data[0]);
220
			res = 0;
221
			break;
222
		case FUNC(GROUP_FPGA_V2, 0x03):
223
			printf("osdr_fpga_set_iq_swap()");
224
			osdr_fpga_set_iq_swap(g_writeState.data[0]);
225
			res = 0;
226
			break;
227
		case FUNC(GROUP_FPGA_V2, 0x04):
228
			printf("osdr_fpga_set_iq_gain()");
229
			osdr_fpga_set_iq_gain(read_bytewise16(g_writeState.data), read_bytewise16(g_writeState.data + 2));
230
			res = 0;
231
			break;
232
		case FUNC(GROUP_FPGA_V2, 0x05):
233
			printf("osdr_fpga_set_iq_ofs()");
234
			osdr_fpga_set_iq_ofs(read_bytewise16(g_writeState.data), read_bytewise16(g_writeState.data + 2));
235
			res = 0;
236
			break;
237 f3f7a28c Christian Daniel
238
		// si570 vcxo commands
239
		case FUNC(GROUP_VCXO_SI570, 0x00): // si570_init()
240 83ebd2b3 Christian Daniel
			printf("si570_init()");
241 f3f7a28c Christian Daniel
			res = si570_reinit(&si570);
242
			break;
243
		case FUNC(GROUP_VCXO_SI570, 0x01):
244 83ebd2b3 Christian Daniel
			printf("si570_reg_write()");
245 f3f7a28c Christian Daniel
			res = si570_reg_write(&si570, g_writeState.data[0], g_writeState.data[1], g_writeState.data + 2);
246
			break;
247
		case FUNC(GROUP_VCXO_SI570, 0x02):
248 83ebd2b3 Christian Daniel
			printf("si570_set_freq()");
249 f3f7a28c Christian Daniel
			res = si570_set_freq(&si570, read_bytewise32(g_writeState.data), read_bytewise32(g_writeState.data + 4));
250
			break;
251
252
		// e4000 tuner commands
253
		case FUNC(GROUP_TUNER_E4K, 0x00):
254 83ebd2b3 Christian Daniel
			printf("e4k_init()");
255 f3f7a28c Christian Daniel
			res = e4k_init(&e4k);
256
			break;
257
		case FUNC(GROUP_TUNER_E4K, 0x01): // reg write
258 83ebd2b3 Christian Daniel
			printf("e4k_reg_write()");
259
			res = -1;
260 f3f7a28c Christian Daniel
			break;
261
		case FUNC(GROUP_TUNER_E4K, 0x02):
262 83ebd2b3 Christian Daniel
			printf("e4k_if_gain_set()");
263 35355c70 Christian Daniel
			res = e4k_if_gain_set(&e4k, g_writeState.data[0], read_bytewise32(g_writeState.data + 1));
264 f3f7a28c Christian Daniel
			break;
265
		case FUNC(GROUP_TUNER_E4K, 0x03):
266 83ebd2b3 Christian Daniel
			printf("e4k_mixer_gain_set()");
267 f3f7a28c Christian Daniel
			res = e4k_mixer_gain_set(&e4k, g_writeState.data[0]);
268
			break;
269
		case FUNC(GROUP_TUNER_E4K, 0x04):
270 83ebd2b3 Christian Daniel
			printf("e4K_commonmode_set()");
271 f3f7a28c Christian Daniel
			res = e4k_commonmode_set(&e4k, g_writeState.data[0]);
272
			break;
273
		case FUNC(GROUP_TUNER_E4K, 0x05):
274 83ebd2b3 Christian Daniel
			printf("e4k_tune_freq()");
275 f3f7a28c Christian Daniel
			res = e4k_tune_freq(&e4k, read_bytewise32(g_writeState.data));
276
			break;
277
		case FUNC(GROUP_TUNER_E4K, 0x06):
278 83ebd2b3 Christian Daniel
			printf("e4k_if_filter_bw_set()");
279 f3f7a28c Christian Daniel
			res = e4k_if_filter_bw_set(&e4k, g_writeState.data[0], read_bytewise32(g_writeState.data + 1));
280
			break;
281
		case FUNC(GROUP_TUNER_E4K, 0x07):
282 83ebd2b3 Christian Daniel
			printf("e4k_if_filter_chan_enable()");
283 f3f7a28c Christian Daniel
			res = e4k_if_filter_chan_enable(&e4k, g_writeState.data[0]);
284
			break;
285
		case FUNC(GROUP_TUNER_E4K, 0x08):
286 83ebd2b3 Christian Daniel
			printf("e4k_manual_dc_offset()");
287 f3f7a28c Christian Daniel
			res = e4k_manual_dc_offset(&e4k, g_writeState.data[0], g_writeState.data[1], g_writeState.data[2], g_writeState.data[3]);
288
			break;
289
		case FUNC(GROUP_TUNER_E4K, 0x09):
290 83ebd2b3 Christian Daniel
			printf("e4k_dc_offset_calibrate()");
291 f3f7a28c Christian Daniel
			res = e4k_dc_offset_calibrate(&e4k);
292
			break;
293
		case FUNC(GROUP_TUNER_E4K, 0x0a):
294 83ebd2b3 Christian Daniel
			printf("e4k_dc_offset_gen_table()");
295 f3f7a28c Christian Daniel
			res = e4k_dc_offset_gen_table(&e4k);
296
			break;
297
		case FUNC(GROUP_TUNER_E4K, 0x0b):
298 83ebd2b3 Christian Daniel
			printf("e4k_set_lna_gain()");
299 f3f7a28c Christian Daniel
			res = e4k_set_lna_gain(&e4k, read_bytewise32(g_writeState.data));
300 35355c70 Christian Daniel
			if(res == -EINVAL)
301
				res = -1;
302
			else res = 0;
303 f3f7a28c Christian Daniel
			break;
304
		case FUNC(GROUP_TUNER_E4K, 0x0c):
305 83ebd2b3 Christian Daniel
			printf("e4k_enable_manual_gain()");
306 f3f7a28c Christian Daniel
			res = e4k_enable_manual_gain(&e4k, g_writeState.data[0]);
307
			break;
308
		case FUNC(GROUP_TUNER_E4K, 0x0d):
309 d8d2cfc7 Christian Daniel
			printf("e4k_set_enh_gain()");
310 f3f7a28c Christian Daniel
			res = e4k_set_enh_gain(&e4k, read_bytewise32(g_writeState.data));
311
			break;
312
313
		default:
314
			res = -1;
315
			break;
316
	}
317
318
	printf(" res: %d\n\r", res);
319
320
	if(res == 0)
321
		USBD_Write(0, 0, 0, 0, 0);
322
	else USBD_Stall(0);
323
}
324
325
static void handle_osmosdr_write(const USBGenericRequest* request)
326
{
327
	uint16_t func = USBGenericRequest_GetValue(request);
328
	int len = USBGenericRequest_GetLength(request);
329
	int i;
330 26bea49a Christian Daniel
/*
331 f3f7a28c Christian Daniel
	printf("OsmoSDR SET request: type:%d, request:%d, value:%04x, index: %04x, length: %d\n\r",
332
		USBGenericRequest_GetType(request),
333
		USBGenericRequest_GetRequest(request),
334
		USBGenericRequest_GetValue(request),
335
		USBGenericRequest_GetIndex(request),
336
		len);
337 26bea49a Christian Daniel
*/
338 f3f7a28c Christian Daniel
	for(i = 0; i < ARRAY_SIZE(g_writeRequests); i++) {
339
		if(g_writeRequests[i].func == func)
340
			break;
341
	}
342
	if(i == ARRAY_SIZE(g_writeRequests)) {
343
		USBD_Stall(0);
344
		return;
345
	}
346
	if(len != g_writeRequests[i].len) {
347
		USBD_Stall(0);
348
		return;
349
	}
350
351
	g_writeState.func = func;
352
353
	if(len > 0)
354
		USBD_Read(0, g_writeState.data, len, finalize_write, 0);
355
	else finalize_write(NULL, 0, 0, 0);
356
}
357
358 e81bf0ed Harald Welte
/* handler for EP0 (control) requests */
359
void fastsource_req_hdlr(const USBGenericRequest *request)
360
{
361
	unsigned char entity;
362
	unsigned char interface;
363
364
	switch (USBGenericRequest_GetType(request)) {
365
	case USBGenericRequest_STANDARD:
366
		USBDDriver_RequestHandler(&fast_source_driver, request);
367
		return;
368
	case USBGenericRequest_CLASS:
369
		/* continue below */
370
		break;
371 f3f7a28c Christian Daniel
	case USBGenericRequest_VENDOR:
372
		if(USBGenericRequest_GetRequest(request) == OSMOSDR_CTRL_WRITE)
373
			handle_osmosdr_write(request);
374
		else if(USBGenericRequest_GetRequest(request) == OSMOSDR_CTRL_READ)
375
			handle_osmosdr_read(request);
376
		else USBD_Stall(0);
377
		return;
378 e81bf0ed Harald Welte
	default:
379
		TRACE_WARNING("Unsupported request type %u\n\r",
380
				USBGenericRequest_GetType(request));
381
		USBD_Stall(0);
382
		return;
383
	}
384
385
	switch (USBGenericRequest_GetRequest(request)) {
386
	case AUDGenericRequest_SETCUR:
387
		entity = AUDGenericRequest_GetEntity(request);
388
		interface = AUDGenericRequest_GetInterface(request);
389
		if (((entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT) ||
390
		     (entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC)) &&
391
		    (interface == AUDDLoopRecDriverDescriptors_CONTROL)) {
392
			fastsource_set_feat_cur_val(entity,
393
				AUDFeatureUnitRequest_GetChannel(request),
394
				AUDFeatureUnitRequest_GetControl(request),
395
				USBGenericRequest_GetLength(request));
396
		} else {
397
			TRACE_WARNING("Unsupported entity/interface combination 0x%04x\n\r",
398
					USBGenericRequest_GetIndex(request));
399
			USBD_Stall(0);
400
		}
401
		break;
402
	case AUDGenericRequest_GETCUR:
403
		entity = AUDGenericRequest_GetEntity(request);
404
		interface = AUDGenericRequest_GetInterface(request);
405
		if (((entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT) ||
406
		     (entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC)) &&
407
		    (interface == AUDDLoopRecDriverDescriptors_CONTROL)) {
408
			fastsource_get_feat_cur_val(entity,
409
				AUDFeatureUnitRequest_GetChannel(request),
410
				AUDFeatureUnitRequest_GetControl(request),
411
				USBGenericRequest_GetLength(request));
412
		} else {
413
			TRACE_WARNING("Unsupported entity/interface combination 0x%04x\n\r",
414
					USBGenericRequest_GetIndex(request));
415
			USBD_Stall(0);
416
		}
417
		break;
418 f3f7a28c Christian Daniel
419 e81bf0ed Harald Welte
	default:
420
		TRACE_WARNING("Unsupported request %u\n\r",
421
				USBGenericRequest_GetIndex(request));
422
		USBD_Stall(0);
423
		break;
424
	}
425
}
426
427
/* Initialize the driver */
428
void fastsource_init(void)
429
{
430 6d95768e Harald Welte
	memset(&usb_state, 0, sizeof(usb_state));
431 f3f7a28c Christian Daniel
	memset(fastsource_interfaces, 0x00, sizeof(fastsource_interfaces));
432 6d95768e Harald Welte
433 e81bf0ed Harald Welte
	INIT_LLIST_HEAD(&usb_state.queue);
434
435
	USBDDriver_Initialize(&fast_source_driver, &auddFastSourceDriverDescriptors,
436 d7cc6950 Harald Welte
				fastsource_interfaces);
437 e81bf0ed Harald Welte
438
	USBD_Init();
439
}
440
441
static int refill_dma(void);
442
443
/* completion callback: USBD_Write() has completed an IN transfer */
444
static void wr_compl_cb(void *arg, unsigned char status, unsigned int transferred,
445
			unsigned int remain)
446
{
447
	struct req_ctx *rctx = arg;
448
449
	usb_state.active = 0;
450
451
	req_ctx_set_state(rctx, RCTX_STATE_FREE);
452
453
	if (status == 0 && remain == 0) {
454
		refill_dma();
455
	} else {
456
		TRACE_WARNING("Err: EP%u wr_compl, status 0x%02u, xfr %u, remain %u\r\n",
457
				EP_NR, status, transferred, remain);
458
	}
459
}
460
461
static int refill_dma(void)
462
{
463
	struct req_ctx *rctx;
464 f3f7a28c Christian Daniel
	int res;
465 e81bf0ed Harald Welte
466
	rctx = req_ctx_dequeue(&usb_state.queue);
467
	if (!rctx) {
468
		//TRACE_WARNING("No rctx for re-filling USB DMA\n\r");
469
		usb_state.active = 0;
470
		return -ENOENT;
471
	}
472
473
	req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_BUSY);
474
475 f3f7a28c Christian Daniel
	if ((res = USBD_Write(EP_NR, rctx->data, rctx->tot_len, wr_compl_cb, rctx)) != USBD_STATUS_SUCCESS) {
476
		TRACE_WARNING("USB EP busy while re-filling USB DMA: %d\n\r", res);
477
		req_ctx_set_state(rctx, RCTX_STATE_FREE);
478 e81bf0ed Harald Welte
		usb_state.active = 0;
479
		return -EBUSY;
480
	}
481
482
	usb_state.active = 1;
483
	return 0;
484
}
485
486
/* user API: requests us to start transmitting data via USB IN EP */
487
void fastsource_start(void)
488
{
489 f3f7a28c Christian Daniel
	if(USBD_GetState() != USBD_STATE_CONFIGURED)
490
		return;
491
492 1982ab41 Christian Daniel
	if (!usb_state.active)
493 e81bf0ed Harald Welte
		refill_dma();
494
}
495
496 6d95768e Harald Welte
/* Use every Nth sample for computing statistics.  At fpga.adc_clkdiv=2 we can
497
 * still do every sample (NTH=1) at 20MHz SSC clock.  Above that, we have to look
498
 * at a sub-set only and thus increase NTH */
499
#define NTH	8
500
501
/* iterate over all samples in a given rctx and generate statistics */
502
static void rctx_stats_add(struct req_ctx *rctx, struct rctx_stats *s)
503
{
504
	uint16_t *data16;
505
	int inited = 0;
506
507
	//for (data16 = rctx->data; data16 < rctx->data + rctx->tot_len; data16 += 2) {
508
	for (data16 = rctx->data; data16 < rctx->data + rctx->tot_len; data16 += NTH*2) {
509
		uint32_t sum = data16[0] + data16[1];
510
		uint16_t diff_i, diff_q, last_i, last_q;
511
512
		s->total++;
513
514
		switch (sum) {
515
		case 0xFFFF:
516
			s->sum_ffff++;
517
			break;
518
		case 0xFFFE:
519
			s->sum_fffe++;
520
			break;
521
		default:
522
			s->sum_other++;
523
			break;
524
		}
525
526
		if (inited) {
527
			diff_i = (uint16_t)(last_i - data16[0]);
528
			diff_q = (uint16_t)(last_q - data16[0]);
529
530
			switch (diff_i) {
531
			case 1*NTH:
532
				s->delta_1++;
533
				break;
534
			case 2*NTH:
535
				s->delta_2++;
536
				break;
537
			case 3*NTH:
538
				s->delta_3++;
539
				break;
540
			default:
541
				s->delta_other++;
542
			}
543
		}
544
545
		inited = 1;
546
		last_i = data16[0];
547
		last_q = data16[1];
548
	}
549
550
	if (s->total > 0xFFFF) {
551
		printf("%u (f=%u/e=%u/o=%u) (1=%u/2=%u/3=%u/o=%u)\n\r",
552
			s->total, s->sum_ffff, s->sum_fffe, s->sum_other,
553
			s->delta_1, s->delta_2, s->delta_3, s->delta_other);
554
		memset(s, 0, sizeof(*s));
555
	}
556
}
557
558 e81bf0ed Harald Welte
/* SSC DMA informs us about completion of filling one rctx */
559
void usb_submit_req_ctx(struct req_ctx *rctx)
560
{
561
	req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING);
562
563 6d95768e Harald Welte
#ifdef FPGA_TEST_STATS
564
	rctx_stats_add(rctx, &usb_state.stats);
565
#endif
566 e81bf0ed Harald Welte
	//TRACE_INFO("USB rctx enqueue (%08x, %u/%u)\n\r", rctx, rctx->size, rctx->tot_len);
567
	req_ctx_enqueue(&usb_state.queue, rctx);
568
569
	fastsource_start();
570
}
571
572
/* callback */
573
void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
574
{
575
	fastsource_req_hdlr(request);
576
}
577
578
void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface,
579
						 unsigned char setting)
580
{
581 b6697b17 Harald Welte
	printf("USB_IF_CHANGED(%u, %u)\n\r", interface, setting);
582 f3f7a28c Christian Daniel
583 5a23c521 Harald Welte
	if ((interface == AUDDLoopRecDriverDescriptors_STREAMINGIN)
584 e81bf0ed Harald Welte
	    && (setting == 0))
585
		LED_Clear(USBD_LEDOTHER);
586
	else
587
		LED_Set(USBD_LEDOTHER);
588
}
589 b93708ed Christian Daniel
590
void fastsource_dump(void)
591
{
592
	struct req_ctx *rctx, *rctx2;
593
594
	printf("usb pending:");
595
	llist_for_each_entry_safe(rctx, rctx2, &usb_state.queue, list)
596
		printf(" %02d", req_ctx_num(rctx));
597
	printf("\n\r");
598
}
Add picture from clipboard (Maximum size: 48.8 MB)