| #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 |