• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/sound/pci/ctxfi/
1/**
2 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
3 *
4 * This source file is released under GPL v2 license (no other versions).
5 * See the COPYING file included in the main directory of this source
6 * distribution for the license terms and conditions.
7 *
8 * @File	ctpcm.c
9 *
10 * @Brief
11 * This file contains the definition of the pcm device functions.
12 *
13 * @Author	Liu Chun
14 * @Date 	Apr 2 2008
15 *
16 */
17
18#include "ctpcm.h"
19#include "cttimer.h"
20#include <linux/slab.h>
21#include <sound/pcm.h>
22
23/* Hardware descriptions for playback */
24static struct snd_pcm_hardware ct_pcm_playback_hw = {
25	.info			= (SNDRV_PCM_INFO_MMAP |
26				   SNDRV_PCM_INFO_INTERLEAVED |
27				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
28				   SNDRV_PCM_INFO_MMAP_VALID |
29				   SNDRV_PCM_INFO_PAUSE),
30	.formats		= (SNDRV_PCM_FMTBIT_U8 |
31				   SNDRV_PCM_FMTBIT_S16_LE |
32				   SNDRV_PCM_FMTBIT_S24_3LE |
33				   SNDRV_PCM_FMTBIT_S32_LE |
34				   SNDRV_PCM_FMTBIT_FLOAT_LE),
35	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
36				   SNDRV_PCM_RATE_8000_192000),
37	.rate_min		= 8000,
38	.rate_max		= 192000,
39	.channels_min		= 1,
40	.channels_max		= 2,
41	.buffer_bytes_max	= (128*1024),
42	.period_bytes_min	= (64),
43	.period_bytes_max	= (128*1024),
44	.periods_min		= 2,
45	.periods_max		= 1024,
46	.fifo_size		= 0,
47};
48
49static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
50	.info			= (SNDRV_PCM_INFO_MMAP |
51				   SNDRV_PCM_INFO_INTERLEAVED |
52				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
53				   SNDRV_PCM_INFO_MMAP_VALID |
54				   SNDRV_PCM_INFO_PAUSE),
55	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
56	.rates			= (SNDRV_PCM_RATE_48000 |
57				   SNDRV_PCM_RATE_44100 |
58				   SNDRV_PCM_RATE_32000),
59	.rate_min		= 32000,
60	.rate_max		= 48000,
61	.channels_min		= 2,
62	.channels_max		= 2,
63	.buffer_bytes_max	= (128*1024),
64	.period_bytes_min	= (64),
65	.period_bytes_max	= (128*1024),
66	.periods_min		= 2,
67	.periods_max		= 1024,
68	.fifo_size		= 0,
69};
70
71/* Hardware descriptions for capture */
72static struct snd_pcm_hardware ct_pcm_capture_hw = {
73	.info			= (SNDRV_PCM_INFO_MMAP |
74				   SNDRV_PCM_INFO_INTERLEAVED |
75				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
76				   SNDRV_PCM_INFO_PAUSE |
77				   SNDRV_PCM_INFO_MMAP_VALID),
78	.formats		= (SNDRV_PCM_FMTBIT_U8 |
79				   SNDRV_PCM_FMTBIT_S16_LE |
80				   SNDRV_PCM_FMTBIT_S24_3LE |
81				   SNDRV_PCM_FMTBIT_S32_LE |
82				   SNDRV_PCM_FMTBIT_FLOAT_LE),
83	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
84				   SNDRV_PCM_RATE_8000_96000),
85	.rate_min		= 8000,
86	.rate_max		= 96000,
87	.channels_min		= 1,
88	.channels_max		= 2,
89	.buffer_bytes_max	= (128*1024),
90	.period_bytes_min	= (384),
91	.period_bytes_max	= (64*1024),
92	.periods_min		= 2,
93	.periods_max		= 1024,
94	.fifo_size		= 0,
95};
96
97static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
98{
99	struct ct_atc_pcm *apcm = atc_pcm;
100
101	if (!apcm->substream)
102		return;
103
104	snd_pcm_period_elapsed(apcm->substream);
105}
106
107static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
108{
109	struct ct_atc_pcm *apcm = runtime->private_data;
110	struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
111
112	atc->pcm_release_resources(atc, apcm);
113	ct_timer_instance_free(apcm->timer);
114	kfree(apcm);
115	runtime->private_data = NULL;
116}
117
118/* pcm playback operations */
119static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
120{
121	struct ct_atc *atc = snd_pcm_substream_chip(substream);
122	struct snd_pcm_runtime *runtime = substream->runtime;
123	struct ct_atc_pcm *apcm;
124	int err;
125
126	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
127	if (!apcm)
128		return -ENOMEM;
129
130	apcm->substream = substream;
131	apcm->interrupt = ct_atc_pcm_interrupt;
132	runtime->private_data = apcm;
133	runtime->private_free = ct_atc_pcm_free_substream;
134	if (IEC958 == substream->pcm->device) {
135		runtime->hw = ct_spdif_passthru_playback_hw;
136		atc->spdif_out_passthru(atc, 1);
137	} else {
138		runtime->hw = ct_pcm_playback_hw;
139		if (FRONT == substream->pcm->device)
140			runtime->hw.channels_max = 8;
141	}
142
143	err = snd_pcm_hw_constraint_integer(runtime,
144					    SNDRV_PCM_HW_PARAM_PERIODS);
145	if (err < 0) {
146		kfree(apcm);
147		return err;
148	}
149	err = snd_pcm_hw_constraint_minmax(runtime,
150					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
151					   1024, UINT_MAX);
152	if (err < 0) {
153		kfree(apcm);
154		return err;
155	}
156
157	apcm->timer = ct_timer_instance_new(atc->timer, apcm);
158	if (!apcm->timer)
159		return -ENOMEM;
160
161	return 0;
162}
163
164static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
165{
166	struct ct_atc *atc = snd_pcm_substream_chip(substream);
167
168	/* TODO: Notify mixer inactive. */
169	if (IEC958 == substream->pcm->device)
170		atc->spdif_out_passthru(atc, 0);
171
172	/* The ct_atc_pcm object will be freed by runtime->private_free */
173
174	return 0;
175}
176
177static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
178				     struct snd_pcm_hw_params *hw_params)
179{
180	struct ct_atc *atc = snd_pcm_substream_chip(substream);
181	struct ct_atc_pcm *apcm = substream->runtime->private_data;
182	int err;
183
184	err = snd_pcm_lib_malloc_pages(substream,
185					params_buffer_bytes(hw_params));
186	if (err < 0)
187		return err;
188	/* clear previous resources */
189	atc->pcm_release_resources(atc, apcm);
190	return err;
191}
192
193static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
194{
195	struct ct_atc *atc = snd_pcm_substream_chip(substream);
196	struct ct_atc_pcm *apcm = substream->runtime->private_data;
197
198	/* clear previous resources */
199	atc->pcm_release_resources(atc, apcm);
200	/* Free snd-allocated pages */
201	return snd_pcm_lib_free_pages(substream);
202}
203
204
205static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
206{
207	int err;
208	struct ct_atc *atc = snd_pcm_substream_chip(substream);
209	struct snd_pcm_runtime *runtime = substream->runtime;
210	struct ct_atc_pcm *apcm = runtime->private_data;
211
212	if (IEC958 == substream->pcm->device)
213		err = atc->spdif_passthru_playback_prepare(atc, apcm);
214	else
215		err = atc->pcm_playback_prepare(atc, apcm);
216
217	if (err < 0) {
218		printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
219		return err;
220	}
221
222	return 0;
223}
224
225static int
226ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
227{
228	struct ct_atc *atc = snd_pcm_substream_chip(substream);
229	struct snd_pcm_runtime *runtime = substream->runtime;
230	struct ct_atc_pcm *apcm = runtime->private_data;
231
232	switch (cmd) {
233	case SNDRV_PCM_TRIGGER_START:
234	case SNDRV_PCM_TRIGGER_RESUME:
235	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
236		atc->pcm_playback_start(atc, apcm);
237		break;
238	case SNDRV_PCM_TRIGGER_STOP:
239	case SNDRV_PCM_TRIGGER_SUSPEND:
240	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
241		atc->pcm_playback_stop(atc, apcm);
242		break;
243	default:
244		break;
245	}
246
247	return 0;
248}
249
250static snd_pcm_uframes_t
251ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
252{
253	unsigned long position;
254	struct ct_atc *atc = snd_pcm_substream_chip(substream);
255	struct snd_pcm_runtime *runtime = substream->runtime;
256	struct ct_atc_pcm *apcm = runtime->private_data;
257
258	/* Read out playback position */
259	position = atc->pcm_playback_position(atc, apcm);
260	position = bytes_to_frames(runtime, position);
261	if (position >= runtime->buffer_size)
262		position = 0;
263	return position;
264}
265
266/* pcm capture operations */
267static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
268{
269	struct ct_atc *atc = snd_pcm_substream_chip(substream);
270	struct snd_pcm_runtime *runtime = substream->runtime;
271	struct ct_atc_pcm *apcm;
272	int err;
273
274	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
275	if (!apcm)
276		return -ENOMEM;
277
278	apcm->started = 0;
279	apcm->substream = substream;
280	apcm->interrupt = ct_atc_pcm_interrupt;
281	runtime->private_data = apcm;
282	runtime->private_free = ct_atc_pcm_free_substream;
283	runtime->hw = ct_pcm_capture_hw;
284	runtime->hw.rate_max = atc->rsr * atc->msr;
285
286	err = snd_pcm_hw_constraint_integer(runtime,
287					    SNDRV_PCM_HW_PARAM_PERIODS);
288	if (err < 0) {
289		kfree(apcm);
290		return err;
291	}
292	err = snd_pcm_hw_constraint_minmax(runtime,
293					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
294					   1024, UINT_MAX);
295	if (err < 0) {
296		kfree(apcm);
297		return err;
298	}
299
300	apcm->timer = ct_timer_instance_new(atc->timer, apcm);
301	if (!apcm->timer)
302		return -ENOMEM;
303
304	return 0;
305}
306
307static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
308{
309	/* The ct_atc_pcm object will be freed by runtime->private_free */
310	/* TODO: Notify mixer inactive. */
311	return 0;
312}
313
314static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
315{
316	int err;
317	struct ct_atc *atc = snd_pcm_substream_chip(substream);
318	struct snd_pcm_runtime *runtime = substream->runtime;
319	struct ct_atc_pcm *apcm = runtime->private_data;
320
321	err = atc->pcm_capture_prepare(atc, apcm);
322	if (err < 0) {
323		printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
324		return err;
325	}
326
327	return 0;
328}
329
330static int
331ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
332{
333	struct ct_atc *atc = snd_pcm_substream_chip(substream);
334	struct snd_pcm_runtime *runtime = substream->runtime;
335	struct ct_atc_pcm *apcm = runtime->private_data;
336
337	switch (cmd) {
338	case SNDRV_PCM_TRIGGER_START:
339		atc->pcm_capture_start(atc, apcm);
340		break;
341	case SNDRV_PCM_TRIGGER_STOP:
342		atc->pcm_capture_stop(atc, apcm);
343		break;
344	default:
345		atc->pcm_capture_stop(atc, apcm);
346		break;
347	}
348
349	return 0;
350}
351
352static snd_pcm_uframes_t
353ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
354{
355	unsigned long position;
356	struct ct_atc *atc = snd_pcm_substream_chip(substream);
357	struct snd_pcm_runtime *runtime = substream->runtime;
358	struct ct_atc_pcm *apcm = runtime->private_data;
359
360	/* Read out playback position */
361	position = atc->pcm_capture_position(atc, apcm);
362	position = bytes_to_frames(runtime, position);
363	if (position >= runtime->buffer_size)
364		position = 0;
365	return position;
366}
367
368/* PCM operators for playback */
369static struct snd_pcm_ops ct_pcm_playback_ops = {
370	.open	 	= ct_pcm_playback_open,
371	.close		= ct_pcm_playback_close,
372	.ioctl		= snd_pcm_lib_ioctl,
373	.hw_params	= ct_pcm_hw_params,
374	.hw_free	= ct_pcm_hw_free,
375	.prepare	= ct_pcm_playback_prepare,
376	.trigger	= ct_pcm_playback_trigger,
377	.pointer	= ct_pcm_playback_pointer,
378	.page		= snd_pcm_sgbuf_ops_page,
379};
380
381/* PCM operators for capture */
382static struct snd_pcm_ops ct_pcm_capture_ops = {
383	.open	 	= ct_pcm_capture_open,
384	.close		= ct_pcm_capture_close,
385	.ioctl		= snd_pcm_lib_ioctl,
386	.hw_params	= ct_pcm_hw_params,
387	.hw_free	= ct_pcm_hw_free,
388	.prepare	= ct_pcm_capture_prepare,
389	.trigger	= ct_pcm_capture_trigger,
390	.pointer	= ct_pcm_capture_pointer,
391	.page		= snd_pcm_sgbuf_ops_page,
392};
393
394/* Create ALSA pcm device */
395int ct_alsa_pcm_create(struct ct_atc *atc,
396		       enum CTALSADEVS device,
397		       const char *device_name)
398{
399	struct snd_pcm *pcm;
400	int err;
401	int playback_count, capture_count;
402
403	playback_count = (IEC958 == device) ? 1 : 8;
404	capture_count = (FRONT == device) ? 1 : 0;
405	err = snd_pcm_new(atc->card, "ctxfi", device,
406			  playback_count, capture_count, &pcm);
407	if (err < 0) {
408		printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
409		return err;
410	}
411
412	pcm->private_data = atc;
413	pcm->info_flags = 0;
414	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
415	strlcpy(pcm->name, device_name, sizeof(pcm->name));
416
417	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
418
419	if (FRONT == device)
420		snd_pcm_set_ops(pcm,
421				SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
422
423	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
424			snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
425
426#ifdef CONFIG_PM
427	atc->pcms[device] = pcm;
428#endif
429
430	return 0;
431}
432