Fix buffer overflow when adding a radio preset.
[kugel-rb.git] / firmware / mp3_playback.c
blobb692a017464fb2dacce407b3c65c3f5b07acbcb5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Code that has been in mpeg.c before, now creating an encapsulated play
11 * data module, to be used by other sources than file playback as well.
13 * Copyright (C) 2004 by Linus Nielsen Feltzing
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdbool.h>
23 #include "config.h"
24 #include "debug.h"
25 #include "panic.h"
26 #include <kernel.h>
27 #include "mpeg.h" /* ToDo: remove crosslinks */
28 #include "mp3_playback.h"
29 #include "sound.h"
30 #ifndef SIMULATOR
31 #include "i2c.h"
32 #include "mas.h"
33 #include "dac.h"
34 #include "system.h"
35 #endif
37 /* hacking into mpeg.c, recording is still there */
38 #if CONFIG_CODEC == MAS3587F
39 enum
41 MPEG_DECODER,
42 MPEG_ENCODER
43 } mpeg_mode;
44 #endif /* #ifdef MAS3587F */
46 #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
47 extern unsigned long shadow_io_control_main;
48 extern unsigned shadow_codec_reg0;
49 #endif
51 /**** globals ****/
53 /* own version, independent of mpeg.c */
54 static bool paused; /* playback is paused */
55 static bool playing; /* We are playing an MP3 stream */
57 #ifndef SIMULATOR
58 /* for measuring the play time */
59 static long playstart_tick;
60 static long cumulative_ticks;
62 /* the registered callback function to ask for more mp3 data */
63 static void (*callback_for_more)(unsigned char**, int*);
64 #endif /* #ifndef SIMULATOR */
66 /* list of tracks in memory */
67 #define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */
68 #define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)
70 #ifndef SIMULATOR
71 bool audio_is_initialized = false;
72 #endif
74 /* FIX: this code pretty much assumes a MAS */
76 #ifndef SIMULATOR
78 unsigned long mas_version_code;
80 #if CONFIG_CODEC == MAS3507D
81 static void mas_poll_start(void)
83 unsigned int count;
85 count = 9 * FREQ / 10000 / 8; /* 0.9 ms */
87 /* We are using timer 1 */
89 TSTR &= ~0x02; /* Stop the timer */
90 TSNC &= ~0x02; /* No synchronization */
91 TMDR &= ~0x02; /* Operate normally */
93 TCNT1 = 0; /* Start counting at 0 */
94 GRA1 = count;
95 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
97 /* Enable interrupt on level 5 */
98 IPRC = (IPRC & ~0x000f) | 0x0005;
100 TSR1 &= ~0x02;
101 TIER1 = 0xf9; /* Enable GRA match interrupt */
103 TSTR |= 0x02; /* Start timer 1 */
105 #elif CONFIG_CODEC != SWCODEC
106 static void postpone_dma_tick(void)
108 unsigned int count;
110 count = 8 * FREQ / 10000 / 8; /* 0.8 ms */
112 /* We are using timer 1 */
114 TSTR &= ~0x02; /* Stop the timer */
115 TSNC &= ~0x02; /* No synchronization */
116 TMDR &= ~0x02; /* Operate normally */
118 TCNT1 = 0; /* Start counting at 0 */
119 GRA1 = count;
120 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
122 /* Enable interrupt on level 5 */
123 IPRC = (IPRC & ~0x000f) | 0x0005;
125 TSR1 &= ~0x02;
126 TIER1 = 0xf9; /* Enable GRA match interrupt */
128 TSTR |= 0x02; /* Start timer 1 */
130 #endif
133 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
134 void demand_irq_enable(bool on)
136 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
138 if(on)
140 IPRA = (IPRA & 0xfff0) | 0x000b;
141 ICR &= ~0x0010; /* IRQ3 level sensitive */
143 else
144 IPRA &= 0xfff0;
146 set_irq_level(oldlevel);
148 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
151 void play_tick(void)
153 if(playing && !paused)
155 /* Start DMA if it is disabled and the DEMAND pin is high */
156 if(!(SCR0 & 0x80) && (PBDR & 0x4000))
158 SCR0 |= 0x80;
161 playback_tick(); /* dirty call to mpeg.c */
165 void DEI3(void) __attribute__((interrupt_handler));
166 void DEI3(void)
168 unsigned char* start;
169 int size = 0;
171 if (callback_for_more != NULL)
173 callback_for_more(&start, &size);
176 if (size > 0)
178 DTCR3 = size & 0xffff;
179 SAR3 = (unsigned int) start;
181 else
183 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
186 CHCR3 &= ~0x0002; /* Clear DMA interrupt */
189 void IMIA1(void) __attribute__((interrupt_handler));
190 void IMIA1(void) /* Timer 1 interrupt */
192 if(playing)
193 play_tick();
194 TSR1 &= ~0x01;
195 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
196 /* Disable interrupt */
197 IPRC &= ~0x000f;
198 #endif
201 void IRQ6(void) __attribute__((interrupt_handler));
202 void IRQ6(void) /* PB14: MAS stop demand IRQ */
204 SCR0 &= ~0x80;
207 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
208 void IRQ3(void) __attribute__((interrupt_handler));
209 void IRQ3(void) /* PA15: MAS demand IRQ */
211 /* Begin with setting the IRQ to edge sensitive */
212 ICR |= 0x0010;
214 #if CONFIG_CODEC == MAS3587F
215 if(mpeg_mode == MPEG_ENCODER)
216 rec_tick();
217 else
218 #endif
219 postpone_dma_tick();
221 /* Workaround for sh-elf-gcc 3.3.x bug with -O2 or -Os and ISRs
222 * (invalid cross-jump optimisation) */
223 asm volatile ("");
225 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
227 static void setup_sci0(void)
229 /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */
230 PBCR1 = (PBCR1 & 0x0cff) | 0x1208;
232 /* Set PB12 to output */
233 or_b(0x10, &PBIORH);
235 /* Disable serial port */
236 SCR0 = 0x00;
238 /* Synchronous, no prescale */
239 SMR0 = 0x80;
241 /* Set baudrate 1Mbit/s */
242 BRR0 = 0x02;
244 /* use SCK as serial clock output */
245 SCR0 = 0x01;
247 /* Clear FER and PER */
248 SSR0 &= 0xe7;
250 /* Set interrupt ITU2 and SCI0 priority to 0 */
251 IPRD &= 0x0ff0;
253 /* set PB15 and PB14 to inputs */
254 and_b(~0x80, &PBIORH);
255 and_b(~0x40, &PBIORH);
257 /* Enable End of DMA interrupt at prio 8 */
258 IPRC = (IPRC & 0xf0ff) | 0x0800;
260 /* Enable Tx (only!) */
261 SCR0 |= 0x20;
264 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
265 static void init_playback(void)
267 unsigned long val;
268 int rc;
270 mp3_play_pause(false);
272 mas_reset();
274 /* Enable the audio CODEC and the DSP core, max analog voltage range */
275 rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
276 if(rc < 0)
277 panicf("mas_ctrl_w: %d", rc);
279 /* Stop the current application */
280 val = 0;
281 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
284 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
285 } while(val);
287 /* Enable the D/A Converter */
288 shadow_codec_reg0 = 0x0001;
289 mas_codec_writereg(0x0, shadow_codec_reg0);
291 /* ADC scale 0%, DSP scale 100% */
292 mas_codec_writereg(6, 0x0000);
293 mas_codec_writereg(7, 0x4000);
295 #ifdef HAVE_SPDIF_OUT
296 val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */
297 #else
298 val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */
299 #endif
300 mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1);
302 /* Set Demand mode and validate all settings */
303 shadow_io_control_main = 0x25;
304 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
306 /* Start the Layer2/3 decoder applications */
307 val = 0x0c;
308 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
311 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
312 } while((val & 0x0c) != 0x0c);
314 #if CONFIG_CODEC == MAS3587F
315 mpeg_mode = MPEG_DECODER;
316 #endif
318 /* set IRQ6 to edge detect */
319 ICR |= 0x02;
321 /* set IRQ6 prio 8 */
322 IPRB = ( IPRB & 0xff0f ) | 0x0080;
324 DEBUGF("MAS Decoding application started\n");
326 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
327 #endif /* SIMULATOR */
329 void mp3_init(int volume, int bass, int treble, int balance, int loudness,
330 int avc, int channel_config, int stereo_width,
331 int mdb_strength, int mdb_harmonics,
332 int mdb_center, int mdb_shape, bool mdb_enable,
333 bool superbass)
335 #ifdef SIMULATOR
336 (void)volume;
337 (void)bass;
338 (void)treble;
339 (void)balance;
340 (void)loudness;
341 (void)avc;
342 (void)channel_config;
343 (void)stereo_width;
344 (void)mdb_strength;
345 (void)mdb_harmonics;
346 (void)mdb_center;
347 (void)mdb_shape;
348 (void)mdb_enable;
349 (void)superbass;
350 #else
351 #if CONFIG_CODEC == MAS3507D
352 unsigned long val;
353 (void)loudness;
354 (void)avc;
355 (void)mdb_strength;
356 (void)mdb_harmonics;
357 (void)mdb_center;
358 (void)mdb_shape;
359 (void)mdb_enable;
360 (void)superbass;
361 #endif
363 setup_sci0();
365 #ifdef HAVE_MAS_SIBI_CONTROL
366 and_b(~0x01, &PBDRH); /* drive SIBI low */
367 or_b(0x01, &PBIORH); /* output for PB8 */
368 #endif
370 #if CONFIG_CODEC == MAS3507D
371 mas_reset();
372 #elif CONFIG_CODEC == MAS3587F
373 or_b(0x08, &PAIORH); /* output for /PR */
374 init_playback();
376 mas_version_code = mas_readver();
377 DEBUGF("MAS3587 derivate %d, version %c%d\n",
378 (mas_version_code & 0xf000) >> 12,
379 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
380 #elif CONFIG_CODEC == MAS3539F
381 or_b(0x08, &PAIORH); /* output for /PR */
382 init_playback();
384 mas_version_code = mas_readver();
385 DEBUGF("MAS3539 derivate %d, version %c%d\n",
386 (mas_version_code & 0xf000) >> 12,
387 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
388 #endif
390 #ifdef HAVE_DAC3550A
391 dac_init();
392 #endif
394 #if CONFIG_CODEC == MAS3507D
395 /* set IRQ6 to edge detect */
396 ICR |= 0x02;
398 /* set IRQ6 prio 8 */
399 IPRB = ( IPRB & 0xff0f ) | 0x0080;
401 mas_readmem(MAS_BANK_D1, 0xff7, &mas_version_code, 1);
403 mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */
404 mas_run(1);
405 sleep(HZ);
407 /* Clear the upper 12 bits of the 32-bit samples */
408 mas_writereg(0xc5, 0);
409 mas_writereg(0xc6, 0);
411 /* We need to set the PLL for a 14.31818MHz crystal */
412 if(mas_version_code == 0x0601) /* Version F10? */
414 val = 0x5d9d0;
415 mas_writemem(MAS_BANK_D0, 0x32d, &val, 1);
416 val = 0xfffceceb;
417 mas_writemem(MAS_BANK_D0, 0x32e, &val, 1);
418 val = 0x0;
419 mas_writemem(MAS_BANK_D0, 0x32f, &val, 1);
420 mas_run(0x475);
422 else
424 val = 0x5d9d0;
425 mas_writemem(MAS_BANK_D0, 0x36d, &val, 1);
426 val = 0xfffceceb;
427 mas_writemem(MAS_BANK_D0, 0x36e, &val, 1);
428 val = 0x0;
429 mas_writemem(MAS_BANK_D0, 0x36f, &val, 1);
430 mas_run(0xfcb);
433 #endif
435 #if CONFIG_CODEC == MAS3507D
436 mas_poll_start();
438 mas_writereg(MAS_REG_KPRESCALE, 0xe9400);
439 dac_enable(true);
440 #endif
442 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
443 ICR &= ~0x0010; /* IRQ3 level sensitive */
444 PACR1 = (PACR1 & 0x3fff) | 0x4000; /* PA15 is IRQ3 */
445 #endif
447 /* Must be done before calling sound_set() */
448 audio_is_initialized = true;
450 sound_set(SOUND_BASS, bass);
451 sound_set(SOUND_TREBLE, treble);
452 sound_set(SOUND_BALANCE, balance);
453 sound_set(SOUND_VOLUME, volume);
454 sound_set(SOUND_CHANNELS, channel_config);
455 sound_set(SOUND_STEREO_WIDTH, stereo_width);
457 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
458 sound_set(SOUND_LOUDNESS, loudness);
459 sound_set(SOUND_AVC, avc);
460 sound_set(SOUND_MDB_STRENGTH, mdb_strength);
461 sound_set(SOUND_MDB_HARMONICS, mdb_harmonics);
462 sound_set(SOUND_MDB_CENTER, mdb_center);
463 sound_set(SOUND_MDB_SHAPE, mdb_shape);
464 sound_set(SOUND_MDB_ENABLE, mdb_enable);
465 sound_set(SOUND_SUPERBASS, superbass);
466 #endif
467 #endif /* !SIMULATOR */
469 playing = false;
470 paused = true;
473 void mp3_shutdown(void)
475 #ifndef SIMULATOR
476 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
477 unsigned long val = 1;
478 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &val, 1); /* Mute */
479 #endif
481 #if CONFIG_CODEC == MAS3507D
482 dac_volume(0, 0, false);
483 #endif
485 #endif
488 /* new functions, to be exported to plugin API */
490 #ifndef SIMULATOR
492 void mp3_play_init(void)
494 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
495 init_playback();
496 #endif
497 playing = false;
498 paused = true;
499 callback_for_more = NULL;
500 mp3_reset_playtime();
503 void mp3_play_data(const unsigned char* start, int size,
504 void (*get_more)(unsigned char** start, int* size) /* callback fn */
507 /* init DMA */
508 DAR3 = 0x5FFFEC3;
509 CHCR3 &= ~0x0002; /* Clear interrupt */
510 CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */
511 DMAOR = 0x0001; /* Enable DMA */
513 callback_for_more = get_more;
515 SAR3 = (unsigned int)start;
516 DTCR3 = size & 0xffff;
518 playing = true;
519 paused = true;
521 CHCR3 |= 0x0001; /* Enable DMA IRQ */
523 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
524 demand_irq_enable(true);
525 #endif
528 void mp3_play_pause(bool play)
530 if (paused && play)
531 { /* resume playback */
532 SCR0 |= 0x80;
533 paused = false;
534 playstart_tick = current_tick;
536 else if (!paused && !play)
537 { /* stop playback */
538 SCR0 &= 0x7f;
539 paused = true;
540 cumulative_ticks += current_tick - playstart_tick;
544 bool mp3_pause_done(void)
546 unsigned long frame_count;
548 if (!paused)
549 return false;
551 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count, 1);
552 /* This works because the frame counter never wraps,
553 * i.e. zero always means lost sync. */
554 return frame_count == 0;
557 void mp3_play_stop(void)
559 playing = false;
560 mp3_play_pause(false);
561 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
562 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
563 demand_irq_enable(false);
564 #endif
567 long mp3_get_playtime(void)
569 if (paused)
570 return cumulative_ticks;
571 else
572 return cumulative_ticks + current_tick - playstart_tick;
575 void mp3_reset_playtime(void)
577 cumulative_ticks = 0;
578 playstart_tick = current_tick;
581 bool mp3_is_playing(void)
583 return playing;
587 /* returns the next byte position which would be transferred */
588 unsigned char* mp3_get_pos(void)
590 return (unsigned char*)SAR3;
594 #endif /* #ifndef SIMULATOR */