/home/hillier_g/checkout/most4linux/most-kernel/most-alsa.c

Go to the documentation of this file.
00001 /*
00002  *  Copyright(c) Siemens AG, Muenchen, Germany, 2005, 2006, 2007
00003  *                           Bernhard Walle <bernhard.walle@gmx.de>
00004  *                           Gernot Hillier <gernot.hillier@siemens.com>
00005  *
00006  * ----------------------------------------------------------------------------
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License version 2 as 
00009  * published by the Free Software Foundation;
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  * ----------------------------------------------------------------------------
00020  */
00021 #ifdef HAVE_CONFIG_H
00022 #include "config/config.h"
00023 #endif
00024 #include <linux/module.h>
00025 #include <linux/init.h>
00026 
00027 #include <sound/driver.h>
00028 #include <sound/core.h>
00029 #include <sound/initval.h>
00030 #include <sound/pcm.h>
00031 
00032 #include "most-constants.h"
00033 #include "most-base.h"
00034 #include "most-sync-common.h"
00035 #include "most-sync.h"
00036 #include "most-alsa.h"
00037 
00038 
00046 /* constants {{{ ----------------------------------------------------------- */
00047 
00051 #define DRIVER_NAME                     "most-alsa"
00052 
00056 #define PR                              DRIVER_NAME       ": "
00057 
00061 #define MOST_SYNC_DEV_TEMPLATE          "/dev/mostsync%d"
00062 
00063 /* }}} */
00064 
00065 /* general static data elements {{{ ---------------------------------------- */
00066 
00070 static char *version = "$Rev: 641 $";
00071 
00075 struct most_alsa_dev *most_alsa_devices[MOST_DEVICE_NUMBER];
00076 
00077 /* }}} */
00078 
00079 /* module parameters {{{ --------------------------------------------------- */
00080 
00084 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
00085 
00089 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
00090 
00094 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
00095 
00103 static int playback_offset[SNDRV_CARDS] = { [0 ... SNDRV_CARDS-1] = 0 };
00104 
00112 static int capture_offset[SNDRV_CARDS] = { [0 ... SNDRV_CARDS-1] = 0 };
00113 
00114 #ifndef DOXYGEN
00115 module_param_array(index, int, NULL, 0444);
00116 MODULE_PARM_DESC(index, "Index value for MOST soundcard.");
00117 
00118 module_param_array(id, charp, NULL, 0444);
00119 MODULE_PARM_DESC(id, "ID string for CS4281 soundcard.");
00120 
00121 module_param_array(enable, bool, NULL, 0444);
00122 MODULE_PARM_DESC(enable, "Enable CS4281 soundcard.");
00123 
00124 module_param_array(playback_offset, int, NULL, 0444);
00125 MODULE_PARM_DESC(playback_offset, 
00126         "Offset for accessing the synchronous data in playback direction");
00127 
00128 module_param_array(capture_offset, int, NULL, 0444);
00129 MODULE_PARM_DESC(capture_offset, 
00130         "Offset for accessing the synchronous data in capture direction");
00131 #endif
00132 
00133 /* }}} */
00134 
00135 /* PCM driver {{{   -------------------------------------------------------- */
00136 
00137 /* Playback {{{ ------------------------------------------------------------ */
00138 
00139 
00147 static int snd_most_playback_setup_sync_file(struct most_alsa_dev   *alsa_dev,
00148                                              struct file            **filp)
00149 {
00150     struct frame_part           frame_part;
00151     struct file                 *most_sync_filp;
00152     char                        syncdev[32];
00153     int                         err;
00154 
00155     snd_assert(filp != NULL);
00156 
00157     /* create the MOST synchronous device */
00158     snprintf(syncdev, PATH_MAX, MOST_SYNC_DEV_TEMPLATE, 
00159             MOST_DEV_CARDNUMBER(alsa_dev->most_dev));
00160     most_sync_filp = filp_open(syncdev, O_WRONLY, 0);
00161     if (!unlikely(most_sync_filp)) {
00162         rtnrt_warn(PR "Couldn't open %s in kernelspace\n", syncdev);
00163         return -EIO;
00164     }
00165 
00166     frame_part.count = 4;
00167     frame_part.offset = playback_offset[alsa_dev->card->number];
00168 
00169     err = most_sync_setup_tx(most_sync_filp, &frame_part);
00170     if (unlikely(err != 0)) {
00171         rtnrt_warn(PR "most_sync_setup_tx failed with %d\n", err);
00172         goto out;
00173     }
00174 
00175     *filp = most_sync_filp;
00176 
00177     return 0;
00178 out:
00179     filp_close(most_sync_filp, current->files);
00180     return err;
00181 }
00182 
00190 static int snd_most_playback_thread(void *data)
00191 {
00192     struct rtnrt_memcopy_desc   copy = { rtnrt_memmove, NULL };
00193     struct most_alsa_dev        *alsa_dev = (struct most_alsa_dev *)data;
00194     struct snd_pcm_runtime      *runtime = alsa_dev->p_substream->runtime;
00195     unsigned int                period_bytes, initial_fill, i;
00196     unsigned char               *zero_buffer = NULL;
00197     int                         err;
00198     struct file                 *most_sync_filp = NULL;
00199     void                        *dma_buf;
00200 
00201     pr_alsa_debug(PR "snd_most_playback_thread started\n");
00202     daemonize("most_alsa_playback");
00203     allow_signal(SIGTERM);
00204     up(&alsa_dev->p_thread_sema);
00205 
00206     /* setup the MOST device */
00207     err = snd_most_playback_setup_sync_file(alsa_dev, &most_sync_filp);
00208     if (unlikely(err != 0)) {
00209         goto out;
00210     }
00211 
00212     /* wait until the buffer was setup */
00213     err = down_interruptible(&alsa_dev->p_buf_setup_sema);
00214     if (unlikely(err < 0)) {
00215         pr_alsa_debug(PR "snd_most_playback_thread: wait_event_interruptible "
00216                 "returned with %d", err);
00217         goto out_close;
00218     }
00219 
00220     /* init some data */
00221     period_bytes = frames_to_bytes(runtime, runtime->period_size);
00222     initial_fill = max(2U, runtime->periods/2);
00223 
00224     /* allocate zero buffer */
00225     zero_buffer = kmalloc(period_bytes, GFP_KERNEL);
00226     if (unlikely(!zero_buffer)) {
00227         rtnrt_warn(PR "snd_most_playback_thread: alloc zero buffer failed\n");
00228         goto out_close;
00229     }
00230     memset(zero_buffer, 0, period_bytes);
00231 
00232     /* fill the buffer initially */
00233     for (i = 0; i < initial_fill; i++) {
00234         err = most_sync_write(most_sync_filp, zero_buffer, period_bytes, &copy);
00235         if (unlikely(err < 0)) {
00236             pr_alsa_debug(PR "snd_most_playback_thread, break write\n");
00237             break;
00238         }
00239         atomic_inc(&alsa_dev->p_cur_period);
00240     }
00241 
00242     /* zero the DMA buffer initially */
00243     err = down_interruptible(&alsa_dev->p_buffer_mutex);
00244     if (unlikely(err != 0)) {
00245         up(&alsa_dev->p_buffer_mutex);
00246         goto out_close;
00247     }
00248 
00249     if (!runtime->dma_buffer_p) {
00250         up(&alsa_dev->p_buffer_mutex);
00251         goto out_close;
00252     }
00253     dma_buf = runtime->dma_buffer_p->area;
00254 
00255     memset(dma_buf, 0, period_bytes * runtime->periods);
00256     up(&alsa_dev->p_buffer_mutex);
00257 
00258     while (!signal_pending(current)) {
00259         unsigned long   offset;
00260 
00261         err = down_interruptible(&alsa_dev->p_event);
00262         if (unlikely(err != 0)) {
00263             break;
00264         }
00265 
00266         err = down_interruptible(&alsa_dev->p_buffer_mutex);
00267         if (unlikely(err != 0)) {
00268             break;
00269         }
00270 
00271         offset = (atomic_read(&alsa_dev->p_cur_period) % runtime->periods) 
00272             * period_bytes;
00273 
00274         if (!alsa_dev->p_silent) {
00275             
00276             if (!runtime->dma_buffer_p) {
00277                 up(&alsa_dev->p_buffer_mutex);
00278                 break;
00279             }
00280             dma_buf = runtime->dma_buffer_p->area;
00281 
00282             /* swap bytes if necessary, we always need big endian */
00283             if (snd_pcm_format_little_endian(runtime->format)) {
00284                 swap_bytes(dma_buf + offset, period_bytes);
00285             }
00286             err = most_sync_write(most_sync_filp, dma_buf + offset, 
00287                     period_bytes, &copy);
00288             if (unlikely(err < 0)) {
00289                 up(&alsa_dev->p_buffer_mutex);
00290                 break;
00291             }
00292 
00293             atomic_inc(&alsa_dev->p_cur_period);
00294             snd_pcm_period_elapsed(alsa_dev->p_substream);
00295         } else {
00296             most_sync_write(most_sync_filp, zero_buffer, period_bytes, &copy);
00297         }
00298 
00299         up(&alsa_dev->p_buffer_mutex);
00300     }
00301 
00302 out_close:
00303     filp_close(most_sync_filp, current->files);
00304 out:
00305     kfree(zero_buffer);
00306     alsa_dev->p_thread_id = 0;
00307     pr_alsa_debug(PR "snd_most_playback_thread finished\n");
00308     complete_and_exit(&alsa_dev->p_completion, 0);
00309 }
00310 
00314 static struct snd_pcm_hardware snd_most_playback_hw = {
00315     .info               = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP),
00316     .formats            = SNDRV_PCM_FMTBIT_S16_LE,
00317     .rates              = SNDRV_PCM_RATE_44100,
00318     .rate_min           = 44100,
00319     .rate_max           = 44100,
00320     .channels_min       = 2,
00321     .channels_max       = 2,
00322     .periods_min        = 2,
00323     .periods_max        = 8
00324 };
00325 
00334 static int snd_most_playback_open(struct snd_pcm_substream *substream)
00335 {
00336     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00337     struct snd_pcm_runtime  *runtime = substream->runtime;
00338     int                     err;
00339 
00340     pr_alsa_debug(PR "snd_most_playback_open\n");
00341 
00342     /* initialise some members at runtime ... */
00343     snd_most_playback_hw.buffer_bytes_max = (hw_tx_buffer_size * 4 * 8);
00344     snd_most_playback_hw.period_bytes_min = (hw_tx_buffer_size * 4);
00345     snd_most_playback_hw.period_bytes_max = (hw_tx_buffer_size * 4);
00346     snd_most_playback_hw.periods_max = min(snd_most_playback_hw.periods_max,
00347             (unsigned int)(sw_tx_buffer_size / hw_tx_buffer_size));
00348 
00349     /* ... and finally assign it */
00350     runtime->hw = snd_most_playback_hw;
00351 
00352     /* setup members of struct most_alsa_dev for playback */
00353     alsa_dev->p_substream = substream;
00354     alsa_dev->p_thread_id = 0;
00355     atomic_set(&alsa_dev->p_cur_period, 0);
00356     init_MUTEX_LOCKED(&alsa_dev->p_event); /* used as sempahore */
00357     init_MUTEX_LOCKED(&alsa_dev->p_thread_sema);
00358     init_MUTEX(&alsa_dev->p_buffer_mutex); /* used as mutex */
00359     init_MUTEX_LOCKED(&alsa_dev->p_buf_setup_sema);
00360     init_completion(&alsa_dev->p_completion);
00361     alsa_dev->p_silent = true;
00362 
00363     /* setup synchronous transmission */
00364     alsa_dev->p_thread_id = kernel_thread(snd_most_playback_thread, 
00365             alsa_dev, CLONE_KERNEL);
00366     if (unlikely(alsa_dev->p_thread_id == 0)) {
00367         rtnrt_warn(PR "playback kernel_thread creation failed\n");
00368         err = -EIO;
00369         goto out;
00370     }
00371 
00372     /* wait until the thread has finished */
00373     err = down_interruptible(&alsa_dev->p_thread_sema);
00374     if (unlikely(err != 0)) {
00375         pr_alsa_debug(PR "snd_most_playback_open interrupted %d\n", err);
00376         goto out_proc;
00377     }
00378 
00379     return 0;
00380 out_proc:
00381     kill_proc(alsa_dev->p_thread_id, SIGTERM, 1);
00382     wait_for_completion(&alsa_dev->p_completion);
00383 out:
00384     return err;
00385 }
00386 
00393 static int snd_most_playback_close(struct snd_pcm_substream *substream)
00394 {
00395     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00396 
00397     pr_alsa_debug(PR "snd_most_playback_close\n");
00398 
00399     /* wait until the kernel thread has finished */
00400     if (likely(alsa_dev->p_thread_id != 0)) {
00401         kill_proc(alsa_dev->p_thread_id, SIGTERM, 1);
00402         wait_for_completion(&alsa_dev->p_completion);
00403     }
00404     alsa_dev->p_substream = NULL;
00405 
00406     return 0;
00407 }
00408 
00417 static int snd_most_playback_hw_params(struct snd_pcm_substream  *substream,
00418                                        struct snd_pcm_hw_params  *hw_params)
00419 {
00420     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00421     int                     ret;
00422 
00423     BUG_ON(alsa_dev->most_dev == NULL);
00424     pr_alsa_debug(PR "snd_most_pcm_hw_params\n");
00425 
00426     ret = down_interruptible(&alsa_dev->p_buffer_mutex);
00427     if (unlikely(ret != 0)) {
00428         rtnrt_warn(PR "snd_most_pcm_hw_params: down_interruptible failed\n");
00429         return ret;
00430     }
00431 
00432     ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
00433     up(&alsa_dev->p_buffer_mutex);
00434 
00435     if (unlikely(ret < 0)) {
00436         rtnrt_warn(PR "snd_most_pcm_hw_params: snd_pcm_lib_malloc_pages "
00437                 "failed with %d\n", ret);
00438         return ret;
00439     }
00440 
00441     alsa_dev->p_silent = false;
00442     up(&alsa_dev->p_buf_setup_sema);
00443 
00444     return 0;
00445 }
00446 
00453 static int snd_most_playback_hw_free(struct snd_pcm_substream *substream)
00454 {
00455     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00456 
00457     pr_alsa_debug(PR "snd_most_playback_hw_free\n");
00458 
00459     alsa_dev->p_silent = true;
00460 
00461     return snd_pcm_lib_free_pages(substream);
00462 }
00463 
00470 static int snd_most_playback_prepare(struct snd_pcm_substream *substream)
00471 {
00472     struct most_alsa_dev      *alsa_dev = snd_pcm_substream_chip(substream);
00473 
00474     atomic_set(&alsa_dev->p_cur_period, 0);
00475 
00476     pr_alsa_debug(PR "snd_most_pcm_prepare\n");
00477     
00478 #if 0
00479     pr_info("rate = %d, channels = %d\n",
00480             substream->runtime->rate, substream->runtime->channels);
00481     pr_info("period_size = %lu, periods = %d\n",
00482             substream->runtime->period_size, substream->runtime->periods);
00483     pr_info("buffer_size = %lu, tick_time = %d\n",
00484             substream->runtime->buffer_size, substream->runtime->tick_time);
00485     pr_info("frame_bits = %d, sample_bits = %d\n",
00486             substream->runtime->frame_bits, substream->runtime->sample_bits);
00487 #endif
00488 
00489     return 0;
00490 }
00491 
00501 static int snd_most_playback_trigger(struct snd_pcm_substream *substream, int cmd)
00502 {
00503     struct most_alsa_dev      *alsa_dev = snd_pcm_substream_chip(substream);
00504 
00505     switch (cmd) {
00506         case SNDRV_PCM_TRIGGER_START:
00507             pr_alsa_debug(PR "SNDRV_PCM_TRIGGER_START\n");
00508             alsa_dev->p_silent = false;
00509             break;
00510 
00511         case SNDRV_PCM_TRIGGER_STOP:
00512             pr_alsa_debug(PR "SNDRV_PCM_TRIGGER_STOP\n");
00513             alsa_dev->p_silent = true;
00514     }
00515 
00516     return 0;
00517 }
00518 
00526 static snd_pcm_uframes_t snd_most_playback_pointer(struct snd_pcm_substream *substream)
00527 {
00528     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00529     struct snd_pcm_runtime  *runtime = substream->runtime;
00530 
00531     return runtime->period_size * 
00532             (atomic_read(&alsa_dev->p_cur_period) % runtime->periods);
00533 }
00534 
00535 /* }}} */
00536 
00537 /* Capture  {{{ ------------------------------------------------------------ */
00538 
00539 
00547 static int snd_most_capture_setup_sync_file(struct most_alsa_dev   *alsa_dev,
00548                                              struct file            **filp)
00549 {
00550     struct frame_part           frame_part;
00551     struct file                 *most_sync_filp;
00552     char                        syncdev[32];
00553     int                         err;
00554 
00555     snd_assert(filp != NULL);
00556 
00557     /* create the MOST synchronous device */
00558     snprintf(syncdev, PATH_MAX, MOST_SYNC_DEV_TEMPLATE, 
00559             MOST_DEV_CARDNUMBER(alsa_dev->most_dev));
00560     most_sync_filp = filp_open(syncdev, O_RDONLY, 0);
00561     if (!unlikely(most_sync_filp)) {
00562         rtnrt_warn(PR "Couldn't open %s in kernelspace\n", syncdev);
00563         return -EIO;
00564     }
00565 
00566     frame_part.count = 4;
00567     frame_part.offset = capture_offset[alsa_dev->card->number];
00568 
00569     err = most_sync_setup_rx(most_sync_filp, &frame_part);
00570     if (unlikely(err != 0)) {
00571         rtnrt_warn(PR "most_sync_setup_rx failed with %d\n", err);
00572         goto out;
00573     }
00574 
00575     *filp = most_sync_filp;
00576 
00577     return 0;
00578 out:
00579     filp_close(most_sync_filp, current->files);
00580     return err;
00581 }
00582 
00590 static int snd_most_capture_thread(void *data)
00591 {
00592     struct rtnrt_memcopy_desc   copy = { rtnrt_memmove, NULL };
00593     struct most_alsa_dev        *alsa_dev = (struct most_alsa_dev *)data;
00594     struct snd_pcm_runtime      *runtime = alsa_dev->c_substream->runtime;
00595     unsigned int                period_bytes;
00596     int                         err;
00597     struct file                 *most_sync_filp = NULL;
00598     void                        *dma_buf;
00599 
00600     pr_alsa_debug(PR "snd_most_capture_thread started\n");
00601     daemonize("most_alsa_capture");
00602     allow_signal(SIGTERM);
00603     up(&alsa_dev->c_thread_sema);
00604 
00605     /* setup the MOST device */
00606     err = snd_most_capture_setup_sync_file(alsa_dev, &most_sync_filp);
00607     if (unlikely(err != 0)) {
00608         goto out;
00609     }
00610 
00611     /* wait until the buffer was setup */
00612     err = down_interruptible(&alsa_dev->c_buf_setup_sema);
00613     if (unlikely(err < 0)) {
00614         pr_alsa_debug(PR "snd_most_capture_thread: wait_event_interruptible "
00615                 "returned with %d\n", err);
00616         goto out_close;
00617     }
00618 
00619     /* init some data */
00620     period_bytes = frames_to_bytes(runtime, runtime->period_size);
00621 
00622     /* fill the buffer initially */
00623     err = down_interruptible(&alsa_dev->c_buffer_mutex);
00624     if (unlikely(err != 0)) {
00625         up(&alsa_dev->c_buffer_mutex);
00626         goto out_close;
00627     }
00628 
00629     if (!runtime->dma_buffer_p) {
00630         up(&alsa_dev->c_buffer_mutex);
00631         goto out_close;
00632     }
00633     dma_buf = runtime->dma_buffer_p->area;
00634 
00635     memset(dma_buf, 0, period_bytes * runtime->periods);
00636     up(&alsa_dev->c_buffer_mutex);
00637 
00638     while (!signal_pending(current)) {
00639         unsigned long   offset;
00640 
00641         err = down_interruptible(&alsa_dev->c_buffer_mutex);
00642         if (unlikely(err != 0)) {
00643             break;
00644         }
00645 
00646         if (!runtime->dma_buffer_p) {
00647             up(&alsa_dev->c_buffer_mutex);
00648             break;
00649         }
00650         dma_buf = runtime->dma_buffer_p->area;
00651         offset = (atomic_read(&alsa_dev->c_cur_period) % runtime->periods) 
00652             * period_bytes;
00653 
00654         if (!alsa_dev->c_silent) {
00655             err = most_sync_read(most_sync_filp, dma_buf + offset, period_bytes, &copy);
00656             if (unlikely(err < 0)) {
00657                 up(&alsa_dev->c_buffer_mutex);
00658                 break;
00659             }
00660             snd_assert(err == period_bytes);
00661 
00662             /* swap bytes if necessary, we always need big endian */
00663             if (snd_pcm_format_little_endian(runtime->format)) {
00664                 swap_bytes(dma_buf + offset, period_bytes);
00665             }
00666             atomic_inc(&alsa_dev->c_cur_period);
00667             snd_pcm_period_elapsed(alsa_dev->c_substream);
00668         } else {
00669             memset(dma_buf, 0, period_bytes * runtime->periods); 
00670         }
00671 
00672         up(&alsa_dev->c_buffer_mutex);
00673     }
00674 
00675 out_close:
00676     filp_close(most_sync_filp, current->files);
00677 out:
00678     alsa_dev->c_thread_id = 0;
00679     pr_alsa_debug(PR "snd_most_capture_thread finished\n");
00680     complete_and_exit(&alsa_dev->c_completion, 0);
00681 }
00682 
00686 static struct snd_pcm_hardware snd_most_capture_hw = {
00687     .info               = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP),
00688     .formats            = SNDRV_PCM_FMTBIT_S16_LE,
00689     .rates              = SNDRV_PCM_RATE_44100,
00690     .rate_min           = 44100,
00691     .rate_max           = 44100,
00692     .channels_min       = 2,
00693     .channels_max       = 2,
00694     .periods_min        = 2,
00695     .periods_max        = 8
00696 };
00697 
00706 static int snd_most_capture_open(struct snd_pcm_substream *substream)
00707 {
00708     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00709     struct snd_pcm_runtime  *runtime = substream->runtime;
00710     int                     err;
00711 
00712     pr_alsa_debug(PR "snd_most_capture_open\n");
00713 
00714     /* initialise some members at runtime ... */
00715     snd_most_capture_hw.buffer_bytes_max = (hw_tx_buffer_size * 4 * 8);
00716     snd_most_capture_hw.period_bytes_min = (hw_tx_buffer_size * 4);
00717     snd_most_capture_hw.period_bytes_max = (hw_tx_buffer_size * 4);
00718     snd_most_capture_hw.periods_max = min(snd_most_capture_hw.periods_max,
00719             (unsigned int)(sw_tx_buffer_size / hw_tx_buffer_size));
00720 
00721     /* ... and finally assign it */
00722     runtime->hw = snd_most_capture_hw;
00723 
00724     /* setup members of struct most_alsa_dev for capture */
00725     alsa_dev->c_substream = substream;
00726     alsa_dev->c_thread_id = 0;
00727     atomic_set(&alsa_dev->c_cur_period, 0);
00728     init_MUTEX(&alsa_dev->c_buffer_mutex);
00729     init_MUTEX_LOCKED(&alsa_dev->c_thread_sema);
00730     init_MUTEX_LOCKED(&alsa_dev->c_buf_setup_sema);
00731     init_completion(&alsa_dev->c_completion);
00732     alsa_dev->c_silent = true;
00733 
00734     /* setup synchronous transmission */
00735     alsa_dev->c_thread_id = kernel_thread(snd_most_capture_thread, 
00736             alsa_dev, CLONE_KERNEL);
00737     if (unlikely(alsa_dev->c_thread_id == 0)) {
00738         rtnrt_warn(PR "capture kernel_thread creation failed\n");
00739         err = -EIO;
00740         goto out;
00741     }
00742 
00743     /* wait until the thread has finished */
00744     err = down_interruptible(&alsa_dev->c_thread_sema);
00745     if (unlikely(err != 0)) {
00746         pr_alsa_debug(PR "snd_most_capture_open interrupted %d\n", err);
00747         goto out_proc;
00748     }
00749 
00750     return 0;
00751 out_proc:
00752     kill_proc(alsa_dev->c_thread_id, SIGTERM, 1);
00753     wait_for_completion(&alsa_dev->c_completion);
00754 out:
00755     return err;
00756 }
00757 
00764 static int snd_most_capture_close(struct snd_pcm_substream *substream)
00765 {
00766     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00767 
00768     pr_alsa_debug(PR "snd_most_capture_close\n");
00769 
00770     /* wait until the kernel thread has finished */
00771     if (likely(alsa_dev->c_thread_id != 0)) {
00772         kill_proc(alsa_dev->c_thread_id, SIGTERM, 1);
00773         wait_for_completion(&alsa_dev->c_completion);
00774     }
00775     alsa_dev->c_substream = NULL;
00776 
00777     return 0;
00778 }
00779 
00788 static int snd_most_capture_hw_params(struct snd_pcm_substream  *substream,
00789                                       struct snd_pcm_hw_params  *hw_params)
00790 {
00791     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00792     int                     ret;
00793 
00794     BUG_ON(alsa_dev->most_dev == NULL);
00795     pr_alsa_debug(PR "snd_most_pcm_hw_params\n");
00796 
00797     ret = down_interruptible(&alsa_dev->c_buffer_mutex);
00798     if (unlikely(ret != 0)) {
00799         rtnrt_warn(PR "snd_most_pcm_hw_params: down_interruptible failed\n");
00800         return ret;
00801     }
00802 
00803     ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
00804     up(&alsa_dev->c_buffer_mutex);
00805 
00806     if (unlikely(ret < 0)) {
00807         rtnrt_warn(PR "snd_most_pcm_hw_params: snd_pcm_lib_malloc_pages "
00808                 "failed with %d\n", ret);
00809         return ret;
00810     }
00811 
00812     alsa_dev->c_silent = false;
00813     up(&alsa_dev->c_buf_setup_sema);
00814 
00815     return 0;
00816 }
00817 
00824 static int snd_most_capture_hw_free(struct snd_pcm_substream *substream)
00825 {
00826     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00827 
00828     pr_alsa_debug(PR "snd_most_capture_hw_free\n");
00829 
00830     alsa_dev->c_silent = true;
00831 
00832     return snd_pcm_lib_free_pages(substream);
00833 }
00834 
00841 static int snd_most_capture_prepare(struct snd_pcm_substream *substream)
00842 {
00843     struct most_alsa_dev      *alsa_dev = snd_pcm_substream_chip(substream);
00844 
00845     atomic_set(&alsa_dev->c_cur_period, 0);
00846 
00847     pr_alsa_debug(PR "snd_most_pcm_prepare\n");
00848     
00849 #if 0
00850     pr_alsa_debug(PR "rate = %d, channels = %d\n",
00851             substream->runtime->rate, substream->runtime->channels);
00852     pr_alsa_debug(PR p"eriod_size = %lu, periods = %d\n",
00853             substream->runtime->period_size, substream->runtime->periods);
00854     pr_alsa_debug(PR "buffer_size = %lu, tick_time = %d\n",
00855             substream->runtime->buffer_size, substream->runtime->tick_time);
00856     pr_alsa_debug(PR "frame_bits = %d, sample_bits = %d\n",
00857             substream->runtime->frame_bits, substream->runtime->sample_bits);
00858 #endif
00859 
00860     return 0;
00861 }
00862 
00872 static int snd_most_capture_trigger(struct snd_pcm_substream *substream, int cmd)
00873 {
00874     struct most_alsa_dev      *alsa_dev = snd_pcm_substream_chip(substream);
00875 
00876     switch (cmd) {
00877         case SNDRV_PCM_TRIGGER_START:
00878             pr_alsa_debug(PR "SNDRV_PCM_TRIGGER_START\n");
00879             alsa_dev->c_silent = false;
00880             break;
00881 
00882         case SNDRV_PCM_TRIGGER_STOP:
00883             pr_alsa_debug(PR "SNDRV_PCM_TRIGGER_STOP\n");
00884             alsa_dev->c_silent = true;
00885     }
00886 
00887     return 0;
00888 }
00889 
00897 static snd_pcm_uframes_t snd_most_capture_pointer(
00898         struct snd_pcm_substream *substream)
00899 {
00900     struct most_alsa_dev    *alsa_dev = snd_pcm_substream_chip(substream);
00901     struct snd_pcm_runtime  *runtime = substream->runtime;
00902 
00903     return runtime->period_size * 
00904             (atomic_read(&alsa_dev->c_cur_period) % runtime->periods);
00905 }
00906 
00907 /* }}} */
00908 
00909 /* General  {{{ ------------------------------------------------------------ */
00910 
00914 static struct snd_pcm_ops snd_most_playback_ops = {
00915     .open       = snd_most_playback_open,
00916     .close      = snd_most_playback_close,
00917     .ioctl      = snd_pcm_lib_ioctl,
00918     .hw_params  = snd_most_playback_hw_params,
00919     .hw_free    = snd_most_playback_hw_free,
00920     .prepare    = snd_most_playback_prepare,
00921     .trigger    = snd_most_playback_trigger,
00922     .pointer    = snd_most_playback_pointer,
00923 };
00924 
00928 static struct snd_pcm_ops snd_most_capture_ops = {
00929     .open       = snd_most_capture_open,
00930     .close      = snd_most_capture_close,
00931     .ioctl      = snd_pcm_lib_ioctl,
00932     .hw_params  = snd_most_capture_hw_params,
00933     .hw_free    = snd_most_capture_hw_free,
00934     .prepare    = snd_most_capture_prepare,
00935     .trigger    = snd_most_capture_trigger,
00936     .pointer    = snd_most_capture_pointer,
00937 };
00938 
00939 
00946 static int __devinit snd_most_new_pcm(struct most_alsa_dev *alsa_dev)
00947 {
00948     struct snd_pcm  *pcm;
00949     int             err;
00950 
00951     err = snd_pcm_new(alsa_dev->card, "MOST PCM", 0, 1, 1, &pcm);
00952     if (unlikely(err != 0)) {
00953         return err;
00954     }
00955 
00956     pcm->private_data = alsa_dev;
00957     strcpy(pcm->name, "MOST PCM");
00958     alsa_dev->pcm = pcm;
00959 
00960     /* set operators */
00961     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_most_playback_ops);
00962     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_most_capture_ops);
00963 
00964     /* pre-allocation of buffers, may fail */
00965     err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
00966             snd_dma_continuous_data(GFP_KERNEL), 
00967             max(hw_tx_buffer_size, hw_rx_buffer_size) * 8 * 4, 
00968             max(hw_tx_buffer_size, hw_rx_buffer_size) * 8 * 4);
00969     if (unlikely(err != 0)) {
00970         rtnrt_warn(PR "snd_pcm_lib_preallocate_pages_for_all failed "
00971                 "with %d\n", err);
00972         goto err_pcm;
00973     }
00974 
00975     return 0;
00976 
00977 err_pcm:
00978     return err;
00979 }
00980 
00981 /* }}} */
00982 
00983 /* }}} */
00984 
00985 /* ALSA Sound Card   {{{ --------------------------------------------------- */
00986 
00992 static void snd_most_free(struct snd_card *card)
00993 {
00994     /* Deinitialise the struct most_alsa_dev elements */
00995 
00996 }
00997 
01004 static int __devinit snd_most_create(struct snd_card    *card, 
01005                                      struct most_dev    *most_dev)
01006 {
01007     struct most_alsa_dev *alsa_dev = ALSA_DEV(card);
01008 
01009     card->private_free = snd_most_free;
01010 
01011     /* initialise the struct most_alsa_dev elements */
01012     memset(alsa_dev, 0, sizeof(struct most_alsa_dev));
01013     alsa_dev->most_dev = most_dev;
01014     alsa_dev->card = card;
01015 
01016     return 0;
01017 }
01018 
01025 static int most_alsa_remove(struct most_dev *most_dev)
01026 {
01027     int                     number = MOST_DEV_CARDNUMBER(most_dev);
01028     struct most_alsa_dev    *alsa_dev = most_alsa_devices[number];
01029 
01030     pr_alsa_debug(PR "alsa_remove called, number = %d\n", number);
01031 
01032     most_alsa_devices[number] = NULL;
01033     snd_card_free(alsa_dev->card);
01034 
01035     return 0;
01036 }
01037 
01044 static int most_alsa_probe(struct most_dev *most_dev)
01045 {
01046     struct snd_card         *card;
01047     int                     err;
01048     int                     number = MOST_DEV_CARDNUMBER(most_dev);
01049 
01050     pr_alsa_debug(PR "alsa_probe called, number = %d\n", number);
01051 
01052     if (most_dev->card_number >= SNDRV_CARDS) {
01053         return -ENODEV;
01054     }
01055     if (!enable[most_dev->card_number]) {
01056         return -ENOENT;
01057     }
01058 
01059     card = snd_card_new(index[number], id[number],
01060             THIS_MODULE, sizeof(struct most_alsa_dev));
01061     if (unlikely(!card)) {
01062         return -ENOMEM;
01063     }
01064 
01065     err = snd_most_create(card, most_dev);
01066     if (unlikely(err < 0)) {
01067         goto out_snd_most;
01068     }
01069 
01070     strcpy(card->driver, "MOST");
01071     strcpy(card->shortname, "OASIS MOST PCI device");
01072     sprintf(card->longname, "%s number %d", card->shortname, most_dev->card_number);
01073 
01074     err = snd_most_new_pcm(ALSA_DEV(card));
01075     if (unlikely(err < 0)) {
01076         goto out_snd_most;
01077     }
01078 
01079     err = snd_card_register(card);
01080     if (unlikely(err < 0)) {
01081         goto out_snd_most;
01082     }
01083 
01084     most_alsa_devices[number] = ALSA_DEV(card);
01085 
01086     return 0;
01087 
01088 out_snd_most:
01089     snd_card_free(card);
01090     return err;
01091 }
01092 
01102 static void most_alsa_int_handler(struct most_dev        *dev,
01103                                   unsigned int           intstatus)
01104 {
01105     int                     number = MOST_DEV_CARDNUMBER(dev);
01106     struct most_alsa_dev    *alsa_dev = most_alsa_devices[number];
01107 
01108     BUG_ON(dev == NULL);
01109     if (alsa_dev) {
01110         if ((intstatus & IESTX) && alsa_dev->p_thread_id != 0) {
01111             up(&alsa_dev->p_event);
01112         }
01113     }
01114 }
01115 
01120 static struct most_high_driver most_alsa_high_driver = {
01121     .name               = "most-alsa",
01122     .sema_list          = LIST_HEAD_INIT(most_alsa_high_driver.sema_list),
01123     .spin_list          = LIST_HEAD_INIT(most_alsa_high_driver.spin_list),
01124     .probe              = most_alsa_probe,
01125     .remove             = most_alsa_remove,
01126     .int_handler        = most_alsa_int_handler,
01127     .interrupt_mask     = (IESTX | IESRX)
01128 };
01129 
01130 /* }}} */
01131 
01132 /* Module init/exit  {{{ --------------------------------------------------- */
01133 
01139 static int __init most_alsa_init(void)
01140 {
01141     int err;
01142 
01143     rtnrt_info(PR "Loading module %s, version %s\n", DRIVER_NAME, version);
01144 
01145     /* register driver */
01146     err = most_register_high_driver(&most_alsa_high_driver);
01147     if (unlikely(err != 0)) {
01148         return err;
01149     }
01150 
01151     return 0;
01152 }
01153 
01157 static void __exit most_alsa_exit(void)
01158 {
01159     most_deregister_high_driver(&most_alsa_high_driver);
01160 
01161     rtnrt_info(PR "Unloading module %s, version %s\n", DRIVER_NAME, version);
01162 }
01163 
01164 /* }}} */
01165 
01166 
01167 #ifndef DOXYGEN
01168 MODULE_LICENSE("GPL");
01169 MODULE_AUTHOR("Bernhard Walle");
01170 MODULE_VERSION("$Rev: 641 $");
01171 MODULE_DESCRIPTION("ALSA Driver for MOST Synchronous data.");
01172 module_init(most_alsa_init);
01173 module_exit(most_alsa_exit);
01174 #endif
01175 
01176 /* vim: set ts=4 et sw=4 foldmethod=marker: */

Generated on Fri Mar 9 14:48:57 2007 for MOST Linux Drivers (Linux and RTAI) by  doxygen 1.5.0