Add a check to make sure initializing the BSS section doesn't pass a negative size...
[Rockbox.git] / apps / plugin.c
blob1db0253c4eae6a56db41876dd8e7c2cfedec8239
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_update,
70 lcd_clear_display,
71 lcd_setmargins,
72 lcd_getstringsize,
73 lcd_putsxy,
74 lcd_puts,
75 lcd_puts_scroll,
76 lcd_stop_scroll,
77 #ifdef HAVE_LCD_CHARCELLS
78 lcd_define_pattern,
79 lcd_get_locked_pattern,
80 lcd_unlock_pattern,
81 lcd_putc,
82 lcd_put_cursor,
83 lcd_remove_cursor,
84 lcd_icon,
85 lcd_double_height,
86 #else
87 lcd_set_drawmode,
88 lcd_get_drawmode,
89 lcd_setfont,
90 lcd_drawpixel,
91 lcd_drawline,
92 lcd_hline,
93 lcd_vline,
94 lcd_drawrect,
95 lcd_fillrect,
96 lcd_mono_bitmap_part,
97 lcd_mono_bitmap,
98 #if LCD_DEPTH > 1
99 lcd_set_foreground,
100 lcd_get_foreground,
101 lcd_set_background,
102 lcd_get_background,
103 lcd_bitmap_part,
104 lcd_bitmap,
105 lcd_set_backdrop,
106 #endif
107 #if LCD_DEPTH == 16
108 lcd_bitmap_transparent_part,
109 lcd_bitmap_transparent,
110 #endif
111 bidi_l2v,
112 font_get_bits,
113 font_load,
114 lcd_puts_style,
115 lcd_puts_scroll_style,
116 &lcd_framebuffer[0][0],
117 lcd_blit,
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 #ifdef HAVE_PRIORITY_SCHEDULING
237 priority_yield,
238 #endif
239 &current_tick,
240 default_event_handler,
241 default_event_handler_ex,
242 create_thread,
243 remove_thread,
244 reset_poweroff_timer,
245 #ifndef SIMULATOR
246 system_memory_guard,
247 &cpu_frequency,
249 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
250 #ifdef CPU_BOOST_LOGGING
251 cpu_boost_,
252 #else
253 cpu_boost,
254 #endif
255 #endif
256 timer_register,
257 timer_unregister,
258 timer_set_period,
259 #endif
260 queue_init,
261 queue_delete,
262 queue_post,
263 queue_wait_w_tmo,
264 usb_acknowledge,
265 #ifdef RB_PROFILE
266 profile_thread,
267 profstop,
268 profile_func_enter,
269 profile_func_exit,
270 #endif
272 #ifdef SIMULATOR
273 /* special simulator hooks */
274 #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH < 8
275 sim_lcd_ex_init,
276 sim_lcd_ex_update_rect,
277 #endif
278 #endif
280 /* strings and memory */
281 snprintf,
282 vsnprintf,
283 strcpy,
284 strncpy,
285 strlen,
286 strrchr,
287 strcmp,
288 strncmp,
289 strcasecmp,
290 strncasecmp,
291 memset,
292 memcpy,
293 memmove,
294 _ctype_,
295 atoi,
296 strchr,
297 strcat,
298 memchr,
299 memcmp,
300 strcasestr,
301 strtok_r,
302 /* unicode stuff */
303 utf8decode,
304 iso_decode,
305 utf16LEdecode,
306 utf16BEdecode,
307 utf8encode,
308 utf8length,
309 utf8seek,
311 /* sound */
312 #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
313 sound_default,
314 #endif
315 sound_set,
316 set_sound,
318 sound_min,
319 sound_max,
320 #ifndef SIMULATOR
321 mp3_play_data,
322 mp3_play_pause,
323 mp3_play_stop,
324 mp3_is_playing,
325 #if CONFIG_CODEC != SWCODEC
326 bitswap,
327 #endif
328 #endif
329 #if CONFIG_CODEC == SWCODEC
330 &audio_master_sampr_list[0],
331 &hw_freq_sampr[0],
332 #ifndef SIMULATOR
333 pcm_apply_settings,
334 #endif
335 pcm_play_data,
336 pcm_play_stop,
337 pcm_set_frequency,
338 pcm_is_playing,
339 pcm_is_paused,
340 pcm_play_pause,
341 pcm_get_bytes_waiting,
342 pcm_calculate_peaks,
343 #ifdef HAVE_RECORDING
344 &rec_freq_sampr[0],
345 #ifndef SIMULATOR
346 pcm_init_recording,
347 pcm_close_recording,
348 pcm_record_data,
349 pcm_record_more,
350 pcm_stop_recording,
351 pcm_calculate_rec_peaks,
352 audio_set_recording_gain,
353 audio_set_output_source,
354 rec_set_source,
355 #endif
356 #endif /* HAVE_RECORDING */
358 #endif
360 /* playback control */
361 playlist_amount,
362 playlist_resume,
363 playlist_start,
364 PREFIX(audio_play),
365 audio_stop,
366 audio_pause,
367 audio_resume,
368 audio_next,
369 audio_prev,
370 audio_ff_rewind,
371 audio_next_track,
372 audio_status,
373 audio_has_changed_track,
374 audio_current_track,
375 audio_flush_and_reload_tracks,
376 audio_get_file_pos,
377 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
378 mpeg_get_last_header,
379 #endif
380 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) || \
381 (CONFIG_CODEC == SWCODEC)
382 sound_set_pitch,
383 #endif
385 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
386 /* MAS communication */
387 mas_readmem,
388 mas_writemem,
389 mas_readreg,
390 mas_writereg,
391 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
392 mas_codec_writereg,
393 mas_codec_readreg,
394 i2c_begin,
395 i2c_end,
396 i2c_write,
397 #endif
398 #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
400 /* menu */
401 do_menu,
402 /* OLD API - dont use unless you have to */
403 menu_init,
404 menu_exit,
405 menu_show,
406 menu_run,
407 menu_count,
408 set_option,
409 set_int,
410 set_bool,
412 /* action handling */
413 get_custom_action,
414 get_action,
415 action_signalscreenchange,
416 action_userabort,
418 /* power */
419 battery_level,
420 battery_level_safe,
421 battery_time,
422 #ifndef SIMULATOR
423 battery_voltage,
424 #endif
425 #if CONFIG_CHARGING
426 charger_inserted,
427 # if CONFIG_CHARGING == CHARGING_MONITOR
428 charging_state,
429 # endif
430 #endif
431 #ifdef HAVE_USB_POWER
432 usb_powered,
433 #endif
435 /* misc */
436 srand,
437 rand,
438 (qsort_func)qsort,
439 kbd_input,
440 get_time,
441 set_time,
442 plugin_get_buffer,
443 plugin_get_audio_buffer,
444 plugin_tsr,
445 #ifdef IRAM_STEAL
446 plugin_iram_init,
447 #endif
448 #if defined(DEBUG) || defined(SIMULATOR)
449 debugf,
450 #endif
451 #ifdef ROCKBOX_HAS_LOGF
452 _logf,
453 #endif
454 &global_settings,
455 &global_status,
456 mp3info,
457 count_mp3_frames,
458 create_xing_header,
459 find_next_frame,
460 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
461 peak_meter_scale_value,
462 peak_meter_set_use_dbfs,
463 peak_meter_get_use_dbfs,
464 #endif
465 #ifdef HAVE_LCD_BITMAP
466 read_bmp_file,
467 screen_dump_set_hook,
468 #endif
469 show_logo,
470 tree_get_context,
472 #ifdef HAVE_WHEEL_POSITION
473 wheel_status,
474 wheel_send_events,
475 #endif
476 #if LCD_DEPTH > 1
477 lcd_get_backdrop,
478 #endif
480 /* new stuff at the end, sort into place next time
481 the API gets incompatible */
483 #ifdef IRIVER_H100_SERIES
484 /* Routines for the iriver_flash -plugin. */
485 detect_original_firmware,
486 detect_flashed_ramimage,
487 detect_flashed_romimage,
488 #endif
491 int plugin_load(const char* plugin, void* parameter)
493 int rc;
494 struct plugin_header *hdr;
495 const char *p = strrchr(plugin,'/');
496 #ifdef SIMULATOR
497 void *pd;
498 #else
499 int fd;
500 ssize_t readsize;
501 #endif
502 int xm, ym;
503 #ifdef HAVE_REMOTE_LCD
504 int rxm, rym;
505 #endif
507 #if LCD_DEPTH > 1
508 fb_data* old_backdrop;
509 #endif
511 if (!p)
512 p = plugin;
513 action_signalscreenchange();
515 if (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */
517 if (pfn_tsr_exit(!strcmp(current_plugin,p)) == false )
519 /* not allowing another plugin to load */
520 return PLUGIN_OK;
522 pfn_tsr_exit = NULL;
523 plugin_loaded = false;
526 gui_syncsplash(0, str(LANG_WAIT));
527 strcpy(current_plugin,p);
529 #ifdef SIMULATOR
530 hdr = sim_plugin_load((char *)plugin, &pd);
531 if (pd == NULL) {
532 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
533 return -1;
535 if (hdr == NULL
536 || hdr->magic != PLUGIN_MAGIC
537 || hdr->target_id != TARGET_ID) {
538 sim_plugin_close(pd);
539 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
540 return -1;
542 if (hdr->api_version > PLUGIN_API_VERSION
543 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
544 sim_plugin_close(pd);
545 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
546 return -1;
548 #else
549 fd = open(plugin, O_RDONLY);
550 if (fd < 0) {
551 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
552 return fd;
555 readsize = read(fd, pluginbuf, PLUGIN_BUFFER_SIZE);
556 close(fd);
558 if (readsize < 0) {
559 gui_syncsplash(HZ*2, str(LANG_READ_FAILED), plugin);
560 return -1;
562 hdr = (struct plugin_header *)pluginbuf;
564 if ((unsigned)readsize <= sizeof(struct plugin_header)
565 || hdr->magic != PLUGIN_MAGIC
566 || hdr->target_id != TARGET_ID
567 || hdr->load_addr != pluginbuf
568 || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE) {
569 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
570 return -1;
572 if (hdr->api_version > PLUGIN_API_VERSION
573 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
574 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
575 return -1;
577 plugin_size = hdr->end_addr - pluginbuf;
579 /* zero out bss area only, above guards end of pluginbuf */
580 if (plugin_size > readsize)
581 memset(pluginbuf + readsize, 0, plugin_size - readsize);
582 #endif
584 plugin_loaded = true;
586 xm = lcd_getxmargin();
587 ym = lcd_getymargin();
588 lcd_setmargins(0,0);
590 #if defined HAVE_LCD_BITMAP && LCD_DEPTH > 1
591 old_backdrop = lcd_get_backdrop();
592 #endif
593 lcd_clear_display();
594 lcd_update();
596 #ifdef HAVE_REMOTE_LCD
597 rxm = lcd_remote_getxmargin();
598 rym = lcd_remote_getymargin();
599 lcd_remote_setmargins(0, 0);
600 lcd_remote_clear_display();
601 lcd_remote_update();
602 #endif
604 invalidate_icache();
606 rc = hdr->entry_point((struct plugin_api*) &rockbox_api, parameter);
607 /* explicitly casting the pointer here to avoid touching every plugin. */
609 action_signalscreenchange();
610 button_clear_queue();
612 #ifdef HAVE_LCD_BITMAP
613 #if LCD_DEPTH > 1
614 lcd_set_backdrop(old_backdrop);
615 #ifdef HAVE_LCD_COLOR
616 lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color,
617 global_settings.bg_color);
618 #else
619 lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG);
620 #endif
621 #else /* LCD_DEPTH == 1 */
622 lcd_set_drawmode(DRMODE_SOLID);
623 #endif /* LCD_DEPTH */
624 #endif /* HAVE_LCD_BITMAP */
626 /* restore margins */
627 lcd_setmargins(xm,ym);
628 lcd_clear_display();
629 lcd_update();
631 #ifdef HAVE_REMOTE_LCD
632 #if LCD_REMOTE_DEPTH > 1
633 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG,
634 LCD_REMOTE_DEFAULT_BG);
635 #else
636 lcd_remote_set_drawmode(DRMODE_SOLID);
637 #endif
638 lcd_remote_setmargins(rxm, rym);
639 lcd_remote_clear_display();
640 lcd_remote_update();
641 #endif
643 if (pfn_tsr_exit == NULL)
644 plugin_loaded = false;
646 sim_plugin_close(pd);
648 switch (rc) {
649 case PLUGIN_OK:
650 break;
652 case PLUGIN_USB_CONNECTED:
653 return PLUGIN_USB_CONNECTED;
655 default:
656 gui_syncsplash(HZ*2, str(LANG_PLUGIN_ERROR));
657 break;
659 return PLUGIN_OK;
662 /* Returns a pointer to the portion of the plugin buffer that is not already
663 being used. If no plugin is loaded, returns the entire plugin buffer */
664 void* plugin_get_buffer(int* buffer_size)
666 int buffer_pos;
668 if (plugin_loaded)
670 if (plugin_size >= PLUGIN_BUFFER_SIZE)
671 return NULL;
673 *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size;
674 buffer_pos = plugin_size;
676 else
678 *buffer_size = PLUGIN_BUFFER_SIZE;
679 buffer_pos = 0;
682 return &pluginbuf[buffer_pos];
685 /* Returns a pointer to the mp3 buffer.
686 Playback gets stopped, to avoid conflicts.
687 Talk buffer is stolen as well.
689 void* plugin_get_audio_buffer(int* buffer_size)
691 #if CONFIG_CODEC == SWCODEC
692 return audio_get_buffer(true, (size_t *)buffer_size);
693 #else
694 audio_stop();
695 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
696 *buffer_size = audiobufend - audiobuf;
697 return audiobuf;
698 #endif
701 #ifdef IRAM_STEAL
702 /* Initializes plugin IRAM */
703 void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size,
704 char *iedata, size_t iedata_size)
706 audio_iram_steal();
707 memcpy(iramstart, iramcopy, iram_size);
708 memset(iedata, 0, iedata_size);
709 memset(iramcopy, 0, iram_size);
711 #endif /* IRAM_STEAL */
713 /* The plugin wants to stay resident after leaving its main function, e.g.
714 runs from timer or own thread. The callback is registered to later
715 instruct it to free its resources before a new plugin gets loaded. */
716 void plugin_tsr(bool (*exit_callback)(bool))
718 pfn_tsr_exit = exit_callback; /* remember the callback for later */