vscodec.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 by egnite GmbH. All rights reserved.
00003  * Copyright (C) 2001-2007 by egnite Software GmbH. All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00022  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00025  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00026  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00028  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00029  * SUCH DAMAGE.
00030  *
00031  * For additional information see http://www.ethernut.de/
00032  * -
00033  *
00034  * This software has been inspired by all the valuable work done by
00035  * Jesper Hansen and Pavel Chromy. Many thanks for all their help.
00036  */
00037 
00038 /*
00039  * $Log: vscodec.c,v $
00040  * Revision 1.5  2008/10/23 08:54:07  haraldkipp
00041  * Include the correct header file.
00042  *
00043  * Revision 1.4  2008/09/18 09:51:58  haraldkipp
00044  * Use the correct PORT macros.
00045  *
00046  * Revision 1.3  2008/08/11 06:59:42  haraldkipp
00047  * BSD types replaced by stdint types (feature request #1282721).
00048  *
00049  * Revision 1.2  2008/04/01 10:15:27  haraldkipp
00050  * VS10xx ioctl() returned -1 on success. Fixed.
00051  *
00052  * Revision 1.1  2008/02/15 16:45:41  haraldkipp
00053  * First release.
00054  *
00055  * Revision 1.1  2007/04/12 08:59:55  haraldkipp
00056  * VS10XX decoder support added.
00057  *
00058  */
00059 
00060 #include <sys/atom.h>
00061 #include <sys/event.h>
00062 #include <sys/timer.h>
00063 #include <sys/heap.h>
00064 
00065 #include <cfg/arch/gpio.h>
00066 #include <cfg/audio.h>
00067 #include <dev/irqreg.h>
00068 #include <dev/vscodec.h>
00069 
00070 #include <sys/bankmem.h>
00071 
00072 #include <stdlib.h>
00073 #include <stddef.h>
00074 #include <string.h>
00075 
00080 
00081 #if !defined(AUDIO_VS1001K) && !defined(AUDIO_VS1011E) && !defined(AUDIO_VS1002D) && !defined(AUDIO_VS1003B) && !defined(AUDIO_VS1033C) && !defined(AUDIO_VS1053C)
00082 #define AUDIO_VS1001K
00083 #endif
00084 
00085 #ifndef VS10XX_FREQ
00086 
00087 #define VS10XX_FREQ             12288000UL
00088 #endif
00089 
00090 #ifndef VS10XX_HWRST_DURATION
00091 
00092 #define VS10XX_HWRST_DURATION   1
00093 #endif
00094 
00095 #ifndef VS10XX_HWRST_RECOVER
00096 
00097 #define VS10XX_HWRST_RECOVER    4
00098 #endif
00099 
00100 #ifndef VS10XX_SWRST_RECOVER
00101 
00102 #define VS10XX_SWRST_RECOVER    2
00103 #endif
00104 
00105 #ifndef VS10XX_SCI_MODE
00106 #define VS10XX_SCI_MODE         0
00107 #endif
00108 
00109 #ifndef VS10XX_SCI_RATE
00110 #define VS10XX_SCI_RATE         (VS10XX_FREQ / 6)
00111 #endif
00112 
00113 #ifndef VS10XX_SDI_MODE
00114 #define VS10XX_SDI_MODE         0
00115 #endif
00116 
00117 #ifndef VS10XX_SDI_RATE
00118 #define VS10XX_SDI_RATE         (VS10XX_FREQ / 6)
00119 #endif
00120 
00121 
00122 /* -------------------------------------------------
00123  * AT91 port specifications.
00124  */
00125 #if defined (MCU_AT91R40008) || defined (MCU_AT91SAM7X256) || defined (MCU_AT91SAM7SE512) || defined (MCU_AT91SAM9260)
00126 
00127 #if defined(ELEKTOR_IR1)
00128 
00129 #define VS_XRESET_BIT           31 /* PB31 */
00130 #define VS10XX_XCS_BIT          PA31_SPI0_NPCS1_A
00131 #define VS10XX_XCS_PORT       PIOA_ID
00132 #define VS10XX_XDCS_BIT         PB30_SPI0_NPCS2_A
00133 #define VS10XX_XDCS_PORT      PIOB_ID
00134 #define VS10XX_DREQ_BIT         PA30_IRQ1_A
00135 #define VS10XX_DREQ_PIO_ID      PIOA_ID
00136 #define VS10XX_SIGNAL           sig_INTERRUPT1
00137 
00138 #endif /* ELEKTOR_IR1 */
00139 
00140 #if defined(VS10XX_XCS_BIT)
00141 
00142 #if !defined(VS10XX_XCS_PORT)
00143 #define VS10XX_XCS_PE_REG        PIO_PER
00144 #define VS10XX_XCS_OE_REG        PIO_OER
00145 #define VS10XX_XCS_COD_REG       PIO_CODR
00146 #define VS10XX_XCS_SOD_REG       PIO_SODR
00147 #elif VS10XX_XCS_PORT == PIOA_ID
00148 #define VS10XX_XCS_PE_REG        PIOA_PER
00149 #define VS10XX_XCS_OE_REG        PIOA_OER
00150 #define VS10XX_XCS_COD_REG       PIOA_CODR
00151 #define VS10XX_XCS_SOD_REG       PIOA_SODR
00152 #elif VS10XX_XCS_PORT == PIOB_ID
00153 #define VS10XX_XCS_PE_REG        PIOB_PER
00154 #define VS10XX_XCS_OE_REG        PIOB_OER
00155 #define VS10XX_XCS_COD_REG       PIOB_CODR
00156 #define VS10XX_XCS_SOD_REG       PIOB_SODR
00157 #elif VS10XX_XCS_PORT == PIOC_ID
00158 #define VS10XX_XCS_PE_REG        PIOC_PER
00159 #define VS10XX_XCS_OE_REG        PIOC_OER
00160 #define VS10XX_XCS_COD_REG       PIOC_CODR
00161 #define VS10XX_XCS_SOD_REG       PIOC_SODR
00162 #endif
00163 #define VS10XX_XCS_ENA() \
00164     outr(VS10XX_XCS_PE_REG, _BV(VS10XX_XCS_BIT)); \
00165     outr(VS10XX_XCS_OE_REG, _BV(VS10XX_XCS_BIT))
00166 #define VS10XX_XCS_CLR()   outr(VS10XX_XCS_COD_REG, _BV(VS10XX_XCS_BIT))
00167 #define VS10XX_XCS_SET()   outr(VS10XX_XCS_SOD_REG, _BV(VS10XX_XCS_BIT))
00168 
00169 #else /* VS10XX_XCS_BIT */
00170 
00171 #define VS10XX_XCS_ENA()
00172 #define VS10XX_XCS_CLR()
00173 #define VS10XX_XCS_SET()
00174 
00175 #endif /* VS10XX_XCS_BIT */
00176 
00177 #if defined(VS10XX_XDCS_BIT)
00178 
00179 #if !defined(VS10XX_XDCS_PORT)
00180 #define VS10XX_XDCS_PE_REG        PIO_PER
00181 #define VS10XX_XDCS_OE_REG        PIO_OER
00182 #define VS10XX_XDCS_COD_REG       PIO_CODR
00183 #define VS10XX_XDCS_SOD_REG       PIO_SODR
00184 #elif VS10XX_XDCS_PORT == PIOA_ID
00185 #define VS10XX_XDCS_PE_REG        PIOA_PER
00186 #define VS10XX_XDCS_OE_REG        PIOA_OER
00187 #define VS10XX_XDCS_COD_REG       PIOA_CODR
00188 #define VS10XX_XDCS_SOD_REG       PIOA_SODR
00189 #elif VS10XX_XDCS_PORT == PIOB_ID
00190 #define VS10XX_XDCS_PE_REG        PIOB_PER
00191 #define VS10XX_XDCS_OE_REG        PIOB_OER
00192 #define VS10XX_XDCS_COD_REG       PIOB_CODR
00193 #define VS10XX_XDCS_SOD_REG       PIOB_SODR
00194 #elif VS10XX_XDCS_PORT == PIOC_ID
00195 #define VS10XX_XDCS_PE_REG        PIOC_PER
00196 #define VS10XX_XDCS_OE_REG        PIOC_OER
00197 #define VS10XX_XDCS_COD_REG       PIOC_CODR
00198 #define VS10XX_XDCS_SOD_REG       PIOC_SODR
00199 #endif
00200 #define VS10XX_XDCS_ENA() \
00201     outr(VS10XX_XDCS_PE_REG, _BV(VS10XX_XDCS_BIT)); \
00202     outr(VS10XX_XDCS_OE_REG, _BV(VS10XX_XDCS_BIT))
00203 #define VS10XX_XDCS_CLR()   outr(VS10XX_XDCS_COD_REG, _BV(VS10XX_XDCS_BIT))
00204 #define VS10XX_XDCS_SET()   outr(VS10XX_XDCS_SOD_REG, _BV(VS10XX_XDCS_BIT))
00205 
00206 #else /* VS10XX_XDCS_BIT */
00207 
00208 #define VS10XX_XDCS_ENA()
00209 #define VS10XX_XDCS_CLR()
00210 #define VS10XX_XDCS_SET()
00211 
00212 #endif /* VS10XX_XDCS_BIT */
00213 
00214 #if defined(VS10XX_DREQ_BIT)
00215 
00216 #if !defined(VS10XX_DREQ_PIO_ID)
00217 #define VS10XX_DREQ_PD_REG       PIO_PDR
00218 #define VS10XX_DREQ_OD_REG       PIO_ODR
00219 #define VS10XX_DREQ_PDS_REG      PIO_PDSR
00220 #elif VS10XX_DREQ_PIO_ID == PIOA_ID
00221 #define VS10XX_DREQ_PD_REG       PIOA_PDR
00222 #define VS10XX_DREQ_OD_REG       PIOA_ODR
00223 #define VS10XX_DREQ_PDS_REG      PIOA_PDSR
00224 #elif VS10XX_DREQ_PIO_ID == PIOB_ID
00225 #define VS10XX_DREQ_PD_REG       PIOB_PDR
00226 #define VS10XX_DREQ_OD_REG       PIOB_ODR
00227 #define VS10XX_DREQ_PDS_REG      PIOB_PDSR
00228 #elif VS10XX_DREQ_PIO_ID == PIOC_ID
00229 #define VS10XX_DREQ_PD_REG       PIOC_PDR
00230 #define VS10XX_DREQ_OD_REG       PIOC_ODR
00231 #define VS10XX_DREQ_PDS_REG      PIOC_PDSR
00232 #endif
00233 
00234 #define VS10XX_DREQ_ENA() \
00235     outr(VS10XX_DREQ_PD_REG, _BV(VS10XX_DREQ_BIT)); \
00236     outr(VS10XX_DREQ_OD_REG, _BV(VS10XX_DREQ_BIT))
00237 #define VS10XX_DREQ_TST()    ((inr(VS10XX_DREQ_PDS_REG) & _BV(VS10XX_DREQ_BIT)) == _BV(VS10XX_DREQ_BIT))
00238 
00239 #else /* VS10XX_DREQ_BIT */
00240 
00241 #define VS10XX_DREQ_ENA()
00242 #define VS10XX_DREQ_TST()   0
00243 
00244 #endif /* VS10XX_DREQ_BIT */
00245 
00246 /* -------------------------------------------------
00247  * End of port specifications.
00248  */
00249 #endif
00250 
00251 
00252 #define VSREQ_PLAY      0x00000001
00253 #define VSREQ_CANCEL    0x00000002
00254 #define VSREQ_BEEP      0x00000004
00255 
00256 typedef struct _VSDCB {
00257     int dcb_pbstat;     
00258     uint32_t dcb_scmd;    
00259     int dcb_crvol;      
00260     int dcb_srvol;      
00261     int dcb_clvol;      
00262     int dcb_slvol;      
00263     uint32_t dcb_pbwlo;   
00264     uint32_t dcb_pbwhi;   
00265 } VSDCB;
00266 
00267 static VSDCB dcb;
00268 static u_int vs_chip;
00269 
00270 /*
00271  * Interlink not ready yet. Provide some basic SPI routines.
00272  */
00273 
00274 static uint8_t SpiByte(uint8_t val)
00275 {
00276     /* Transmission is started by writing the transmit data. */
00277     outr(SPI0_TDR, val);
00278     /* Wait for receiver data register full. */
00279     while((inr(SPI0_SR) & SPI_RDRF) == 0);
00280     /* Read data. */
00281     val = (uint8_t)inr(SPI0_RDR);
00282 
00283     return val;
00284 }
00285 
00286 static void SciSelect(void)
00287 {
00288     outr(SPI0_CSR0, (24 << SPI_SCBR_LSB) | SPI_NCPHA);
00289     outr(SPI0_MR, SPI_MODFDIS | SPI_MSTR);
00290     outr(PIOA_CODR, _BV(VS10XX_XCS_BIT));
00291 }
00292 
00293 static void SciDeselect(void)
00294 {
00295     outr(PIOA_SODR, _BV(VS10XX_XCS_BIT));
00296 }
00297 
00304 static int VsWaitReady(void)
00305 {
00306     int tmo = 16384;
00307 
00308     do {
00309         if (VS10XX_DREQ_TST()) {
00310             return 0;
00311         }
00312     } while (tmo--);
00313 
00314     return -1;
00315 }
00316 
00317 /*
00318  * \brief Write a specified number of bytes to the VS10XX data interface.
00319  *
00320  * This function will check the DREQ line. Decoder interrupts must have 
00321  * been disabled before calling this function.
00322  */
00323 static int VsSdiWrite(CONST uint8_t * data, size_t len)
00324 {
00325     while (len--) {
00326         if (!VS10XX_DREQ_TST() && VsWaitReady()) {
00327             return -1;
00328         }
00329         SpiByte(*data);
00330         data++;
00331     }
00332     return 0;
00333 }
00334 
00335 /*
00336  * \brief Write a specified number of bytes from program space to the 
00337  *        VS10XX data interface.
00338  *
00339  * This function is similar to VsSdiWrite() except that the data is 
00340  * located in program space.
00341  */
00342 static int VsSdiWrite_P(PGM_P data, size_t len)
00343 {
00344     while (len--) {
00345         if (!VS10XX_DREQ_TST() && VsWaitReady()) {
00346             return -1;
00347         }
00348         SpiByte(PRG_RDB(data));
00349         data++;
00350     }
00351     return 0;
00352 }
00353 
00354 /*
00355  * \brief Write to a decoder register.
00356  *
00357  * Decoder interrupts must have been disabled before calling this function.
00358  */
00359 static void VsRegWrite(ureg_t reg, uint16_t data)
00360 {
00361     VsWaitReady();
00362     SciSelect();
00363     SpiByte(VS_OPCODE_WRITE);
00364     SpiByte((uint8_t) reg);
00365     SpiByte((uint8_t) (data >> 8));
00366     SpiByte((uint8_t) data);
00367     SciDeselect();
00368 }
00369 
00370 /*
00371  * \brief Read from a register.
00372  *
00373  * Decoder interrupts must have been disabled before calling this function.
00374  * 
00375  * \return Register contents.
00376  */
00377 static uint16_t VsRegRead(ureg_t reg)
00378 {
00379     uint16_t data;
00380 
00381     VsWaitReady();
00382     SciSelect();
00383     SpiByte(VS_OPCODE_READ);
00384     SpiByte((uint8_t) reg);
00385     data = (uint16_t)SpiByte(0) << 8;
00386     data |= SpiByte(0);
00387     SciDeselect();
00388 
00389     return data;
00390 }
00391 
00402 static int VsBeep(uint8_t fsin, uint8_t ms)
00403 {
00404     static prog_char on[] = { 0x53, 0xEF, 0x6E };
00405     static prog_char off[] = { 0x45, 0x78, 0x69, 0x74 };
00406     static prog_char end[] = { 0x00, 0x00, 0x00, 0x00 };
00407 
00408     VsRegWrite(VS_MODE_REG, VS_SM_TESTS | VS_SM_SDINEW);
00409 
00410     fsin = 56 + (fsin & 7) * 9;
00411     VsSdiWrite_P(on, sizeof(on));
00412     VsSdiWrite(&fsin, 1);
00413     VsSdiWrite_P(end, sizeof(end));
00414     NutDelay(ms);
00415     VsSdiWrite_P(off, sizeof(off));
00416     VsSdiWrite_P(end, sizeof(end));
00417 
00418     VsRegWrite(VS_MODE_REG, VS_SM_SDINEW);
00419 
00420     return 0;
00421 }
00422 
00423 static HANDLE vs_ready;
00424 
00425 static void VsInterrupt(void *arg)
00426 {
00427     NutEventPostFromIrq(&vs_ready);
00428 }
00429 
00430 THREAD(FeederThread, arg)
00431 {
00432     char *bp;
00433     size_t avail;
00434     int filled;
00435     uint8_t crgain;
00436     uint8_t srgain;
00437     uint8_t clgain;
00438     uint8_t slgain;
00439 
00440     NutSleep(500);
00441 
00442     dcb.dcb_slvol = dcb.dcb_clvol = -12;
00443     dcb.dcb_srvol = dcb.dcb_crvol = -12;
00444     srgain = (uint8_t)(-2 * dcb.dcb_srvol);
00445     crgain = 254;
00446     slgain = (uint8_t)(-2 * dcb.dcb_slvol);
00447     clgain = 254;
00448     VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
00449 
00450     /* Register the interrupt routine */
00451     while (NutRegisterIrqHandler(&VS10XX_SIGNAL, VsInterrupt, NULL)) {
00452         NutSleep(1000);
00453     }
00454 
00455     /* Rising edge will generate an interrupt. */
00456     NutIrqSetMode(&VS10XX_SIGNAL, NUT_IRQMODE_RISINGEDGE);
00457 
00458     VS10XX_DREQ_ENA();
00459     NutIrqEnable(&VS10XX_SIGNAL);
00460 
00461     for (;;) {
00462         NutEventWait(&vs_ready, 100);
00463         if (!VS10XX_DREQ_TST()) {
00464             continue;
00465         }
00466         if (dcb.dcb_scmd) {
00467             if (dcb.dcb_scmd & VSREQ_CANCEL) {
00468                 NutSegBufReset();
00469             }
00470             if (dcb.dcb_scmd & VSREQ_BEEP) {
00471                 VsBeep(2, 100);
00472             }
00473             dcb.dcb_scmd &= VSREQ_PLAY;
00474         }
00475         if (NutSegBufUsed() < dcb.dcb_pbwlo) {
00476             dcb.dcb_pbstat = CODEC_STATUS_IDLE;
00477             if (crgain != 254) {
00478                 clgain = crgain = 254;
00479                 VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
00480             }
00481             while (NutSegBufUsed() <  dcb.dcb_pbwhi) {
00482                 if (dcb.dcb_scmd) {
00483                     if (dcb.dcb_scmd & VSREQ_PLAY) {
00484                         dcb.dcb_pbwhi = dcb.dcb_pbwlo = NutSegBufUsed() / 2;
00485                     }
00486                     break;
00487                 }
00488                 NutSleep(100);
00489             }
00490         }
00491         dcb.dcb_scmd &= ~VSREQ_PLAY;
00492         if (dcb.dcb_scmd) {
00493             continue;
00494         }
00495 
00496         outr(SPI0_CSR0, (12 << SPI_SCBR_LSB) | SPI_NCPHA);
00497         outr(SPI0_MR, SPI_MODFDIS | SPI_MSTR);
00498         if (dcb.dcb_pbstat != CODEC_STATUS_PLAYING) {
00499             outr(PIOB_CODR, _BV(30));
00500             while (!VS10XX_DREQ_TST()) {
00501                 SpiByte(0);
00502             }
00503             outr(PIOB_SODR, _BV(30));
00504         }
00505 
00506         for (;;) {
00507             if (!VS10XX_DREQ_TST()) {
00508                 break;
00509             }
00510             bp = NutSegBufReadRequest(&avail);
00511             if (avail == 0) {
00512                 dcb.dcb_pbstat = CODEC_STATUS_IDLE;
00513                 if (crgain != 254) {
00514                     clgain = crgain = 254;
00515                     VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
00516                 }
00517                 break;
00518             }
00519             outr(PIOB_CODR, _BV(30));
00520             for (filled = 0; avail--; filled++, bp++) {
00521                 if (!VS10XX_DREQ_TST()) {
00522                     dcb.dcb_pbstat = CODEC_STATUS_PLAYING;
00523                     break;
00524                 }
00525                 SpiByte(*bp);
00526             }
00527             outr(PIOB_SODR, _BV(30));
00528             NutSegBufReadLast(filled);
00529         }
00530         if (dcb.dcb_clvol != dcb.dcb_slvol || dcb.dcb_crvol != dcb.dcb_srvol) {
00531             srgain = (uint8_t)(-2 * dcb.dcb_srvol);
00532             slgain = (uint8_t)(-2 * dcb.dcb_slvol);
00533 
00534             dcb.dcb_clvol = dcb.dcb_slvol;
00535             dcb.dcb_crvol = dcb.dcb_srvol;
00536         }
00537         else if (srgain != crgain || slgain != clgain) {
00538             int diff = (int)srgain - (int)crgain;
00539 
00540             if (diff > 4) {
00541                 diff = 4;
00542             }
00543             else if (diff < -4) {
00544                 diff = -4;
00545             }
00546             crgain = (uint8_t)((int)crgain + diff);
00547 
00548             diff = (int)slgain - (int)clgain;
00549             if (diff > 4) {
00550                 diff = 4;
00551             }
00552             else if (diff < -4) {
00553                 diff = -4;
00554             }
00555             clgain = (uint8_t)((int)clgain + diff);
00556             VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
00557         }
00558     }
00559 }
00560 
00561 static int VsPlayerFlush(void)
00562 {
00563     int tmo = 1000; /* TODO: Configurable timeout. */
00564 
00565     /* Stupid polling for now. */
00566     while(dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
00567         NutSleep(1);
00568         if (tmo-- <= 0) {
00569             return -1;
00570         }
00571     }
00572     return 0;
00573 }
00574 
00583 static int VsWrite(NUTFILE * fp, CONST void *data, int len)
00584 {
00585     char *buf;
00586     size_t rbytes;
00587 
00588     /* Flush buffer if data pointer is a NULL pointer. */
00589     if (data == NULL || len == 0) {
00590         return VsPlayerFlush();
00591     }
00592     if (len) {
00593         buf = NutSegBufWriteRequest(&rbytes);
00594         if (len > rbytes) {
00595             len = rbytes;
00596         }
00597         if (len) {
00598             memcpy(buf, data, len);
00599         }
00600         NutSegBufWriteLast(len);
00601     }
00602     return len;
00603 }
00604 
00605 #ifdef __HARVARD_ARCH__
00606 
00628 static int VsWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00629 {
00630     return -1;
00631 }
00632 #endif
00633 
00639 static NUTFILE *VsOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00640 {
00641     NUTFILE *nfp;
00642 
00643     VsRegWrite(VS_MODE_REG, VS_SM_RESET | VS_SM_SDINEW);
00644     NutSleep(2);
00645 
00646     nfp = malloc(sizeof(NUTFILE));
00647     nfp->nf_next = NULL;
00648     nfp->nf_dev = dev;
00649     nfp->nf_fcb = NULL;
00650 
00651     NutSegBufReset();
00652 
00653     return nfp;
00654 }
00655 
00659 static int VsClose(NUTFILE * nfp)
00660 {
00661     int rc = VsPlayerFlush();
00662 
00663     if (nfp) {
00664         free(nfp);
00665     }
00666     return rc;
00667 }
00668 
00669 static int VsPlayBufferInit(uint32_t size)
00670 {
00671     if (dcb.dcb_pbstat != CODEC_STATUS_IDLE) {
00672         return -1;
00673     }
00674     if (NutSegBufInit((size_t)size) == NULL) {
00675         return -1;
00676     }
00677     dcb.dcb_pbwlo = NutSegBufAvailable() / 3;
00678     dcb.dcb_pbwhi = dcb.dcb_pbwlo * 2;
00679 
00680     return 0;
00681 }
00682 
00702 static int VsIOCtl(NUTDEVICE * dev, int req, void *conf)
00703 {
00704     int rc = 0;
00705     uint32_t *lvp = (uint32_t *) conf;
00706     int *ivp = (int *) conf;
00707     int iv = *ivp;
00708 
00709     switch (req) {
00710     case AUDIO_PLAY:
00711         /* Immediately start playing. */
00712         if (dcb.dcb_pbstat != CODEC_STATUS_PLAYING) {
00713             dcb.dcb_scmd |= VSREQ_PLAY;
00714         }
00715         break;
00716     case AUDIO_CANCEL:
00717         /* Immediately stop playing and discard buffer. */
00718         if (dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
00719             dcb.dcb_scmd |= VSREQ_CANCEL;
00720         }
00721         break;
00722     case AUDIO_GET_STATUS:
00723         *ivp = dcb.dcb_pbstat;
00724         break;
00725     case AUDIO_GET_PLAYGAIN:
00726         if (dcb.dcb_crvol >= dcb.dcb_clvol) {
00727             *ivp = dcb.dcb_crvol;
00728         }
00729         else {
00730             *ivp = dcb.dcb_clvol;
00731         }
00732         break;
00733     case AUDIO_SET_PLAYGAIN:
00734         if (iv > AUDIO_DAC_MAX_GAIN) {
00735             iv = AUDIO_DAC_MAX_GAIN;
00736         }
00737         if (iv < AUDIO_DAC_MIN_GAIN) {
00738             iv = AUDIO_DAC_MIN_GAIN;
00739         }
00740         dcb.dcb_slvol = dcb.dcb_srvol = iv;
00741         break;
00742     case AUDIO_GET_PBSIZE:
00743         *lvp = NutSegBufAvailable() + NutSegBufUsed();
00744         break;
00745     case AUDIO_SET_PBSIZE:
00746         rc = VsPlayBufferInit(*lvp);
00747         break;
00748     case AUDIO_GET_PBLEVEL:
00749         *lvp = NutSegBufUsed();
00750         break;
00751     case AUDIO_GET_PBWLOW:
00752         *lvp = dcb.dcb_pbwlo;
00753         break;
00754     case AUDIO_SET_PBWLOW:
00755         dcb.dcb_pbwlo = *lvp;
00756         break;
00757     case AUDIO_GET_PBWHIGH:
00758         *lvp = dcb.dcb_pbwhi;
00759         break;
00760     case AUDIO_SET_PBWHIGH:
00761         dcb.dcb_pbwhi = *lvp;
00762         break;
00763     case AUDIO_BEEP:
00764         dcb.dcb_scmd |= VSREQ_BEEP;
00765         break;
00766 #if 0
00767     case AUDIO_GET_DECINFO:
00768         /* Retrieve decoder information. */
00769         break;
00770     case AUDIO_GET_DECCAPS:
00771         /* Retrieve decoder capabilities. */
00772         break;
00773     case AUDIO_GET_DECFMTS:
00774         /* Retrieve decoder formats. */
00775         break;
00776     case AUDIO_SET_DECFMTS:
00777         /* Enable or disable specific decoder formats. */
00778         break;
00779     case AUDIO_GET_CODINFO:
00780         /* Retrieve encoder information. */
00781         break;
00782     case AUDIO_GET_CODCAPS:
00783         /* Retrieve encoder capabilities. */
00784         break;
00785     case AUDIO_GET_CODFMTS:
00786         /* Retrieve encoder formats. */
00787         break;
00788     case AUDIO_SET_CODFMTS:
00789         /* Enable or disable specific encoder formats. */
00790         break;
00791     case AUDIO_GET_MIDINFO:
00792         /* Retrieve midi information. */
00793         break;
00794     case AUDIO_GET_MIDCAPS:
00795         /* Retrieve midi capabilities. */
00796         break;
00797 #endif
00798     default:
00799         rc = -1;
00800         break;
00801     }
00802     return rc;
00803 }
00804 
00805 /*
00806  * Called via dev_init pointer when the device is registered.
00807  */
00808 static int VsInit(NUTDEVICE * dev)
00809 {
00810     uint16_t mode;
00811 
00812     /* Release reset line and read the status register. */
00813     outr(PIOB_PER, _BV(VS_XRESET_BIT));
00814     outr(PIOB_SODR, _BV(VS_XRESET_BIT));
00815     outr(PIOB_OER, _BV(VS_XRESET_BIT));
00816     NutSleep(3);
00817 
00818     VsRegRead(VS_MODE_REG); /* Dummy read. TODO: Why? */
00819     mode = VsRegRead(VS_MODE_REG);
00820     if ((mode & VS_SM_SDINEW) == 0) {
00821         VsRegWrite(VS_MODE_REG, VS_SM_RESET | VS_SM_SDINEW);
00822         NutSleep(2);
00823     }
00824     vs_chip = (VsRegRead(VS_STATUS_REG) & VS_SS_VER) >> VS_SS_VER_LSB;
00825 #if VS10XX_FREQ < 20000000UL
00826     VsRegWrite(VS_CLOCKF_REG, (uint16_t)(VS_CF_DOUBLER | (VS10XX_FREQ / 2000UL)));
00827 #else
00828     VsRegWrite(VS_CLOCKF_REG, (uint16_t)(VS10XX_FREQ / 2000UL));
00829 #endif
00830     if (vs_chip == 0) {
00831         /* Force frequency change (see datasheet). */
00832         VsRegWrite(VS_INT_FCTLH_REG, 0x8008);
00833     }
00834 
00835     if (VsPlayBufferInit(0)) {
00836         return -1;
00837     }
00838     if (NutThreadCreate("vsdeco", FeederThread, NULL, 1024) == 0) {
00839         return -1;
00840     }
00841     return 0;
00842 }
00843 
00854 NUTDEVICE devVsCodec = {
00855     0,              /* Pointer to next device, dev_next. */
00856     {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0},    /* Unique device name, dev_name. */
00857     IFTYP_CHAR,     /* Type of device, dev_type. */
00858     0,              /* Base address, dev_base (not used). */
00859     0,              /* First interrupt number, dev_irq (not used). */
00860     0,              /* Interface control block, dev_icb (not used). */
00861     &dcb,           /* Driver control block, dev_dcb. */
00862     VsInit,         /* Driver initialization routine, dev_init. */
00863     VsIOCtl,        /* Driver specific control function, dev_ioctl. */
00864     NULL,           /* Read from device, dev_read. */
00865     VsWrite,        /* Write to device, dev_write. */
00866 #ifdef __HARVARD_ARCH__
00867     VsWrite_P,      /* Write data from program space to device, dev_write_P. */
00868 #endif
00869     VsOpen,         /* Open a device or file, dev_open. */
00870     VsClose,        /* Close a device or file, dev_close. */
00871     NULL            /* Request file size, dev_size. */
00872 };
00873 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/