FS#7487 - mpegplayer - video start time seek with resume
[Rockbox.git] / apps / plugin.c
blob7981c36b92b2594ea17dc92762beaca929690244
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "plugin.h"
20 #include <ctype.h>
21 #include <string.h>
22 #include <sprintf.h>
23 #include <atoi.h>
24 #include "debug.h"
25 #include "i2c.h"
26 #include "lang.h"
27 #include "led.h"
28 #include "keyboard.h"
29 #include "buffer.h"
30 #include "backlight.h"
31 #include "sound_menu.h"
32 #include "mp3data.h"
33 #include "powermgmt.h"
34 #include "splash.h"
35 #include "logf.h"
36 #include "option_select.h"
37 #include "talk.h"
39 #if CONFIG_CHARGING
40 #include "power.h"
41 #endif
43 #ifdef HAVE_LCD_BITMAP
44 #include "scrollbar.h"
45 #include "peakmeter.h"
46 #include "bmp.h"
47 #include "bidi.h"
48 #endif
50 #ifdef SIMULATOR
51 static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
52 void *sim_plugin_load(char *plugin, void **pd);
53 void sim_plugin_close(void *pd);
54 void sim_lcd_ex_init(int shades, unsigned long (*getpixel)(int, int));
55 void sim_lcd_ex_update_rect(int x, int y, int width, int height);
56 #else
57 #define sim_plugin_close(x)
58 extern unsigned char pluginbuf[];
59 #include "bitswap.h"
60 #endif
62 /* for actual plugins only, not for codecs */
63 static bool plugin_loaded = false;
64 static int plugin_size = 0;
65 static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
66 static char current_plugin[MAX_PATH];
68 char *plugin_get_current_filename(void);
70 extern struct thread_entry threads[MAXTHREADS];
72 static const struct plugin_api rockbox_api = {
74 /* lcd */
75 lcd_set_contrast,
76 lcd_update,
77 lcd_clear_display,
78 lcd_setmargins,
79 lcd_getstringsize,
80 lcd_putsxy,
81 lcd_puts,
82 lcd_puts_scroll,
83 lcd_stop_scroll,
84 #ifdef HAVE_LCD_CHARCELLS
85 lcd_define_pattern,
86 lcd_get_locked_pattern,
87 lcd_unlock_pattern,
88 lcd_putc,
89 lcd_put_cursor,
90 lcd_remove_cursor,
91 lcd_icon,
92 lcd_double_height,
93 #else
94 lcd_set_drawmode,
95 lcd_get_drawmode,
96 lcd_setfont,
97 lcd_drawpixel,
98 lcd_drawline,
99 lcd_hline,
100 lcd_vline,
101 lcd_drawrect,
102 lcd_fillrect,
103 lcd_mono_bitmap_part,
104 lcd_mono_bitmap,
105 #if LCD_DEPTH > 1
106 lcd_set_foreground,
107 lcd_get_foreground,
108 lcd_set_background,
109 lcd_get_background,
110 lcd_bitmap_part,
111 lcd_bitmap,
112 lcd_get_backdrop,
113 lcd_set_backdrop,
114 #endif
115 #if LCD_DEPTH == 16
116 lcd_bitmap_transparent_part,
117 lcd_bitmap_transparent,
118 #endif
119 bidi_l2v,
120 font_get_bits,
121 font_load,
122 lcd_puts_style,
123 lcd_puts_scroll_style,
124 &lcd_framebuffer[0][0],
125 lcd_blit,
126 lcd_update_rect,
127 gui_scrollbar_draw,
128 font_get,
129 font_getstringsize,
130 font_get_width,
131 screen_clear_area,
132 #endif
133 backlight_on,
134 backlight_off,
135 backlight_set_timeout,
136 #if CONFIG_CHARGING
137 backlight_set_timeout_plugged,
138 #endif
139 gui_syncsplash,
140 #ifdef HAVE_REMOTE_LCD
141 /* remote lcd */
142 lcd_remote_set_contrast,
143 lcd_remote_clear_display,
144 lcd_remote_puts,
145 lcd_remote_puts_scroll,
146 lcd_remote_stop_scroll,
147 lcd_remote_set_drawmode,
148 lcd_remote_get_drawmode,
149 lcd_remote_setfont,
150 lcd_remote_getstringsize,
151 lcd_remote_drawpixel,
152 lcd_remote_drawline,
153 lcd_remote_hline,
154 lcd_remote_vline,
155 lcd_remote_drawrect,
156 lcd_remote_fillrect,
157 lcd_remote_mono_bitmap_part,
158 lcd_remote_mono_bitmap,
159 lcd_remote_putsxy,
160 lcd_remote_puts_style,
161 lcd_remote_puts_scroll_style,
162 &lcd_remote_framebuffer[0][0],
163 lcd_remote_update,
164 lcd_remote_update_rect,
166 remote_backlight_on,
167 remote_backlight_off,
168 #endif
169 #if NB_SCREENS == 2
170 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
171 #else
172 {&screens[SCREEN_MAIN]},
173 #endif
174 #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
175 lcd_remote_set_foreground,
176 lcd_remote_get_foreground,
177 lcd_remote_set_background,
178 lcd_remote_get_background,
179 lcd_remote_bitmap_part,
180 lcd_remote_bitmap,
181 #endif
183 #if defined(HAVE_LCD_COLOR)
184 lcd_yuv_blit,
185 #endif
186 /* list */
187 gui_synclist_init,
188 gui_synclist_set_nb_items,
189 gui_synclist_set_icon_callback,
190 gui_synclist_get_nb_items,
191 gui_synclist_get_sel_pos,
192 gui_synclist_draw,
193 gui_synclist_select_item,
194 gui_synclist_add_item,
195 gui_synclist_del_item,
196 gui_synclist_limit_scroll,
197 gui_synclist_flash,
198 gui_synclist_do_button,
199 gui_synclist_set_title,
201 /* button */
202 button_get,
203 button_get_w_tmo,
204 button_status,
205 button_clear_queue,
206 #ifdef HAS_BUTTON_HOLD
207 button_hold,
208 #endif
210 /* file */
211 (open_func)PREFIX(open),
212 PREFIX(close),
213 (read_func)PREFIX(read),
214 PREFIX(lseek),
215 (creat_func)PREFIX(creat),
216 (write_func)PREFIX(write),
217 PREFIX(remove),
218 PREFIX(rename),
219 PREFIX(ftruncate),
220 PREFIX(filesize),
221 fdprintf,
222 read_line,
223 settings_parseline,
224 #ifndef SIMULATOR
225 ata_sleep,
226 ata_disk_is_active,
227 #endif
228 ata_spindown,
229 reload_directory,
230 create_numbered_filename,
232 /* dir */
233 opendir,
234 closedir,
235 readdir,
236 mkdir,
237 rmdir,
239 /* kernel/ system */
240 PREFIX(sleep),
241 yield,
242 #ifdef HAVE_PRIORITY_SCHEDULING
243 priority_yield,
244 #endif
245 &current_tick,
246 default_event_handler,
247 default_event_handler_ex,
248 threads,
249 create_thread,
250 remove_thread,
251 reset_poweroff_timer,
252 #ifndef SIMULATOR
253 system_memory_guard,
254 &cpu_frequency,
256 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
257 #ifdef CPU_BOOST_LOGGING
258 cpu_boost_,
259 #else
260 cpu_boost,
261 #endif
262 #endif
263 #endif
264 timer_register,
265 timer_unregister,
266 timer_set_period,
268 queue_init,
269 queue_delete,
270 queue_post,
271 queue_wait_w_tmo,
272 usb_acknowledge,
273 #ifdef RB_PROFILE
274 profile_thread,
275 profstop,
276 profile_func_enter,
277 profile_func_exit,
278 #endif
280 #ifdef SIMULATOR
281 /* special simulator hooks */
282 #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH < 8
283 sim_lcd_ex_init,
284 sim_lcd_ex_update_rect,
285 #endif
286 #endif
288 /* strings and memory */
289 snprintf,
290 vsnprintf,
291 strcpy,
292 strncpy,
293 strlen,
294 strrchr,
295 strcmp,
296 strncmp,
297 strcasecmp,
298 strncasecmp,
299 memset,
300 memcpy,
301 memmove,
302 _ctype_,
303 atoi,
304 strchr,
305 strcat,
306 memchr,
307 memcmp,
308 strcasestr,
309 strtok_r,
310 /* unicode stuff */
311 utf8decode,
312 iso_decode,
313 utf16LEdecode,
314 utf16BEdecode,
315 utf8encode,
316 utf8length,
317 utf8seek,
319 /* sound */
320 #if CONFIG_CODEC == SWCODEC
321 sound_default,
322 #endif
323 sound_set,
325 sound_min,
326 sound_max,
327 #ifndef SIMULATOR
328 mp3_play_data,
329 mp3_play_pause,
330 mp3_play_stop,
331 mp3_is_playing,
332 #if CONFIG_CODEC != SWCODEC
333 bitswap,
334 #endif
335 #endif
336 #if CONFIG_CODEC == SWCODEC
337 &audio_master_sampr_list[0],
338 &hw_freq_sampr[0],
339 pcm_apply_settings,
340 pcm_play_data,
341 pcm_play_stop,
342 pcm_set_frequency,
343 pcm_is_playing,
344 pcm_is_paused,
345 pcm_play_pause,
346 pcm_get_bytes_waiting,
347 pcm_calculate_peaks,
348 #ifdef HAVE_RECORDING
349 &rec_freq_sampr[0],
350 pcm_init_recording,
351 pcm_close_recording,
352 pcm_record_data,
353 pcm_record_more,
354 pcm_stop_recording,
355 pcm_calculate_rec_peaks,
356 audio_set_recording_gain,
357 #endif /* HAVE_RECORDING */
358 #if INPUT_SRC_CAPS != 0
359 audio_set_output_source,
360 audio_set_input_source,
361 #endif
362 #endif /* CONFIG_CODEC == SWCODEC */
364 /* playback control */
365 playlist_amount,
366 playlist_resume,
367 playlist_start,
368 PREFIX(audio_play),
369 audio_stop,
370 audio_pause,
371 audio_resume,
372 audio_next,
373 audio_prev,
374 audio_ff_rewind,
375 audio_next_track,
376 audio_status,
377 audio_has_changed_track,
378 audio_current_track,
379 audio_flush_and_reload_tracks,
380 audio_get_file_pos,
381 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
382 mpeg_get_last_header,
383 #endif
384 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) || \
385 (CONFIG_CODEC == SWCODEC)
386 sound_set_pitch,
387 #endif
389 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
390 /* MAS communication */
391 mas_readmem,
392 mas_writemem,
393 mas_readreg,
394 mas_writereg,
395 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
396 mas_codec_writereg,
397 mas_codec_readreg,
398 i2c_begin,
399 i2c_end,
400 i2c_write,
401 #endif
402 #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
404 /* menu */
405 do_menu,
406 /* statusbars */
407 &statusbars,
408 gui_syncstatusbar_draw,
409 /* options */
410 find_setting,
411 option_screen,
412 set_option,
413 set_bool_options,
414 set_int,
415 set_bool,
416 #ifdef HAVE_LCD_COLOR
417 set_color,
418 #endif
420 /* action handling */
421 get_custom_action,
422 get_action,
423 action_userabort,
425 /* power */
426 battery_level,
427 battery_level_safe,
428 battery_time,
429 #ifndef SIMULATOR
430 battery_voltage,
431 #endif
432 #if CONFIG_CHARGING
433 charger_inserted,
434 # if CONFIG_CHARGING == CHARGING_MONITOR
435 charging_state,
436 # endif
437 #endif
438 #ifdef HAVE_USB_POWER
439 usb_powered,
440 #endif
442 /* misc */
443 srand,
444 rand,
445 (qsort_func)qsort,
446 kbd_input,
447 get_time,
448 set_time,
449 #if CONFIG_RTC
450 mktime,
451 #endif
452 plugin_get_buffer,
453 plugin_get_audio_buffer,
454 plugin_tsr,
455 plugin_get_current_filename,
456 #ifdef IRAM_STEAL
457 plugin_iram_init,
458 #endif
459 #if defined(DEBUG) || defined(SIMULATOR)
460 debugf,
461 #endif
462 #ifdef ROCKBOX_HAS_LOGF
463 _logf,
464 #endif
465 &global_settings,
466 &global_status,
467 mp3info,
468 count_mp3_frames,
469 create_xing_header,
470 find_next_frame,
471 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
472 peak_meter_scale_value,
473 peak_meter_set_use_dbfs,
474 peak_meter_get_use_dbfs,
475 #endif
476 #ifdef HAVE_LCD_BITMAP
477 read_bmp_file,
478 screen_dump_set_hook,
479 #endif
480 show_logo,
481 tree_get_context,
482 set_current_file,
483 set_dirfilter,
485 #ifdef HAVE_WHEEL_POSITION
486 wheel_status,
487 wheel_send_events,
488 #endif
490 #ifdef IRIVER_H100_SERIES
491 /* Routines for the iriver_flash -plugin. */
492 detect_original_firmware,
493 detect_flashed_ramimage,
494 detect_flashed_romimage,
495 #endif
496 /* new stuff at the end, sort into place next time
497 the API gets incompatible */
499 #if (CONFIG_CODEC == SWCODEC)
500 spinlock_init,
501 spinlock_lock,
502 spinlock_unlock,
504 codec_load_file,
505 get_codec_filename,
506 get_metadata,
507 #endif
508 led,
510 #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
511 lcd_yuv_set_options,
512 #endif
514 #ifdef CACHE_FUNCTIONS_AS_CALL
515 flush_icache,
516 invalidate_icache,
517 #endif
518 talk_disable_menus,
519 talk_enable_menus,
521 button_available,
525 int plugin_load(const char* plugin, void* parameter)
527 int rc;
528 struct plugin_header *hdr;
529 #ifdef SIMULATOR
530 void *pd;
531 #else
532 int fd;
533 ssize_t readsize;
534 #endif
535 int xm, ym;
536 #ifdef HAVE_REMOTE_LCD
537 int rxm, rym;
538 #endif
540 #if LCD_DEPTH > 1
541 fb_data* old_backdrop;
542 #endif
544 if (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */
546 if (pfn_tsr_exit(!strcmp(current_plugin, plugin)) == false )
548 /* not allowing another plugin to load */
549 return PLUGIN_OK;
551 pfn_tsr_exit = NULL;
552 plugin_loaded = false;
555 gui_syncsplash(0, ID2P(LANG_WAIT));
556 strcpy(current_plugin, plugin);
558 #ifdef SIMULATOR
559 hdr = sim_plugin_load((char *)plugin, &pd);
560 if (pd == NULL) {
561 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
562 return -1;
564 if (hdr == NULL
565 || hdr->magic != PLUGIN_MAGIC
566 || hdr->target_id != TARGET_ID) {
567 sim_plugin_close(pd);
568 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
569 return -1;
571 if (hdr->api_version > PLUGIN_API_VERSION
572 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
573 sim_plugin_close(pd);
574 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
575 return -1;
577 #else
578 fd = open(plugin, O_RDONLY);
579 if (fd < 0) {
580 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
581 return fd;
584 readsize = read(fd, pluginbuf, PLUGIN_BUFFER_SIZE);
585 close(fd);
587 if (readsize < 0) {
588 gui_syncsplash(HZ*2, str(LANG_READ_FAILED), plugin);
589 return -1;
591 hdr = (struct plugin_header *)pluginbuf;
593 if ((unsigned)readsize <= sizeof(struct plugin_header)
594 || hdr->magic != PLUGIN_MAGIC
595 || hdr->target_id != TARGET_ID
596 || hdr->load_addr != pluginbuf
597 || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE) {
598 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
599 return -1;
601 if (hdr->api_version > PLUGIN_API_VERSION
602 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
603 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
604 return -1;
606 plugin_size = hdr->end_addr - pluginbuf;
608 /* zero out bss area only, above guards end of pluginbuf */
609 if (plugin_size > readsize)
610 memset(pluginbuf + readsize, 0, plugin_size - readsize);
611 #endif
613 plugin_loaded = true;
615 xm = lcd_getxmargin();
616 ym = lcd_getymargin();
617 lcd_setmargins(0,0);
619 #if defined HAVE_LCD_BITMAP && LCD_DEPTH > 1
620 old_backdrop = lcd_get_backdrop();
621 #endif
622 lcd_clear_display();
623 lcd_update();
625 #ifdef HAVE_REMOTE_LCD
626 rxm = lcd_remote_getxmargin();
627 rym = lcd_remote_getymargin();
628 lcd_remote_setmargins(0, 0);
629 lcd_remote_clear_display();
630 lcd_remote_update();
631 #endif
633 invalidate_icache();
635 rc = hdr->entry_point((struct plugin_api*) &rockbox_api, parameter);
636 /* explicitly casting the pointer here to avoid touching every plugin. */
638 button_clear_queue();
640 #ifdef HAVE_LCD_BITMAP
641 #if LCD_DEPTH > 1
642 lcd_set_backdrop(old_backdrop);
643 #ifdef HAVE_LCD_COLOR
644 lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color,
645 global_settings.bg_color);
646 #else
647 lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG);
648 #endif
649 #else /* LCD_DEPTH == 1 */
650 lcd_set_drawmode(DRMODE_SOLID);
651 #endif /* LCD_DEPTH */
652 #endif /* HAVE_LCD_BITMAP */
654 /* restore margins */
655 lcd_setmargins(xm,ym);
656 lcd_clear_display();
657 lcd_update();
659 #ifdef HAVE_REMOTE_LCD
660 #if LCD_REMOTE_DEPTH > 1
661 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG,
662 LCD_REMOTE_DEFAULT_BG);
663 #else
664 lcd_remote_set_drawmode(DRMODE_SOLID);
665 #endif
666 lcd_remote_setmargins(rxm, rym);
667 lcd_remote_clear_display();
668 lcd_remote_update();
669 #endif
671 if (pfn_tsr_exit == NULL)
672 plugin_loaded = false;
674 sim_plugin_close(pd);
676 switch (rc) {
677 case PLUGIN_OK:
678 break;
680 case PLUGIN_USB_CONNECTED:
681 return PLUGIN_USB_CONNECTED;
683 default:
684 gui_syncsplash(HZ*2, str(LANG_PLUGIN_ERROR));
685 break;
687 return PLUGIN_OK;
690 /* Returns a pointer to the portion of the plugin buffer that is not already
691 being used. If no plugin is loaded, returns the entire plugin buffer */
692 void* plugin_get_buffer(size_t *buffer_size)
694 int buffer_pos;
696 if (plugin_loaded)
698 if (plugin_size >= PLUGIN_BUFFER_SIZE)
699 return NULL;
701 *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size;
702 buffer_pos = plugin_size;
704 else
706 *buffer_size = PLUGIN_BUFFER_SIZE;
707 buffer_pos = 0;
710 return &pluginbuf[buffer_pos];
713 /* Returns a pointer to the mp3 buffer.
714 Playback gets stopped, to avoid conflicts.
715 Talk buffer is stolen as well.
717 void* plugin_get_audio_buffer(size_t *buffer_size)
719 #if CONFIG_CODEC == SWCODEC
720 return audio_get_buffer(true, buffer_size);
721 #else
722 audio_stop();
723 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
724 *buffer_size = audiobufend - audiobuf;
725 return audiobuf;
726 #endif
729 #ifdef IRAM_STEAL
730 /* Initializes plugin IRAM */
731 void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size,
732 char *iedata, size_t iedata_size)
734 audio_iram_steal();
735 memcpy(iramstart, iramcopy, iram_size);
736 memset(iedata, 0, iedata_size);
737 memset(iramcopy, 0, iram_size);
738 #if NUM_CORES > 1
739 /* writeback cleared iedata and iramcopy areas */
740 flush_icache();
741 #endif
743 #endif /* IRAM_STEAL */
745 /* The plugin wants to stay resident after leaving its main function, e.g.
746 runs from timer or own thread. The callback is registered to later
747 instruct it to free its resources before a new plugin gets loaded. */
748 void plugin_tsr(bool (*exit_callback)(bool))
750 pfn_tsr_exit = exit_callback; /* remember the callback for later */
753 char *plugin_get_current_filename(void)
755 return current_plugin;