Player: Save a bit of space by only using 7 bytes/char in the glyph table.
[Rockbox.git] / apps / plugin.c
blobde04269a89397fe52a7dbf8e0cd2662540246880
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 "keyboard.h"
28 #include "buffer.h"
29 #include "backlight.h"
30 #include "sound_menu.h"
31 #include "mp3data.h"
32 #include "powermgmt.h"
33 #include "splash.h"
34 #include "logf.h"
36 #if CONFIG_CHARGING
37 #include "power.h"
38 #endif
40 #ifdef HAVE_LCD_BITMAP
41 #include "scrollbar.h"
42 #include "peakmeter.h"
43 #include "bmp.h"
44 #include "bidi.h"
45 #endif
47 #ifdef SIMULATOR
48 static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
49 void *sim_plugin_load(char *plugin, void **pd);
50 void sim_plugin_close(void *pd);
51 void sim_lcd_ex_init(int shades, unsigned long (*getpixel)(int, int));
52 void sim_lcd_ex_update_rect(int x, int y, int width, int height);
53 #else
54 #define sim_plugin_close(x)
55 extern unsigned char pluginbuf[];
56 #include "bitswap.h"
57 #endif
59 /* for actual plugins only, not for codecs */
60 static bool plugin_loaded = false;
61 static int plugin_size = 0;
62 static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
63 static char current_plugin[MAX_PATH];
65 static const struct plugin_api rockbox_api = {
67 /* lcd */
68 lcd_set_contrast,
69 lcd_clear_display,
70 lcd_setmargins,
71 lcd_getstringsize,
72 lcd_putsxy,
73 lcd_puts,
74 lcd_puts_scroll,
75 lcd_stop_scroll,
76 #ifdef HAVE_LCD_CHARCELLS
77 lcd_define_pattern,
78 lcd_get_locked_pattern,
79 lcd_unlock_pattern,
80 lcd_putc,
81 lcd_put_cursor,
82 lcd_remove_cursor,
83 PREFIX(lcd_icon),
84 lcd_double_height,
85 #else
86 lcd_set_drawmode,
87 lcd_get_drawmode,
88 lcd_setfont,
89 lcd_drawpixel,
90 lcd_drawline,
91 lcd_hline,
92 lcd_vline,
93 lcd_drawrect,
94 lcd_fillrect,
95 lcd_mono_bitmap_part,
96 lcd_mono_bitmap,
97 #if LCD_DEPTH > 1
98 lcd_set_foreground,
99 lcd_get_foreground,
100 lcd_set_background,
101 lcd_get_background,
102 lcd_bitmap_part,
103 lcd_bitmap,
104 lcd_set_backdrop,
105 #endif
106 #if LCD_DEPTH == 16
107 lcd_bitmap_transparent_part,
108 lcd_bitmap_transparent,
109 #endif
110 bidi_l2v,
111 font_get_bits,
112 font_load,
113 lcd_puts_style,
114 lcd_puts_scroll_style,
115 &lcd_framebuffer[0][0],
116 lcd_blit,
117 lcd_update,
118 lcd_update_rect,
119 gui_scrollbar_draw,
120 font_get,
121 font_getstringsize,
122 font_get_width,
123 #endif
124 backlight_on,
125 backlight_off,
126 backlight_set_timeout,
127 gui_syncsplash,
128 #ifdef HAVE_REMOTE_LCD
129 /* remote lcd */
130 lcd_remote_set_contrast,
131 lcd_remote_clear_display,
132 lcd_remote_puts,
133 lcd_remote_puts_scroll,
134 lcd_remote_stop_scroll,
135 lcd_remote_set_drawmode,
136 lcd_remote_get_drawmode,
137 lcd_remote_setfont,
138 lcd_remote_getstringsize,
139 lcd_remote_drawpixel,
140 lcd_remote_drawline,
141 lcd_remote_hline,
142 lcd_remote_vline,
143 lcd_remote_drawrect,
144 lcd_remote_fillrect,
145 lcd_remote_mono_bitmap_part,
146 lcd_remote_mono_bitmap,
147 lcd_remote_putsxy,
148 lcd_remote_puts_style,
149 lcd_remote_puts_scroll_style,
150 &lcd_remote_framebuffer[0][0],
151 lcd_remote_update,
152 lcd_remote_update_rect,
154 remote_backlight_on,
155 remote_backlight_off,
156 #endif
157 #if NB_SCREENS == 2
158 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
159 #else
160 {&screens[SCREEN_MAIN]},
161 #endif
162 #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
163 lcd_remote_set_foreground,
164 lcd_remote_get_foreground,
165 lcd_remote_set_background,
166 lcd_remote_get_background,
167 lcd_remote_bitmap_part,
168 lcd_remote_bitmap,
169 #endif
171 #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
172 lcd_yuv_blit,
173 #endif
174 /* list */
175 gui_synclist_init,
176 gui_synclist_set_nb_items,
177 gui_synclist_set_icon_callback,
178 gui_synclist_get_nb_items,
179 gui_synclist_get_sel_pos,
180 gui_synclist_draw,
181 gui_synclist_select_item,
182 gui_synclist_add_item,
183 gui_synclist_del_item,
184 gui_synclist_limit_scroll,
185 gui_synclist_flash,
186 gui_synclist_do_button,
187 gui_synclist_set_title,
189 /* button */
190 button_get,
191 button_get_w_tmo,
192 button_status,
193 button_clear_queue,
194 #ifdef HAS_BUTTON_HOLD
195 button_hold,
196 #endif
198 /* file */
199 (open_func)PREFIX(open),
200 close,
201 (read_func)read,
202 PREFIX(lseek),
203 (creat_func)PREFIX(creat),
204 (write_func)write,
205 PREFIX(remove),
206 PREFIX(rename),
207 PREFIX(ftruncate),
208 PREFIX(filesize),
209 fdprintf,
210 read_line,
211 settings_parseline,
212 #ifndef SIMULATOR
213 ata_sleep,
214 ata_disk_is_active,
215 #endif
216 ata_spindown,
217 reload_directory,
219 /* dir */
220 PREFIX(opendir),
221 PREFIX(closedir),
222 PREFIX(readdir),
223 PREFIX(mkdir),
224 PREFIX(rmdir),
226 /* dir, cached */
227 #ifdef HAVE_DIRCACHE
228 opendir_cached,
229 readdir_cached,
230 closedir_cached,
231 #endif
233 /* kernel/ system */
234 PREFIX(sleep),
235 yield,
236 &current_tick,
237 default_event_handler,
238 default_event_handler_ex,
239 create_thread,
240 remove_thread,
241 reset_poweroff_timer,
242 #ifndef SIMULATOR
243 system_memory_guard,
244 &cpu_frequency,
246 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
247 #ifdef CPU_BOOST_LOGGING
248 cpu_boost_,
249 #else
250 cpu_boost,
251 #endif
252 #endif
253 timer_register,
254 timer_unregister,
255 timer_set_period,
256 #endif
257 queue_init,
258 queue_delete,
259 queue_post,
260 queue_wait_w_tmo,
261 usb_acknowledge,
262 #ifdef RB_PROFILE
263 profile_thread,
264 profstop,
265 profile_func_enter,
266 profile_func_exit,
267 #endif
269 #ifdef SIMULATOR
270 /* special simulator hooks */
271 #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH < 8
272 sim_lcd_ex_init,
273 sim_lcd_ex_update_rect,
274 #endif
275 #endif
277 /* strings and memory */
278 snprintf,
279 vsnprintf,
280 strcpy,
281 strncpy,
282 strlen,
283 strrchr,
284 strcmp,
285 strncmp,
286 strcasecmp,
287 strncasecmp,
288 memset,
289 memcpy,
290 memmove,
291 _ctype_,
292 atoi,
293 strchr,
294 strcat,
295 memchr,
296 memcmp,
297 strcasestr,
298 strtok_r,
299 /* unicode stuff */
300 utf8decode,
301 iso_decode,
302 utf16LEdecode,
303 utf16BEdecode,
304 utf8encode,
305 utf8length,
306 utf8seek,
308 /* sound */
309 sound_set,
310 set_sound,
312 sound_min,
313 sound_max,
314 #ifndef SIMULATOR
315 mp3_play_data,
316 mp3_play_pause,
317 mp3_play_stop,
318 mp3_is_playing,
319 #if CONFIG_CODEC != SWCODEC
320 bitswap,
321 #endif
322 #endif
323 #if CONFIG_CODEC == SWCODEC
324 pcm_play_data,
325 pcm_play_stop,
326 pcm_set_frequency,
327 pcm_is_playing,
328 pcm_play_pause,
329 #endif
330 #if CONFIG_CODEC == SWCODEC
331 pcm_calculate_peaks,
332 #endif
334 /* playback control */
335 PREFIX(audio_play),
336 audio_stop,
337 audio_pause,
338 audio_resume,
339 audio_next,
340 audio_prev,
341 audio_ff_rewind,
342 audio_next_track,
343 playlist_amount,
344 audio_status,
345 audio_has_changed_track,
346 audio_current_track,
347 audio_flush_and_reload_tracks,
348 audio_get_file_pos,
349 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
350 mpeg_get_last_header,
351 #endif
352 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) || \
353 (CONFIG_CODEC == SWCODEC)
354 sound_set_pitch,
355 #endif
357 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
358 /* MAS communication */
359 mas_readmem,
360 mas_writemem,
361 mas_readreg,
362 mas_writereg,
363 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
364 mas_codec_writereg,
365 mas_codec_readreg,
366 i2c_begin,
367 i2c_end,
368 i2c_write,
369 #endif
370 #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
372 /* menu */
373 do_menu,
374 /* OLD API - dont use unless you have to */
375 menu_init,
376 menu_exit,
377 menu_show,
378 menu_run,
379 menu_count,
380 set_option,
381 set_int,
382 set_bool,
384 /* action handling */
385 get_custom_action,
386 get_action,
387 action_signalscreenchange,
388 action_userabort,
390 /* power */
391 battery_level,
392 battery_level_safe,
393 battery_time,
394 #ifndef SIMULATOR
395 battery_voltage,
396 #endif
397 #if CONFIG_CHARGING
398 charger_inserted,
399 # if CONFIG_CHARGING == CHARGING_MONITOR
400 charging_state,
401 # endif
402 #endif
403 #ifdef HAVE_USB_POWER
404 usb_powered,
405 #endif
407 /* misc */
408 srand,
409 rand,
410 (qsort_func)qsort,
411 kbd_input,
412 get_time,
413 set_time,
414 plugin_get_buffer,
415 plugin_get_audio_buffer,
416 plugin_tsr,
417 #if defined(DEBUG) || defined(SIMULATOR)
418 debugf,
419 #endif
420 #ifdef ROCKBOX_HAS_LOGF
421 _logf,
422 #endif
423 &global_settings,
424 mp3info,
425 count_mp3_frames,
426 create_xing_header,
427 find_next_frame,
428 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
429 peak_meter_scale_value,
430 peak_meter_set_use_dbfs,
431 peak_meter_get_use_dbfs,
432 #endif
433 #ifdef HAVE_LCD_BITMAP
434 read_bmp_file,
435 screen_dump_set_hook,
436 #endif
437 show_logo,
438 tree_get_context,
440 #ifdef HAVE_WHEEL_POSITION
441 wheel_status,
442 wheel_send_events,
443 #endif
444 #if LCD_DEPTH > 1
445 lcd_get_backdrop,
446 #endif
447 /* new stuff at the end, sort into place next time
448 the API gets incompatible */
450 /* Keep these at the bottom till fully proven */
451 #if CONFIG_CODEC == SWCODEC
452 &audio_master_sampr_list[0],
453 &hw_freq_sampr[0],
454 #ifndef SIMULATOR
455 pcm_apply_settings,
456 #endif
457 #ifdef HAVE_RECORDING
458 &rec_freq_sampr[0],
459 #ifndef SIMULATOR
460 pcm_init_recording,
461 pcm_close_recording,
462 pcm_record_data,
463 pcm_stop_recording,
464 pcm_calculate_rec_peaks,
465 audio_set_recording_gain,
466 audio_set_output_source,
467 rec_set_source,
468 #endif
469 #endif /* HAVE_RECORDING */
470 #endif /* CONFIG_CODEC == SWCODEC */
472 #ifdef IRAM_STEAL
473 plugin_iram_init,
474 #endif
476 #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(SIMULATOR)
477 sound_default,
478 pcm_record_more,
479 #endif
481 #ifdef IRIVER_H100_SERIES
482 /* Routines for the iriver_flash -plugin. */
483 detect_original_firmware,
484 detect_flashed_ramimage,
485 detect_flashed_romimage,
486 #endif
487 playlist_resume,
488 playlist_start,
489 &global_status,
491 #if CONFIG_CODEC == SWCODEC
492 pcm_get_bytes_waiting,
493 #endif
496 int plugin_load(const char* plugin, void* parameter)
498 int rc;
499 struct plugin_header *hdr;
500 const char *p = strrchr(plugin,'/');
501 #ifdef SIMULATOR
502 void *pd;
503 #else
504 int fd;
505 ssize_t readsize;
506 #endif
507 #ifdef HAVE_LCD_BITMAP
508 int xm, ym;
509 #endif
510 #ifdef HAVE_REMOTE_LCD
511 int rxm, rym;
512 #endif
514 #if LCD_DEPTH > 1
515 fb_data* old_backdrop;
516 #endif
518 if (!p)
519 p = plugin;
520 action_signalscreenchange();
522 if (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */
524 if (pfn_tsr_exit(!strcmp(current_plugin,p)) == false )
526 /* not allowing another plugin to load */
527 return PLUGIN_OK;
529 pfn_tsr_exit = NULL;
530 plugin_loaded = false;
533 gui_syncsplash(0, str(LANG_WAIT));
534 strcpy(current_plugin,p);
536 #ifdef SIMULATOR
537 hdr = sim_plugin_load((char *)plugin, &pd);
538 if (pd == NULL) {
539 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
540 return -1;
542 if (hdr == NULL
543 || hdr->magic != PLUGIN_MAGIC
544 || hdr->target_id != TARGET_ID) {
545 sim_plugin_close(pd);
546 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
547 return -1;
549 if (hdr->api_version > PLUGIN_API_VERSION
550 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
551 sim_plugin_close(pd);
552 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
553 return -1;
555 #else
556 fd = open(plugin, O_RDONLY);
557 if (fd < 0) {
558 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
559 return fd;
562 readsize = read(fd, pluginbuf, PLUGIN_BUFFER_SIZE);
563 close(fd);
565 if (readsize < 0) {
566 gui_syncsplash(HZ*2, str(LANG_READ_FAILED), plugin);
567 return -1;
569 hdr = (struct plugin_header *)pluginbuf;
571 if ((unsigned)readsize <= sizeof(struct plugin_header)
572 || hdr->magic != PLUGIN_MAGIC
573 || hdr->target_id != TARGET_ID
574 || hdr->load_addr != pluginbuf
575 || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE) {
576 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
577 return -1;
579 if (hdr->api_version > PLUGIN_API_VERSION
580 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
581 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
582 return -1;
584 plugin_size = hdr->end_addr - pluginbuf;
586 /* zero out bss area only, above guards end of pluginbuf */
587 memset(pluginbuf + readsize, 0, plugin_size - readsize);
588 #endif
590 plugin_loaded = true;
592 #ifdef HAVE_LCD_BITMAP
593 xm = lcd_getxmargin();
594 ym = lcd_getymargin();
595 lcd_setmargins(0,0);
597 #if LCD_DEPTH > 1
598 old_backdrop = lcd_get_backdrop();
599 #endif
601 lcd_clear_display();
602 lcd_update();
603 #else /* !HAVE_LCD_BITMAP */
604 lcd_clear_display();
605 #endif
607 #ifdef HAVE_REMOTE_LCD
608 rxm = lcd_remote_getxmargin();
609 rym = lcd_remote_getymargin();
610 lcd_remote_setmargins(0, 0);
611 lcd_remote_clear_display();
612 lcd_remote_update();
613 #endif
615 invalidate_icache();
617 rc = hdr->entry_point((struct plugin_api*) &rockbox_api, parameter);
618 /* explicitly casting the pointer here to avoid touching every plugin. */
620 button_clear_queue();
622 #ifdef HAVE_LCD_BITMAP
623 #if LCD_DEPTH > 1
624 lcd_set_backdrop(old_backdrop);
625 #ifdef HAVE_LCD_COLOR
626 lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color,
627 global_settings.bg_color);
628 #else
629 lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG);
630 #endif
631 #else /* LCD_DEPTH == 1 */
632 lcd_set_drawmode(DRMODE_SOLID);
633 #endif /* LCD_DEPTH */
634 /* restore margins */
635 lcd_setmargins(xm,ym);
636 lcd_clear_display();
637 lcd_update();
638 #endif /* HAVE_LCD_BITMAP */
640 #ifdef HAVE_REMOTE_LCD
641 #if LCD_REMOTE_DEPTH > 1
642 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG,
643 LCD_REMOTE_DEFAULT_BG);
644 #else
645 lcd_remote_set_drawmode(DRMODE_SOLID);
646 #endif
647 lcd_remote_setmargins(rxm, rym);
648 lcd_remote_clear_display();
649 lcd_remote_update();
650 #endif
651 action_signalscreenchange();
653 if (pfn_tsr_exit == NULL)
654 plugin_loaded = false;
656 sim_plugin_close(pd);
658 switch (rc) {
659 case PLUGIN_OK:
660 break;
662 case PLUGIN_USB_CONNECTED:
663 return PLUGIN_USB_CONNECTED;
665 default:
666 gui_syncsplash(HZ*2, str(LANG_PLUGIN_ERROR));
667 break;
669 return PLUGIN_OK;
672 /* Returns a pointer to the portion of the plugin buffer that is not already
673 being used. If no plugin is loaded, returns the entire plugin buffer */
674 void* plugin_get_buffer(int* buffer_size)
676 int buffer_pos;
678 if (plugin_loaded)
680 if (plugin_size >= PLUGIN_BUFFER_SIZE)
681 return NULL;
683 *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size;
684 buffer_pos = plugin_size;
686 else
688 *buffer_size = PLUGIN_BUFFER_SIZE;
689 buffer_pos = 0;
692 return &pluginbuf[buffer_pos];
695 /* Returns a pointer to the mp3 buffer.
696 Playback gets stopped, to avoid conflicts.
697 Talk buffer is stolen as well.
699 void* plugin_get_audio_buffer(int* buffer_size)
701 #if CONFIG_CODEC == SWCODEC
702 return audio_get_buffer(true, (size_t *)buffer_size);
703 #else
704 audio_stop();
705 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
706 *buffer_size = audiobufend - audiobuf;
707 return audiobuf;
708 #endif
711 #ifdef IRAM_STEAL
712 /* Initializes plugin IRAM */
713 void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size,
714 char *iedata, size_t iedata_size)
716 audio_iram_steal();
717 memcpy(iramstart, iramcopy, iram_size);
718 memset(iedata, 0, iedata_size);
719 memset(iramcopy, 0, iram_size);
721 #endif /* IRAM_STEAL */
723 /* The plugin wants to stay resident after leaving its main function, e.g.
724 runs from timer or own thread. The callback is registered to later
725 instruct it to free its resources before a new plugin gets loaded. */
726 void plugin_tsr(bool (*exit_callback)(bool))
728 pfn_tsr_exit = exit_callback; /* remember the callback for later */