hxcodec.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  * $Log$
00038  * Revision 1.4  2009/02/13 14:46:19  haraldkipp
00039  * Using the VS10xx driver as a template for redesign.
00040  *
00041  * Revision 1.3  2009/01/17 11:26:46  haraldkipp
00042  * Getting rid of two remaining BSD types in favor of stdint.
00043  * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
00044  *
00045  * Revision 1.2  2008/10/23 08:54:07  haraldkipp
00046  * Include the correct header file.
00047  *
00048  * Revision 1.1  2008/10/05 16:56:15  haraldkipp
00049  * Added Helix audio device.
00050  *
00051  */
00052 
00053 #include <sys/atom.h>
00054 #include <sys/event.h>
00055 #include <sys/timer.h>
00056 #include <sys/heap.h>
00057 
00058 #include <cfg/arch/gpio.h>
00059 #include <cfg/audio.h>
00060 #include <dev/irqreg.h>
00061 
00062 #include <contrib/hxmp3/mp3dec.h>
00063 #include <contrib/hxmp3/hermite.h>
00064 #include <dev/hxcodec.h>
00065 #include <dev/tlv320dac.h>
00066 
00067 #include <sys/bankmem.h>
00068 
00069 #include <stdlib.h>
00070 #include <stddef.h>
00071 #include <string.h>
00072 #include <memdebug.h>
00073 
00074 #if 0
00075 /* Use for local debugging. */
00076 #define NUTDEBUG
00077 #include <stdio.h>
00078 #endif
00079 
00080 #ifndef NUT_THREAD_HXCODEC0STACK
00081 /* arm-elf-gcc optimized code used 540 bytes. */
00082 #define NUT_THREAD_HXCODEC0STACK    768
00083 #endif
00084 
00085 #ifndef HXCODEC0_MAX_OUTPUT_BUFSIZ
00086 
00087 #define HXCODEC0_MAX_OUTPUT_BUFSIZ  16384
00088 #endif
00089 
00090 #ifndef DAC_OUTPUT_RATE
00091 #if defined (AT91SAM9260_EK)
00092 #define DAC_OUTPUT_RATE     44100
00093 #else
00094 #define DAC_OUTPUT_RATE     8000
00095 #endif
00096 #endif
00097 
00098 #ifndef MP3_BUFSIZ
00099 #if defined (AT91SAM9260_EK)
00100 #define MP3_BUFSIZ          1048576
00101 #else
00102 #define MP3_BUFSIZ          (4 * MAINBUF_SIZE)
00103 #endif
00104 #endif
00105 
00106 #ifdef HXCODEC0_RESAMPLER
00107 static int rs_maxout;
00108 static short *rs_pcmbuf;
00109 #endif
00110 
00114 #define HXREQ_PLAY      0x00000001
00115 
00116 #define HXREQ_CANCEL    0x00000002
00117 
00118 #define HXREQ_VOLUPD    0x00000004
00119 
00120 #define HXREQ_BEEP      0x00000008
00121 
00127 
00128 typedef struct _HXDCB {
00129     int dcb_pbstat;     
00130     uint32_t dcb_scmd;    
00131     int dcb_rvol;           
00132     int dcb_lvol;           
00133     uint32_t dcb_pbwlo;   
00134     uint32_t dcb_pbwhi;   
00135     uint32_t dcb_wtmo;      
00136     HANDLE dcb_bufque;      
00137     HANDLE dcb_feedme;      
00138 } HXDCB;
00139 
00140 static HXDCB dcb;
00141 #ifdef HXCODEC0_RESAMPLER
00142 static void *hres;
00143 #endif
00144 
00145 typedef struct _MP3PLAYERINFO {
00146     HMP3Decoder mpi_mp3dec;
00147     MP3FrameInfo mpi_frameinfo;
00148 } MP3PLAYERINFO;
00149 
00150 static MP3PLAYERINFO mpi;
00151 
00152 static short pi_pcmbuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP];
00153 
00154 static int first_frame;
00155 static int samprate;
00156 
00166 static int HelixPlayerSetVolume(NUTDEVICE *dev, int left, int right)
00167 {
00168     HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00169 
00170     /* Honor limits. */
00171     left = left > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : left;
00172     left = left < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : left;
00173     right = right > AUDIO_DAC_MAX_GAIN ? AUDIO_DAC_MAX_GAIN : right;
00174     right = right < AUDIO_DAC_MIN_GAIN ? AUDIO_DAC_MIN_GAIN : right;
00175 
00176     Tlv320DacSetVolume(left, right);
00177 
00178     dcb->dcb_lvol = left;
00179     dcb->dcb_rvol = right;
00180 
00181     return 0;
00182 }
00183 
00184 static int DecodeFrame(uint8_t *buf, int len)
00185 {
00186     int rc = len;
00187     int skip;
00188 
00189     while (len >= 2 * MAINBUF_SIZE) {
00190         if ((skip = MP3FindSyncWord(buf, len)) < 0) {
00191             return -1;
00192         }
00193         if (skip) {
00194             len -= skip;
00195             buf += skip;
00196         } else {
00197             if (MP3Decode(mpi.mpi_mp3dec, &buf, &len, pi_pcmbuf, 0)) {
00198                 return -1;
00199             }
00200             if (first_frame) {
00201                 MP3GetLastFrameInfo(mpi.mpi_mp3dec, &mpi.mpi_frameinfo);
00202                 if (mpi.mpi_frameinfo.nChans == 1) {
00203                     samprate = mpi.mpi_frameinfo.samprate / 2;
00204                 }
00205                 else if (mpi.mpi_frameinfo.nChans == 2) {
00206                     samprate = mpi.mpi_frameinfo.samprate;
00207                 }
00208                 else {
00209                     return -1;
00210                 }
00211                 if (mpi.mpi_frameinfo.samprate < 8000 || samprate > DAC_OUTPUT_RATE) {
00212                     return -1;
00213                 }
00214                 if (mpi.mpi_frameinfo.bitsPerSample != 16) {
00215                     return -1;
00216                 }
00217 #ifdef HXCODEC0_RESAMPLER
00218                 /* If needed, initialize resampler. */
00219                 if (samprate != DAC_OUTPUT_RATE) {
00220                     if ((hres = RAInitResamplerHermite(samprate, DAC_OUTPUT_RATE, mpi.mpi_frameinfo.nChans)) == NULL) {
00221                         return -1;
00222                     }
00223                     rs_maxout = RAGetMaxOutputHermite(mpi.mpi_frameinfo.outputSamps, hres);
00224                     if ((rs_pcmbuf = malloc(rs_maxout * 2)) == NULL) {
00225                         return -1;
00226                     }
00227                 }
00228 #endif
00229                 first_frame = 0;
00230             }
00231             if (Tlv320DacWrite(pi_pcmbuf, mpi.mpi_frameinfo.outputSamps)) {
00232                 return -1;
00233             }
00234             break;
00235         }
00236     }
00237     return rc - len;
00238 }
00239 
00240 /*
00241  * Initialize the stream output buffer with a given size.
00242  *
00243  * \param dev Specifies the audio codec device.
00244  */
00245 static int HelixPlayerBufferInit(NUTDEVICE *dev, uint32_t size)
00246 {
00247     HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00248 
00249     /* Make sure that the decoder is idle. */
00250     if (dcb->dcb_pbstat != CODEC_STATUS_IDLE) {
00251         return -1;
00252     }
00253     /* Set new buffer size. */
00254     if (NutSegBufInit((size_t)size) == NULL) {
00255         return -1;
00256     }
00257     /* Set watermark defaults. */
00258     dcb->dcb_pbwlo = NutSegBufAvailable() / 3;
00259     dcb->dcb_pbwhi = dcb->dcb_pbwlo * 2;
00260 
00261     return 0;
00262 }
00263 
00264 /*
00265  * VLSI decoder feeding thread.
00266  */
00267 THREAD(FeederThread, arg)
00268 {
00269     uint8_t *bp;
00270     uint8_t *backbuf = NULL;
00271     int backcnt = 0;
00272     size_t avail;
00273     int filled;
00274     NUTDEVICE *dev = (NUTDEVICE *)arg;
00275     HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00276 
00277     /* We are a high priority thread. */
00278     NutThreadSetPriority(7);
00279     for (;;) {
00280         /* 
00281         ** Idle mode processing. 
00282         */
00283         if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00284             /* Wait for a request or a buffer update. */
00285             NutEventWait(&dcb->dcb_feedme, NUT_WAIT_INFINITE);
00286             /* Check if we should change to play mode. This will happen
00287             ** if we receive a play request or if the buffer contents
00288             ** reaches the high watermark. */
00289             if ((dcb->dcb_scmd & HXREQ_PLAY) != 0 || NutSegBufUsed() >=  dcb->dcb_pbwhi) {
00290                 dcb->dcb_scmd &= ~(HXREQ_PLAY | HXREQ_CANCEL);
00291                 dcb->dcb_pbstat = CODEC_STATUS_PLAYING;
00292                 HelixPlayerSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
00293             }
00294         }
00295 
00296         /* 
00297         ** Play mode processing. 
00298         */
00299         if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
00300             /* Process cancel requests. */
00301             if (dcb->dcb_scmd & HXREQ_CANCEL) {
00302                 dcb->dcb_scmd &= ~HXREQ_CANCEL;
00303                 NutSegBufReset();
00304             }
00305             /* Process volume update requests. */
00306             if (dcb->dcb_scmd & HXREQ_VOLUPD) {
00307                 HelixPlayerSetVolume(dev, dcb->dcb_lvol, dcb->dcb_rvol);
00308                 dcb->dcb_scmd &= ~HXREQ_VOLUPD;
00309             }
00310 
00311             /* Retrieve new data from the input buffer. */
00312             bp = (uint8_t *) NutSegBufReadRequest(&avail);
00313             /* Any data available? */
00314             if (avail == 0) {
00315                 /* No data, wait for a request or a buffer update. */
00316                 NutEventWait(&dcb->dcb_feedme, 10);
00317                 /* Check if MP3 buffer is empty. */
00318                 if (NutSegBufUsed() == 0) {
00319                     /* Consume any remaining back buffer contents. */
00320                     while (backcnt > 0) {
00321                         filled = DecodeFrame(backbuf, backcnt);
00322                         if (filled <= 0 || filled >= backcnt) {
00323                             break;
00324                         }
00325                         backcnt -= filled;
00326                     }
00327                     /* Finally we reached idle mode. */
00328                     if (backcnt) {
00329                         backcnt = 0;
00330                         free(backbuf);
00331                     }
00332                     dcb->dcb_pbstat = CODEC_STATUS_IDLE;
00333                     NutEventPost(&dcb->dcb_bufque);
00334                 }
00335             }
00336             /* Check for back buffer contents. */
00337             else if (backcnt) {
00338                 /* Check if we have a full frame. */
00339                 if (backcnt + avail >= 2 * MAINBUF_SIZE) {
00340                     memcpy(&backbuf[backcnt], bp, 2 * MAINBUF_SIZE - backcnt);
00341                     filled = DecodeFrame(backbuf, 2 * MAINBUF_SIZE);
00342                     /* Discard back buffer in case of an error. */
00343                     if (filled <= 0) {
00344                         if (filled) {
00345                             backcnt = 0;
00346                             free(backbuf);
00347                         }
00348                     }
00349                     /* Check if something is left in the back buffer. */
00350                     else if (filled < backcnt) {
00351                         bp = &backbuf[filled];
00352                         backcnt -= filled;
00353                         /* Check if the remaining part is larger than the consumed part. */
00354                         if (filled < backcnt) {
00355 #if RADIO_HAS_LARGE_RAM
00356                             /* Yes, we need an intermediate buffer because memcpy
00357                             ** may not work with overlapping buffers. */
00358                             uint8_t *backrem = malloc(backcnt);
00359                             if (backrem) {
00360                                 memcpy(backrem, bp, backcnt);
00361                                 memcpy(backbuf, backrem, backcnt);
00362                                 free(backrem);
00363                             } else {
00364                                 /* Out of memory, discard the back buffer. */
00365                                 backcnt = 0;
00366                                 free(backbuf);
00367                             }
00368 #else
00369                             /* On low memory system we do a manual copy. */
00370                             int i;
00371                             for (i = 0; i < backcnt; i++) {
00372                                 backbuf[i] = *bp++;
00373                             }
00374 #endif
00375                         }
00376                         /* No overlapping, we can directly use memcpy. */
00377                         else {
00378                             memcpy(backbuf, bp, backcnt);
00379                         }
00380                     }
00381                     /* Nothing left in the back buffer, discard it. */
00382                     else {
00383                         if (filled > backcnt) {
00384                             NutSegBufReadLast(filled - backcnt);
00385                             NutEventPost(&dcb->dcb_bufque);
00386                         }
00387                         backcnt = 0;
00388                         free(backbuf);
00389                     }
00390                 }
00391                 /* No full frame available. Add everything to the back buffer. */
00392                 else {
00393                     memcpy(&backbuf[backcnt], bp, avail);
00394                     backcnt += avail;
00395                     NutSegBufReadLast(avail);
00396                     NutEventPost(&dcb->dcb_bufque);
00397                 }
00398             }
00399             /* Nothing in the back buffer. Check for full frame. */
00400             else if (avail >= 2 * MAINBUF_SIZE) {
00401                 filled = DecodeFrame(bp, avail);
00402                 if (filled <= 0) {
00403                     NutSegBufReadLast(1);
00404                 } else {
00405                     NutSegBufReadLast(filled);
00406                 }
00407                 NutEventPost(&dcb->dcb_bufque);
00408             }
00409             /* No full frame. Check if this is caused by a buffer wrap around. */
00410             else if (NutSegBufUsed() > avail) {
00411                 backbuf = malloc(2 * MAINBUF_SIZE);
00412                 if (backbuf) {
00413                     memcpy(backbuf, bp, avail);
00414                     backcnt = avail;
00415                     NutSegBufReadLast(avail);
00416                     NutEventPost(&dcb->dcb_bufque);
00417                 } else {
00418                     /* Out of memory. Take a nap. */
00419                     NutSleep(10);
00420                 }
00421             }
00422             /* Wait for more data. */
00423             else if (NutEventWait(&dcb->dcb_feedme, 10)) {
00424                 /* Consume any remaining buffer contents. */
00425                 while (avail) {
00426                     filled = DecodeFrame(backbuf, backcnt);
00427                     if (filled <= 0 || filled >= avail) {
00428                         break;
00429                     }
00430                     bp = (uint8_t *) NutSegBufReadRequest(&avail);
00431                 }
00432                 /* Finally we reached idle mode. */
00433                 dcb->dcb_pbstat = CODEC_STATUS_IDLE;
00434                 NutEventPost(&dcb->dcb_bufque);
00435             }
00436         }
00437     }
00438 }
00439 
00459 static int HelixIOCtl(NUTDEVICE * dev, int req, void *conf)
00460 {
00461     int rc = 0;
00462     uint32_t *lvp = (uint32_t *) conf;
00463     int *ivp = (int *) conf;
00464     HXDCB *dcb = (HXDCB *)dev->dev_dcb;
00465 
00466     switch (req) {
00467     case AUDIO_PLAY:
00468         if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00469             /* Immediately start playing. */
00470             dcb->dcb_scmd |= HXREQ_PLAY;
00471         }
00472         NutEventPost(&dcb->dcb_feedme);
00473         break;
00474     case AUDIO_CANCEL:
00475         if (dcb->dcb_pbstat == CODEC_STATUS_PLAYING) {
00476             /* Immediately stop playing and discard buffer. */
00477             dcb->dcb_scmd |= HXREQ_CANCEL;
00478         }
00479         NutEventPost(&dcb->dcb_feedme);
00480         break;
00481     case AUDIO_GET_STATUS:
00482         *ivp = dcb->dcb_pbstat;
00483         break;
00484     case AUDIO_GET_PLAYGAIN:
00485         *ivp = dcb->dcb_rvol > dcb->dcb_lvol ? dcb->dcb_rvol : dcb->dcb_lvol;
00486         break;
00487     case AUDIO_SET_PLAYGAIN:
00488         dcb->dcb_lvol = *ivp;
00489         dcb->dcb_rvol = *ivp;
00490         dcb->dcb_scmd |= HXREQ_VOLUPD;
00491         break;
00492     case AUDIO_GET_PBSIZE:
00493         *lvp = NutSegBufAvailable() + NutSegBufUsed();
00494         break;
00495     case AUDIO_SET_PBSIZE:
00496         rc = HelixPlayerBufferInit(dev, *lvp);
00497         break;
00498     case AUDIO_GET_PBLEVEL:
00499         *lvp = NutSegBufUsed();
00500         break;
00501     case AUDIO_GET_PBWLOW:
00502         *lvp = dcb->dcb_pbwlo;
00503         break;
00504     case AUDIO_SET_PBWLOW:
00505         dcb->dcb_pbwlo = *lvp;
00506         break;
00507     case AUDIO_GET_PBWHIGH:
00508         *lvp = dcb->dcb_pbwhi;
00509         break;
00510     case AUDIO_SET_PBWHIGH:
00511         dcb->dcb_pbwhi = *lvp;
00512         break;
00513     case AUDIO_SETWRITETIMEOUT:
00514         dcb->dcb_wtmo = *lvp;
00515         break;
00516     case AUDIO_GETWRITETIMEOUT:
00517         *lvp = dcb->dcb_wtmo;
00518         break;
00519     default:
00520         rc = -1;
00521         break;
00522     }
00523     return rc;
00524 }
00525 
00538 static int HelixPlayerFlush(NUTDEVICE *dev, uint32_t tmo)
00539 {
00540     int rc = 0;
00541     HXDCB *dcb = dev->dev_dcb;
00542 
00543     for (;;) {
00544         /* Keep the player running if the buffer contains data. */
00545         if (NutSegBufUsed()) {
00546             HelixIOCtl(dev, AUDIO_PLAY, NULL);
00547         }
00548         /* No data in buffer. If idle, then we are done. */
00549         else if (dcb->dcb_pbstat == CODEC_STATUS_IDLE) {
00550             /* No data and player is idle. */
00551             break;
00552         }
00553         /* Wait for a new buffer update. */
00554         rc = NutEventWait(&dcb->dcb_bufque, tmo);
00555         if (rc) {
00556             break;
00557         }
00558     }
00559     return rc;
00560 }
00561 
00570 static int HelixWrite(NUTFILE * nfp, CONST void *data, int len)
00571 {
00572     int rc = 0;
00573     uint8_t *bp;
00574     CONST uint8_t *dp;
00575     size_t rbytes;
00576     HXDCB *dcb = nfp->nf_dev->dev_dcb;
00577 
00578     dcb->dcb_wtmo = 3000; //DEBUG
00579     /* Flush buffer if data pointer is a NULL pointer. */
00580     if (data == NULL || len == 0) {
00581         return HelixPlayerFlush(nfp->nf_dev, dcb->dcb_wtmo);
00582     }
00583     dp = data;
00584     while (len) {
00585         bp = (uint8_t *)NutSegBufWriteRequest(&rbytes);
00586         if (rbytes == 0) {
00587             /* No buffer space, wait for change. */
00588             if (NutEventWait(&dcb->dcb_bufque, dcb->dcb_wtmo)) {
00589                 /* Write timeout. */
00590                 break;
00591             }
00592         } else {
00593             if (rbytes > len) {
00594                 rbytes = len;
00595             }
00596             memcpy(bp, dp, rbytes);
00597             NutSegBufWriteLast(rbytes);
00598             NutEventPost(&dcb->dcb_feedme);
00599             len -= rbytes;
00600             rc += rbytes;
00601             dp += rbytes;
00602         }
00603     }
00604     return rc;
00605 }
00606 
00607 #ifdef __HARVARD_ARCH__
00608 
00630 static int HelixWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00631 {
00632     return -1;
00633 }
00634 #endif
00635 
00641 static NUTFILE *HelixOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00642 {
00643     NUTFILE *nfp;
00644 
00645     if ((mpi.mpi_mp3dec = MP3InitDecoder()) == NULL) {
00646         return NUTFILE_EOF;
00647     }
00648 
00649     first_frame = 1;
00650 
00651     NutSleep(2);
00652 
00653     nfp = malloc(sizeof(NUTFILE));
00654     nfp->nf_next = NULL;
00655     nfp->nf_dev = dev;
00656     nfp->nf_fcb = NULL;
00657 
00658     NutSegBufReset();
00659 
00660     return nfp;
00661 }
00662 
00666 static int HelixClose(NUTFILE * nfp)
00667 {
00668     HXDCB *dcb = nfp->nf_dev->dev_dcb;
00669     int rc = HelixPlayerFlush(nfp->nf_dev, dcb->dcb_wtmo);
00670 
00671     if (nfp) {
00672         if (mpi.mpi_mp3dec) {
00673             MP3FreeDecoder(mpi.mpi_mp3dec);
00674             mpi.mpi_mp3dec = NULL;
00675         }
00676         free(nfp);
00677     }
00678     return rc;
00679 }
00680 
00681 /*
00682  * Called via dev_init pointer when the device is registered.
00683  */
00684 static int HelixInit(NUTDEVICE * dev)
00685 {
00686     size_t avail;
00687 
00688     Tlv320DacInit(DAC_OUTPUT_RATE);
00689 
00690     dcb.dcb_rvol = -32;
00691     dcb.dcb_lvol = -32;
00692     Tlv320DacSetVolume(dcb.dcb_lvol, dcb.dcb_rvol);
00693 
00694     /*
00695     ** Initialize the decoder stream buffer.
00696     */
00697 #ifdef HXCODEC0_OUTPUT_BUFSIZ
00698     avail = HXCODEC0_OUTPUT_BUFSIZ;
00699 #else
00700     avail = NutHeapAvailable() / 2;
00701     if (avail > HXCODEC0_MAX_OUTPUT_BUFSIZ) {
00702         avail = HXCODEC0_MAX_OUTPUT_BUFSIZ;
00703     }
00704 #endif
00705     if (HelixPlayerBufferInit(dev, avail)) {
00706         return -1;
00707     }
00708 
00709     /* Start the feeder thread. */
00710     if (NutThreadCreate(dev->dev_name, FeederThread, dev, 
00711         (NUT_THREAD_HXCODEC0STACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == 0) {
00712         return -1;
00713     }
00714     return 0;
00715 }
00716 
00727 NUTDEVICE devHelixCodec = {
00728     0,              /* Pointer to next device, dev_next. */
00729     {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0},    /* Unique device name, dev_name. */
00730     IFTYP_CHAR,     /* Type of device, dev_type. */
00731     0,              /* Base address, dev_base (not used). */
00732     0,              /* First interrupt number, dev_irq (not used). */
00733     0,              /* Interface control block, dev_icb (not used). */
00734     &dcb,           /* Driver control block, dev_dcb. */
00735     HelixInit,         /* Driver initialization routine, dev_init. */
00736     HelixIOCtl,        /* Driver specific control function, dev_ioctl. */
00737     NULL,           /* Read from device, dev_read. */
00738     HelixWrite,        /* Write to device, dev_write. */
00739 #ifdef __HARVARD_ARCH__
00740     HelixWrite_P,      /* Write data from program space to device, dev_write_P. */
00741 #endif
00742     HelixOpen,         /* Open a device or file, dev_open. */
00743     HelixClose,        /* Close a device or file, dev_close. */
00744     NULL            /* Request file size, dev_size. */
00745 };
00746 

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