Increase ITD queue count.
USBHost6ChDac.cpp
- Committer:
- dokunewon
- Date:
- 2015-10-18
- Revision:
- 3:5006f79eb589
File content as of revision 3:5006f79eb589:
/******************************************************************************* * DISCLAIMER * This software is supplied by Renesas Electronics Corporation and is only * intended for use with Renesas products. No other uses are authorized. This * software is owned by Renesas Electronics Corporation and is protected under * all applicable laws, including copyright laws. * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * Renesas reserves the right, without notice, to make changes to this software * and to discontinue the availability of this software. By using this software, * you agree to the additional terms and conditions found by accessing the * following link: * http://www.renesas.com/disclaimer * Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved. *******************************************************************************/ #include "USBHost6ChDac.h" #define FUCS_CH0 (0x00) #define FUCS_CH1 (0x01) #define FUCS_CH2 (0x02) #define FUCS_CH3 (0x03) #define FUCS_MUTE (0x0100) #define FUCS_VOLUME (0x0200) #define SAMPLING (0x0100) #define SET_CUR (0x01) #define FRAME_COUNT (8) #define PACKET_SIZE (192) #define PACKET_SIZE_6CH (192 * 3) //doku #define QUEUE_NUM (3) #define QUEUE_NUM (11) //#define DESC_REP printf #define DESC_REP(...) while(0); USBHostDac::USBHostDac() { host = USBHost::getHostInst(); iso_send.m_isoEp = new IsochronousEp; iso_send.p_rest_data = NULL; iso_recv.m_isoEp = new IsochronousEp; iso_recv.p_rest_data = NULL; init(); } USBHostDac::~USBHostDac() { delete iso_send.m_isoEp; delete iso_recv.m_isoEp; } void USBHostDac::init() { dev = NULL; dev_connected = false; audio_device_found = false; audio_intf = -1; audio_intf_cnt = 0; iso_send.bEndpointAddress = 0; iso_send.rest_data_index = 0; iso_send.rest_data_size = 0; if (iso_send.p_rest_data != NULL) { delete iso_send.p_rest_data; iso_send.p_rest_data = NULL; } iso_recv.bEndpointAddress = 0; iso_recv.rest_data_index = 0; iso_recv.rest_data_size = 0; if (iso_recv.p_rest_data != NULL) { delete iso_recv.p_rest_data; iso_recv.p_rest_data = NULL; } } bool USBHostDac::connected() { return dev_connected; } bool USBHostDac::connect() { if (dev_connected) { return true; } for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { if ((dev = host->getDevice(i)) != NULL) { if (host->enumerate(dev, this)) { break; } if (audio_device_found) { USB_INFO("New UsbDac device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, audio_intf); dev->setName("UsbDac", audio_intf); host->registerDriver(dev, audio_intf, this, &USBHostDac::onDisconnect); int addr = dev->getAddress(); if (iso_send.bEndpointAddress != 0) { iso_send.p_rest_data = new uint8_t[PACKET_SIZE_6CH * FRAME_COUNT]; iso_send.m_isoEp->init(addr, iso_send.bEndpointAddress, PACKET_SIZE_6CH, FRAME_COUNT, QUEUE_NUM); setInterface(iso_send.bAlternateSetting, iso_send.bInterfaceNumber); setSamplingRate(iso_send.bEndpointAddress, 48000); } if (iso_recv.bEndpointAddress != 0) { iso_recv.p_rest_data = new uint8_t[iso_recv.wMaxPacketSize * FRAME_COUNT]; iso_recv.m_isoEp->init(addr, iso_recv.bEndpointAddress, iso_recv.wMaxPacketSize, FRAME_COUNT, QUEUE_NUM); setInterface(iso_recv.bAlternateSetting, iso_recv.bInterfaceNumber); setSamplingRate(iso_recv.bEndpointAddress, 48000); } setMuteAndVolume(); dev_connected = true; return true; } } } init(); return false; } uint32_t USBHostDac::send(uint8_t* buf, uint32_t len, bool flush) { uint32_t send_index = 0; uint32_t rest_size = len; uint32_t send_size; uint32_t copy_size; int result; if (iso_send.bEndpointAddress == 0) { return 0; } if (iso_send.rest_data_index != 0) { if (rest_size > iso_send.rest_data_size) { copy_size = iso_send.rest_data_size; } else { copy_size = rest_size; } memcpy(&iso_send.p_rest_data[iso_send.rest_data_index], &buf[send_index], copy_size); send_index += copy_size; rest_size -= copy_size; iso_send.rest_data_index += copy_size; if ((flush != false) || (iso_send.rest_data_index >= (PACKET_SIZE_6CH * FRAME_COUNT))) { if (iso_send.m_isoEp->getQueueNum() == 0) { iso_send.m_isoEp->reset(4); } result = iso_send.m_isoEp->isochronousSend(&iso_send.p_rest_data[0], iso_send.rest_data_index, 100); iso_send.rest_data_index = 0; } } while ((dev_connected) && (rest_size > 0)) { if ((flush == false) && (rest_size < (PACKET_SIZE_6CH * FRAME_COUNT))) { memcpy(&iso_send.p_rest_data[0], &buf[send_index], rest_size); iso_send.rest_data_index = rest_size; iso_send.rest_data_size = (PACKET_SIZE_6CH * FRAME_COUNT) - rest_size; break; } else { if (rest_size >= (PACKET_SIZE_6CH * FRAME_COUNT)) { send_size = (PACKET_SIZE_6CH * FRAME_COUNT); } else { send_size = rest_size; } if (iso_send.m_isoEp->getQueueNum() == 0) { iso_send.m_isoEp->reset(4); } result = iso_send.m_isoEp->isochronousSend(&buf[send_index], send_size, 100); send_index += result; rest_size -= result; } } return send_index; } uint32_t USBHostDac::receive(uint8_t* buf, uint32_t len) { uint32_t recv_index = 0; uint32_t rest_size = len; uint32_t copy_size; if (iso_recv.bEndpointAddress == 0) { return 0; } if (iso_recv.rest_data_size != 0) { if (rest_size > iso_recv.rest_data_size) { copy_size = iso_recv.rest_data_size; } else { copy_size = rest_size; } memcpy(&buf[recv_index], &iso_recv.p_rest_data[iso_recv.rest_data_index], copy_size); recv_index += copy_size; rest_size -= copy_size; iso_recv.rest_data_index += copy_size; iso_recv.rest_data_size -= copy_size; } while ((dev_connected) && (rest_size > 0)) { iso_recv.rest_data_index = 0; iso_recv.rest_data_size = 0; if (iso_recv.m_isoEp->getQueueNum() == 0) { iso_recv.m_isoEp->reset(4); } HCITD* itd = iso_recv.m_isoEp->isochronousReceive(100); if (itd) { uint8_t cc = itd->ConditionCode(); if (cc == 0) { int fc = itd->FrameCount(); uint8_t* wk_buf = const_cast<uint8_t*>(itd->buf); int mps = iso_recv.m_isoEp->m_PacketSize; for (int i = 0; i < fc; i++) { uint16_t psw = itd->OffsetPSW[i]; cc = psw>>12; if (cc == 0 || cc == 9) { int wk_len = psw & 0x7ff; if (rest_size > 0) { if (rest_size > wk_len) { copy_size = wk_len; } else { copy_size = rest_size; } memcpy(&buf[recv_index], wk_buf, copy_size); recv_index += copy_size; rest_size -= copy_size; if (copy_size < wk_len) { memcpy(&iso_recv.p_rest_data[iso_recv.rest_data_size], &wk_buf[copy_size], (wk_len - copy_size)); iso_recv.rest_data_size += (wk_len - copy_size); } } else { memcpy(&iso_recv.p_rest_data[iso_recv.rest_data_size], &wk_buf[0], wk_len); iso_recv.rest_data_size += wk_len; } } wk_buf += mps; } } delete itd; } } return recv_index; } /*virtual*/ void USBHostDac::setVidPid(uint16_t vid, uint16_t pid) { // we don't check VID/PID for audio driver } /*virtual*/ bool USBHostDac::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed { bool ret; if (audio_intf_cnt >= 2) { ret = false; } else if ((intf_class == AUDIO_CLASS) && (intf_subclass == 2) && (intf_protocol == 0)) { // AUDIOSTREAMING Subclass ret = chkAudioStreaming(); if (ret != false) { audio_intf = intf_nb; audio_device_found = true; audio_intf_cnt++; } } else { ret = false; } return false; } /*virtual*/ bool USBHostDac::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used { return false; } bool USBHostDac::chkAudioStreaming() { uint8_t * conf_descr = host->getConfDescrCurPtr(); uint16_t len = host->getConfDescrRestLen(); uint32_t index = 0; uint32_t len_desc = conf_descr[index]; uint32_t cnt; uint32_t wk_sampling; bool smpling_ok = false; bool loop_end = false; uint8_t channels = 0; uint8_t SubframeSize = 0; uint8_t id; uint16_t wk_wMaxPacketSize; uint8_t wk_bEndpointAddress; uint8_t wk_bInterfaceNumber; uint8_t wk_bAlternateSetting; DESC_REP("audio streaming interface:%d alt:%d found\n",conf_descr[index + 2],conf_descr[index + 3]); /* bNumEndpoints */ if (conf_descr[index + 4] >= 1) { wk_bInterfaceNumber = conf_descr[index + 2]; wk_bAlternateSetting = conf_descr[index + 3]; wk_wMaxPacketSize = 0; wk_bEndpointAddress = 0; index += len_desc; while ((index < len) && (loop_end == false)) { len_desc = conf_descr[index]; id = conf_descr[index+1]; switch (id) { case INTERFACE_DESCRIPTOR: DESC_REP("interface descriptor found\n"); /* next interface descriptor */ loop_end = true; break; case ENDPOINT_DESCRIPTOR: DESC_REP("endpoint descriptor found\n"); if ((conf_descr[index + 3] & 0x03) == ISOCHRONOUS_ENDPOINT) { wk_bEndpointAddress = conf_descr[index + 2]; wk_wMaxPacketSize = (conf_descr[index + 5] << 8) + conf_descr[index + 4]; loop_end = true; } break; case 0x24: /* Audio Class Specific INTERFACE Descriptor */ DESC_REP("audio specific descriptor found\n"); //doku if ((conf_descr[index + 2] == 2) && (conf_descr[index + 3] == 1)) { if ((conf_descr[index + 2] == 2) && (conf_descr[index + 3] == 1 && (wk_bAlternateSetting != 5))) { channels = conf_descr[index + 4]; SubframeSize = conf_descr[index + 5]; for (cnt = 8; (cnt + 3) <= len_desc; cnt += 3) { wk_sampling = ((uint32_t)conf_descr[index + cnt + 0] << 0) | ((uint32_t)conf_descr[index + cnt + 1] << 8) | ((uint32_t)conf_descr[index + cnt + 2] << 16); DESC_REP("interface:%d alt:%d found channels:%d subframe size:%d sampling:%d\n",wk_bInterfaceNumber,wk_bAlternateSetting,channels,SubframeSize,wk_sampling); if (wk_sampling == 48000) { smpling_ok = true; } } } break; default: break; } index += len_desc; } DESC_REP("interface:%d alt:%d endpoint:%02x found\n",wk_bInterfaceNumber,wk_bAlternateSetting,wk_bEndpointAddress); if (((wk_bEndpointAddress & 0x80) == 0) && (wk_wMaxPacketSize >= PACKET_SIZE_6CH) && (channels == 6) && (SubframeSize == 2) && (smpling_ok != false)) { DESC_REP("****** fit for send ******\n"); iso_send.wMaxPacketSize = wk_wMaxPacketSize; iso_send.bEndpointAddress = wk_bEndpointAddress; iso_send.bInterfaceNumber = wk_bInterfaceNumber; iso_send.bAlternateSetting = wk_bAlternateSetting; return true; } DESC_REP("end point:%d packet size:%d channels:%d subflame:%d ampling ok:%d\n",wk_bEndpointAddress,wk_wMaxPacketSize,channels,SubframeSize,smpling_ok); //doku if (((wk_bEndpointAddress & 0x80) != 0) && (wk_wMaxPacketSize >= (PACKET_SIZE/2)) if (((wk_bEndpointAddress & 0x80) != 0) && (wk_wMaxPacketSize >= (PACKET_SIZE)) && (channels == 2) && (SubframeSize == 2) && (smpling_ok != false)) { DESC_REP("****** fit for receive ******\n"); iso_recv.wMaxPacketSize = wk_wMaxPacketSize; iso_recv.bEndpointAddress = wk_bEndpointAddress; iso_recv.bInterfaceNumber = wk_bInterfaceNumber; iso_recv.bAlternateSetting = wk_bAlternateSetting; return true; } } return false; } void USBHostDac::onDisconnect() { if (dev_connected) { if (iso_send.bEndpointAddress != 0) { iso_send.m_isoEp->disconnect(); } if (iso_recv.bEndpointAddress != 0) { iso_recv.m_isoEp->disconnect(); } init(); } } USB_TYPE USBHostDac::setInterface(uint16_t alt, uint16_t index) { DESC_REP("set interface:%d alt:%d\n",index,alt); return host->controlWrite( dev, USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, SET_INTERFACE, alt, index, NULL, 0); } void USBHostDac::setSamplingRate(uint8_t endpoint_adder, uint32_t sampling_rate) { uint8_t data[3]; DESC_REP("set sampling rate endpoint:%02x rate:%d\n",endpoint_adder,sampling_rate); data[0] = (uint8_t)((sampling_rate >> 0) & 0xff); data[1] = (uint8_t)((sampling_rate >> 8) & 0xff); data[2] = (uint8_t)((sampling_rate >> 16) & 0xff); host->controlWrite( dev, USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, SET_CUR, SAMPLING, endpoint_adder, data, 3); } void USBHostDac::FUMute(int unit, int ch, int mute) { // DESC_REP("mute:%d\n",mute); uint8_t data[1]; unit <<= 8; data[0] = 0xff & mute; host->controlWrite( dev, USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, SET_CUR, FUCS_MUTE | ch, unit, data, 1); } void USBHostDac::FUVolume(int unit, int ch,int volume) { // DESC_REP("volume:%d\n",volume); uint8_t data[2]; unit <<= 8; data[0] = volume & 0xFF; data[1] = (volume>>8) & 0xFF; host->controlWrite( dev, USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, SET_CUR, FUCS_VOLUME | ch, unit, data, 2); } void USBHostDac::FUSelect(int unit, int sel) { // DESC_REP("volume:%d\n",volume); uint8_t data[1]; unit <<= 8; data[0] = sel & 0xFF; host->controlWrite( dev, USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, SET_CUR, 0 , unit, data, 1); } void USBHostDac::setMuteAndVolume(void) { //off playback mute // FUMute(13, 0, 0); //front volume // FUVolume(13, 1, -256 * 0); // FUVolume(13, 2, -256 * 0); //recoding volume // FUMute(15, 0, 0); // FUVolume(15, 1, -256 * 0); //recoding selector FUSelect(7, 2); }