2 * Driver for Sound Core PDAudioCF soundcards
6 * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
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.
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.
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
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"
33 * we use a vmalloc'ed (sg-)buffer
36 /* get the physical page pointer on the given offset */
37 static struct page
*snd_pcm_get_vmalloc_page(snd_pcm_substream_t
*subs
, unsigned long offset
)
39 void *pageptr
= subs
->runtime
->dma_area
+ offset
;
40 return vmalloc_to_page(pageptr
);
45 * NOTE: this may be called not only once per pcm open!
47 static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t
*subs
, size_t size
)
49 snd_pcm_runtime_t
*runtime
= subs
->runtime
;
50 if (runtime
->dma_area
) {
51 if (runtime
->dma_bytes
>= size
)
52 return 0; /* already enough large */
53 vfree_nocheck(runtime
->dma_area
);
55 runtime
->dma_area
= vmalloc_nocheck(size
);
56 if (! runtime
->dma_area
)
58 runtime
->dma_bytes
= size
;
64 * NOTE: this may be called not only once per pcm open!
66 static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t
*subs
)
68 snd_pcm_runtime_t
*runtime
= subs
->runtime
;
69 if (runtime
->dma_area
) {
70 vfree_nocheck(runtime
->dma_area
);
71 runtime
->dma_area
= NULL
;
77 * clear the SRAM contents
79 static int pdacf_pcm_clear_sram(pdacf_t
*chip
)
81 int max_loop
= 64 * 1024;
83 while (inw(chip
->port
+ PDAUDIOCF_REG_RDP
) != inw(chip
->port
+ PDAUDIOCF_REG_WDP
)) {
86 inw(chip
->port
+ PDAUDIOCF_REG_MD
);
92 * pdacf_pcm_trigger - trigger callback for capture
94 static int pdacf_pcm_trigger(snd_pcm_substream_t
*subs
, int cmd
)
96 pdacf_t
*chip
= snd_pcm_substream_chip(subs
);
97 snd_pcm_runtime_t
*runtime
= subs
->runtime
;
98 int inc
, ret
= 0, rate
;
99 unsigned short mask
, val
, tmp
;
101 if (chip
->chip_status
& PDAUDIOCF_STAT_IS_STALE
)
105 case SNDRV_PCM_TRIGGER_START
:
109 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
110 case SNDRV_PCM_TRIGGER_RESUME
:
112 val
= PDAUDIOCF_RECORD
;
114 rate
= snd_ak4117_check_rate_and_errors(chip
->ak4117
, AK4117_CHECK_NO_STAT
|AK4117_CHECK_NO_RATE
);
116 case SNDRV_PCM_TRIGGER_STOP
:
117 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
118 case SNDRV_PCM_TRIGGER_SUSPEND
:
119 mask
= PDAUDIOCF_RECORD
;
127 spin_lock(&chip
->reg_lock
);
128 chip
->pcm_running
+= inc
;
129 tmp
= pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
);
130 if (chip
->pcm_running
) {
131 if ((chip
->ak4117
->rcs0
& AK4117_UNLCK
) || runtime
->rate
!= rate
) {
132 chip
->pcm_running
-= inc
;
139 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, tmp
);
141 spin_unlock(&chip
->reg_lock
);
142 snd_ak4117_check_rate_and_errors(chip
->ak4117
, AK4117_CHECK_NO_RATE
);
147 * pdacf_pcm_hw_params - hw_params callback for playback and capture
149 static int pdacf_pcm_hw_params(snd_pcm_substream_t
*subs
,
150 snd_pcm_hw_params_t
*hw_params
)
152 return snd_pcm_alloc_vmalloc_buffer(subs
, params_buffer_bytes(hw_params
));
156 * pdacf_pcm_hw_free - hw_free callback for playback and capture
158 static int pdacf_pcm_hw_free(snd_pcm_substream_t
*subs
)
160 return snd_pcm_free_vmalloc_buffer(subs
);
164 * pdacf_pcm_prepare - prepare callback for playback and capture
166 static int pdacf_pcm_prepare(snd_pcm_substream_t
*subs
)
168 pdacf_t
*chip
= snd_pcm_substream_chip(subs
);
169 snd_pcm_runtime_t
*runtime
= subs
->runtime
;
172 if (chip
->chip_status
& PDAUDIOCF_STAT_IS_STALE
)
175 chip
->pcm_channels
= runtime
->channels
;
177 chip
->pcm_little
= snd_pcm_format_little_endian(runtime
->format
) > 0;
178 #ifdef SNDRV_LITTLE_ENDIAN
179 chip
->pcm_swab
= snd_pcm_format_big_endian(runtime
->format
) > 0;
181 chip
->pcm_swab
= chip
->pcm_little
;
184 if (snd_pcm_format_unsigned(runtime
->format
))
185 chip
->pcm_xor
= 0x80008000;
187 if (pdacf_pcm_clear_sram(chip
) < 0)
190 val
= nval
= pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
);
191 nval
&= ~(PDAUDIOCF_DATAFMT0
|PDAUDIOCF_DATAFMT1
);
192 switch (runtime
->format
) {
193 case SNDRV_PCM_FORMAT_S16_LE
:
194 case SNDRV_PCM_FORMAT_S16_BE
:
196 default: /* 24-bit */
197 nval
|= PDAUDIOCF_DATAFMT0
| PDAUDIOCF_DATAFMT1
;
201 chip
->pcm_sample
= 4;
202 switch (runtime
->format
) {
203 case SNDRV_PCM_FORMAT_S16_LE
:
204 case SNDRV_PCM_FORMAT_S16_BE
:
205 aval
= AK4117_DIF_16R
;
207 chip
->pcm_sample
= 2;
209 case SNDRV_PCM_FORMAT_S24_3LE
:
210 case SNDRV_PCM_FORMAT_S24_3BE
:
211 chip
->pcm_sample
= 3;
213 default: /* 24-bit */
214 aval
= AK4117_DIF_24R
;
216 chip
->pcm_xor
&= 0xffff0000;
221 snd_ak4117_reg_write(chip
->ak4117
, AK4117_REG_IO
, AK4117_DIF2
|AK4117_DIF1
|AK4117_DIF0
, aval
);
222 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, nval
);
225 val
= pdacf_reg_read(chip
, PDAUDIOCF_REG_IER
);
226 val
&= ~(PDAUDIOCF_IRQLVLEN1
);
227 val
|= PDAUDIOCF_IRQLVLEN0
;
228 pdacf_reg_write(chip
, PDAUDIOCF_REG_IER
, val
);
230 chip
->pcm_size
= runtime
->buffer_size
;
231 chip
->pcm_period
= runtime
->period_size
;
232 chip
->pcm_area
= runtime
->dma_area
;
239 * capture hw information
242 static snd_pcm_hardware_t pdacf_pcm_capture_hw
= {
243 .info
= (SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_INTERLEAVED
|
244 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
|
245 SNDRV_PCM_INFO_MMAP_VALID
),
246 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S16_BE
|
247 SNDRV_PCM_FMTBIT_S24_3LE
| SNDRV_PCM_FMTBIT_S24_3BE
|
248 SNDRV_PCM_FMTBIT_S32_LE
| SNDRV_PCM_FMTBIT_S32_BE
,
249 .rates
= SNDRV_PCM_RATE_32000
|
250 SNDRV_PCM_RATE_44100
|
251 SNDRV_PCM_RATE_48000
|
252 SNDRV_PCM_RATE_88200
|
253 SNDRV_PCM_RATE_96000
|
254 SNDRV_PCM_RATE_176400
|
255 SNDRV_PCM_RATE_192000
,
260 .buffer_bytes_max
= (512*1024),
261 .period_bytes_min
= 8*1024,
262 .period_bytes_max
= (64*1024),
270 * pdacf_pcm_capture_open - open callback for capture
272 static int pdacf_pcm_capture_open(snd_pcm_substream_t
*subs
)
274 snd_pcm_runtime_t
*runtime
= subs
->runtime
;
275 pdacf_t
*chip
= snd_pcm_substream_chip(subs
);
277 if (chip
->chip_status
& PDAUDIOCF_STAT_IS_STALE
)
280 runtime
->hw
= pdacf_pcm_capture_hw
;
281 runtime
->private_data
= chip
;
282 chip
->pcm_substream
= subs
;
288 * pdacf_pcm_capture_close - close callback for capture
290 static int pdacf_pcm_capture_close(snd_pcm_substream_t
*subs
)
292 pdacf_t
*chip
= snd_pcm_substream_chip(subs
);
296 pdacf_reinit(chip
, 0);
297 chip
->pcm_substream
= NULL
;
303 * pdacf_pcm_capture_pointer - pointer callback for capture
305 static snd_pcm_uframes_t
pdacf_pcm_capture_pointer(snd_pcm_substream_t
*subs
)
307 pdacf_t
*chip
= snd_pcm_substream_chip(subs
);
308 return chip
->pcm_hwptr
;
312 * operators for PCM capture
314 static snd_pcm_ops_t pdacf_pcm_capture_ops
= {
315 .open
= pdacf_pcm_capture_open
,
316 .close
= pdacf_pcm_capture_close
,
317 .ioctl
= snd_pcm_lib_ioctl
,
318 .hw_params
= pdacf_pcm_hw_params
,
319 .hw_free
= pdacf_pcm_hw_free
,
320 .prepare
= pdacf_pcm_prepare
,
321 .trigger
= pdacf_pcm_trigger
,
322 .pointer
= pdacf_pcm_capture_pointer
,
323 .page
= snd_pcm_get_vmalloc_page
,
328 * free callback for pcm
330 static void snd_pdacf_pcm_free(snd_pcm_t
*pcm
)
332 pdacf_t
*chip
= pcm
->private_data
;
337 * snd_pdacf_pcm_new - create and initialize a pcm
339 int snd_pdacf_pcm_new(pdacf_t
*chip
)
344 err
= snd_pcm_new(chip
->card
, "PDAudioCF", 0, 0, 1, &pcm
);
348 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &pdacf_pcm_capture_ops
);
350 pcm
->private_data
= chip
;
351 pcm
->private_free
= snd_pdacf_pcm_free
;
353 strcpy(pcm
->name
, chip
->card
->shortname
);
356 err
= snd_ak4117_build(chip
->ak4117
, pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
);