summaryrefslogtreecommitdiff
path: root/firmware/target/coldfire
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-10-06 22:27:27 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-10-06 22:27:27 +0000
commit6077e5b7c85c0d6f5963e4aadb215faf2c4d10d2 (patch)
treea6bc91ee4168e83617e942eeaea46e5523e82420 /firmware/target/coldfire
parentf6de0d4083a4fcb6da57f271e1f8ccaf715e571d (diff)
downloadrockbox-6077e5b7c85c0d6f5963e4aadb215faf2c4d10d2.tar.gz
rockbox-6077e5b7c85c0d6f5963e4aadb215faf2c4d10d2.zip
Unify PCM interface just above the hardware driver level for all targets including the sims. Perform lockout of audio callback when changing states. Weird new playback or recording trouble? Check before and after this revision first though things seem quite sound.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15006 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/coldfire')
-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 */