A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Björn Stenberg
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#define DIRFUNCTIONS_DEFINED
22#define FILEFUNCTIONS_DEFINED
23#include "plugin.h"
24#include "open_plugin.h"
25#include <ctype.h>
26#include <string.h>
27#include <stdlib.h>
28#include "debug.h"
29#include "i2c.h"
30#include "lang.h"
31#include "led.h"
32#include "keyboard.h"
33#include "backlight.h"
34#include "sound_menu.h"
35#include "mp3data.h"
36#include "powermgmt.h"
37#include "splash.h"
38#include "logf.h"
39#include "option_select.h"
40#include "talk.h"
41#include "version.h"
42#include "storage.h"
43#include "pcmbuf.h"
44#include "errno.h"
45#include "diacritic.h"
46#include "pathfuncs.h"
47#include "load_code.h"
48#include "file.h"
49#include "core_keymap.h"
50#include "language.h"
51
52#if CONFIG_CHARGING
53#include "power.h"
54#endif
55
56#include "scrollbar.h"
57#include "peakmeter.h"
58#include "bmp.h"
59#include "bidi.h"
60
61#ifdef USB_ENABLE_HID
62#include "usbstack/usb_hid.h"
63#endif
64
65#ifdef USB_ENABLE_AUDIO
66#include "usbstack/usb_audio.h"
67#endif
68
69#define WRAPPER(_x_) _x_ ## _wrapper
70
71#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
72static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
73void sim_lcd_ex_init(unsigned long (*getpixel)(int, int));
74void sim_lcd_ex_update_rect(int x, int y, int width, int height);
75#else
76extern unsigned char pluginbuf[];
77#include "bitswap.h"
78#endif
79
80/* for actual plugins only, not for codecs */
81static int plugin_size = 0;
82static int (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
83static char current_plugin[MAX_PATH];
84/* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */
85static void *current_plugin_handle;
86
87char *plugin_get_current_filename(void);
88
89static void* plugin_get_audio_buffer(size_t *buffer_size);
90static void plugin_release_audio_buffer(void);
91static void plugin_tsr(int (*exit_callback)(bool));
92
93extern struct battery_tables_t device_battery_tables; /* powermgmt.c */
94
95#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
96/* File handle leak prophylaxis */
97#include "bitarray.h"
98#include "file_internal.h" /* for MAX_OPEN_FILES */
99
100#define PCOC_WRAPPER(_x_) WRAPPER(_x_)
101
102BITARRAY_TYPE_DECLARE(plugin_check_open_close_bitmap_t, open_files_bitmap,
103 MAX_OPEN_FILES)
104
105static plugin_check_open_close_bitmap_t open_files_bitmap;
106
107static void plugin_check_open_close__enter(void)
108{
109 if (!current_plugin_handle)
110 open_files_bitmap_clear(&open_files_bitmap);
111}
112
113static void plugin_check_open_close__open(int fildes)
114{
115 if (fildes >= 0)
116 open_files_bitmap_set_bit(&open_files_bitmap, fildes);
117}
118
119static void plugin_check_open_close__close(int fildes)
120{
121 if (fildes < 0)
122 return;
123
124 if (!open_files_bitmap_test_bit(&open_files_bitmap, fildes))
125 {
126 logf("double close from plugin");
127 }
128
129 open_files_bitmap_clear_bit(&open_files_bitmap, fildes);
130}
131
132static int WRAPPER(open)(const char *path, int oflag, ...)
133{
134 int fildes = FS_PREFIX(open)(path, oflag __OPEN_MODE_ARG);
135 plugin_check_open_close__open(fildes);
136 return fildes;
137}
138
139static int WRAPPER(creat)(const char *path, mode_t mode)
140{
141 int fildes = FS_PREFIX(creat)(path __CREAT_MODE_ARG);
142 plugin_check_open_close__open(fildes);
143 return fildes;
144 (void)mode;
145}
146
147static int WRAPPER(close)(int fildes)
148{
149 int rc = FS_PREFIX(close)(fildes);
150 if (rc >= 0)
151 plugin_check_open_close__close(fildes);
152
153 return rc;
154}
155
156static void plugin_check_open_close__exit(void)
157{
158 if (current_plugin_handle)
159 return;
160
161 if (open_files_bitmap_is_clear(&open_files_bitmap))
162 return;
163
164 logf("Plugin '%s' leaks file handles", current_plugin);
165
166 static const char *lines[] =
167 { ID2P(LANG_PLUGIN_ERROR), "#leak-file-handles" };
168 static const struct text_message message = { lines, 2 };
169 button_clear_queue(); /* Empty the keyboard buffer */
170 gui_syncyesno_run(&message, NULL, NULL);
171
172 FOR_EACH_BITARRAY_SET_BIT(&open_files_bitmap, fildes)
173 WRAPPER(close)(fildes);
174}
175
176#else /* !HAVE_PLUGIN_CHECK_OPEN_CLOSE */
177
178#define PCOC_WRAPPER(_x_) FS_PREFIX(_x_)
179#define plugin_check_open_close__enter()
180#define plugin_check_open_close__exit()
181
182#endif /* HAVE_PLUGIN_CHECK_OPEN_CLOSE */
183
184static const struct plugin_api rockbox_api = {
185 rbversion,
186 &global_settings,
187 &global_status,
188 language_strings,
189 &core_bitmaps[0],
190 /* lcd */
191 splashf,
192 splash_progress,
193 splash_progress_set_delay,
194#ifdef HAVE_LCD_CONTRAST
195 lcd_set_contrast,
196#endif
197 lcd_update,
198 lcd_clear_display,
199 lcd_getstringsize,
200 lcd_putsxy,
201 lcd_putsxyf,
202 lcd_puts,
203 lcd_putsf,
204 lcd_puts_scroll,
205 lcd_scroll_stop,
206 lcd_set_viewport,
207 lcd_bmp_part,
208 lcd_update_rect,
209 lcd_set_drawmode,
210 lcd_get_drawmode,
211 screen_helper_setfont,
212 lcd_drawpixel,
213 lcd_drawline,
214 lcd_hline,
215 lcd_vline,
216 lcd_drawrect,
217 lcd_fillrect,
218 lcd_mono_bitmap_part,
219 lcd_mono_bitmap,
220#if LCD_DEPTH > 1
221 lcd_set_foreground,
222 lcd_get_foreground,
223 lcd_set_background,
224 lcd_get_background,
225 lcd_bitmap_part,
226 lcd_bitmap,
227 lcd_get_backdrop,
228 lcd_set_backdrop,
229#endif
230#if LCD_DEPTH >= 16
231 lcd_bitmap_transparent_part,
232 lcd_bitmap_transparent,
233#if MEMORYSIZE > 2
234 lcd_blit_yuv,
235#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200) \
236 || defined(IRIVER_H10) || defined(COWON_D2) || defined(PHILIPS_HDD1630) \
237 || defined(SANSA_FUZE) || defined(SANSA_E200V2) || defined(SANSA_FUZEV2) \
238 || defined(TOSHIBA_GIGABEAT_S) || defined(PHILIPS_SA9200)
239 lcd_yuv_set_options,
240#endif
241#endif /* MEMORYSIZE > 2 */
242#elif (LCD_DEPTH < 4) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
243 lcd_blit_mono,
244 lcd_blit_grey_phase,
245#endif /* LCD_DEPTH */
246#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
247 lcd_blit_pal256,
248 lcd_pal256_update_pal,
249#endif
250#ifdef HAVE_LCD_INVERT
251 lcd_set_invert_display,
252#endif /* HAVE_LCD_INVERT */
253#if defined(HAVE_LCD_MODES)
254 lcd_set_mode,
255#endif
256#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
257 button_queue_post,
258#endif
259 bidi_l2v,
260 is_diacritic,
261 font_get_bits,
262 font_load,
263 font_unload,
264 font_get,
265 font_getstringsize,
266 font_get_width,
267 screen_clear_area,
268 gui_scrollbar_draw,
269 get_codepage_name,
270
271#ifdef HAVE_REMOTE_LCD
272 /* remote lcd */
273 lcd_remote_set_contrast,
274 lcd_remote_clear_display,
275 lcd_remote_puts,
276 lcd_remote_puts_scroll,
277 lcd_remote_scroll_stop,
278 lcd_remote_set_drawmode,
279 lcd_remote_get_drawmode,
280 lcd_remote_setfont,
281 lcd_remote_getstringsize,
282 lcd_remote_drawpixel,
283 lcd_remote_drawline,
284 lcd_remote_hline,
285 lcd_remote_vline,
286 lcd_remote_drawrect,
287 lcd_remote_fillrect,
288 lcd_remote_mono_bitmap_part,
289 lcd_remote_mono_bitmap,
290 lcd_remote_putsxy,
291 lcd_remote_update,
292 lcd_remote_update_rect,
293#if (LCD_REMOTE_DEPTH > 1)
294 lcd_remote_set_foreground,
295 lcd_remote_get_foreground,
296 lcd_remote_set_background,
297 lcd_remote_get_background,
298 lcd_remote_bitmap_part,
299 lcd_remote_bitmap,
300#endif
301#endif /* HAVE_REMOTE_LCD */
302#if NB_SCREENS == 2
303 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
304#else
305 {&screens[SCREEN_MAIN]},
306#endif
307
308 viewport_set_defaults,
309 viewportmanager_theme_enable,
310 viewportmanager_theme_undo,
311 viewport_set_fullscreen,
312 viewport_set_buffer,
313
314#ifdef HAVE_BACKLIGHT
315 /* lcd backlight */
316 /* For OLED targets like the Sansa Clip, the backlight_* functions control
317 * the display enable, which has essentially the same effect. */
318 is_backlight_on,
319 backlight_on,
320 backlight_off,
321 backlight_set_timeout,
322#ifdef HAVE_BACKLIGHT_BRIGHTNESS
323 backlight_set_brightness,
324#endif /* HAVE_BACKLIGHT_BRIGHTNESS */
325
326#if CONFIG_CHARGING
327 backlight_set_timeout_plugged,
328#endif
329
330#ifdef HAVE_REMOTE_LCD
331 remote_backlight_on,
332 remote_backlight_off,
333 remote_backlight_set_timeout,
334#if CONFIG_CHARGING
335 remote_backlight_set_timeout_plugged,
336#endif
337#endif /* HAVE_REMOTE_LCD */
338#endif /* HAVE_BACKLIGHT */
339
340 /* list */
341 gui_synclist_init,
342 gui_synclist_set_nb_items,
343 gui_synclist_set_voice_callback,
344 gui_synclist_set_icon_callback,
345 gui_synclist_get_nb_items,
346 gui_synclist_get_sel_pos,
347 gui_synclist_draw,
348 gui_synclist_speak_item,
349 gui_synclist_select_item,
350 gui_synclist_add_item,
351 gui_synclist_del_item,
352 gui_synclist_do_button,
353 gui_synclist_set_title,
354 gui_syncyesno_run,
355 simplelist_info_init,
356 simplelist_show_list,
357 yesno_pop,
358
359 /* action handling */
360 get_custom_action,
361 get_action,
362#ifdef HAVE_TOUCHSCREEN
363 action_get_touchscreen_press,
364 action_get_touchscreen_press_in_vp,
365#endif
366 action_userabort,
367 core_set_keyremap,
368
369 /* button */
370 button_get,
371 button_get_w_tmo,
372 button_status,
373#ifdef HAVE_BUTTON_DATA
374 button_get_data,
375 button_status_wdata,
376#endif
377 button_clear_queue,
378 button_queue_count,
379#ifdef HAS_BUTTON_HOLD
380 button_hold,
381#endif
382#ifdef HAVE_SW_POWEROFF
383 button_set_sw_poweroff_state,
384 button_get_sw_poweroff_state,
385#endif
386#ifdef HAVE_TOUCHSCREEN
387 touchscreen_set_mode,
388 touchscreen_get_mode,
389#endif
390
391#ifdef HAVE_BUTTON_LIGHT
392 buttonlight_set_timeout,
393 buttonlight_off,
394 buttonlight_on,
395#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
396 buttonlight_set_brightness,
397#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
398#endif /* HAVE_BUTTON_LIGHT */
399
400 /* file */
401 open_utf8,
402 PCOC_WRAPPER(open),
403 PCOC_WRAPPER(creat),
404 PCOC_WRAPPER(close),
405 FS_PREFIX(read),
406 FS_PREFIX(lseek),
407 FS_PREFIX(write),
408 FS_PREFIX(remove),
409 FS_PREFIX(rename),
410 FS_PREFIX(ftruncate),
411 FS_PREFIX(filesize),
412 fdprintf,
413 read_line,
414 settings_parseline,
415 storage_sleep,
416 STORAGE_FUNCTION(spin),
417 STORAGE_FUNCTION(spindown),
418#ifdef USING_STORAGE_CALLBACK
419 register_storage_idle_func,
420 unregister_storage_idle_func,
421#endif /* USING_STORAGE_CALLBACK */
422 reload_directory,
423 create_numbered_filename,
424 FS_PREFIX(file_exists),
425 strip_extension,
426 crc_32,
427 crc_32r,
428 filetype_get_attr,
429 filetype_get_plugin,
430
431 /* dir */
432 FS_PREFIX(opendir),
433 FS_PREFIX(closedir),
434 FS_PREFIX(readdir),
435 FS_PREFIX(mkdir),
436 FS_PREFIX(rmdir),
437 FS_PREFIX(dir_exists),
438 dir_get_info,
439
440 /* browsing */
441 rockbox_browse,
442 tree_get_context,
443 tree_get_entries,
444 tree_get_entry_at,
445 set_current_file,
446 set_dirfilter,
447 onplay_show_playlist_menu,
448 onplay_show_playlist_cat_menu,
449 browse_id3,
450
451 /* talking */
452 talk_id,
453 talk_idarray,
454 talk_file,
455 talk_file_or_spell,
456 talk_fullpath,
457 talk_dir_or_spell,
458 talk_number,
459 talk_value_decimal,
460 talk_spell,
461 talk_time,
462 talk_date,
463 talk_disable,
464 talk_shutup,
465 talk_force_shutup,
466 talk_force_enqueue_next,
467
468 /* kernel/ system */
469#if defined(ARM_NEED_DIV0)
470 __div0,
471#endif
472 sleep,
473 yield,
474 ¤t_tick,
475 default_event_handler,
476 default_event_handler_ex,
477 create_thread,
478 thread_self,
479 thread_exit,
480 thread_wait,
481 thread_thaw,
482#ifdef HAVE_PRIORITY_SCHEDULING
483 thread_set_priority,
484#endif
485 mutex_init,
486 mutex_lock,
487 mutex_unlock,
488#ifdef HAVE_SEMAPHORE_OBJECTS
489 semaphore_init,
490 semaphore_wait,
491 semaphore_release,
492#endif
493 reset_poweroff_timer,
494 set_sleeptimer_duration, /*stub*/
495 get_sleep_timer, /*stub*/
496#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
497 system_memory_guard,
498 &cpu_frequency,
499
500#ifdef HAVE_ADJUSTABLE_CPU_FREQ
501#ifdef CPU_BOOST_LOGGING
502 cpu_boost_,
503#else
504 cpu_boost,
505#endif
506#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
507#endif /* PLATFORM_NATIVE */
508#ifdef HAVE_SCHEDULER_BOOSTCTRL
509 trigger_cpu_boost,
510 cancel_cpu_boost,
511#endif
512
513 commit_dcache,
514 commit_discard_dcache,
515 commit_discard_idcache,
516
517 lc_open,
518 lc_open_from_mem,
519 lc_get_header,
520 lc_close,
521
522 timer_register,
523 timer_unregister,
524 timer_set_period,
525
526 queue_init,
527 queue_delete,
528 queue_post,
529 queue_wait_w_tmo,
530 queue_enable_queue_send,
531 queue_empty,
532 queue_wait,
533 queue_send,
534 queue_reply,
535 queue_remove_from_head,
536
537#ifdef RB_PROFILE
538 profile_thread,
539 profstop,
540 __cyg_profile_func_enter,
541 __cyg_profile_func_exit,
542#endif
543 add_event,
544 remove_event,
545 send_event,
546
547#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
548 /* special simulator hooks */
549#if LCD_DEPTH < 8
550 sim_lcd_ex_init,
551 sim_lcd_ex_update_rect,
552#endif
553#endif
554
555 /* strings and memory */
556 snprintf,
557 vsnprintf,
558 vuprintf,
559 strcpy,
560 strlcpy,
561 strlen,
562 strrchr,
563 strcmp,
564 strncmp,
565 strcasecmp,
566 strncasecmp,
567 memset,
568 memcpy,
569 memmove,
570#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
571 _ctype_,
572#endif
573 atoi,
574 strchr,
575 strcat,
576 strlcat,
577 memchr,
578 memcmp,
579 strcasestr,
580 strtok_r,
581 output_dyn_value,
582 /* unicode stuff */
583 utf8decode,
584 iso_decode,
585 utf16LEdecode,
586 utf16BEdecode,
587 utf8encode,
588 utf8length,
589 utf8seek,
590
591 /* language */
592 lang_is_rtl,
593
594 /* the buflib memory management library */
595 buflib_init,
596 buflib_available,
597 buflib_alloc,
598 buflib_alloc_ex,
599 buflib_alloc_maximum,
600 buflib_buffer_in,
601 buflib_buffer_out,
602 buflib_free,
603 buflib_shrink,
604 buflib_get_data,
605
606 /* sound */
607 adjust_volume,
608 sound_set,
609 sound_current, /*stub*/
610 sound_default,
611 sound_min,
612 sound_max,
613 sound_unit,
614 sound_val2phys,
615#ifdef AUDIOHW_HAVE_EQ
616 sound_enum_hw_eq_band_setting,
617#endif
618#if defined (HAVE_PITCHCONTROL)
619 sound_get_pitch,
620 sound_set_pitch,
621#endif
622 &audio_master_sampr_list[0],
623 &hw_freq_sampr[0],
624 pcm_apply_settings,
625 pcm_play_data,
626 pcm_play_stop,
627 pcm_set_frequency,
628 pcm_is_playing,
629 pcm_play_lock,
630 pcm_play_unlock,
631 beep_play,
632#ifdef HAVE_RECORDING
633 &rec_freq_sampr[0],
634 pcm_init_recording,
635 pcm_close_recording,
636 pcm_record_data,
637 pcm_stop_recording,
638 pcm_calculate_rec_peaks,
639 audio_set_recording_gain,
640#endif /* HAVE_RECORDING */
641#if INPUT_SRC_CAPS != 0
642 audio_set_output_source,
643 audio_set_input_source,
644#endif
645 dsp_set_crossfeed_type ,
646 dsp_eq_enable,
647 dsp_dither_enable,
648#ifdef HAVE_PITCHCONTROL
649 dsp_get_timestretch,
650 dsp_set_timestretch,
651 dsp_timestretch_enable,
652 dsp_timestretch_available,
653#endif
654 dsp_configure,
655 dsp_get_config,
656 dsp_process,
657
658 mixer_channel_status,
659 mixer_channel_get_buffer,
660 mixer_channel_calculate_peaks,
661 mixer_channel_play_data,
662 mixer_channel_play_pause,
663 mixer_channel_stop,
664 mixer_channel_set_amplitude,
665 mixer_channel_get_bytes_waiting,
666 mixer_channel_set_buffer_hook,
667 mixer_set_frequency,
668 mixer_get_frequency,
669
670 pcmbuf_fade,
671 pcmbuf_set_low_latency,
672 system_sound_play,
673 keyclick_click,
674
675 /* metadata */
676 get_metadata,
677 get_codec_string,
678 count_mp3_frames,
679 create_xing_header,
680#ifdef HAVE_TAGCACHE
681 tagcache_search,
682 tagcache_search_set_uniqbuf,
683 tagcache_search_add_filter,
684 tagcache_get_next,
685 tagcache_retrieve,
686 tagcache_search_finish,
687 tagcache_get_numeric,
688 tagcache_get_stat,
689 tagcache_commit_finalize,
690#if defined(HAVE_TC_RAMCACHE)
691 tagcache_is_in_ram,
692#if defined(HAVE_DIRCACHE)
693 tagcache_fill_tags,
694#endif
695#endif
696 tagtree_subentries_do_action,
697#endif /* HAVE_TAGCACHE */
698
699#ifdef HAVE_ALBUMART
700 search_albumart_files,
701#endif
702
703 /* playback control */
704 playlist_get_current,
705 playlist_get_resume_info,
706 playlist_get_track_info,
707 playlist_get_first_index,
708 playlist_get_display_index,
709 playlist_entries_iterate,
710 playlist_amount,
711 playlist_resume,
712 playlist_resume_track,
713 playlist_set_modified,
714 playlist_start,
715 playlist_sync,
716 playlist_remove_all_tracks,
717 playlist_create,
718 playlist_insert_track,
719 playlist_insert_directory,
720 playlist_insert_playlist,
721 playlist_shuffle,
722 warn_on_pl_erase,
723 audio_play,
724 audio_stop,
725 audio_pause,
726 audio_resume,
727 audio_next,
728 audio_prev,
729 audio_ff_rewind,
730 audio_next_track,
731 audio_status,
732 audio_current_track,
733 audio_flush_and_reload_tracks,
734 audio_get_file_pos,
735#ifdef PLUGIN_USE_IRAM
736 audio_hard_stop,
737#endif
738
739 /* menu */
740 root_menu_get_options,
741 do_menu,
742 root_menu_set_default,
743 root_menu_write_to_cfg,
744 root_menu_load_from_cfg,
745
746 /* options */
747 get_settings_list,
748 find_setting,
749 settings_save,
750 option_screen,
751 set_option,
752 set_bool_options,
753 set_int,
754 set_int_ex,
755 set_bool,
756#ifdef HAVE_LCD_COLOR
757 set_color,
758#endif
759
760 /* power */
761 battery_level,
762 battery_level_safe,
763 battery_time,
764 battery_voltage,
765 battery_current,
766#if CONFIG_CHARGING
767 charger_inserted,
768# if CONFIG_CHARGING >= CHARGING_MONITOR
769 charging_state,
770# endif
771#endif
772 /* usb */
773 usb_inserted,
774 usb_acknowledge,
775#ifdef USB_ENABLE_HID
776 usb_hid_send,
777#endif
778 /* misc */
779#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
780 __errno,
781#endif
782 led,
783 srand,
784 rand,
785 (void *)qsort,
786 kbd_input,
787 get_time,
788 gmtime_r,
789#if CONFIG_RTC
790 mktime,
791#endif
792 format_time_auto,
793#if defined(DEBUG) || defined(SIMULATOR)
794 debugf,
795#endif
796#ifdef ROCKBOX_HAS_LOGF
797 _logf,
798#endif
799 codec_thread_do_callback,
800 codec_load_file,
801 codec_run_proc,
802 codec_close,
803 get_codec_filename,
804 find_array_ptr,
805 remove_array_ptr,
806 round_value_to_list32,
807
808 read_bmp_file,
809 read_bmp_fd,
810#ifdef HAVE_JPEG
811 read_jpeg_file,
812 read_jpeg_fd,
813#endif
814 screen_dump_set_hook,
815
816#ifdef HAVE_WHEEL_POSITION
817 wheel_status,
818 wheel_send_events,
819#endif
820
821#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
822 /* Routines for the iriver_flash -plugin. */
823 detect_original_firmware,
824 detect_flashed_ramimage,
825 detect_flashed_romimage,
826#endif
827
828 /*plugin*/
829 plugin_open,
830 plugin_get_buffer,
831 plugin_get_audio_buffer, /* defined in plugin.c */
832 plugin_release_audio_buffer, /* defined in plugin.c */
833 plugin_tsr, /* defined in plugin.c */
834 plugin_get_current_filename,
835 plugin_reserve_buffer,
836
837 /* reboot and poweroff */
838 sys_poweroff,
839 sys_reboot,
840
841 /* pathfuncs */
842 fix_path_part,
843#ifdef HAVE_MULTIVOLUME
844 path_strip_volume,
845#endif
846
847 /* new stuff at the end, sort into place next time
848 the API gets incompatible */
849 add_playbacklog,
850 &device_battery_tables,
851 yesno_pop_confirm,
852#ifdef USB_ENABLE_AUDIO
853 usb_audio_get_playing,
854#endif
855};
856
857static int plugin_buffer_handle;
858static size_t plugin_buffer_size;
859
860int plugin_load(const char* plugin, const void* parameter)
861{
862 struct plugin_header *p_hdr;
863 struct lc_header *hdr;
864 const char * resume_plugin = NULL;
865
866 if (!plugin)
867 return PLUGIN_ERROR;
868
869 /* for some plugins, the SBS can be left enabled */
870 const char *sepch = strrchr(plugin, PATH_SEPCH);
871 bool theme_enabled = sepch && (!strcmp("properties.rock", sepch + 1) ||
872 !strcmp("main_menu_config.rock", sepch + 1) ||
873 !strcmp("disktidy.rock", sepch + 1));
874
875 if (current_plugin_handle)
876 {
877 if (!pfn_tsr_exit)
878 {
879 /* not allowing another plugin to load */
880 logf("Attempt to load plugin `%s` while another non-TSR plugin `%s` is running.", plugin, current_plugin);
881 return PLUGIN_OK;
882 }
883
884 /* if we have a resident old plugin and a callback */
885 bool reenter = (strcmp(current_plugin, plugin) == 0);
886 int exit_status = pfn_tsr_exit(reenter);
887 if (exit_status == PLUGIN_TSR_CONTINUE)
888 {
889 /* not allowing another plugin to load */
890 return PLUGIN_OK;
891 }
892 else
893 {
894 lc_close(current_plugin_handle);
895 current_plugin_handle = pfn_tsr_exit = NULL;
896 plugin_buffer_handle = core_free(plugin_buffer_handle);
897
898 if (!reenter)
899 resume_plugin = strdupa(current_plugin);
900 else if (exit_status == PLUGIN_TSR_TERMINATE)
901 return PLUGIN_OK; /* don't even load the new plugin either */
902 }
903 }
904
905#ifdef HAVE_DISK_STORAGE
906 if (!storage_disk_is_active())
907 splash(0, ID2P(LANG_WAIT));
908#endif
909 strcpy(current_plugin, plugin);
910 current_plugin_handle = lc_open(plugin, pluginbuf, PLUGIN_BUFFER_SIZE);
911 if (current_plugin_handle == NULL) {
912 if (global_settings.talk_menu)
913 {
914 talk_id(LANG_PLUGIN_CANT_OPEN, false);
915 talk_spell(plugin, true);
916 talk_force_enqueue_next();
917 }
918 /* (voiced above) */
919 splashf(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
920 return -1;
921 }
922
923 p_hdr = lc_get_header(current_plugin_handle);
924 hdr = p_hdr ? &p_hdr->lc_hdr : NULL;
925
926 if (hdr == NULL
927 || hdr->magic != PLUGIN_MAGIC
928 || hdr->target_id != TARGET_ID
929#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
930 || hdr->load_addr != pluginbuf
931 || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE
932#endif
933 )
934 {
935 hdr = NULL;
936 }
937
938 if (hdr == NULL || hdr->api_version != PLUGIN_API_VERSION ||
939 p_hdr->api_size > sizeof(struct plugin_api))
940 {
941 lc_close(current_plugin_handle);
942 current_plugin_handle = NULL;
943 splash(HZ*2, hdr ? ID2P(LANG_PLUGIN_WRONG_VERSION)
944 : ID2P(LANG_PLUGIN_WRONG_MODEL));
945 return -1;
946 }
947
948#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
949 /* tlsf crashes observed on arm with 0x4 aligned addresses */
950 plugin_size = ALIGN_UP(hdr->end_addr - pluginbuf, 0x8);
951#else
952 plugin_size = 0;
953#endif
954
955 *(p_hdr->api) = &rockbox_api;
956 lcd_set_viewport(NULL);
957 if (!theme_enabled)
958 lcd_clear_display();
959
960#ifdef HAVE_REMOTE_LCD
961 lcd_remote_set_viewport(NULL);
962 lcd_remote_clear_display();
963 lcd_remote_update();
964#endif
965 if (get_current_activity() == ACTIVITY_WPS)
966 push_activity_without_refresh(ACTIVITY_PLUGIN);
967 else
968 push_current_activity(ACTIVITY_PLUGIN);
969 /* some plugins assume the entry cache doesn't move and save pointers to it
970 * they should be fixed properly instead of this lock */
971 struct tree_context *tc = tree_get_context();
972 tree_lock_cache(tc);
973 int *last_dirfilter_p = tc->dirfilter; /* store incoming dirfilter pointer */
974
975 if (!theme_enabled)
976 FOR_NB_SCREENS(i)
977 viewportmanager_theme_enable(i, false, NULL);
978
979#ifdef HAVE_TOUCHSCREEN
980 touchscreen_set_mode(TOUCHSCREEN_BUTTON);
981#endif
982
983 /* allow voice to back off if the plugin needs lots of memory */
984 if (!global_settings.talk_menu)
985 talk_buffer_set_policy(TALK_BUFFER_LOOSE);
986
987 plugin_check_open_close__enter();
988
989 int rc = p_hdr->entry_point(parameter); /* run the loaded plugin */
990
991 /* unlock the tree and restore the dirfilter pointer */
992 tree_unlock_cache(tc);
993 tc->dirfilter = last_dirfilter_p;
994
995 pop_current_activity_without_refresh();
996 if (get_current_activity() != ACTIVITY_WPS)
997 {
998 FOR_NB_SCREENS(i)
999 skin_update(CUSTOM_STATUSBAR, i, SKIN_REFRESH_ALL);
1000 }
1001
1002 if (!pfn_tsr_exit)
1003 { /* close handle if plugin is no tsr one */
1004 lc_close(current_plugin_handle);
1005 current_plugin_handle = NULL;
1006 plugin_buffer_handle = core_free(plugin_buffer_handle);
1007 }
1008
1009 talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
1010
1011 /* Go back to the global setting in case the plugin changed it */
1012#ifdef HAVE_TOUCHSCREEN
1013 touchscreen_set_mode(global_settings.touch_mode);
1014#endif
1015 /* restore default vp */
1016 lcd_set_viewport(NULL);
1017 screen_helper_setfont(FONT_UI);
1018#if LCD_DEPTH > 1
1019#ifdef HAVE_LCD_COLOR
1020 lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color,
1021 global_settings.bg_color);
1022#else
1023 lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG);
1024#endif
1025#else /* LCD_DEPTH == 1 */
1026 lcd_set_drawmode(DRMODE_SOLID);
1027#endif /* LCD_DEPTH */
1028
1029#ifdef HAVE_REMOTE_LCD
1030 lcd_remote_set_viewport(NULL);
1031
1032#if LCD_REMOTE_DEPTH > 1
1033 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG,
1034 LCD_REMOTE_DEFAULT_BG);
1035#else
1036 lcd_remote_set_drawmode(DRMODE_SOLID);
1037#endif
1038#endif
1039
1040#ifdef HAVE_REMOTE_LCD
1041 lcd_remote_clear_display();
1042#endif
1043
1044 if (!theme_enabled)
1045 {
1046 lcd_clear_display();
1047 FOR_NB_SCREENS(i)
1048 viewportmanager_theme_undo(i, true);
1049 }
1050
1051 plugin_check_open_close__exit();
1052
1053 status_save(false);
1054
1055 if (rc == PLUGIN_ERROR)
1056 splash(HZ*2, str(LANG_PLUGIN_ERROR));
1057
1058 if (resume_plugin && rc != PLUGIN_GOTO_PLUGIN && !pfn_tsr_exit)
1059 {
1060 /*plugin = resume_plugin;*/
1061 /*parameter = rockbox_api.plugin_tsr;*/
1062 return plugin_load(resume_plugin, rockbox_api.plugin_tsr);
1063 }
1064 return rc;
1065}
1066
1067/* For Terminate Stay Resident plugins
1068 * Locks buffer_size bytes of the plugin buffer
1069 * freed on plugin exit; call plugin_get_buffer first then reserve all
1070 * or a portion with plugin_reserve_buffer()
1071 * Returns size of buffer remaining */
1072size_t plugin_reserve_buffer(size_t buffer_size)
1073{
1074 size_t locked_size = 0;
1075
1076 if (current_plugin_handle)
1077 {
1078 locked_size = ALIGN_UP(plugin_size + buffer_size, 0x8);
1079 if (locked_size > PLUGIN_BUFFER_SIZE)
1080 locked_size = PLUGIN_BUFFER_SIZE;
1081
1082 plugin_size = locked_size;
1083 }
1084
1085 return (PLUGIN_BUFFER_SIZE - locked_size);
1086}
1087
1088/* Returns a pointer to the portion of the plugin buffer that is not already
1089 being used. If no plugin is loaded, returns the entire plugin buffer */
1090void* plugin_get_buffer(size_t *buffer_size)
1091{
1092 int buffer_pos;
1093
1094 if (current_plugin_handle)
1095 {
1096 if (plugin_size >= PLUGIN_BUFFER_SIZE)
1097 return NULL;
1098
1099 *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size;
1100 buffer_pos = plugin_size;
1101 }
1102 else
1103 {
1104 *buffer_size = PLUGIN_BUFFER_SIZE;
1105 buffer_pos = 0;
1106 }
1107
1108 return &pluginbuf[buffer_pos];
1109}
1110
1111/* Returns a pointer to the mp3 buffer.
1112 Playback gets stopped, to avoid conflicts.
1113 Talk buffer is stolen as well.
1114 */
1115static void* plugin_get_audio_buffer(size_t *buffer_size)
1116{
1117 if (plugin_buffer_handle <= 0)
1118 {
1119 plugin_buffer_handle = core_alloc_maximum(&plugin_buffer_size,
1120 &buflib_ops_locked);
1121 }
1122
1123 if (buffer_size)
1124 *buffer_size = plugin_buffer_size;
1125
1126 return core_get_data(plugin_buffer_handle);
1127}
1128
1129static void plugin_release_audio_buffer(void)
1130{
1131 if (plugin_buffer_handle > 0)
1132 {
1133 plugin_buffer_handle = core_free(plugin_buffer_handle);
1134 plugin_buffer_size = 0;
1135 }
1136}
1137
1138/* The plugin wants to stay resident after leaving its main function, e.g.
1139 runs from timer or own thread. The callback is registered to later
1140 instruct it to free its resources before a new plugin gets loaded. */
1141static void plugin_tsr(int (*exit_callback)(bool))
1142{
1143 pfn_tsr_exit = exit_callback; /* remember the callback for later */
1144}
1145
1146int plugin_open(const char *plugin, const char *parameter)
1147{
1148 open_plugin_add_path(ID2P(LANG_OPEN_PLUGIN), plugin, parameter);
1149 return PLUGIN_GOTO_PLUGIN;
1150}
1151
1152char *plugin_get_current_filename(void)
1153{
1154 return current_plugin;
1155}