spi_vscodec.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2009 by egnite GmbH
00003  * Copyright (C) 2001-2007 by egnite Software GmbH
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  */
00035 
00036 /*
00037  * $Id: spi_vscodec.c 2657 2009-09-01 17:49:04Z haraldkipp $
00038  */
00039 
00040 #include <dev/vscodec.h>
00041 
00042 #include <sys/event.h>
00043 #include <sys/timer.h>
00044 #include <sys/nutdebug.h>
00045 #include <sys/bankmem.h>
00046 
00047 #include <stdlib.h>
00048 #include <string.h>
00049 #include <memdebug.h>
00050 
00055 
00059 #define VSREQ_PLAY      0x00000001
00060 
00061 #define VSREQ_CANCEL    0x00000002
00062 
00063 #define VSREQ_VOLUPD    0x00000004
00064 
00065 #define VSREQ_AUDIOE    0x00000008
00066 
00067 #define VSREQ_BEEP      0x00000010
00068 
00071 /* Used to send zeros to the decoder. */
00072 uint8_t zero_chunk[VSCODEC_DATA_CHUNK_SIZE];
00073 
00082 int VsCodecWaitReady(NUTDEVICE *dev, uint32_t tmo)
00083 {
00084     VSDCB *dcb = (VSDCB *) dev->dev_dcb;
00085 
00086     while (!(* dcb->dcb_isready)()) {
00087         if (NutEventWait(&dcb->dcb_feedme, tmo)) {
00088             return -1;
00089         }
00090     }
00091     return 0;
00092 }
00093 
00094 /*
00095  * \brief Read from or write to a VLSI audio codec register.
00096  *
00097  * \param dev  Specifies the codec device.
00098  * \param op   Operation, either \ref VS_OPCODE_READ or
00099  *             \ref VS_OPCODE_WRITE.
00100  * \param reg  The register index.
00101  * \param val  This value will be stored in the register on a write
00102  *             operation. It is ignored on read operations.
00103  *
00104  * \return Register contents. On write operations, the contents before
00105  *         the modification is returned.
00106  */
00107 uint16_t VsCodecReg(NUTDEVICE *dev, uint_fast8_t op, uint_fast8_t reg, uint_fast16_t val)
00108 {
00109     uint8_t cmd[4];
00110     VSDCB *dcb = (VSDCB *) dev->dev_dcb;
00111 
00112     /* Assemble command buffer. */
00113     cmd[0] = (uint8_t) op;
00114     cmd[1] = (uint8_t) reg;
00115     cmd[2] = (uint8_t) (val >> 8);
00116     cmd[3] = (uint8_t) val;
00117 
00118     VsCodecWaitReady(dev, VSCODEC_CMD_TIMEOUT);
00119     (*dcb->dcb_sendcmd)(cmd, 4);
00120     val = cmd[2];
00121     val <<= 8;
00122     val |= cmd[3];
00123     return (uint16_t) val;
00124 }
00125 
00138 uint16_t VsCodecMode(NUTDEVICE *dev, uint_fast16_t flags, uint_fast16_t mask)
00139 {
00140     uint16_t rc;
00141 
00142     /* Read the mode register. */
00143     rc = VsCodecReg(dev, VS_OPCODE_READ, VS_MODE_REG, 0);
00144     if (mask | flags) {
00145         VsCodecReg(dev, VS_OPCODE_WRITE, VS_MODE_REG, (rc & ~mask) | flags);
00146         /* Add delay after software reset, if configured. */
00147 #if defined(VSCODEC_SWRST_RECOVER)
00148         if (flags & VS_SM_RESET) {
00149             NutSleep(VSCODEC_SWRST_RECOVER);
00150         }
00151 #endif
00152     }
00153     return rc;
00154 }
00155 
00165 int VsDecoderSetVolume(NUTDEVICE *dev, int left, int right)
00166 {
00167     VSDCB *dcb = (VSDCB *)dev->dev_dcb;
00168     uint16_t l;
00169     uint16_t r;
00170 
00171     //printf("vol set %d %d\n", left, right);
00172     /* Honor limits. */
00173     left = left > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : left;
00174     left = left < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : left;
00175     right = right > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : right;
00176     right = right < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : right;
00177 
00178     /* Convert to register values. */
00179     l = (uint16_t)(-2 * left);
00180     r = (uint16_t)(-2 * right);
00181 
00182     VsCodecReg(dev, VS_OPCODE_WRITE, VS_VOL_REG, (l << VS_VOL_LEFT_LSB) | (r << VS_VOL_RIGHT_LSB));
00183     dcb->dcb_lvol = left;
00184     dcb->dcb_rvol = right;
00185 
00186     return 0;
00187 }
00188 
00200 int VsDecoderSetBass(NUTDEVICE *dev, int treb, int tfin, int bass, int bfin)
00201 {
00202 #ifdef VS_HAS_BASS_REG
00203     VSDCB *dcb = (VSDCB *)dev->dev_dcb;
00204 //    uint16_t t;
00205 //    uint16_t b;
00206 
00207     //printf("bass: t:%ddB tf:%dHz b:%ddB bf:%dHz\n", treb, tfin*1000, bass, bfin);
00208     /* Honor limits. */
00209     treb = treb > AUDIO_DAC_MAX_TREB ? AUDIO_DAC_MAX_TREB : treb;
00210     treb = treb < 0 ? 0 : treb;
00211     tfin = tfin > AUDIO_DAC_MAX_TFIN ? AUDIO_DAC_MAX_TFIN : tfin;
00212     tfin = tfin < 0 ? 0 : tfin;
00213     bass = bass > AUDIO_DAC_MAX_BASS ? AUDIO_DAC_MAX_BASS : bass;
00214     bass = bass < 0 ? 0 : bass;
00215     bfin = bfin > AUDIO_DAC_MAX_BFIN ? AUDIO_DAC_MAX_BFIN : bfin;
00216     bfin = bfin < 0 ? 0 : bfin;
00217 
00218     /* Convert to register values. */
00219     /*
00220     l = (uint16_t)(-2 * left);
00221     r = (uint16_t)(-2 * right);
00222     */
00223 
00224     VsCodecReg(dev, VS_OPCODE_WRITE, VS_BASS_REG,
00225         (treb << VS_ST_AMPLITUDE_LSB) | (tfin << VS_ST_FREQLIMIT_LSB) |
00226         (treb << VS_SB_AMPLITUDE_LSB) | (tfin << VS_SB_FREQLIMIT_LSB)
00227     );
00228 
00229     dcb->dcb_treb = treb;
00230     dcb->dcb_tfin = tfin;
00231     dcb->dcb_bass = bass;
00232     dcb->dcb_bfin = bfin;
00233 #endif
00234 
00235     return 0;
00236 }
00237 
00249 uint16_t VsCodecBeep(NUTDEVICE *dev, uint16_t fsin)
00250 {
00251     uint16_t rc = 0;
00252     static uint8_t on[] = { 0x53, 0xEF, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00 };
00253     static CONST uint8_t off[] = { 0x45, 0x78, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00 };
00254     static CONST uint16_t ftab[] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000 };
00255     static uint16_t mode;
00256     VSDCB *dcb = (VSDCB *)dev->dev_dcb;
00257 
00258     if (fsin) {
00259         uint_fast16_t s;
00260         uint32_t f;
00261         uint_fast16_t d;
00262         int_fast8_t i = sizeof(ftab) / sizeof(ftab[0]);
00263         int_fast8_t ie = 0;
00264         int_fast16_t dmin = fsin;
00265         uint32_t fs = (long)fsin * 128;
00266 
00267         while (--i >= ie) {
00268             /* Calculate skip speed. */
00269             f = ftab[i];
00270             s = (fs + f / 2) / f;
00271             /* Check that skip is within 5-bit range. */
00272             if (s && s < 32) {
00273                 /* Calculate the absolute deviation. */
00274                 f *= s;
00275                 f += 64;
00276                 f >>= 7;
00277                 d = (uint_fast16_t)(fsin > f ? fsin - f : f - fsin);
00278                 /* Check if this is a new minimum. */
00279                 if (d < dmin) {
00280                     dmin = d;
00281                     rc = (uint16_t) f;
00282                     /* Set new skip speed and frequency index. */
00283                     on[3] = (i << 5) | s;
00284                     /* We can stop earlier with this fit. */
00285                     if (i > 1) {
00286                         ie = i - 2;
00287                     }
00288                 }
00289             }
00290         }
00291         mode = VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET);
00292 #ifdef VS_SM_TESTS
00293         VsCodecMode(dev, mode | VS_SM_TESTS, 0xffff);
00294 #endif
00295         (*dcb->dcb_senddata)(on, sizeof(on));
00296     } else {
00297         (*dcb->dcb_senddata)(off, sizeof(off));
00298 #ifdef VS_SM_TESTS
00299         VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET | VS_SM_TESTS);
00300 #else
00301         VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET);
00302 #endif
00303         VsCodecMode(dev, mode, 0xffff);
00304     }
00305     return rc;
00306 }
00307 
00308 /*
00309  * Initialize the stream output buffer with a given size.
00310  *
00311  * \param dev Specifies the audio codec device.
00312  */
00313 int VsDecoderBufferInit(NUTDEVICE *dev, uint32_t size)
00314 {
00315     VSDCB *dcb = (VSDCB *)dev->dev_dcb;
00316 
00317     /* Make sure that the decoder is idle. */
00318     if (dcb->dcb_pbstat != CODEC_STATUS_IDLE) {
00319         return -1;
00320     }
00321     /* Set new buffer size. */
00322     if (NutSegBufInit((size_t)size) == NULL) {
00323         return -1;
00324     }
00325     /* Set watermark defaults. */
00326     dcb->dcb_pbwlo = NutSegBufAvailable() / 3;
00327     dcb->dcb_pbwhi = dcb->dcb_pbwlo * 2;
00328 
00329     return 0;
00330 }
00331 
00332 /*
00333  * VLSI decoder feeding thread.
00334  */
00335 THREAD(FeederThread, arg)
00336 {
00337     uint8_t *bp;
00338     size_t avail;
00339     int filled;
00340     uint_fast8_t intest = 0;
00341     uint_fast16_t idlefill = 0;
00342     NUTDEVICE *dev = (NUTDEVICE *)arg;
00343     VSDCB *dcb = (VSDCB *)dev->dev_dcb;
00344 
00345     /* We are a high priority thread. */
00346     NutThreadSetPriority(7);
00347     for (;;) {
00348         /*
00349         ** Idle mode processing.
00350         */
00351         if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00352             /* Loop while in test mode. */
00353             do {
00354                 /* Wait for a request or a buffer update. */
00355                 NutEventWait(&dcb->dcb_feedme, NUT_WAIT_INFINITE);
00356                 /* Process beep commands. */
00357                 if (dcb->dcb_scmd & VSREQ_BEEP) {
00358                     if ((*dcb->dcb_isready)()) {
00359                         dcb->dcb_scmd &= ~VSREQ_BEEP;
00360                         intest = VsCodecBeep(dev, dcb->dcb_sinefreq) != 0;
00361                     }
00362                 }
00363             } while (intest);
00364             /* Check if we should change to play mode. This will happen
00365             ** if we receive a play request or if the buffer contents
00366             ** reaches the high watermark. */
00367             if ((dcb->dcb_scmd & VSREQ_PLAY) != 0 || NutSegBufUsed() >=  dcb->dcb_pbwhi) {
00368                 dcb->dcb_scmd &= ~(VSREQ_PLAY | VSREQ_CANCEL);
00369                 dcb->dcb_pbstat = CODEC_STATUS_PLAYING;
00370                 VsDecoderSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
00371             }
00372         }
00373 
00374         /*
00375         ** Play mode processing.
00376         */
00377         if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
00378             /* Wait while decoder is busy. */
00379             VsCodecWaitReady(dev, NUT_WAIT_INFINITE);
00380             /* Process cancel requests. */
00381             if (dcb->dcb_scmd & VSREQ_CANCEL) {
00382                 dcb->dcb_scmd &= ~VSREQ_CANCEL;
00383                 NutSegBufReset();
00384 #if VS_HAS_SM_CANCEL
00385                 VsCodecMode(dev, VS_SM_CANCEL, VS_SM_CANCEL);
00386 #endif
00387             }
00388             /* Retrieve new data from the input buffer. */
00389             bp = (uint8_t *) NutSegBufReadRequest(&avail);
00390             if (avail) {
00391                 /* More data available, send as much as possible to the
00392                 ** decoder. If no data was sent, then the bus may be
00393                 ** blocked by another device. */
00394                 filled = (*dcb->dcb_senddata)(bp, avail);
00395                 if (filled) {
00396                     /* Update the buffer's read position. */
00397                     NutSegBufReadLast(filled);
00398                     NutEventPost(&dcb->dcb_bufque);
00399                     idlefill = 2048;
00400                 }
00401                 if (dcb->dcb_scmd & VSREQ_VOLUPD) {
00402                     VsDecoderSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
00403                     dcb->dcb_scmd &= ~VSREQ_VOLUPD;
00404                 }
00405                 if (dcb->dcb_scmd & VSREQ_AUDIOE) {
00406                     VsDecoderSetBass( dev, dcb->dcb_treb, dcb->dcb_tfin, dcb->dcb_bass, dcb->dcb_bfin);
00407                     dcb->dcb_scmd &= ~VSREQ_AUDIOE;
00408                 }
00409             } else if (NutSegBufUsed() == 0) {
00410                 /* Running out of data. */
00411                 if (idlefill) {
00412                     /* For some reason the HDAT0/HDAT1 registers in the
00413                     ** VS1053 do not contain zero when the codec runs
00414                     ** empty. I expected this when reading the datasheet.
00415                     ** Instead we fill the buffer with zeros, to make
00416                     ** sure that the whole buffer is decoded before we
00417                     ** enter idle mode. */
00418                     idlefill -= (*dcb->dcb_senddata)(NULL, idlefill);
00419                 }
00420                 if (idlefill == 0) {
00421                     /* Finally we reached idle mode. */
00422                     dcb->dcb_pbstat = CODEC_STATUS_IDLE;
00423                     NutEventPost(&dcb->dcb_bufque);
00424                 }
00425             }
00426         }
00427     }
00428 }
00429 
00451 int VsCodecIOCtl(NUTDEVICE * dev, int req, void *conf)
00452 {
00453     int rc = 0;
00454     uint32_t *lvp = (uint32_t *) conf;
00455     int *ivp = (int *) conf;
00456     VSDCB *dcb = (VSDCB *)dev->dev_dcb;
00457 
00458     switch (req) {
00459     case AUDIO_PLAY:
00460         if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00461             /* Immediately start playing. */
00462             dcb->dcb_scmd |= VSREQ_PLAY;
00463         }
00464         NutEventPost(&dcb->dcb_feedme);
00465         break;
00466     case AUDIO_CANCEL:
00467         if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
00468             /* Immediately stop playing and discard buffer. */
00469             dcb->dcb_scmd |= VSREQ_CANCEL;
00470         }
00471         NutEventPost(&dcb->dcb_feedme);
00472         break;
00473     case AUDIO_GET_STATUS:
00474         *ivp = dcb->dcb_pbstat;
00475         break;
00476     case AUDIO_GET_PLAYGAIN:
00477         *ivp = dcb->dcb_rvol > dcb->dcb_lvol ? dcb->dcb_rvol : dcb->dcb_lvol;
00478         break;
00479     case AUDIO_SET_PLAYGAIN:
00480         dcb->dcb_lvol = *ivp;
00481         dcb->dcb_rvol = *ivp;
00482         dcb->dcb_scmd |= VSREQ_VOLUPD;
00483         break;
00484     case AUDIO_SET_TREB:
00485         dcb->dcb_treb = *ivp;
00486         dcb->dcb_scmd |= VSREQ_AUDIOE;
00487         break;
00488     case AUDIO_SET_TFIN:
00489         dcb->dcb_tfin = *ivp;
00490         dcb->dcb_scmd |= VSREQ_AUDIOE;
00491         break;
00492     case AUDIO_SET_BASS:
00493         dcb->dcb_bass = *ivp;
00494         dcb->dcb_scmd |= VSREQ_AUDIOE;
00495         break;
00496     case AUDIO_SET_BFIN:
00497         dcb->dcb_bfin = *ivp;
00498         dcb->dcb_scmd |= VSREQ_AUDIOE;
00499         break;
00500     case AUDIO_GET_PBSIZE:
00501         *lvp = NutSegBufAvailable() + NutSegBufUsed();
00502         break;
00503     case AUDIO_SET_PBSIZE:
00504         rc = VsDecoderBufferInit(dev, *lvp);
00505         break;
00506     case AUDIO_GET_PBLEVEL:
00507         *lvp = NutSegBufUsed();
00508         break;
00509     case AUDIO_GET_PBWLOW:
00510         *lvp = dcb->dcb_pbwlo;
00511         break;
00512     case AUDIO_SET_PBWLOW:
00513         dcb->dcb_pbwlo = *lvp;
00514         break;
00515     case AUDIO_GET_PBWHIGH:
00516         *lvp = dcb->dcb_pbwhi;
00517         break;
00518     case AUDIO_SET_PBWHIGH:
00519         dcb->dcb_pbwhi = *lvp;
00520         break;
00521     case AUDIO_SETWRITETIMEOUT:
00522         dcb->dcb_wtmo = *lvp;
00523         break;
00524     case AUDIO_GETWRITETIMEOUT:
00525         *lvp = dcb->dcb_wtmo;
00526         break;
00527     case AUDIO_BEEP:
00528         if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00529             dcb->dcb_sinefreq = *((uint16_t *) conf);
00530             dcb->dcb_scmd |= VSREQ_BEEP;
00531             NutEventPost(&dcb->dcb_feedme);
00532         } else {
00533             rc = -1;
00534         }
00535         break;
00536 #if 0
00537     case AUDIO_GET_DECINFO:
00538         /* Retrieve decoder information. */
00539         break;
00540     case AUDIO_GET_DECCAPS:
00541         /* Retrieve decoder capabilities. */
00542         break;
00543     case AUDIO_GET_DECFMTS:
00544         /* Retrieve decoder formats. */
00545         break;
00546     case AUDIO_SET_DECFMTS:
00547         /* Enable or disable specific decoder formats. */
00548         break;
00549     case AUDIO_GET_CODINFO:
00550         /* Retrieve encoder information. */
00551         break;
00552     case AUDIO_GET_CODCAPS:
00553         /* Retrieve encoder capabilities. */
00554         break;
00555     case AUDIO_GET_CODFMTS:
00556         /* Retrieve encoder formats. */
00557         break;
00558     case AUDIO_SET_CODFMTS:
00559         /* Enable or disable specific encoder formats. */
00560         break;
00561     case AUDIO_GET_MIDINFO:
00562         /* Retrieve midi information. */
00563         break;
00564     case AUDIO_GET_MIDCAPS:
00565         /* Retrieve midi capabilities. */
00566         break;
00567 #endif
00568     default:
00569         rc = -1;
00570         break;
00571     }
00572     return rc;
00573 }
00574 
00587 static int VsDecoderBufferFlush(NUTDEVICE *dev, uint32_t tmo)
00588 {
00589     int rc = 0;
00590     VSDCB *dcb = dev->dev_dcb;
00591 
00592     for (;;) {
00593         /* Keep the player running if the buffer contains data. */
00594         if (NutSegBufUsed()) {
00595             VsCodecIOCtl(dev, AUDIO_PLAY, NULL);
00596         }
00597         /* No data in buffer. If idle, then we are done. */
00598         else if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00599             /* No data and player is idle. */
00600             break;
00601         }
00602         /* Wait for a new buffer update. */
00603         rc = NutEventWait(&dcb->dcb_bufque, tmo);
00604         if (rc) {
00605             break;
00606         }
00607     }
00608     return rc;
00609 }
00610 
00624 int VsCodecWrite(NUTFILE * nfp, CONST void *data, int len)
00625 {
00626     int rc = 0;
00627     uint8_t *bp;
00628     CONST uint8_t *dp;
00629     size_t rbytes;
00630     VSDCB *dcb = nfp->nf_dev->dev_dcb;
00631 
00632     /* Flush buffer if data pointer is a NULL pointer. */
00633     if (data == NULL || len == 0) {
00634         return VsDecoderBufferFlush(nfp->nf_dev, dcb->dcb_wtmo);
00635     }
00636     dp = data;
00637     while (len) {
00638         bp = (uint8_t *)NutSegBufWriteRequest(&rbytes);
00639         if (rbytes == 0) {
00640             /* No buffer space, wait for change. */
00641             if (NutEventWait(&dcb->dcb_bufque, dcb->dcb_wtmo)) {
00642                 /* Write timeout. */
00643                 break;
00644             }
00645         } else {
00646             if (rbytes > len) {
00647                 rbytes = len;
00648             }
00649             memcpy(bp, dp, rbytes);
00650             NutSegBufWriteLast(rbytes);
00651             NutEventPost(&dcb->dcb_feedme);
00652             len -= rbytes;
00653             rc += rbytes;
00654             dp += rbytes;
00655         }
00656     }
00657     return rc;
00658 }
00659 
00660 #ifdef __HARVARD_ARCH__
00661 
00683 int VsCodecWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00684 {
00685     return -1;
00686 }
00687 #endif
00688 
00689 /*
00690  * Open codec stream.
00691  */
00692 NUTFILE *VsCodecOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00693 {
00694     NUTFILE *nfp;
00695 
00696 #if defined(VS_SW_RESET_ON_OPEN)
00697     VsCodecMode(dev, VS_SM_RESET, VS_SM_RESET);
00698 #endif
00699 
00700     nfp = malloc(sizeof(NUTFILE));
00701     nfp->nf_next = NULL;
00702     nfp->nf_dev = dev;
00703     nfp->nf_fcb = NULL;
00704 
00705     NutSegBufReset();
00706 
00707     return nfp;
00708 }
00709 
00710 /*
00711  * Close codec stream.
00712  */
00713 int VsCodecClose(NUTFILE * nfp)
00714 {
00715     VSDCB *dcb = nfp->nf_dev->dev_dcb;
00716 
00717     int rc = VsDecoderBufferFlush(nfp->nf_dev, dcb->dcb_wtmo);
00718 
00719     if (nfp) {
00720         free(nfp);
00721     }
00722     return rc;
00723 }
00724 

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