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