added loopback example with adc samples and dac playback
[pcm-lib.git] / source / pcm.c
blob0fed646cabc170456a4ed155b0481c3532e7dc23
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 * pcm.c - pcm internal function
6 * <liu090@sina.com>
7 */
9 #include "os_utils.h"
11 #include "pcm.h"
13 /* global var */
14 uint32_t HZ = 0;
15 unsigned int sys_dma_inited = 0; /* if other driver inited dma ,set this flag to ture */
17 /* pcm misc */
18 #define INT int
20 //#define XRUN_AND_INTRLOST_DEBUG
22 static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
23 [SNDRV_PCM_FORMAT_S8] = {
24 .width = 8, .phys = 8, .le = -1, .signd = 1,
25 .silence = {0},
27 [SNDRV_PCM_FORMAT_U8] = {
28 .width = 8, .phys = 8, .le = -1, .signd = 0,
29 .silence = { 0x80 },
31 [SNDRV_PCM_FORMAT_S16_LE] = {
32 .width = 16, .phys = 16, .le = 1, .signd = 1,
33 .silence = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
35 [SNDRV_PCM_FORMAT_S16_BE] = {
36 .width = 16, .phys = 16, .le = 0, .signd = 1,
37 .silence = {0},
39 [SNDRV_PCM_FORMAT_U16_LE] = {
40 .width = 16, .phys = 16, .le = 1, .signd = 0,
41 .silence = { 0x00, 0x80 },
43 [SNDRV_PCM_FORMAT_U16_BE] = {
44 .width = 16, .phys = 16, .le = 0, .signd = 0,
45 .silence = { 0x80, 0x00 },
47 [SNDRV_PCM_FORMAT_S24_LE] = {
48 .width = 24, .phys = 32, .le = 1, .signd = 1,
49 .silence = {0},
51 [SNDRV_PCM_FORMAT_S24_BE] = {
52 .width = 24, .phys = 32, .le = 0, .signd = 1,
53 .silence = {0},
55 [SNDRV_PCM_FORMAT_U24_LE] = {
56 .width = 24, .phys = 32, .le = 1, .signd = 0,
57 .silence = { 0x00, 0x00, 0x80 },
59 [SNDRV_PCM_FORMAT_U24_BE] = {
60 .width = 24, .phys = 32, .le = 0, .signd = 0,
61 .silence = { 0x00, 0x80, 0x00, 0x00 },
63 [SNDRV_PCM_FORMAT_S32_LE] = {
64 .width = 32, .phys = 32, .le = 1, .signd = 1,
65 .silence = {0},
67 [SNDRV_PCM_FORMAT_S32_BE] = {
68 .width = 32, .phys = 32, .le = 0, .signd = 1,
69 .silence = {0},
71 [SNDRV_PCM_FORMAT_U32_LE] = {
72 .width = 32, .phys = 32, .le = 1, .signd = 0,
73 .silence = { 0x00, 0x00, 0x00, 0x80 },
75 [SNDRV_PCM_FORMAT_U32_BE] = {
76 .width = 32, .phys = 32, .le = 0, .signd = 0,
77 .silence = { 0x80, 0x00, 0x00, 0x00 },
79 #if 0
80 [SNDRV_PCM_FORMAT_FLOAT_LE] = {
81 .width = 32, .phys = 32, .le = 1, .signd = -1,
82 .silence = {0},
84 [SNDRV_PCM_FORMAT_FLOAT_BE] = {
85 .width = 32, .phys = 32, .le = 0, .signd = -1,
86 .silence = {0},
88 [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
89 .width = 64, .phys = 64, .le = 1, .signd = -1,
90 .silence = {0},
92 [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
93 .width = 64, .phys = 64, .le = 0, .signd = -1,
94 .silence = {0},
96 #else
97 [SNDRV_PCM_FORMAT_S24_3LE] = {
98 .width = 24, .phys = 24, .le = 1, .signd = 1,
99 .silence = {0},
101 [SNDRV_PCM_FORMAT_S24_3BE] = {
102 .width = 24, .phys = 24, .le = 0, .signd = 1,
103 .silence = {0},
105 [SNDRV_PCM_FORMAT_U24_3LE] = {
106 .width = 24, .phys = 24, .le = 1, .signd = 0,
107 .silence = { 0x00, 0x00, 0x80 },
109 [SNDRV_PCM_FORMAT_U24_3BE] = {
110 .width = 24, .phys = 24, .le = 0, .signd = 0,
111 .silence = { 0x80, 0x00, 0x00 },
113 #endif
114 #ifndef LIMITED_FORMATS
115 [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
116 .width = 32, .phys = 32, .le = 1, .signd = -1,
117 .silence = {0},
119 [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
120 .width = 32, .phys = 32, .le = 0, .signd = -1,
121 .silence = {0},
123 [SNDRV_PCM_FORMAT_MU_LAW] = {
124 .width = 8, .phys = 8, .le = -1, .signd = -1,
125 .silence = { 0x7f },
127 [SNDRV_PCM_FORMAT_A_LAW] = {
128 .width = 8, .phys = 8, .le = -1, .signd = -1,
129 .silence = { 0x55 },
131 [SNDRV_PCM_FORMAT_IMA_ADPCM] = {
132 .width = 4, .phys = 4, .le = -1, .signd = -1,
133 .silence = {0},
135 [SNDRV_PCM_FORMAT_G723_24] = {
136 .width = 3, .phys = 3, .le = -1, .signd = -1,
137 .silence = {0},
139 [SNDRV_PCM_FORMAT_G723_40] = {
140 .width = 5, .phys = 5, .le = -1, .signd = -1,
141 .silence = {0},
143 /* FIXME: the following three formats are not defined properly yet */
144 [SNDRV_PCM_FORMAT_MPEG] = {
145 .le = -1, .signd = -1,
147 [SNDRV_PCM_FORMAT_GSM] = {
148 .le = -1, .signd = -1,
150 [SNDRV_PCM_FORMAT_SPECIAL] = {
151 .le = -1, .signd = -1,
153 #if 0
154 [SNDRV_PCM_FORMAT_S24_3LE] = {
155 .width = 24, .phys = 24, .le = 1, .signd = 1,
156 .silence = {0},
158 [SNDRV_PCM_FORMAT_S24_3BE] = {
159 .width = 24, .phys = 24, .le = 0, .signd = 1,
160 .silence = {0},
162 [SNDRV_PCM_FORMAT_U24_3LE] = {
163 .width = 24, .phys = 24, .le = 1, .signd = 0,
164 .silence = { 0x00, 0x00, 0x80 },
166 [SNDRV_PCM_FORMAT_U24_3BE] = {
167 .width = 24, .phys = 24, .le = 0, .signd = 0,
168 .silence = { 0x80, 0x00, 0x00 },
170 #else
171 [SNDRV_PCM_FORMAT_FLOAT_LE] = {
172 .width = 32, .phys = 32, .le = 1, .signd = -1,
173 .silence = {0},
175 [SNDRV_PCM_FORMAT_FLOAT_BE] = {
176 .width = 32, .phys = 32, .le = 0, .signd = -1,
177 .silence = {0},
179 [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
180 .width = 64, .phys = 64, .le = 1, .signd = -1,
181 .silence = {0},
183 [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
184 .width = 64, .phys = 64, .le = 0, .signd = -1,
185 .silence = {0},
187 #endif
188 [SNDRV_PCM_FORMAT_S20_3LE] = {
189 .width = 20, .phys = 24, .le = 1, .signd = 1,
190 .silence = {0},
192 [SNDRV_PCM_FORMAT_S20_3BE] = {
193 .width = 20, .phys = 24, .le = 0, .signd = 1,
194 .silence = {0},
196 [SNDRV_PCM_FORMAT_U20_3LE] = {
197 .width = 20, .phys = 24, .le = 1, .signd = 0,
198 .silence = { 0x00, 0x00, 0x08 },
200 [SNDRV_PCM_FORMAT_U20_3BE] = {
201 .width = 20, .phys = 24, .le = 0, .signd = 0,
202 .silence = { 0x08, 0x00, 0x00 },
204 [SNDRV_PCM_FORMAT_S18_3LE] = {
205 .width = 18, .phys = 24, .le = 1, .signd = 1,
206 .silence = {0},
208 [SNDRV_PCM_FORMAT_S18_3BE] = {
209 .width = 18, .phys = 24, .le = 0, .signd = 1,
210 .silence = {0},
212 [SNDRV_PCM_FORMAT_U18_3LE] = {
213 .width = 18, .phys = 24, .le = 1, .signd = 0,
214 .silence = { 0x00, 0x00, 0x02 },
216 [SNDRV_PCM_FORMAT_U18_3BE] = {
217 .width = 18, .phys = 24, .le = 0, .signd = 0,
218 .silence = { 0x02, 0x00, 0x00 },
220 [SNDRV_PCM_FORMAT_G723_24_1B] = {
221 .width = 3, .phys = 8, .le = -1, .signd = -1,
222 .silence = {0},
224 [SNDRV_PCM_FORMAT_G723_40_1B] = {
225 .width = 5, .phys = 8, .le = -1, .signd = -1,
226 .silence = {0},
228 #endif
231 /* pre declare */
232 static void snd_pcm_period_elapsed(struct snd_pcm_runtime *runtime);
233 static int snd_pcm_attach_runtime(struct snd_pcm_runtime **runtime);
234 static void snd_pcm_detach_runtime(struct snd_pcm_runtime *runtime);
235 int snd_pcm_update_hw_ptr(struct snd_pcm_runtime *runtime);
238 /******************************************************************************/
239 /* dma operation functions */
240 static snd_pcm_uframes_t snd_pcm_pointer(struct snd_pcm_runtime *runtime,int in_interrupt)
242 struct sco_pcm_runtime_data *iprtd = runtime->private_data;
244 /* printf("%s: %ld %ld,%d\n", __func__, iprtd->offset,
245 bytes_to_frames(runtime, iprtd->offset),in_interrupt);
247 return bytes_to_frames(runtime, iprtd->offset);
251 * dma interrupt callback
253 void audio_dma_irq(void *data,uint_8 chan)
255 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)data;
256 struct sco_pcm_runtime_data *iprtd = (struct sco_pcm_runtime_data *)runtime->private_data;
258 iprtd->offset += iprtd->period_bytes;
259 iprtd->offset %= iprtd->period_bytes * iprtd->periods; /* offeset = 0,1period, 2periods ... n periods .(circle) */
261 snd_pcm_period_elapsed(runtime); /* update ring buffer by call snd_pcm_update_hw_ptr0 */
263 // os_get_ticks_interval (runtime); // hw_ptr_ticks_inteval ,get accurate intrrupts interval
267 * set the silence data on the buffer
269 static int snd_pcm_format_set_silence(struct snd_pcm_runtime *runtime, void *data, unsigned int samples)
271 int width;
272 unsigned char *dst;
273 const unsigned char * pat;
274 snd_pcm_format_t format;
276 format = runtime->format;
278 if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
279 return -1;
280 if (samples == 0)
281 return 0;
282 /* physical width */
283 width = pcm_formats[(INT)format].phys;
284 pat = pcm_formats[(INT)format].silence;
285 if (! width)
286 return -1;
287 /* signed or 1 byte data */
288 if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
289 unsigned int bytes = samples * width / 8;
290 // fixme
291 bytes = (bytes * runtime->sample_aligned_bits / width /*runtime->sample_bits*/);
292 os_memset(data, *pat, bytes);
293 return 0;
295 /* non-zero samples, fill using a loop */
296 width /= 8;
297 dst = data;
298 #if 0
299 while (samples--) {
300 memcpy(dst, pat, width);
301 dst += width;
303 #else
304 /* a bit optimization for constant width */
305 switch (width) {
306 case 2:
307 while (samples--) {
308 os_memcpy(dst, pat, 2);
309 dst += 2;
311 break;
312 case 3:
313 while (samples--) {
314 os_memcpy(dst, pat, 3);
315 dst += 3;
317 break;
318 case 4:
319 while (samples--) {
320 os_memcpy(dst, pat, 4);
321 dst += 4;
323 break;
324 case 8:
325 while (samples--) {
326 os_memcpy(dst, pat, 8);
327 dst += 8;
329 break;
331 #endif
332 return 0;
334 /* end pcm misc */
337 * fill ring buffer with silence
338 * runtime->silence_start: starting pointer to silence area
339 * runtime->silence_filled: size filled with silence
340 * runtime->silence_threshold: threshold from application
341 * runtime->silence_size: maximal size from application
343 * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
345 void snd_pcm_playback_silence(struct snd_pcm_runtime *runtime, snd_pcm_uframes_t new_hw_ptr)
347 snd_pcm_uframes_t frames, ofs, transfer;
349 if (runtime->silence_size < runtime->boundary) {
350 snd_pcm_sframes_t noise_dist, n;
351 if (runtime->silence_start != runtime->control->appl_ptr) {
352 n = runtime->control->appl_ptr - runtime->silence_start;
353 if (n < 0)
354 n += runtime->boundary;
355 if ((snd_pcm_uframes_t)n < runtime->silence_filled)
356 runtime->silence_filled -= n;
357 else
358 runtime->silence_filled = 0;
359 runtime->silence_start = runtime->control->appl_ptr;
361 if (runtime->silence_filled >= runtime->buffer_size)
362 return;
363 noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
364 if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
365 return;
366 frames = runtime->silence_threshold - noise_dist;
367 if (frames > runtime->silence_size)
368 frames = runtime->silence_size;
369 } else {
370 if (new_hw_ptr == ULONG_MAX) { /* initialization */
371 snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
372 if (avail > runtime->buffer_size)
373 avail = runtime->buffer_size;
374 runtime->silence_filled = avail > 0 ? avail : 0;
375 runtime->silence_start = (runtime->status->hw_ptr +
376 runtime->silence_filled) %
377 runtime->boundary; /* initialization silence_start pointer always at the end of valid pcm data */
378 } else {
379 ofs = runtime->status->hw_ptr;
380 frames = new_hw_ptr - ofs;
381 if ((snd_pcm_sframes_t)frames < 0)
382 frames += runtime->boundary;
383 runtime->silence_filled -= frames;
384 if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
385 runtime->silence_filled = 0;
386 runtime->silence_start = new_hw_ptr;
387 } else {
388 runtime->silence_start = ofs;
391 /* at init, fill silence from the end of valid pcm data to the end of buffer */
392 frames = runtime->buffer_size - runtime->silence_filled;
394 if (snd_BUG_ON(frames > runtime->buffer_size))
395 return;
396 if (frames == 0)
397 return;
398 ofs = runtime->silence_start % runtime->buffer_size;
399 while (frames > 0) {
400 transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
401 if (runtime->access == SNDRV_PCM_ACCESS_INTERLEAVED) { /* left sample, right sample */
402 /* if (ops->silence) { sco_pcm_silence
403 int err;
404 err = ops->silence(runtime, -1, ofs, transfer);
405 snd_BUG_ON(err < 0);
406 } else {*/
407 //unsigned char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs) * (runtime->sample_aligned_bits / runtime->sample_bits); /* fixme */
408 unsigned char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs) * runtime->sample_aligned_bits / runtime->sample_phy_bits/* runtime->sample_bits*/; /* fixme */
409 /* remove silence fill temprary ,fixme */
410 snd_pcm_format_set_silence(runtime/*->format*/, hwbuf, transfer * runtime->channels );
411 /*}*/
412 } else {
413 /* support lefts and rights */
414 unsigned int c;
415 unsigned int channels = runtime->channels;
416 /* sco_pcm_silence dont implement
417 if (ops->silence) {
418 for (c = 0; c < channels; ++c) {
419 int err;
420 err = ops->silence(runtime, c, ofs, transfer);
421 snd_BUG_ON(err < 0);
423 } else { */
424 size_t dma_csize = runtime->dma_bytes / channels; /* left samples | right samples */
425 for (c = 0; c < channels; ++c) { /* fixme for sample aliged size in dma buff */
426 char *hwbuf = (char *)runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
427 snd_pcm_format_set_silence(runtime/*->format*/, hwbuf, transfer);
430 runtime->silence_filled += transfer;
431 frames -= transfer;
432 ofs = 0;
437 /*******************************************************************/
438 /* start ,stop,reset ,prepare */
440 * start callbacks
442 struct action_ops {
443 int (*pre_action)(struct snd_pcm_runtime *runtime, int state);
444 int (*do_action)(struct snd_pcm_runtime *runtime, int state);
445 void (*undo_action)(struct snd_pcm_runtime *runtime, int state);
446 void (*post_action)(struct snd_pcm_runtime *runtime, int state);
449 static int snd_pcm_action(struct action_ops *ops,
450 struct snd_pcm_runtime *runtime, int state)
452 int res;
454 /* snd_pcm_start set state = SNDRV_PCM_STATE_RUNNING */
455 res = ops->pre_action(runtime, state);
456 if (res < 0)
457 return res;
458 res = ops->do_action(runtime, state);
459 if (res == 0)
460 ops->post_action(runtime, state);
461 else if (ops->undo_action)
462 ops->undo_action(runtime, state);
463 return res;
466 static int snd_pcm_pre_start(struct snd_pcm_runtime *runtime, int state)
468 if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)
469 return -1;
470 return 0;
473 static int snd_pcm_do_start(struct snd_pcm_runtime *runtime, int state)
475 // the order of triger start
476 //dma triger start
477 //cpu interface triger start
478 return sco_pcm_trigger(runtime ,SNDRV_PCM_TRIGGER_START);
481 static void snd_pcm_undo_start(struct snd_pcm_runtime *runtime, int state)
483 //dma triger stop
484 //cpu interface triger stop
485 sco_pcm_trigger(runtime ,/*SNDRV_PCM_TRIGGER_START*/ SNDRV_PCM_TRIGGER_STOP);
488 static void snd_pcm_post_start(struct snd_pcm_runtime *runtime, int state)
490 runtime->hw_ptr_ticks = get_curr_ticks();
491 runtime->hw_ptr_buffer_ticks = (runtime->buffer_size * HZ) / runtime->rate;
492 runtime->status->state = state;
494 if (runtime->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0)
495 snd_pcm_playback_silence(runtime, ULONG_MAX);
498 static struct action_ops snd_pcm_action_start = {
499 .pre_action = snd_pcm_pre_start,
500 .do_action = snd_pcm_do_start,
501 .undo_action = snd_pcm_undo_start,
502 .post_action = snd_pcm_post_start
505 static int snd_pcm_start(struct snd_pcm_runtime *runtime)
507 /* previous state is prepare */
508 int ret;
509 ret = snd_pcm_action(&snd_pcm_action_start, runtime,
510 SNDRV_PCM_STATE_RUNNING);
511 return ret;
515 * stop callbacks
517 static int snd_pcm_pre_stop(struct snd_pcm_runtime *runtime, int state)
519 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
520 return -1;
521 return 0;
524 static int snd_pcm_do_stop(struct snd_pcm_runtime *runtime, int state)
526 if (snd_pcm_running(runtime)){
527 //ops->trigger(runtime, SNDRV_PCM_TRIGGER_STOP);
528 //dma triger stop
529 //cpu interface triger stop
530 return sco_pcm_trigger(runtime ,SNDRV_PCM_TRIGGER_STOP);
532 return 0; /* unconditonally stop all substreams */
535 static void snd_pcm_post_stop(struct snd_pcm_runtime *runtime, int state)
537 if (runtime->status->state != state) {
538 runtime->status->state = state;
540 // To wake_up something at this
543 static struct action_ops snd_pcm_action_stop = {
544 .pre_action = snd_pcm_pre_stop,
545 .do_action = snd_pcm_do_stop,
546 .post_action = snd_pcm_post_stop
550 * try to stop all running streams in the substream group
551 * The state of each stream is then changed to the given state unconditionally.
553 int snd_pcm_stop(struct snd_pcm_runtime *runtime, snd_pcm_state_t state)
555 return snd_pcm_action(&snd_pcm_action_stop, runtime, state);
559 * reset
561 static int snd_pcm_lib_reset(struct snd_pcm_runtime *runtime,
562 void *arg)
564 unsigned long flags;
565 snd_pcm_stream_lock_irqsave(runtime, flags);
566 if (snd_pcm_running(runtime) &&
567 snd_pcm_update_hw_ptr(runtime) >= 0){
568 printf("reset at run time,hw_ptr >0\n");
569 runtime->status->hw_ptr %= runtime->buffer_size;
571 else{
572 //---printf("reset at not runtime \n");
573 runtime->status->hw_ptr = 0;
575 snd_pcm_stream_unlock_irqrestore(runtime, flags);
576 return 0;
579 static int snd_pcm_pre_reset(struct snd_pcm_runtime *runtime, int state)
581 switch (runtime->status->state) {
582 case SNDRV_PCM_STATE_RUNNING:
583 case SNDRV_PCM_STATE_PREPARED:
584 case SNDRV_PCM_STATE_PAUSED:
585 case SNDRV_PCM_STATE_SUSPENDED:
586 return 0;
587 default:
588 return -1;
592 static int snd_pcm_do_reset(struct snd_pcm_runtime *runtime, int state)
594 /* snd_pcm_lib_reset => runtime->status->hw_ptr = 0; */
595 int err = snd_pcm_lib_reset(runtime, NULL);
596 if (err < 0)
597 return err;
598 runtime->hw_ptr_base = 0;
599 runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
600 runtime->status->hw_ptr % runtime->period_size;
601 runtime->silence_start = runtime->status->hw_ptr;
602 runtime->silence_filled = 0;
603 return 0;
606 static void snd_pcm_post_reset(struct snd_pcm_runtime *runtime, int state)
608 runtime->control->appl_ptr = runtime->status->hw_ptr;
609 /* only playback */
610 if (runtime->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0)
611 snd_pcm_playback_silence(runtime, ULONG_MAX);
614 static struct action_ops snd_pcm_action_reset = {
615 .pre_action = snd_pcm_pre_reset,
616 .do_action = snd_pcm_do_reset,
617 .post_action = snd_pcm_post_reset
620 int snd_pcm_reset(struct snd_pcm_runtime *runtime)
622 /* snd_pcm_start set state = SNDRV_PCM_STATE_RUNNING */
623 return snd_pcm_action(&snd_pcm_action_reset, runtime,
624 SNDRV_PCM_STATE_RUNNING);
627 /* we use the second argument for updating f_flags,
628 must prepare before runing */
629 static int snd_pcm_pre_prepare(struct snd_pcm_runtime *runtime, int f_flags)
631 if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
632 runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
633 return -1;
634 if (snd_pcm_running(runtime)) /* if pcm in the running state */
635 return -1;
636 /*runtime->f_flags = f_flags;*/
637 return 0;
640 static int snd_pcm_do_prepare(struct snd_pcm_runtime *runtime, int state)
642 #if 1
643 sco_pcm_prepare(runtime);
645 /* mark '*' is essential ( sco_pcm_prepare )
646 pre init prepare
647 * dma prepare
648 codec interface prepare
649 cpu interface prepare
651 #endif
652 /* reset silence start = hw_ptr */
653 return snd_pcm_do_reset(runtime, 0);
656 static void snd_pcm_post_prepare(struct snd_pcm_runtime *runtime, int state)
658 /* set appl_prt of write equal the hw_ptr of read*/
659 runtime->control->appl_ptr = runtime->status->hw_ptr;
661 /* set prepared directly ? */
662 runtime->status->state = SNDRV_PCM_STATE_PREPARED;
665 static struct action_ops snd_pcm_action_prepare = {
666 .pre_action = snd_pcm_pre_prepare,
667 .do_action = snd_pcm_do_prepare,
668 .post_action = snd_pcm_post_prepare
672 * snd_pcm_prepare - prepare the PCM substream to be triggerable
674 int snd_pcm_prepare(void * handle)
676 int res;
677 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
678 // wait poweron ,clock on
680 res = snd_pcm_action(&snd_pcm_action_prepare, runtime, 0);
681 return res;
685 * use to stop play
687 static int snd_pcm_drop(struct snd_pcm_runtime *runtime)
689 int result = 0;
691 if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
692 runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
693 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED){
694 pr_err(" Before snd_pcm_drop ,the state is error\n");
695 return -1;
698 snd_pcm_stream_lock_irq(runtime);
699 /* resume pause */
700 //if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
701 //snd_pcm_pause(substream, 0); // runtime->hw_ptr_ticks = get_curr_ticks() - HZ * 1000;
703 snd_pcm_stop(runtime, SNDRV_PCM_STATE_SETUP);
704 /* runtime->control->appl_ptr = runtime->status->hw_ptr; */
705 snd_pcm_stream_unlock_irq(runtime);
707 return result;
711 /* start ,stop,reset ,prepare */
712 /*******************************************************************/
714 static void xrun(struct snd_pcm_runtime *runtime)
716 //os_printf("XRUN\n");
717 #ifdef XRUN_AND_INTRLOST_DEBUG
718 pr_err("X\n");
719 #endif
720 snd_pcm_stop(runtime, SNDRV_PCM_STATE_XRUN);
723 int snd_pcm_update_state(struct snd_pcm_runtime *runtime)
725 snd_pcm_uframes_t avail;
727 if (runtime->stream == SNDRV_PCM_STREAM_PLAYBACK)
728 avail = snd_pcm_playback_avail(runtime);
729 else
730 avail = snd_pcm_capture_avail(runtime);
732 if (avail > runtime->avail_max)
733 runtime->avail_max = avail;
734 #if 0 /* don't support draining */
735 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
736 if (avail >= runtime->buffer_size) {
737 snd_pcm_drain_done(runtime);
738 return -1;
740 } else {
741 #endif
742 if (avail >= runtime->stop_threshold) {
743 os_printf("x%d\n",avail/*,runtime->stop_threshold*/);
744 xrun(runtime);
745 return -1;
747 return 0;
750 static int snd_pcm_update_hw_ptr0(struct snd_pcm_runtime *runtime,
751 unsigned int in_interrupt) /* flag indicate that called by dma complete intr */
753 snd_pcm_uframes_t pos;
754 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
755 snd_pcm_sframes_t hdelta, delta;
756 unsigned long jdelta;
758 old_hw_ptr = runtime->status->hw_ptr;
760 pos = snd_pcm_pointer(runtime,in_interrupt); /* get hardware frame ptr => snd_imx_pcm_pointer */
762 if (pos == /*-1*/SNDRV_PCM_POS_XRUN) { /* indicate over or under run */
763 return -1;
765 if (pos >= runtime->buffer_size) { /* current hardware pointer more than buffer size */
766 os_printf("BUG: pos >= runtime->buffer_size, pos = %ld, "
767 "buffer size = %ld, period size = %ld\n",
768 pos, runtime->buffer_size,
769 runtime->period_size);
770 pos = 0;
772 pos -= pos % runtime->min_align;
774 hw_base = runtime->hw_ptr_base;
775 new_hw_ptr = hw_base + pos;
776 if (in_interrupt) {
777 /* we know that one period was processed */
778 /* delta = "expected next hw_ptr" for in_interrupt != 0 */
779 delta = runtime->hw_ptr_interrupt + runtime->period_size;
780 if (delta > new_hw_ptr) {
781 #ifdef CHECK_DOUBLE_ACKED_INTRS
782 /* check for double acknowledged interrupts */
783 hdelta = get_curr_ticks() - runtime->hw_ptr_ticks;
784 if (hdelta > runtime->hw_ptr_buffer_ticks/2) {
785 printf(" check for double acknowledged interrupts\n");
786 hw_base += runtime->buffer_size; /* reasign hw_base */
787 if (hw_base >= runtime->boundary)
788 hw_base = 0;
789 new_hw_ptr = hw_base + pos;
790 goto __delta;
792 #else
793 hw_base += runtime->buffer_size;
794 if (hw_base >= runtime->boundary)
795 hw_base = 0;
796 new_hw_ptr = hw_base + pos;
797 goto __delta;
798 os_printf("\nd%d>%d\n",delta,new_hw_ptr);
799 #endif
803 /* new_hw_ptr might be lower than old_hw_ptr in case when */
804 /* pointer crosses the end of the ring buffer */
805 if (new_hw_ptr < old_hw_ptr) {
806 hw_base += runtime->buffer_size;
807 if (hw_base >= runtime->boundary)
808 hw_base = 0;
809 new_hw_ptr = hw_base + pos;
811 __delta:
812 delta = new_hw_ptr - old_hw_ptr;
813 if (delta < 0)
814 delta += runtime->boundary;
815 /* xrun debug message
816 snd_printd("_update: %s: pos=%u/%u/%u, "
817 "hwptr=%ld/%ld/%ld/%ld\n",
818 in_interrupt ? "period" : "hwptr",
819 (unsigned int)pos,
820 (unsigned int)runtime->period_size,
821 (unsigned int)runtime->buffer_size,
822 (unsigned long)delta,
823 (unsigned long)old_hw_ptr,
824 (unsigned long)new_hw_ptr,
825 (unsigned long)runtime->hw_ptr_base);
828 //if (runtime->no_period_wakeup) {
829 //this is in not period interrupt condition,
830 //(but period interrupt defined a interrupt occured when period data process completely )
833 /* something must be really wrong */
834 if (delta >= runtime->buffer_size + runtime->period_size) {
835 printf("Unexpected hw_pointer value %s"
836 "( pos=%ld, new_hw_ptr=%ld, "
837 "old_hw_ptr=%ld)\n",
838 in_interrupt ? "[Q] " : "[P]",
839 (long)pos,
840 (long)new_hw_ptr, (long)old_hw_ptr);
841 return 0;
843 #if 0 /* don't support ticks check */
844 /* Skip the ticks check for hardwares with BATCH flag.
845 * Such hardware usually just increases the position at each IRQ,
846 * thus it can't give any strange position.
848 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
849 goto no_ticks_check;
850 hdelta = delta;
851 /* if (hdelta < runtime->delay) // remove for no runtime delay (hdelta 's unit is frames)
852 goto no_ticks_check;
853 hdelta -= runtime->delay; */
854 jdelta = get_curr_ticks() - runtime->hw_ptr_ticks;
855 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
856 delta = jdelta /(((runtime->period_size * HZ) / runtime->rate) + HZ/100);
857 /* move new_hw_ptr according ticks not pos variable */
858 new_hw_ptr = old_hw_ptr;
859 hw_base = delta;
860 /* use loop to avoid checks for delta overflows */
861 /* the delta value is small or zero in most cases */
862 while (delta > 0) {
863 new_hw_ptr += runtime->period_size;
864 if (new_hw_ptr >= runtime->boundary)
865 new_hw_ptr -= runtime->boundary;
866 delta--;
868 /* align hw_base to buffer_size */
870 pr_err(substream,
871 "hw_ptr skipping! %s"
872 "(pos=%ld, delta=%ld, period=%ld, "
873 "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
874 in_interrupt ? "[Q] " : "",
875 (long)pos, (long)hdelta,
876 (long)runtime->period_size, jdelta,
877 ((hdelta * HZ) / runtime->rate), hw_base,
878 (unsigned long)old_hw_ptr,
879 (unsigned long)new_hw_ptr); */
880 /* reset values to proper state */
881 delta = 0;
882 hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
884 #endif
886 no_ticks_check:
887 if (delta > runtime->period_size + runtime->period_size / 2) {
888 /* printf("Lost interrupts? %s"
889 "(stream=%d, delta=%ld, new_hw_ptr=%ld, "
890 "old_hw_ptr=%ld)\n",
891 in_interrupt ? "[Q] " : "",
892 runtime->stream, (long)delta,
893 (long)new_hw_ptr,
894 (long)old_hw_ptr);*/
895 //printf("Lost interrupts?\n");
896 #ifdef XRUN_AND_INTRLOST_DEBUG
897 pr_err("L\n");
898 #endif
901 no_delta_check:
902 if (runtime->status->hw_ptr == new_hw_ptr)
903 return 0;
905 if (runtime->stream == SNDRV_PCM_STREAM_PLAYBACK
906 && runtime->silence_size > 0)
907 snd_pcm_playback_silence(runtime, new_hw_ptr);
909 if (in_interrupt) {
910 delta = new_hw_ptr - runtime->hw_ptr_interrupt;
911 if (delta < 0)
912 delta += runtime->boundary;
913 delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
914 runtime->hw_ptr_interrupt += delta;
915 if (runtime->hw_ptr_interrupt >= runtime->boundary)
916 runtime->hw_ptr_interrupt -= runtime->boundary;
918 runtime->hw_ptr_base = hw_base;
919 runtime->status->hw_ptr = new_hw_ptr;
920 #ifdef CHECK_DOUBLE_ACKED_INTRS
921 runtime->hw_ptr_ticks = get_curr_ticks();
922 #endif
924 return snd_pcm_update_state( runtime);
925 //return 0;
928 /* pcm misc */
929 int pcm_format_width(snd_pcm_format_t format)
931 int val;
932 if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
933 return -1;
934 if ((val = pcm_formats[(INT)format].width) == 0)
935 return -1;
936 return val;
939 int pcm_format_physical_width(snd_pcm_format_t format)
941 int val;
942 if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
943 return -1;
944 if ((val = pcm_formats[(INT)format].phys) == 0)
945 return -1;
946 return val;
949 int pcm_format_little_endian(snd_pcm_format_t format)
951 int val;
952 if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
953 return -1;
954 if ((val = pcm_formats[(INT)format].le) < 0)
955 return -1;
956 return val;
959 /* CAUTION: call it with irq disabled */
960 int snd_pcm_update_hw_ptr(struct snd_pcm_runtime *runtime)
962 return snd_pcm_update_hw_ptr0(runtime, 0);
965 /* called by period interrupt */
966 static void snd_pcm_period_elapsed(struct snd_pcm_runtime *runtime)
968 unsigned long flags;
970 snd_pcm_stream_lock_irqsave(runtime, flags);
971 if (!snd_pcm_running(runtime) ||
972 snd_pcm_update_hw_ptr0(runtime, 1) < 0) /* update hw ptr at dma buffer ! */
973 goto _end;
975 _end:
976 snd_pcm_stream_unlock_irqrestore(runtime, flags);
977 /* after transfer callback ack end
978 if (transfer_ack_end)
979 transfer_ack_end(substream); */
980 return;
983 /* write call back */
984 static int snd_pcm_write_transfer(struct snd_pcm_runtime *runtime,
985 unsigned int hwoff,
986 unsigned long data, unsigned int off,
987 snd_pcm_uframes_t frames)
989 int err;
990 /* the offset of playback write data */
991 char *buf = (char *) data + frames_to_bytes(runtime, off);
992 #if 0
993 if (pcm_stream_copy) {
994 if ((err = pcm_stream_copy(runtime, -1, hwoff, buf, frames)) < 0)
995 return err;
996 } else {
997 /* copy to the place of dma_area hwbuf offset */
998 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
999 os_memcpy(hwbuf, buf, frames_to_bytes(runtime, frames));
1001 #else
1002 sco_pcm_stream_copy(runtime, -1, hwoff, buf, frames);
1003 #endif
1004 return 0;
1008 * Wait until avail_min data becomes available
1009 * Returns a negative error code if any error occurs during operation.
1010 * The available space is stored on availp. When err = 0 and avail = 0
1011 * on the capture stream, it indicates the stream is in DRAINING state.
1013 static int wait_for_avail(struct snd_pcm_runtime *runtime,
1014 snd_pcm_uframes_t *availp)
1016 int is_playback = (runtime->stream == SNDRV_PCM_STREAM_PLAYBACK);
1017 /* wait_queue_t wait; */
1018 int err = 0;
1019 snd_pcm_uframes_t avail = 0;
1020 long wait_time/*, tout*/;
1022 #if 0
1023 if (runtime->no_period_wakeup)
1024 wait_time = MAX_SCHEDULE_TIMEOUT;
1025 else {
1026 wait_time = 10;
1027 if (runtime->rate) {
1028 long t = runtime->period_size * 2 / runtime->rate;
1029 wait_time = max(t, wait_time);
1032 #else
1033 struct sco_pcm_runtime_data *iprtd = (struct sco_pcm_runtime_data *)runtime->private_data;
1035 wait_time = 10;
1036 if (runtime->rate) {
1037 long t = /* runtime->period_size * 2 / runtime->rate */iprtd->period_time;
1038 wait_time = max(t, wait_time); /* use ms delay */
1040 #endif
1042 for (;;) {
1044 * We need to check if space became available already
1045 * (and thus the wakeup happened already) first to close
1046 * the race of space already having become available.
1047 * This check must happen after been added to the waitqueue
1048 * and having current state be INTERRUPTIBLE.
1050 if (is_playback)
1051 avail = snd_pcm_playback_avail(runtime);
1052 else
1053 avail = snd_pcm_capture_avail(runtime);
1055 if (avail >= Wait_avail_min)
1056 break;
1057 snd_pcm_stream_unlock_irq(runtime);
1059 /* or use wait availd event (transfer_ack_end)*/
1060 os_msleep(wait_time);
1062 snd_pcm_stream_lock_irq(runtime);
1064 *availp = avail;
1065 err = -(avail == 0);
1066 return err;
1069 snd_pcm_sframes_t snd_pcm_lib_write(void * handle,
1070 unsigned long data, snd_pcm_uframes_t size ,int nonblock)
1072 snd_pcm_uframes_t xfer = 0;
1073 snd_pcm_uframes_t offset = 0;
1074 int err = 0;
1076 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1078 snd_pcm_stream_lock_irq(runtime);
1080 #if 1 /* open -> prepared -> running */
1081 switch (runtime->status->state) {
1082 case SNDRV_PCM_STATE_PREPARED:
1083 case SNDRV_PCM_STATE_RUNNING:
1084 case SNDRV_PCM_STATE_PAUSED:
1085 break;
1086 case SNDRV_PCM_STATE_XRUN:
1087 err = -1;
1088 goto _end_unlock;
1089 case SNDRV_PCM_STATE_SUSPENDED:
1090 err = -1;
1091 goto _end_unlock;
1092 default:
1093 err = -1;
1094 goto _end_unlock;
1096 #endif
1098 while (size > 0) { /* while until size == 0 */
1099 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1100 snd_pcm_uframes_t avail;
1101 snd_pcm_uframes_t cont;
1102 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
1103 snd_pcm_update_hw_ptr(runtime);
1104 avail = snd_pcm_playback_avail(runtime);
1105 if (!avail) {
1106 if (nonblock) {
1107 err = -1;
1108 goto _end_unlock;
1111 runtime->twake = min_t(snd_pcm_uframes_t, size,
1112 runtime->control->avail_min ? : 1); */
1113 err = wait_for_avail(runtime, &avail); /* wait for peroid consuming time to check has avild space ? */
1114 if (err < 0)
1115 goto _end_unlock;
1118 frames = size > avail ? avail : size; /* min of the size and availd*/
1119 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
1120 if (frames > cont) /* where space at the both of end and first of the dma buffer , process the end space filling firstly */
1121 frames = cont;
1123 if (snd_BUG_ON(!frames)) {
1124 //runtime->twake = 0;
1125 snd_pcm_stream_unlock_irq(runtime);
1126 return -1;
1129 appl_ptr = runtime->control->appl_ptr;
1130 appl_ofs = appl_ptr % runtime->buffer_size; /* attention the mod! it caulate the indeed writing pointer */
1131 snd_pcm_stream_unlock_irq(runtime);
1132 err = snd_pcm_write_transfer(runtime, appl_ofs, data, offset, frames); /* snd_pcm_lib_write_transfer(...) */
1134 snd_pcm_stream_lock_irq(runtime);
1135 if (err < 0)
1136 goto _end_unlock;
1138 appl_ptr += frames;
1139 if (appl_ptr >= runtime->boundary)
1140 appl_ptr -= runtime->boundary; /* update appl_ptr (+frames)*/
1141 runtime->control->appl_ptr = appl_ptr;
1142 // ack();
1144 offset += frames;
1145 size -= frames;
1146 xfer += frames;
1147 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
1148 snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
1149 err = snd_pcm_start(runtime); /* start dma */
1150 if (err < 0)
1151 goto _end_unlock;
1154 _end_unlock:
1156 if (xfer > 0 && err >= 0){
1157 snd_pcm_update_state(runtime);
1159 snd_pcm_stream_unlock_irq(runtime);
1160 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
1164 size_t u_audio_playback(void * handle, void *buf, size_t count)
1166 ssize_t result;
1167 snd_pcm_sframes_t frames;
1169 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1171 try_again:
1172 if(!runtime)
1173 return 0;
1174 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1175 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1176 result = snd_pcm_prepare(runtime);
1177 if (result < 0) {
1178 printf("Preparing sound card failed: %d\n", (int)result);
1179 return result;
1183 frames = bytes_to_frames(runtime, count);
1184 result = snd_pcm_lib_write(runtime,(unsigned long)buf, frames , NON_BLOCK /*RW_BLOCK*/);
1185 if (result != frames) {
1186 if ( runtime->status->state != SNDRV_PCM_STATE_XRUN ) {
1187 //count -= frames_to_bytes(runtime,result);
1188 os_msleep((HZ * runtime->period_size + (runtime->rate -1)) /runtime->rate); /* or sleep 10ms */
1189 //printf("Playback %d error: %d\n", frames, (int)result);
1190 #ifdef XRUN_AND_INTRLOST_DEBUG
1191 printf("%d:%d\n", frames, (int)result);
1192 #endif
1193 return 0;
1195 goto try_again;
1198 return 0;
1201 size_t file_playback(void * handle, void *buf, size_t count)
1203 ssize_t result;
1204 snd_pcm_sframes_t frames;
1206 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1208 try_again:
1209 if(!runtime)
1210 return 0;
1211 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1212 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1213 result = snd_pcm_prepare(runtime);
1214 if (result < 0) {
1215 printf("Preparing sound card failed: %d\n", (int)result);
1216 return result;
1220 frames = bytes_to_frames(runtime, count);
1221 result = snd_pcm_lib_write(runtime,(unsigned long)buf, frames ,/*NON_BLOCK*/RW_BLOCK);
1222 if (result != frames) {
1223 //_time_delay(2);
1224 //os_msleep(10);
1225 os_msleep(/* 10 */(HZ * runtime->period_size + (runtime->rate -1)) /runtime->rate);
1226 printf("Playback error: %d\n", (int)result);
1227 goto try_again;
1230 return 0;
1233 size_t sync_capture(void * handle, void *buf, size_t count)
1235 ssize_t result;
1236 snd_pcm_sframes_t frames;
1238 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1240 try_again:
1241 if(!runtime)
1242 return 0;
1243 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1244 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1245 result = snd_pcm_prepare(runtime);
1246 if (result < 0) {
1247 printf("Preparing sound card failed: %d\n", (int)result);
1248 return result;
1252 frames = bytes_to_frames(runtime, count);
1253 result = snd_pcm_lib_read(runtime,(unsigned long)buf, frames ,/*NON_BLOCK*/RW_BLOCK);
1254 if (result != frames) {
1255 //_time_delay(2);
1256 //os_msleep(10);
1257 os_msleep(/* 10 */(HZ * runtime->period_size + (runtime->rate -1)) /runtime->rate);
1258 printf("scapture error: %d\n", (int)result);
1259 goto try_again;
1262 return 0 /*result*/;
1265 static int snd_pcm_read_transfer(struct snd_pcm_runtime *runtime,
1266 unsigned int hwoff,
1267 unsigned long data, unsigned int off,
1268 snd_pcm_uframes_t frames)
1270 int err;
1271 char *buf = (char *) data + frames_to_bytes(runtime, off);
1272 #if 0
1273 if (pcm_copy) {
1274 if ((err = pcm_copy(runtime, -1, hwoff, buf, frames)) < 0)
1275 return err;
1276 } else {
1277 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
1278 os_memcpy(buf, hwbuf, frames_to_bytes(runtime, frames));
1280 #else
1281 sco_pcm_stream_copy(runtime, -1, hwoff, buf, frames);
1282 return 0;
1283 #endif
1286 /* capture */
1287 snd_pcm_sframes_t snd_pcm_lib_read(void * handle,
1288 unsigned long data, snd_pcm_uframes_t size , int nonblock)
1290 snd_pcm_uframes_t xfer = 0;
1291 snd_pcm_uframes_t offset = 0;
1292 int err = 0;
1294 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1296 if (size == 0)
1297 return 0;
1299 snd_pcm_stream_lock_irq(runtime);
1301 switch (runtime->status->state) {
1302 case SNDRV_PCM_STATE_PREPARED:
1303 if (size >= runtime->start_threshold) {
1304 err = snd_pcm_start(runtime);
1305 if (err < 0)
1306 goto _end_unlock;
1308 break;
1309 case SNDRV_PCM_STATE_DRAINING:
1310 case SNDRV_PCM_STATE_RUNNING:
1311 case SNDRV_PCM_STATE_PAUSED:
1312 break;
1313 case SNDRV_PCM_STATE_XRUN:
1314 err = -1;
1315 goto _end_unlock;
1316 case SNDRV_PCM_STATE_SUSPENDED:
1317 err = -1;
1318 goto _end_unlock;
1319 default:
1320 err = -1;
1321 goto _end_unlock;
1324 while (size > 0) {
1325 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1326 snd_pcm_uframes_t avail;
1327 snd_pcm_uframes_t cont;
1328 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
1329 snd_pcm_update_hw_ptr(runtime);
1330 avail = snd_pcm_capture_avail(runtime);
1331 if (!avail) {
1332 #if 0
1333 if (runtime->status->state ==
1334 SNDRV_PCM_STATE_DRAINING) {
1335 snd_pcm_stop(runtime, SNDRV_PCM_STATE_SETUP);
1336 goto _end_unlock;
1338 #endif
1339 #if 1
1340 if (nonblock) {
1341 err = -1;
1342 goto _end_unlock;
1345 runtime->twake = min_t(snd_pcm_uframes_t, size,
1346 runtime->control->avail_min ? : 1); */
1347 err = wait_for_avail(runtime, &avail);
1348 if (err < 0)
1349 goto _end_unlock;
1350 if (!avail)
1351 continue; /* draining */
1352 #endif
1354 frames = size > avail ? avail : size;
1355 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
1356 if (frames > cont)
1357 frames = cont;
1358 if (snd_BUG_ON(!frames)) {
1359 //runtime->twake = 0;
1360 snd_pcm_stream_unlock_irq(runtime);
1361 return -1;
1363 appl_ptr = runtime->control->appl_ptr;
1364 appl_ofs = appl_ptr % runtime->buffer_size;
1365 snd_pcm_stream_unlock_irq(runtime);
1366 err = /* transfer*/ snd_pcm_read_transfer(runtime, appl_ofs, data, offset, frames);
1367 snd_pcm_stream_lock_irq(runtime);
1368 if (err < 0)
1369 goto _end_unlock;
1371 switch (runtime->status->state) {
1372 case SNDRV_PCM_STATE_XRUN:
1373 err = -1;
1374 goto _end_unlock;
1375 case SNDRV_PCM_STATE_SUSPENDED:
1376 err = -1;
1377 goto _end_unlock;
1378 default:
1379 break;
1382 appl_ptr += frames;
1383 if (appl_ptr >= runtime->boundary)
1384 appl_ptr -= runtime->boundary;
1385 runtime->control->appl_ptr = appl_ptr;
1386 // ack(runtime);
1388 offset += frames;
1389 size -= frames;
1390 xfer += frames;
1392 _end_unlock:
1394 if (xfer > 0 && err >= 0)
1395 snd_pcm_update_state(runtime);
1396 snd_pcm_stream_unlock_irq(runtime);
1397 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
1400 int snd_pcm_params(void * handle,
1401 struct snd_pcm_params *params)
1403 int err, usecs;
1404 unsigned int bits;
1405 snd_pcm_uframes_t frames;
1406 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1408 /*if (PCM_RUNTIME_CHECK(runtime))
1409 return -1;*/
1410 snd_pcm_stream_lock_irq(runtime);
1411 switch (runtime->status->state) {
1412 case SNDRV_PCM_STATE_OPEN:
1413 case SNDRV_PCM_STATE_SETUP:
1414 case SNDRV_PCM_STATE_PREPARED:
1415 break; /* set params only at the state of open,setup and prepared ! */
1416 default:
1417 snd_pcm_stream_unlock_irq(runtime);
1418 return -1;
1420 snd_pcm_stream_unlock_irq(runtime);
1422 /* Default params */
1423 /* SNDRV_PCM_ACCESS_INTERLEAVED;
1424 SNDRV_PCM_ACCESS_NONINTERLEAVED
1425 for two channels ,one channel SNDRV_PCM_ACCESS_INTERLEAVED */
1426 runtime->access = params->access;
1428 runtime->format = params->format;
1429 runtime->channels = params->channels;
1431 /* lookup sample bits from runtime format */
1432 bits = pcm_format_physical_width (runtime->format);
1433 runtime->sample_bits = bits;
1434 bits *= runtime->channels;
1435 runtime->frame_bits = bits;
1437 runtime->sample_aligned_bits = runtime->sample_bits; /* hw buf ,sample aligned bits */
1438 runtime->sample_phy_bits = pcm_format_physical_width(runtime->format);
1440 frames = 1;
1441 while (bits % 8 != 0) {
1442 bits *= 2;
1443 frames *= 2;
1445 /* runtime->byte_align = bits / 8; */
1446 runtime->min_align = frames;
1448 runtime->rate = params->rate;
1450 /* must set before soc codec paramaters setting ! */
1451 runtime->period_size = params->period_size;
1453 err = sco_pcm_params(runtime,params);
1455 runtime->dma_bytes = frames_to_bytes(runtime,runtime->buffer_size)
1456 * runtime->sample_aligned_bits / runtime->sample_phy_bits;
1458 return err;
1461 int pcm_stream_init(void ** handle , unsigned int direction,struct snd_pcm_params *params)
1463 /* static int sco_pcm_open(struct snd_pcm_substream *substream) platform ,sco,cpu dai init startup */
1464 int ret = 0;
1465 unsigned int bits;
1466 snd_pcm_uframes_t frames;
1467 //struct sco_pcm_runtime_data *iprtd = NULL;
1468 struct snd_pcm_runtime **runtime = (struct snd_pcm_runtime **)handle;
1469 static int sys_inited = 0;
1471 if(!sys_inited) {
1472 HZ = get_hz();
1473 sys_inited = 1;
1474 os_printf("system HZ is %d\n",HZ);
1477 ret = snd_pcm_attach_runtime(runtime);
1478 if(ret)
1479 return ret;
1481 (*runtime)->stream = direction;
1483 //iprtd = (struct sco_pcm_runtime_data *)(*runtime)->private_data;
1485 ret = sco_pcm_open(*runtime);
1486 if(ret)
1487 return ret;
1489 if(params) {
1490 ret = snd_pcm_params((void *)(*runtime),params);
1491 if(ret == 0)
1492 snd_pcm_prepare((void *)(*runtime));
1495 return ret;
1498 void pcm_stream_deinit(void * handle)
1500 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1501 //printf("pcm_stream_deinit+\n");
1502 if (PCM_RUNTIME_CHECK(runtime))
1503 return ;
1505 snd_pcm_drop(runtime);
1507 sco_pcm_close(runtime);
1509 //edma_free_chan(SSI_TX_DMA_CHN);
1511 snd_pcm_detach_runtime(runtime);
1512 handle = NULL;
1513 //printf("pcm_stream_deinit-\n");
1516 /* This is first executed function when use this pcm lib , then playback_pcm_runtime_init */
1517 static int snd_pcm_attach_runtime(struct snd_pcm_runtime **runtime)
1519 size_t size;
1520 int extra_size = sizeof(struct sco_pcm_runtime_data);
1522 struct snd_pcm_runtime * pt ;
1524 *runtime = os_zalloc(sizeof(struct snd_pcm_runtime) + extra_size);
1525 if (*runtime == NULL)
1526 return -1;
1527 //printf("%d\n",sizeof(struct snd_pcm_runtime));
1528 os_memset((void *)(*runtime),0, sizeof(struct snd_pcm_runtime) + extra_size);
1530 pt = *runtime;
1532 size = sizeof(struct snd_pcm_rt_status);
1533 /* alloc and zero the snd_pcm_mmap_status struct */
1534 pt->status = os_zalloc(size);
1535 if (pt->status == NULL) {
1536 PCM_mem_free(pt);
1537 return -1;
1540 os_memset((void*)(pt->status), 0, sizeof(struct snd_pcm_rt_status));
1542 size = sizeof(struct snd_pcm_rt_control);
1543 pt->control = os_zalloc(size);
1544 if (pt->control == NULL) {
1545 PCM_mem_free((void*)pt->status);
1546 PCM_mem_free(pt);
1547 return -1;
1549 os_memset((void*)(pt->control), 0, sizeof(struct snd_pcm_rt_control));
1551 pt->private_data = (char *)pt + sizeof(struct snd_pcm_runtime);
1553 /* first status */
1554 pt->status->state = SNDRV_PCM_STATE_OPEN;
1556 return 0;
1559 void snd_pcm_detach_runtime(struct snd_pcm_runtime *runtime)
1561 PCM_mem_free((void*)runtime->status);
1562 PCM_mem_free((void*)runtime->control);
1564 PCM_mem_free(runtime);
1567 int pcm_stream_rate(void * handle)
1569 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1570 unsigned int curr_ticks;
1571 // check handle not null
1572 if (PCM_RUNTIME_CHECK(runtime))
1573 return -1;
1575 if(snd_pcm_running(runtime)){
1576 //printf("%d\n",runtime->hw_ptr_ticks_inteval);
1577 return runtime->period_size * 1000 *100 / runtime->hw_ptr_ticks_inteval;
1579 else
1580 return 0;
1583 int snd_pcm_get_avail_rate(void * handle)
1585 struct snd_pcm_runtime *runtime = (struct snd_pcm_runtime *)handle;
1586 int rate = 0;
1588 if(!snd_pcm_running(runtime))
1589 return -1;
1590 snd_pcm_stream_lock_irq(runtime);
1591 if (runtime->stream == SNDRV_PCM_STREAM_PLAYBACK)
1592 rate = snd_pcm_playback_avail(runtime) * 100 / runtime->buffer_size;
1593 else
1594 rate = snd_pcm_capture_avail(runtime) * 100 / runtime->buffer_size;
1595 snd_pcm_stream_unlock_irq(runtime);
1596 return rate;
1599 int snd_pcm_vol_ctrl(void * handle,int updown) /* 1 up , 0 down */
1601 if(updown)
1602 return sco_pcm_vol_up();
1603 else
1604 return sco_pcm_vol_down();