#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) | #define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) | ||||
uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; | uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; | ||||
uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] DMABUFATTR; | uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] DMABUFATTR; | ||||
uint32_t usb_audio_sync_feedback DMABUFATTR; | |||||
void AudioInputUSB::begin(void) | void AudioInputUSB::begin(void) | ||||
{ | { | ||||
// but also because the PC may stop transmitting data, which | // but also because the PC may stop transmitting data, which | ||||
// means we no longer get receive callbacks from usb_dev. | // means we no longer get receive callbacks from usb_dev. | ||||
update_responsibility = false; | update_responsibility = false; | ||||
usb_audio_sync_feedback = 722824; | |||||
} | } | ||||
static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len) | static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len) | ||||
audio_block_t *left, *right; | audio_block_t *left, *right; | ||||
const uint32_t *data; | const uint32_t *data; | ||||
//return; | |||||
len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right | len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right | ||||
data = (const uint32_t *)usb_audio_receive_buffer; | data = (const uint32_t *)usb_audio_receive_buffer; | ||||
copy_to_buffers(data, left->data + count, right->data + count, avail); | copy_to_buffers(data, left->data + count, right->data + count, avail); | ||||
data += avail; | data += avail; | ||||
len -= avail; | len -= avail; | ||||
if (AudioInputUSB::ready_left) | |||||
if (AudioInputUSB::ready_left) // buffer overrun, PC sending too fast | |||||
AudioStream::release(AudioInputUSB::ready_left); | AudioStream::release(AudioInputUSB::ready_left); | ||||
AudioInputUSB::ready_left = left; | AudioInputUSB::ready_left = left; | ||||
if (AudioInputUSB::ready_right) | if (AudioInputUSB::ready_right) | ||||
right = ready_right; | right = ready_right; | ||||
ready_right = NULL; | ready_right = NULL; | ||||
// TODO: use incoming_count for USB isochronous feedback | // TODO: use incoming_count for USB isochronous feedback | ||||
uint16_t c = incoming_count; | |||||
__enable_irq(); | __enable_irq(); | ||||
//if (left && right) { | |||||
//serial_print("$"); | |||||
//} else { | |||||
//serial_print("#"); | |||||
//} | |||||
//serial_phex(c); | |||||
//serial_print("."); | |||||
if (!left || !right) { | |||||
//serial_print("#"); // buffer underrun - PC sending too slow | |||||
} | |||||
if (left) { | if (left) { | ||||
transmit(left, 0); | transmit(left, 0); | ||||
release(left); | release(left); |
extern uint16_t usb_audio_transmit_buffer[]; | extern uint16_t usb_audio_transmit_buffer[]; | ||||
extern void usb_audio_receive_callback(unsigned int len); | extern void usb_audio_receive_callback(unsigned int len); | ||||
extern unsigned int usb_audio_transmit_callback(void); | extern unsigned int usb_audio_transmit_callback(void); | ||||
extern uint32_t usb_audio_sync_feedback; | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||
#define AUDIO_INTERFACE_DESC_POS KEYMEDIA_INTERFACE_DESC_POS+KEYMEDIA_INTERFACE_DESC_SIZE | #define AUDIO_INTERFACE_DESC_POS KEYMEDIA_INTERFACE_DESC_POS+KEYMEDIA_INTERFACE_DESC_SIZE | ||||
#ifdef AUDIO_INTERFACE | #ifdef AUDIO_INTERFACE | ||||
#define AUDIO_INTERFACE_DESC_SIZE 9+10+12+9+12+9 + 9+9+7+11+9+7 + 9+9+7+11+9+7 | |||||
#define AUDIO_INTERFACE_DESC_SIZE 9+10+12+9+12+9 + 9+9+7+11+9+7 + 9+9+7+11+9+7+9 | |||||
#else | #else | ||||
#define AUDIO_INTERFACE_DESC_SIZE 0 | #define AUDIO_INTERFACE_DESC_SIZE 0 | ||||
#endif | #endif | ||||
1, // bSamFreqType = 1 frequency | 1, // bSamFreqType = 1 frequency | ||||
LSB(44100), MSB(44100), 0, // tSamFreq | LSB(44100), MSB(44100), 0, // tSamFreq | ||||
// Standard AS Isochronous Audio Data Endpoint Descriptor | // Standard AS Isochronous Audio Data Endpoint Descriptor | ||||
// SB DCD for Audio Devices 1.0, Section 4.6.1.1, Table 4-20, page 61-62 | |||||
// USB DCD for Audio Devices 1.0, Section 4.6.1.1, Table 4-20, page 61-62 | |||||
9, // bLength | 9, // bLength | ||||
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | ||||
AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress | AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress | ||||
4, // bDescriptorType = INTERFACE | 4, // bDescriptorType = INTERFACE | ||||
AUDIO_INTERFACE+2, // bInterfaceNumber | AUDIO_INTERFACE+2, // bInterfaceNumber | ||||
1, // bAlternateSetting | 1, // bAlternateSetting | ||||
1, // bNumEndpoints | |||||
2, // bNumEndpoints | |||||
1, // bInterfaceClass, 1 = AUDIO | 1, // bInterfaceClass, 1 = AUDIO | ||||
2, // bInterfaceSubclass, 2 = AUDIO_STREAMING | 2, // bInterfaceSubclass, 2 = AUDIO_STREAMING | ||||
0, // bInterfaceProtocol | 0, // bInterfaceProtocol | ||||
1, // bSamFreqType = 1 frequency | 1, // bSamFreqType = 1 frequency | ||||
LSB(44100), MSB(44100), 0, // tSamFreq | LSB(44100), MSB(44100), 0, // tSamFreq | ||||
// Standard AS Isochronous Audio Data Endpoint Descriptor | // Standard AS Isochronous Audio Data Endpoint Descriptor | ||||
// SB DCD for Audio Devices 1.0, Section 4.6.1.1, Table 4-20, page 61-62 | |||||
// USB DCD for Audio Devices 1.0, Section 4.6.1.1, Table 4-20, page 61-62 | |||||
9, // bLength | 9, // bLength | ||||
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | ||||
AUDIO_RX_ENDPOINT, // bEndpointAddress | AUDIO_RX_ENDPOINT, // bEndpointAddress | ||||
LSB(AUDIO_RX_SIZE), MSB(AUDIO_RX_SIZE), // wMaxPacketSize | LSB(AUDIO_RX_SIZE), MSB(AUDIO_RX_SIZE), // wMaxPacketSize | ||||
1, // bInterval, 1 = every frame | 1, // bInterval, 1 = every frame | ||||
0, // bRefresh | 0, // bRefresh | ||||
0, // bSynchAddress | |||||
AUDIO_SYNC_ENDPOINT | 0x80, // bSynchAddress | |||||
// Class-Specific AS Isochronous Audio Data Endpoint Descriptor | // Class-Specific AS Isochronous Audio Data Endpoint Descriptor | ||||
// USB DCD for Audio Devices 1.0, Section 4.6.1.2, Table 4-21, page 62-63 | // USB DCD for Audio Devices 1.0, Section 4.6.1.2, Table 4-21, page 62-63 | ||||
7, // bLength | 7, // bLength | ||||
0x01, // bmAttributes = Sampling Frequency | 0x01, // bmAttributes = Sampling Frequency | ||||
1, // bLockDelayUnits, 1 = ms | 1, // bLockDelayUnits, 1 = ms | ||||
0x30, 0x00, // wLockDelay | 0x30, 0x00, // wLockDelay | ||||
// Standard AS Isochronous Audio Synch Endpoint Descriptor | |||||
// USB DCD for Audio Devices 1.0, Section 4.6.2.1, Table 4-22, page 63-64 | |||||
9, // bLength | |||||
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | |||||
AUDIO_SYNC_ENDPOINT | 0x80, // bEndpointAddress | |||||
0x01, // bmAttributes = isochronous | |||||
3, 0, // wMaxPacketSize, 3 bytes | |||||
1, // bInterval, 1 = every frame | |||||
1, // bRefresh, 1=2ms, 2=8ms | |||||
0, // bSynchAddress | |||||
#endif | #endif | ||||
}; | }; | ||||
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','A','u','d','i','o'} | #define PRODUCT_NAME {'T','e','e','n','s','y',' ','A','u','d','i','o'} | ||||
#define PRODUCT_NAME_LEN 12 | #define PRODUCT_NAME_LEN 12 | ||||
#define EP0_SIZE 64 | #define EP0_SIZE 64 | ||||
#define NUM_ENDPOINTS 4 | |||||
#define NUM_ENDPOINTS 5 | |||||
#define NUM_USB_BUFFERS 16 | #define NUM_USB_BUFFERS 16 | ||||
#define NUM_INTERFACE 4 | #define NUM_INTERFACE 4 | ||||
#define SEREMU_INTERFACE 3 // Serial emulation | #define SEREMU_INTERFACE 3 // Serial emulation | ||||
#define AUDIO_TX_SIZE 180 | #define AUDIO_TX_SIZE 180 | ||||
#define AUDIO_RX_ENDPOINT 4 | #define AUDIO_RX_ENDPOINT 4 | ||||
#define AUDIO_RX_SIZE 180 | #define AUDIO_RX_SIZE 180 | ||||
#define AUDIO_SYNC_ENDPOINT 5 | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | ||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | ||||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||||
#endif | #endif | ||||
} | } | ||||
table[index(i, TX, EVEN)].desc = 0; | table[index(i, TX, EVEN)].desc = 0; | ||||
table[index(i, TX, ODD)].desc = 0; | table[index(i, TX, ODD)].desc = 0; | ||||
#ifdef AUDIO_INTERFACE | |||||
if (i == AUDIO_SYNC_ENDPOINT) { | |||||
table[index(i, TX, EVEN)].addr = &usb_audio_sync_feedback; | |||||
table[index(i, TX, EVEN)].desc = (3<<16) | BDT_OWN; | |||||
} | |||||
#endif | |||||
} | } | ||||
break; | break; | ||||
case 0x0880: // GET_CONFIGURATION | case 0x0880: // GET_CONFIGURATION | ||||
usb_audio_receive_callback(b->desc >> 16); | usb_audio_receive_callback(b->desc >> 16); | ||||
b->addr = usb_audio_receive_buffer; | b->addr = usb_audio_receive_buffer; | ||||
b->desc = (AUDIO_RX_SIZE << 16) | BDT_OWN; | b->desc = (AUDIO_RX_SIZE << 16) | BDT_OWN; | ||||
} else if ((endpoint == AUDIO_SYNC_ENDPOINT-1) && (stat & 0x08)) { | |||||
b = (bdt_t *)((uint32_t)b ^ 8); | |||||
b->addr = &usb_audio_sync_feedback; | |||||
b->desc = (3 << 16) | BDT_OWN; | |||||
tx_state[endpoint] ^= 1; | |||||
} else | } else | ||||
#endif | #endif | ||||
if (stat & 0x08) { // transmit | if (stat & 0x08) { // transmit |
#ifdef AUDIO_INTERFACE | #ifdef AUDIO_INTERFACE | ||||
extern uint16_t usb_audio_receive_buffer[]; | extern uint16_t usb_audio_receive_buffer[]; | ||||
extern uint16_t usb_audio_transmit_buffer[]; | extern uint16_t usb_audio_transmit_buffer[]; | ||||
extern uint32_t usb_audio_sync_feedback; | |||||
extern void usb_audio_receive_callback(unsigned int len); | extern void usb_audio_receive_callback(unsigned int len); | ||||
extern unsigned int usb_audio_transmit_callback(void); | extern unsigned int usb_audio_transmit_callback(void); | ||||
#endif | #endif |