forked from PAWPAW-Mirror/lib_xua
Doc updates
This commit is contained in:
22
module_usb_audio/usb_buffer/decouple.h
Normal file
22
module_usb_audio/usb_buffer/decouple.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#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_midi,
|
||||
chanend ?c_clk_int
|
||||
#ifdef IAP
|
||||
, chanend ?c_iap
|
||||
#endif
|
||||
);
|
||||
|
||||
#endif // __decouple_h__
|
||||
1142
module_usb_audio/usb_buffer/decouple.xc
Normal file
1142
module_usb_audio/usb_buffer/decouple.xc
Normal file
File diff suppressed because it is too large
Load Diff
1169
module_usb_audio/usb_buffer/decouple.xc.orig
Normal file
1169
module_usb_audio/usb_buffer/decouple.xc.orig
Normal file
File diff suppressed because it is too large
Load Diff
49
module_usb_audio/usb_buffer/get_adc_counts.c
Normal file
49
module_usb_audio/usb_buffer/get_adc_counts.c
Normal file
@@ -0,0 +1,49 @@
|
||||
extern unsigned int g_curUsbSpeed;
|
||||
#define XUD_SPEED_HS 2
|
||||
|
||||
/* Returns the max and min packet sizes to send back to host for a given sample frequency
|
||||
* See page 13 of USB Audio Device Class Definitions for Audio Data Formats Spec (v2.0)
|
||||
*
|
||||
* Audio samples per frame = INT(sampFreq/frametime); Variation allowed is + 1;
|
||||
*
|
||||
* For HS frame time = 8 * 1000
|
||||
*
|
||||
* so n = INT(SampFreq/8000) | INT (SampFreq/8000) + 1
|
||||
*
|
||||
* In the case where INT(SampFreq/8000) == SampFreq/8000) n may vary between
|
||||
*
|
||||
* INT(SamFreq/8000) - 1 | INT(SampFreq/8000) | INT (SampFreq/8000) + 1
|
||||
*
|
||||
* Note: Assumes HS (i.e. 8 frames per 1ms)
|
||||
*
|
||||
* Examples:
|
||||
* 44100: min: 5 max: 6
|
||||
* 48000: min: 5 max: 7
|
||||
* 96000: min: 11 max: 13
|
||||
* 88200: min: 11 max: 12
|
||||
* 176400: min: 22 max: 23
|
||||
* 192000: min: 23 max: 25
|
||||
*
|
||||
*/
|
||||
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_audio/usb_buffer/interrupt.h
Normal file
198
module_usb_audio/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
|
||||
|
||||
17
module_usb_audio/usb_buffer/testct_byref.h
Normal file
17
module_usb_audio/usb_buffer/testct_byref.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//#pragma select handler
|
||||
#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
|
||||
static inline void testct_byref(chanend c, unsigned &isCt)
|
||||
{
|
||||
if (testct(c))
|
||||
{
|
||||
isCt = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
isCt = 0;
|
||||
}
|
||||
}
|
||||
//void testct_byref(chanend c, unsigned &isCt) ;
|
||||
15
module_usb_audio/usb_buffer/testct_byref.xc
Normal file
15
module_usb_audio/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_byrefnot(chanend c, unsigned &isCt)
|
||||
{
|
||||
if (testct(c))
|
||||
{
|
||||
isCt = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
isCt = 0;
|
||||
}
|
||||
}
|
||||
41
module_usb_audio/usb_buffer/usb_buffer.h
Normal file
41
module_usb_audio/usb_buffer/usb_buffer.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#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,
|
||||
#ifdef MIDI
|
||||
chanend c_midi_from_host,
|
||||
chanend c_midi_to_host,
|
||||
chanend c_midi,
|
||||
#endif
|
||||
#ifdef IAP
|
||||
#error IAP
|
||||
chanend c_iap_from_host,
|
||||
chanend c_iap_to_host,
|
||||
chanend c_iap_to_host_int,
|
||||
#endif
|
||||
chanend? c_int,
|
||||
chanend c_sof,
|
||||
chanend c_aud_ctl,
|
||||
in port p_off_mclk
|
||||
#ifdef HID_CONTROLS
|
||||
,chanend c_hid
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
738
module_usb_audio/usb_buffer/usb_buffer.xc
Normal file
738
module_usb_audio/usb_buffer/usb_buffer.xc
Normal file
@@ -0,0 +1,738 @@
|
||||
|
||||
#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"
|
||||
#ifdef IAP
|
||||
#include "iAP.h"
|
||||
#endif
|
||||
#include "xc_ptr.h"
|
||||
#include "clockcmds.h"
|
||||
#include "xud.h"
|
||||
#include "testct_byref.h"
|
||||
|
||||
int pktCount = 0;
|
||||
|
||||
XUD_ep XUD_Init_Ep(chanend c_ep);
|
||||
//
|
||||
//static 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];
|
||||
|
||||
#if defined (MIDI) || defined(IAP)
|
||||
static inline void swap(xc_ptr &a, xc_ptr &b)
|
||||
{
|
||||
xc_ptr tmp;
|
||||
tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MIDI
|
||||
unsigned int g_midi_to_host_buffer_A[MAX_USB_MIDI_PACKET_SIZE/4+4];
|
||||
unsigned int g_midi_to_host_buffer_B[MAX_USB_MIDI_PACKET_SIZE/4+4];
|
||||
int g_midi_from_host_buffer[MAX_USB_MIDI_PACKET_SIZE/4+4];
|
||||
#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,
|
||||
#ifdef MIDI
|
||||
chanend c_midi_from_host,
|
||||
chanend c_midi_to_host,
|
||||
chanend c_midi,
|
||||
#endif
|
||||
#ifdef IAP
|
||||
chanend c_iap_from_host,
|
||||
chanend c_iap_to_host,
|
||||
chanend c_iap_to_host_int,
|
||||
#endif
|
||||
chanend ?c_int, chanend c_sof,
|
||||
chanend c_aud_ctl,
|
||||
in port p_off_mclk
|
||||
#ifdef HID_CONTROLS
|
||||
,chanend c_hid
|
||||
#endif
|
||||
)
|
||||
{
|
||||
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
|
||||
#ifdef IAP
|
||||
XUD_ep ep_iap_from_host = XUD_Init_Ep(c_iap_from_host);
|
||||
XUD_ep ep_iap_to_host = XUD_Init_Ep(c_iap_to_host);
|
||||
XUD_ep ep_iap_to_host_int = XUD_Init_Ep(c_iap_to_host_int);
|
||||
#endif
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
XUD_ep ep_int = XUD_Init_Ep(c_int);
|
||||
#endif
|
||||
|
||||
#ifdef HID_CONTROLS
|
||||
XUD_ep ep_hid = XUD_Init_Ep(c_hid);
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
|
||||
xc_ptr midi_from_host_rdptr;
|
||||
xc_ptr midi_to_host_buffer_being_sent = array_to_xc_ptr(g_midi_to_host_buffer_A);
|
||||
xc_ptr midi_to_host_buffer_being_collected = array_to_xc_ptr(g_midi_to_host_buffer_B);
|
||||
|
||||
|
||||
int is_ack;
|
||||
unsigned int datum;
|
||||
int midi_data_remaining_to_device = 0;
|
||||
int midi_data_collected_from_device = 0;
|
||||
int midi_waiting_on_send_to_host = 0;
|
||||
int midi_to_host_flag = 0;
|
||||
int midi_from_host_flag = 0;
|
||||
#endif
|
||||
|
||||
xc_ptr p_inZeroBuff = array_to_xc_ptr(inZeroBuff);
|
||||
|
||||
set_thread_fast_mode_on();
|
||||
|
||||
#ifdef IAP
|
||||
/* Note the order here is important */
|
||||
XUD_ResetDrain(c_iap_to_host);
|
||||
XUD_ResetDrain(c_iap_to_host_int);
|
||||
XUD_GetBusSpeed(c_iap_to_host);
|
||||
XUD_GetBusSpeed(c_iap_to_host_int);
|
||||
#endif
|
||||
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
asm("stw %0, dp[int_usb_ep]"::"r"(ep_int));
|
||||
#endif
|
||||
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));
|
||||
#ifdef HID_CONTROLS
|
||||
asm("stw %0, dp[g_ep_hid]"::"r"(ep_hid));
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||
}
|
||||
|
||||
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"(p_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 IAP
|
||||
// get the two buffers to use for iap device->host
|
||||
asm("ldaw %0, dp[g_iap_to_host_buffer_A]":"=r"(iap_to_host_buffer));
|
||||
asm("ldaw %0, dp[g_iap_to_host_buffer_B]":"=r"(iap_to_host_waiting_buffer));
|
||||
asm("ldaw %0, dp[g_iap_from_host_buffer]":"=r"(iap_from_host_buffer));
|
||||
|
||||
|
||||
// pass the iap->XUD chanends to decouple so that thread can
|
||||
// initialize comm with XUD
|
||||
asm("stw %0, dp[iap_to_host_usb_ep]"::"r"(ep_iap_to_host));
|
||||
asm("stw %0, dp[iap_to_host_int_usb_ep]"::"r"(ep_iap_to_host_int));
|
||||
asm("stw %0, dp[iap_from_host_usb_ep]"::"r"(ep_iap_from_host));
|
||||
swap(iap_to_host_buffer, iap_to_host_waiting_buffer);
|
||||
SET_SHARED_GLOBAL(g_iap_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));
|
||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
{
|
||||
XUD_SetReady_In(ep_aud_fb, fb_clocks, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
XUD_SetReady_In(ep_aud_fb, fb_clocks, 3);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MIDI
|
||||
XUD_SetReady_OutPtr(ep_midi_from_host, midi_from_host_buffer);
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Wait for response from XUD and service relevant EP */
|
||||
select
|
||||
{
|
||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
||||
/* 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sample Freq our chan count update from ep 0 */
|
||||
case testct_byref(c_aud_ctl, tmp):
|
||||
{
|
||||
if (tmp) {
|
||||
// is a control token sent by reboot_device
|
||||
inct(c_aud_ctl);
|
||||
outct(c_aud_ctl, XS1_CT_END);
|
||||
while(1) {};
|
||||
} else {
|
||||
int min, mid, max;
|
||||
int usb_speed;
|
||||
int frameTime;
|
||||
tmp = inuint(c_aud_ctl);
|
||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||
|
||||
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"(p_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;
|
||||
|
||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||
|
||||
if(usb_speed != XUD_SPEED_HS)
|
||||
mask = MASK_16_10;
|
||||
|
||||
/* Number of MCLKS this SOF, approx 125 * 24 (3000), sample by sample rate */
|
||||
GET_SHARED_GLOBAL(cycles, g_curSamFreqMultiplier);
|
||||
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;
|
||||
|
||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||
|
||||
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 INPUT
|
||||
/* DEVICE -> HOST */
|
||||
case XUD_SetData_Select(c_aud_in, ep_aud_in, tmp):
|
||||
{
|
||||
/* Inform stream that buffer sent */
|
||||
SET_SHARED_GLOBAL(g_aud_to_host_flag, bufferIn+1);
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OUTPUT
|
||||
/* Feedback Pipe */
|
||||
case XUD_SetData_Select(c_aud_fb, ep_aud_fb, tmp):
|
||||
{
|
||||
|
||||
int usb_speed;
|
||||
int x;
|
||||
|
||||
asm("#aud fb");
|
||||
|
||||
asm("ldaw %0, dp[fb_clocks]":"=r"(x));
|
||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
{
|
||||
XUD_SetReady_In(ep_aud_fb, fb_clocks, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
XUD_SetReady_In(ep_aud_fb, fb_clocks, 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Audio HOST -> DEVICE */
|
||||
case XUD_GetData_Select(c_aud_out, ep_aud_out, tmp):
|
||||
{
|
||||
asm("#h->d aud data");
|
||||
|
||||
GET_SHARED_GLOBAL(aud_from_host_buffer, g_aud_from_host_buffer);
|
||||
|
||||
write_via_xc_ptr(aud_from_host_buffer, tmp);
|
||||
|
||||
/* Sync with audio thread */
|
||||
SET_SHARED_GLOBAL(g_aud_from_host_flag, 1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef MIDI
|
||||
case XUD_GetData_Select(c_midi_from_host, ep_midi_from_host, tmp):
|
||||
asm("#midi h->d");
|
||||
|
||||
/* Get buffer data from host - MIDI OUT from host always into a single buffer */
|
||||
/* Write datalength (tmp) into buffer[0], data stored in buffer[4] onwards */
|
||||
midi_data_remaining_to_device = tmp;
|
||||
|
||||
/* Increment read pointer - buffer[0] is length */
|
||||
midi_from_host_rdptr = midi_from_host_buffer + 4;
|
||||
|
||||
if (midi_data_remaining_to_device)
|
||||
{
|
||||
read_via_xc_ptr(datum, midi_from_host_rdptr);
|
||||
outuint(c_midi, datum);
|
||||
midi_from_host_rdptr += 4;
|
||||
midi_data_remaining_to_device -= 4;
|
||||
}
|
||||
break;
|
||||
|
||||
/* MIDI IN to host */
|
||||
case XUD_SetData_Select(c_midi_to_host, ep_midi_to_host, tmp):
|
||||
asm("#midi d->h");
|
||||
|
||||
swap(midi_to_host_buffer, midi_to_host_waiting_buffer);
|
||||
|
||||
/* The buffer has been sent to the host, so we can ack the midi thread */
|
||||
if (midi_data_collected_from_device != 0)
|
||||
{
|
||||
/* We have some more data to send set the amount of data to send */
|
||||
write_via_xc_ptr(midi_to_host_buffer_being_collected, midi_data_collected_from_device);
|
||||
|
||||
/* Swap the collecting and sending buffer */
|
||||
swap(midi_to_host_buffer_being_collected, midi_to_host_buffer_being_sent);
|
||||
|
||||
/* Request to send packet */
|
||||
XUD_SetReady_InPtr(ep_midi_to_host, midi_to_host_buffer_being_sent+4, midi_data_collected_from_device);
|
||||
|
||||
/* Mark as waiting for host to poll us */
|
||||
midi_waiting_on_send_to_host = 1;
|
||||
/* Reset the collected data count */
|
||||
midi_data_collected_from_device = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
midi_waiting_on_send_to_host = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef IAP
|
||||
case testct_byref(c_iap_from_host, tmp):
|
||||
asm("#iap h->d");
|
||||
if (tmp) {
|
||||
// Is a control token, not expected
|
||||
} else {
|
||||
// Not a control token so is data
|
||||
/* Get buffer data from host - IAP OUT from host always into a single buffer */
|
||||
xc_ptr p = iap_from_host_buffer + 4;
|
||||
xc_ptr p0 = p;
|
||||
int tail;
|
||||
inuint(c_iap_from_host); // And discard
|
||||
while (!testct(c_iap_from_host))
|
||||
{
|
||||
unsigned int datum = inuint(c_iap_from_host);
|
||||
write_via_xc_ptr(p, datum);
|
||||
p += 4;
|
||||
}
|
||||
tail = inct(c_iap_from_host);
|
||||
datalength = p - p0;// - 4;
|
||||
switch (tail)
|
||||
{
|
||||
case 10:
|
||||
// the tail is 0 which means
|
||||
datalength -= 6;
|
||||
break;
|
||||
case 11:
|
||||
// the tail is 1 which means
|
||||
datalength -= 5;
|
||||
break;
|
||||
case 12:
|
||||
// the tail is 2 which means
|
||||
datalength -= 4;
|
||||
break;
|
||||
case 13:
|
||||
// the tail is 3 which means
|
||||
datalength -= 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// XUD_SetNotReady(ep_iap_from_host);
|
||||
|
||||
write_via_xc_ptr(iap_from_host_buffer, datalength);
|
||||
|
||||
/* release the buffer */
|
||||
SET_SHARED_GLOBAL(g_iap_from_host_flag, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
/* IAP IN to host */
|
||||
case testct_byref(c_iap_to_host, tmp):
|
||||
asm("#iap d->h");
|
||||
if (tmp)
|
||||
{
|
||||
// Is a control token so reset
|
||||
XUD_ResetDrain(c_iap_to_host);
|
||||
XUD_ResetDrain(c_iap_to_host_int);
|
||||
XUD_GetBusSpeed(c_iap_to_host);
|
||||
XUD_GetBusSpeed(c_iap_to_host_int);
|
||||
|
||||
XUD_SetNotReady(ep_iap_to_host);
|
||||
XUD_SetNotReady(ep_iap_to_host_int);
|
||||
} else {
|
||||
inuint(c_iap_to_host); // And discard
|
||||
// fill in the data
|
||||
//XUD_SetData_Inline(ep_iap_to_host, c_iap_to_host);
|
||||
|
||||
//XUD_SetNotReady(ep_iap_to_host);
|
||||
|
||||
// ack the decouple thread to say it has been sent to host
|
||||
SET_SHARED_GLOBAL(g_iap_to_host_flag, 1);
|
||||
|
||||
swap(iap_to_host_buffer, iap_to_host_waiting_buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
/* IAP interrupt IN to host */
|
||||
case testct_byref(c_iap_to_host_int, tmp):
|
||||
asm("#iap interrupt d->h");
|
||||
if (tmp)
|
||||
{
|
||||
// Is a control token so reset
|
||||
XUD_ResetDrain(c_iap_to_host);
|
||||
XUD_ResetDrain(c_iap_to_host_int);
|
||||
XUD_GetBusSpeed(c_iap_to_host);
|
||||
XUD_GetBusSpeed(c_iap_to_host_int);
|
||||
|
||||
XUD_SetNotReady(ep_iap_to_host);
|
||||
XUD_SetNotReady(ep_iap_to_host_int);
|
||||
}
|
||||
else
|
||||
{
|
||||
inuint(c_iap_to_host_int); // And discard
|
||||
// fill in the data
|
||||
// XUD_SetData_Inline(ep_iap_to_host_int, c_iap_to_host_int);
|
||||
//XUD_SetNotReady(ep_iap_to_host_int);
|
||||
// Don't need to handle data here as always ZLP
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HID_CONTROLS
|
||||
/* HID Report Data */
|
||||
case XUD_SetData_Select(c_hid, ep_hid, tmp):
|
||||
{
|
||||
asm("stw %0, dp[g_hidFlag]" :: "r" (0) );
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef MIDI
|
||||
/* Received word from MIDI thread - Check for ACK or Data */
|
||||
case midi_get_ack_or_data(c_midi, is_ack, datum):
|
||||
if (is_ack)
|
||||
{
|
||||
/* An ack from the midi/uart thread means it has accepted some data we sent it
|
||||
* we are okay to send another word */
|
||||
if (midi_data_remaining_to_device == 0)
|
||||
{
|
||||
/* We have read an entire packet - Mark ready to receive another */
|
||||
XUD_SetReady_OutPtr(ep_midi_from_host, midi_from_host_buffer+4);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read another word from the fifo and output it to MIDI thread */
|
||||
read_via_xc_ptr(datum, midi_from_host_rdptr);
|
||||
outuint(c_midi, datum);
|
||||
midi_from_host_rdptr += 4;
|
||||
midi_data_remaining_to_device -= 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The midi/uart thread has sent us some data - handshake back */
|
||||
midi_send_ack(c_midi);
|
||||
if (midi_data_collected_from_device < MIDI_USB_BUFFER_TO_HOST_SIZE)
|
||||
{
|
||||
/* There is room in the collecting buffer for the data */
|
||||
xc_ptr p = (midi_to_host_buffer_being_collected + 4) + midi_data_collected_from_device;
|
||||
// Add data to the buffer
|
||||
write_via_xc_ptr(p, datum);
|
||||
midi_data_collected_from_device += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too many events from device - drop
|
||||
}
|
||||
|
||||
// If we are not sending data to the host then initiate it
|
||||
if (!midi_waiting_on_send_to_host)
|
||||
{
|
||||
write_via_xc_ptr(midi_to_host_buffer_being_collected, midi_data_collected_from_device);
|
||||
|
||||
swap(midi_to_host_buffer_being_collected, midi_to_host_buffer_being_sent);
|
||||
|
||||
// Signal other side to swap
|
||||
XUD_SetReady_InPtr(ep_midi_to_host, midi_to_host_buffer_being_sent+4, midi_data_collected_from_device);
|
||||
midi_data_collected_from_device = 0;
|
||||
midi_waiting_on_send_to_host = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* ifdef MIDI */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set_thread_fast_mode_off();
|
||||
|
||||
}
|
||||
34
module_usb_audio/usb_buffer/xc_ptr.h
Normal file
34
module_usb_audio/usb_buffer/xc_ptr.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef __xc_ptr__
|
||||
#define __xc_ptr__
|
||||
|
||||
typedef unsigned int xc_ptr;
|
||||
|
||||
// Note that this function is marked as const to avoid the XC
|
||||
// parallel usage checks, this is only really going to work if this
|
||||
// is the *only* way the array a is accessed (and everything else uses
|
||||
// the xc_ptr)
|
||||
inline xc_ptr array_to_xc_ptr(const 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 write_byte_via_xc_ptr_indexed(p,i,x) asm("st8 %0, %1[%2]"::"r"(x),"r"(p),"r"(i))
|
||||
// No immediate st8 format
|
||||
#define write_byte_via_xc_ptr(p,x) write_byte_via_xc_ptr_indexed(p, 0, x)
|
||||
|
||||
#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 read_byte_via_xc_ptr_indexed(x,p,i) asm("ld8u %0, %1[%2]":"=r"(x):"r"(p),"r"(i));
|
||||
// No immediate ld8u format
|
||||
#define read_byte_via_xc_ptr(x,p) read_byte_via_xc_ptr_indexed(x, p, 0)
|
||||
|
||||
#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
|
||||
3
module_usb_audio/usb_buffer/xc_ptr.xc
Normal file
3
module_usb_audio/usb_buffer/xc_ptr.xc
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "xc_ptr.h"
|
||||
|
||||
extern inline xc_ptr array_to_xc_ptr(const unsigned a[]);
|
||||
Reference in New Issue
Block a user