/[openvortex]/alsa/pci/au88x0/au88x0_pcm.c
ViewVC logotype

Diff of /alsa/pci/au88x0/au88x0_pcm.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.6 by vizard, Mon Jul 28 23:09:37 2003 UTC revision 1.7 by mjander, Thu Aug 7 01:58:51 2003 UTC
# Line 1  Line 1 
1  /*  #define __NO_VERSION__
2   * Vortex PCM ALSA driver.  #include "../../alsa-kernel/pci/au88x0/au88x0_pcm.c"
  *  
  * Supports ADB and WT DMA. Unfortunately, WT routing is still a  
  * mistery. To discover that, we need to disassemble the windoze  
  * driver too.  
  *  
  *  
  */  
3    
 #include <sound/driver.h>  
 #include <linux/time.h>  
 #include <sound/core.h>  
 #include <sound/pcm.h>  
 #include <sound/pcm_params.h>  
 #include "au88x0.h"  
   
 #define chip_t vortex_t  
   
 /* hardware definition */  
 static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {  
     .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME| SNDRV_PCM_INFO_PAUSE |  
              SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID),  
     .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |  
              SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,  
     .rates = SNDRV_PCM_RATE_CONTINUOUS,  
     .rate_min = 5000,  
     .rate_max = 48000,  
     .channels_min = 1,  
     .channels_max = 2,  
     .buffer_bytes_max = 0x10000,  
     .period_bytes_min = 0x0100,  
     .period_bytes_max = 0x1000,  
     .periods_min = 1,  
     .periods_max = 64,  
 };  
   
 static snd_pcm_hardware_t snd_vortex_playback_hw_wt = {  
     .info = (SNDRV_PCM_INFO_MMAP |  
              SNDRV_PCM_INFO_INTERLEAVED |  
              SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),  
     .formats = SNDRV_PCM_FMTBIT_S16_LE,  
     .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000,  
     .rate_min = 8000,  
     .rate_max = 48000,  
     .channels_min = 1,  
     .channels_max = 2,  
     .buffer_bytes_max = 0x10000,  
     .period_bytes_min = 0x0400,  
     .period_bytes_max = 0x1000,  
     .periods_min = 1,  
     .periods_max = 64,  
 };  
   
 /* open callback */  
 static int snd_vortex_pcm_open(snd_pcm_substream_t *substream) {  
     chip_t *chip = snd_pcm_substream_chip(substream);  
     snd_pcm_runtime_t *runtime = substream->runtime;  
         int dma, err;  
           
         /* Force equal size periods */  
         if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)  
         return err;  
         /* Force DMA 32 bit alignment */  
         if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4)) < 0)  
         return err;  
           
     if (substream->pcm == chip->pcm_adb) {  
                 runtime->hw = snd_vortex_playback_hw_adb;  
                 dma = vortex_getadb(chip);  
                 if (dma < 0)  
                         return -EBUSY;  
                 substream->runtime->private_data = &chip->dma_adb[dma];  
         chip->dma_adb[dma].substream = substream;  
     } else {  
                 runtime->hw = snd_vortex_playback_hw_wt;  
                 dma = vortex_getwt(chip);  
                 if (dma < 0)  
                         return -EBUSY;  
                 substream->runtime->private_data = &chip->dma_wt[dma];  
         chip->dma_wt[dma].substream = substream;  
     }  
     return 0;  
 }  
   
 /* close callback */  
 static int snd_vortex_pcm_close(snd_pcm_substream_t *substream) {  
     //vortex_t *chip = snd_pcm_substream_chip(substream);  
         dma_t *dma = (dma_t*)substream->runtime->private_data;  
   
     // the hardware-specific codes will be here  
     // Dealloc DMA and remove audio route.  
     dma->substream = NULL;  
         dma->nr_ch = 0;  
     substream->runtime->private_data = NULL;  
     return 0;  
 }  
   
 /* hw_params callback */  
 static int snd_vortex_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params) {  
         chip_t *chip = snd_pcm_substream_chip(substream);  
         snd_pcm_runtime_t *runtime = substream->runtime;  
         dma_t *dma = (dma_t*)substream->runtime->private_data;  
   
         int err;  
   
         // Alloc buffer memory.  
         err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));  
         if (err < 0) {  
                 printk(KERN_ERR "Vortex: pcm page alloc failed!\n");  
                 return err;  
         }  
   
         printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),  
                 params_period_bytes(hw_params), params_channels(hw_params));  
   
         if (params_buffer_bytes(hw_params) != (params_periods(hw_params)*params_period_bytes(hw_params)))  
                 printk(KERN_INFO "vortex: Warning: Click condition (non integer period count).\n");  
           
         // Make audio routes and config buffer DMA.  
         if (substream->pcm == chip->pcm_adb) {  
                 vortex_adbdma_setbuffers(chip, dma->dma, (u32)(runtime->dma_addr), params_period_bytes(hw_params), params_periods(hw_params));  
                 //if (dma->nr_ch != 0)  
                         vortex_adb_waveroute(chip, dma->dma, 0);  
                 //if (params_channels(hw_params) != 0)  
                         vortex_adb_waveroute(chip, dma->dma, params_channels(hw_params));  
         } else {  
                 vortex_wtdma_setbuffers(chip, dma->dma, (u32)(runtime->dma_addr), params_period_bytes(hw_params), params_periods(hw_params));  
                 if (dma->nr_ch)  
                         vortex_wt_waveroute(chip, dma->dma, 0);  
                 if (params_channels(hw_params))  
                         vortex_wt_waveroute(chip, dma->dma, params_channels(hw_params));  
         }  
         return 0;  
 }  
   
 /* hw_free callback */  
 static int snd_vortex_pcm_hw_free(snd_pcm_substream_t *substream) {  
     chip_t *chip = snd_pcm_substream_chip(substream);  
     dma_t *dma = (dma_t*)substream->runtime->private_data;  
   
     // Delete audio routes.  
     if (substream->pcm == chip->pcm_adb)  
         vortex_adb_waveroute(chip, dma->dma, 0);  
     else  
         vortex_wt_waveroute(chip, dma->dma, 0);  
   
     return snd_pcm_lib_free_pages(substream);  
 }  
   
 /* prepare callback */  
 static int snd_vortex_pcm_prepare(snd_pcm_substream_t *substream) {  
     vortex_t *chip = snd_pcm_substream_chip(substream);  
     snd_pcm_runtime_t *runtime = substream->runtime;  
         dma_t *dma = (dma_t*)substream->runtime->private_data;  
     int fmt, dir;  
   
     // set up the hardware with the current configuration.  
         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  
                 dir = 1;  
         else  
                 dir = 0;  
     fmt = vortex_alsafmt_aspfmt(runtime->format);  
     if (substream->pcm == chip->pcm_adb) {  
         vortex_adbdma_setmode(chip, dma->dma, 1, dir, fmt, 0/*?*/, 0);  
         vortex_adbdma_setstartbuffer(chip, dma->dma, 0);  
         vortex_adb_setsrc(chip, dma->dma, runtime->rate, dir);  
     } else {  
         vortex_wtdma_setmode(chip, dma->dma, 1, dir, fmt, 0, 0);  
         // FIXME: Set rate (i guess using vortex_wt_writereg() somehow).  
         vortex_wtdma_setstartbuffer(chip, dma->dma, 0);  
     }  
     return 0;  
 }  
   
 /* trigger callback */  
 static int snd_vortex_pcm_trigger(snd_pcm_substream_t *substream, int cmd) {  
     chip_t *chip = snd_pcm_substream_chip(substream);  
     dma_t *dma = (dma_t*)substream->runtime->private_data;  
   
     switch (cmd) {  
     case SNDRV_PCM_TRIGGER_START:  
         // do something to start the PCM engine  
         printk(KERN_INFO "vortex: start %d\n", dma->dma);  
         if (substream->pcm == chip->pcm_adb) {  
             dma->fifo_enabled = 1;  
             vortex_adbdma_startfifo(chip, dma->dma);  
         } else {  
             dma->fifo_enabled = 1;  
             vortex_wtdma_startfifo(chip, dma->dma);  
         }  
         break;  
     case SNDRV_PCM_TRIGGER_STOP:  
         // do something to stop the PCM engine  
         printk(KERN_INFO "vortex: stop %d\n", dma->dma);  
         if (substream->pcm == chip->pcm_adb) {  
             dma->fifo_enabled = 0;  
             vortex_adbdma_stopfifo(chip, dma->dma);  
         }  
         else {  
             dma->fifo_enabled = 0;  
             vortex_wtdma_stopfifo(chip, dma->dma);  
         }  
         break;  
     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:  
         printk(KERN_INFO "vortex: pause %d\n", dma->dma);  
         if (substream->pcm == chip->pcm_adb)  
             vortex_adbdma_pausefifo(chip, dma->dma);  
         else  
             vortex_wtdma_pausefifo(chip, dma->dma);  
         break;  
     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:  
         printk(KERN_INFO "vortex: resume %d\n", dma->dma);  
         if (substream->pcm == chip->pcm_adb)  
             vortex_adbdma_resumefifo(chip, dma->dma);  
         else  
             vortex_wtdma_resumefifo(chip, dma->dma);  
         break;  
     default:  
         return -EINVAL;  
     }  
     return 0;  
 }  
   
 /* pointer callback */  
 static snd_pcm_uframes_t snd_vortex_pcm_pointer(snd_pcm_substream_t *substream) {  
     vortex_t *chip = snd_pcm_substream_chip(substream);  
     snd_pcm_uframes_t current_ptr = 0;  
         dma_t *dma = (dma_t*)substream->runtime->private_data;  
   
         spin_lock(&chip->lock);  
     if (substream->pcm == chip->pcm_adb)  
         current_ptr = vortex_adbdma_getlinearpos(chip, dma->dma);  
     else  
         current_ptr = vortex_wtdma_getlinearpos(chip, dma->dma);  
     //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);  
         spin_unlock(&chip->lock);  
     return (bytes_to_frames(substream->runtime, current_ptr));  
 }  
   
 /* operators */  
 static snd_pcm_ops_t snd_vortex_playback_ops = {  
     .open = snd_vortex_pcm_open,  
     .close = snd_vortex_pcm_close,  
     .ioctl = snd_pcm_lib_ioctl,  
     .hw_params = snd_vortex_pcm_hw_params,  
     .hw_free = snd_vortex_pcm_hw_free,  
     .prepare = snd_vortex_pcm_prepare,  
     .trigger = snd_vortex_pcm_trigger,  
     .pointer = snd_vortex_pcm_pointer,  
     //.page = snd_pcm_sgbuf_ops_page,  
 };  
   
 /*  
 *  definitions of capture are omitted here...  
 */  
   
 /* create a pcm device */  
 int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) {  
     snd_pcm_t *pcm;  
     int err;  
   
     if ((chip == 0)||(idx < 0)||(idx>1))  
         return -ENODEV;  
   
     if (idx == 0) {  
         if ((err = snd_pcm_new(chip->card, "Aureal Vortex ADB", idx, nr, nr, &pcm)) < 0)  
             return err;  
         strcpy(pcm->name, "adb");  
         chip->pcm_adb = pcm;  
     } else {  
         if ((err = snd_pcm_new(chip->card, "Aureal Vortex WT", idx, nr, 0, &pcm)) < 0)  
             return err;  
         strcpy(pcm->name, "wt");  
                 chip->pcm_wt = pcm;  
     }  
     pcm->private_data = chip;  
     /* set operators */  
     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vortex_playback_ops);  
     if (idx == 0)  
         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vortex_playback_ops);  
     /* pre-allocation of buffers */  
     snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci_dev, pcm, 0x10000, 0x10000);  
   
     return 0;  
 }  

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26