/[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.7 by mjander, Thu Aug 7 01:58:51 2003 UTC revision 1.8 by vizard, Sun Aug 10 20:00:34 2003 UTC
# Line 1  Line 1 
1  #define __NO_VERSION__  /*
2  #include "../../alsa-kernel/pci/au88x0/au88x0_pcm.c"   * Vortex PCM ALSA driver.
3     *
4     * Supports ADB and WT DMA. Unfortunately, WT routing is still a
5     * mistery. To discover that, we need to disassemble the windoze
6     * driver too.
7     *
8     *
9     */
10    
11    #include <sound/driver.h>
12    #include <linux/time.h>
13    #include <sound/core.h>
14    #include <sound/pcm.h>
15    #include <sound/pcm_params.h>
16    #include "au88x0.h"
17    
18    #define chip_t vortex_t
19    
20    /* hardware definition */
21    static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
22        .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME| SNDRV_PCM_INFO_PAUSE |
23                 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID),
24        .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
25                 SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
26        .rates = SNDRV_PCM_RATE_CONTINUOUS,
27        .rate_min = 5000,
28        .rate_max = 48000,
29        .channels_min = 1,
30        .channels_max = 2,
31        .buffer_bytes_max = 0x10000,
32        .period_bytes_min = 0x0100,
33        .period_bytes_max = 0x1000,
34        .periods_min = 1,
35        .periods_max = 64,
36    };
37    
38    static snd_pcm_hardware_t snd_vortex_playback_hw_wt = {
39        .info = (SNDRV_PCM_INFO_MMAP |
40                 SNDRV_PCM_INFO_INTERLEAVED |
41                 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
42        .formats = SNDRV_PCM_FMTBIT_S16_LE,
43        .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000,
44        .rate_min = 8000,
45        .rate_max = 48000,
46        .channels_min = 1,
47        .channels_max = 2,
48        .buffer_bytes_max = 0x10000,
49        .period_bytes_min = 0x0400,
50        .period_bytes_max = 0x1000,
51        .periods_min = 1,
52        .periods_max = 64,
53    };
54    
55    /* open callback */
56    static int snd_vortex_pcm_open(snd_pcm_substream_t *substream) {
57        chip_t *chip = snd_pcm_substream_chip(substream);
58        snd_pcm_runtime_t *runtime = substream->runtime;
59            int dma, err;
60            
61            /* Force equal size periods */
62            if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
63            return err;
64            /* Force DMA 32 bit alignment */
65            if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4)) < 0)
66            return err;
67            
68        if (substream->pcm == chip->pcm_adb) {
69                    runtime->hw = snd_vortex_playback_hw_adb;
70                    dma = vortex_getadb(chip);
71                    if (dma < 0)
72                            return -EBUSY;
73                    substream->runtime->private_data = &chip->dma_adb[dma];
74            chip->dma_adb[dma].substream = substream;
75        } else {
76                    runtime->hw = snd_vortex_playback_hw_wt;
77                    dma = vortex_getwt(chip);
78                    if (dma < 0)
79                            return -EBUSY;
80                    substream->runtime->private_data = &chip->dma_wt[dma];
81            chip->dma_wt[dma].substream = substream;
82        }
83        return 0;
84    }
85    
86    /* close callback */
87    static int snd_vortex_pcm_close(snd_pcm_substream_t *substream) {
88        //vortex_t *chip = snd_pcm_substream_chip(substream);
89            dma_t *dma = (dma_t*)substream->runtime->private_data;
90    
91        // the hardware-specific codes will be here
92        // Dealloc DMA and remove audio route.
93        dma->substream = NULL;
94            dma->nr_ch = 0;
95        substream->runtime->private_data = NULL;
96        return 0;
97    }
98    
99    /* hw_params callback */
100    static int snd_vortex_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params) {
101            chip_t *chip = snd_pcm_substream_chip(substream);
102            snd_pcm_runtime_t *runtime = substream->runtime;
103            dma_t *dma = (dma_t*)substream->runtime->private_data;
104    
105            int err;
106    
107            // Alloc buffer memory.
108            err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
109            if (err < 0) {
110                    printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
111                    return err;
112            }
113    
114            printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
115                    params_period_bytes(hw_params), params_channels(hw_params));
116    
117            if (params_buffer_bytes(hw_params) != (params_periods(hw_params)*params_period_bytes(hw_params)))
118                    printk(KERN_INFO "vortex: Warning: Click condition (non integer period count).\n");
119            
120            // Make audio routes and config buffer DMA.
121            if (substream->pcm == chip->pcm_adb) {
122                    vortex_adbdma_setbuffers(chip, dma->dma, (u32)(runtime->dma_addr), params_period_bytes(hw_params), params_periods(hw_params));
123                    //if (dma->nr_ch != 0)
124                            vortex_adb_waveroute(chip, dma->dma, 0);
125                    //if (params_channels(hw_params) != 0)
126                            vortex_adb_waveroute(chip, dma->dma, params_channels(hw_params));
127            } else {
128                    vortex_wtdma_setbuffers(chip, dma->dma, (u32)(runtime->dma_addr), params_period_bytes(hw_params), params_periods(hw_params));
129                    if (dma->nr_ch)
130                            vortex_wt_waveroute(chip, dma->dma, 0);
131                    if (params_channels(hw_params))
132                            vortex_wt_waveroute(chip, dma->dma, params_channels(hw_params));
133            }
134            return 0;
135    }
136    
137    /* hw_free callback */
138    static int snd_vortex_pcm_hw_free(snd_pcm_substream_t *substream) {
139        chip_t *chip = snd_pcm_substream_chip(substream);
140        dma_t *dma = (dma_t*)substream->runtime->private_data;
141    
142        // Delete audio routes.
143        if (substream->pcm == chip->pcm_adb)
144            vortex_adb_waveroute(chip, dma->dma, 0);
145        else
146            vortex_wt_waveroute(chip, dma->dma, 0);
147    
148        return snd_pcm_lib_free_pages(substream);
149    }
150    
151    /* prepare callback */
152    static int snd_vortex_pcm_prepare(snd_pcm_substream_t *substream) {
153        vortex_t *chip = snd_pcm_substream_chip(substream);
154        snd_pcm_runtime_t *runtime = substream->runtime;
155            dma_t *dma = (dma_t*)substream->runtime->private_data;
156        int fmt, dir;
157    
158        // set up the hardware with the current configuration.
159            if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
160                    dir = 1;
161            else
162                    dir = 0;
163        fmt = vortex_alsafmt_aspfmt(runtime->format);
164        if (substream->pcm == chip->pcm_adb) {
165            vortex_adbdma_setmode(chip, dma->dma, 1, dir, fmt, 0/*?*/, 0);
166            vortex_adbdma_setstartbuffer(chip, dma->dma, 0);
167            vortex_adb_setsrc(chip, dma->dma, runtime->rate, dir);
168        } else {
169            vortex_wtdma_setmode(chip, dma->dma, 1, dir, fmt, 0, 0);
170            // FIXME: Set rate (i guess using vortex_wt_writereg() somehow).
171            vortex_wtdma_setstartbuffer(chip, dma->dma, 0);
172        }
173        return 0;
174    }
175    
176    /* trigger callback */
177    static int snd_vortex_pcm_trigger(snd_pcm_substream_t *substream, int cmd) {
178        chip_t *chip = snd_pcm_substream_chip(substream);
179        dma_t *dma = (dma_t*)substream->runtime->private_data;
180    
181        switch (cmd) {
182        case SNDRV_PCM_TRIGGER_START:
183            // do something to start the PCM engine
184            printk(KERN_INFO "vortex: start %d\n", dma->dma);
185            if (substream->pcm == chip->pcm_adb) {
186                dma->fifo_enabled = 1;
187                vortex_adbdma_startfifo(chip, dma->dma);
188            } else {
189                dma->fifo_enabled = 1;
190                vortex_wtdma_startfifo(chip, dma->dma);
191            }
192            break;
193        case SNDRV_PCM_TRIGGER_STOP:
194            // do something to stop the PCM engine
195            printk(KERN_INFO "vortex: stop %d\n", dma->dma);
196            if (substream->pcm == chip->pcm_adb) {
197                dma->fifo_enabled = 0;
198                vortex_adbdma_stopfifo(chip, dma->dma);
199            }
200            else {
201                dma->fifo_enabled = 0;
202                vortex_wtdma_stopfifo(chip, dma->dma);
203            }
204            break;
205        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
206            printk(KERN_INFO "vortex: pause %d\n", dma->dma);
207            if (substream->pcm == chip->pcm_adb)
208                vortex_adbdma_pausefifo(chip, dma->dma);
209            else
210                vortex_wtdma_pausefifo(chip, dma->dma);
211            break;
212        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
213            printk(KERN_INFO "vortex: resume %d\n", dma->dma);
214            if (substream->pcm == chip->pcm_adb)
215                vortex_adbdma_resumefifo(chip, dma->dma);
216            else
217                vortex_wtdma_resumefifo(chip, dma->dma);
218            break;
219        default:
220            return -EINVAL;
221        }
222        return 0;
223    }
224    
225    /* pointer callback */
226    static snd_pcm_uframes_t snd_vortex_pcm_pointer(snd_pcm_substream_t *substream) {
227        vortex_t *chip = snd_pcm_substream_chip(substream);
228        snd_pcm_uframes_t current_ptr = 0;
229            dma_t *dma = (dma_t*)substream->runtime->private_data;
230    
231            spin_lock(&chip->lock);
232        if (substream->pcm == chip->pcm_adb)
233            current_ptr = vortex_adbdma_getlinearpos(chip, dma->dma);
234        else
235            current_ptr = vortex_wtdma_getlinearpos(chip, dma->dma);
236        //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);
237            spin_unlock(&chip->lock);
238        return (bytes_to_frames(substream->runtime, current_ptr));
239    }
240    
241    /* operators */
242    static snd_pcm_ops_t snd_vortex_playback_ops = {
243        .open = snd_vortex_pcm_open,
244        .close = snd_vortex_pcm_close,
245        .ioctl = snd_pcm_lib_ioctl,
246        .hw_params = snd_vortex_pcm_hw_params,
247        .hw_free = snd_vortex_pcm_hw_free,
248        .prepare = snd_vortex_pcm_prepare,
249        .trigger = snd_vortex_pcm_trigger,
250        .pointer = snd_vortex_pcm_pointer,
251        //.page = snd_pcm_sgbuf_ops_page,
252    };
253    
254    /*
255    *  definitions of capture are omitted here...
256    */
257    
258    /* create a pcm device */
259    int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) {
260        snd_pcm_t *pcm;
261        int err;
262    
263        if ((chip == 0)||(idx < 0)||(idx>1))
264            return -ENODEV;
265    
266        if (idx == 0) {
267            if ((err = snd_pcm_new(chip->card, "Aureal Vortex ADB", idx, nr, nr, &pcm)) < 0)
268                return err;
269            strcpy(pcm->name, "adb");
270            chip->pcm_adb = pcm;
271        } else {
272            if ((err = snd_pcm_new(chip->card, "Aureal Vortex WT", idx, nr, 0, &pcm)) < 0)
273                return err;
274            strcpy(pcm->name, "wt");
275                    chip->pcm_wt = pcm;
276        }
277        pcm->private_data = chip;
278        /* set operators */
279        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vortex_playback_ops);
280        if (idx == 0)
281            snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vortex_playback_ops);
282        /* pre-allocation of buffers */
283        snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci_dev, pcm, 0x10000, 0x10000);
284    
285        return 0;
286    }

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

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