Increase ITD queue count.
Revision 3:5006f79eb589, committed 2015-10-18
- Comitter:
- dokunewon
- Date:
- Sun Oct 18 08:16:39 2015 +0000
- Parent:
- 2:4afe26b3d48b
- Commit message:
- Change a little.
Changed in this revision
diff -r 4afe26b3d48b -r 5006f79eb589 USBHost6ChDac.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost6ChDac.cpp Sun Oct 18 08:16:39 2015 +0000 @@ -0,0 +1,469 @@ +/******************************************************************************* +* 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); +} +
diff -r 4afe26b3d48b -r 5006f79eb589 USBHost6ChDac.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost6ChDac.h Sun Oct 18 08:16:39 2015 +0000 @@ -0,0 +1,128 @@ +/******************************************************************************* +* 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. +*******************************************************************************/ + +#ifndef USBHOSTAUDIO_H +#define USBHOSTAUDIO_H + +#include "USBHostConf.h" +#include "USBHost.h" +#include "USBIsochronous.h" + +#define USBDAC_DATA_SIZE (192 * 8) +#define USBDAC_DATA_SIZE_6CH (192 * 8 * 3) //doku + +#define USBDAC_ + +/** + * A class to communicate a USB dac (send:only 48kHz,16bit,2ch , receive:only 48kHz,16bit,1ch) + */ +class USBHostDac : public IUSBEnumerator { +public: + + /** + * Constructor + */ + USBHostDac(); + + /** Destructor + * + */ + virtual ~USBHostDac(); + + /** + * Try to connect a audio device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a audio is connected + * + * @returns true if a audio is connected + */ + bool connected(); + + /** + * Data send : only 48kHz,16bit,2ch. It's sent by the 1536byte unit. + * + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param flush if true, less than 1536 bytes of data is sent + * + * @returns the number of bytes written is returned + */ + uint32_t send(uint8_t* buf, uint32_t len, bool flush = true); + + + /** + * Data receive : only 48kHz,16bit,1ch + * + * @param buf pointer on a buffer which will be read + * @param len length of the transfer + * + * @returns the number of bytes read is returned + */ + uint32_t receive(uint8_t* buf, uint32_t len); + + void FUMute(int unit, int ch, int mute); //doku + void FUVolume(int unit, int ch, int mute); //doku + void USBHostDac::FUSelect(int unit, int sel); //doku + void USBHostDac::setMuteAndVolume(void); //doku + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool 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 + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + typedef struct { + IsochronousEp* m_isoEp; + uint16_t wMaxPacketSize; + uint8_t bEndpointAddress; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t* p_rest_data; + uint32_t rest_data_index; + uint32_t rest_data_size; + } iso_if_t; + + USBHost * host; + USBDeviceConnected * dev; + + bool dev_connected; + bool audio_device_found; + int audio_intf; + int audio_intf_cnt; + + iso_if_t iso_send; + iso_if_t iso_recv; + + void init(); + void onDisconnect(); + bool chkAudioStreaming(); + USB_TYPE setInterface(uint16_t alt, uint16_t index); + void setSamplingRate(uint8_t endpoint_adder, uint32_t sampling_rate); +}; +#endif
diff -r 4afe26b3d48b -r 5006f79eb589 USBHostDac.cpp --- a/USBHostDac.cpp Wed Sep 30 06:08:15 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -/******************************************************************************* -* 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 "USBHostDac.h" - -#define SAMPLING (0x0100) -#define SET_CUR (0x01) -#define FRAME_COUNT (8) -#define PACKET_SIZE (192) -#define QUEUE_NUM (3) - -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 * FRAME_COUNT]; - iso_send.m_isoEp->init(addr, iso_send.bEndpointAddress, PACKET_SIZE, 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); - } - - 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 * 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 * 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 * FRAME_COUNT) - rest_size; - break; - } else { - if (rest_size >= (PACKET_SIZE * FRAME_COUNT)) { - send_size = (PACKET_SIZE * 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; - - /* 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: - /* next interface descriptor */ - loop_end = true; - break; - case ENDPOINT_DESCRIPTOR: - 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 */ - if ((conf_descr[index + 2] == 2) && (conf_descr[index + 3] == 1)) { - 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); - if (wk_sampling == 48000) { - smpling_ok = true; - } - } - } - break; - default: - break; - } - index += len_desc; - } - - if (((wk_bEndpointAddress & 0x80) == 0) && (wk_wMaxPacketSize >= PACKET_SIZE) - && (channels == 2) && (SubframeSize == 2) && (smpling_ok != false)) { - iso_send.wMaxPacketSize = wk_wMaxPacketSize; - iso_send.bEndpointAddress = wk_bEndpointAddress; - iso_send.bInterfaceNumber = wk_bInterfaceNumber; - iso_send.bAlternateSetting = wk_bAlternateSetting; - return true; - } - - if (((wk_bEndpointAddress & 0x80) != 0) && (wk_wMaxPacketSize >= (PACKET_SIZE/2)) - && (channels == 1) && (SubframeSize == 2) && (smpling_ok != false)) { - 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) { - 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]; - - 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); -} -
diff -r 4afe26b3d48b -r 5006f79eb589 USBHostDac.h --- a/USBHostDac.h Wed Sep 30 06:08:15 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/******************************************************************************* -* 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. -*******************************************************************************/ - -#ifndef USBHOSTAUDIO_H -#define USBHOSTAUDIO_H - -#include "USBHostConf.h" -#include "USBHost.h" -#include "USBIsochronous.h" - -#define USBDAC_DATA_SIZE (192 * 8) - -#define USBDAC_ - -/** - * A class to communicate a USB dac (send:only 48kHz,16bit,2ch , receive:only 48kHz,16bit,1ch) - */ -class USBHostDac : public IUSBEnumerator { -public: - - /** - * Constructor - */ - USBHostDac(); - - /** Destructor - * - */ - virtual ~USBHostDac(); - - /** - * Try to connect a audio device - * - * @return true if connection was successful - */ - bool connect(); - - /** - * Check if a audio is connected - * - * @returns true if a audio is connected - */ - bool connected(); - - /** - * Data send : only 48kHz,16bit,2ch. It's sent by the 1536byte unit. - * - * @param buf pointer on a buffer which will be written - * @param len length of the transfer - * @param flush if true, less than 1536 bytes of data is sent - * - * @returns the number of bytes written is returned - */ - uint32_t send(uint8_t* buf, uint32_t len, bool flush = true); - - /** - * Data receive : only 48kHz,16bit,1ch - * - * @param buf pointer on a buffer which will be read - * @param len length of the transfer - * - * @returns the number of bytes read is returned - */ - uint32_t receive(uint8_t* buf, uint32_t len); - -protected: - //From IUSBEnumerator - virtual void setVidPid(uint16_t vid, uint16_t pid); - virtual bool 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 - virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used - -private: - typedef struct { - IsochronousEp* m_isoEp; - uint16_t wMaxPacketSize; - uint8_t bEndpointAddress; - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t* p_rest_data; - uint32_t rest_data_index; - uint32_t rest_data_size; - } iso_if_t; - - USBHost * host; - USBDeviceConnected * dev; - - bool dev_connected; - bool audio_device_found; - int audio_intf; - int audio_intf_cnt; - - iso_if_t iso_send; - iso_if_t iso_recv; - - void init(); - void onDisconnect(); - bool chkAudioStreaming(); - USB_TYPE setInterface(uint16_t alt, uint16_t index); - void setSamplingRate(uint8_t endpoint_adder, uint32_t sampling_rate); -}; -#endif