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.2  2008/04/01 10:15:27  haraldkipp
00041  * VS10xx ioctl() returned -1 on success. Fixed.
00042  *
00043  * Revision 1.1  2008/02/15 16:45:41  haraldkipp
00044  * First release.
00045  *
00046  * Revision 1.1  2007/04/12 08:59:55  haraldkipp
00047  * VS10XX decoder support added.
00048  *
00049  */
00050 
00051 #include <cfg/arch/avr.h>
00052 #include <cfg/audio.h>
00053 
00054 #include <sys/atom.h>
00055 #include <sys/event.h>
00056 #include <sys/timer.h>
00057 #include <sys/heap.h>
00058 
00059 #include <dev/irqreg.h>
00060 #include <dev/vscodec.h>
00061 
00062 #include <sys/bankmem.h>
00063 
00064 #include <stdlib.h>
00065 #include <stddef.h>
00066 #include <string.h>
00067 
00072 
00073 #if !defined(AUDIO_VS1001K) && !defined(AUDIO_VS1011E) && !defined(AUDIO_VS1002D) && !defined(AUDIO_VS1003B) && !defined(AUDIO_VS1033C) && !defined(AUDIO_VS1053C)
00074 #define AUDIO_VS1001K
00075 #endif
00076 
00077 #ifndef VS10XX_FREQ
00078 
00079 #define VS10XX_FREQ             12288000UL
00080 #endif
00081 
00082 #ifndef VS10XX_HWRST_DURATION
00083 
00084 #define VS10XX_HWRST_DURATION   1
00085 #endif
00086 
00087 #ifndef VS10XX_HWRST_RECOVER
00088 
00089 #define VS10XX_HWRST_RECOVER    4
00090 #endif
00091 
00092 #ifndef VS10XX_SWRST_RECOVER
00093 
00094 #define VS10XX_SWRST_RECOVER    2
00095 #endif
00096 
00097 #ifndef VS10XX_SCI_MODE
00098 #define VS10XX_SCI_MODE         0
00099 #endif
00100 
00101 #ifndef VS10XX_SCI_RATE
00102 #define VS10XX_SCI_RATE         (VS10XX_FREQ / 6)
00103 #endif
00104 
00105 #ifndef VS10XX_SDI_MODE
00106 #define VS10XX_SDI_MODE         0
00107 #endif
00108 
00109 #ifndef VS10XX_SDI_RATE
00110 #define VS10XX_SDI_RATE         (VS10XX_FREQ / 6)
00111 #endif
00112 
00113 
00114 /* -------------------------------------------------
00115  * AT91 port specifications.
00116  */
00117 #if defined (MCU_AT91R40008) || defined (MCU_AT91SAM7X256) || defined (MCU_AT91SAM7SE512) || defined (MCU_AT91SAM9260)
00118 
00119 #if defined(ELEKTOR_IR1)
00120 
00121 #define VS_XRESET_BIT           31 /* PB31 */
00122 #define VS10XX_XCS_BIT          PA31_SPI0_NPCS1_A
00123 #define VS10XX_XCS_PIO_ID       PIOA_ID
00124 #define VS10XX_XDCS_BIT         PB30_SPI0_NPCS2_A
00125 #define VS10XX_XDCS_PIO_ID      PIOB_ID
00126 #define VS10XX_DREQ_BIT         PA30_IRQ1_A
00127 #define VS10XX_DREQ_PIO_ID      PIOA_ID
00128 #define VS10XX_SIGNAL           sig_INTERRUPT1
00129 
00130 #endif /* ELEKTOR_IR1 */
00131 
00132 #if defined(VS10XX_XCS_BIT)
00133 
00134 #if !defined(VS10XX_XCS_PIO_ID)
00135 #define VS10XX_XCS_PE_REG        PIO_PER
00136 #define VS10XX_XCS_OE_REG        PIO_OER
00137 #define VS10XX_XCS_COD_REG       PIO_CODR
00138 #define VS10XX_XCS_SOD_REG       PIO_SODR
00139 #elif VS10XX_XCS_PIO_ID == PIOA_ID
00140 #define VS10XX_XCS_PE_REG        PIOA_PER
00141 #define VS10XX_XCS_OE_REG        PIOA_OER
00142 #define VS10XX_XCS_COD_REG       PIOA_CODR
00143 #define VS10XX_XCS_SOD_REG       PIOA_SODR
00144 #elif VS10XX_XCS_PIO_ID == PIOB_ID
00145 #define VS10XX_XCS_PE_REG        PIOB_PER
00146 #define VS10XX_XCS_OE_REG        PIOB_OER
00147 #define VS10XX_XCS_COD_REG       PIOB_CODR
00148 #define VS10XX_XCS_SOD_REG       PIOB_SODR
00149 #elif VS10XX_XCS_PIO_ID == PIOC_ID
00150 #define VS10XX_XCS_PE_REG        PIOC_PER
00151 #define VS10XX_XCS_OE_REG        PIOC_OER
00152 #define VS10XX_XCS_COD_REG       PIOC_CODR
00153 #define VS10XX_XCS_SOD_REG       PIOC_SODR
00154 #endif
00155 #define VS10XX_XCS_ENA() \
00156     outr(VS10XX_XCS_PE_REG, _BV(VS10XX_XCS_BIT)); \
00157     outr(VS10XX_XCS_OE_REG, _BV(VS10XX_XCS_BIT))
00158 #define VS10XX_XCS_CLR()   outr(VS10XX_XCS_COD_REG, _BV(VS10XX_XCS_BIT))
00159 #define VS10XX_XCS_SET()   outr(VS10XX_XCS_SOD_REG, _BV(VS10XX_XCS_BIT))
00160 
00161 #else /* VS10XX_XCS_BIT */
00162 
00163 #define VS10XX_XCS_ENA()
00164 #define VS10XX_XCS_CLR()
00165 #define VS10XX_XCS_SET()
00166 
00167 #endif /* VS10XX_XCS_BIT */
00168 
00169 #if defined(VS10XX_XDCS_BIT)
00170 
00171 #if !defined(VS10XX_XDCS_PIO_ID)
00172 #define VS10XX_XDCS_PE_REG        PIO_PER
00173 #define VS10XX_XDCS_OE_REG        PIO_OER
00174 #define VS10XX_XDCS_COD_REG       PIO_CODR
00175 #define VS10XX_XDCS_SOD_REG       PIO_SODR
00176 #elif VS10XX_XDCS_PIO_ID == PIOA_ID
00177 #define VS10XX_XDCS_PE_REG        PIOA_PER
00178 #define VS10XX_XDCS_OE_REG        PIOA_OER
00179 #define VS10XX_XDCS_COD_REG       PIOA_CODR
00180 #define VS10XX_XDCS_SOD_REG       PIOA_SODR
00181 #elif VS10XX_XDCS_PIO_ID == PIOB_ID
00182 #define VS10XX_XDCS_PE_REG        PIOB_PER
00183 #define VS10XX_XDCS_OE_REG        PIOB_OER
00184 #define VS10XX_XDCS_COD_REG       PIOB_CODR
00185 #define VS10XX_XDCS_SOD_REG       PIOB_SODR
00186 #elif VS10XX_XDCS_PIO_ID == PIOC_ID
00187 #define VS10XX_XDCS_PE_REG        PIOC_PER
00188 #define VS10XX_XDCS_OE_REG        PIOC_OER
00189 #define VS10XX_XDCS_COD_REG       PIOC_CODR
00190 #define VS10XX_XDCS_SOD_REG       PIOC_SODR
00191 #endif
00192 #define VS10XX_XDCS_ENA() \
00193     outr(VS10XX_XDCS_PE_REG, _BV(VS10XX_XDCS_BIT)); \
00194     outr(VS10XX_XDCS_OE_REG, _BV(VS10XX_XDCS_BIT))
00195 #define VS10XX_XDCS_CLR()   outr(VS10XX_XDCS_COD_REG, _BV(VS10XX_XDCS_BIT))
00196 #define VS10XX_XDCS_SET()   outr(VS10XX_XDCS_SOD_REG, _BV(VS10XX_XDCS_BIT))
00197 
00198 #else /* VS10XX_XDCS_BIT */
00199 
00200 #define VS10XX_XDCS_ENA()
00201 #define VS10XX_XDCS_CLR()
00202 #define VS10XX_XDCS_SET()
00203 
00204 #endif /* VS10XX_XDCS_BIT */
00205 
00206 #if defined(VS10XX_DREQ_BIT)
00207 
00208 #if !defined(VS10XX_DREQ_PIO_ID)
00209 #define VS10XX_DREQ_PD_REG       PIO_PDR
00210 #define VS10XX_DREQ_OD_REG       PIO_ODR
00211 #define VS10XX_DREQ_PDS_REG      PIO_PDSR
00212 #elif VS10XX_DREQ_PIO_ID == PIOA_ID
00213 #define VS10XX_DREQ_PD_REG       PIOA_PDR
00214 #define VS10XX_DREQ_OD_REG       PIOA_ODR
00215 #define VS10XX_DREQ_PDS_REG      PIOA_PDSR
00216 #elif VS10XX_DREQ_PIO_ID == PIOB_ID
00217 #define VS10XX_DREQ_PD_REG       PIOB_PDR
00218 #define VS10XX_DREQ_OD_REG       PIOB_ODR
00219 #define VS10XX_DREQ_PDS_REG      PIOB_PDSR
00220 #elif VS10XX_DREQ_PIO_ID == PIOC_ID
00221 #define VS10XX_DREQ_PD_REG       PIOC_PDR
00222 #define VS10XX_DREQ_OD_REG       PIOC_ODR
00223 #define VS10XX_DREQ_PDS_REG      PIOC_PDSR
00224 #endif
00225 
00226 #define VS10XX_DREQ_ENA() \
00227     outr(VS10XX_DREQ_PD_REG, _BV(VS10XX_DREQ_BIT)); \
00228     outr(VS10XX_DREQ_OD_REG, _BV(VS10XX_DREQ_BIT))
00229 #define VS10XX_DREQ_TST()    ((inr(VS10XX_DREQ_PDS_REG) & _BV(VS10XX_DREQ_BIT)) == _BV(VS10XX_DREQ_BIT))
00230 
00231 #else /* VS10XX_DREQ_BIT */
00232 
00233 #define VS10XX_DREQ_ENA()
00234 #define VS10XX_DREQ_TST()   0
00235 
00236 #endif /* VS10XX_DREQ_BIT */
00237 
00238 /* -------------------------------------------------
00239  * End of port specifications.
00240  */
00241 #endif
00242 
00243 
00244 #define VSREQ_PLAY      0x00000001
00245 #define VSREQ_CANCEL    0x00000002
00246 #define VSREQ_BEEP      0x00000004
00247 
00248 typedef struct _VSDCB {
00249     int dcb_pbstat;     
00250     u_long dcb_scmd;    
00251     int dcb_crvol;      
00252     int dcb_srvol;      
00253     int dcb_clvol;      
00254     int dcb_slvol;      
00255     u_long dcb_pbwlo;   
00256     u_long dcb_pbwhi;   
00257 } VSDCB;
00258 
00259 static VSDCB dcb;
00260 static u_int vs_chip;
00261 
00262 /*
00263  * Interlink not ready yet. Provide some basic SPI routines.
00264  */
00265 
00266 static u_char SpiByte(u_char val)
00267 {
00268     /* Transmission is started by writing the transmit data. */
00269     outr(SPI0_TDR, val);
00270     /* Wait for receiver data register full. */
00271     while((inr(SPI0_SR) & SPI_RDRF) == 0);
00272     /* Read data. */
00273     val = (u_char)inr(SPI0_RDR);
00274 
00275     return val;
00276 }
00277 
00278 static void SciSelect(void)
00279 {
00280     outr(SPI0_CSR0, (24 << SPI_SCBR_LSB) | SPI_NCPHA);
00281     outr(SPI0_MR, SPI_MODFDIS | SPI_MSTR);
00282     outr(PIOA_CODR, _BV(VS10XX_XCS_BIT));
00283 }
00284 
00285 static void SciDeselect(void)
00286 {
00287     outr(PIOA_SODR, _BV(VS10XX_XCS_BIT));
00288 }
00289 
00296 static int VsWaitReady(void)
00297 {
00298     int tmo = 16384;
00299 
00300     do {
00301         if (VS10XX_DREQ_TST()) {
00302             return 0;
00303         }
00304     } while (tmo--);
00305 
00306     return -1;
00307 }
00308 
00309 /*
00310  * \brief Write a specified number of bytes to the VS10XX data interface.
00311  *
00312  * This function will check the DREQ line. Decoder interrupts must have 
00313  * been disabled before calling this function.
00314  */
00315 static int VsSdiWrite(CONST u_char * data, size_t len)
00316 {
00317     while (len--) {
00318         if (!VS10XX_DREQ_TST() && VsWaitReady()) {
00319             return -1;
00320         }
00321         SpiByte(*data);
00322         data++;
00323     }
00324     return 0;
00325 }
00326 
00327 /*
00328  * \brief Write a specified number of bytes from program space to the 
00329  *        VS10XX data interface.
00330  *
00331  * This function is similar to VsSdiWrite() except that the data is 
00332  * located in program space.
00333  */
00334 static int VsSdiWrite_P(PGM_P data, size_t len)
00335 {
00336     while (len--) {
00337         if (!VS10XX_DREQ_TST() && VsWaitReady()) {
00338             return -1;
00339         }
00340         SpiByte(PRG_RDB(data));
00341         data++;
00342     }
00343     return 0;
00344 }
00345 
00346 /*
00347  * \brief Write to a decoder register.
00348  *
00349  * Decoder interrupts must have been disabled before calling this function.
00350  */
00351 static void VsRegWrite(ureg_t reg, u_short data)
00352 {
00353     VsWaitReady();
00354     SciSelect();
00355     SpiByte(VS_OPCODE_WRITE);
00356     SpiByte((u_char) reg);
00357     SpiByte((u_char) (data >> 8));
00358     SpiByte((u_char) data);
00359     SciDeselect();
00360 }
00361 
00362 /*
00363  * \brief Read from a register.
00364  *
00365  * Decoder interrupts must have been disabled before calling this function.
00366  * 
00367  * \return Register contents.
00368  */
00369 static u_short VsRegRead(ureg_t reg)
00370 {
00371     u_short data;
00372 
00373     VsWaitReady();
00374     SciSelect();
00375     SpiByte(VS_OPCODE_READ);
00376     SpiByte((u_char) reg);
00377     data = (u_short)SpiByte(0) << 8;
00378     data |= SpiByte(0);
00379     SciDeselect();
00380 
00381     return data;
00382 }
00383 
00394 static int VsBeep(u_char fsin, u_char ms)
00395 {
00396     static prog_char on[] = { 0x53, 0xEF, 0x6E };
00397     static prog_char off[] = { 0x45, 0x78, 0x69, 0x74 };
00398     static prog_char end[] = { 0x00, 0x00, 0x00, 0x00 };
00399 
00400     VsRegWrite(VS_MODE_REG, VS_SM_TESTS | VS_SM_SDINEW);
00401 
00402     fsin = 56 + (fsin & 7) * 9;
00403     VsSdiWrite_P(on, sizeof(on));
00404     VsSdiWrite(&fsin, 1);
00405     VsSdiWrite_P(end, sizeof(end));
00406     NutDelay(ms);
00407     VsSdiWrite_P(off, sizeof(off));
00408     VsSdiWrite_P(end, sizeof(end));
00409 
00410     VsRegWrite(VS_MODE_REG, VS_SM_SDINEW);
00411 
00412     return 0;
00413 }
00414 
00415 static HANDLE vs_ready;
00416 
00417 static void VsInterrupt(void *arg)
00418 {
00419     NutEventPostFromIrq(&vs_ready);
00420 }
00421 
00422 THREAD(FeederThread, arg)
00423 {
00424     char *bp;
00425     size_t avail;
00426     int filled;
00427     u_char crgain;
00428     u_char srgain;
00429     u_char clgain;
00430     u_char slgain;
00431 
00432     NutSleep(500);
00433 
00434     dcb.dcb_slvol = dcb.dcb_clvol = -12;
00435     dcb.dcb_srvol = dcb.dcb_crvol = -12;
00436     srgain = (u_char)(-2 * dcb.dcb_srvol);
00437     crgain = 254;
00438     slgain = (u_char)(-2 * dcb.dcb_slvol);
00439     clgain = 254;
00440     VsRegWrite(VS_VOL_REG, ((u_short)clgain << VS_VOL_LEFT_LSB) | ((u_short)crgain << VS_VOL_RIGHT_LSB));
00441 
00442     /* Register the interrupt routine */
00443     while (NutRegisterIrqHandler(&VS10XX_SIGNAL, VsInterrupt, NULL)) {
00444         NutSleep(1000);
00445     }
00446 
00447     /* Rising edge will generate an interrupt. */
00448     NutIrqSetMode(&VS10XX_SIGNAL, NUT_IRQMODE_RISINGEDGE);
00449 
00450     VS10XX_DREQ_ENA();
00451     NutIrqEnable(&VS10XX_SIGNAL);
00452 
00453     for (;;) {
00454         NutEventWait(&vs_ready, 100);
00455         if (!VS10XX_DREQ_TST()) {
00456             continue;
00457         }
00458         if (dcb.dcb_scmd) {
00459             if (dcb.dcb_scmd & VSREQ_CANCEL) {
00460                 NutSegBufReset();
00461             }
00462             if (dcb.dcb_scmd & VSREQ_BEEP) {
00463                 VsBeep(2, 100);
00464             }
00465             dcb.dcb_scmd &= VSREQ_PLAY;
00466         }
00467         if (NutSegBufUsed() < dcb.dcb_pbwlo) {
00468             dcb.dcb_pbstat = CODEC_STATUS_IDLE;
00469             if (crgain != 254) {
00470                 clgain = crgain = 254;
00471                 VsRegWrite(VS_VOL_REG, ((u_short)clgain << VS_VOL_LEFT_LSB) | ((u_short)crgain << VS_VOL_RIGHT_LSB));
00472             }
00473             while (NutSegBufUsed() <  dcb.dcb_pbwhi) {
00474                 if (dcb.dcb_scmd) {
00475                     if (dcb.dcb_scmd & VSREQ_PLAY) {
00476                         dcb.dcb_pbwhi = dcb.dcb_pbwlo = NutSegBufUsed() / 2;
00477                     }
00478                     break;
00479                 }
00480                 NutSleep(100);
00481             }
00482         }
00483         dcb.dcb_scmd &= ~VSREQ_PLAY;
00484         if (dcb.dcb_scmd) {
00485             continue;
00486         }
00487 
00488         outr(SPI0_CSR0, (12 << SPI_SCBR_LSB) | SPI_NCPHA);
00489         outr(SPI0_MR, SPI_MODFDIS | SPI_MSTR);
00490         if (dcb.dcb_pbstat != CODEC_STATUS_PLAYING) {
00491             outr(PIOB_CODR, _BV(30));
00492             while (!VS10XX_DREQ_TST()) {
00493                 SpiByte(0);
00494             }
00495             outr(PIOB_SODR, _BV(30));
00496         }
00497 
00498         for (;;) {
00499             if (!VS10XX_DREQ_TST()) {
00500                 break;
00501             }
00502             bp = NutSegBufReadRequest(&avail);
00503             if (avail == 0) {
00504                 dcb.dcb_pbstat = CODEC_STATUS_IDLE;
00505                 if (crgain != 254) {
00506                     clgain = crgain = 254;
00507                     VsRegWrite(VS_VOL_REG, ((u_short)clgain << VS_VOL_LEFT_LSB) | ((u_short)crgain << VS_VOL_RIGHT_LSB));
00508                 }
00509                 break;
00510             }
00511             outr(PIOB_CODR, _BV(30));
00512             for (filled = 0; avail--; filled++, bp++) {
00513                 if (!VS10XX_DREQ_TST()) {
00514                     dcb.dcb_pbstat = CODEC_STATUS_PLAYING;
00515                     break;
00516                 }
00517                 SpiByte(*bp);
00518             }
00519             outr(PIOB_SODR, _BV(30));
00520             NutSegBufReadLast(filled);
00521         }
00522         if (dcb.dcb_clvol != dcb.dcb_slvol || dcb.dcb_crvol != dcb.dcb_srvol) {
00523             srgain = (u_char)(-2 * dcb.dcb_srvol);
00524             slgain = (u_char)(-2 * dcb.dcb_slvol);
00525 
00526             dcb.dcb_clvol = dcb.dcb_slvol;
00527             dcb.dcb_crvol = dcb.dcb_srvol;
00528         }
00529         else if (srgain != crgain || slgain != clgain) {
00530             int diff = (int)srgain - (int)crgain;
00531 
00532             if (diff > 4) {
00533                 diff = 4;
00534             }
00535             else if (diff < -4) {
00536                 diff = -4;
00537             }
00538             crgain = (u_char)((int)crgain + diff);
00539 
00540             diff = (int)slgain - (int)clgain;
00541             if (diff > 4) {
00542                 diff = 4;
00543             }
00544             else if (diff < -4) {
00545                 diff = -4;
00546             }
00547             clgain = (u_char)((int)clgain + diff);
00548             VsRegWrite(VS_VOL_REG, ((u_short)clgain << VS_VOL_LEFT_LSB) | ((u_short)crgain << VS_VOL_RIGHT_LSB));
00549         }
00550     }
00551 }
00552 
00553 static int VsPlayerFlush(void)
00554 {
00555     int tmo = 1000; /* TODO: Configurable timeout. */
00556 
00557     /* Stupid polling for now. */
00558     while(dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
00559         NutSleep(1);
00560         if (tmo-- <= 0) {
00561             return -1;
00562         }
00563     }
00564     return 0;
00565 }
00566 
00575 static int VsWrite(NUTFILE * fp, CONST void *data, int len)
00576 {
00577     char *buf;
00578     size_t rbytes;
00579 
00580     /* Flush buffer if data pointer is a NULL pointer. */
00581     if (data == NULL || len == 0) {
00582         return VsPlayerFlush();
00583     }
00584     if (len) {
00585         buf = NutSegBufWriteRequest(&rbytes);
00586         if (len > rbytes) {
00587             len = rbytes;
00588         }
00589         if (len) {
00590             memcpy(buf, data, len);
00591         }
00592         NutSegBufWriteLast(len);
00593     }
00594     return len;
00595 }
00596 
00597 #ifdef __HARVARD_ARCH__
00598 
00620 static int VsWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00621 {
00622     return -1;
00623 }
00624 #endif
00625 
00631 static NUTFILE *VsOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00632 {
00633     NUTFILE *nfp;
00634 
00635     VsRegWrite(VS_MODE_REG, VS_SM_RESET | VS_SM_SDINEW);
00636     NutSleep(2);
00637 
00638     nfp = malloc(sizeof(NUTFILE));
00639     nfp->nf_next = NULL;
00640     nfp->nf_dev = dev;
00641     nfp->nf_fcb = NULL;
00642 
00643     NutSegBufReset();
00644 
00645     return nfp;
00646 }
00647 
00651 static int VsClose(NUTFILE * nfp)
00652 {
00653     int rc = VsPlayerFlush();
00654 
00655     if (nfp) {
00656         free(nfp);
00657     }
00658     return rc;
00659 }
00660 
00661 static int VsPlayBufferInit(u_long size)
00662 {
00663     if (dcb.dcb_pbstat != CODEC_STATUS_IDLE) {
00664         return -1;
00665     }
00666     if (NutSegBufInit((size_t)size) == NULL) {
00667         return -1;
00668     }
00669     dcb.dcb_pbwlo = NutSegBufAvailable() / 3;
00670     dcb.dcb_pbwhi = dcb.dcb_pbwlo * 2;
00671 
00672     return 0;
00673 }
00674 
00694 static int VsIOCtl(NUTDEVICE * dev, int req, void *conf)
00695 {
00696     int rc = 0;
00697     u_long *lvp = (u_long *) conf;
00698     int *ivp = (int *) conf;
00699     int iv = *ivp;
00700 
00701     switch (req) {
00702     case AUDIO_PLAY:
00703         /* Immediately start playing. */
00704         if (dcb.dcb_pbstat != CODEC_STATUS_PLAYING) {
00705             dcb.dcb_scmd |= VSREQ_PLAY;
00706         }
00707         break;
00708     case AUDIO_CANCEL:
00709         /* Immediately stop playing and discard buffer. */
00710         if (dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
00711             dcb.dcb_scmd |= VSREQ_CANCEL;
00712         }
00713         break;
00714     case AUDIO_GET_STATUS:
00715         *ivp = dcb.dcb_pbstat;
00716         break;
00717     case AUDIO_GET_PLAYGAIN:
00718         if (dcb.dcb_crvol >= dcb.dcb_clvol) {
00719             *ivp = dcb.dcb_crvol;
00720         }
00721         else {
00722             *ivp = dcb.dcb_clvol;
00723         }
00724         break;
00725     case AUDIO_SET_PLAYGAIN:
00726         if (iv > AUDIO_DAC_MAX_GAIN) {
00727             iv = AUDIO_DAC_MAX_GAIN;
00728         }
00729         if (iv < AUDIO_DAC_MIN_GAIN) {
00730             iv = AUDIO_DAC_MIN_GAIN;
00731         }
00732         dcb.dcb_slvol = dcb.dcb_srvol = iv;
00733         break;
00734     case AUDIO_GET_PBSIZE:
00735         *lvp = NutSegBufAvailable() + NutSegBufUsed();
00736         break;
00737     case AUDIO_SET_PBSIZE:
00738         rc = VsPlayBufferInit(*lvp);
00739         break;
00740     case AUDIO_GET_PBLEVEL:
00741         *lvp = NutSegBufUsed();
00742         break;
00743     case AUDIO_GET_PBWLOW:
00744         *lvp = dcb.dcb_pbwlo;
00745         break;
00746     case AUDIO_SET_PBWLOW:
00747         dcb.dcb_pbwlo = *lvp;
00748         break;
00749     case AUDIO_GET_PBWHIGH:
00750         *lvp = dcb.dcb_pbwhi;
00751         break;
00752     case AUDIO_SET_PBWHIGH:
00753         dcb.dcb_pbwhi = *lvp;
00754         break;
00755     case AUDIO_BEEP:
00756         dcb.dcb_scmd |= VSREQ_BEEP;
00757         break;
00758 #if 0
00759     case AUDIO_GET_DECINFO:
00760         /* Retrieve decoder information. */
00761         break;
00762     case AUDIO_GET_DECCAPS:
00763         /* Retrieve decoder capabilities. */
00764         break;
00765     case AUDIO_GET_DECFMTS:
00766         /* Retrieve decoder formats. */
00767         break;
00768     case AUDIO_SET_DECFMTS:
00769         /* Enable or disable specific decoder formats. */
00770         break;
00771     case AUDIO_GET_CODINFO:
00772         /* Retrieve encoder information. */
00773         break;
00774     case AUDIO_GET_CODCAPS:
00775         /* Retrieve encoder capabilities. */
00776         break;
00777     case AUDIO_GET_CODFMTS:
00778         /* Retrieve encoder formats. */
00779         break;
00780     case AUDIO_SET_CODFMTS:
00781         /* Enable or disable specific encoder formats. */
00782         break;
00783     case AUDIO_GET_MIDINFO:
00784         /* Retrieve midi information. */
00785         break;
00786     case AUDIO_GET_MIDCAPS:
00787         /* Retrieve midi capabilities. */
00788         break;
00789 #endif
00790     default:
00791         rc = -1;
00792         break;
00793     }
00794     return rc;
00795 }
00796 
00797 /*
00798  * Called via dev_init pointer when the device is registered.
00799  */
00800 static int VsInit(NUTDEVICE * dev)
00801 {
00802     u_short mode;
00803 
00804     /* Release reset line and read the status register. */
00805     outr(PIOB_PER, _BV(VS_XRESET_BIT));
00806     outr(PIOB_SODR, _BV(VS_XRESET_BIT));
00807     outr(PIOB_OER, _BV(VS_XRESET_BIT));
00808     NutSleep(3);
00809 
00810     VsRegRead(VS_MODE_REG); /* Dummy read. TODO: Why? */
00811     mode = VsRegRead(VS_MODE_REG);
00812     if ((mode & VS_SM_SDINEW) == 0) {
00813         VsRegWrite(VS_MODE_REG, VS_SM_RESET | VS_SM_SDINEW);
00814         NutSleep(2);
00815     }
00816     vs_chip = (VsRegRead(VS_STATUS_REG) & VS_SS_VER) >> VS_SS_VER_LSB;
00817 #if VS10XX_FREQ < 20000000UL
00818     VsRegWrite(VS_CLOCKF_REG, (u_short)(VS_CF_DOUBLER | (VS10XX_FREQ / 2000UL)));
00819 #else
00820     VsRegWrite(VS_CLOCKF_REG, (u_short)(VS10XX_FREQ / 2000UL));
00821 #endif
00822     if (vs_chip == 0) {
00823         /* Force frequency change (see datasheet). */
00824         VsRegWrite(VS_INT_FCTLH_REG, 0x8008);
00825     }
00826 
00827     if (VsPlayBufferInit(0)) {
00828         return -1;
00829     }
00830     if (NutThreadCreate("vsdeco", FeederThread, NULL, 1024) == 0) {
00831         return -1;
00832     }
00833     return 0;
00834 }
00835 
00846 NUTDEVICE devVsCodec = {
00847     0,              /* Pointer to next device, dev_next. */
00848     {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0},    /* Unique device name, dev_name. */
00849     IFTYP_CHAR,     /* Type of device, dev_type. */
00850     0,              /* Base address, dev_base (not used). */
00851     0,              /* First interrupt number, dev_irq (not used). */
00852     0,              /* Interface control block, dev_icb (not used). */
00853     &dcb,           /* Driver control block, dev_dcb. */
00854     VsInit,         /* Driver initialization routine, dev_init. */
00855     VsIOCtl,        /* Driver specific control function, dev_ioctl. */
00856     NULL,           /* Read from device, dev_read. */
00857     VsWrite,        /* Write to device, dev_write. */
00858 #ifdef __HARVARD_ARCH__
00859     VsWrite_P,      /* Write data from program space to device, dev_write_P. */
00860 #endif
00861     VsOpen,         /* Open a device or file, dev_open. */
00862     VsClose,        /* Close a device or file, dev_close. */
00863     NULL            /* Request file size, dev_size. */
00864 };
00865 

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