Linux Audio

Check our new training course

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