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 
32 /*
33  * we use a vmalloc'ed (sg-)buffer
34  */
35 
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)
38 {
39 	void *pageptr = subs->runtime->dma_area + offset;
40 	return vmalloc_to_page(pageptr);
41 }
42 
43 /*
44  * hw_params callback
45  * NOTE: this may be called not only once per pcm open!
46  */
47 static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
48 {
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);
54 	}
55 	runtime->dma_area = vmalloc_nocheck(size);
56 	if (! runtime->dma_area)
57 		return -ENOMEM;
58 	runtime->dma_bytes = size;
59 	return 0;
60 }
61 
62 /*
63  * hw_free callback
64  * NOTE: this may be called not only once per pcm open!
65  */
66 static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
67 {
68 	snd_pcm_runtime_t *runtime = subs->runtime;
69 	if (runtime->dma_area) {
70 		vfree_nocheck(runtime->dma_area);
71 		runtime->dma_area = NULL;
72 	}
73 	return 0;
74 }
75 
76 /*
77  * clear the SRAM contents
78  */
79 static int pdacf_pcm_clear_sram(pdacf_t *chip)
80 {
81 	int max_loop = 64 * 1024;
82 
83 	while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {
84 		if (max_loop-- < 0)
85 			return -EIO;
86 		inw(chip->port + PDAUDIOCF_REG_MD);
87 	}
88 	return 0;
89 }
90 
91 /*
92  * pdacf_pcm_trigger - trigger callback for capture
93  */
94 static int pdacf_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
95 {
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;
100 
101 	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
102 		return -EBUSY;
103 
104 	switch (cmd) {
105 	case SNDRV_PCM_TRIGGER_START:
106 		chip->pcm_hwptr = 0;
107 		chip->pcm_tdone = 0;
108 		/* fall thru */
109 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
110 	case SNDRV_PCM_TRIGGER_RESUME:
111 		mask = 0;
112 		val = PDAUDIOCF_RECORD;
113 		inc = 1;
114 		rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);
115 		break;
116 	case SNDRV_PCM_TRIGGER_STOP:
117 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
118 	case SNDRV_PCM_TRIGGER_SUSPEND:
119 		mask = PDAUDIOCF_RECORD;
120 		val = 0;
121 		inc = -1;
122 		rate = 0;
123 		break;
124 	default:
125 		return -EINVAL;
126 	}
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;
133 			ret = -EIO;
134 			goto __end;
135 		}
136 	}
137 	tmp &= ~mask;
138 	tmp |= val;
139 	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
140       __end:
141 	spin_unlock(&chip->reg_lock);
142 	snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
143 	return ret;
144 }
145 
146 /*
147  * pdacf_pcm_hw_params - hw_params callback for playback and capture
148  */
149 static int pdacf_pcm_hw_params(snd_pcm_substream_t *subs,
150 				     snd_pcm_hw_params_t *hw_params)
151 {
152 	return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
153 }
154 
155 /*
156  * pdacf_pcm_hw_free - hw_free callback for playback and capture
157  */
158 static int pdacf_pcm_hw_free(snd_pcm_substream_t *subs)
159 {
160 	return snd_pcm_free_vmalloc_buffer(subs);
161 }
162 
163 /*
164  * pdacf_pcm_prepare - prepare callback for playback and capture
165  */
166 static int pdacf_pcm_prepare(snd_pcm_substream_t *subs)
167 {
168 	pdacf_t *chip = snd_pcm_substream_chip(subs);
169 	snd_pcm_runtime_t *runtime = subs->runtime;
170 	u16 val, nval, aval;
171 
172 	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
173 		return -EBUSY;
174 
175 	chip->pcm_channels = runtime->channels;
176 
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;
180 #else
181 	chip->pcm_swab = chip->pcm_little;
182 #endif
183 
184 	if (snd_pcm_format_unsigned(runtime->format))
185 		chip->pcm_xor = 0x80008000;
186 
187 	if (pdacf_pcm_clear_sram(chip) < 0)
188 		return -EIO;
189 
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:
195 		break;
196 	default: /* 24-bit */
197 		nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;
198 		break;
199 	}
200 	aval = 0;
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;
206 		chip->pcm_frame = 2;
207 		chip->pcm_sample = 2;
208 		break;
209 	case SNDRV_PCM_FORMAT_S24_3LE:
210 	case SNDRV_PCM_FORMAT_S24_3BE:
211 		chip->pcm_sample = 3;
212 		/* fall trough */
213 	default: /* 24-bit */
214 		aval = AK4117_DIF_24R;
215 		chip->pcm_frame = 3;
216 		chip->pcm_xor &= 0xffff0000;
217 		break;
218 	}
219 
220 	if (val != nval) {
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);
223 	}
224 
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);
229 
230 	chip->pcm_size = runtime->buffer_size;
231 	chip->pcm_period = runtime->period_size;
232 	chip->pcm_area = runtime->dma_area;
233 
234 	return 0;
235 }
236 
237 
238 /*
239  * capture hw information
240  */
241 
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,
256 	.rate_min =		32000,
257 	.rate_max =		192000,
258 	.channels_min =		1,
259 	.channels_max =		2,
260 	.buffer_bytes_max =	(512*1024),
261 	.period_bytes_min =	8*1024,
262 	.period_bytes_max =	(64*1024),
263 	.periods_min =		2,
264 	.periods_max =		128,
265 	.fifo_size =		0,
266 };
267 
268 
269 /*
270  * pdacf_pcm_capture_open - open callback for capture
271  */
272 static int pdacf_pcm_capture_open(snd_pcm_substream_t *subs)
273 {
274 	snd_pcm_runtime_t *runtime = subs->runtime;
275 	pdacf_t *chip = snd_pcm_substream_chip(subs);
276 
277 	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
278 		return -EBUSY;
279 
280 	runtime->hw = pdacf_pcm_capture_hw;
281 	runtime->private_data = chip;
282 	chip->pcm_substream = subs;
283 
284 	return 0;
285 }
286 
287 /*
288  * pdacf_pcm_capture_close - close callback for capture
289  */
290 static int pdacf_pcm_capture_close(snd_pcm_substream_t *subs)
291 {
292 	pdacf_t *chip = snd_pcm_substream_chip(subs);
293 
294 	if (!chip)
295 		return -EINVAL;
296 	pdacf_reinit(chip, 0);
297 	chip->pcm_substream = NULL;
298 	return 0;
299 }
300 
301 
302 /*
303  * pdacf_pcm_capture_pointer - pointer callback for capture
304  */
305 static snd_pcm_uframes_t pdacf_pcm_capture_pointer(snd_pcm_substream_t *subs)
306 {
307 	pdacf_t *chip = snd_pcm_substream_chip(subs);
308 	return chip->pcm_hwptr;
309 }
310 
311 /*
312  * operators for PCM capture
313  */
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,
324 };
325 
326 
327 /*
328  * free callback for pcm
329  */
330 static void snd_pdacf_pcm_free(snd_pcm_t *pcm)
331 {
332 	pdacf_t *chip = pcm->private_data;
333 	chip->pcm = NULL;
334 }
335 
336 /*
337  * snd_pdacf_pcm_new - create and initialize a pcm
338  */
339 int snd_pdacf_pcm_new(pdacf_t *chip)
340 {
341 	snd_pcm_t *pcm;
342 	int err;
343 
344 	err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);
345 	if (err < 0)
346 		return err;
347 
348 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);
349 
350 	pcm->private_data = chip;
351 	pcm->private_free = snd_pdacf_pcm_free;
352 	pcm->info_flags = 0;
353 	strcpy(pcm->name, chip->card->shortname);
354 	chip->pcm = pcm;
355 
356 	err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
357 	if (err < 0)
358 		return err;
359 
360 	return 0;
361 }
362