blob: 26d86dc35e52f32d81e52b3670a1b2d46f2a3b52 [file] [log] [blame]
Wai Yew CHAY8cc72362009-05-14 08:05:58 +02001/**
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 <sound/pcm.h>
20
21/* Hardware descriptions for playback */
22static struct snd_pcm_hardware ct_pcm_playback_hw = {
23 .info = (SNDRV_PCM_INFO_MMAP |
24 SNDRV_PCM_INFO_INTERLEAVED |
25 SNDRV_PCM_INFO_BLOCK_TRANSFER |
26 SNDRV_PCM_INFO_MMAP_VALID |
27 SNDRV_PCM_INFO_PAUSE),
28 .formats = (SNDRV_PCM_FMTBIT_U8 |
Wai Yew CHAY8cc72362009-05-14 08:05:58 +020029 SNDRV_PCM_FMTBIT_S16_LE |
Wai Yew CHAY8cc72362009-05-14 08:05:58 +020030 SNDRV_PCM_FMTBIT_S24_3LE |
Takashi Iwaid2b9b962009-06-02 14:39:05 +020031 SNDRV_PCM_FMTBIT_S32_LE |
32 SNDRV_PCM_FMTBIT_FLOAT_LE),
Wai Yew CHAY8cc72362009-05-14 08:05:58 +020033 .rates = (SNDRV_PCM_RATE_CONTINUOUS |
34 SNDRV_PCM_RATE_8000_192000),
35 .rate_min = 8000,
36 .rate_max = 192000,
37 .channels_min = 1,
38 .channels_max = 2,
39 .buffer_bytes_max = (128*1024),
40 .period_bytes_min = (64),
41 .period_bytes_max = (128*1024),
42 .periods_min = 1,
43 .periods_max = 1024,
44 .fifo_size = 0,
45};
46
47static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
48 .info = (SNDRV_PCM_INFO_MMAP |
49 SNDRV_PCM_INFO_INTERLEAVED |
50 SNDRV_PCM_INFO_BLOCK_TRANSFER |
51 SNDRV_PCM_INFO_MMAP_VALID |
52 SNDRV_PCM_INFO_PAUSE),
Takashi Iwaid2b9b962009-06-02 14:39:05 +020053 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Wai Yew CHAY8cc72362009-05-14 08:05:58 +020054 .rates = (SNDRV_PCM_RATE_48000 |
55 SNDRV_PCM_RATE_44100 |
56 SNDRV_PCM_RATE_32000),
57 .rate_min = 32000,
58 .rate_max = 48000,
59 .channels_min = 2,
60 .channels_max = 2,
61 .buffer_bytes_max = (128*1024),
62 .period_bytes_min = (64),
63 .period_bytes_max = (128*1024),
64 .periods_min = 1,
65 .periods_max = 1024,
66 .fifo_size = 0,
67};
68
69/* Hardware descriptions for capture */
70static struct snd_pcm_hardware ct_pcm_capture_hw = {
71 .info = (SNDRV_PCM_INFO_MMAP |
72 SNDRV_PCM_INFO_INTERLEAVED |
73 SNDRV_PCM_INFO_BLOCK_TRANSFER |
74 SNDRV_PCM_INFO_PAUSE |
75 SNDRV_PCM_INFO_MMAP_VALID),
76 .formats = (SNDRV_PCM_FMTBIT_U8 |
Wai Yew CHAY8cc72362009-05-14 08:05:58 +020077 SNDRV_PCM_FMTBIT_S16_LE |
Wai Yew CHAY8cc72362009-05-14 08:05:58 +020078 SNDRV_PCM_FMTBIT_S24_3LE |
Takashi Iwaid2b9b962009-06-02 14:39:05 +020079 SNDRV_PCM_FMTBIT_S32_LE |
80 SNDRV_PCM_FMTBIT_FLOAT_LE),
Wai Yew CHAY8cc72362009-05-14 08:05:58 +020081 .rates = (SNDRV_PCM_RATE_CONTINUOUS |
82 SNDRV_PCM_RATE_8000_96000),
83 .rate_min = 8000,
84 .rate_max = 96000,
85 .channels_min = 1,
86 .channels_max = 2,
87 .buffer_bytes_max = (128*1024),
88 .period_bytes_min = (384),
89 .period_bytes_max = (64*1024),
90 .periods_min = 2,
91 .periods_max = 1024,
92 .fifo_size = 0,
93};
94
95static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
96{
97 struct ct_atc_pcm *apcm = atc_pcm;
98
99 if (NULL == apcm->substream)
100 return;
101
102 snd_pcm_period_elapsed(apcm->substream);
103}
104
105static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
106{
107 struct ct_atc_pcm *apcm = runtime->private_data;
108 struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
109
110 atc->pcm_release_resources(atc, apcm);
111 kfree(apcm);
112 runtime->private_data = NULL;
113}
114
115/* pcm playback operations */
116static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
117{
118 struct ct_atc *atc = snd_pcm_substream_chip(substream);
119 struct snd_pcm_runtime *runtime = substream->runtime;
120 struct ct_atc_pcm *apcm;
121 int err;
122
123 apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
124 if (NULL == apcm)
125 return -ENOMEM;
126
127 spin_lock_init(&apcm->timer_lock);
128 apcm->stop_timer = 0;
129 apcm->substream = substream;
130 apcm->interrupt = ct_atc_pcm_interrupt;
131 runtime->private_data = apcm;
132 runtime->private_free = ct_atc_pcm_free_substream;
133 if (IEC958 == substream->pcm->device) {
134 runtime->hw = ct_spdif_passthru_playback_hw;
135 atc->spdif_out_passthru(atc, 1);
136 } else {
137 runtime->hw = ct_pcm_playback_hw;
138 if (FRONT == substream->pcm->device)
139 runtime->hw.channels_max = 8;
140 }
141
142 err = snd_pcm_hw_constraint_integer(runtime,
143 SNDRV_PCM_HW_PARAM_PERIODS);
144 if (err < 0) {
145 kfree(apcm);
146 return err;
147 }
148 err = snd_pcm_hw_constraint_minmax(runtime,
149 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
150 1024, UINT_MAX);
151 if (err < 0) {
152 kfree(apcm);
153 return err;
154 }
155
156 return 0;
157}
158
159static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
160{
161 struct ct_atc *atc = snd_pcm_substream_chip(substream);
162
163 /* TODO: Notify mixer inactive. */
164 if (IEC958 == substream->pcm->device)
165 atc->spdif_out_passthru(atc, 0);
166
167 /* The ct_atc_pcm object will be freed by runtime->private_free */
168
169 return 0;
170}
171
172static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
173 struct snd_pcm_hw_params *hw_params)
174{
175 return snd_pcm_lib_malloc_pages(substream,
176 params_buffer_bytes(hw_params));
177}
178
179static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
180{
181 /* Free snd-allocated pages */
182 return snd_pcm_lib_free_pages(substream);
183}
184
185static void ct_pcm_timer_callback(unsigned long data)
186{
187 struct ct_atc_pcm *apcm = (struct ct_atc_pcm *)data;
188 struct snd_pcm_substream *substream = apcm->substream;
189 struct snd_pcm_runtime *runtime = substream->runtime;
190 unsigned int period_size = runtime->period_size;
191 unsigned int buffer_size = runtime->buffer_size;
192 unsigned long flags;
193 unsigned int position = 0, dist = 0, interval = 0;
194
195 position = substream->ops->pointer(substream);
196 dist = (position + buffer_size - apcm->position) % buffer_size;
197 if ((dist >= period_size) ||
198 (position/period_size != apcm->position/period_size)) {
199 apcm->interrupt(apcm);
200 apcm->position = position;
201 }
202 /* Add extra HZ*5/1000 to avoid overrun issue when recording
203 * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
204 interval = ((period_size - (position % period_size))
205 * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
206 spin_lock_irqsave(&apcm->timer_lock, flags);
207 apcm->timer.expires = jiffies + interval;
208 if (!apcm->stop_timer)
209 add_timer(&apcm->timer);
210
211 spin_unlock_irqrestore(&apcm->timer_lock, flags);
212}
213
214static int ct_pcm_timer_prepare(struct ct_atc_pcm *apcm)
215{
216 unsigned long flags;
217
218 spin_lock_irqsave(&apcm->timer_lock, flags);
219 if (timer_pending(&apcm->timer)) {
220 /* The timer has already been started. */
221 spin_unlock_irqrestore(&apcm->timer_lock, flags);
222 return 0;
223 }
224
225 init_timer(&apcm->timer);
226 apcm->timer.data = (unsigned long)apcm;
227 apcm->timer.function = ct_pcm_timer_callback;
228 spin_unlock_irqrestore(&apcm->timer_lock, flags);
229 apcm->position = 0;
230
231 return 0;
232}
233
234static int ct_pcm_timer_start(struct ct_atc_pcm *apcm)
235{
236 struct snd_pcm_runtime *runtime = apcm->substream->runtime;
237 unsigned long flags;
238
239 spin_lock_irqsave(&apcm->timer_lock, flags);
240 if (timer_pending(&apcm->timer)) {
241 /* The timer has already been started. */
242 spin_unlock_irqrestore(&apcm->timer_lock, flags);
243 return 0;
244 }
245
246 apcm->timer.expires = jiffies + (runtime->period_size * HZ +
247 (runtime->rate - 1)) / runtime->rate;
248 apcm->stop_timer = 0;
249 add_timer(&apcm->timer);
250 spin_unlock_irqrestore(&apcm->timer_lock, flags);
251
252 return 0;
253}
254
255static int ct_pcm_timer_stop(struct ct_atc_pcm *apcm)
256{
257 unsigned long flags;
258
259 spin_lock_irqsave(&apcm->timer_lock, flags);
260 apcm->stop_timer = 1;
261 del_timer(&apcm->timer);
262 spin_unlock_irqrestore(&apcm->timer_lock, flags);
263
264 try_to_del_timer_sync(&apcm->timer);
265
266 return 0;
267}
268
269static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
270{
271 int err;
272 struct ct_atc *atc = snd_pcm_substream_chip(substream);
273 struct snd_pcm_runtime *runtime = substream->runtime;
274 struct ct_atc_pcm *apcm = runtime->private_data;
275
276 if (IEC958 == substream->pcm->device)
277 err = atc->spdif_passthru_playback_prepare(atc, apcm);
278 else
279 err = atc->pcm_playback_prepare(atc, apcm);
280
281 if (err < 0) {
Takashi Iwaib3e0afe2009-05-14 15:19:30 +0200282 printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200283 return err;
284 }
285
286 ct_pcm_timer_prepare(apcm);
287
288 return 0;
289}
290
291static int
292ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
293{
294 struct ct_atc *atc = snd_pcm_substream_chip(substream);
295 struct snd_pcm_runtime *runtime = substream->runtime;
296 struct ct_atc_pcm *apcm = runtime->private_data;
297
298 switch (cmd) {
299 case SNDRV_PCM_TRIGGER_START:
300 case SNDRV_PCM_TRIGGER_RESUME:
301 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
302 atc->pcm_playback_start(atc, apcm);
303 ct_pcm_timer_start(apcm);
304 break;
305 case SNDRV_PCM_TRIGGER_STOP:
306 case SNDRV_PCM_TRIGGER_SUSPEND:
307 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
308 ct_pcm_timer_stop(apcm);
309 atc->pcm_playback_stop(atc, apcm);
310 break;
311 default:
312 break;
313 }
314
315 return 0;
316}
317
318static snd_pcm_uframes_t
319ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
320{
321 unsigned long position;
322 struct ct_atc *atc = snd_pcm_substream_chip(substream);
323 struct snd_pcm_runtime *runtime = substream->runtime;
324 struct ct_atc_pcm *apcm = runtime->private_data;
325
326 /* Read out playback position */
327 position = atc->pcm_playback_position(atc, apcm);
328 position = bytes_to_frames(runtime, position);
329 return position;
330}
331
332/* pcm capture operations */
333static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
334{
335 struct ct_atc *atc = snd_pcm_substream_chip(substream);
336 struct snd_pcm_runtime *runtime = substream->runtime;
337 struct ct_atc_pcm *apcm;
338 int err;
339
340 apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
341 if (NULL == apcm)
342 return -ENOMEM;
343
344 spin_lock_init(&apcm->timer_lock);
345 apcm->started = 0;
346 apcm->stop_timer = 0;
347 apcm->substream = substream;
348 apcm->interrupt = ct_atc_pcm_interrupt;
349 runtime->private_data = apcm;
350 runtime->private_free = ct_atc_pcm_free_substream;
351 runtime->hw = ct_pcm_capture_hw;
352 runtime->hw.rate_max = atc->rsr * atc->msr;
353
354 err = snd_pcm_hw_constraint_integer(runtime,
355 SNDRV_PCM_HW_PARAM_PERIODS);
356 if (err < 0) {
357 kfree(apcm);
358 return err;
359 }
360 err = snd_pcm_hw_constraint_minmax(runtime,
361 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
362 1024, UINT_MAX);
363 if (err < 0) {
364 kfree(apcm);
365 return err;
366 }
367
368 return 0;
369}
370
371static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
372{
373 /* The ct_atc_pcm object will be freed by runtime->private_free */
374 /* TODO: Notify mixer inactive. */
375 return 0;
376}
377
378static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
379{
380 int err;
381 struct ct_atc *atc = snd_pcm_substream_chip(substream);
382 struct snd_pcm_runtime *runtime = substream->runtime;
383 struct ct_atc_pcm *apcm = runtime->private_data;
384
385 err = atc->pcm_capture_prepare(atc, apcm);
386 if (err < 0) {
Takashi Iwaib3e0afe2009-05-14 15:19:30 +0200387 printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200388 return err;
389 }
390
391 ct_pcm_timer_prepare(apcm);
392
393 return 0;
394}
395
396static int
397ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
398{
399 struct ct_atc *atc = snd_pcm_substream_chip(substream);
400 struct snd_pcm_runtime *runtime = substream->runtime;
401 struct ct_atc_pcm *apcm = runtime->private_data;
402
403 switch (cmd) {
404 case SNDRV_PCM_TRIGGER_START:
405 atc->pcm_capture_start(atc, apcm);
406 ct_pcm_timer_start(apcm);
407 break;
408 case SNDRV_PCM_TRIGGER_STOP:
409 ct_pcm_timer_stop(apcm);
410 atc->pcm_capture_stop(atc, apcm);
411 break;
412 default:
413 ct_pcm_timer_stop(apcm);
414 atc->pcm_capture_stop(atc, apcm);
415 break;
416 }
417
418 return 0;
419}
420
421static snd_pcm_uframes_t
422ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
423{
424 unsigned long position;
425 struct ct_atc *atc = snd_pcm_substream_chip(substream);
426 struct snd_pcm_runtime *runtime = substream->runtime;
427 struct ct_atc_pcm *apcm = runtime->private_data;
428
429 /* Read out playback position */
430 position = atc->pcm_capture_position(atc, apcm);
431 position = bytes_to_frames(runtime, position);
432 return position;
433}
434
435/* PCM operators for playback */
436static struct snd_pcm_ops ct_pcm_playback_ops = {
437 .open = ct_pcm_playback_open,
438 .close = ct_pcm_playback_close,
439 .ioctl = snd_pcm_lib_ioctl,
440 .hw_params = ct_pcm_hw_params,
441 .hw_free = ct_pcm_hw_free,
442 .prepare = ct_pcm_playback_prepare,
443 .trigger = ct_pcm_playback_trigger,
444 .pointer = ct_pcm_playback_pointer,
445};
446
447/* PCM operators for capture */
448static struct snd_pcm_ops ct_pcm_capture_ops = {
449 .open = ct_pcm_capture_open,
450 .close = ct_pcm_capture_close,
451 .ioctl = snd_pcm_lib_ioctl,
452 .hw_params = ct_pcm_hw_params,
453 .hw_free = ct_pcm_hw_free,
454 .prepare = ct_pcm_capture_prepare,
455 .trigger = ct_pcm_capture_trigger,
456 .pointer = ct_pcm_capture_pointer,
457};
458
459/* Create ALSA pcm device */
460int ct_alsa_pcm_create(struct ct_atc *atc,
461 enum CTALSADEVS device,
462 const char *device_name)
463{
464 struct snd_pcm *pcm;
465 int err;
466 int playback_count, capture_count;
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200467
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200468 playback_count = (IEC958 == device) ? 1 : 8;
469 capture_count = (FRONT == device) ? 1 : 0;
Takashi Iwai8372d4982009-06-02 14:27:56 +0200470 err = snd_pcm_new(atc->card, "ctxfi", device,
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200471 playback_count, capture_count, &pcm);
472 if (err < 0) {
Takashi Iwaib3e0afe2009-05-14 15:19:30 +0200473 printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200474 return err;
475 }
476
477 pcm->private_data = atc;
478 pcm->info_flags = 0;
479 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
Takashi Iwai8372d4982009-06-02 14:27:56 +0200480 strlcpy(pcm->name, device_name, sizeof(pcm->name));
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200481
482 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
483
484 if (FRONT == device)
485 snd_pcm_set_ops(pcm,
486 SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
487
488 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
489 snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
490
491 return 0;
492}