This is the task that deals with the endpoints. LED3 (I'm using XK-AUDIO-316-MC-AB) blinks every ~200 ms or so, that is every time an IN report is sent. LED0-2 also blink according to the data received on the OUT endpoint. Wireshark shows consistent transactions.
Code: Select all
/* Task that handles the HID endpoint IN and endpoint OUT */
DECLARE_JOB(hid_inout_task, (chanend_t, chanend_t));
void hid_inout_task(chanend c_ep_out, chanend c_ep_in)
{
unsigned char rxBuffer[64];
unsigned length;
XUD_Result_t result;
unsigned int counter = 0;
int led_state = 0;
debug_printf("Launching hid_inout_task...\n");
XUD_ep ep_out = XUD_InitEp(c_ep_out);
XUD_ep ep_in = XUD_InitEp(c_ep_in);
/* Mark OUT and IN endpoints as ready to receive/send */
XUD_SetReady_Out(ep_out, rxBuffer);
XUD_SetReady_In(ep_in, g_reportBuffer, sizeof(g_reportBuffer));
SELECT_RES(
CASE_THEN(c_ep_out, ep_out_label),
CASE_THEN(c_ep_in, ep_in_label))
{
ep_out_label:
XUD_GetData_Select(c_ep_out, ep_out, &length, &result);
/* Process data from host (length bytes) */
led_state = (led_state & 0xFFFFFFF8) | (1 << (rxBuffer[0] % 4));
port_out(led_port, led_state);
/* Mark EP as ready again */
XUD_SetReady_Out(ep_out, rxBuffer);
continue;
ep_in_label:
if ((counter++ | 0xFFF00000) == 0xFFF00000) {
led_state = led_state ^ 0x8;
port_out(led_port, led_state);
XUD_SetData_Select(c_ep_in, ep_in, &result);
/* Packet successfully sent to host, create next byte */
g_reportBuffer[0] = (char)((counter & 0x0FF00000) >> 20);
/* Mark EP as ready again */
XUD_SetReady_In(ep_in, g_reportBuffer, sizeof(g_reportBuffer));
}
continue;
}
}
Even more strange is the fact that in the case marked with // [COMMENT 1], if I remove the if statement (if ((hidInCounter++ | 0xFFF00000) == 0xFFF00000)), then I see input reports every 4ms! So it's like `if' statement is never true. I tried different conditions for the if statement, even a simple if (hidInCounter++ == 10) with hidInCounter reset to 0 inside the if doesn't work.
Why is that? I would never realized by myself that I need to handle the IN endpoint in the 'default' statement, but I noticed that original lib_xua does the same (see here) to handle its own input HID for playback control (that is not enabled here, and not present in the descriptors).
Code: Select all
unsafe{volatile unsigned * unsafe masterClockFreq_ptr;}
void XUA_Buffer_Ep(
register chanend c_aud_out,
register chanend c_aud_in,
chanend c_aud_fb,
chanend c_sof,
chanend c_aud_ctl,
in port p_off_mclk,
chanend c_hid,
chanend c_hid_out
)
{
XUD_ep ep_aud_out = XUD_InitEp(c_aud_out);
XUD_ep ep_aud_in = XUD_InitEp(c_aud_in);
XUD_ep ep_aud_fb = XUD_InitEp(c_aud_fb);
XUD_ep ep_hid = XUD_InitEp(c_hid);
unsigned int hidInCounter = 0;
int led_state = 0;
XUD_ep ep_hid_out = XUD_InitEp(c_hid_out);
unsigned u_tmp;
unsigned char cmd;
unsigned sampleFreq = 48000 ;
unsigned masterClockFreq = (512*48000) ;
unsigned lastClock = 0;
unsigned freqChange = 0;
unsafe{masterClockFreq_ptr = &masterClockFreq;}
unsigned clocks = 0;
long long clockcounter = 0;
unsigned bufferIn = 1;
int sofCount = 0;
unsigned mod_from_last_time = 0;
xc_ptr aud_from_host_buffer = 0;
unsigned char hid_from_host_buffer[64];
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));
asm volatile("stw %0, dp[" "g_aud_from_host_flag" "]"::"r"(1):"memory") ;
asm volatile("stw %0, dp[" "g_aud_to_host_flag" "]"::"r"(1):"memory") ;
fb_clocks[0] = 0;
XUD_SetReady_In(ep_hid, g_customHidData, sizeof(g_customHidData));
XUD_SetReady_Out(ep_hid_out, hid_from_host_buffer);
while(1)
{
XUD_Result_t result;
unsigned length;
select
{
case __builtin_inct_byref(c_aud_ctl, cmd) :
{
if(cmd == 4 )
{
unsigned receivedSampleFreq = __builtin_in_uint(c_aud_ctl) ;
asm volatile("stw %0, dp[" "g_freqChange_sampFreq" "]"::"r"(receivedSampleFreq):"memory") ;
}
else if(cmd == 9 )
{
unsigned formatChange_DataFormat = __builtin_in_uint(c_aud_ctl) ;
unsigned formatChange_NumChans = __builtin_in_uint(c_aud_ctl) ;
unsigned formatChange_SubSlot = __builtin_in_uint(c_aud_ctl) ;
unsigned formatChange_SampRes = __builtin_in_uint(c_aud_ctl) ;
asm volatile("stw %0, dp[" "g_formatChange_NumChans" "]"::"r"(formatChange_NumChans):"memory") ;
asm volatile("stw %0, dp[" "g_formatChange_SubSlot" "]"::"r"(formatChange_SubSlot):"memory") ;
asm volatile("stw %0, dp[" "g_formatChange_DataFormat" "]"::"r"(formatChange_DataFormat):"memory") ;
asm volatile("stw %0, dp[" "g_formatChange_SampRes" "]"::"r"(formatChange_SampRes):"memory") ;
}
else if (cmd == 8 )
{
XUD_BusSpeed_t busSpeed;
unsigned formatChange_DataFormat = __builtin_in_uint(c_aud_ctl) ;
unsigned formatChange_NumChans = __builtin_in_uint(c_aud_ctl) ;
unsigned formatChange_SubSlot = __builtin_in_uint(c_aud_ctl) ;
unsigned formatChange_SampRes = __builtin_in_uint(c_aud_ctl) ;
asm volatile("stw %0, dp[" "g_formatChange_NumChans" "]"::"r"(formatChange_NumChans):"memory") ;
asm volatile("stw %0, dp[" "g_formatChange_SubSlot" "]"::"r"(formatChange_SubSlot):"memory") ;
asm volatile("stw %0, dp[" "g_formatChange_DataFormat" "]"::"r"(formatChange_DataFormat):"memory") ;
asm volatile("stw %0, dp[" "g_formatChange_SampRes" "]"::"r"(formatChange_SampRes):"memory") ;
asm volatile("ldw %0, dp[" "g_curUsbSpeed" "]":"=r"(busSpeed)::"memory") ;
if (busSpeed == XUD_SPEED_HS)
{
XUD_SetReady_In(ep_aud_fb, (fb_clocks, unsigned char[]), 4);
}
else
{
XUD_SetReady_In(ep_aud_fb, (fb_clocks, unsigned char[]), 3);
}
}
asm volatile("stw %0, dp[" "g_freqChange" "]"::"r"(cmd):"memory") ;
asm volatile("stw %0, dp[" "g_freqChange_flag" "]"::"r"(cmd):"memory") ;
break;
}
case __builtin_in_uint_byref(c_sof, u_tmp) :
asm volatile(" getts %0, res[%1]" : "=r" (u_tmp) : "r" (p_off_mclk));
asm volatile("ldw %0, dp[" "g_freqChange" "]":"=r"(freqChange)::"memory") ;
if((freqChange == 4 ) || !feedbackValid)
{
lastClock = u_tmp;
feedbackValid = 1;
}
else
{
unsigned usb_speed;
asm volatile("ldw %0, dp[" "g_curUsbSpeed" "]":"=r"(usb_speed)::"memory") ;
unsigned long long feedbackMul = 64ULL;
if(usb_speed != XUD_SPEED_HS)
feedbackMul = 8ULL;
int count = (int) ((short)(u_tmp - lastClock));
unsigned long long full_result = count * feedbackMul * sampleFreq;
clockcounter += full_result;
lastClock = u_tmp;
if(sofCount == 128)
{
sofCount = 0;
clockcounter += mod_from_last_time;
clocks = clockcounter / masterClockFreq;
mod_from_last_time = clockcounter % masterClockFreq;
if(usb_speed == XUD_SPEED_HS)
{
clocks <<= 3;
}
else
{
clocks <<= 6;
}
{
asm volatile("stw %0, dp[g_speed]"::"r"(clocks));
asm volatile("ldw %0, dp[" "g_curUsbSpeed" "]":"=r"(usb_speed)::"memory") ;
if (usb_speed == XUD_SPEED_HS)
{
fb_clocks[0] = clocks;
}
else
{
fb_clocks[0] = clocks >> 2;
}
}
clockcounter = 0;
}
sofCount++;
}
break;
case XUD_SetData_Select(c_aud_in, ep_aud_in, result):
{
asm volatile("stw %0, dp[" "g_aud_to_host_flag" "]"::"r"(bufferIn+1):"memory") ;
break;
}
case XUD_SetData_Select(c_aud_fb, ep_aud_fb, result):
{
XUD_BusSpeed_t busSpeed;
asm volatile("ldw %0, dp[" "g_curUsbSpeed" "]":"=r"(busSpeed)::"memory") ;
if (busSpeed == XUD_SPEED_HS)
{
XUD_SetReady_In(ep_aud_fb, (fb_clocks, unsigned char[]), 4);
}
else
{
XUD_SetReady_In(ep_aud_fb, (fb_clocks, unsigned char[]), 3);
}
break;
}
case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result):
{
asm volatile("ldw %0, dp[" "g_aud_from_host_buffer" "]":"=r"(aud_from_host_buffer)::"memory") ;
asm volatile("stw %0, %1[0]"::"r"(length),"r"(aud_from_host_buffer)) ;
asm volatile("stw %0, dp[" "g_aud_from_host_flag" "]"::"r"(1):"memory") ;
break;
}
case XUD_SetData_Select(c_hid, ep_hid, result):
// [COMMENT 1]
if ((hidInCounter++ | 0xFFF00000) == 0xFFF00000) {
led_state = led_state ^ 0x8;
led_port <: led_state;
g_customHidData[0] = (char)((hidInCounter & 0x0FF00000) >> 20);
XUD_SetReady_In(ep_hid, g_customHidData, sizeof(g_customHidData));
}
break;
case XUD_GetData_Select(c_hid_out, ep_hid_out, length, result):
debug_printf("HID data from host, result %d, len %d\n", result, length) ;
led_state = (led_state & 0xFFFFFFF8) | (1 << (hid_from_host_buffer[0] % 4));
led_port <: led_state;
XUD_SetReady_Out(ep_hid_out, hid_from_host_buffer);
break;
default:
// [COMMENT 2]
if ((hidInCounter++ | 0xFFF00000) == 0xFFF00000) {
led_state = led_state ^ 0x8;
led_port <: led_state;
g_customHidData[0] = (char)((hidInCounter & 0x0FF00000) >> 20);
XUD_SetReady_In(ep_hid, g_customHidData, sizeof(g_customHidData));
}
break;
}
}
}