forked from PAWPAW-Mirror/lib_xua
First commit
This commit is contained in:
1
module_usb_aud_shared/README
Normal file
1
module_usb_aud_shared/README
Normal file
@@ -0,0 +1 @@
|
||||
Shared USB Audio Files
|
||||
18
module_usb_aud_shared/audio.h
Normal file
18
module_usb_aud_shared/audio.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef __audio_h__
|
||||
#define __audio_h__
|
||||
|
||||
/** The audio driver thread.
|
||||
*
|
||||
* This function drives I2S ports and handles samples to/from other digital
|
||||
* I/O threads.
|
||||
*
|
||||
* \param c_in Audio sample channel connected to the mixer() thread or the
|
||||
* decouple() thread
|
||||
* \param c_dig channel connected to the clockGen() thread for
|
||||
* receiving/transmitting samples
|
||||
* \param c_config An optional channel that will be passed on to the
|
||||
* CODEC configuration functions.
|
||||
*/
|
||||
void audio(chanend c_in, chanend ?c_dig, chanend ?c_config);
|
||||
|
||||
#endif // __audio_h__
|
||||
621
module_usb_aud_shared/audio.xc
Executable file
621
module_usb_aud_shared/audio.xc
Executable file
@@ -0,0 +1,621 @@
|
||||
/**
|
||||
* @file audio.xc
|
||||
* @brief XMOS L1/L2 USB 2,0 Audio Reference Design. Audio Functions.
|
||||
* @author Ross Owen, XMOS Semiconductor Ltd
|
||||
*
|
||||
* This thread handles I2S and pars an additional SPDIF Tx thread. It forwards samples to the SPDIF Tx thread.
|
||||
* Additionally this thread handles clocking and CODEC/DAC/ADC config.
|
||||
**/
|
||||
|
||||
#include <syscall.h>
|
||||
#include <platform.h>
|
||||
#include <xs1.h>
|
||||
#include <xclib.h>
|
||||
#include <print.h>
|
||||
|
||||
#include "clocking.h"
|
||||
#include "audioports.h"
|
||||
#include "codec.h"
|
||||
#include "devicedefines.h"
|
||||
#include "SpdifTransmit.h"
|
||||
|
||||
//#define RAMP_CHECK 1
|
||||
|
||||
//#pragma xta command "analyse path i2s_output_l i2s_output_r"
|
||||
//#pragma xta command "set required - 2000 ns"
|
||||
|
||||
//#pragma xta command "analyse path i2s_output_r i2s_output_l"
|
||||
//#pragma xta command "set required - 2000 ns"
|
||||
|
||||
/* I2S Data I/O*/
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
extern buffered out port:32 p_i2s_dac[I2S_WIRES_DAC];
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC];
|
||||
#endif
|
||||
|
||||
/* I2S LR/Bit clock I/O */
|
||||
#ifdef CODEC_SLAVE
|
||||
extern buffered out port:32 p_lrclk;
|
||||
extern buffered out port:32 p_bclk;
|
||||
#else
|
||||
extern in port p_lrclk;
|
||||
extern in port p_bclk;
|
||||
#endif
|
||||
|
||||
/* Master clock input */
|
||||
extern port p_mclk;
|
||||
|
||||
#ifdef SPDIF
|
||||
extern buffered out port:32 p_spdif_tx;
|
||||
#endif
|
||||
|
||||
extern clock clk_audio_mclk;
|
||||
extern clock clk_audio_bclk;
|
||||
extern clock clk_mst_spd;
|
||||
|
||||
extern void device_reboot(void);
|
||||
|
||||
/* I2S delivery thread */
|
||||
#pragma unsafe arrays
|
||||
unsigned deliver(chanend c_out, chanend c_spd_out, unsigned divide, chanend ?c_dig_rx)
|
||||
{
|
||||
unsigned sample;
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
unsigned samplesOut[NUM_USB_CHAN_OUT];
|
||||
#endif
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
unsigned samplesIn[NUM_USB_CHAN_IN];
|
||||
unsigned samplesInPrev[NUM_USB_CHAN_IN];
|
||||
#endif
|
||||
unsigned tmp;
|
||||
unsigned index;
|
||||
#ifdef RAMP_CHECK
|
||||
unsigned prev=0;
|
||||
int started = 0;
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
samplesIn[i] = 0;
|
||||
samplesInPrev[i] = 0;
|
||||
}
|
||||
#endif
|
||||
outuint(c_out, 0);
|
||||
|
||||
/* Check for sample freq change or new samples from mixer*/
|
||||
if(testct(c_out))
|
||||
{
|
||||
inct(c_out);
|
||||
return inuint(c_out);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef MIXER // Interfaces straight to decouple()
|
||||
(void) inuint(c_out);
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, samplesIn[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
samplesOut[i] = inuint(c_out);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int tmp = inuint(c_out);
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
tmp<<=3;
|
||||
#endif
|
||||
samplesOut[i] = tmp;
|
||||
}
|
||||
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, samplesIn[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CODEC_SLAVE
|
||||
/* Clear I2S port buffers */
|
||||
clearbuf(p_lrclk);
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
clearbuf(p_i2s_dac[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
clearbuf(p_i2s_adc[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(divide == 1)
|
||||
{
|
||||
p_lrclk <: 0 @ tmp;
|
||||
tmp += 30;
|
||||
|
||||
/* Prefill the ports so data starts to be input */
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
p_lrclk @ tmp <: 0x7FFFFFFF;
|
||||
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
p_i2s_adc[0] @ (tmp - 1) :> void;
|
||||
#endif
|
||||
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
clearbuf(p_i2s_adc[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
clearbuf(p_bclk);
|
||||
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
/* Prefill the ports so data is input in advance */
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
p_i2s_dac[i] <: 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
p_lrclk <: 0x7FFFFFFF;
|
||||
p_bclk <: 0xAAAAAAAA;
|
||||
p_bclk <: 0xAAAAAAAA;
|
||||
}
|
||||
#else
|
||||
/* CODEC is master */
|
||||
/* Wait for LRCLK edge */
|
||||
p_lrclk when pinseq(0) :> void;
|
||||
p_lrclk when pinseq(1) :> void;
|
||||
p_lrclk when pinseq(0) :> void;
|
||||
p_lrclk when pinseq(1) :> void;
|
||||
p_lrclk when pinseq(0) :> void @ tmp;
|
||||
tmp += 33;
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
p_i2s_adc[0] @ tmp - 1 :> void;
|
||||
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
clearbuf(p_i2s_adc[i]);
|
||||
}
|
||||
|
||||
/* TODO In master mode, the i/o loop assumes L/RCLK = 32bit clocks. We should check this every interation
|
||||
* and resync if we got a bclk glitch */
|
||||
|
||||
#endif
|
||||
|
||||
/* Main Audio I/O loop */
|
||||
while (1)
|
||||
{
|
||||
outuint(c_out, 0);
|
||||
|
||||
/* Check for sample freq change or new samples from mixer*/
|
||||
if(testct(c_out))
|
||||
{
|
||||
inct(c_out);
|
||||
return inuint(c_out);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef MIXER // Interfaces straight to decouple()
|
||||
(void) inuint(c_out);
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, samplesIn[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
samplesOut[i] = inuint(c_out);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int tmp = inuint(c_out);
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
tmp<<=3;
|
||||
#endif
|
||||
samplesOut[i] = tmp;
|
||||
}
|
||||
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, samplesIn[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
inuint(c_dig_rx);
|
||||
#endif
|
||||
#ifdef SPDIF_RX
|
||||
asm("ldw %0, dp[g_digData]":"=r"(samplesIn[SPDIF_RX_INDEX + 0]));
|
||||
asm("ldw %0, dp[g_digData+4]":"=r"(samplesIn[SPDIF_RX_INDEX + 1]));
|
||||
|
||||
#endif
|
||||
#ifdef ADAT_RX
|
||||
asm("ldw %0, dp[g_digData+8]":"=r"(samplesIn[ADAT_RX_INDEX + 0]));
|
||||
asm("ldw %0, dp[g_digData+12]":"=r"(samplesIn[ADAT_RX_INDEX+ 1]));
|
||||
asm("ldw %0, dp[g_digData+16]":"=r"(samplesIn[ADAT_RX_INDEX + 2]));
|
||||
asm("ldw %0, dp[g_digData+20]":"=r"(samplesIn[ADAT_RX_INDEX + 3]));
|
||||
asm("ldw %0, dp[g_digData+24]":"=r"(samplesIn[ADAT_RX_INDEX + 4]));
|
||||
asm("ldw %0, dp[g_digData+28]":"=r"(samplesIn[ADAT_RX_INDEX + 5]));
|
||||
asm("ldw %0, dp[g_digData+32]":"=r"(samplesIn[ADAT_RX_INDEX + 6]));
|
||||
asm("ldw %0, dp[g_digData+36]":"=r"(samplesIn[ADAT_RX_INDEX + 7]));
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
/* Request digital data (with prefill) */
|
||||
outuint(c_dig_rx, 0);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
tmp = 0;
|
||||
|
||||
#pragma xta endpoint "i2s_output_l"
|
||||
|
||||
#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0)
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_CHANS_DAC; i+=2)
|
||||
{
|
||||
p_i2s_dac[tmp++] <: bitrev(samplesOut[i]); /* Output LEFT sample to DAC */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_SLAVE
|
||||
/* Generate clocks LR Clock low - LEFT */
|
||||
switch (divide)
|
||||
{
|
||||
case 8:
|
||||
|
||||
/* LR clock delayed by one clock, This is so MSB is output on the falling edge of BCLK
|
||||
* after the falling edge on which LRCLK was toggled. (see I2S spec) */
|
||||
p_lrclk <: 0x80000000;
|
||||
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
p_lrclk <: 0x80000000;
|
||||
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
p_lrclk <: 0x80000000;
|
||||
|
||||
p_bclk <: 0xAAAAAAAA;
|
||||
p_bclk <: 0xAAAAAAAA;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
p_lrclk <: 0x80000000;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
/* Input prevous R sample into R in buffer */
|
||||
index = 0;
|
||||
#pragma loop unroll
|
||||
for(int i = 1; i < I2S_CHANS_ADC; i += 2)
|
||||
{
|
||||
p_i2s_adc[index++] :> sample;
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
samplesIn[i] = bitrev(sample);
|
||||
|
||||
/* Store the previous left in left */
|
||||
samplesIn[i-1] = samplesInPrev[i];
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF) && (NUM_USB_CHAN_OUT > 0)
|
||||
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to SPDIF txt thread */
|
||||
sample = samplesOut[SPDIF_TX_INDEX + 1];
|
||||
outuint(c_spd_out, sample); /* Forward sample to SPDIF txt thread */
|
||||
#ifdef RAMP_CHECK
|
||||
sample >>= 8;
|
||||
if (started<10000) {
|
||||
if (sample == prev+1)
|
||||
started++;
|
||||
}
|
||||
else
|
||||
if (sample != prev+1 && sample != 0) {
|
||||
printintln(prev);
|
||||
printintln(sample);
|
||||
printintln(prev-sample+1);
|
||||
}
|
||||
prev = sample;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
tmp = 0;
|
||||
#pragma xta endpoint "i2s_output_r"
|
||||
#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0)
|
||||
#pragma loop unroll
|
||||
for(int i = 1; i < I2S_CHANS_DAC; i+=2)
|
||||
{
|
||||
p_i2s_dac[tmp++] <: bitrev(samplesOut[i]); /* Output RIGHT sample to DAC */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_SLAVE
|
||||
/* Clock out data (and LR clock) */
|
||||
switch (divide)
|
||||
{
|
||||
case 8:
|
||||
p_lrclk <: 0x7FFFFFFF;
|
||||
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
p_bclk <: 0xF0F0F0F0;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
p_lrclk <: 0x7FFFFFFF;
|
||||
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
p_bclk <: 0xCCCCCCCC;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
p_lrclk <: 0x7FFFFFFF;
|
||||
|
||||
p_bclk <: 0xAAAAAAAA;
|
||||
p_bclk <: 0xAAAAAAAA;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
p_lrclk <: 0x7FFFFFFF;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
/* Input previous L ADC sample */
|
||||
index = 0;
|
||||
#pragma loop unroll
|
||||
for(int i = 1; i < I2S_CHANS_ADC; i += 2)
|
||||
{
|
||||
p_i2s_adc[index++] :> sample;
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
samplesInPrev[i] = bitrev(sample);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is a dummy version of the deliver thread that does not
|
||||
connect to the codec ports. It is used during DFU reset. */
|
||||
static unsigned dummy_deliver(chanend c_out) {
|
||||
while (1)
|
||||
{
|
||||
outuint(c_out, 0);
|
||||
|
||||
/* Check for sample freq change or new samples from mixer*/
|
||||
if(testct(c_out))
|
||||
{
|
||||
inct(c_out);
|
||||
return inuint(c_out);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef MIXER // Interfaces straight to decouple()
|
||||
(void) inuint(c_out);
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, 0);
|
||||
}
|
||||
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
(void) inuint(c_out);
|
||||
}
|
||||
#else
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
(void) inuint(c_out);
|
||||
}
|
||||
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio(chanend c_mix_out, chanend ?c_dig_rx, chanend ?c_config)
|
||||
{
|
||||
chan c_spdif_out;
|
||||
unsigned curSamFreq = DEFAULT_FREQ;
|
||||
unsigned mClk;
|
||||
unsigned divide;
|
||||
unsigned firstRun = 1;
|
||||
|
||||
#ifdef SPDIF
|
||||
SpdifTransmitPortConfig(p_spdif_tx, clk_mst_spd, p_mclk);
|
||||
#endif
|
||||
|
||||
/* Initialise master clock generation */
|
||||
ClockingInit();
|
||||
|
||||
/* Perform required CODEC/ADC/DAC initialisation */
|
||||
CodecInit(c_config);
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Calculate what master clock we should be using */
|
||||
if ((curSamFreq % 22050) == 0)
|
||||
{
|
||||
mClk = MCLK_441;
|
||||
}
|
||||
else if ((curSamFreq % 24000) == 0)
|
||||
{
|
||||
mClk = MCLK_48;
|
||||
}
|
||||
|
||||
/* Calculate divide required for bit clock e.g. 11.289600 / (176400 * 64) = 1 */
|
||||
divide = mClk / ( curSamFreq * 64 );
|
||||
|
||||
/* Configure clocking for required master clock */
|
||||
ClockingConfig(mClk);
|
||||
|
||||
if(!firstRun)
|
||||
{
|
||||
/* TODO wait for good mclk instead of delay */
|
||||
/* No delay for DFU modes */
|
||||
if ((curSamFreq != AUDIO_REBOOT_FROM_DFU) && (curSamFreq != AUDIO_STOP_FOR_DFU))
|
||||
{
|
||||
timer t;
|
||||
unsigned time;
|
||||
t :> time;
|
||||
t when timerafter(time+AUDIO_PLL_LOCK_DELAY) :> void;
|
||||
|
||||
/* Handshake back */
|
||||
outct(c_mix_out, XS1_CT_END);
|
||||
}
|
||||
}
|
||||
firstRun = 0;
|
||||
|
||||
/* Configure CODEC/DAC/ADC for SampleFreq/MClk */
|
||||
CodecConfig(curSamFreq, mClk, c_config);
|
||||
|
||||
/* Configure audio ports */
|
||||
ConfigAudioPorts(divide);
|
||||
|
||||
par
|
||||
{
|
||||
|
||||
#ifdef SPDIF
|
||||
{ //set_thread_fast_mode_on();
|
||||
SpdifTransmit(p_spdif_tx, c_spdif_out);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
#ifdef SPDIF
|
||||
/* Communicate master clock and sample freq to S/PDIF thread */
|
||||
outuint(c_spdif_out, curSamFreq);
|
||||
outuint(c_spdif_out, mClk);
|
||||
#endif
|
||||
|
||||
curSamFreq = deliver(c_mix_out, c_spdif_out, divide, c_dig_rx);
|
||||
|
||||
// Currently no more audio will happen after this point
|
||||
if (curSamFreq == AUDIO_STOP_FOR_DFU)
|
||||
{
|
||||
outct(c_mix_out, XS1_CT_END);
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
curSamFreq = dummy_deliver(c_mix_out);
|
||||
|
||||
if (curSamFreq == AUDIO_START_FROM_DFU)
|
||||
{
|
||||
outct(c_mix_out, XS1_CT_END);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef SPDIF
|
||||
/* Notify S/PDIF thread of impending new freq... */
|
||||
outct(c_spdif_out, XS1_CT_END);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
module_usb_aud_shared/audiostream/audiostream.h
Normal file
17
module_usb_aud_shared/audiostream/audiostream.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef _AUDIOSTREAM_H_
|
||||
#define _AUDIOSTREAM_H_
|
||||
|
||||
/* Functions that handle functions that must occur on stream start/stop e.g. DAC mute/un-mute
|
||||
*
|
||||
* THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN
|
||||
*
|
||||
* */
|
||||
|
||||
/* Any actions required for stream start e.g. DAC un-mute - run every stream start */
|
||||
void AudioStreamStart(void);
|
||||
|
||||
/* Any actions required on stream stop e.g. DAC mute - run every steam stop */
|
||||
void AudioStreamStop(void);
|
||||
|
||||
#endif
|
||||
|
||||
30
module_usb_aud_shared/clockcmds.h
Normal file
30
module_usb_aud_shared/clockcmds.h
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
#include "devicedefines.h"
|
||||
|
||||
/* Clocking commands - c_clk_ctl */
|
||||
#define GET_SEL 0 /* Get value of clock selector */
|
||||
#define SET_SEL 1 /* Set value of clock selector */
|
||||
#define GET_FREQ 2 /* Get current freq */
|
||||
#define GET_VALID 3 /* Get current validity */
|
||||
|
||||
#define CLOCK_INTERNAL 1
|
||||
#define CLOCK_SPDIF 2
|
||||
#ifdef SPDIF_RX
|
||||
#define CLOCK_ADAT 3
|
||||
#else
|
||||
#define CLOCK_ADAT 2
|
||||
#endif
|
||||
|
||||
#define CLOCK_INTERNAL_INDEX (CLOCK_INTERNAL - 1)
|
||||
#define CLOCK_ADAT_INDEX (CLOCK_ADAT - 1)
|
||||
#define CLOCK_SPDIF_INDEX (CLOCK_SPDIF - 1)
|
||||
|
||||
#define SET_SMUX 7
|
||||
|
||||
/* c_audioControl */
|
||||
#define SET_SAMPLE_FREQ 4
|
||||
#define SET_CHAN_COUNT_IN 5
|
||||
#define SET_CHAN_COUNT_OUT 6
|
||||
|
||||
|
||||
|
||||
797
module_usb_aud_shared/clocking/clockgen.xc
Normal file
797
module_usb_aud_shared/clocking/clockgen.xc
Normal file
@@ -0,0 +1,797 @@
|
||||
|
||||
#include <xs1.h>
|
||||
#include <assert.h>
|
||||
#include <print.h>
|
||||
|
||||
#include "devicedefines.h"
|
||||
#include "clockcmds.h"
|
||||
#include "SpdifReceive.h"
|
||||
|
||||
|
||||
#ifdef SPDIF_RX
|
||||
#pragma xta command "analyse path digital_out digital_out"
|
||||
#pragma xta command "set required - 5200 ns" /* 192kHz */
|
||||
#endif
|
||||
|
||||
#define LOCAL_CLOCK_INCREMENT 166667
|
||||
#define LOCAL_CLOCK_MARGIN 1666
|
||||
|
||||
#define MAX_SAMPLES 64 /* Must be power of 2 */
|
||||
#define MAX_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
|
||||
#define MAX_ADAT_SAMPLES (8 * MAX_SAMPLES) /* Must be power of 2 */
|
||||
|
||||
#define SPDIF_FRAME_ERRORS_THRESH 40
|
||||
|
||||
unsigned g_digData[10];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int receivedSamples;
|
||||
int samples;
|
||||
int savedSamples;
|
||||
int lastDiff;
|
||||
unsigned identicaldiffs;
|
||||
int samplesPerTick;
|
||||
} Counter;
|
||||
|
||||
static int clockFreq[NUM_CLOCKS]; /* Store current clock freq for each clock unit */
|
||||
static int clockValid[NUM_CLOCKS]; /* Store current validity of each clock unit */
|
||||
static int clockInt[NUM_CLOCKS]; /* Interupt flag for clocks */
|
||||
static int clockId[NUM_CLOCKS];
|
||||
|
||||
int abs(int x)
|
||||
{
|
||||
if (x < 0) return -x;
|
||||
return x;
|
||||
}
|
||||
|
||||
int channelContainsControlToken(chanend x)
|
||||
{
|
||||
unsigned char tmpc;
|
||||
|
||||
select
|
||||
{
|
||||
case inct_byref(x, tmpc):
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void outInterrupt(chanend c_interruptControl, int value)
|
||||
{
|
||||
/* Non-blocking check for control token */
|
||||
//if (channelContainsControlToken(c_interruptControl))
|
||||
{
|
||||
outuint(c_interruptControl, value);
|
||||
outct(c_interruptControl, XS1_CT_END);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLOCK_VALIDITY_CALL
|
||||
void VendorClockValidity(int valid);
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
static inline void setClockValidity(chanend c_interruptControl, int clkIndex, int valid, int currentClkMode)
|
||||
{
|
||||
if (clockValid[clkIndex] != valid)
|
||||
{
|
||||
clockValid[clkIndex] = valid;
|
||||
outInterrupt(c_interruptControl, clockId[clkIndex]);
|
||||
|
||||
#ifdef CLOCK_VALIDITY_CALL
|
||||
#ifdef ADAT_RX
|
||||
if (currentClkMode == CLOCK_ADAT && clkIndex == CLOCK_ADAT_INDEX)
|
||||
{
|
||||
VendorClockValidity(valid);
|
||||
}
|
||||
#endif
|
||||
#ifdef SPDIF_RX
|
||||
if (currentClkMode == CLOCK_SPDIF && clkIndex == CLOCK_SPDIF_INDEX)
|
||||
{
|
||||
VendorClockValidity(valid);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Returns 1 for valid clock found else 0 */
|
||||
static inline int validSamples(Counter &counter, int clockIndex)
|
||||
{
|
||||
int diff = counter.samples - counter.savedSamples;
|
||||
|
||||
counter.savedSamples = counter.samples;
|
||||
|
||||
/* Check for stable sample rate (with some small margin) */
|
||||
if (diff != 0 && abs( diff - counter.lastDiff ) < 5 )
|
||||
{
|
||||
counter.identicaldiffs++;
|
||||
|
||||
if (counter.identicaldiffs > 10)
|
||||
{
|
||||
/* Detect current sample rate (round to nearest) */
|
||||
int s = -1;
|
||||
|
||||
if (diff > 137 && diff < 157)
|
||||
{
|
||||
s = 147;
|
||||
}
|
||||
else if (diff > 150 && diff < 170)
|
||||
{
|
||||
s = 160;
|
||||
}
|
||||
else if(diff > 284 && diff < 304)
|
||||
{
|
||||
s = 294;
|
||||
}
|
||||
else if (diff > 310 && diff < 330)
|
||||
{
|
||||
s = 320;
|
||||
}
|
||||
else if (diff > 578 && diff < 598)
|
||||
{
|
||||
s = 588;
|
||||
}
|
||||
else if (diff > 630 && diff < 650)
|
||||
{
|
||||
s = 640;
|
||||
}
|
||||
|
||||
/* Check if we found a valid freq */
|
||||
if (s != -1)
|
||||
{
|
||||
/* Update expected samples per tick */
|
||||
counter.samplesPerTick = s;
|
||||
|
||||
/* Update record of external clock source sample frequency */
|
||||
s *= 300;
|
||||
|
||||
|
||||
if (clockFreq[clockIndex] != s)
|
||||
{
|
||||
clockFreq[clockIndex] = s;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not a valid frequency - Reset counter and find another run of samples */
|
||||
counter.identicaldiffs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
counter.identicaldiffs = 0;
|
||||
counter.lastDiff = diff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SPDIF_RX
|
||||
//:badParity
|
||||
/* Returns 1 for bad parity, else 0 */
|
||||
static inline int badParity(unsigned x)
|
||||
{
|
||||
unsigned X = (x>>4);
|
||||
crc32(X, 0, 1);
|
||||
return X & 1;
|
||||
}
|
||||
//:
|
||||
#endif
|
||||
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
void VendorLedRefresh(unsigned levelData[]);
|
||||
unsigned g_inputLevelData[NUM_USB_CHAN_IN];
|
||||
extern int samples_to_host_inputs[NUM_USB_CHAN_IN];
|
||||
extern int samples_to_host_inputs_buff[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */
|
||||
#endif
|
||||
|
||||
int VendorAudCoreReqs(unsigned cmd, chanend c);
|
||||
|
||||
#pragma unsafe arrays
|
||||
void clockGen (streaming chanend c_spdif_rx, chanend c_adat_rx, out port p, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
|
||||
{
|
||||
timer t_local;
|
||||
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
||||
unsigned pinVal = 0;
|
||||
unsigned short pinTime;
|
||||
unsigned clkMode = CLOCK_INTERNAL; /* Current clocking mode in operation */
|
||||
unsigned tmp;
|
||||
|
||||
/* start in no-SMUX (8-channel) mode */
|
||||
int smux = 0;
|
||||
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
timer t_level;
|
||||
unsigned levelTime;
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
timer t_external;
|
||||
#endif
|
||||
|
||||
#ifdef SPDIF_RX
|
||||
/* S/PDIF buffer state */
|
||||
int spdifSamples[MAX_SPDIF_SAMPLES]; /* S/PDIF sample buffer */
|
||||
int spdifWr = 0; /* Write index */
|
||||
int spdifRd = 0; /* Read index */ //(spdifWriteIndex ^ (MAX_SPDIF_SAMPLES >> 1)) & ~1; // Start in middle
|
||||
int spdifOverflow = 0; /* Overflow/undeflow flags */
|
||||
int spdifUnderflow = 1;
|
||||
int spdifSamps = 0; /* Number of samples in buffer */
|
||||
Counter spdifCounters;
|
||||
int spdifReceivedTime;
|
||||
unsigned tmp2;
|
||||
unsigned spdifLeft = 0;
|
||||
#endif
|
||||
|
||||
#ifdef ADAT_RX
|
||||
/* ADAT buffer state */
|
||||
int adatSamples[MAX_ADAT_SAMPLES];
|
||||
int adatWr = 0;
|
||||
int adatRd = 0;
|
||||
int adatOverflow = 0;
|
||||
int adatUnderflow = 1;
|
||||
//int adatFrameErrors = 0;
|
||||
int adatSamps = 0;
|
||||
Counter adatCounters;
|
||||
int adatReceivedTime;
|
||||
|
||||
unsigned adatFrame[8];
|
||||
int adatChannel = 0;
|
||||
int adatSamplesEver = 0;
|
||||
#endif
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
g_digData[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Init clock unit state */
|
||||
#ifdef SPDIF_RX
|
||||
clockFreq[CLOCK_SPDIF_INDEX] = 0;
|
||||
clockValid[CLOCK_SPDIF_INDEX] = 0;
|
||||
clockInt[CLOCK_SPDIF_INDEX] = 0;
|
||||
clockId[CLOCK_SPDIF_INDEX] = ID_CLKSRC_EXT;
|
||||
#endif
|
||||
clockFreq[CLOCK_INTERNAL_INDEX] = 0;
|
||||
clockId[CLOCK_INTERNAL_INDEX] = ID_CLKSRC_INT;
|
||||
clockValid[CLOCK_INTERNAL_INDEX] = 0;
|
||||
clockInt[CLOCK_INTERNAL_INDEX] = 0;
|
||||
#ifdef ADAT_RX
|
||||
clockFreq[CLOCK_ADAT_INDEX] = 0;
|
||||
clockInt[CLOCK_ADAT_INDEX] = 0;
|
||||
clockValid[CLOCK_ADAT_INDEX] = 0;
|
||||
clockId[CLOCK_ADAT_INDEX] = ID_CLKSRC_ADAT;
|
||||
#endif
|
||||
#ifdef SPDIF_RX
|
||||
spdifCounters.receivedSamples = 0;
|
||||
spdifCounters.samples = 0;
|
||||
spdifCounters.savedSamples = 0;
|
||||
spdifCounters.lastDiff = 0;
|
||||
spdifCounters.identicaldiffs = 0;
|
||||
spdifCounters.samplesPerTick = 0;
|
||||
#endif
|
||||
|
||||
#ifdef ADAT_RX
|
||||
adatCounters.receivedSamples = 0;
|
||||
adatCounters.samples = 0;
|
||||
adatCounters.savedSamples = 0;
|
||||
adatCounters.lastDiff = 0;
|
||||
adatCounters.identicaldiffs = 0;
|
||||
adatCounters.samplesPerTick = 0;
|
||||
#endif
|
||||
|
||||
|
||||
t_local :> timeNextEdge;
|
||||
timeLastEdge = timeNextEdge;
|
||||
timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT / 2);
|
||||
timeNextEdge += LOCAL_CLOCK_INCREMENT;
|
||||
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
t_level :> levelTime;
|
||||
levelTime+= LEVEL_UPDATE_RATE;
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
/* Fill channel */
|
||||
outuint(c_dig_rx, 1);
|
||||
#endif
|
||||
|
||||
/* Initial ref clock output and get timestamp */
|
||||
p <: pinVal @ pinTime;
|
||||
pinTime += (unsigned short)(LOCAL_CLOCK_INCREMENT - (LOCAL_CLOCK_INCREMENT/2));
|
||||
p @ pinTime <: pinVal;
|
||||
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
{
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
#warning Level metering enabled
|
||||
case t_level when timerafter(levelTime) :> void:
|
||||
|
||||
levelTime += LEVEL_UPDATE_RATE;
|
||||
|
||||
/* Copy over level data and reset */
|
||||
for(int i = 0; i< NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int tmp;
|
||||
//g_inputLevelData[i] = samples_to_host_inputs[i];
|
||||
asm("ldw %0, %1[%2]":"=r"(tmp):"r"(samples_to_host_inputs),"r"(i));
|
||||
g_inputLevelData[i] = tmp;
|
||||
|
||||
//samples_to_host_inputs[i] = 0;
|
||||
asm("stw %0, %1[%2]"::"r"(0),"r"(samples_to_host_inputs),"r"(i));
|
||||
|
||||
/* Guard against host polling slower than timer and missing peaks */
|
||||
if(g_inputLevelData[i] > samples_to_host_inputs_buff[i])
|
||||
{
|
||||
samples_to_host_inputs_buff[i] = g_inputLevelData[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Call user LED refresh */
|
||||
VendorLedRefresh(g_inputLevelData);
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Updates to clock settings from endpoint 0 */
|
||||
case inuint_byref(c_clk_ctl, tmp):
|
||||
switch(tmp)
|
||||
{
|
||||
case GET_SEL:
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
|
||||
/* Send back current clock mode */
|
||||
outuint(c_clk_ctl, clkMode);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
|
||||
break;
|
||||
|
||||
case SET_SEL:
|
||||
/* Update clock mode */
|
||||
tmp = inuint(c_clk_ctl);
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
|
||||
if(tmp!=0)
|
||||
{
|
||||
clkMode = tmp;
|
||||
}
|
||||
#ifdef CLOCK_VALIDITY_CALL
|
||||
switch(clkMode)
|
||||
{
|
||||
case CLOCK_INTERNAL:
|
||||
VendorClockValidity(1);
|
||||
break;
|
||||
#ifdef ADAT_RX
|
||||
case CLOCK_ADAT:
|
||||
VendorClockValidity(clockValid[CLOCK_ADAT_INDEX]);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SPDIF_RX
|
||||
case CLOCK_SPDIF:
|
||||
VendorClockValidity(clockValid[CLOCK_SPDIF_INDEX]);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GET_VALID:
|
||||
/* Clock Unit Index */
|
||||
tmp = inuint(c_clk_ctl);
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
outuint(c_clk_ctl, clockValid[tmp]);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
case GET_FREQ:
|
||||
tmp = inuint(c_clk_ctl);
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
outuint(c_clk_ctl, clockFreq[tmp]);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
case SET_SMUX:
|
||||
smux = inuint(c_clk_ctl);
|
||||
#ifdef ADAT_RX
|
||||
adatRd = 0; /* Reset adat FIFO */
|
||||
adatWr = 0;
|
||||
adatSamps = 0;
|
||||
#endif
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef VENDOR_AUDCORE_REQS
|
||||
if(VendorAudCoreReqs(tmp, c_clk_ctl))
|
||||
#endif
|
||||
printstrln("ERR: Bad req in clockgen\n");
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* Generate local clock from timer */
|
||||
case t_local when timerafter(timeNextEdge) :> void:
|
||||
|
||||
|
||||
/* Setup next local clock edge */
|
||||
pinTime += (short) LOCAL_CLOCK_INCREMENT;
|
||||
pinVal = !pinVal;
|
||||
p @ pinTime <: pinVal;
|
||||
|
||||
/* Record time of edge */
|
||||
timeLastEdge = timeNextEdge;
|
||||
|
||||
/* Setup for next edge */
|
||||
timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT/2);
|
||||
timeNextEdge += LOCAL_CLOCK_INCREMENT;
|
||||
|
||||
/* If we are in an external clock mode and this fire, then clock invalid */
|
||||
|
||||
#ifdef SPDIF_RX
|
||||
// if(clkMode == CLOCK_SPDIF)
|
||||
{
|
||||
/* We must have lost valid S/PDIF stream, reset counters, so we dont produce a double edge */
|
||||
spdifCounters.receivedSamples = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef ADAT_RX
|
||||
//if(clkMode == CLOCK_ADAT)
|
||||
{
|
||||
adatCounters.receivedSamples = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_VALIDITY_CALL
|
||||
if(clkMode == CLOCK_INTERNAL)
|
||||
{
|
||||
/* Internal clock always valid */
|
||||
VendorClockValidity(1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
case t_external when timerafter(timeNextClockDetection) :> void:
|
||||
|
||||
timeNextClockDetection += (LOCAL_CLOCK_INCREMENT);
|
||||
#ifdef SPDIF_RX
|
||||
tmp = spdifCounters.samplesPerTick;
|
||||
|
||||
/* Returns 1 if valid clock found */
|
||||
tmp = validSamples(spdifCounters, CLOCK_SPDIF_INDEX);
|
||||
setClockValidity(c_clk_int, CLOCK_SPDIF_INDEX, tmp, clkMode);
|
||||
#endif
|
||||
#ifdef ADAT_RX
|
||||
tmp = validSamples(adatCounters, CLOCK_ADAT_INDEX);
|
||||
setClockValidity(c_clk_int, CLOCK_ADAT_INDEX, tmp, clkMode);
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SPDIF_RX
|
||||
/* Receive sample from S/PDIF RX thread (steaming chan) */
|
||||
case c_spdif_rx :> tmp:
|
||||
|
||||
/* Record time of sample */
|
||||
t_local :> spdifReceivedTime;
|
||||
|
||||
/* Check parity and ignore if bad */
|
||||
if(badParity(tmp))
|
||||
continue;
|
||||
|
||||
/* Get pre-amble */
|
||||
tmp2 = tmp & 0xF;
|
||||
switch(tmp2)
|
||||
{
|
||||
/* LEFT */
|
||||
case FRAME_X:
|
||||
case FRAME_Z:
|
||||
|
||||
spdifLeft = tmp << 4;
|
||||
break;
|
||||
|
||||
/* RIGHT */
|
||||
case FRAME_Y:
|
||||
|
||||
/* Only store sample if not in overflow and stream is reasonably valid */
|
||||
if(!spdifOverflow && clockValid[CLOCK_SPDIF_INDEX])
|
||||
{
|
||||
/* Store left and right sample pair to buffer */
|
||||
spdifSamples[spdifWr] = spdifLeft;
|
||||
spdifSamples[spdifWr+1] = tmp << 4;
|
||||
|
||||
spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1);
|
||||
|
||||
spdifSamps += 2;
|
||||
|
||||
/* Check for over flow */
|
||||
if(spdifSamps > MAX_SPDIF_SAMPLES-1)
|
||||
{
|
||||
spdifOverflow = 1;
|
||||
}
|
||||
|
||||
/* Check for coming out of under flow */
|
||||
if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1)))
|
||||
{
|
||||
spdifUnderflow = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Bad sample, skip */
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
spdifCounters.samples += 1;
|
||||
|
||||
if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF_INDEX])
|
||||
{
|
||||
spdifCounters.receivedSamples+=1;
|
||||
|
||||
/* Inspect for if we need to produce an edge */
|
||||
if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick))
|
||||
{
|
||||
/* Check edge is about right... S/PDIF may have changed freq... */
|
||||
if(timeafter(spdifReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
|
||||
{
|
||||
/* Record edge time */
|
||||
timeLastEdge = spdifReceivedTime;
|
||||
|
||||
/* Setup for next edge */
|
||||
timeNextEdge = spdifReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
|
||||
/* Toggle edge */
|
||||
p <: pinVal @ pinTime;
|
||||
pinTime += (short) LOCAL_CLOCK_INCREMENT;
|
||||
pinVal = !pinVal;
|
||||
p @ pinTime <: pinVal;
|
||||
|
||||
/* Reset counters */
|
||||
spdifCounters.receivedSamples = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef ADAT_RX
|
||||
/* receive sample from ADAT rx thread (streaming channel with CT_END) */
|
||||
case inuint_byref(c_adat_rx, tmp):
|
||||
/* record time of sample */
|
||||
t_local :> adatReceivedTime;
|
||||
|
||||
/* Sync is: 1 | (user_byte << 4) */
|
||||
if(tmp&1)
|
||||
{
|
||||
/* user bits - start of frame */
|
||||
adatChannel = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* audio sample */
|
||||
adatSamplesEver++;
|
||||
adatFrame[adatChannel] = tmp;
|
||||
|
||||
adatChannel++;
|
||||
if (adatChannel == 8)
|
||||
{
|
||||
/* only store left samples if not in overflow and stream is reasonably valid */
|
||||
if (!adatOverflow && clockValid[CLOCK_ADAT_INDEX])
|
||||
{
|
||||
if(smux)
|
||||
{
|
||||
|
||||
adatSamples[adatWr + 0] = adatFrame[0];
|
||||
adatSamples[adatWr + 4] = adatFrame[1];
|
||||
adatSamples[adatWr + 1] = adatFrame[2];
|
||||
adatSamples[adatWr + 5] = adatFrame[3];
|
||||
adatSamples[adatWr + 2] = adatFrame[4];
|
||||
adatSamples[adatWr + 6] = adatFrame[5];
|
||||
adatSamples[adatWr + 3] = adatFrame[6];
|
||||
adatSamples[adatWr + 7] = adatFrame[7];
|
||||
}
|
||||
else
|
||||
{
|
||||
adatSamples[adatWr + 0] = adatFrame[0];
|
||||
adatSamples[adatWr + 1] = adatFrame[1];
|
||||
adatSamples[adatWr + 2] = adatFrame[2];
|
||||
adatSamples[adatWr + 3] = adatFrame[3];
|
||||
adatSamples[adatWr + 4] = adatFrame[4];
|
||||
adatSamples[adatWr + 5] = adatFrame[5];
|
||||
adatSamples[adatWr + 6] = adatFrame[6];
|
||||
adatSamples[adatWr + 7] = adatFrame[7];
|
||||
}
|
||||
adatWr = (adatWr + 8) & (MAX_ADAT_SAMPLES - 1);
|
||||
adatSamps += 8;
|
||||
|
||||
/* check for overflow */
|
||||
if (adatSamps > MAX_ADAT_SAMPLES - 1)
|
||||
{
|
||||
adatOverflow = 1;
|
||||
}
|
||||
|
||||
/* check for coming out of underflow */
|
||||
if (adatUnderflow && (adatSamps >= (MAX_ADAT_SAMPLES >> 1)))
|
||||
{
|
||||
adatUnderflow = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(adatChannel == 4 || adatChannel == 8)
|
||||
{
|
||||
adatCounters.samples += 1;
|
||||
|
||||
if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT_INDEX])
|
||||
{
|
||||
adatCounters.receivedSamples += 1;
|
||||
|
||||
/* Inspect for if we need to produce an edge */
|
||||
if ((adatCounters.receivedSamples >= adatCounters.samplesPerTick))
|
||||
{
|
||||
/* Check edge is about right... S/PDIF may have changed freq... */
|
||||
if (timeafter(adatReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
|
||||
{
|
||||
/* Record edge time */
|
||||
timeLastEdge = adatReceivedTime;
|
||||
|
||||
/* Setup for next edge */
|
||||
timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
|
||||
/* Toggle edge */
|
||||
p <: pinVal @ pinTime;
|
||||
pinTime += LOCAL_CLOCK_INCREMENT;
|
||||
pinVal = !pinVal;
|
||||
p @ pinTime <: pinVal;
|
||||
|
||||
/* Reset counters */
|
||||
adatCounters.receivedSamples = 0;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (adatChannel == 8)
|
||||
adatChannel = 0;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
/* Mixer requests data */
|
||||
case inuint_byref(c_dig_rx, tmp):
|
||||
#ifdef SPDIF_RX
|
||||
if(spdifUnderflow)
|
||||
{
|
||||
/* S/PDIF underflowing, send out zero samples */
|
||||
g_digData[0] = 0;
|
||||
g_digData[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read out samples from S/PDIF buffer and send... */
|
||||
tmp = spdifSamples[spdifRd];
|
||||
tmp2 = spdifSamples[spdifRd + 1];
|
||||
|
||||
spdifRd += 2;
|
||||
spdifRd &= (MAX_SPDIF_SAMPLES - 1);
|
||||
|
||||
#pragma xta endpoint "digital_out"
|
||||
|
||||
g_digData[0] = tmp;
|
||||
g_digData[1] = tmp2;
|
||||
|
||||
spdifSamps -= 2;
|
||||
|
||||
/* spdifSamps could go to -1 */
|
||||
if(spdifSamps < 0)
|
||||
{
|
||||
/* We're out of S/PDIF samples, mark underflow condition */
|
||||
spdifUnderflow = 1;
|
||||
spdifLeft = 0;
|
||||
}
|
||||
|
||||
/* If we are in over flow condition and we have a sensible number of samples
|
||||
* come out of overflow condition */
|
||||
if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1)))
|
||||
{
|
||||
spdifOverflow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef ADAT_RX
|
||||
if (adatUnderflow)
|
||||
{
|
||||
/* ADAT underflowing, send out zero samples */
|
||||
g_digData[2] = 0;
|
||||
g_digData[3] = 0;
|
||||
g_digData[4] = 0;
|
||||
g_digData[5] = 0;
|
||||
g_digData[6] = 0;
|
||||
g_digData[7] = 0;
|
||||
g_digData[8] = 0;
|
||||
g_digData[9] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO SMUX II mode */
|
||||
/* read out samples from the ADAT buffer and send */
|
||||
/* always return 8 samples */
|
||||
if (smux)
|
||||
{
|
||||
/* SMUX mode - 4 samples from fifo and 4 zero samples */
|
||||
g_digData[2] = adatSamples[adatRd + 0];
|
||||
g_digData[3] = adatSamples[adatRd + 1];
|
||||
g_digData[4] = adatSamples[adatRd + 2];
|
||||
g_digData[5] = adatSamples[adatRd + 3];
|
||||
|
||||
g_digData[6] = 0;
|
||||
g_digData[7] = 0;
|
||||
g_digData[8] = 0;
|
||||
g_digData[9] = 0;
|
||||
adatRd = (adatRd + 4) & (MAX_ADAT_SAMPLES - 1);
|
||||
adatSamps -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no SMUX mode - 8 samples from fifo */
|
||||
g_digData[2] = adatSamples[adatRd + 0];
|
||||
g_digData[3] = adatSamples[adatRd + 1];
|
||||
g_digData[4] = adatSamples[adatRd + 2];
|
||||
g_digData[5] = adatSamples[adatRd + 3];
|
||||
|
||||
g_digData[6] = adatSamples[adatRd + 4];
|
||||
g_digData[7] = adatSamples[adatRd + 5];
|
||||
g_digData[8] = adatSamples[adatRd + 6];
|
||||
g_digData[9] = adatSamples[adatRd + 7];
|
||||
|
||||
adatRd = (adatRd + 8) & (MAX_ADAT_SAMPLES - 1);
|
||||
adatSamps -= 8;
|
||||
}
|
||||
|
||||
/* adatSamps could go to -1 */
|
||||
if (adatSamps < 0)
|
||||
{
|
||||
/* we're out of ADAT samples, mark underflow condition */
|
||||
adatUnderflow = 1;
|
||||
}
|
||||
|
||||
/* if we are in overflow condition and have a sensible number of samples
|
||||
come out of overflow condition */
|
||||
if (adatOverflow && adatSamps < (MAX_ADAT_SAMPLES >> 1))
|
||||
{
|
||||
adatOverflow = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
outuint(c_dig_rx, 1);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
module_usb_aud_shared/clocking/clocking.h
Normal file
27
module_usb_aud_shared/clocking/clocking.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef _CLOCKING_H_
|
||||
#define _CLOCKING_H_
|
||||
|
||||
/* Functions that handle master clock generation. These need modifying for an existing design */
|
||||
|
||||
/* Any initialisation required for master clock generation - run once at start up */
|
||||
void ClockingInit(void);
|
||||
|
||||
/* Configuration for a specific master clock frequency - run every sample frequency change */
|
||||
void ClockingConfig(unsigned mClkFreq);
|
||||
|
||||
|
||||
/** Clock generation and digital audio I/O handling.
|
||||
*
|
||||
* \param c_spdif_rx channel connected to S/PDIF receive thread
|
||||
* \param c_adat_rx channel connect to ADAT receive thread
|
||||
* \param p port to output clock signal to drive external frequency synthesizer
|
||||
* \param c_audio channel connected to the audio() thread
|
||||
* \param c_clk_ctl channel connected to Endpoint0() for configuration of the
|
||||
* clock
|
||||
* \param c_clk_int channel connected to the decouple() thread for clock
|
||||
interrupts
|
||||
*/
|
||||
void clockGen (streaming chanend c_spdif_rx, chanend c_adat_rx, out port p, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int);
|
||||
#endif
|
||||
|
||||
14
module_usb_aud_shared/codec/codec.h
Normal file
14
module_usb_aud_shared/codec/codec.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _CODEC_H_
|
||||
#define _CODEC_H_
|
||||
|
||||
/* These functions must be implemented for the CODEC/ADC/DAC arrangement of a specific design */
|
||||
|
||||
/* TODO Are the channel args required? */
|
||||
|
||||
/* Any required CODEC initialisation - run once at start up */
|
||||
void CodecInit(chanend ?c_codec);
|
||||
|
||||
/* Configure condec for a specific mClk/Sample frquency - run on every sample frequency change */
|
||||
void CodecConfig(unsigned samFreq, unsigned mClk, chanend ?c_codec);
|
||||
|
||||
#endif
|
||||
144
module_usb_aud_shared/dbtable.h
Normal file
144
module_usb_aud_shared/dbtable.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @file dbtable.h
|
||||
* @brief 128 entry + neg inf db table from -inf to 0xffffffff
|
||||
* @author Ross Owen, XMOS Semiconductor
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
#ifndef _DBTABLE_
|
||||
#define _DBTABLE_
|
||||
|
||||
static unsigned dbTable[129] =
|
||||
{
|
||||
4294967295, /* 0 -> 0xffffffff */
|
||||
3827893631,
|
||||
3411613790,
|
||||
3040603991,
|
||||
2709941159,
|
||||
2415237600,
|
||||
2152582777,
|
||||
1918491420,
|
||||
1709857277,
|
||||
1523911903,
|
||||
1358187913,
|
||||
1210486251,
|
||||
1078847007,
|
||||
961523407,
|
||||
856958639,
|
||||
763765191,
|
||||
680706443,
|
||||
606680256,
|
||||
540704347,
|
||||
481903257,
|
||||
429496729,
|
||||
382789363,
|
||||
341161379,
|
||||
304060399,
|
||||
270994116,
|
||||
241523760,
|
||||
215258278,
|
||||
191849142,
|
||||
170985728,
|
||||
152391190,
|
||||
135818791,
|
||||
121048625,
|
||||
107884701,
|
||||
96152341,
|
||||
85695864,
|
||||
76376519,
|
||||
68070644,
|
||||
60668026,
|
||||
54070435,
|
||||
48190326,
|
||||
42949673,
|
||||
38278936,
|
||||
34116138,
|
||||
30406040,
|
||||
27099412,
|
||||
24152376,
|
||||
21525828,
|
||||
19184914,
|
||||
17098573,
|
||||
15239119,
|
||||
13581879,
|
||||
12104863,
|
||||
10788470,
|
||||
9615234,
|
||||
8569586,
|
||||
7637652,
|
||||
6807064,
|
||||
6066803,
|
||||
5407043,
|
||||
4819033,
|
||||
4294967,
|
||||
3827894,
|
||||
3411614,
|
||||
3040604,
|
||||
2709941,
|
||||
2415238,
|
||||
2152583,
|
||||
1918491,
|
||||
1709857,
|
||||
1523912,
|
||||
1358188,
|
||||
1210486,
|
||||
1078847,
|
||||
961523,
|
||||
856959,
|
||||
763765,
|
||||
680706,
|
||||
606680,
|
||||
540704,
|
||||
481903,
|
||||
429497,
|
||||
382789,
|
||||
341161,
|
||||
304060,
|
||||
270994,
|
||||
241524,
|
||||
215258,
|
||||
191849,
|
||||
170986,
|
||||
152391,
|
||||
135819,
|
||||
121049,
|
||||
107885,
|
||||
96152,
|
||||
85696,
|
||||
76377,
|
||||
68071,
|
||||
60668,
|
||||
54070,
|
||||
48190,
|
||||
42950,
|
||||
38279,
|
||||
34116,
|
||||
30406,
|
||||
27099,
|
||||
24152,
|
||||
21526,
|
||||
19185,
|
||||
17099,
|
||||
15239,
|
||||
13582,
|
||||
12105,
|
||||
10788,
|
||||
9615,
|
||||
8570,
|
||||
7638,
|
||||
6807,
|
||||
6067,
|
||||
5407,
|
||||
4819,
|
||||
4295,
|
||||
3828,
|
||||
3412,
|
||||
3041,
|
||||
2710,
|
||||
2415,
|
||||
2153,
|
||||
1918,
|
||||
0 // -0x8000
|
||||
};
|
||||
|
||||
#endif
|
||||
343
module_usb_aud_shared/devicedefines.h
Normal file
343
module_usb_aud_shared/devicedefines.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* @file internaldefines.h
|
||||
* @brief Defines relating to device configuration and customisation.
|
||||
* @author Ross Owen, XMOS Limited
|
||||
*/
|
||||
|
||||
#ifndef _DEVICEDEFINES_H_
|
||||
#define _DEVICEDEFINES_H_
|
||||
|
||||
#include "customdefines.h"
|
||||
|
||||
/* Tidy up historical INPUT/OUTPUT defines. INPUT/OUTPUT now enabled based on channel count defines */
|
||||
#if !defined(NUM_USB_CHAN_IN)
|
||||
#error NUM_USB_CHAN_IN must be defined!
|
||||
#else
|
||||
#if (NUM_USB_CHAN_IN == 0)
|
||||
#undef INPUT
|
||||
#else
|
||||
#define INPUT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(NUM_USB_CHAN_OUT)
|
||||
#error NUM_USB_CHAN_OUT must be defined!
|
||||
#else
|
||||
#if (NUM_USB_CHAN_OUT == 0)
|
||||
#undef OUTPUT
|
||||
#else
|
||||
#define OUTPUT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MIDI) && (MIDI == 0)
|
||||
#undef MIDI
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF) && (SPDIF == 0)
|
||||
#undef SPDIF
|
||||
#endif
|
||||
|
||||
#if defined(INPUT) && (INPUT == 0)
|
||||
#undef INPUT
|
||||
#endif
|
||||
|
||||
#if defined(OUTPUT) && (OUTPUT == 0)
|
||||
#undef OUTPUT
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF_RX) && (SPDIF_RX == 0)
|
||||
#undef SPDIF_RX
|
||||
#endif
|
||||
|
||||
#if defined(ADAT_RX) && (ADAT_RX == 0)
|
||||
#undef ADAT_RX
|
||||
#endif
|
||||
|
||||
#if defined(DFU) && (DFU == 0)
|
||||
#undef DFU
|
||||
#endif
|
||||
|
||||
#if defined(CODEC_SLAVE) && (CODEC_SLAVE == 0)
|
||||
#undef CODEC_SLAVE
|
||||
#endif
|
||||
|
||||
#if defined(LEVEL_METER_LEDS) && !defined(LEVEL_UPDATE_RATE)
|
||||
#define LEVEL_UPDATE_RATE 400000
|
||||
#endif
|
||||
|
||||
#if(AUDIO_CLASS != 1) && (AUDIO_CLASS != 2)
|
||||
#warning AUDIO_CLASS not defined, using 2
|
||||
#define AUDIO_CLASS 2
|
||||
#endif
|
||||
|
||||
/* Number of IS2 chans to DAC */
|
||||
#ifndef I2S_CHANS_DAC
|
||||
#error I2S_CHANS_DAC not defined
|
||||
#else
|
||||
#define I2S_WIRES_DAC (I2S_CHANS_DAC >> 1)
|
||||
#endif
|
||||
|
||||
/* Number of I2S chans from ADC */
|
||||
#ifndef I2S_CHANS_ADC
|
||||
#error I2S_CHANS_ADC not defined
|
||||
#else
|
||||
#define I2S_WIRES_ADC (I2S_CHANS_ADC >> 1)
|
||||
#endif
|
||||
|
||||
/* SPDIF and ADAT first input chan indices */
|
||||
#ifdef SPDIF_RX
|
||||
#ifndef SPDIF_RX_INDEX
|
||||
#error SPDIF_RX_INDEX not defined and SPDIF_RX defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ADAT_RX
|
||||
#ifndef ADAT_RX_INDEX
|
||||
#error ADAT_RX_INDEX not defined and ADAT_RX defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SPDIF_TX_INDEX
|
||||
#warning SPDIF_TX_INDEX not defined! Using 0
|
||||
#define SPDIF_TX_INDEX (0)
|
||||
#endif
|
||||
|
||||
/* Max supported freq for device */
|
||||
#ifndef MAX_FREQ
|
||||
#warning MAX_FREQ not defined! Using 48000
|
||||
#define MAX_FREQ (48000)
|
||||
#endif
|
||||
|
||||
/* Default device freq */
|
||||
#ifndef DEFAULT_FREQ
|
||||
#warning DEFAULT not defined! Using MAX_FREQ
|
||||
#define DEFAULT_FREQ (MAX_FREQ)
|
||||
#endif
|
||||
|
||||
/* Master clock defines (in Hz) */
|
||||
#ifndef MCLK_441
|
||||
#error MCLK_441 not defined
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#error MCLK_441 not defined
|
||||
#endif
|
||||
|
||||
/* The number of clock ticks to wait for the audio PLL to lock */
|
||||
#define AUDIO_PLL_LOCK_DELAY (40000000)
|
||||
|
||||
/* Vendor/Product strings */
|
||||
#ifndef VENDOR_STR
|
||||
#define VENDOR_STR "XMOS "
|
||||
//#warning VENDOR_STR not defined. Using XMOS
|
||||
#endif
|
||||
|
||||
#ifndef VENDOR_ID
|
||||
#warning VENDOR_ID not defined. Using XMOS vendor ID
|
||||
#define VENDOR_ID (0x20B1) /* XMOS VID */
|
||||
#endif
|
||||
|
||||
#ifndef PID_AUDIO_1
|
||||
#define PID_AUDIO_1 (0x0001)
|
||||
#warning PRODUCT_ID not defined. Using 0x0001
|
||||
#endif
|
||||
|
||||
#ifndef PID_AUDIO_2
|
||||
#define PID_AUDIO_2 (0x0001)
|
||||
#warning PRODUCT_ID not defined. Using 0x0001
|
||||
#endif
|
||||
|
||||
/* Device release number in BCD: 0xJJMNi */
|
||||
#ifndef BCD_DEVICE
|
||||
#define BCD_DEVICE (0x0000)
|
||||
#warning BCD_DEVICE not defined. Using 0x0000
|
||||
#endif
|
||||
|
||||
/* Addition interfaces based on defines */
|
||||
#if defined(DFU) && DFU != 0
|
||||
#define DFU_INTERFACES (1) /* DFU interface count */
|
||||
#else
|
||||
#define DFU_INTERFACES (0)
|
||||
#endif
|
||||
|
||||
#ifdef INPUT
|
||||
#define INPUT_INTERFACES (1)
|
||||
#else
|
||||
#define INPUT_INTERFACES (0)
|
||||
#endif
|
||||
|
||||
#if defined(OUTPUT) && OUTPUT != 0
|
||||
#define OUTPUT_INTERFACES (1)
|
||||
#else
|
||||
#define OUTPUT_INTERFACES (0)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MIDI)
|
||||
#define MIDI_INTERFACES (2)
|
||||
#else
|
||||
#define MIDI_INTERFACES (0)
|
||||
#endif
|
||||
|
||||
#define AUDIO_STOP_FOR_DFU (0x12345678)
|
||||
#define AUDIO_START_FROM_DFU (0x87654321)
|
||||
#define AUDIO_REBOOT_FROM_DFU (0xa5a5a5a5)
|
||||
|
||||
|
||||
#define MAX_VOL (0x20000000)
|
||||
|
||||
#define NUM_EP_OUT 3 /* Max number of device endpoints used */
|
||||
#define NUM_EP_IN 5
|
||||
/* Length of clock unit/clock-selector units */
|
||||
#if defined(SPDIF_RX) && defined(ADAT_RX)
|
||||
#define NUM_CLOCKS 3
|
||||
#elif defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
#define NUM_CLOCKS 2
|
||||
#else
|
||||
#define NUM_CLOCKS 1
|
||||
#endif
|
||||
|
||||
|
||||
/* Total number of USB interfaces this device implements (+1 for required control interface) */
|
||||
#define NUM_INTERFACES INPUT_INTERFACES + OUTPUT_INTERFACES + DFU_INTERFACES + MIDI_INTERFACES + 1
|
||||
/* Audio Unit ID defines */
|
||||
#define FU_USBIN 11 /* Feature Unit: USB Audio device -> host */
|
||||
#define FU_USBOUT 10 /* Feature Unit: USB Audio host -> device*/
|
||||
#define ID_IT_USB 2 /* Input terminal: USB streaming */
|
||||
#define ID_IT_AUD 1 /* Input terminal: Analogue input */
|
||||
#define ID_OT_USB 22 /* Output terminal: USB streaming */
|
||||
#define ID_OT_AUD 20 /* Output terminal: Analogue output */
|
||||
|
||||
#define ID_CLKSEL 40 /* Clock selector ID */
|
||||
#define ID_CLKSRC_INT 41 /* Clock source ID (internal) */
|
||||
#define ID_CLKSRC_EXT 42 /* Clock source ID (external) */
|
||||
#define ID_CLKSRC_ADAT 43 /* Clock source ID (external) */
|
||||
|
||||
#define ID_XU_MIXSEL 50
|
||||
#define ID_XU_OUT 51
|
||||
#define ID_XU_IN 52
|
||||
|
||||
#define ID_MIXER_1 60
|
||||
|
||||
#ifndef SERIAL_STR
|
||||
#define SERIAL_STR "0000" /* Serial number string */
|
||||
#endif
|
||||
|
||||
#define SERIAL_STR_INDEX 0x03
|
||||
#define MANUFACTURER_STR_INDEX 0x01
|
||||
#define PRODUCT_STR_INDEX 0x02
|
||||
|
||||
/* Mixer defines */
|
||||
#ifndef MIX_INPUTS
|
||||
#define MIX_INPUTS 18
|
||||
#endif
|
||||
|
||||
#ifndef MAX_MIX_COUNT
|
||||
#define MAX_MIX_COUNT 8
|
||||
#endif
|
||||
|
||||
|
||||
/* Volume defines */
|
||||
|
||||
#ifndef MIN_VOLUME
|
||||
/* The minimum volume setting above -inf. This is a signed 8.8 fixed point
|
||||
number that must be strictly greater than -128 (0x8000) */
|
||||
/* Default min volume is -127db */
|
||||
#define MIN_VOLUME (0x8100)
|
||||
#endif
|
||||
|
||||
#ifndef MAX_VOLUME
|
||||
/* The maximum volume setting. This is a signed 8.8 fixed point number. */
|
||||
/* Default max volume is 0db */
|
||||
#define MAX_VOLUME (0x0000)
|
||||
#endif
|
||||
|
||||
#ifndef VOLUME_RES
|
||||
/* The resolution of the volume control in db as a 8.8 fixed point number */
|
||||
/* Default volume resolution 1db */
|
||||
#define VOLUME_RES (0x100)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MIN_MIXER_VOLUME
|
||||
/* The minimum volume setting for the mixer unit above -inf.
|
||||
This is a signed 8.8 fixed point
|
||||
number that must be strictly greater than -128 (0x8000) */
|
||||
/* Default min volume is -127db */
|
||||
#define MIN_MIXER_VOLUME (0x8100)
|
||||
#endif
|
||||
|
||||
#ifndef MAX_MIXER_VOLUME
|
||||
/* The maximum volume setting for the mixer.
|
||||
This is a signed 8.8 fixed point number. */
|
||||
/* Default max volume is 0db */
|
||||
#define MAX_MIXER_VOLUME (0x0000)
|
||||
#endif
|
||||
|
||||
#ifndef VOLUME_RES_MIXER
|
||||
/* The resolution of the volume control in db as a 8.8 fixed point number */
|
||||
/* Default volume resolution 1db */
|
||||
#define VOLUME_RES_MIXER (0x100)
|
||||
#endif
|
||||
|
||||
/* Handle out volume control in the mixer */
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0)
|
||||
#undef OUT_VOLUME_IN_MIXER
|
||||
#else
|
||||
#if defined(MIXER)
|
||||
// Enabled by default
|
||||
#define OUT_VOLUME_IN_MIXER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Apply out volume controls after the mix */
|
||||
#if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0)
|
||||
#undef OUT_VOLUME_AFTER_MIX
|
||||
#else
|
||||
#if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER)
|
||||
// Enabled by default
|
||||
#define OUT_VOLUME_AFTER_MIX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define for reporting as self or bus-powered to the host */
|
||||
#if defined(SELF_POWERED) && (SELF_POWERED==0)
|
||||
#undef SELF_POWERED
|
||||
#endif
|
||||
|
||||
/* Handle in volume control in the mixer */
|
||||
#if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0)
|
||||
#undef IN_VOLUME_IN_MIXER
|
||||
#else
|
||||
#if defined(MIXER)
|
||||
/* Enabled by default */
|
||||
#define IN_VOLUME_IN_MIXER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Apply in volume controls after the mix */
|
||||
#if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0)
|
||||
#undef IN_VOLUME_AFTER_MIX
|
||||
#else
|
||||
#if defined(MIXER) && defined(IN_VOLUME_IN_MIXER)
|
||||
// Enabled by default
|
||||
#define IN_VOLUME_AFTER_MIX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS_FALLBACK==0)
|
||||
#undef AUDIO_CLASS_FALLBACK
|
||||
#endif
|
||||
|
||||
/* Defines for DFU */
|
||||
#ifndef PID_DFU
|
||||
#define PID_DFU PID_AUDIO_2
|
||||
#endif
|
||||
|
||||
#define DFU_VENDOR_ID VENDOR_ID
|
||||
#define DFU_BCD_DEVICE BCD_DEVICE
|
||||
#define DFU_SERIAL_STR_INDEX SERIAL_STR_INDEX
|
||||
#define DFU_MANUFACTURER_INDEX MANUFACTURER_STR_INDEX
|
||||
#define DFU_PRODUCT_INDEX PRODUCT_STR_INDEX
|
||||
#endif
|
||||
1291
module_usb_aud_shared/endpoint0/audiorequests.xc
Normal file
1291
module_usb_aud_shared/endpoint0/audiorequests.xc
Normal file
File diff suppressed because it is too large
Load Diff
1829
module_usb_aud_shared/endpoint0/cscope.out
Normal file
1829
module_usb_aud_shared/endpoint0/cscope.out
Normal file
File diff suppressed because it is too large
Load Diff
20
module_usb_aud_shared/endpoint0/dbcalc.h
Normal file
20
module_usb_aud_shared/endpoint0/dbcalc.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef __dbcalc_h__
|
||||
#define __dbcalc_h__
|
||||
|
||||
/* Function: db_to_mult
|
||||
|
||||
This function converts decibels into a volume multiplier. It uses a fixed-point polynomial approximation
|
||||
to 10^(db/10).
|
||||
|
||||
Parameters:
|
||||
db - The db value to convert.
|
||||
db_frac_bits - The number of binary fractional bits in the supplied decibel value
|
||||
result_frac_bits - The number of required fractional bits in the result.
|
||||
|
||||
Returns:
|
||||
The multiplier value as a fixed point value with the number of fractional bits as specified by
|
||||
the result_frac_bits parameter.
|
||||
*/
|
||||
unsigned db_to_mult(int db, int db_frac_bits, int result_frac_bits);
|
||||
|
||||
#endif // __dbcalc_h__
|
||||
127
module_usb_aud_shared/endpoint0/dbcalc.xc
Normal file
127
module_usb_aud_shared/endpoint0/dbcalc.xc
Normal file
@@ -0,0 +1,127 @@
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
/* The coefficients of the chebychev polynomial to approximate 10^x in the interval [-1,1].
|
||||
This polynomial was calculated using the mpmath library in Python:
|
||||
|
||||
from mpmath import *
|
||||
mp.dps = 15
|
||||
mp.pretty = True
|
||||
poly, err = chebyfit(lambda x: pow(10,x), [-1,1], 14, error=True)
|
||||
nprint([int(x * pow(2,28)) for x in poly])
|
||||
*/
|
||||
#define COEF_PREC 28
|
||||
static unsigned coef[14] = {2407, 13778, 64588, 308051, 1346110, 5261991, 18277531, 55564576, 144789513, 314406484, 546179875, 711608713, 618095479, 268435456};
|
||||
|
||||
#define DB_CALC_PREC 28
|
||||
|
||||
/* Function: db_to_mult
|
||||
|
||||
This function converts decibels into a volume multiplier. It uses a fixed-point polynomial approximation
|
||||
to 10^(db/10).
|
||||
|
||||
Parameters:
|
||||
db - The db value to convert.
|
||||
db_frac_bits - The number of binary fractional bits in the supplied decibel value
|
||||
result_frac_bits - The number of required fractional bits in the result.
|
||||
|
||||
Returns:
|
||||
The multiplier value as a fixed point value with the number of fractional bits as specified by
|
||||
the result_frac_bits parameter.
|
||||
*/
|
||||
unsigned db_to_mult(int db, int db_frac_bits, int result_frac_bits)
|
||||
{
|
||||
int intpart;
|
||||
int val = 0;
|
||||
int val0=0;
|
||||
unsigned ret;
|
||||
unsigned mask = ~((1<<DB_CALC_PREC)-1);
|
||||
|
||||
/* Make sure we get 0db bang on */
|
||||
if (db == 0)
|
||||
return (1 << result_frac_bits);
|
||||
|
||||
|
||||
/* First scale the decibal value to the required precision and divide by 10
|
||||
We scale to DB_CALC_PREC - 4 before the division with to make sure we don't overflow */
|
||||
db = db << (DB_CALC_PREC - 4 - 1 - db_frac_bits);
|
||||
db = db / 10;
|
||||
db = db << 4;
|
||||
|
||||
|
||||
/* Extract the integer part of the exponent and calculate the integer power */
|
||||
/* This could have been done a bit more efficiently by extracting the largest multiple log_10(2)
|
||||
and then calculating a power of 2 (with the polynomial calc in the range [-log_10(2),log_10(2)].
|
||||
But we have something that works here and ultra-fast performance is not a requirement */
|
||||
if (db < 0) {
|
||||
intpart = ((-db) & mask);
|
||||
db = db + intpart;
|
||||
intpart = intpart >> DB_CALC_PREC;
|
||||
|
||||
if (intpart) {
|
||||
val0 = 1 << DB_CALC_PREC;
|
||||
for (int i=0;i<intpart;i++)
|
||||
val0 = val0/10;
|
||||
}
|
||||
}
|
||||
else {
|
||||
intpart = (db & mask);
|
||||
db = db - intpart;
|
||||
intpart = intpart >> DB_CALC_PREC;
|
||||
if (intpart) {
|
||||
val0 = 1 << DB_CALC_PREC;
|
||||
for (int i=0;i<intpart;i++)
|
||||
val0 = val0*10;
|
||||
}
|
||||
}
|
||||
|
||||
/* db is now just the fractional part in the interval [-1,1] so we can approximate using
|
||||
the chebychev polynomial */
|
||||
for (int i=0;i<14;i++)
|
||||
{
|
||||
int hi=0;
|
||||
unsigned lo=0;
|
||||
|
||||
{hi, lo} = macs(db,val,hi,lo);
|
||||
|
||||
val = (hi << (32-DB_CALC_PREC)) | (lo >> DB_CALC_PREC);
|
||||
val += coef[i] >> (COEF_PREC - DB_CALC_PREC);
|
||||
}
|
||||
|
||||
/* Finally multiply by the integer power (if there was an integer part) */
|
||||
if (val0) {
|
||||
int hi=0;
|
||||
unsigned lo=0;
|
||||
|
||||
{hi, lo} = macs(val0,val,hi,lo);
|
||||
val = (hi << (32-DB_CALC_PREC)) | (lo >> DB_CALC_PREC);
|
||||
}
|
||||
|
||||
|
||||
/* We now have the result, just need to scale it to the required precision */
|
||||
ret = val;
|
||||
|
||||
if (result_frac_bits > DB_CALC_PREC) {
|
||||
return ret<<(result_frac_bits-DB_CALC_PREC);
|
||||
}
|
||||
else {
|
||||
return ret>>(DB_CALC_PREC-result_frac_bits);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_DBCALC
|
||||
#include <print.h>
|
||||
|
||||
int main() {
|
||||
|
||||
/* Check that we don't overflow up to 9db
|
||||
Should give a value just under 0x80000 */
|
||||
printhexln(db_to_mult(9,0,16));
|
||||
|
||||
/* This test recreates the old db lookup table */
|
||||
printuintln(0xffffffff);
|
||||
for (int i=1;i<128;i++) {
|
||||
printuintln(db_to_mult(-i,0,32));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
1619
module_usb_aud_shared/endpoint0/descriptors_2.h
Normal file
1619
module_usb_aud_shared/endpoint0/descriptors_2.h
Normal file
File diff suppressed because it is too large
Load Diff
58
module_usb_aud_shared/endpoint0/descriptors_2.rst
Normal file
58
module_usb_aud_shared/endpoint0/descriptors_2.rst
Normal file
@@ -0,0 +1,58 @@
|
||||
Descriptors in XMOS USB Audio
|
||||
=============================
|
||||
|
||||
ADAT Alternate Settings
|
||||
-----------------------
|
||||
|
||||
6 interfaces
|
||||
|
||||
endpoint can only be shared between alternate settings of the same interface (not between interfaces)
|
||||
|
||||
change alternate settings via SET_INTERFACE request
|
||||
|
||||
an alternate setting has its' own interface and endpoint descriptors
|
||||
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
| interface | type | alt. | endps. | note |
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
| 0 | AC | irq_in | |
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
| 1 | AS | 0 | | null interface |
|
||||
| | +-------+----------------+--------------------------------------------------+
|
||||
| | | 1 | iso_out iso_in | 18 channels, host -> device, iso_in is feedback |
|
||||
| | +-------+----------------+--------------------------------------------------+
|
||||
| | | 2 | shared | 18 channels |
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
| 2 | AS | 0 | | null interface |
|
||||
| | +-------+----------------+--------------------------------------------------+
|
||||
| | | 1 | iso_in | 18 channels, device -> host |
|
||||
| | +-------+----------------+--------------------------------------------------+
|
||||
| | | 2 | shared | 14 channels |
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
| 3 | AC | | MIDI |
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
| 4 | MS | bul_out bul_in | |
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
| 5 | DFU | | |
|
||||
+-----------+------+-------+----------------+--------------------------------------------------+
|
||||
|
||||
Interface 1: host -> device
|
||||
|
||||
Interface 2: device -> host
|
||||
|
||||
Structure of defines::
|
||||
|
||||
alt 0
|
||||
alt 1
|
||||
18 ch
|
||||
#ifdef ADAT
|
||||
alt 2
|
||||
14 ch
|
||||
#endif
|
||||
|
||||
|
||||
Inconsistencies
|
||||
---------------
|
||||
|
||||
- is MIDI AC interface is required? spec says 1 AC interface per function
|
||||
- interface association descriptor specifies 3 interfaces, but there are 6
|
||||
23
module_usb_aud_shared/endpoint0/endpoint0.h
Normal file
23
module_usb_aud_shared/endpoint0/endpoint0.h
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef _ENDPOINT0_H_
|
||||
#define _ENDPOINT0_H_
|
||||
|
||||
/** Function implementing Endpoint 0 for enumeration, control and configuration
|
||||
* of USB audio devices. It uses the descriptors defined in ``descriptors_2.h``.
|
||||
*
|
||||
* \param c_ep0_out Chanend connected to the XUD_Manager() out endpoint array
|
||||
* \param c_ep0_in Chanend connected to the XUD_Manager() in endpoint array
|
||||
* \param c_audioCtrl Chanend connected to the decouple thread for control
|
||||
* audio (sample rate changes etc.)
|
||||
* \param c_mix_ctl Optional chanend to be connected to the mixer thread if
|
||||
* present
|
||||
* \param c_clk_ctl Optional chanend to be connected to the clockgen thread if
|
||||
* present.
|
||||
*/
|
||||
void Endpoint0( chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCtrl, chanend ?c_mix_ctl,chanend ?c_clk_ctl
|
||||
#ifdef EP0_THREAD_COMBINED_WITH_SPI
|
||||
, chanend c_spi, chanend c_spi_ss
|
||||
#endif
|
||||
);
|
||||
|
||||
#endif
|
||||
840
module_usb_aud_shared/endpoint0/endpoint0.xc
Executable file
840
module_usb_aud_shared/endpoint0/endpoint0.xc
Executable file
@@ -0,0 +1,840 @@
|
||||
/**
|
||||
* @file endpoint0.xc
|
||||
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
||||
* @author Ross Owen, XMOS Semiconductor
|
||||
*/
|
||||
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
#include <safestring.h>
|
||||
|
||||
#include "xud.h" /* XUD user defines and functions */
|
||||
#include "usb.h" /* Defines from USB 2.0 Spec */
|
||||
#include "usbaudio20.h" /* Defines from USB Audio 2.0 spec */
|
||||
|
||||
#include "devicedefines.h"
|
||||
#include "DescriptorRequests.h" /* This device's descriptors */
|
||||
#include "descriptors_2.h" /* Descriptors */
|
||||
#include "clockcmds.h"
|
||||
#include "audiostream.h"
|
||||
#include "vendorrequests.h"
|
||||
#include "dfu_types.h"
|
||||
|
||||
/* Windows does not have a built in DFU driver (windows will prompt), so warn that DFU will not be functional in Audio 1.0 mode.Udi
|
||||
* Of course, OSX is unaffected.
|
||||
*/
|
||||
#if ((AUDIO_CLASS==1) || defined(AUDIO_CLASS_FALLBACK)) && defined(DFU)
|
||||
#warning DFU will require a seperate driver (but will be enabled) in AUDIO 1.0 mode
|
||||
#endif
|
||||
|
||||
/* MIDI not supported in Audio 1.0 mode */
|
||||
#if ((AUDIO_CLASS==1) || defined(AUDIO_CLASS_FALLBACK)) && defined(MIDI)
|
||||
#warning MIDI is not supported and will not be enabled in AUDIO 1.0 mode
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef PID_DFU
|
||||
#warning PID_DFU not defined, Using PID_AUDIO_2. This is probably fine!
|
||||
#endif
|
||||
|
||||
#ifdef DFU
|
||||
#include "dfu.h"
|
||||
#define DFU_IF_NUM INPUT_INTERFACES + OUTPUT_INTERFACES + MIDI_INTERFACES + 1
|
||||
|
||||
unsigned int DFU_mode_active = 0; // 0 - App active, 1 - DFU active
|
||||
extern void device_reboot(void);
|
||||
#endif
|
||||
|
||||
/* Handles Audio Class requests */
|
||||
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, SetupPacket &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
|
||||
int AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, SetupPacket &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
|
||||
|
||||
/* Global var for current frequency, set to default freq */
|
||||
unsigned int g_curSamFreq = DEFAULT_FREQ;
|
||||
unsigned int g_curSamFreq48000Family = DEFAULT_FREQ % 48000 == 0;
|
||||
unsigned int g_curSamFreqMultiplier = DEFAULT_FREQ / 48000;
|
||||
|
||||
/* Global volume and mute tables */
|
||||
int volsOut[NUM_USB_CHAN_OUT + 1];
|
||||
unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
|
||||
//unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
||||
|
||||
int volsIn[NUM_USB_CHAN_IN + 1];
|
||||
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
|
||||
//unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
||||
|
||||
unsigned char mixer1Crossbar[18];
|
||||
short mixer1Weights[18*8];
|
||||
//#define MAX_MIX_COUNT 8
|
||||
|
||||
unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
#endif
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
||||
#endif
|
||||
unsigned char mixSel[MIX_INPUTS];
|
||||
|
||||
int min(int x, int y);
|
||||
|
||||
/* Records alt setting for each interface */
|
||||
int interfaceAlt[NUM_INTERFACES] = {0, 0, 0, 0};
|
||||
|
||||
/* Global current device config var*/
|
||||
unsigned g_config = 0;
|
||||
|
||||
/* Global endpoint status arrays */
|
||||
unsigned g_epStatusOut[NUM_EP_OUT];
|
||||
unsigned g_epStatusIn[NUM_EP_IN];
|
||||
|
||||
/* Global variable for current USB bus speed (i.e. FS/HS) */
|
||||
unsigned g_curUsbSpeed = 0;
|
||||
|
||||
#ifdef HOST_ACTIVE_CALL
|
||||
void VendorHostActive(int active);
|
||||
#endif
|
||||
|
||||
/* Used when setting/clearing EP halt */
|
||||
void SetEndpointStatus(unsigned epNum, unsigned status)
|
||||
{
|
||||
/* Inspect for IN bit */
|
||||
if( epNum & 0x80 )
|
||||
{
|
||||
epNum &= 0x7f;
|
||||
|
||||
/* Range check */
|
||||
if(epNum < NUM_EP_IN)
|
||||
{
|
||||
g_epStatusIn[ epNum & 0x7F ] = status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(epNum < NUM_EP_OUT)
|
||||
{
|
||||
g_epStatusOut[ epNum ] = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define STR_USENG 0x0409
|
||||
|
||||
#define DESC_STR_LANGIDS \
|
||||
{ \
|
||||
STR_USENG & 0xff, /* 2 wLangID[0] */ \
|
||||
STR_USENG>>8, /* 3 wLangID[0] */ \
|
||||
'\0' \
|
||||
}
|
||||
|
||||
/* String descriptors */
|
||||
static unsigned char strDesc_langIDs[] = DESC_STR_LANGIDS;
|
||||
|
||||
void VendorAudioRequestsInit(chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
|
||||
|
||||
/* Endpoint 0 function. Handles all requests to the device */
|
||||
void Endpoint0( chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl
|
||||
)
|
||||
{
|
||||
unsigned char buffer[512];
|
||||
SetupPacket sp;
|
||||
XUD_ep ep0_out = XUD_Init_Ep(c_ep0_out);
|
||||
XUD_ep ep0_in = XUD_Init_Ep(c_ep0_in);
|
||||
|
||||
/* Init endpoint status tables */
|
||||
for (int i = 0; i++; i < NUM_EP_OUT)
|
||||
g_epStatusOut[i] = 0;
|
||||
|
||||
for (int i = 0; i++; i < NUM_EP_IN)
|
||||
g_epStatusIn[i] = 0;
|
||||
|
||||
/* Init tables for volumes (+ 1 for master) */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
|
||||
{
|
||||
volsOut[i] = 0;
|
||||
mutesOut[i] = 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
|
||||
{
|
||||
volsIn[i] = 0;
|
||||
mutesIn[i] = 0;
|
||||
}
|
||||
|
||||
/* Set up mixer default state */
|
||||
for (int i = 0; i < 18*8; i++) {
|
||||
mixer1Weights[i] = 0x8001; //-inf
|
||||
}
|
||||
|
||||
/* Configure default connections */
|
||||
mixer1Weights[0] = 0;
|
||||
mixer1Weights[9] = 0;
|
||||
mixer1Weights[18] = 0;
|
||||
mixer1Weights[27] = 0;
|
||||
mixer1Weights[36] = 0;
|
||||
mixer1Weights[45] = 0;
|
||||
mixer1Weights[54] = 0;
|
||||
mixer1Weights[63] = 0;
|
||||
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
/* Setup up audio output channel mapping */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
channelMapAud[i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up channel mapping default */
|
||||
for (int i = 0; i < NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
channelMap[i] = i;
|
||||
}
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
/* Mixer outputs mapping defaults */
|
||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init mixer inputs */
|
||||
for(int i = 0; i < MIX_INPUTS; i++)
|
||||
{
|
||||
mixSel[i] = i;
|
||||
}
|
||||
|
||||
/* Copy langIDs string desc into string[0] */
|
||||
/* TODO: Macro? */
|
||||
#if defined(AUDIO_CLASS_FALLBACK) || (AUDIO_CLASS == 1)
|
||||
safememcpy(strDescs_Audio1[0], strDesc_langIDs, sizeof(strDesc_langIDs));
|
||||
#endif
|
||||
safememcpy(strDescs_Audio2[0], strDesc_langIDs, sizeof(strDesc_langIDs));
|
||||
|
||||
/* Build up channel string table - By default all channels are marked as analogue
|
||||
* TODO We really want to do this an build time... */
|
||||
#if defined(SPDIF_RX) && (SPDIF_RX_INDEX != 0)
|
||||
safestrcpy(strDescs_Audio2[SPDIF_RX_INDEX + 33], "S/PDIF 1");
|
||||
safestrcpy(strDescs_Audio2[SPDIF_RX_INDEX + 34], "S/PDIF 2");
|
||||
#endif
|
||||
#if defined(ADAT_RX) && (ADAT_RX_INDEX != 0)
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 33], "ADAT 1");
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 34], "ADAT 2");
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 35], "ADAT 3");
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 36], "ADAT 4");
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 37], "ADAT 5");
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 38], "ADAT 6");
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 39], "ADAT 7");
|
||||
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 40], "ADAT 8");
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF) && (SPDIF_TX_INDEX != 0) /* "Analogue naming gets priority */
|
||||
safestrcpy(strDescs_Audio2[SPDIF_TX_INDEX + 15], "S/PDIF 1");
|
||||
safestrcpy(strDescs_Audio2[SPDIF_TX_INDEX + 16], "S/PDIF 2");
|
||||
#endif
|
||||
#if defined(ADAT_TX) && (ADAT_TX_INDEX != 0)
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 15], "ADAT 1");
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 16], "ADAT 2");
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 17], "ADAT 3");
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 18], "ADAT 4");
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 19], "ADAT 5");
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 20], "ADAT 6");
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 21], "ADAT 7");
|
||||
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 22], "ADAT 8");
|
||||
#endif
|
||||
|
||||
#ifdef VENDOR_AUDIO_REQS
|
||||
VendorAudioRequestsInit(c_audioControl, c_mix_ctl, c_clk_ctl);
|
||||
#endif
|
||||
|
||||
#ifdef DFU
|
||||
/* Check if device has started in DFU mode */
|
||||
if (DFUReportResetState(null))
|
||||
{
|
||||
/* Stop audio */
|
||||
outuint(c_audioControl, SET_SAMPLE_FREQ);
|
||||
outuint(c_audioControl, AUDIO_STOP_FOR_DFU);
|
||||
// No Handshake
|
||||
//chkct(c_audioControl, XS1_CT_END);
|
||||
DFU_mode_active = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
{
|
||||
int retVal = 1;
|
||||
|
||||
/* Do standard enumeration requests */
|
||||
#ifndef DFU
|
||||
if(g_curUsbSpeed == XUD_SPEED_HS)
|
||||
{
|
||||
|
||||
#ifdef AUDIO_CLASS_FALLBACK
|
||||
/* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */
|
||||
cfgDesc_Audio2[1] = CONFIGURATION;
|
||||
cfgDesc_Audio1[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Audio2, sizeof(devDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
devQualDesc_Audio1, sizeof(devQualDesc_Audio1),
|
||||
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
|
||||
strDescs_Audio2, sp);
|
||||
#else
|
||||
/* Return Audio 2.0 Descriptors */
|
||||
cfgDesc_Audio2[1] = CONFIGURATION;
|
||||
cfgDesc_Null[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Audio2, sizeof(devDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
devQualDesc_Null, sizeof(devQualDesc_Null),
|
||||
cfgDesc_Null, sizeof(cfgDesc_Null),
|
||||
strDescs_Audio2, sp);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return descriptors for full-speed - Audio 1.0? */
|
||||
#ifdef AUDIO_CLASS_FALLBACK
|
||||
cfgDesc_Audio1[1] = CONFIGURATION;
|
||||
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Audio1, sizeof(devDesc_Audio1),
|
||||
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
|
||||
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
strDescs_Audio1, sp);
|
||||
|
||||
#else
|
||||
cfgDesc_Null[1] = CONFIGURATION;
|
||||
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Null, sizeof(devDesc_Null),
|
||||
cfgDesc_Null, sizeof(cfgDesc_Null),
|
||||
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
strDescs_Audio2, sp);
|
||||
#endif
|
||||
|
||||
}
|
||||
#else /* ifndef DFU */
|
||||
if (!DFU_mode_active)
|
||||
{
|
||||
if(g_curUsbSpeed == XUD_SPEED_HS)
|
||||
{
|
||||
|
||||
#ifdef AUDIO_CLASS_FALLBACK
|
||||
/* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */
|
||||
cfgDesc_Audio2[1] = CONFIGURATION;
|
||||
cfgDesc_Audio1[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Audio2, sizeof(devDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
devQualDesc_Audio1, sizeof(devQualDesc_Audio1),
|
||||
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
|
||||
strDescs_Audio2, sp);
|
||||
#else
|
||||
/* Return Audio 2.0 Descriptors with Null device as fallback */
|
||||
cfgDesc_Audio2[1] = CONFIGURATION;
|
||||
cfgDesc_Null[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Audio2, sizeof(devDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
devQualDesc_Null, sizeof(devQualDesc_Null),
|
||||
cfgDesc_Null, sizeof(cfgDesc_Null),
|
||||
strDescs_Audio2, sp);
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return descriptors for full-speed - Audio 1.0? */
|
||||
#ifdef AUDIO_CLASS_FALLBACK
|
||||
cfgDesc_Audio1[1] = CONFIGURATION;
|
||||
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Audio1, sizeof(devDesc_Audio1),
|
||||
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
|
||||
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
strDescs_Audio1, sp);
|
||||
#else
|
||||
cfgDesc_Null[1] = CONFIGURATION;
|
||||
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
|
||||
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
devDesc_Null, sizeof(devDesc_Null),
|
||||
cfgDesc_Null, sizeof(cfgDesc_Null),
|
||||
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
|
||||
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
|
||||
strDescs_Audio2, sp);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Running in DFU mode - always return same descs for DFU whether HS or FS */
|
||||
retVal = DescriptorRequests(ep0_out, ep0_in,
|
||||
DFUdevDesc, sizeof(DFUdevDesc),
|
||||
DFUcfgDesc, sizeof(DFUcfgDesc),
|
||||
DFUdevQualDesc, sizeof(DFUdevQualDesc),
|
||||
DFUoSpeedCfgDesc, sizeof(DFUoSpeedCfgDesc),
|
||||
strDescs_Audio2, sp);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (retVal == 1)
|
||||
{
|
||||
/* Request not covered by XUD_DoEnumReqs() so decode ourselves */
|
||||
/* Inspect Request type and Receipient */
|
||||
switch( (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) )
|
||||
{
|
||||
case STANDARD_INTERFACE_REQUEST:
|
||||
|
||||
switch(sp.bRequest)
|
||||
{
|
||||
/* Set Interface */
|
||||
case SET_INTERFACE:
|
||||
|
||||
|
||||
#if defined(OUTPUT) && defined(INPUT)
|
||||
/* Check for stream start stop on output and input audio interfaces */
|
||||
if(sp.wValue && !interfaceAlt[1] && !interfaceAlt[2])
|
||||
{
|
||||
/* If start and input AND output not currently running */
|
||||
AudioStreamStart();
|
||||
}
|
||||
else if(((sp.wIndex == 1)&& (!sp.wValue)) && interfaceAlt[1] && (!interfaceAlt[2]))
|
||||
{
|
||||
/* if output stop and output running and input not running */
|
||||
AudioStreamStop();
|
||||
}
|
||||
else if(((sp.wIndex == 2) && (!sp.wValue)) && interfaceAlt[2] && (!interfaceAlt[1]))
|
||||
{
|
||||
/* if input stop and input running and output not running */
|
||||
AudioStreamStop();
|
||||
}
|
||||
#elif defined(OUTPUT) || defined(INPUT)
|
||||
if(sp.wValue && (!interfaceAlt[1]))
|
||||
{
|
||||
/* if start and not currently running */
|
||||
AudioStreamStart();
|
||||
}
|
||||
else if (!sp.wValue && interfaceAlt[1])
|
||||
{
|
||||
/* if stop and currently running */
|
||||
AudioStreamStop();
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Record interface change */
|
||||
if( sp.wIndex < NUM_INTERFACES )
|
||||
interfaceAlt[sp.wIndex] = sp.wValue;
|
||||
#if 1
|
||||
/* Check for audio stream from host start/stop */
|
||||
if(sp.wIndex == 2) // Input interface
|
||||
{
|
||||
switch(sp.wValue)
|
||||
{
|
||||
case 0:
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Stream active + 0 chans */
|
||||
outuint(c_audioControl, SET_CHAN_COUNT_IN);
|
||||
outuint(c_audioControl, NUM_USB_CHAN_IN);
|
||||
|
||||
#ifdef ADAT_RX
|
||||
outuint(c_clk_ctl, SET_SMUX);
|
||||
outuint(c_clk_ctl, 0);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
#ifdef ADAT_RX
|
||||
case 2:
|
||||
|
||||
/* Stream active + 8 chans */
|
||||
outuint(c_audioControl, SET_CHAN_COUNT_IN);
|
||||
outuint(c_audioControl, NUM_USB_CHAN_IN-4);
|
||||
|
||||
outuint(c_clk_ctl, SET_SMUX);
|
||||
outuint(c_clk_ctl, 1);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
outuint(c_audioControl, SET_CHAN_COUNT_IN);
|
||||
outuint(c_audioControl, NUM_USB_CHAN_IN-6);
|
||||
|
||||
|
||||
outuint(c_clk_ctl, SET_SMUX);
|
||||
outuint(c_clk_ctl, 1);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
/* Stream active + 8 chans */
|
||||
//outuint(c_audioControl, 8);
|
||||
// Handshake
|
||||
//chkct(c_audioControl, XS1_CT_END);
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* No data stage for this request, just do data stage */
|
||||
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
|
||||
break;
|
||||
|
||||
/* A device must support the GetInterface request if it has alternate setting for that interface */
|
||||
case GET_INTERFACE:
|
||||
|
||||
buffer[0] = 0;
|
||||
|
||||
/* Bounds check */
|
||||
if( sp.wIndex < NUM_INTERFACES )
|
||||
buffer[0] = interfaceAlt[sp.wIndex];
|
||||
|
||||
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 1, sp.wLength);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
printstr("Unknown Standard Interface Request: ");
|
||||
printhexln(sp.bRequest);
|
||||
printhexln(sp.bmRequestType.Type);
|
||||
printhexln(sp.bmRequestType.Recipient);
|
||||
printhexln(sp.bmRequestType.Recipient | (sp.bmRequestType.Type << 5));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Recipient: Device */
|
||||
case STANDARD_DEVICE_REQUEST:
|
||||
|
||||
/* Standard Device requests (8) */
|
||||
switch( sp.bRequest )
|
||||
{
|
||||
|
||||
/* Set Device Address: This is a unique set request. */
|
||||
case SET_ADDRESS:
|
||||
|
||||
/* Status stage: Send a zero length packet */
|
||||
retVal = XUD_SetBuffer_ResetPid(ep0_in, buffer, 0, PIDn_DATA1);
|
||||
|
||||
/* TODO We should wait until ACK is received for status stage before changing address */
|
||||
//XUD_Sup_Delay(50000);
|
||||
{
|
||||
timer t;
|
||||
unsigned time;
|
||||
t :> time;
|
||||
t when timerafter(time+50000) :> void;
|
||||
}
|
||||
|
||||
/* Set device address in XUD */
|
||||
XUD_SetDevAddr(sp.wValue);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
/* TODO Check direction */
|
||||
/* Standard request: SetConfiguration */
|
||||
case SET_CONFIGURATION:
|
||||
|
||||
g_config = sp.wValue;
|
||||
|
||||
#ifdef HOST_ACTIVE_CALL
|
||||
if(g_config == 1)
|
||||
{
|
||||
/* Consider host active with valid driver at this point */
|
||||
VendorHostActive(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No data stage for this request, just do status stage */
|
||||
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
|
||||
break;
|
||||
|
||||
case GET_CONFIGURATION:
|
||||
buffer[0] = g_config;
|
||||
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 1, sp.wLength);
|
||||
break;
|
||||
|
||||
/* Get Status request */
|
||||
case GET_STATUS:
|
||||
|
||||
buffer[0] = 0; // bus powered
|
||||
buffer[1] = 0; // remote wakeup not supported
|
||||
|
||||
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2, sp.wLength);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
XUD_Error("Unknown device request");
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
/* Receipient: Endpoint */
|
||||
case STANDARD_ENDPOINT_REQUEST:
|
||||
|
||||
/* Standard endpoint requests */
|
||||
switch ( sp.bRequest )
|
||||
{
|
||||
|
||||
/* ClearFeature */
|
||||
case CLEAR_FEATURE:
|
||||
|
||||
switch ( sp.wValue )
|
||||
{
|
||||
case ENDPOINT_HALT:
|
||||
|
||||
/* Mark the endpoint status */
|
||||
|
||||
SetEndpointStatus(sp.wIndex, 0);
|
||||
|
||||
/* No data stage for this request, just do status stage */
|
||||
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
XUD_Error( "Unknown request in Endpoint ClearFeature" );
|
||||
break;
|
||||
}
|
||||
break; /* B_REQ_CLRFEAR */
|
||||
|
||||
/* SetFeature */
|
||||
case SET_FEATURE:
|
||||
|
||||
switch( sp.wValue )
|
||||
{
|
||||
case ENDPOINT_HALT:
|
||||
|
||||
/* Check request is in range */
|
||||
SetEndpointStatus(sp.wIndex, 1);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
XUD_Error("Unknown feature in SetFeature Request");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
/* Endpoint GetStatus Request */
|
||||
case GET_STATUS:
|
||||
|
||||
buffer[0] = 0;
|
||||
buffer[1] = 0;
|
||||
|
||||
if( sp.wIndex & 0x80 )
|
||||
{
|
||||
/* IN Endpoint */
|
||||
if((sp.wIndex&0x7f) < NUM_EP_IN)
|
||||
{
|
||||
buffer[0] = ( g_epStatusIn[ sp.wIndex & 0x7F ] & 0xff );
|
||||
buffer[1] = ( g_epStatusIn[ sp.wIndex & 0x7F ] >> 8 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OUT Endpoint */
|
||||
if(sp.wIndex < NUM_EP_OUT)
|
||||
{
|
||||
buffer[0] = ( g_epStatusOut[ sp.wIndex ] & 0xff );
|
||||
buffer[1] = ( g_epStatusOut[ sp.wIndex ] >> 8 );
|
||||
}
|
||||
}
|
||||
|
||||
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2, sp.wLength);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
//printstrln("Unknown Standard Endpoint Request");
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case CLASS_INTERFACE_REQUEST:
|
||||
case CLASS_ENDPOINT_REQUEST:
|
||||
{
|
||||
unsigned interfaceNum = sp.wIndex & 0xff;
|
||||
unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5);
|
||||
|
||||
/* TODO Check interface number */
|
||||
/* TODO Check on return value retval = */
|
||||
#ifdef DFU
|
||||
unsigned DFU_IF = DFU_IF_NUM;
|
||||
|
||||
/* DFU interface number changes based on which mode we are currently running in */
|
||||
if (DFU_mode_active)
|
||||
{
|
||||
DFU_IF = 0;
|
||||
}
|
||||
|
||||
if (interfaceNum == DFU_IF)
|
||||
{
|
||||
|
||||
/* If running in application mode stop audio */
|
||||
/* Don't interupt audio for save and restore cmds */
|
||||
if ((DFU_IF == DFU_IF_NUM) && (sp.bRequest != XMOS_DFU_SAVESTATE) && (sp.bRequest != XMOS_DFU_RESTORESTATE))
|
||||
{
|
||||
// Stop audio
|
||||
outuint(c_audioControl, SET_SAMPLE_FREQ);
|
||||
outuint(c_audioControl, AUDIO_STOP_FOR_DFU);
|
||||
// Handshake
|
||||
chkct(c_audioControl, XS1_CT_END);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* This will return 1 if reset requested */
|
||||
if (DFUDeviceRequests(ep0_out, ep0_in, sp, null, interfaceAlt[sp.wIndex], 1))
|
||||
{
|
||||
timer tmr;
|
||||
unsigned s;
|
||||
/* Send reboot command */
|
||||
//outuint(c_audioControl, SET_SAMPLE_FREQ);
|
||||
//outuint(c_audioControl, AUDIO_REBOOT_FROM_DFU);
|
||||
tmr :> s;
|
||||
tmr when timerafter(s + 50000000) :> s;
|
||||
device_reboot();
|
||||
}
|
||||
|
||||
/* TODO we should not make the assumption that all DFU requests are handled */
|
||||
retVal = 0;
|
||||
}
|
||||
/* Check for: Audio interface request - always 0, note we check for DFU first
|
||||
* Audio endpoint request */
|
||||
else if(((request == CLASS_INTERFACE_REQUEST) && (interfaceNum == 0))
|
||||
|| (request == CLASS_ENDPOINT_REQUEST && ((interfaceNum == 0x82) || (interfaceNum == 0x01))))
|
||||
{
|
||||
#endif
|
||||
|
||||
#if (AUDIO_CLASS == 2) && defined(AUDIO_CLASS_FALLBACK)
|
||||
if(g_curUsbSpeed == XUD_SPEED_HS)
|
||||
{
|
||||
retVal = AudioClassRequests_2(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = AudioClassRequests_1(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
|
||||
}
|
||||
#elif (AUDIO_CLASS==2)
|
||||
retVal = AudioClassRequests_2(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
|
||||
#else
|
||||
retVal = AudioClassRequests_1(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
|
||||
#endif
|
||||
|
||||
#ifdef VENDOR_AUDIO_REQS
|
||||
/* If retVal is 1 at this point, then request to audio interface not handled - handle vendor audio reqs */
|
||||
if(retVal == 1)
|
||||
{
|
||||
retVal = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest,
|
||||
sp.wValue >> 8, sp.wValue & 0xff,
|
||||
sp.wIndex >> 8, sp.bmRequestType.Direction,
|
||||
c_audioControl, c_mix_ctl, c_clk_ctl);
|
||||
}
|
||||
#endif
|
||||
#ifdef DFU
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//printstr("unrecognised request\n");
|
||||
//printhexln(sp.bRequest);
|
||||
//printhexln(sp.bmRequestType.Type);
|
||||
//printhexln(sp.bmRequestType.Recipient);
|
||||
//printhexln(sp.bmRequestType.Recipient | (sp.bmRequestType.Type << 5));
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} /* if(retVal == 0) */
|
||||
|
||||
if(retVal == 1)
|
||||
{
|
||||
/* Did not handle request - Protocol Stall Secion 8.4.5 of USB 2.0 spec
|
||||
* Detailed in Section 8.5.3. Protocol stall is unique to control pipes.
|
||||
Protocol stall differs from functional stall in meaning and duration.
|
||||
A protocol STALL is returned during the Data or Status stage of a control
|
||||
transfer, and the STALL condition terminates at the beginning of the
|
||||
next control transfer (Setup). The remainder of this section refers to
|
||||
the general case of a functional stall */
|
||||
XUD_SetStall_Out(0);
|
||||
XUD_SetStall_In(0);
|
||||
}
|
||||
|
||||
if (retVal < 0)
|
||||
{
|
||||
g_curUsbSpeed = XUD_ResetEndpoint(ep0_in, ep0_out);
|
||||
|
||||
g_config = 0;
|
||||
|
||||
#ifdef DFU
|
||||
if (DFUReportResetState(null))
|
||||
{
|
||||
if (!DFU_mode_active)
|
||||
{
|
||||
timer tmr;
|
||||
unsigned s;
|
||||
DFU_mode_active = 1;
|
||||
//tmr :> s;
|
||||
//tmr when timerafter(s + 500000) :> s;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DFU_mode_active)
|
||||
{
|
||||
timer tmr;
|
||||
unsigned s;
|
||||
// Restart audio
|
||||
//outuint(c_audioControl, AUDIO_START_FROM_DFU);
|
||||
DFU_mode_active = 0;
|
||||
// Send reboot command
|
||||
//outuint(c_audioControl, SET_SAMPLE_FREQ);
|
||||
//outuint(c_audioControl, AUDIO_REBOOT_FROM_DFU);
|
||||
// No handshake on reboot
|
||||
tmr :> s;
|
||||
tmr when timerafter(s + 5000000) :> s;
|
||||
device_reboot();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
16
module_usb_aud_shared/endpoint0/vendorrequests.h
Normal file
16
module_usb_aud_shared/endpoint0/vendorrequests.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef _VENDORREQUESTS_H_
|
||||
#define _VENDORREQUESTS_H_
|
||||
|
||||
/* Functions that handle vustomer vendor requests.
|
||||
*
|
||||
* THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN
|
||||
*
|
||||
* Should return 0 if handled sucessfully, else return 0 (-1 for passing up reset/suspend)
|
||||
*
|
||||
* */
|
||||
|
||||
int VendorAudioRequests(XUD_ep ep0_out, XUD_ep ep0_in, unsigned char bRequest, unsigned char cs, unsigned char cn,
|
||||
unsigned short unitId, unsigned char direction, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctL);
|
||||
|
||||
#endif
|
||||
|
||||
4
module_usb_aud_shared/i2c/i2c.h
Normal file
4
module_usb_aud_shared/i2c/i2c.h
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
void I2cRegWrite(int deviceAdrs, int Adrs, int WrData, port AUD_SCLK, port AUD_SDIN);
|
||||
|
||||
int I2cRegRead(int deviceAdrs, int Adrs, port AUD_SCLK, port AUD_SDIN);
|
||||
321
module_usb_aud_shared/i2c/i2c.xc
Executable file
321
module_usb_aud_shared/i2c/i2c.xc
Executable file
@@ -0,0 +1,321 @@
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
|
||||
int I2cRegRead(int device, int addr, port scl, port sda)
|
||||
{
|
||||
//int Result;
|
||||
timer gt;
|
||||
unsigned time;
|
||||
int Temp, CtlAdrsData, i;
|
||||
// three device ACK
|
||||
int ack[3];
|
||||
int rdData;
|
||||
|
||||
// initial values.
|
||||
scl <: 1;
|
||||
sda <: 1;
|
||||
sync(sda);
|
||||
gt :> time;
|
||||
time += 1000 + 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
// start bit on SDI
|
||||
scl <: 1;
|
||||
sda <: 0;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
// shift 7bits of address and 1bit R/W (fixed to write).
|
||||
// WARNING: Assume MSB first.
|
||||
for (i = 0; i < 8; i += 1)
|
||||
{
|
||||
Temp = (device >> (7 - i)) & 0x1;
|
||||
sda <: Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
}
|
||||
// turn the data to input
|
||||
sda :> Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
// sample first ACK.
|
||||
sda :> ack[0];
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
|
||||
CtlAdrsData = (addr & 0xFF);
|
||||
// shift first 8 bits.
|
||||
for (i = 0; i < 8; i += 1)
|
||||
{
|
||||
Temp = (CtlAdrsData >> (7 - i)) & 0x1;
|
||||
sda <: Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
}
|
||||
// turn the data to input
|
||||
sda :> Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
// sample second ACK.
|
||||
sda :> ack[1];
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
|
||||
|
||||
// stop bit
|
||||
gt :> time;
|
||||
time += 1000 + 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
// start bit on SDI
|
||||
scl <: 1;
|
||||
sda <: 1;
|
||||
time += 1000 + 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
time += 1000 + 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
|
||||
|
||||
// send address and read
|
||||
scl <: 1;
|
||||
sda <: 1;
|
||||
sync(sda);
|
||||
gt :> time;
|
||||
time += 1000 + 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
// start bit on SDI
|
||||
scl <: 1;
|
||||
sda <: 0;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
// shift 7bits of address and 1bit R/W (fixed to write).
|
||||
// WARNING: Assume MSB first.
|
||||
for (i = 0; i < 8; i += 1)
|
||||
{
|
||||
int deviceAddr = device | 1;
|
||||
Temp = (deviceAddr >> (7 - i)) & 0x1;
|
||||
sda <: Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
}
|
||||
// turn the data to input
|
||||
sda :> Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
// sample first ACK.
|
||||
sda :> ack[0];
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
|
||||
|
||||
rdData = 0;
|
||||
// shift second 8 bits.
|
||||
for (i = 0; i < 8; i += 1)
|
||||
{
|
||||
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
|
||||
sda :> Temp;
|
||||
rdData = (rdData << 1) | (Temp & 1);
|
||||
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
}
|
||||
|
||||
// turn the data to input
|
||||
sda :> Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
// sample second ACK.
|
||||
sda :> ack[2];
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 0;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> int _;
|
||||
scl <: 1;
|
||||
// put the data to a good value for next round.
|
||||
sda <: 1;
|
||||
// validate all items are ACK properly.
|
||||
//Result = 0;
|
||||
//for (i = 0; i < 3; i += 1)
|
||||
//{
|
||||
//if ((ack[i]&1) != 0)
|
||||
//{
|
||||
//Result = Result | (1 << i);
|
||||
//}
|
||||
//}
|
||||
|
||||
return rdData;
|
||||
}
|
||||
|
||||
void I2cRegWrite(int device, int addr, int data, port scl, port sda)
|
||||
{
|
||||
//int Result;
|
||||
timer gt;
|
||||
unsigned time;
|
||||
int Temp, CtlAdrsData, i;
|
||||
// three device ACK
|
||||
int ack[3];
|
||||
|
||||
// initial values.
|
||||
scl <: 1;
|
||||
sda <: 1;
|
||||
sync(sda);
|
||||
|
||||
gt :> time;
|
||||
time += 1000 + 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
|
||||
// start bit on SDI
|
||||
scl <: 1;
|
||||
sda <: 0;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 0;
|
||||
|
||||
// shift 7bits of address and 1bit R/W (fixed to write).
|
||||
// WARNING: Assume MSB first.
|
||||
for (i = 0; i < 8; i += 1)
|
||||
{
|
||||
Temp = (device >> (7 - i)) & 0x1;
|
||||
sda <: Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 1;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 0;
|
||||
}
|
||||
|
||||
// turn the data to input
|
||||
sda :> Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 1;
|
||||
|
||||
// sample first ACK.
|
||||
sda :> ack[0];
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 0;
|
||||
|
||||
CtlAdrsData = (addr & 0xFF);
|
||||
|
||||
// shift first 8 bits.
|
||||
for (i = 0; i < 8; i += 1)
|
||||
{
|
||||
Temp = (CtlAdrsData >> (7 - i)) & 0x1;
|
||||
sda <: Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 1;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 0;
|
||||
}
|
||||
// turn the data to input
|
||||
sda :> Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 1;
|
||||
// sample second ACK.
|
||||
sda :> ack[1];
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 0;
|
||||
|
||||
CtlAdrsData = (data & 0xFF);
|
||||
// shift second 8 bits.
|
||||
for (i = 0; i < 8; i += 1)
|
||||
{
|
||||
Temp = (CtlAdrsData >> (7 - i)) & 0x1;
|
||||
sda <: Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 1;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 0;
|
||||
}
|
||||
// turn the data to input
|
||||
sda :> Temp;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 1;
|
||||
// sample second ACK.
|
||||
sda :> ack[2];
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 0;
|
||||
gt :> time;
|
||||
time += 1000;
|
||||
gt when timerafter(time) :> void;
|
||||
scl <: 1;
|
||||
// put the data to a good value for next round.
|
||||
sda <: 1;
|
||||
// validate all items are ACK properly.
|
||||
//Result = 0;
|
||||
//for (i = 0; i < 3; i += 1)
|
||||
//{
|
||||
//if ((ack[i]&1) != 0)
|
||||
//{
|
||||
//Result = Result | (1 << i);
|
||||
//}
|
||||
//}
|
||||
//return(Result);
|
||||
}
|
||||
167
module_usb_aud_shared/mixer/fastmix.S
Normal file
167
module_usb_aud_shared/mixer/fastmix.S
Normal file
@@ -0,0 +1,167 @@
|
||||
//#include "devicedefines.h"
|
||||
|
||||
#define MAX_MIX_COUNT 8
|
||||
#define MIX_INPUTS 18
|
||||
|
||||
|
||||
|
||||
#define DOMIX_TOP(i) \
|
||||
.cc_top doMix##i.function,doMix##i; \
|
||||
.align 4 ;\
|
||||
.globl doMix##i ;\
|
||||
.globl doMix##i##.nstackwords ;\
|
||||
.globl doMix##i##.maxthreads ; \
|
||||
.globl doMix##i##.maxtimers ; \
|
||||
.globl doMix##i##.maxchanends ; \
|
||||
.globl doMix##i##.maxsync ;\
|
||||
.linkset doMix##i##.locnoside, 1; \
|
||||
.linkset doMix##i##.locnochandec, 1;\
|
||||
.linkset doMix##i##.nstackwords, 0 ;\
|
||||
.linkset doMix##i##.maxchanends, 0 ;\
|
||||
.linkset doMix##i##.maxtimers, 0 ;\
|
||||
.linkset doMix##i##.maxthreads, 1; \
|
||||
doMix##i##: ;\
|
||||
set cp, r0; \
|
||||
set dp, r1; \
|
||||
lsub r0, r1, r0, r0, r0;\
|
||||
.label_##i##:
|
||||
|
||||
#define DOMIX_BOT(i) \
|
||||
ldap r11, _dp; \
|
||||
set dp, r11;\
|
||||
ldap r11, _cp;\
|
||||
set cp, r11;\
|
||||
\
|
||||
mov r0, r1;\
|
||||
ldc r2, 0x19;\
|
||||
sext r0, r2;\
|
||||
eq r0, r0, r1;\
|
||||
bf r0, .L20; \
|
||||
\
|
||||
shl r0, r1, 0x7;\
|
||||
retsp 0x0;\
|
||||
\
|
||||
\
|
||||
.cc_bottom doMix##i##.function;
|
||||
|
||||
#define N MIX_INPUTS
|
||||
#define BODY(i) \
|
||||
ldw r2,cp[i]; \
|
||||
ldw r11, dp[i]; \
|
||||
maccs r1, r0, r2, r11;
|
||||
|
||||
|
||||
.text
|
||||
|
||||
.L20:\
|
||||
lss r0, r1, r3;\
|
||||
bt r0, .L16; \
|
||||
ldw r0, cp[.LC0];\
|
||||
retsp 0x0; \
|
||||
.L16:\
|
||||
ldw r0, cp[.LC1];\
|
||||
retsp 0x0; \
|
||||
|
||||
|
||||
|
||||
|
||||
#if(MAX_MIX_COUNT > 0)
|
||||
DOMIX_TOP(0)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(0)
|
||||
#endif
|
||||
|
||||
|
||||
#if(MAX_MIX_COUNT > 1)
|
||||
DOMIX_TOP(1)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(1)
|
||||
#endif
|
||||
|
||||
#if(MAX_MIX_COUNT > 2)
|
||||
DOMIX_TOP(2)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(2)
|
||||
#endif
|
||||
|
||||
#if(MAX_MIX_COUNT > 3)
|
||||
DOMIX_TOP(3)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(3)
|
||||
#endif
|
||||
|
||||
#if(MAX_MIX_COUNT > 4)
|
||||
DOMIX_TOP(4)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(4)
|
||||
#endif
|
||||
|
||||
#if(MAX_MIX_COUNT > 5)
|
||||
DOMIX_TOP(5)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(5)
|
||||
#endif
|
||||
|
||||
#if(MAX_MIX_COUNT > 6)
|
||||
DOMIX_TOP(6)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(6)
|
||||
#endif
|
||||
|
||||
#if(MAX_MIX_COUNT > 7)
|
||||
DOMIX_TOP(7)
|
||||
#include "repeat.h"
|
||||
DOMIX_BOT(7)
|
||||
#endif
|
||||
|
||||
#if(MAX_MIX_COUNT>8)
|
||||
#error MAX_MIX_COUNT>7
|
||||
#endif
|
||||
|
||||
/* We need MIX_OUTPUT x setPtr functions */
|
||||
|
||||
#undef N
|
||||
#undef BODY
|
||||
#define N MAX_MIX_COUNT
|
||||
.cc_top setPtr.function,setPtr;
|
||||
.align 4 ;
|
||||
.globl setPtr.nstackwords;
|
||||
.globl setPtr;
|
||||
.globl setPtr.maxthreads;
|
||||
.globl setPtr.maxtimers;
|
||||
.globl setPtr.maxchanends;
|
||||
.globl setPtr.maxsync;
|
||||
.linkset setPtr.locnoside, 1;
|
||||
.linkset setPtr.locnochandec, 1;
|
||||
.linkset setPtr.nstackwords, 0;
|
||||
.linkset setPtr.maxchanends, 0;
|
||||
.linkset setPtr.maxtimers, 0;
|
||||
.linkset setPtr.maxthreads, 1;
|
||||
setPtr:
|
||||
shl r2, r2, 1
|
||||
.xtabranch .label_0
|
||||
bru r2
|
||||
#define BODY(i) \
|
||||
ldap r11, .label_##i; \
|
||||
bu setPtr_go
|
||||
#include "repeat.h"
|
||||
setPtr_go:
|
||||
shl r0, r0, 3;
|
||||
ldc r2, 0x80;
|
||||
add r1, r1, r2;
|
||||
st8 r1, r11[r0];
|
||||
retsp 0;
|
||||
.cc_bottom setPtr.function
|
||||
|
||||
.section .cp.const4, "acM", @progbits, 4
|
||||
.LC0:
|
||||
.align 4
|
||||
.int 0x7fffff00
|
||||
.LC1:
|
||||
.int 0x80000000
|
||||
|
||||
#undef N
|
||||
#undef BODY
|
||||
|
||||
|
||||
|
||||
32
module_usb_aud_shared/mixer/mixer.h
Normal file
32
module_usb_aud_shared/mixer/mixer.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef __mixer_h__
|
||||
#define __mixer_h__
|
||||
|
||||
enum mix_ctl_cmd {
|
||||
SET_SAMPLES_TO_HOST_MAP,
|
||||
SET_SAMPLES_TO_DEVICE_MAP,
|
||||
SET_MIX_MULT,
|
||||
SET_MIX_MAP,
|
||||
SET_MIX_IN_VOL,
|
||||
SET_MIX_OUT_VOL,
|
||||
GET_INPUT_LEVELS,
|
||||
GET_STREAM_LEVELS,
|
||||
GET_OUTPUT_LEVELS
|
||||
};
|
||||
|
||||
|
||||
/** Digital sample mixer.
|
||||
*
|
||||
* This thread mixes audio streams between the decouple() thread and
|
||||
* the audio() thread.
|
||||
*
|
||||
* \param c_to_host a chanend connected to the decouple() thread for
|
||||
* receiving/transmitting samples
|
||||
* \param c_to_audio a chanend connected to the audio() thread for
|
||||
* receiving/transmitting samples
|
||||
* \param c_mix_ctl a chanend connected to the Endpoint0() thread for
|
||||
* receiving control commands
|
||||
*
|
||||
*/
|
||||
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
|
||||
|
||||
#endif
|
||||
669
module_usb_aud_shared/mixer/mixer.xc
Normal file
669
module_usb_aud_shared/mixer/mixer.xc
Normal file
@@ -0,0 +1,669 @@
|
||||
|
||||
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
#include "mixer.h"
|
||||
#include "devicedefines.h"
|
||||
|
||||
#ifdef MIXER
|
||||
|
||||
#define FAST_MIXER 1
|
||||
#warning USING FAST MIXER
|
||||
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
static unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
||||
#endif
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||
static unsigned abs(int x)
|
||||
{
|
||||
#if 0
|
||||
if (x < 0)
|
||||
return x*-1;
|
||||
return x;
|
||||
#else
|
||||
int const mask = x >> sizeof(int) * 8 - 1;
|
||||
return (x + mask) ^ mask;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
|
||||
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
|
||||
int samples_to_host_map[NUM_USB_CHAN_IN];
|
||||
|
||||
int samples_to_device_map[NUM_USB_CHAN_OUT];
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
int mix_mult[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
#ifndef FAST_MIXER
|
||||
int mix_map[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Arrays for level data */
|
||||
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
int samples_to_host_inputs_buff[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */
|
||||
#endif
|
||||
static int samples_to_host_streams[NUM_USB_CHAN_OUT]; /* Audio stream to host from host */
|
||||
static int samples_to_host_outputs[NUM_USB_CHAN_OUT]; /* Device outputs */
|
||||
|
||||
#if 0
|
||||
#pragma xta command "add exclusion mixer1_rate_change"
|
||||
#pragma xta command "analyse path mixer1_req mixer1_req"
|
||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#pragma xta command "add exclusion mixer2_rate_change"
|
||||
#pragma xta command "analyse path mixer2_req mixer2_req"
|
||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||
static inline void ComputeMixerLevel(int sample, int i)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
unsigned ptr;
|
||||
|
||||
|
||||
x = abs(sample);
|
||||
|
||||
/* y = samples_to_host_outputs[i] */
|
||||
asm("ldaw %0, dp[samples_to_host_outputs]":"=r"(ptr):); /* Might want to hoist this */
|
||||
asm("ldw %0, %1[%2]":"=r"(y):"r"(ptr),"r"(i));
|
||||
|
||||
if(x > y)
|
||||
{
|
||||
/* samples_to_host_outputs[i] = x; */
|
||||
asm("stw %0, %1[%2]"::"r"(y),"r"(ptr),"r"(i));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef FAST_MIXER
|
||||
void setPtr(int src, int dst, int mix);
|
||||
int doMix0(const int samples[], int mult[]);
|
||||
int doMix1(const int samples[], int mult[]);
|
||||
int doMix2(const int samples[], int mult[]);
|
||||
int doMix3(const int samples[], int mult[]);
|
||||
int doMix4(const int samples[], int mult[]);
|
||||
int doMix5(const int samples[], int mult[]);
|
||||
int doMix6(const int samples[], int mult[]);
|
||||
int doMix7(const int samples[], int mult[]);
|
||||
int doMix8(const int samples[], int mult[]);
|
||||
#else
|
||||
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
|
||||
/* At 18 x 12dB we could get 64 x bigger */
|
||||
#pragma unsafe arrays
|
||||
int doMix(const int samples[], const int ptr[], int mult[])
|
||||
{
|
||||
int h=0;
|
||||
int l=0;
|
||||
|
||||
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */
|
||||
#pragma loop unroll
|
||||
for (int i=0; i<MIX_INPUTS; i++)
|
||||
{
|
||||
{h,l} = macs(samples[ptr[i]], mult[i], h, l);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* Perform saturation */
|
||||
l = sext(h, 25);
|
||||
|
||||
if(l != h)
|
||||
{
|
||||
//if(h < 0)
|
||||
if(h>>32)
|
||||
h = (0x80000000>>7);
|
||||
else
|
||||
h = (0x7fffff00>>7);
|
||||
}
|
||||
#endif
|
||||
return h<<7;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma unsafe arrays
|
||||
void giveSamplesToHost(chanend c, const int samples[], const int ptr[], const unsigned multIn[])
|
||||
{
|
||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
int sample;
|
||||
sample = samples[ptr[i]];
|
||||
|
||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#warning IN Vols in mixer, AFTER mix & map
|
||||
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
|
||||
mult = multIn[i];
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
|
||||
//h <<= 3 done on other side */
|
||||
|
||||
outuint(c, h);
|
||||
#else
|
||||
outuint(c,sample);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#pragma unsafe arrays
|
||||
static void getSamplesFromHost(chanend c, const int samples[], int base)
|
||||
{
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
int sample, x;
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
/* Receive sample from decouple */
|
||||
sample = inuint(c);
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
/* Compute peak level data */
|
||||
x = abs(sample);
|
||||
if(x > samples_to_host_streams[i])
|
||||
samples_to_host_streams[i] = x;
|
||||
#endif
|
||||
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
||||
#warning OUT Vols in mixer, BEFORE mix & map
|
||||
asm("ldw %0, %1[%2]":"=r"(mult):"r"(multOut),"r"(i));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h<<=3;
|
||||
asm("stw %0, %1[%2]"::"r"(h),"r"(samples),"r"(base+i));
|
||||
#else
|
||||
asm("stw %0, %1[%2]"::"r"(sample),"r"(samples),"r"(base+i));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#pragma unsafe arrays
|
||||
void giveSamplesToDevice(chanend c, const int samples[],const int ptr[], const unsigned multOut[])
|
||||
{
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
int sample,x;
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
|
||||
sample = samples[ptr[i]];
|
||||
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
#warning OUT Vols in mixer, AFTER mix & map
|
||||
mult = multOut[i];
|
||||
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multOut),"r"(i));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
//h <<= 3 done in audio thread
|
||||
outuint(c, h);
|
||||
#else
|
||||
outuint(c, sample);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#pragma unsafe arrays
|
||||
void getSamplesFromDevice(chanend c, const int samples[], int base)
|
||||
{
|
||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
int sample;
|
||||
int x;
|
||||
sample = inuint(c);
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
/* Compute peak level data */
|
||||
x = abs(sample);
|
||||
if(x > samples_to_host_inputs[i])
|
||||
samples_to_host_inputs[i] = x;
|
||||
#endif
|
||||
|
||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
||||
asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<=3;
|
||||
asm("stw %0, %1[%2]"::"r"(h),"r"(samples),"r"(base+i));
|
||||
#else
|
||||
asm("stw %0, %1[%2]"::"r"(sample),"r"(samples),"r"(base+i));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int mixer1_mix2_flag = (DEFAULT_FREQ > 96000);
|
||||
|
||||
#pragma unsafe arrays
|
||||
void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
{
|
||||
int mixed;
|
||||
unsigned cmd;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
#pragma xta endpoint "mixer1_req"
|
||||
inuint(c_mixer2);
|
||||
|
||||
/* Request data from decouple thread */
|
||||
outuint(c_host, 0);
|
||||
|
||||
/* Between request to decouple and respose ~ 400nS latency for interrupt to fire */
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_mix_ctl, cmd):
|
||||
{
|
||||
int mix, index, val;
|
||||
switch (cmd)
|
||||
{
|
||||
#if MAX_MIX_COUNT > 0
|
||||
case SET_SAMPLES_TO_HOST_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
asm("stw %0, %1[%2]"::"r"(val),"r"(samples_to_host_map),"r"(index));
|
||||
break;
|
||||
|
||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
asm("stw %0, %1[%2]"::"r"(val),"r"(samples_to_device_map),"r"(index));
|
||||
break;
|
||||
|
||||
case SET_MIX_MULT:
|
||||
mix = inuint(c_mix_ctl);
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
asm("stw %0, %1[%2]"::"r"(val),"r"(mix_mult[mix]),"r"(index));
|
||||
break;
|
||||
|
||||
case SET_MIX_MAP:
|
||||
mix = inuint(c_mix_ctl);
|
||||
index = inuint(c_mix_ctl); /* mixer input */
|
||||
val = inuint(c_mix_ctl); /* source */
|
||||
inct(c_mix_ctl);
|
||||
#ifdef FAST_MIXER
|
||||
setPtr(index, val, mix);
|
||||
#else
|
||||
asm("stw %0, %1[%2]"::"r"(val),"r"(mix_map[mix]),"r"(index));
|
||||
#endif
|
||||
break;
|
||||
#endif /* if MAX_MIX_COUNT > 0 */
|
||||
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
case SET_MIX_IN_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
asm("stw %0, %1[%2]"::"r"(val),"r"(multIn),"r"(index));
|
||||
break;
|
||||
#endif
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
case SET_MIX_OUT_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
asm("stw %0, %1[%2]"::"r"(val),"r"(multOut),"r"(index));
|
||||
break;
|
||||
#endif
|
||||
|
||||
case GET_STREAM_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
outuint(c_mix_ctl, samples_to_host_streams[index]);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
samples_to_host_streams[index] = 0;
|
||||
break;
|
||||
|
||||
case GET_INPUT_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
/* Level LEDS process reseting samples_to_host_inputs
|
||||
* Other side makes sure we don't miss a peak */
|
||||
asm("ldw %0, %1[%2]":"=r"(val):"r"(samples_to_host_inputs_buff),"r"(index));
|
||||
asm("stw %0, %1[%2]"::"r"(0),"r"(samples_to_host_inputs_buff),"r"(index));
|
||||
#else
|
||||
/* We dont have a level LEDs process, so reset ourselves */
|
||||
asm("ldw %0, %1[%2]":"=r"(val):"r"(samples_to_host_inputs),"r"(index));
|
||||
asm("stw %0, %1[%2]"::"r"(0),"r"(samples_to_host_inputs),"r"(index));
|
||||
#endif
|
||||
outuint(c_mix_ctl, val);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
case GET_OUTPUT_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
asm("ldw %0, %1[%2]":"=r"(val):"r"(samples_to_host_outputs),"r"(index));
|
||||
asm("stw %0, %1[%2]"::"r"(mix),"r"(samples_to_host_outputs),"r"(index));
|
||||
outuint(c_mix_ctl, val);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Select default */
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Get response from decouple */
|
||||
if(testct(c_host))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer1_rate_change"
|
||||
inct(c_host);
|
||||
sampFreq = inuint(c_host);
|
||||
|
||||
mixer1_mix2_flag = sampFreq > 96000;
|
||||
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
{
|
||||
asm("stw %0, %1[%2]"::"r"(0),"r"(samples),"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i));
|
||||
}
|
||||
|
||||
/* Inform mixer 2 about freq change */
|
||||
outct(c_mixer2, XS1_CT_END);
|
||||
outuint(c_mixer2, sampFreq);
|
||||
|
||||
/* Wait for handshake and pass on */
|
||||
chkct(c_mixer2, XS1_CT_END);
|
||||
outct(c_host, XS1_CT_END);
|
||||
}
|
||||
else
|
||||
{
|
||||
inuint(c_host);
|
||||
#if MAX_MIX_COUNT > 0
|
||||
outuint(c_mixer2, 0);
|
||||
giveSamplesToHost(c_host, samples, samples_to_host_map, multIn);
|
||||
|
||||
outuint(c_mixer2, 0);
|
||||
inuint(c_mixer2);
|
||||
getSamplesFromHost(c_host, samples, 0);
|
||||
outuint(c_mixer2, 0);
|
||||
inuint(c_mixer2);
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix0(samples, mix_mult[0]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[0],mix_mult[0]);
|
||||
#endif
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0));
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 0);
|
||||
#endif
|
||||
|
||||
#if (MAX_FREQ > 96000)
|
||||
if (!mixer1_mix2_flag)
|
||||
#endif
|
||||
{
|
||||
|
||||
#if MAX_MIX_COUNT > 2
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix2(samples, mix_mult[2]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[2],mix_mult[2]);
|
||||
#endif
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2));
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 4
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix4(samples, mix_mult[4]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[4],mix_mult[4]);
|
||||
#endif
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4));
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 4);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 6
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix6(samples, mix_mult[6]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[6],mix_mult[6]);
|
||||
#endif
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6));
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 6);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#else /* IF MAX_MIX_COUNT > 0 */
|
||||
/* No mixes, this thread runs on its own doing just volume */
|
||||
giveSamplesToDevice(c_mixer2, samples, samples_to_device_map, multOut);
|
||||
getSamplesFromDevice(c_mixer2, samples, NUM_USB_CHAN_OUT);
|
||||
giveSamplesToHost(c_host, samples, samples_to_host_map, multIn);
|
||||
getSamplesFromHost(c_host, samples, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mixer2_mix2_flag = (DEFAULT_FREQ > 96000);
|
||||
|
||||
#pragma unsafe arrays
|
||||
void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
{
|
||||
int mixed;
|
||||
|
||||
while (1) {
|
||||
outuint(c_mixer1, 0);
|
||||
#pragma xta endpoint "mixer2_req"
|
||||
inuint(c_audio);
|
||||
if(testct(c_mixer1))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer2_rate_change"
|
||||
inct(c_mixer1);
|
||||
sampFreq = inuint(c_mixer1);
|
||||
|
||||
|
||||
mixer2_mix2_flag = sampFreq > 96000;
|
||||
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
{
|
||||
asm("stw %0, %1[%2]":: "r"(0),"r"(samples),"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i));
|
||||
}
|
||||
|
||||
/* Inform audio thread about freq change */
|
||||
outct(c_audio, XS1_CT_END);
|
||||
outuint(c_audio, sampFreq);
|
||||
|
||||
/* Wait for handshake and pass on */
|
||||
chkct(c_audio, XS1_CT_END);
|
||||
outct(c_mixer1, XS1_CT_END);
|
||||
}
|
||||
else {
|
||||
(void) inuint(c_mixer1);
|
||||
giveSamplesToDevice(c_audio, samples, samples_to_device_map, multOut);
|
||||
inuint(c_mixer1);
|
||||
outuint(c_mixer1, 0);
|
||||
getSamplesFromDevice(c_audio, samples, NUM_USB_CHAN_OUT);
|
||||
inuint(c_mixer1);
|
||||
outuint(c_mixer1, 0);
|
||||
|
||||
#if MAX_MIX_COUNT > 1
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix1(samples, mix_mult[1]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[1],mix_mult[1]);
|
||||
#endif
|
||||
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1));
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if (MAX_FREQ > 96000)
|
||||
if (!mixer2_mix2_flag)
|
||||
#endif
|
||||
{
|
||||
#if MAX_MIX_COUNT > 3
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix3(samples, mix_mult[3]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[3],mix_mult[3]);
|
||||
#endif
|
||||
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3));
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 5
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix5(samples, mix_mult[5]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[5],mix_mult[5]);
|
||||
#endif
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5));
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 5);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 7
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix7(samples, mix_mult[7]);
|
||||
#else
|
||||
mixed = doMix(samples,mix_map[7],mix_mult[7]);
|
||||
#endif
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(mixed),"r"(samples),
|
||||
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7));
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 7);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
||||
{
|
||||
chan c;
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
||||
{
|
||||
samples[i] = 0;
|
||||
}
|
||||
|
||||
{
|
||||
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
asm("stw %0, %1[%2]"::
|
||||
"r"(i),
|
||||
"r"(samples_to_device_map),
|
||||
"r"(i));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
multOut[i] = MAX_VOL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
multIn[i] = MAX_VOL;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
samples_to_host_map[i] = NUM_USB_CHAN_OUT + i;
|
||||
}
|
||||
|
||||
#if MAX_MIX_COUNT> 0
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
for (int j=0;j<MIX_INPUTS;j++)
|
||||
{
|
||||
#ifndef FAST_MIXER
|
||||
mix_map[i][j] = j < 16 ? j : j + 2;
|
||||
#endif
|
||||
mix_mult[i][j] = i==j ? MAX_VOL >> 3 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
par
|
||||
{
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
mixer1(c_mix_in, c_mix_ctl, c);
|
||||
mixer2(c, c_mix_out);
|
||||
#else
|
||||
mixer1(c_mix_in, c_mix_ctl, c_mix_out);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
777
module_usb_aud_shared/mixer/repeat.h
Normal file
777
module_usb_aud_shared/mixer/repeat.h
Normal file
@@ -0,0 +1,777 @@
|
||||
#ifndef N
|
||||
#error "N must be defined before including repeat.h"
|
||||
#endif
|
||||
#if N > 256
|
||||
#error "N cannot be larger than 256"
|
||||
#endif
|
||||
#ifndef BODY
|
||||
#error "BODY must be defined before including repeat.h"
|
||||
#endif
|
||||
#if N > 0
|
||||
BODY(0)
|
||||
#endif
|
||||
#if N > 1
|
||||
BODY(1)
|
||||
#endif
|
||||
#if N > 2
|
||||
BODY(2)
|
||||
#endif
|
||||
#if N > 3
|
||||
BODY(3)
|
||||
#endif
|
||||
#if N > 4
|
||||
BODY(4)
|
||||
#endif
|
||||
#if N > 5
|
||||
BODY(5)
|
||||
#endif
|
||||
#if N > 6
|
||||
BODY(6)
|
||||
#endif
|
||||
#if N > 7
|
||||
BODY(7)
|
||||
#endif
|
||||
#if N > 8
|
||||
BODY(8)
|
||||
#endif
|
||||
#if N > 9
|
||||
BODY(9)
|
||||
#endif
|
||||
#if N > 10
|
||||
BODY(10)
|
||||
#endif
|
||||
#if N > 11
|
||||
BODY(11)
|
||||
#endif
|
||||
#if N > 12
|
||||
BODY(12)
|
||||
#endif
|
||||
#if N > 13
|
||||
BODY(13)
|
||||
#endif
|
||||
#if N > 14
|
||||
BODY(14)
|
||||
#endif
|
||||
#if N > 15
|
||||
BODY(15)
|
||||
#endif
|
||||
#if N > 16
|
||||
BODY(16)
|
||||
#endif
|
||||
#if N > 17
|
||||
BODY(17)
|
||||
#endif
|
||||
#if N > 18
|
||||
BODY(18)
|
||||
#endif
|
||||
#if N > 19
|
||||
BODY(19)
|
||||
#endif
|
||||
#if N > 20
|
||||
BODY(20)
|
||||
#endif
|
||||
#if N > 21
|
||||
BODY(21)
|
||||
#endif
|
||||
#if N > 22
|
||||
BODY(22)
|
||||
#endif
|
||||
#if N > 23
|
||||
BODY(23)
|
||||
#endif
|
||||
#if N > 24
|
||||
BODY(24)
|
||||
#endif
|
||||
#if N > 25
|
||||
BODY(25)
|
||||
#endif
|
||||
#if N > 26
|
||||
BODY(26)
|
||||
#endif
|
||||
#if N > 27
|
||||
BODY(27)
|
||||
#endif
|
||||
#if N > 28
|
||||
BODY(28)
|
||||
#endif
|
||||
#if N > 29
|
||||
BODY(29)
|
||||
#endif
|
||||
#if N > 30
|
||||
BODY(30)
|
||||
#endif
|
||||
#if N > 31
|
||||
BODY(31)
|
||||
#endif
|
||||
#if N > 32
|
||||
BODY(32)
|
||||
#endif
|
||||
#if N > 33
|
||||
BODY(33)
|
||||
#endif
|
||||
#if N > 34
|
||||
BODY(34)
|
||||
#endif
|
||||
#if N > 35
|
||||
BODY(35)
|
||||
#endif
|
||||
#if N > 36
|
||||
BODY(36)
|
||||
#endif
|
||||
#if N > 37
|
||||
BODY(37)
|
||||
#endif
|
||||
#if N > 38
|
||||
BODY(38)
|
||||
#endif
|
||||
#if N > 39
|
||||
BODY(39)
|
||||
#endif
|
||||
#if N > 40
|
||||
BODY(40)
|
||||
#endif
|
||||
#if N > 41
|
||||
BODY(41)
|
||||
#endif
|
||||
#if N > 42
|
||||
BODY(42)
|
||||
#endif
|
||||
#if N > 43
|
||||
BODY(43)
|
||||
#endif
|
||||
#if N > 44
|
||||
BODY(44)
|
||||
#endif
|
||||
#if N > 45
|
||||
BODY(45)
|
||||
#endif
|
||||
#if N > 46
|
||||
BODY(46)
|
||||
#endif
|
||||
#if N > 47
|
||||
BODY(47)
|
||||
#endif
|
||||
#if N > 48
|
||||
BODY(48)
|
||||
#endif
|
||||
#if N > 49
|
||||
BODY(49)
|
||||
#endif
|
||||
#if N > 50
|
||||
BODY(50)
|
||||
#endif
|
||||
#if N > 51
|
||||
BODY(51)
|
||||
#endif
|
||||
#if N > 52
|
||||
BODY(52)
|
||||
#endif
|
||||
#if N > 53
|
||||
BODY(53)
|
||||
#endif
|
||||
#if N > 54
|
||||
BODY(54)
|
||||
#endif
|
||||
#if N > 55
|
||||
BODY(55)
|
||||
#endif
|
||||
#if N > 56
|
||||
BODY(56)
|
||||
#endif
|
||||
#if N > 57
|
||||
BODY(57)
|
||||
#endif
|
||||
#if N > 58
|
||||
BODY(58)
|
||||
#endif
|
||||
#if N > 59
|
||||
BODY(59)
|
||||
#endif
|
||||
#if N > 60
|
||||
BODY(60)
|
||||
#endif
|
||||
#if N > 61
|
||||
BODY(61)
|
||||
#endif
|
||||
#if N > 62
|
||||
BODY(62)
|
||||
#endif
|
||||
#if N > 63
|
||||
BODY(63)
|
||||
#endif
|
||||
#if N > 64
|
||||
BODY(64)
|
||||
#endif
|
||||
#if N > 65
|
||||
BODY(65)
|
||||
#endif
|
||||
#if N > 66
|
||||
BODY(66)
|
||||
#endif
|
||||
#if N > 67
|
||||
BODY(67)
|
||||
#endif
|
||||
#if N > 68
|
||||
BODY(68)
|
||||
#endif
|
||||
#if N > 69
|
||||
BODY(69)
|
||||
#endif
|
||||
#if N > 70
|
||||
BODY(70)
|
||||
#endif
|
||||
#if N > 71
|
||||
BODY(71)
|
||||
#endif
|
||||
#if N > 72
|
||||
BODY(72)
|
||||
#endif
|
||||
#if N > 73
|
||||
BODY(73)
|
||||
#endif
|
||||
#if N > 74
|
||||
BODY(74)
|
||||
#endif
|
||||
#if N > 75
|
||||
BODY(75)
|
||||
#endif
|
||||
#if N > 76
|
||||
BODY(76)
|
||||
#endif
|
||||
#if N > 77
|
||||
BODY(77)
|
||||
#endif
|
||||
#if N > 78
|
||||
BODY(78)
|
||||
#endif
|
||||
#if N > 79
|
||||
BODY(79)
|
||||
#endif
|
||||
#if N > 80
|
||||
BODY(80)
|
||||
#endif
|
||||
#if N > 81
|
||||
BODY(81)
|
||||
#endif
|
||||
#if N > 82
|
||||
BODY(82)
|
||||
#endif
|
||||
#if N > 83
|
||||
BODY(83)
|
||||
#endif
|
||||
#if N > 84
|
||||
BODY(84)
|
||||
#endif
|
||||
#if N > 85
|
||||
BODY(85)
|
||||
#endif
|
||||
#if N > 86
|
||||
BODY(86)
|
||||
#endif
|
||||
#if N > 87
|
||||
BODY(87)
|
||||
#endif
|
||||
#if N > 88
|
||||
BODY(88)
|
||||
#endif
|
||||
#if N > 89
|
||||
BODY(89)
|
||||
#endif
|
||||
#if N > 90
|
||||
BODY(90)
|
||||
#endif
|
||||
#if N > 91
|
||||
BODY(91)
|
||||
#endif
|
||||
#if N > 92
|
||||
BODY(92)
|
||||
#endif
|
||||
#if N > 93
|
||||
BODY(93)
|
||||
#endif
|
||||
#if N > 94
|
||||
BODY(94)
|
||||
#endif
|
||||
#if N > 95
|
||||
BODY(95)
|
||||
#endif
|
||||
#if N > 96
|
||||
BODY(96)
|
||||
#endif
|
||||
#if N > 97
|
||||
BODY(97)
|
||||
#endif
|
||||
#if N > 98
|
||||
BODY(98)
|
||||
#endif
|
||||
#if N > 99
|
||||
BODY(99)
|
||||
#endif
|
||||
#if N > 100
|
||||
BODY(100)
|
||||
#endif
|
||||
#if N > 101
|
||||
BODY(101)
|
||||
#endif
|
||||
#if N > 102
|
||||
BODY(102)
|
||||
#endif
|
||||
#if N > 103
|
||||
BODY(103)
|
||||
#endif
|
||||
#if N > 104
|
||||
BODY(104)
|
||||
#endif
|
||||
#if N > 105
|
||||
BODY(105)
|
||||
#endif
|
||||
#if N > 106
|
||||
BODY(106)
|
||||
#endif
|
||||
#if N > 107
|
||||
BODY(107)
|
||||
#endif
|
||||
#if N > 108
|
||||
BODY(108)
|
||||
#endif
|
||||
#if N > 109
|
||||
BODY(109)
|
||||
#endif
|
||||
#if N > 110
|
||||
BODY(110)
|
||||
#endif
|
||||
#if N > 111
|
||||
BODY(111)
|
||||
#endif
|
||||
#if N > 112
|
||||
BODY(112)
|
||||
#endif
|
||||
#if N > 113
|
||||
BODY(113)
|
||||
#endif
|
||||
#if N > 114
|
||||
BODY(114)
|
||||
#endif
|
||||
#if N > 115
|
||||
BODY(115)
|
||||
#endif
|
||||
#if N > 116
|
||||
BODY(116)
|
||||
#endif
|
||||
#if N > 117
|
||||
BODY(117)
|
||||
#endif
|
||||
#if N > 118
|
||||
BODY(118)
|
||||
#endif
|
||||
#if N > 119
|
||||
BODY(119)
|
||||
#endif
|
||||
#if N > 120
|
||||
BODY(120)
|
||||
#endif
|
||||
#if N > 121
|
||||
BODY(121)
|
||||
#endif
|
||||
#if N > 122
|
||||
BODY(122)
|
||||
#endif
|
||||
#if N > 123
|
||||
BODY(123)
|
||||
#endif
|
||||
#if N > 124
|
||||
BODY(124)
|
||||
#endif
|
||||
#if N > 125
|
||||
BODY(125)
|
||||
#endif
|
||||
#if N > 126
|
||||
BODY(126)
|
||||
#endif
|
||||
#if N > 127
|
||||
BODY(127)
|
||||
#endif
|
||||
#if N > 128
|
||||
BODY(128)
|
||||
#endif
|
||||
#if N > 129
|
||||
BODY(129)
|
||||
#endif
|
||||
#if N > 130
|
||||
BODY(130)
|
||||
#endif
|
||||
#if N > 131
|
||||
BODY(131)
|
||||
#endif
|
||||
#if N > 132
|
||||
BODY(132)
|
||||
#endif
|
||||
#if N > 133
|
||||
BODY(133)
|
||||
#endif
|
||||
#if N > 134
|
||||
BODY(134)
|
||||
#endif
|
||||
#if N > 135
|
||||
BODY(135)
|
||||
#endif
|
||||
#if N > 136
|
||||
BODY(136)
|
||||
#endif
|
||||
#if N > 137
|
||||
BODY(137)
|
||||
#endif
|
||||
#if N > 138
|
||||
BODY(138)
|
||||
#endif
|
||||
#if N > 139
|
||||
BODY(139)
|
||||
#endif
|
||||
#if N > 140
|
||||
BODY(140)
|
||||
#endif
|
||||
#if N > 141
|
||||
BODY(141)
|
||||
#endif
|
||||
#if N > 142
|
||||
BODY(142)
|
||||
#endif
|
||||
#if N > 143
|
||||
BODY(143)
|
||||
#endif
|
||||
#if N > 144
|
||||
BODY(144)
|
||||
#endif
|
||||
#if N > 145
|
||||
BODY(145)
|
||||
#endif
|
||||
#if N > 146
|
||||
BODY(146)
|
||||
#endif
|
||||
#if N > 147
|
||||
BODY(147)
|
||||
#endif
|
||||
#if N > 148
|
||||
BODY(148)
|
||||
#endif
|
||||
#if N > 149
|
||||
BODY(149)
|
||||
#endif
|
||||
#if N > 150
|
||||
BODY(150)
|
||||
#endif
|
||||
#if N > 151
|
||||
BODY(151)
|
||||
#endif
|
||||
#if N > 152
|
||||
BODY(152)
|
||||
#endif
|
||||
#if N > 153
|
||||
BODY(153)
|
||||
#endif
|
||||
#if N > 154
|
||||
BODY(154)
|
||||
#endif
|
||||
#if N > 155
|
||||
BODY(155)
|
||||
#endif
|
||||
#if N > 156
|
||||
BODY(156)
|
||||
#endif
|
||||
#if N > 157
|
||||
BODY(157)
|
||||
#endif
|
||||
#if N > 158
|
||||
BODY(158)
|
||||
#endif
|
||||
#if N > 159
|
||||
BODY(159)
|
||||
#endif
|
||||
#if N > 160
|
||||
BODY(160)
|
||||
#endif
|
||||
#if N > 161
|
||||
BODY(161)
|
||||
#endif
|
||||
#if N > 162
|
||||
BODY(162)
|
||||
#endif
|
||||
#if N > 163
|
||||
BODY(163)
|
||||
#endif
|
||||
#if N > 164
|
||||
BODY(164)
|
||||
#endif
|
||||
#if N > 165
|
||||
BODY(165)
|
||||
#endif
|
||||
#if N > 166
|
||||
BODY(166)
|
||||
#endif
|
||||
#if N > 167
|
||||
BODY(167)
|
||||
#endif
|
||||
#if N > 168
|
||||
BODY(168)
|
||||
#endif
|
||||
#if N > 169
|
||||
BODY(169)
|
||||
#endif
|
||||
#if N > 170
|
||||
BODY(170)
|
||||
#endif
|
||||
#if N > 171
|
||||
BODY(171)
|
||||
#endif
|
||||
#if N > 172
|
||||
BODY(172)
|
||||
#endif
|
||||
#if N > 173
|
||||
BODY(173)
|
||||
#endif
|
||||
#if N > 174
|
||||
BODY(174)
|
||||
#endif
|
||||
#if N > 175
|
||||
BODY(175)
|
||||
#endif
|
||||
#if N > 176
|
||||
BODY(176)
|
||||
#endif
|
||||
#if N > 177
|
||||
BODY(177)
|
||||
#endif
|
||||
#if N > 178
|
||||
BODY(178)
|
||||
#endif
|
||||
#if N > 179
|
||||
BODY(179)
|
||||
#endif
|
||||
#if N > 180
|
||||
BODY(180)
|
||||
#endif
|
||||
#if N > 181
|
||||
BODY(181)
|
||||
#endif
|
||||
#if N > 182
|
||||
BODY(182)
|
||||
#endif
|
||||
#if N > 183
|
||||
BODY(183)
|
||||
#endif
|
||||
#if N > 184
|
||||
BODY(184)
|
||||
#endif
|
||||
#if N > 185
|
||||
BODY(185)
|
||||
#endif
|
||||
#if N > 186
|
||||
BODY(186)
|
||||
#endif
|
||||
#if N > 187
|
||||
BODY(187)
|
||||
#endif
|
||||
#if N > 188
|
||||
BODY(188)
|
||||
#endif
|
||||
#if N > 189
|
||||
BODY(189)
|
||||
#endif
|
||||
#if N > 190
|
||||
BODY(190)
|
||||
#endif
|
||||
#if N > 191
|
||||
BODY(191)
|
||||
#endif
|
||||
#if N > 192
|
||||
BODY(192)
|
||||
#endif
|
||||
#if N > 193
|
||||
BODY(193)
|
||||
#endif
|
||||
#if N > 194
|
||||
BODY(194)
|
||||
#endif
|
||||
#if N > 195
|
||||
BODY(195)
|
||||
#endif
|
||||
#if N > 196
|
||||
BODY(196)
|
||||
#endif
|
||||
#if N > 197
|
||||
BODY(197)
|
||||
#endif
|
||||
#if N > 198
|
||||
BODY(198)
|
||||
#endif
|
||||
#if N > 199
|
||||
BODY(199)
|
||||
#endif
|
||||
#if N > 200
|
||||
BODY(200)
|
||||
#endif
|
||||
#if N > 201
|
||||
BODY(201)
|
||||
#endif
|
||||
#if N > 202
|
||||
BODY(202)
|
||||
#endif
|
||||
#if N > 203
|
||||
BODY(203)
|
||||
#endif
|
||||
#if N > 204
|
||||
BODY(204)
|
||||
#endif
|
||||
#if N > 205
|
||||
BODY(205)
|
||||
#endif
|
||||
#if N > 206
|
||||
BODY(206)
|
||||
#endif
|
||||
#if N > 207
|
||||
BODY(207)
|
||||
#endif
|
||||
#if N > 208
|
||||
BODY(208)
|
||||
#endif
|
||||
#if N > 209
|
||||
BODY(209)
|
||||
#endif
|
||||
#if N > 210
|
||||
BODY(210)
|
||||
#endif
|
||||
#if N > 211
|
||||
BODY(211)
|
||||
#endif
|
||||
#if N > 212
|
||||
BODY(212)
|
||||
#endif
|
||||
#if N > 213
|
||||
BODY(213)
|
||||
#endif
|
||||
#if N > 214
|
||||
BODY(214)
|
||||
#endif
|
||||
#if N > 215
|
||||
BODY(215)
|
||||
#endif
|
||||
#if N > 216
|
||||
BODY(216)
|
||||
#endif
|
||||
#if N > 217
|
||||
BODY(217)
|
||||
#endif
|
||||
#if N > 218
|
||||
BODY(218)
|
||||
#endif
|
||||
#if N > 219
|
||||
BODY(219)
|
||||
#endif
|
||||
#if N > 220
|
||||
BODY(220)
|
||||
#endif
|
||||
#if N > 221
|
||||
BODY(221)
|
||||
#endif
|
||||
#if N > 222
|
||||
BODY(222)
|
||||
#endif
|
||||
#if N > 223
|
||||
BODY(223)
|
||||
#endif
|
||||
#if N > 224
|
||||
BODY(224)
|
||||
#endif
|
||||
#if N > 225
|
||||
BODY(225)
|
||||
#endif
|
||||
#if N > 226
|
||||
BODY(226)
|
||||
#endif
|
||||
#if N > 227
|
||||
BODY(227)
|
||||
#endif
|
||||
#if N > 228
|
||||
BODY(228)
|
||||
#endif
|
||||
#if N > 229
|
||||
BODY(229)
|
||||
#endif
|
||||
#if N > 230
|
||||
BODY(230)
|
||||
#endif
|
||||
#if N > 231
|
||||
BODY(231)
|
||||
#endif
|
||||
#if N > 232
|
||||
BODY(232)
|
||||
#endif
|
||||
#if N > 233
|
||||
BODY(233)
|
||||
#endif
|
||||
#if N > 234
|
||||
BODY(234)
|
||||
#endif
|
||||
#if N > 235
|
||||
BODY(235)
|
||||
#endif
|
||||
#if N > 236
|
||||
BODY(236)
|
||||
#endif
|
||||
#if N > 237
|
||||
BODY(237)
|
||||
#endif
|
||||
#if N > 238
|
||||
BODY(238)
|
||||
#endif
|
||||
#if N > 239
|
||||
BODY(239)
|
||||
#endif
|
||||
#if N > 240
|
||||
BODY(240)
|
||||
#endif
|
||||
#if N > 241
|
||||
BODY(241)
|
||||
#endif
|
||||
#if N > 242
|
||||
BODY(242)
|
||||
#endif
|
||||
#if N > 243
|
||||
BODY(243)
|
||||
#endif
|
||||
#if N > 244
|
||||
BODY(244)
|
||||
#endif
|
||||
#if N > 245
|
||||
BODY(245)
|
||||
#endif
|
||||
#if N > 246
|
||||
BODY(246)
|
||||
#endif
|
||||
#if N > 247
|
||||
BODY(247)
|
||||
#endif
|
||||
#if N > 248
|
||||
BODY(248)
|
||||
#endif
|
||||
#if N > 249
|
||||
BODY(249)
|
||||
#endif
|
||||
#if N > 250
|
||||
BODY(250)
|
||||
#endif
|
||||
#if N > 251
|
||||
BODY(251)
|
||||
#endif
|
||||
#if N > 252
|
||||
BODY(252)
|
||||
#endif
|
||||
#if N > 253
|
||||
BODY(253)
|
||||
#endif
|
||||
#if N > 254
|
||||
BODY(254)
|
||||
#endif
|
||||
#if N > 255
|
||||
BODY(255)
|
||||
#endif
|
||||
32
module_usb_aud_shared/module_build_info
Normal file
32
module_usb_aud_shared/module_build_info
Normal file
@@ -0,0 +1,32 @@
|
||||
# This file describes how this module will affect the application
|
||||
# using it. The file is included in the Makefile of the main application.
|
||||
#
|
||||
# The module contributes to the build of the application by extending
|
||||
# the following variables:
|
||||
#
|
||||
# SOURCE_DIRS - directories with source files to be included in the build
|
||||
# INCLUDE_DIRS - directories to be added to the include path during the build
|
||||
# LIB_DIRS - directories containing libraries to be linked into the build
|
||||
#
|
||||
# Note that all the source files in each directory in SOURCE_DIRS
|
||||
# will be compiled (you do not need to name the files individually).
|
||||
#
|
||||
|
||||
# You can change the flags of a set of files using the SET_XCC_[lang]_FLAGS
|
||||
# functions. The first argument is a list of directories and the
|
||||
# second argument is the value to set the compile flags to. e.g.
|
||||
#
|
||||
# $(call SET_XCC_C_FLAGS, mydir1 mydir2, $(XCC_FLAGS) -g -O3)
|
||||
|
||||
|
||||
# You can change the flags of an individual file by setting the
|
||||
# XCC_FLAGS_[filename] variable. e.g.
|
||||
#
|
||||
# XCC_FLAGS_myfile.xc = $(XCC_FLAGS) -fsubword-select
|
||||
|
||||
|
||||
# You can exclude particular files from the build even if they occur
|
||||
# within SOURCE_DIRS by adding the file name (with no path) to the
|
||||
# EXCLUDE_FILES variable e..g
|
||||
#
|
||||
EXCLUDE_FILES += descriptors_2.rst
|
||||
1
module_usb_aud_shared/module_description
Normal file
1
module_usb_aud_shared/module_description
Normal file
@@ -0,0 +1 @@
|
||||
Common USB Audio source files/headers.
|
||||
4
module_usb_aud_shared/pll/pll.h
Normal file
4
module_usb_aud_shared/pll/pll.h
Normal file
@@ -0,0 +1,4 @@
|
||||
void PllInit(void);
|
||||
|
||||
|
||||
void PllMult(unsigned mult);
|
||||
6
module_usb_aud_shared/ports/audioports.h
Normal file
6
module_usb_aud_shared/ports/audioports.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _AUDIOPORTS_H_
|
||||
#define _AUDIOPORTS_H_
|
||||
|
||||
void ConfigAudioPorts(unsigned int divide);
|
||||
|
||||
#endif
|
||||
138
module_usb_aud_shared/ports/audioports.xc
Normal file
138
module_usb_aud_shared/ports/audioports.xc
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <xs1.h>
|
||||
#include "devicedefines.h"
|
||||
#include "audioports.h"
|
||||
|
||||
/* Audio IOs */
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
extern buffered out port:32 p_i2s_dac[I2S_WIRES_DAC];
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC];
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0)
|
||||
#ifdef CODEC_SLAVE
|
||||
extern buffered out port:32 p_lrclk;
|
||||
extern buffered out port:32 p_bclk;
|
||||
#else
|
||||
extern in port p_lrclk;
|
||||
extern in port p_bclk;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern port p_mclk;
|
||||
|
||||
extern clock clk_audio_mclk;
|
||||
extern clock clk_audio_bclk;
|
||||
|
||||
void ConfigAudioPorts(unsigned int divide)
|
||||
{
|
||||
|
||||
#ifdef CODEC_SLAVE
|
||||
/* Output 0 on BCLK to ensure clock is low
|
||||
* Required as stop_clock will only complete when the clock is low
|
||||
*/
|
||||
configure_out_port_no_ready(p_bclk, clk_audio_mclk, 0);
|
||||
p_bclk <: 0;
|
||||
|
||||
/* Stop bit and master clock blocks and clear port buffers */
|
||||
stop_clock(clk_audio_bclk);
|
||||
stop_clock(clk_audio_mclk);
|
||||
|
||||
clearbuf(p_lrclk);
|
||||
clearbuf(p_bclk);
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
clearbuf(p_i2s_adc[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
clearbuf(p_i2s_dac[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clock master clock-block from master-clock port */
|
||||
configure_clock_src(clk_audio_mclk, p_mclk);
|
||||
|
||||
/* For a divide of one (i.e. bitclock == master-clock) BClk is set to clock_output mode.
|
||||
* In this mode it outputs an edge clock on every tick of itsassociated clock_block.
|
||||
*
|
||||
* For all other divides, BClk is clocked by the master clock and data
|
||||
* will be output to p_bclk to generate the bit clock.
|
||||
*/
|
||||
if (divide == 1) /* e.g. 176.4KHz from 11.2896 */
|
||||
{
|
||||
configure_port_clock_output(p_bclk, clk_audio_mclk);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* bit clock port from master clock clock-clock block */
|
||||
configure_out_port_no_ready(p_bclk, clk_audio_mclk, 0);
|
||||
}
|
||||
|
||||
/* Generate bit clock block from pin */
|
||||
configure_clock_src(clk_audio_bclk, p_bclk);
|
||||
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
/* Clock I2S output data ports from clock block */
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
/* Clock I2S input data ports from clock block */
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clock LR clock from bit clock-block */
|
||||
configure_out_port_no_ready(p_lrclk, clk_audio_bclk, 0);
|
||||
|
||||
/* Start clock blocks ticking */
|
||||
start_clock(clk_audio_mclk);
|
||||
start_clock(clk_audio_bclk);
|
||||
|
||||
/* bclk initial state needs to be high */
|
||||
p_bclk <: 0xFFFFFFFF;
|
||||
|
||||
/* Pause until output completes */
|
||||
sync(p_bclk);
|
||||
|
||||
#else
|
||||
/* Stop bit and master clock blocks and clear port buffers */
|
||||
stop_clock(clk_audio_bclk);
|
||||
stop_clock(clk_audio_mclk);
|
||||
|
||||
/* Clock bclk clock-block from bclk pin */
|
||||
configure_clock_src(clk_audio_bclk, p_bclk);
|
||||
|
||||
/* Clock I2S output data ports from b-clock clock block */
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
|
||||
}
|
||||
|
||||
/* Clock I2S input data ports from clock block */
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
|
||||
}
|
||||
|
||||
configure_in_port_no_ready(p_lrclk, clk_audio_bclk);
|
||||
|
||||
start_clock(clk_audio_bclk);
|
||||
|
||||
#endif
|
||||
}
|
||||
15
module_usb_aud_shared/reboot.c
Normal file
15
module_usb_aud_shared/reboot.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
|
||||
|
||||
int write_sswitch_reg_blind(unsigned coreid, unsigned reg, unsigned data);
|
||||
|
||||
/* Reboots XMOS device by writing to the PLL config register */
|
||||
void device_reboot(void)
|
||||
{
|
||||
unsigned int pllVal;
|
||||
unsigned int core_id = get_core_id();
|
||||
read_sswitch_reg(core_id, 6, &pllVal);
|
||||
write_sswitch_reg_blind(core_id^0x8000, 6, pllVal);
|
||||
write_sswitch_reg_blind(core_id, 6, pllVal);
|
||||
}
|
||||
18
module_usb_aud_shared/usb_buffer/decouple.h
Normal file
18
module_usb_aud_shared/usb_buffer/decouple.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef __decouple_h__
|
||||
#define __decouple_h__
|
||||
|
||||
|
||||
/** Manage the data transfer between the USB audio buffer and the
|
||||
* Audio I/O driver.
|
||||
*
|
||||
* \param c_audio_out Channel connected to the audio() or mixer() threads
|
||||
* \param c_led Optional chanend connected to an led driver thread for
|
||||
* debugging purposes
|
||||
* \param c_midi Optional chanend connect to usb_midi() thread if present
|
||||
* \param c_clk_int Optional chanend connected to the clockGen() thread if present
|
||||
*/
|
||||
void decouple(chanend c_audio_out,
|
||||
chanend ?c_led,
|
||||
chanend ?c_midi, chanend ?c_clk_int);
|
||||
|
||||
#endif // __decouple_h__
|
||||
1142
module_usb_aud_shared/usb_buffer/decouple.xc
Normal file
1142
module_usb_aud_shared/usb_buffer/decouple.xc
Normal file
File diff suppressed because it is too large
Load Diff
1169
module_usb_aud_shared/usb_buffer/decouple.xc.orig
Normal file
1169
module_usb_aud_shared/usb_buffer/decouple.xc.orig
Normal file
File diff suppressed because it is too large
Load Diff
24
module_usb_aud_shared/usb_buffer/get_adc_counts.c
Normal file
24
module_usb_aud_shared/usb_buffer/get_adc_counts.c
Normal file
@@ -0,0 +1,24 @@
|
||||
extern unsigned int g_curUsbSpeed;
|
||||
#define XUD_SPEED_HS 2
|
||||
void GetADCCounts(unsigned samFreq, int *min, int *mid, int *max)
|
||||
{
|
||||
unsigned frameTime;
|
||||
int usb_speed;
|
||||
usb_speed = g_curUsbSpeed;
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
frameTime = 8000;
|
||||
else
|
||||
frameTime = 1000;
|
||||
|
||||
*min = samFreq / frameTime;
|
||||
*max = *min + 1;
|
||||
|
||||
*mid = *min;
|
||||
|
||||
/* Check for INT(SampFreq/8000) == SampFreq/8000 */
|
||||
if((samFreq % frameTime) == 0)
|
||||
{
|
||||
*min -= 1;
|
||||
}
|
||||
|
||||
}
|
||||
198
module_usb_aud_shared/usb_buffer/interrupt.h
Normal file
198
module_usb_aud_shared/usb_buffer/interrupt.h
Normal file
@@ -0,0 +1,198 @@
|
||||
#ifndef __interrupt_h__
|
||||
#define __interrupt_h__
|
||||
|
||||
#define store_args0(c) \
|
||||
asm("kentsp 19; stw %0, sp[1]; krestsp 19"::"r"(c));
|
||||
|
||||
#define store_args1(c,x) \
|
||||
asm("kentsp 20; stw %0, sp[1]; stw %1, sp[2]; krestsp 20"::"r"(c),"r"(x));
|
||||
|
||||
#define store_args2(c,x0,x1) \
|
||||
asm("kentsp 21; stw %0, sp[1];" \
|
||||
"stw %1, sp[2];" \
|
||||
"stw %2, sp[3];" \
|
||||
" krestsp 21"::"r"(c),"r"(x0),"r"(x1));
|
||||
|
||||
#define store_args3(c,x0,x1,x2) \
|
||||
asm("kentsp 22; stw %0, sp[1];" \
|
||||
"stw %1, sp[2];" \
|
||||
"stw %2, sp[3];" \
|
||||
"stw %3, sp[4];" \
|
||||
" krestsp 22"::"r"(c),"r"(x0),"r"(x1),"r"(x2));
|
||||
|
||||
#define store_args4(c,x0,x1,x2,x3) \
|
||||
asm("kentsp 23; stw %4, sp[1];" \
|
||||
"stw %0, sp[2];" \
|
||||
"stw %1, sp[3];" \
|
||||
"stw %2, sp[4];" \
|
||||
"stw %3, sp[5];" \
|
||||
" krestsp 23"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3));
|
||||
|
||||
#define store_args5(c,x0,x1,x2,x3,x4) \
|
||||
asm("kentsp 24;" \
|
||||
"stw %4, sp[1];" \
|
||||
"stw %5, sp[2];" \
|
||||
"stw %0, sp[3];" \
|
||||
"stw %1, sp[4];" \
|
||||
"stw %2, sp[5];" \
|
||||
"stw %3, sp[6];" \
|
||||
" krestsp 24"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4));
|
||||
|
||||
#define store_args6(c,x0,x1,x2,x3,x4,x5) \
|
||||
asm("kentsp 25;" \
|
||||
"stw %4, sp[1];" \
|
||||
"stw %5, sp[2];" \
|
||||
"stw %6, sp[3];" \
|
||||
"stw %0, sp[4];" \
|
||||
"stw %1, sp[5];" \
|
||||
"stw %2, sp[6];" \
|
||||
"stw %3, sp[7];" \
|
||||
" krestsp 25"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5));
|
||||
|
||||
#define store_args7(c,x0,x1,x2,x3,x4,x5,x6) \
|
||||
asm("kentsp 26;" \
|
||||
"stw %4, sp[1];" \
|
||||
"stw %5, sp[2];" \
|
||||
"stw %6, sp[3];" \
|
||||
"stw %7, sp[4];" \
|
||||
"stw %0, sp[5];" \
|
||||
"stw %1, sp[6];" \
|
||||
"stw %2, sp[7];" \
|
||||
"stw %3, sp[8];" \
|
||||
" krestsp 26"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5),"r"(x6));
|
||||
|
||||
#define store_args8(c,x0,x1,x2,x3,x4,x5,x6,x7) \
|
||||
asm("kentsp 27;" \
|
||||
"stw %4, sp[1];" \
|
||||
"stw %5, sp[2];" \
|
||||
"stw %6, sp[3];" \
|
||||
"stw %7, sp[4];" \
|
||||
"stw %8, sp[5];" \
|
||||
"stw %0, sp[6];" \
|
||||
"stw %1, sp[7];" \
|
||||
"stw %2, sp[8];" \
|
||||
"stw %3, sp[9];" \
|
||||
" krestsp 27"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5),"r"(x6),"r"(x7));
|
||||
|
||||
|
||||
|
||||
|
||||
#define load_args0(f) \
|
||||
"ldw r0, sp[1]\n"
|
||||
|
||||
#define load_args1(f)\
|
||||
"ldw r0, sp[1]\n" \
|
||||
"ldw r1, sp[2]\n"
|
||||
|
||||
#define load_args2(f)\
|
||||
"ldw r0, sp[1]\n" \
|
||||
"ldw r1, sp[2]\n" \
|
||||
"ldw r2, sp[3]\n"
|
||||
|
||||
#define load_args3(f)\
|
||||
"ldw r0, sp[1]\n" \
|
||||
"ldw r1, sp[2]\n" \
|
||||
"ldw r2, sp[3]\n" \
|
||||
"ldw r3, sp[4]\n"
|
||||
|
||||
#define load_argsn(f, args) \
|
||||
".linkset __"#f"_handler_arg0, "#args"-2\n"\
|
||||
"ldw r0, sp[" "__"#f"_handler_arg0" "]\n" \
|
||||
".linkset __"#f"_handler_arg1, "#args"-1\n"\
|
||||
"ldw r1, sp[" "__"#f"_handler_arg1" "]\n" \
|
||||
".linkset __"#f"_handler_arg2, "#args"-0\n"\
|
||||
"ldw r2, sp[" "__"#f"_handler_arg2" "]\n" \
|
||||
".linkset __"#f"_handler_arg3, "#args"+1\n"\
|
||||
"ldw r3, sp[" "__"#f"_handler_arg3" "]\n"
|
||||
|
||||
#define load_args4(f) load_argsn(f,4)
|
||||
#define load_args5(f) load_argsn(f,5)
|
||||
#define load_args6(f) load_argsn(f,6)
|
||||
#define load_args7(f) load_argsn(f,7)
|
||||
#define load_args8(f) load_argsn(f,8)
|
||||
|
||||
#define save_state(f,args) \
|
||||
".linkset __"#f"_handler_r0_save, "#args"+12\n" \
|
||||
"stw r0, sp[" "__"#f"_handler_r0_save" "]\n" \
|
||||
".linkset __"#f"_handler_r1_save, "#args"+13\n" \
|
||||
"stw r1, sp[" "__"#f"_handler_r1_save" "]\n" \
|
||||
".linkset __"#f"_handler_r2_save, "#args"+2\n" \
|
||||
"stw r2, sp[" "__"#f"_handler_r2_save" "]\n" \
|
||||
".linkset __"#f"_handler_r3_save, "#args"+3\n" \
|
||||
"stw r3, sp[" "__"#f"_handler_r3_save" "]\n" \
|
||||
".linkset __"#f"_handler_r4_save, "#args"+4\n" \
|
||||
"stw r4, sp[" "__"#f"_handler_r4_save" "]\n" \
|
||||
".linkset __"#f"_handler_r5_save, "#args"+5\n" \
|
||||
"stw r5, sp[" "__"#f"_handler_r5_save" "]\n" \
|
||||
".linkset __"#f"_handler_r6_save, "#args"+6\n" \
|
||||
"stw r6, sp[" "__"#f"_handler_r6_save" "]\n" \
|
||||
".linkset __"#f"_handler_r7_save, "#args"+7\n" \
|
||||
"stw r7, sp[" "__"#f"_handler_r7_save" "]\n" \
|
||||
".linkset __"#f"_handler_r8_save, "#args"+8\n" \
|
||||
"stw r8, sp[" "__"#f"_handler_r8_save" "]\n" \
|
||||
".linkset __"#f"_handler_r9_save, "#args"+9\n" \
|
||||
"stw r9, sp[" "__"#f"_handler_r9_save" "]\n" \
|
||||
".linkset __"#f"_handler_r10_save, "#args"+10\n" \
|
||||
"stw r10, sp[" "__"#f"_handler_r10_save" "]\n" \
|
||||
".linkset __"#f"_handler_r11_save, "#args"+11\n" \
|
||||
"stw r11, sp[" "__"#f"_handler_r11_save" "]\n" \
|
||||
".linkset __"#f"_handler_lr_save, "#args"+14\n" \
|
||||
"stw lr, sp[" "__"#f"_handler_lr_save" "]\n"
|
||||
|
||||
#define restore_state(f,args) \
|
||||
"ldw r0, sp[" "__"#f"_handler_r0_save" "]\n" \
|
||||
"ldw r1, sp[" "__"#f"_handler_r1_save" "]\n" \
|
||||
"ldw r2, sp[" "__"#f"_handler_r2_save" "]\n" \
|
||||
"ldw r3, sp[" "__"#f"_handler_r3_save" "]\n" \
|
||||
"ldw r4, sp[" "__"#f"_handler_r4_save" "]\n" \
|
||||
"ldw r5, sp[" "__"#f"_handler_r5_save" "]\n" \
|
||||
"ldw r6, sp[" "__"#f"_handler_r6_save" "]\n" \
|
||||
"ldw r7, sp[" "__"#f"_handler_r7_save" "]\n" \
|
||||
"ldw r8, sp[" "__"#f"_handler_r8_save" "]\n" \
|
||||
"ldw r9, sp[" "__"#f"_handler_r9_save" "]\n" \
|
||||
"ldw r10, sp[" "__"#f"_handler_r10_save" "]\n" \
|
||||
"ldw r11, sp[" "__"#f"_handler_r11_save" "]\n" \
|
||||
"ldw lr, sp[" "__"#f"_handler_lr_save" "]\n"
|
||||
|
||||
|
||||
#define STRINGIFY0(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY0(x)
|
||||
|
||||
#define ENABLE_INTERRUPTS() asm("setsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1)))
|
||||
|
||||
#define DISABLE_INTERRUPTS() asm("clrsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1)))
|
||||
|
||||
//int ksp_enter, ksp_exit, r11_store;
|
||||
|
||||
#define do_interrupt_handler(f,args) \
|
||||
asm("bu .L__" #f "_handler_skip;\n" \
|
||||
"__" #f "_handler:\n" \
|
||||
"kentsp " #args " + 19\n" \
|
||||
"__kent:" \
|
||||
save_state(f,args) \
|
||||
load_args ## args (f) \
|
||||
"bl " #f "\n" \
|
||||
restore_state(f,args) \
|
||||
"krestsp " #args " + 19 \n" \
|
||||
"__kret:\n" \
|
||||
"kret\n" \
|
||||
".L__" #f "_handler_skip:\n");
|
||||
|
||||
#define set_interrupt_handler(f, nstackwords, args, c, ...) \
|
||||
asm (" .section .dp.data, \"adw\", @progbits\n" \
|
||||
" .align 4\n" \
|
||||
"__" #f "_kernel_stack:\n" \
|
||||
" .space " #nstackwords ", 0\n" \
|
||||
" .text\n"); \
|
||||
asm("mov r10, %0; ldaw r11, dp[__" #f "_kernel_stack];add r11, r11, r10;ldaw r10, sp[0]; "\
|
||||
"set sp,r11;stw r10, sp[0]; krestsp 0"::"r"(nstackwords-8):"r10","r11"); \
|
||||
store_args ## args(c, __VA_ARGS__) \
|
||||
do_interrupt_handler(f, args) \
|
||||
asm("ldap r11, __" #f "_handler; setv res[%0],r11"::"r"(c):"r11"); \
|
||||
asm("setc res[%0], 0xa; eeu res[%0]"::"r"(c)); \
|
||||
asm("setsr (((0) & ~(((1 << 0x1) - 1) << 0x1)) | (((1) << 0x1) & (((1 << 0x1) - 1) << 0x1)))");
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
2
module_usb_aud_shared/usb_buffer/testct_byref.h
Normal file
2
module_usb_aud_shared/usb_buffer/testct_byref.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma select handler
|
||||
void testct_byref(chanend c, unsigned &isCt) ;
|
||||
15
module_usb_aud_shared/usb_buffer/testct_byref.xc
Normal file
15
module_usb_aud_shared/usb_buffer/testct_byref.xc
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <xs1.h>
|
||||
|
||||
/* TODO Currently complier does not support inline select functions, hense this is in a seperate file to ensure this is not the case */
|
||||
#pragma select handler
|
||||
void testct_byref(chanend c, unsigned &isCt)
|
||||
{
|
||||
if (testct(c))
|
||||
{
|
||||
isCt = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
isCt = 0;
|
||||
}
|
||||
}
|
||||
14
module_usb_aud_shared/usb_buffer/ub
Normal file
14
module_usb_aud_shared/usb_buffer/ub
Normal file
@@ -0,0 +1,14 @@
|
||||
#if 0
|
||||
{
|
||||
tmr :> sof_time;
|
||||
if (last_sof_time && ((sof_time - last_sof_time) > 20000)) {
|
||||
missed_sofcount = sofCount;
|
||||
missed_count--;
|
||||
if (!missed_count) {
|
||||
asm("ecallf %0"::"r"(0));
|
||||
}
|
||||
|
||||
}
|
||||
last_sof_time = sof_time;
|
||||
}
|
||||
#endif
|
||||
28
module_usb_aud_shared/usb_buffer/usb_buffer.h
Normal file
28
module_usb_aud_shared/usb_buffer/usb_buffer.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef __usb_buffer_h__
|
||||
#define __usb_buffer_h__
|
||||
/** USB Audio Buffering Thread.
|
||||
*
|
||||
* This function buffers USB audio data between the XUD layer and the decouple
|
||||
* thread. Most of the chanend parameters to the function should be connected to
|
||||
* XUD_Manager()
|
||||
*
|
||||
* \param c_aud_out Audio OUT endpoint channel connected to the XUD
|
||||
* \param c_aud_in Audio IN endpoint channel connected to the XUD
|
||||
* \param c_aud_fb Audio feedback endpoint channel connected to the XUD
|
||||
* \param c_midi_from_host MIDI OUT endpoint channel connected to the XUD
|
||||
* \param c_midi_to_host MIDI IN endpoint channel connected to the XUD
|
||||
* \param c_int Audio clocking interrupt endpoint channel connected to the XUD
|
||||
* \param c_sof Start of frame channel connected to the XUD
|
||||
* \param c_aud_ctl Audio control channel connected to Endpoint0()
|
||||
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
|
||||
*/
|
||||
void buffer(chanend c_aud_out, chanend c_aud_in, chanend c_aud_fb,
|
||||
chanend c_midi_from_host,
|
||||
chanend c_midi_to_host,
|
||||
chanend c_int,
|
||||
chanend c_sof,
|
||||
chanend c_aud_ctl,
|
||||
in port p_off_mclk);
|
||||
|
||||
|
||||
#endif
|
||||
508
module_usb_aud_shared/usb_buffer/usb_buffer.xc
Normal file
508
module_usb_aud_shared/usb_buffer/usb_buffer.xc
Normal file
@@ -0,0 +1,508 @@
|
||||
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
|
||||
//In this file xud.h is not included since we are interpreting the
|
||||
//assembly functions GetData/SetData as taking xc_ptrs
|
||||
//#include "xud.h"
|
||||
|
||||
#define XUD_SPEED_HS 2
|
||||
|
||||
#include "usb.h"
|
||||
#include "devicedefines.h"
|
||||
#include "usb_midi.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "clockcmds.h"
|
||||
#include "xud.h"
|
||||
|
||||
|
||||
//typedef unsigned int XUD_ep;
|
||||
|
||||
//int XUD_GetData_NoReq(chanend c, xc_ptr buffer);
|
||||
//int XUD_SetData_NoReq(chanend c, xc_ptr buffer, unsigned datalength, unsigned startIndex);
|
||||
XUD_ep XUD_Init_Ep(chanend c_ep);
|
||||
|
||||
inline void XUD_SetNotReady(XUD_ep e)
|
||||
{
|
||||
int chan_array_ptr;
|
||||
asm ("ldw %0, %1[0]":"=r"(chan_array_ptr):"r"(e));
|
||||
asm ("stw %0, %1[0]"::"r"(0),"r"(chan_array_ptr));
|
||||
}
|
||||
|
||||
void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max);
|
||||
#define BUFFER_SIZE_OUT (1028 >> 2)
|
||||
#define BUFFER_SIZE_IN (1028 >> 2)
|
||||
|
||||
/* Packet buffers for audio data */
|
||||
|
||||
extern unsigned int g_curSamFreqMultiplier;
|
||||
|
||||
|
||||
/* Global var for speed. Related to feedback. Used by input stream to determine IN packet size */
|
||||
unsigned g_speed;
|
||||
unsigned g_freqChange = 0;
|
||||
|
||||
/* Interrupt EP data */
|
||||
unsigned char g_intData[8];
|
||||
|
||||
#ifdef MIDI
|
||||
static inline void swap(xc_ptr &a, xc_ptr &b)
|
||||
{
|
||||
xc_ptr tmp;
|
||||
tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned char fb_clocks[16];
|
||||
|
||||
//#define FB_TOLERANCE_TEST
|
||||
#define FB_TOLERANCE 0x100
|
||||
|
||||
extern unsigned inZeroBuff[];
|
||||
extern unsigned g_numUsbChanIn;
|
||||
/**
|
||||
* Buffers data from audio endpoints
|
||||
* @param c_aud_out chanend for audio from xud
|
||||
* @param c_aud_in chanend for audio to xud
|
||||
* @param c_aud_fb chanend for feeback to xud
|
||||
* @return void
|
||||
*/
|
||||
void buffer(register chanend c_aud_out, register chanend c_aud_in, chanend c_aud_fb,
|
||||
chanend c_midi_from_host,
|
||||
chanend c_midi_to_host,
|
||||
chanend c_int, chanend c_sof,
|
||||
chanend c_aud_ctl,
|
||||
in port p_off_mclk
|
||||
)
|
||||
{
|
||||
XUD_ep ep_aud_out = XUD_Init_Ep(c_aud_out);
|
||||
XUD_ep ep_aud_in = XUD_Init_Ep(c_aud_in);
|
||||
XUD_ep ep_aud_fb = XUD_Init_Ep(c_aud_fb);
|
||||
#ifdef MIDI
|
||||
XUD_ep ep_midi_from_host = XUD_Init_Ep(c_midi_from_host);
|
||||
XUD_ep ep_midi_to_host = XUD_Init_Ep(c_midi_to_host);
|
||||
#endif
|
||||
XUD_ep ep_int = XUD_Init_Ep(c_int);
|
||||
|
||||
unsigned datalength;
|
||||
unsigned tmp;
|
||||
unsigned sampleFreq = 0;
|
||||
unsigned lastClock;
|
||||
|
||||
unsigned clocks = 0;
|
||||
|
||||
|
||||
unsigned bufferIn = 1;
|
||||
unsigned remnant = 0, cycles;
|
||||
unsigned sofCount = 0;
|
||||
unsigned freqChange = 0;
|
||||
//unsigned expected = (DEFAULT_FREQ/8000)<<16;
|
||||
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
unsigned expected_fb = 0;
|
||||
#endif
|
||||
|
||||
xc_ptr aud_from_host_buffer = 0;
|
||||
|
||||
#ifdef MIDI
|
||||
xc_ptr midi_from_host_buffer = 0;
|
||||
xc_ptr midi_to_host_buffer = 0;
|
||||
xc_ptr midi_to_host_waiting_buffer = 0;
|
||||
#endif
|
||||
|
||||
|
||||
set_thread_fast_mode_on();
|
||||
|
||||
asm("stw %0, dp[int_usb_ep]"::"r"(ep_int));
|
||||
asm("stw %0, dp[aud_from_host_usb_ep]"::"r"(ep_aud_out));
|
||||
asm("stw %0, dp[aud_to_host_usb_ep]"::"r"(ep_aud_in));
|
||||
asm("stw %0, dp[buffer_aud_ctl_chan]"::"r"(c_aud_ctl));
|
||||
|
||||
/* Wait for USB connect then setup our first packet */
|
||||
{
|
||||
int min, mid, max;
|
||||
int usb_speed = 0;
|
||||
int frameTime;
|
||||
|
||||
while(usb_speed == 0)
|
||||
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
|
||||
|
||||
GetADCCounts(DEFAULT_FREQ, min, mid, max);
|
||||
asm("stw %0, dp[g_speed]"::"r"(mid << 16));
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
mid*=NUM_USB_CHAN_IN*4;
|
||||
else
|
||||
mid*=NUM_USB_CHAN_IN*3;
|
||||
asm("stw %0, %1[0]"::"r"(mid),"r"(inZeroBuff));
|
||||
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
expected_fb = ((DEFAULT_FREQ * 0x2000) / 1000);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef MIDI
|
||||
// get the two buffers to use for midi device->host
|
||||
asm("ldaw %0, dp[g_midi_to_host_buffer_A]":"=r"(midi_to_host_buffer));
|
||||
asm("ldaw %0, dp[g_midi_to_host_buffer_B]":"=r"(midi_to_host_waiting_buffer));
|
||||
asm("ldaw %0, dp[g_midi_from_host_buffer]":"=r"(midi_from_host_buffer));
|
||||
|
||||
|
||||
// pass the midi->XUD chanends to decouple so that thread can
|
||||
// initialize comm with XUD
|
||||
asm("stw %0, dp[midi_to_host_usb_ep]"::"r"(ep_midi_to_host));
|
||||
asm("stw %0, dp[midi_from_host_usb_ep]"::"r"(ep_midi_from_host));
|
||||
swap(midi_to_host_buffer, midi_to_host_waiting_buffer);
|
||||
SET_SHARED_GLOBAL(g_midi_from_host_flag, 1);
|
||||
#endif
|
||||
|
||||
#ifdef OUTPUT
|
||||
SET_SHARED_GLOBAL(g_aud_from_host_flag, 1);
|
||||
#endif
|
||||
|
||||
#ifdef INPUT
|
||||
SET_SHARED_GLOBAL(g_aud_to_host_flag, 1);
|
||||
#endif
|
||||
|
||||
(fb_clocks, unsigned[])[0] = 0;
|
||||
|
||||
|
||||
{
|
||||
int usb_speed;
|
||||
int x;
|
||||
|
||||
asm("ldaw %0, dp[fb_clocks]":"=r"(x));
|
||||
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
|
||||
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
{
|
||||
|
||||
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 4);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 3);
|
||||
}
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* Wait for response from XUD and service relevant EP */
|
||||
select
|
||||
{
|
||||
/* Interrupt EP, send back interrupt data. Note, request made from decouple */
|
||||
case inuint_byref(c_int, tmp):
|
||||
{
|
||||
int sent_ok = 0;
|
||||
/* Start XUD_SetData */
|
||||
|
||||
XUD_SetData_Inline(ep_int, c_int);
|
||||
|
||||
#if 0
|
||||
while (!sent_ok)
|
||||
{
|
||||
outct(c_int, 64);
|
||||
asm("ldw %0, dp[g_intData]":"=r"(tmp));
|
||||
outuint(c_int, tmp);
|
||||
asm("ldw %0, dp[g_intData+4]":"=r"(tmp));
|
||||
outct(c_int, 64);
|
||||
outuint(c_int, tmp);
|
||||
sent_ok = inuint(c_int);
|
||||
/* End XUD_SetData */
|
||||
}
|
||||
#endif
|
||||
|
||||
asm("stw %0, dp[g_intFlag]" :: "r" (0) );
|
||||
XUD_SetNotReady(ep_int);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Sample Freq our chan count update from ep 0 */
|
||||
case inuint_byref(c_aud_ctl, tmp):
|
||||
{
|
||||
int min, mid, max;
|
||||
int usb_speed;
|
||||
int frameTime;
|
||||
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
|
||||
|
||||
if(tmp == SET_SAMPLE_FREQ)
|
||||
{
|
||||
sampleFreq = inuint(c_aud_ctl);
|
||||
|
||||
/* Tidy up double buffer, note we can do better than this for 44.1 etc but better
|
||||
* than sending two packets at old speed! */
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
frameTime = 8000;
|
||||
else
|
||||
frameTime = 1000;
|
||||
|
||||
min = sampleFreq / frameTime;
|
||||
|
||||
max = min + 1;
|
||||
|
||||
mid = min;
|
||||
|
||||
/* Check for INT(SampFreq/8000) == SampFreq/8000 */
|
||||
if((sampleFreq % frameTime) == 0)
|
||||
{
|
||||
min -= 1;
|
||||
}
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
expected_fb = ((sampleFreq * 0x2000) / frametime);
|
||||
#endif
|
||||
|
||||
asm("stw %0, dp[g_speed]"::"r"(mid << 16));
|
||||
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
mid *= NUM_USB_CHAN_IN*4;
|
||||
else
|
||||
mid *= NUM_USB_CHAN_IN*3;
|
||||
|
||||
asm("stw %0, %1[0]"::"r"(mid),"r"(inZeroBuff));
|
||||
|
||||
/* Reset FB */
|
||||
/* Note, Endpoint 0 will hold off host for a sufficient period to allow out feedback
|
||||
* to stabilise (i.e. sofCount == 128 to fire) */
|
||||
sofCount = 0;
|
||||
clocks = 0;
|
||||
remnant = 0;
|
||||
|
||||
/* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this
|
||||
* thread locked, it must stay responsive to packets/SOFs. So, set a flag and check for
|
||||
* handshake elsewhere */
|
||||
/* Pass on sample freq change to decouple */
|
||||
SET_SHARED_GLOBAL(g_freqChange, SET_SAMPLE_FREQ);
|
||||
SET_SHARED_GLOBAL(g_freqChange_sampFreq, sampleFreq);
|
||||
SET_SHARED_GLOBAL(g_freqChange_flag, SET_SAMPLE_FREQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
sampleFreq = inuint(c_aud_ctl);
|
||||
SET_SHARED_GLOBAL(g_freqChange, tmp); /* Set command */
|
||||
SET_SHARED_GLOBAL(g_freqChange_sampFreq, sampleFreq); /* Set flag */
|
||||
SET_SHARED_GLOBAL(g_freqChange_flag, tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#define MASK_16_13 (7) // Bits that should not be transmitted as part of feedback.
|
||||
#define MASK_16_10 (127) //(63) /* For Audio 1.0 we use a mask 1 bit longer than expected to avoid Windows LSB isses */
|
||||
|
||||
case inuint_byref(c_sof, tmp):
|
||||
|
||||
/* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to
|
||||
* lastClock being incorrect */
|
||||
asm("#sof");
|
||||
|
||||
/* Get MCLK count */
|
||||
asm (" getts %0, res[%1]" : "=r" (tmp) : "r" (p_off_mclk));
|
||||
|
||||
GET_SHARED_GLOBAL(freqChange, g_freqChange);
|
||||
if(freqChange == SET_SAMPLE_FREQ)
|
||||
{
|
||||
/* Keep getting MCLK counts */
|
||||
lastClock = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned mask = MASK_16_13, usb_speed;
|
||||
|
||||
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
|
||||
|
||||
if(usb_speed != XUD_SPEED_HS)
|
||||
mask = MASK_16_10;
|
||||
|
||||
/* Number of MCLKS this SOF, approx 125 * 24 (3000), sample by sample rate */
|
||||
asm("ldw %0, dp[g_curSamFreqMultiplier]":"=r"(cycles));
|
||||
cycles = ((int)((short)(tmp - lastClock))) * cycles;
|
||||
|
||||
/* Any odd bits (lower than 16.23) have to be kept seperate */
|
||||
remnant += cycles & mask;
|
||||
|
||||
/* Add 16.13 bits into clock count */
|
||||
clocks += (cycles & ~mask) + (remnant & ~mask);
|
||||
|
||||
/* and overflow from odd bits. Remove overflow from odd bits. */
|
||||
remnant &= mask;
|
||||
|
||||
/* Store MCLK for next time around... */
|
||||
lastClock = tmp;
|
||||
|
||||
/* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll
|
||||
* We always could 128 sofs, so 16ms @ HS, 128ms @ FS */
|
||||
if(sofCount == 128)
|
||||
{
|
||||
sofCount = 0;
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
if (clocks > (expected_fb - FB_TOLERANCE) &&
|
||||
clocks < (expected_fb + FB_TOLERANCE))
|
||||
#endif
|
||||
{
|
||||
int usb_speed;
|
||||
asm("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
|
||||
//fb_clocks = clocks;
|
||||
|
||||
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
|
||||
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
{
|
||||
(fb_clocks, unsigned[])[0] = clocks;
|
||||
}
|
||||
else
|
||||
{
|
||||
(fb_clocks, unsigned[])[0] = clocks>>2;
|
||||
}
|
||||
}
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
else {
|
||||
}
|
||||
#endif
|
||||
clocks = 0;
|
||||
}
|
||||
|
||||
sofCount++;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef OUTPUT
|
||||
/* Audio HOST -> DEVICE */
|
||||
case inuint_byref(c_aud_out, tmp):
|
||||
|
||||
asm("#h->d aud data");
|
||||
GET_SHARED_GLOBAL(aud_from_host_buffer, g_aud_from_host_buffer);
|
||||
|
||||
// XUD_GetData
|
||||
{
|
||||
xc_ptr p = aud_from_host_buffer+4;
|
||||
xc_ptr p0 = p;
|
||||
int tail;
|
||||
while (!testct(c_aud_out))
|
||||
{
|
||||
unsigned int datum = inuint(c_aud_out);
|
||||
write_via_xc_ptr(p, datum);
|
||||
p += 4;
|
||||
}
|
||||
tail = inct(c_aud_out);
|
||||
datalength = p - p0 - 4;
|
||||
switch (tail)
|
||||
{
|
||||
case 10:
|
||||
// the tail is 0 which means
|
||||
datalength -= 2;
|
||||
break;
|
||||
default:
|
||||
// the tail is 2 which means the input was word aligned
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XUD_SetNotReady(ep_aud_out);
|
||||
write_via_xc_ptr(aud_from_host_buffer, datalength);
|
||||
/* Sync with audio thread */
|
||||
SET_SHARED_GLOBAL(g_aud_from_host_flag, 1);
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef INPUT
|
||||
/* DEVICE -> HOST */
|
||||
case inuint_byref(c_aud_in, tmp):
|
||||
{
|
||||
XUD_SetData_Inline(ep_aud_in, c_aud_in);
|
||||
|
||||
XUD_SetNotReady(ep_aud_in);
|
||||
|
||||
/* Inform stream that buffer sent */
|
||||
SET_SHARED_GLOBAL(g_aud_to_host_flag, bufferIn+1);
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OUTPUT
|
||||
/* Feedback Pipe */
|
||||
case inuint_byref(c_aud_fb, tmp):
|
||||
{
|
||||
|
||||
int usb_speed;
|
||||
int x;
|
||||
|
||||
asm("#aud fb");
|
||||
|
||||
XUD_SetData_Inline(ep_aud_fb, c_aud_fb);
|
||||
|
||||
asm("ldaw %0, dp[fb_clocks]":"=r"(x));
|
||||
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
|
||||
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
{
|
||||
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MIDI
|
||||
case inuint_byref(c_midi_from_host, tmp):
|
||||
asm("#midi h->d");
|
||||
|
||||
/* Get buffer data from host - MIDI OUT from host always into a single buffer */
|
||||
{
|
||||
xc_ptr p = midi_from_host_buffer + 4;
|
||||
xc_ptr p0 = p;
|
||||
xc_ptr p1 = p + MAX_USB_MIDI_PACKET_SIZE;
|
||||
while (!testct(c_midi_from_host))
|
||||
{
|
||||
unsigned int datum = inuint(c_midi_from_host);
|
||||
write_via_xc_ptr(p, datum);
|
||||
p += 4;
|
||||
}
|
||||
(void) inct(c_midi_from_host);
|
||||
datalength = p - p0 - 4;
|
||||
}
|
||||
|
||||
XUD_SetNotReady(ep_midi_from_host);
|
||||
|
||||
write_via_xc_ptr(midi_from_host_buffer, datalength);
|
||||
|
||||
/* release the buffer */
|
||||
SET_SHARED_GLOBAL(g_midi_from_host_flag, 1);
|
||||
|
||||
break;
|
||||
|
||||
/* MIDI IN to host */
|
||||
case inuint_byref(c_midi_to_host, tmp):
|
||||
asm("#midi d->h");
|
||||
|
||||
// fill in the data
|
||||
XUD_SetData_Inline(ep_midi_to_host, c_midi_to_host);
|
||||
|
||||
XUD_SetNotReady(ep_midi_to_host);
|
||||
|
||||
// ack the decouple thread to say it has been sent to host
|
||||
SET_SHARED_GLOBAL(g_midi_to_host_flag, 1);
|
||||
|
||||
swap(midi_to_host_buffer, midi_to_host_waiting_buffer);
|
||||
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set_thread_fast_mode_off();
|
||||
|
||||
}
|
||||
23
module_usb_aud_shared/usb_buffer/xc_ptr.h
Normal file
23
module_usb_aud_shared/usb_buffer/xc_ptr.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef __xc_ptr__
|
||||
#define __xc_ptr__
|
||||
|
||||
typedef unsigned int xc_ptr;
|
||||
|
||||
inline xc_ptr array_to_xc_ptr(unsigned a[]) {
|
||||
xc_ptr x;
|
||||
asm("mov %0, %1":"=r"(x):"r"(a));
|
||||
return x;
|
||||
}
|
||||
|
||||
#define write_via_xc_ptr(p,x) asm("stw %0, %1[0]"::"r"(x),"r"(p))
|
||||
|
||||
#define write_via_xc_ptr_indexed(p,i,x) asm("stw %0, %1[%2]"::"r"(x),"r"(p),"r"(i))
|
||||
|
||||
#define read_via_xc_ptr(x,p) asm("ldw %0, %1[0]":"=r"(x):"r"(p));
|
||||
|
||||
#define read_via_xc_ptr_indexed(x,p,i) asm("ldw %0, %1[%2]":"=r"(x):"r"(p),"r"(i));
|
||||
|
||||
#define GET_SHARED_GLOBAL(x, g) asm("ldw %0, dp[" #g "]":"=r"(x))
|
||||
#define SET_SHARED_GLOBAL(g, v) asm("stw %0, dp[" #g "]"::"r"(v))
|
||||
|
||||
#endif
|
||||
59
module_usb_aud_shared/write_sswitch_reg_blind.S
Normal file
59
module_usb_aud_shared/write_sswitch_reg_blind.S
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
#include "xs1_kernel.h"
|
||||
#include "xs1_user.h"
|
||||
|
||||
|
||||
|
||||
.global write_sswitch_reg_blind, "f{si}(ui,ui,ui)"
|
||||
.global write_sswitch_reg_blind.nstackwords
|
||||
.linkset write_sswitch_reg_blind.nstackwords, 0
|
||||
//.type read_sswitch_reg, @function
|
||||
// r0 - coreid
|
||||
// r1 - reg
|
||||
// r2 - data
|
||||
.cc_top write_sswitch_reg_blind.function, write_sswitch_reg_blind
|
||||
.align 2
|
||||
write_sswitch_reg_blind:
|
||||
// Check range of coreid
|
||||
shr r3, r0, XS1_CHAN_ID_PROCESSOR_SIZE + XS1_CHAN_ID_NODE_SIZE
|
||||
bt r3, write_switch_reg_fail
|
||||
|
||||
// Check range of reg
|
||||
shr r3, r1, 16
|
||||
bt r3, write_switch_reg_fail
|
||||
|
||||
// Allocate channel end
|
||||
getr r3, XS1_RES_TYPE_CHANEND
|
||||
|
||||
// Set destination
|
||||
ldc r11, XS1_RES_TYPE_CONFIG | (XS1_CT_SSCTRL << XS1_CHAN_ID_CHANNUM_SHIFT)
|
||||
|
||||
// r0 - l
|
||||
// r1 - reg
|
||||
// r2 - data
|
||||
// r3 - chanend
|
||||
// r11 - low half of dest
|
||||
write_switch_reg:
|
||||
shl r0, r0, XS1_CHAN_ID_PROCESSOR_SHIFT
|
||||
or r0, r0, r11
|
||||
setd res[r3], r0
|
||||
|
||||
// Send packet
|
||||
ldc r11, XS1_CT_WRITEC // Too big for outct immediate
|
||||
outct res[r3], r11
|
||||
mkmsk r0, 32
|
||||
shl r0, r0, 8
|
||||
shr r11, r1, 8
|
||||
or r0, r0, r11
|
||||
out res[r3], r0 // (0xffffff00) | (reg >> 8)
|
||||
outt res[r3], r1 // reg & 0xff
|
||||
out res[r3], r2
|
||||
outct res[r3], XS1_CT_END
|
||||
|
||||
// Receive response
|
||||
freer res[r3]
|
||||
retsp 0
|
||||
write_switch_reg_fail:
|
||||
ldc r0, 0
|
||||
retsp 0
|
||||
.cc_bottom write_sswitch_reg_blind.function
|
||||
23
module_usb_aud_shared/xuduser/xuduser.xc
Normal file
23
module_usb_aud_shared/xuduser/xuduser.xc
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#include "devicedefines.h"
|
||||
|
||||
#ifdef HOST_ACTIVE_CALL
|
||||
void VendorHostActive(int valid);
|
||||
|
||||
void XUD_UserSuspend(void)
|
||||
{
|
||||
VendorHostActive(0);
|
||||
}
|
||||
|
||||
void XUD_UserResume(void)
|
||||
{
|
||||
unsigned config;
|
||||
|
||||
asm("ldw %0, dp[g_config]" : "=r" (config):);
|
||||
|
||||
if(config == 1)
|
||||
{
|
||||
VendorHostActive(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user