summaryrefslogtreecommitdiff
path: root/firmware/target/coldfire/pcm-coldfire.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/coldfire/pcm-coldfire.c')
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c478
1 files changed, 170 insertions, 308 deletions
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index 315479f115..6d79ed08f1 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -26,17 +26,6 @@
26#include "spdif.h" 26#include "spdif.h"
27#endif 27#endif
28 28
29/* peaks */
30static unsigned long *rec_peak_addr;
31enum
32{
33 PLAY_PEAK_LEFT = 0,
34 PLAY_PEAK_RIGHT,
35 REC_PEAK_LEFT,
36 REC_PEAK_RIGHT
37};
38static int peaks[4]; /* p-l, p-r, r-l, r-r */
39
40#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \ 29#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
41 (IIS_PLAY & (7 << 8)) | \ 30 (IIS_PLAY & (7 << 8)) | \
42 (4 << 2) ) /* 64 bit clocks / word clock */ 31 (4 << 2) ) /* 64 bit clocks / word clock */
@@ -51,6 +40,12 @@ static int peaks[4]; /* p-l, p-r, r-l, r-r */
51#define IIS_PLAY IIS2CONFIG 40#define IIS_PLAY IIS2CONFIG
52#endif 41#endif
53 42
43struct dma_lock
44{
45 int locked;
46 unsigned long state;
47};
48
54static bool is_playback_monitoring(void) 49static bool is_playback_monitoring(void)
55{ 50{
56 return (IIS_PLAY & (7 << 8)) == (3 << 8); 51 return (IIS_PLAY & (7 << 8)) == (3 << 8);
@@ -93,7 +88,7 @@ static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
93}; 88};
94#endif 89#endif
95 90
96static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ 91static unsigned long pcm_freq = 0; /* 44.1 is default */
97static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT]; 92static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
98 93
99/* set frequency used by the audio hardware */ 94/* set frequency used by the audio hardware */
@@ -126,13 +121,12 @@ void pcm_set_frequency(unsigned int frequency)
126/* apply audio settings */ 121/* apply audio settings */
127bool _pcm_apply_settings(bool clear_reset) 122bool _pcm_apply_settings(bool clear_reset)
128{ 123{
129 static int last_pcm_freq = 0;
130 bool did_reset = false; 124 bool did_reset = false;
131 unsigned long iis_play_defparm = IIS_PLAY_DEFPARM; 125 unsigned long iis_play_defparm = IIS_PLAY_DEFPARM;
132 126
133 if (pcm_freq != last_pcm_freq) 127 if (pcm_freq != pcm_curr_sampr)
134 { 128 {
135 last_pcm_freq = pcm_freq; 129 pcm_curr_sampr = pcm_freq;
136 /* Reprogramming bits 15-12 requires FIFO to be in a reset 130 /* Reprogramming bits 15-12 requires FIFO to be in a reset
137 condition - Users Manual 17-8, Note 11 */ 131 condition - Users Manual 17-8, Note 11 */
138 or_l(IIS_FIFO_RESET, &IIS_PLAY); 132 or_l(IIS_FIFO_RESET, &IIS_PLAY);
@@ -159,6 +153,14 @@ bool _pcm_apply_settings(bool clear_reset)
159 return did_reset; 153 return did_reset;
160} /* _pcm_apply_settings */ 154} /* _pcm_apply_settings */
161 155
156/* apply audio setting with all DMA interrupts disabled */
157void _pcm_apply_settings_irq_lock(bool clear_reset)
158{
159 int level = set_irq_level(DMA_IRQ_LEVEL);
160 _pcm_apply_settings(clear_reset);
161 set_irq_level(level);
162}
163
162/* This clears the reset bit to enable monitoring immediately if monitoring 164/* This clears the reset bit to enable monitoring immediately if monitoring
163 recording sources or always if playback is in progress - we might be 165 recording sources or always if playback is in progress - we might be
164 switching samplerates on the fly */ 166 switching samplerates on the fly */
@@ -176,76 +178,8 @@ void pcm_apply_settings(void)
176 set_irq_level(level); 178 set_irq_level(level);
177} /* pcm_apply_settings */ 179} /* pcm_apply_settings */
178 180
179/** DMA **/ 181void pcm_play_dma_init(void)
180
181/****************************************************************************
182 ** Playback DMA transfer
183 **/
184
185/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
186void pcm_play_dma_start(const void *addr, size_t size)
187{
188 int level;
189
190 logf("pcm_play_dma_start");
191
192 addr = (void *)((unsigned long)addr & ~3); /* Align data */
193 size &= ~3; /* Size must be multiple of 4 */
194
195 /* If a tranfer is going, prevent an interrupt while setting up
196 a new one */
197 level = set_irq_level(DMA_IRQ_LEVEL);
198
199 pcm_playing = true;
200
201 /* Set up DMA transfer */
202 SAR0 = (unsigned long)addr; /* Source address */
203 DAR0 = (unsigned long)&PDOR3; /* Destination address */
204 BCR0 = (unsigned long)size; /* Bytes to transfer */
205
206 /* Enable the FIFO and force one write to it */
207 _pcm_apply_settings(is_playback_monitoring());
208
209 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
210 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
211
212 set_irq_level(level);
213} /* pcm_play_dma_start */
214
215/* Stops the DMA transfer and interrupt */
216static void pcm_play_dma_stop_irq(void)
217{
218 pcm_playing = false;
219 if (!audio_status())
220 pcm_paused = false;
221
222 DSR0 = 1;
223 DCR0 = 0;
224
225 /* Place TX FIFO in reset condition if playback monitoring is on.
226 Recording monitoring something else should not be stopped. */
227 iis_play_reset_if_playback(true);
228} /* pcm_play_dma_stop_irq */
229
230void pcm_play_dma_stop(void)
231{ 182{
232 int level = set_irq_level(DMA_IRQ_LEVEL);
233
234 logf("pcm_play_dma_stop");
235
236 pcm_play_dma_stop_irq();
237
238 set_irq_level(level);
239} /* pcm_play_dma_stop */
240
241void pcm_init(void)
242{
243 logf("pcm_init");
244
245 pcm_playing = false;
246 pcm_paused = false;
247 pcm_callback_for_more = NULL;
248
249 AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */ 183 AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */
250 | (1 << 7) /* PDIR2 fifo auto sync */ 184 | (1 << 7) /* PDIR2 fifo auto sync */
251#ifdef HAVE_SPDIF_OUT 185#ifdef HAVE_SPDIF_OUT
@@ -259,8 +193,6 @@ void pcm_init(void)
259 193
260 /* Call pcm_play_dma_stop to initialize everything. */ 194 /* Call pcm_play_dma_stop to initialize everything. */
261 pcm_play_dma_stop(); 195 pcm_play_dma_stop();
262 /* Call pcm_close_recording to put in closed state */
263 pcm_close_recording();
264 196
265 /* Setup Coldfire I2S before initializing hardware or changing 197 /* Setup Coldfire I2S before initializing hardware or changing
266 other settings. */ 198 other settings. */
@@ -282,14 +214,95 @@ void pcm_init(void)
282#endif 214#endif
283 /* Enable interrupt at level 6, priority 0 */ 215 /* Enable interrupt at level 6, priority 0 */
284 ICR6 = (6 << 2); 216 ICR6 = (6 << 2);
285 and_l(~(1 << 14), &IMR); /* bit 14 is DMA0 */ 217} /* pcm_play_dma_init */
286} /* pcm_init */
287 218
288void pcm_postinit(void) 219void pcm_postinit(void)
289{ 220{
290 audiohw_postinit(); 221 audiohw_postinit();
291} 222}
292 223
224/** DMA **/
225
226/****************************************************************************
227 ** Playback DMA transfer
228 **/
229/* For the locks, DMA interrupt must be disabled when manipulating the lock
230 if the handler ever calls these - right now things are arranged so it
231 doesn't */
232static struct dma_lock dma_play_lock =
233{
234 .locked = 0,
235 .state = (0 << 14) /* bit 14 is DMA0 */
236};
237
238void pcm_play_lock(void)
239{
240 if (++dma_play_lock.locked == 1)
241 or_l((1 << 14), &IMR);
242}
243
244void pcm_play_unlock(void)
245{
246 if (--dma_play_lock.locked == 0)
247 and_l(~dma_play_lock.state, &IMR);
248}
249
250/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
251void pcm_play_dma_start(const void *addr, size_t size)
252{
253 logf("pcm_play_dma_start");
254
255 /* stop any DMA in progress */
256 DSR0 = 1;
257 DCR0 = 0;
258
259 /* Set up DMA transfer */
260 SAR0 = (unsigned long)addr; /* Source address */
261 DAR0 = (unsigned long)&PDOR3; /* Destination address */
262 BCR0 = (unsigned long)size; /* Bytes to transfer */
263
264 /* Enable the FIFO and force one write to it */
265 _pcm_apply_settings_irq_lock(is_playback_monitoring());
266
267 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
268 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
269
270 dma_play_lock.state = (1 << 14);
271} /* pcm_play_dma_start */
272
273/* Stops the DMA transfer and interrupt */
274void pcm_play_dma_stop(void)
275{
276 DSR0 = 1;
277 DCR0 = 0;
278 BCR0 = 0;
279
280 /* Place TX FIFO in reset condition if playback monitoring is on.
281 Recording monitoring something else should not be stopped. */
282 iis_play_reset_if_playback(true);
283
284 dma_play_lock.state = (0 << 14);
285} /* pcm_play_dma_stop */
286
287void pcm_play_dma_pause(bool pause)
288{
289 if (pause)
290 {
291 /* pause playback on current buffer */
292 and_l(~DMA_EEXT, &DCR0);
293 iis_play_reset_if_playback(true);
294 dma_play_lock.state = (0 << 14);
295 }
296 else
297 {
298 /* restart playback on current buffer */
299 /* Enable the FIFO and force one write to it */
300 _pcm_apply_settings_irq_lock(is_playback_monitoring());
301 or_l(DMA_EEXT | DMA_START, &DCR0);
302 dma_play_lock.state = (1 << 14);
303 }
304} /* pcm_play_dma_pause */
305
293size_t pcm_get_bytes_waiting(void) 306size_t pcm_get_bytes_waiting(void)
294{ 307{
295 return BCR0 & 0xffffff; 308 return BCR0 & 0xffffff;
@@ -341,29 +354,54 @@ void DMA0(void)
341#endif 354#endif
342 } 355 }
343 356
344 pcm_play_dma_stop_irq(); 357 /* Stop interrupt and futher transfers */
358 pcm_play_dma_stop();
359 /* Inform PCM that we're done */
360 pcm_play_dma_stopped_callback();
345} /* DMA0 */ 361} /* DMA0 */
346 362
363const void * pcm_play_dma_get_peak_buffer(int *count)
364{
365 unsigned long addr = SAR0;
366 int cnt = BCR0;
367 *count = (cnt & 0xffffff) >> 2;
368 return (void *)((addr + 2) & ~3);
369} /* pcm_play_dma_get_peak_buffer */
370
347/**************************************************************************** 371/****************************************************************************
348 ** Recording DMA transfer 372 ** Recording DMA transfer
349 **/ 373 **/
350void pcm_rec_dma_start(void *addr, size_t size) 374static struct dma_lock dma_rec_lock =
351{ 375{
352 int level; 376 .locked = 0,
353 logf("pcm_rec_dma_start"); 377 .state = (0 << 15) /* bit 15 is DMA1 */
378};
354 379
355 addr = (void *)((unsigned long)addr & ~3); /* Align data */ 380/* For the locks, DMA interrupt must be disabled when manipulating the lock
356 size &= ~3; /* Size must be multiple of 4 */ 381 if the handler ever calls these - right now things are arranged so it
382 doesn't */
383void pcm_rec_lock(void)
384{
385 if (++dma_rec_lock.locked == 1)
386 or_l((1 << 15), &IMR);
387}
357 388
358 /* No DMA1 interrupts while setting up a new transfer */ 389void pcm_rec_unlock(void)
359 level = set_irq_level(DMA_IRQ_LEVEL); 390{
391 if (--dma_rec_lock.locked == 0)
392 and_l(~dma_rec_lock.state, &IMR);
393}
360 394
361 pcm_recording = true; 395void pcm_rec_dma_start(void *addr, size_t size)
396{
397 /* stop any DMA in progress */
398 and_l(~DMA_EEXT, &DCR1);
399 DSR1 = 1;
362 400
363 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); 401 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
364 /* Clear TX FIFO reset bit if the source is not set to monitor playback 402 /* Clear TX FIFO reset bit if the source is not set to monitor playback
365 otherwise maintain independence between playback and recording. */ 403 otherwise maintain independence between playback and recording. */
366 _pcm_apply_settings(!is_playback_monitoring()); 404 _pcm_apply_settings_irq_lock(!is_playback_monitoring());
367 405
368 /* Start the DMA transfer.. */ 406 /* Start the DMA transfer.. */
369#ifdef HAVE_SPDIF_REC 407#ifdef HAVE_SPDIF_REC
@@ -371,74 +409,48 @@ void pcm_rec_dma_start(void *addr, size_t size)
371 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22); 409 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
372#endif 410#endif
373 411
374 SAR1 = (unsigned long)&PDIR2; /* Source address */ 412 SAR1 = (unsigned long)&PDIR2; /* Source address */
375 rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */ 413 pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
376 DAR1 = (unsigned long)addr; /* Destination address */ 414 DAR1 = (unsigned long)addr; /* Destination address */
377 BCR1 = (unsigned long)size; /* Bytes to transfer */ 415 BCR1 = (unsigned long)size; /* Bytes to transfer */
378 416
379 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | 417 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
380 DMA_DSIZE(DMA_SIZE_LINE) /* | DMA_START */; 418 DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
381 419
382 set_irq_level(level); 420 dma_rec_lock.state = (1 << 15);
383} /* pcm_dma_start */ 421} /* pcm_rec_dma_start */
384 422
385static void pcm_rec_dma_stop_irq(void) 423void pcm_rec_dma_stop(void)
386{ 424{
387 DSR1 = 1; /* Clear interrupt */ 425 DSR1 = 1; /* Clear interrupt */
388 DCR1 = 0; 426 DCR1 = 0;
389 pcm_recording = false; 427 BCR1 = 0;
390 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL); 428 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
391 429
392 iis_play_reset_if_playback(false); 430 iis_play_reset_if_playback(false);
393} /* pcm_rec_dma_stop_irq */
394
395void pcm_rec_dma_stop(void)
396{
397 int level = set_irq_level(DMA_IRQ_LEVEL);
398
399 logf("pcm_rec_dma_stop");
400
401 pcm_rec_dma_stop_irq();
402 431
403 set_irq_level(level); 432 dma_rec_lock.state = (0 << 15);
404} /* pcm_rec_dma_stop */ 433} /* pcm_rec_dma_stop */
405 434
406void pcm_init_recording(void) 435void pcm_rec_dma_init(void)
407{ 436{
408 int level = set_irq_level(DMA_IRQ_LEVEL); 437 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
409 438 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
410 logf("pcm_init_recording");
411
412 pcm_recording = false;
413 pcm_callback_more_ready = NULL;
414
415 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
416 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
417 and_l(0xffff00ff, &DMAROUTE); 439 and_l(0xffff00ff, &DMAROUTE);
418 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE); 440 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE);
419 441
420 pcm_rec_dma_stop_irq(); 442 pcm_rec_dma_stop();
421
422 ICR7 = (6 << 2) | (1 << 0); /* Enable interrupt at level 6, priority 1 */
423 and_l(~(1 << 15), &IMR); /* bit 15 is DMA1 */
424 443
425 set_irq_level(level); 444 /* Enable interrupt at level 6, priority 1 */
445 ICR7 = (6 << 2) | (1 << 0);
426} /* pcm_init_recording */ 446} /* pcm_init_recording */
427 447
428void pcm_close_recording(void) 448void pcm_rec_dma_close(void)
429{ 449{
430 int level = set_irq_level(DMA_IRQ_LEVEL);
431
432 logf("pcm_close_recording");
433
434 pcm_rec_dma_stop_irq();
435
436 and_l(0xffff00ff, &DMAROUTE); 450 and_l(0xffff00ff, &DMAROUTE);
437 ICR7 = 0x00; /* Disable interrupt */ 451 ICR7 = 0x00; /* Disable interrupt */
438 or_l((1 << 15), &IMR); /* bit 15 is DMA1 */ 452 dma_rec_lock.state = (0 << 15);
439 453} /* pcm_rec_dma_close */
440 set_irq_level(level);
441} /* pcm_close_recording */
442 454
443/* DMA1 Interrupt is called when the DMA has finished transfering a chunk 455/* DMA1 Interrupt is called when the DMA has finished transfering a chunk
444 into the caller's buffer */ 456 into the caller's buffer */
@@ -485,175 +497,25 @@ void DMA1(void)
485 logf("DMA1 done:%04x %d", res, status); 497 logf("DMA1 done:%04x %d", res, status);
486#endif 498#endif
487 /* Finished recording */ 499 /* Finished recording */
488 pcm_rec_dma_stop_irq(); 500 pcm_rec_dma_stop();
501 /* Inform PCM that we're done */
502 pcm_rec_dma_stopped_callback();
489} /* DMA1 */ 503} /* DMA1 */
490 504
491/* Continue transferring data in - call from interrupt callback */ 505/* Continue transferring data in - call from interrupt callback */
492void pcm_record_more(void *start, size_t size) 506void pcm_record_more(void *start, size_t size)
493{ 507{
494 rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ 508 pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
495 DAR1 = (unsigned long)start; /* Destination address */ 509 DAR1 = (unsigned long)start; /* Destination address */
496 BCR1 = (unsigned long)size; /* Bytes to transfer */ 510 BCR1 = (unsigned long)size; /* Bytes to transfer */
497 or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */ 511 or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */
498} 512} /* pcm_record_more */
499 513
500void pcm_mute(bool mute) 514const void * pcm_rec_dma_get_peak_buffer(int *count)
501{ 515{
502 audiohw_mute(mute); 516 unsigned long addr = (unsigned long)pcm_rec_peak_addr;
503 if (mute) 517 unsigned long end = DAR1;
504 sleep(HZ/16); 518 addr >>= 2;
505} /* pcm_mute */ 519 *count = (end >> 2) - addr;
506 520 return (void *)(addr << 2);
507void pcm_play_pause_pause(void) 521} /* pcm_rec_dma_get_peak_buffer */
508{
509 /* Disable DMA peripheral request. */
510 int level = set_irq_level(DMA_IRQ_LEVEL);
511
512 and_l(~DMA_EEXT, &DCR0);
513 iis_play_reset_if_playback(true);
514
515 set_irq_level(level);
516} /* pcm_play_pause_pause */
517
518void pcm_play_pause_unpause(void)
519{
520 int level = set_irq_level(DMA_IRQ_LEVEL);
521
522 /* Enable the FIFO and force one write to it */
523 _pcm_apply_settings(is_playback_monitoring());
524 or_l(DMA_EEXT | DMA_START, &DCR0);
525
526 set_irq_level(level);
527} /* pcm_play_pause_unpause */
528
529/**
530 * Do peak calculation using distance squared from axis and save a lot
531 * of jumps and negation. Don't bother with the calculations of left or
532 * right only as it's never really used and won't save much time.
533 */
534static void pcm_peak_peeker(unsigned long *addr, unsigned long *end,
535 int peaks[2])
536{
537 long peak_l = 0, peak_r = 0;
538 long peaksq_l = 0, peaksq_r = 0;
539
540 do
541 {
542 long value = *addr;
543 long ch, chsq;
544
545 ch = value >> 16;
546 chsq = ch*ch;
547 if (chsq > peaksq_l)
548 peak_l = ch, peaksq_l = chsq;
549
550 ch = (short)value;
551 chsq = ch*ch;
552 if (chsq > peaksq_r)
553 peak_r = ch, peaksq_r = chsq;
554
555 addr += 4;
556 }
557 while (addr < end);
558
559 peaks[0] = abs(peak_l);
560 peaks[1] = abs(peak_r);
561} /* pcm_peak_peeker */
562
563/**
564 * Return playback peaks - Peaks ahead in the DMA buffer based upon the
565 * calling period to attempt to compensate for
566 * delay.
567 */
568void pcm_calculate_peaks(int *left, int *right)
569{
570 static unsigned long last_peak_tick = 0;
571 static unsigned long frame_period = 0;
572
573 long samples, samp_frames;
574 unsigned long *addr;
575
576 /* Throttled peak ahead based on calling period */
577 unsigned long period = current_tick - last_peak_tick;
578
579 /* Keep reasonable limits on period */
580 if (period < 1)
581 period = 1;
582 else if (period > HZ/5)
583 period = HZ/5;
584
585 frame_period = (3*frame_period + period) >> 2;
586
587 last_peak_tick = current_tick;
588
589 if (pcm_playing && !pcm_paused)
590 {
591 /* Snapshot as quickly as possible */
592 asm volatile (
593 "move.l %c[sar0], %[start] \n"
594 "move.l %c[bcr0], %[count] \n"
595 : [start]"=r"(addr), [count]"=r"(samples)
596 : [sar0]"p"(&SAR0), [bcr0]"p"(&BCR0)
597 );
598
599 samples &= 0xfffffc;
600 samp_frames = frame_period*pcm_freq/(HZ/4);
601 samples = MIN(samp_frames, samples) >> 2;
602
603 if (samples > 0)
604 {
605 addr = (long *)((long)addr & ~3);
606 pcm_peak_peeker(addr, addr + samples, &peaks[PLAY_PEAK_LEFT]);
607 }
608 }
609 else
610 {
611 peaks[PLAY_PEAK_LEFT] = peaks[PLAY_PEAK_RIGHT] = 0;
612 }
613
614 if (left)
615 *left = peaks[PLAY_PEAK_LEFT];
616
617 if (right)
618 *right = peaks[PLAY_PEAK_RIGHT];
619} /* pcm_calculate_peaks */
620
621/**
622 * Return recording peaks - From the end of the last peak up to
623 * current write position.
624 */
625void pcm_calculate_rec_peaks(int *left, int *right)
626{
627 if (pcm_recording)
628 {
629 unsigned long *addr, *end;
630
631 /* Snapshot as quickly as possible */
632 asm volatile (
633 "move.l %c[start], %[addr] \n"
634 "move.l %c[dar1], %[end] \n"
635 "and.l %[mask], %[addr] \n"
636 "and.l %[mask], %[end] \n"
637 : [addr]"=r"(addr), [end]"=r"(end)
638 : [start]"p"(&rec_peak_addr), [dar1]"p"(&DAR1), [mask]"r"(~3)
639 );
640
641 if (addr < end)
642 {
643 pcm_peak_peeker(addr, end, &peaks[REC_PEAK_LEFT]);
644
645 if (addr == rec_peak_addr)
646 rec_peak_addr = end;
647 }
648 }
649 else
650 {
651 peaks[REC_PEAK_LEFT] = peaks[REC_PEAK_RIGHT] = 0;
652 }
653
654 if (left)
655 *left = peaks[REC_PEAK_LEFT];
656
657 if (right)
658 *right = peaks[REC_PEAK_RIGHT];
659} /* pcm_calculate_rec_peaks */