ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / sound / pcmcia / pdaudiocf / pdaudiocf_pcm.c
1 /*
2  * Driver for Sound Core PDAudioCF soundcards
3  *
4  * PCM part
5  *
6  * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
7  *
8  *   This program is free software; you can redistribute it and/or modify
9  *   it under the terms of the GNU General Public License as published by
10  *   the Free Software Foundation; either version 2 of the License, or
11  *   (at your option) any later version.
12  *
13  *   This program is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include <sound/driver.h>
24 #include <linux/slab.h>
25 #include <linux/vmalloc.h>
26 #include <linux/delay.h>
27 #include <sound/core.h>
28 #include <sound/asoundef.h>
29 #include "pdaudiocf.h"
30
31 #define chip_t  pdacf_t
32
33
34 /*
35  * we use a vmalloc'ed (sg-)buffer
36  */
37
38 /* get the physical page pointer on the given offset */
39 static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs, unsigned long offset)
40 {
41         void *pageptr = subs->runtime->dma_area + offset;
42         return vmalloc_to_page(pageptr);
43 }
44
45 /*
46  * hw_params callback
47  * NOTE: this may be called not only once per pcm open!
48  */
49 static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
50 {
51         snd_pcm_runtime_t *runtime = subs->runtime;
52         if (runtime->dma_area) {
53                 if (runtime->dma_bytes >= size)
54                         return 0; /* already enough large */
55                 vfree_nocheck(runtime->dma_area);
56         }
57         runtime->dma_area = vmalloc_nocheck(size);
58         if (! runtime->dma_area)
59                 return -ENOMEM;
60         runtime->dma_bytes = size;
61         return 0;
62 }
63
64 /*
65  * hw_free callback
66  * NOTE: this may be called not only once per pcm open!
67  */
68 static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
69 {
70         snd_pcm_runtime_t *runtime = subs->runtime;
71         if (runtime->dma_area) {
72                 vfree_nocheck(runtime->dma_area);
73                 runtime->dma_area = NULL;
74         }
75         return 0;
76 }
77
78 /*
79  * clear the SRAM contents
80  */
81 static int pdacf_pcm_clear_sram(pdacf_t *chip)
82 {
83         int max_loop = 64 * 1024;
84
85         while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {
86                 if (max_loop-- < 0)
87                         return -EIO;
88                 inw(chip->port + PDAUDIOCF_REG_MD);
89         }
90         return 0;
91 }
92
93 /*
94  * pdacf_pcm_trigger - trigger callback for capture
95  */
96 static int pdacf_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
97 {
98         pdacf_t *chip = snd_pcm_substream_chip(subs);
99         snd_pcm_runtime_t *runtime = subs->runtime;
100         int inc, ret = 0, rate;
101         unsigned short mask, val, tmp;
102
103         if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
104                 return -EBUSY;
105
106         switch (cmd) {
107         case SNDRV_PCM_TRIGGER_START:
108                 chip->pcm_hwptr = 0;
109                 chip->pcm_tdone = 0;
110                 /* fall thru */
111         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
112         case SNDRV_PCM_TRIGGER_RESUME:
113                 mask = 0;
114                 val = PDAUDIOCF_RECORD;
115                 inc = 1;
116                 rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);
117                 break;
118         case SNDRV_PCM_TRIGGER_STOP:
119         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
120         case SNDRV_PCM_TRIGGER_SUSPEND:
121                 mask = PDAUDIOCF_RECORD;
122                 val = 0;
123                 inc = -1;
124                 rate = 0;
125                 break;
126         default:
127                 return -EINVAL;
128         }
129         spin_lock(&chip->reg_lock);
130         chip->pcm_running += inc;
131         tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
132         if (chip->pcm_running) {
133                 if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
134                         chip->pcm_running -= inc;
135                         ret = -EIO;
136                         goto __end;
137                 }
138         }
139         tmp &= ~mask;
140         tmp |= val;
141         pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
142       __end:
143         spin_unlock(&chip->reg_lock);
144         snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
145         return ret;
146 }
147
148 /*
149  * pdacf_pcm_hw_params - hw_params callback for playback and capture
150  */
151 static int pdacf_pcm_hw_params(snd_pcm_substream_t *subs,
152                                      snd_pcm_hw_params_t *hw_params)
153 {
154         return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
155 }
156
157 /*
158  * pdacf_pcm_hw_free - hw_free callback for playback and capture
159  */
160 static int pdacf_pcm_hw_free(snd_pcm_substream_t *subs)
161 {
162         return snd_pcm_free_vmalloc_buffer(subs);
163 }
164
165 /*
166  * pdacf_pcm_prepare - prepare callback for playback and capture
167  */
168 static int pdacf_pcm_prepare(snd_pcm_substream_t *subs)
169 {
170         pdacf_t *chip = snd_pcm_substream_chip(subs);
171         snd_pcm_runtime_t *runtime = subs->runtime;
172         u16 val, nval, aval;
173
174         if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
175                 return -EBUSY;
176
177         chip->pcm_channels = runtime->channels;
178
179         chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;
180 #ifdef SNDRV_LITTLE_ENDIAN
181         chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;
182 #else
183         chip->pcm_swab = chip->pcm_little;
184 #endif
185
186         if (snd_pcm_format_unsigned(runtime->format))
187                 chip->pcm_xor = 0x80008000;
188
189         if (pdacf_pcm_clear_sram(chip) < 0)
190                 return -EIO;
191         
192         val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
193         nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);
194         switch (runtime->format) {
195         case SNDRV_PCM_FORMAT_S16_LE:
196         case SNDRV_PCM_FORMAT_S16_BE:
197                 break;
198         default: /* 24-bit */
199                 nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;
200                 break;
201         }
202         aval = 0;
203         chip->pcm_sample = 4;
204         switch (runtime->format) {
205         case SNDRV_PCM_FORMAT_S16_LE:
206         case SNDRV_PCM_FORMAT_S16_BE:
207                 aval = AK4117_DIF_16R;
208                 chip->pcm_frame = 2;
209                 chip->pcm_sample = 2;
210                 break;
211         case SNDRV_PCM_FORMAT_S24_3LE:
212         case SNDRV_PCM_FORMAT_S24_3BE:
213                 chip->pcm_sample = 3;
214                 /* fall trough */
215         default: /* 24-bit */
216                 aval = AK4117_DIF_24R;
217                 chip->pcm_frame = 3;
218                 chip->pcm_xor &= 0xffff0000;
219                 break;
220         }
221
222         if (val != nval) {
223                 snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);
224                 pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);
225         }
226
227         val = pdacf_reg_read(chip,  PDAUDIOCF_REG_IER);
228         val &= ~(PDAUDIOCF_IRQLVLEN1);
229         val |= PDAUDIOCF_IRQLVLEN0;
230         pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);
231
232         chip->pcm_size = runtime->buffer_size;
233         chip->pcm_period = runtime->period_size;
234         chip->pcm_area = runtime->dma_area;
235
236         return 0;
237 }
238
239
240 /*
241  * capture hw information
242  */
243
244 static snd_pcm_hardware_t pdacf_pcm_capture_hw = {
245         .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
246                                  SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
247                                  SNDRV_PCM_INFO_MMAP_VALID),
248         .formats =              SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
249                                 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
250                                 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
251         .rates =                SNDRV_PCM_RATE_32000 |
252                                 SNDRV_PCM_RATE_44100 |
253                                 SNDRV_PCM_RATE_48000 |
254                                 SNDRV_PCM_RATE_88200 |
255                                 SNDRV_PCM_RATE_96000 |
256                                 SNDRV_PCM_RATE_176400 |
257                                 SNDRV_PCM_RATE_192000,
258         .rate_min =             32000,
259         .rate_max =             192000,
260         .channels_min =         1,
261         .channels_max =         2,
262         .buffer_bytes_max =     (512*1024),
263         .period_bytes_min =     8*1024,
264         .period_bytes_max =     (64*1024),
265         .periods_min =          2,
266         .periods_max =          128,
267         .fifo_size =            0,
268 };
269
270
271 /*
272  * pdacf_pcm_capture_open - open callback for capture
273  */
274 static int pdacf_pcm_capture_open(snd_pcm_substream_t *subs)
275 {
276         snd_pcm_runtime_t *runtime = subs->runtime;
277         pdacf_t *chip = snd_pcm_substream_chip(subs);
278
279         if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
280                 return -EBUSY;
281
282         runtime->hw = pdacf_pcm_capture_hw;
283         runtime->private_data = chip;
284         chip->pcm_substream = subs;
285
286         return 0;
287 }
288
289 /*
290  * pdacf_pcm_capture_close - close callback for capture
291  */
292 static int pdacf_pcm_capture_close(snd_pcm_substream_t *subs)
293 {
294         pdacf_t *chip = snd_pcm_substream_chip(subs);
295
296         if (!chip)
297                 return -EINVAL;
298         pdacf_reinit(chip, 0);
299         chip->pcm_substream = NULL;
300         return 0;
301 }
302
303
304 /*
305  * pdacf_pcm_capture_pointer - pointer callback for capture
306  */
307 static snd_pcm_uframes_t pdacf_pcm_capture_pointer(snd_pcm_substream_t *subs)
308 {
309         pdacf_t *chip = snd_pcm_substream_chip(subs);
310         return chip->pcm_hwptr;
311 }
312
313 /*
314  * operators for PCM capture
315  */
316 static snd_pcm_ops_t pdacf_pcm_capture_ops = {
317         .open =         pdacf_pcm_capture_open,
318         .close =        pdacf_pcm_capture_close,
319         .ioctl =        snd_pcm_lib_ioctl,
320         .hw_params =    pdacf_pcm_hw_params,
321         .hw_free =      pdacf_pcm_hw_free,
322         .prepare =      pdacf_pcm_prepare,
323         .trigger =      pdacf_pcm_trigger,
324         .pointer =      pdacf_pcm_capture_pointer,
325         .page =         snd_pcm_get_vmalloc_page,
326 };
327
328
329 /*
330  * free callback for pcm
331  */
332 static void snd_pdacf_pcm_free(snd_pcm_t *pcm)
333 {
334         pdacf_t *chip = snd_magic_cast(pdacf_t, pcm->private_data, return);
335         chip->pcm = NULL;
336 }
337
338 /*
339  * snd_pdacf_pcm_new - create and initialize a pcm
340  */
341 int snd_pdacf_pcm_new(pdacf_t *chip)
342 {
343         snd_pcm_t *pcm;
344         int err;
345
346         err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);
347         if (err < 0)
348                 return err;
349                 
350         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);
351
352         pcm->private_data = chip;
353         pcm->private_free = snd_pdacf_pcm_free;
354         pcm->info_flags = 0;
355         strcpy(pcm->name, chip->card->shortname);
356         chip->pcm = pcm;
357         
358         err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
359         if (err < 0)
360                 return err;
361
362         return 0;
363 }