rbutilQt: added Talkfile creation.
[Rockbox.git] / apps / plugin.c
blob20ecafb5320da1120724b518d99598d8891e4726
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"
38 #if CONFIG_CHARGING
39 #include "power.h"
40 #endif
42 #ifdef HAVE_LCD_BITMAP
43 #include "scrollbar.h"
44 #include "peakmeter.h"
45 #include "bmp.h"
46 #include "bidi.h"
47 #endif
49 #ifdef SIMULATOR
50 static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
51 void *sim_plugin_load(char *plugin, void **pd);
52 void sim_plugin_close(void *pd);
53 void sim_lcd_ex_init(int shades, unsigned long (*getpixel)(int, int));
54 void sim_lcd_ex_update_rect(int x, int y, int width, int height);
55 #else
56 #define sim_plugin_close(x)
57 extern unsigned char pluginbuf[];
58 #include "bitswap.h"
59 #endif
61 /* for actual plugins only, not for codecs */
62 static bool plugin_loaded = false;
63 static int plugin_size = 0;
64 static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
65 static char current_plugin[MAX_PATH];
67 extern struct thread_entry threads[MAXTHREADS];
69 static const struct plugin_api rockbox_api = {
71 /* lcd */
72 lcd_set_contrast,
73 lcd_update,
74 lcd_clear_display,
75 lcd_setmargins,
76 lcd_getstringsize,
77 lcd_putsxy,
78 lcd_puts,
79 lcd_puts_scroll,
80 lcd_stop_scroll,
81 #ifdef HAVE_LCD_CHARCELLS
82 lcd_define_pattern,
83 lcd_get_locked_pattern,
84 lcd_unlock_pattern,
85 lcd_putc,
86 lcd_put_cursor,
87 lcd_remove_cursor,
88 lcd_icon,
89 lcd_double_height,
90 #else
91 lcd_set_drawmode,
92 lcd_get_drawmode,
93 lcd_setfont,
94 lcd_drawpixel,
95 lcd_drawline,
96 lcd_hline,
97 lcd_vline,
98 lcd_drawrect,
99 lcd_fillrect,
100 lcd_mono_bitmap_part,
101 lcd_mono_bitmap,
102 #if LCD_DEPTH > 1
103 lcd_set_foreground,
104 lcd_get_foreground,
105 lcd_set_background,
106 lcd_get_background,
107 lcd_bitmap_part,
108 lcd_bitmap,
109 lcd_get_backdrop,
110 lcd_set_backdrop,
111 #endif
112 #if LCD_DEPTH == 16
113 lcd_bitmap_transparent_part,
114 lcd_bitmap_transparent,
115 #endif
116 bidi_l2v,
117 font_get_bits,
118 font_load,
119 lcd_puts_style,
120 lcd_puts_scroll_style,
121 &lcd_framebuffer[0][0],
122 lcd_blit,
123 lcd_update_rect,
124 gui_scrollbar_draw,
125 font_get,
126 font_getstringsize,
127 font_get_width,
128 #endif
129 backlight_on,
130 backlight_off,
131 backlight_set_timeout,
132 gui_syncsplash,
133 #ifdef HAVE_REMOTE_LCD
134 /* remote lcd */
135 lcd_remote_set_contrast,
136 lcd_remote_clear_display,
137 lcd_remote_puts,
138 lcd_remote_puts_scroll,
139 lcd_remote_stop_scroll,
140 lcd_remote_set_drawmode,
141 lcd_remote_get_drawmode,
142 lcd_remote_setfont,
143 lcd_remote_getstringsize,
144 lcd_remote_drawpixel,
145 lcd_remote_drawline,
146 lcd_remote_hline,
147 lcd_remote_vline,
148 lcd_remote_drawrect,
149 lcd_remote_fillrect,
150 lcd_remote_mono_bitmap_part,
151 lcd_remote_mono_bitmap,
152 lcd_remote_putsxy,
153 lcd_remote_puts_style,
154 lcd_remote_puts_scroll_style,
155 &lcd_remote_framebuffer[0][0],
156 lcd_remote_update,
157 lcd_remote_update_rect,
159 remote_backlight_on,
160 remote_backlight_off,
161 #endif
162 #if NB_SCREENS == 2
163 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
164 #else
165 {&screens[SCREEN_MAIN]},
166 #endif
167 #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
168 lcd_remote_set_foreground,
169 lcd_remote_get_foreground,
170 lcd_remote_set_background,
171 lcd_remote_get_background,
172 lcd_remote_bitmap_part,
173 lcd_remote_bitmap,
174 #endif
176 #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
177 lcd_yuv_blit,
178 #endif
179 /* list */
180 gui_synclist_init,
181 gui_synclist_set_nb_items,
182 gui_synclist_set_icon_callback,
183 gui_synclist_get_nb_items,
184 gui_synclist_get_sel_pos,
185 gui_synclist_draw,
186 gui_synclist_select_item,
187 gui_synclist_add_item,
188 gui_synclist_del_item,
189 gui_synclist_limit_scroll,
190 gui_synclist_flash,
191 gui_synclist_do_button,
192 gui_synclist_set_title,
194 /* button */
195 button_get,
196 button_get_w_tmo,
197 button_status,
198 button_clear_queue,
199 #ifdef HAS_BUTTON_HOLD
200 button_hold,
201 #endif
203 /* file */
204 (open_func)PREFIX(open),
205 close,
206 (read_func)read,
207 PREFIX(lseek),
208 (creat_func)PREFIX(creat),
209 (write_func)write,
210 PREFIX(remove),
211 PREFIX(rename),
212 PREFIX(ftruncate),
213 PREFIX(filesize),
214 fdprintf,
215 read_line,
216 settings_parseline,
217 #ifndef SIMULATOR
218 ata_sleep,
219 ata_disk_is_active,
220 #endif
221 ata_spindown,
222 reload_directory,
223 create_numbered_filename,
225 /* dir */
226 opendir,
227 closedir,
228 readdir,
229 mkdir,
230 rmdir,
232 /* kernel/ system */
233 PREFIX(sleep),
234 yield,
235 #ifdef HAVE_PRIORITY_SCHEDULING
236 priority_yield,
237 #endif
238 &current_tick,
239 default_event_handler,
240 default_event_handler_ex,
241 threads,
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 #endif
257 timer_register,
258 timer_unregister,
259 timer_set_period,
261 queue_init,
262 queue_delete,
263 queue_post,
264 queue_wait_w_tmo,
265 usb_acknowledge,
266 #ifdef RB_PROFILE
267 profile_thread,
268 profstop,
269 profile_func_enter,
270 profile_func_exit,
271 #endif
273 #ifdef SIMULATOR
274 /* special simulator hooks */
275 #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH < 8
276 sim_lcd_ex_init,
277 sim_lcd_ex_update_rect,
278 #endif
279 #endif
281 /* strings and memory */
282 snprintf,
283 vsnprintf,
284 strcpy,
285 strncpy,
286 strlen,
287 strrchr,
288 strcmp,
289 strncmp,
290 strcasecmp,
291 strncasecmp,
292 memset,
293 memcpy,
294 memmove,
295 _ctype_,
296 atoi,
297 strchr,
298 strcat,
299 memchr,
300 memcmp,
301 strcasestr,
302 strtok_r,
303 /* unicode stuff */
304 utf8decode,
305 iso_decode,
306 utf16LEdecode,
307 utf16BEdecode,
308 utf8encode,
309 utf8length,
310 utf8seek,
312 /* sound */
313 #if CONFIG_CODEC == SWCODEC
314 sound_default,
315 #endif
316 sound_set,
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 pcm_apply_settings,
333 pcm_play_data,
334 pcm_play_stop,
335 pcm_set_frequency,
336 pcm_is_playing,
337 pcm_is_paused,
338 pcm_play_pause,
339 pcm_get_bytes_waiting,
340 pcm_calculate_peaks,
341 #ifdef HAVE_RECORDING
342 &rec_freq_sampr[0],
343 pcm_init_recording,
344 pcm_close_recording,
345 pcm_record_data,
346 pcm_record_more,
347 pcm_stop_recording,
348 pcm_calculate_rec_peaks,
349 audio_set_recording_gain,
350 #endif /* HAVE_RECORDING */
351 #if INPUT_SRC_CAPS != 0
352 audio_set_output_source,
353 audio_set_input_source,
354 #endif
355 #endif /* CONFIG_CODEC == SWCODEC */
357 /* playback control */
358 playlist_amount,
359 playlist_resume,
360 playlist_start,
361 PREFIX(audio_play),
362 audio_stop,
363 audio_pause,
364 audio_resume,
365 audio_next,
366 audio_prev,
367 audio_ff_rewind,
368 audio_next_track,
369 audio_status,
370 audio_has_changed_track,
371 audio_current_track,
372 audio_flush_and_reload_tracks,
373 audio_get_file_pos,
374 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
375 mpeg_get_last_header,
376 #endif
377 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) || \
378 (CONFIG_CODEC == SWCODEC)
379 sound_set_pitch,
380 #endif
382 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
383 /* MAS communication */
384 mas_readmem,
385 mas_writemem,
386 mas_readreg,
387 mas_writereg,
388 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
389 mas_codec_writereg,
390 mas_codec_readreg,
391 i2c_begin,
392 i2c_end,
393 i2c_write,
394 #endif
395 #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
397 /* menu */
398 do_menu,
399 /* statusbars */
400 &statusbars,
401 gui_syncstatusbar_draw,
402 /* options */
403 find_setting,
404 option_screen,
405 set_option,
406 set_bool_options,
407 set_int,
408 set_bool,
409 #ifdef HAVE_LCD_COLOR
410 set_color,
411 #endif
413 /* action handling */
414 get_custom_action,
415 get_action,
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 #if CONFIG_RTC
443 mktime,
444 #endif
445 plugin_get_buffer,
446 plugin_get_audio_buffer,
447 plugin_tsr,
448 #ifdef IRAM_STEAL
449 plugin_iram_init,
450 #endif
451 #if defined(DEBUG) || defined(SIMULATOR)
452 debugf,
453 #endif
454 #ifdef ROCKBOX_HAS_LOGF
455 _logf,
456 #endif
457 &global_settings,
458 &global_status,
459 mp3info,
460 count_mp3_frames,
461 create_xing_header,
462 find_next_frame,
463 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
464 peak_meter_scale_value,
465 peak_meter_set_use_dbfs,
466 peak_meter_get_use_dbfs,
467 #endif
468 #ifdef HAVE_LCD_BITMAP
469 read_bmp_file,
470 screen_dump_set_hook,
471 #endif
472 show_logo,
473 tree_get_context,
475 #ifdef HAVE_WHEEL_POSITION
476 wheel_status,
477 wheel_send_events,
478 #endif
480 #ifdef IRIVER_H100_SERIES
481 /* Routines for the iriver_flash -plugin. */
482 detect_original_firmware,
483 detect_flashed_ramimage,
484 detect_flashed_romimage,
485 #endif
486 /* new stuff at the end, sort into place next time
487 the API gets incompatible */
489 #if (CONFIG_CODEC == SWCODEC)
490 spinlock_init,
491 spinlock_lock,
492 spinlock_unlock,
494 codec_load_file,
495 get_codec_filename,
496 get_metadata,
497 #endif
498 #ifdef HAVE_LCD_BITMAP
499 screen_clear_area,
500 #endif
501 led,
502 set_current_file,
503 set_dirfilter,
506 int plugin_load(const char* plugin, void* parameter)
508 int rc;
509 struct plugin_header *hdr;
510 const char *p = strrchr(plugin,'/');
511 #ifdef SIMULATOR
512 void *pd;
513 #else
514 int fd;
515 ssize_t readsize;
516 #endif
517 int xm, ym;
518 #ifdef HAVE_REMOTE_LCD
519 int rxm, rym;
520 #endif
522 #if LCD_DEPTH > 1
523 fb_data* old_backdrop;
524 #endif
526 if (!p)
527 p = plugin;
529 if (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */
531 if (pfn_tsr_exit(!strcmp(current_plugin,p)) == false )
533 /* not allowing another plugin to load */
534 return PLUGIN_OK;
536 pfn_tsr_exit = NULL;
537 plugin_loaded = false;
540 gui_syncsplash(0, str(LANG_WAIT));
541 strcpy(current_plugin,p);
543 #ifdef SIMULATOR
544 hdr = sim_plugin_load((char *)plugin, &pd);
545 if (pd == NULL) {
546 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
547 return -1;
549 if (hdr == NULL
550 || hdr->magic != PLUGIN_MAGIC
551 || hdr->target_id != TARGET_ID) {
552 sim_plugin_close(pd);
553 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
554 return -1;
556 if (hdr->api_version > PLUGIN_API_VERSION
557 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
558 sim_plugin_close(pd);
559 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
560 return -1;
562 #else
563 fd = open(plugin, O_RDONLY);
564 if (fd < 0) {
565 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
566 return fd;
569 readsize = read(fd, pluginbuf, PLUGIN_BUFFER_SIZE);
570 close(fd);
572 if (readsize < 0) {
573 gui_syncsplash(HZ*2, str(LANG_READ_FAILED), plugin);
574 return -1;
576 hdr = (struct plugin_header *)pluginbuf;
578 if ((unsigned)readsize <= sizeof(struct plugin_header)
579 || hdr->magic != PLUGIN_MAGIC
580 || hdr->target_id != TARGET_ID
581 || hdr->load_addr != pluginbuf
582 || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE) {
583 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
584 return -1;
586 if (hdr->api_version > PLUGIN_API_VERSION
587 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
588 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
589 return -1;
591 plugin_size = hdr->end_addr - pluginbuf;
593 /* zero out bss area only, above guards end of pluginbuf */
594 if (plugin_size > readsize)
595 memset(pluginbuf + readsize, 0, plugin_size - readsize);
596 #endif
598 plugin_loaded = true;
600 xm = lcd_getxmargin();
601 ym = lcd_getymargin();
602 lcd_setmargins(0,0);
604 #if defined HAVE_LCD_BITMAP && LCD_DEPTH > 1
605 old_backdrop = lcd_get_backdrop();
606 #endif
607 lcd_clear_display();
608 lcd_update();
610 #ifdef HAVE_REMOTE_LCD
611 rxm = lcd_remote_getxmargin();
612 rym = lcd_remote_getymargin();
613 lcd_remote_setmargins(0, 0);
614 lcd_remote_clear_display();
615 lcd_remote_update();
616 #endif
618 invalidate_icache();
620 rc = hdr->entry_point((struct plugin_api*) &rockbox_api, parameter);
621 /* explicitly casting the pointer here to avoid touching every plugin. */
623 button_clear_queue();
625 #ifdef HAVE_LCD_BITMAP
626 #if LCD_DEPTH > 1
627 lcd_set_backdrop(old_backdrop);
628 #ifdef HAVE_LCD_COLOR
629 lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color,
630 global_settings.bg_color);
631 #else
632 lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG);
633 #endif
634 #else /* LCD_DEPTH == 1 */
635 lcd_set_drawmode(DRMODE_SOLID);
636 #endif /* LCD_DEPTH */
637 #endif /* HAVE_LCD_BITMAP */
639 /* restore margins */
640 lcd_setmargins(xm,ym);
641 lcd_clear_display();
642 lcd_update();
644 #ifdef HAVE_REMOTE_LCD
645 #if LCD_REMOTE_DEPTH > 1
646 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG,
647 LCD_REMOTE_DEFAULT_BG);
648 #else
649 lcd_remote_set_drawmode(DRMODE_SOLID);
650 #endif
651 lcd_remote_setmargins(rxm, rym);
652 lcd_remote_clear_display();
653 lcd_remote_update();
654 #endif
656 if (pfn_tsr_exit == NULL)
657 plugin_loaded = false;
659 sim_plugin_close(pd);
661 switch (rc) {
662 case PLUGIN_OK:
663 break;
665 case PLUGIN_USB_CONNECTED:
666 return PLUGIN_USB_CONNECTED;
668 default:
669 gui_syncsplash(HZ*2, str(LANG_PLUGIN_ERROR));
670 break;
672 return PLUGIN_OK;
675 /* Returns a pointer to the portion of the plugin buffer that is not already
676 being used. If no plugin is loaded, returns the entire plugin buffer */
677 void* plugin_get_buffer(size_t *buffer_size)
679 int buffer_pos;
681 if (plugin_loaded)
683 if (plugin_size >= PLUGIN_BUFFER_SIZE)
684 return NULL;
686 *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size;
687 buffer_pos = plugin_size;
689 else
691 *buffer_size = PLUGIN_BUFFER_SIZE;
692 buffer_pos = 0;
695 return &pluginbuf[buffer_pos];
698 /* Returns a pointer to the mp3 buffer.
699 Playback gets stopped, to avoid conflicts.
700 Talk buffer is stolen as well.
702 void* plugin_get_audio_buffer(size_t *buffer_size)
704 #if CONFIG_CODEC == SWCODEC
705 return audio_get_buffer(true, buffer_size);
706 #else
707 audio_stop();
708 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
709 *buffer_size = audiobufend - audiobuf;
710 return audiobuf;
711 #endif
714 #ifdef IRAM_STEAL
715 /* Initializes plugin IRAM */
716 void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size,
717 char *iedata, size_t iedata_size)
719 audio_iram_steal();
720 memcpy(iramstart, iramcopy, iram_size);
721 memset(iedata, 0, iedata_size);
722 memset(iramcopy, 0, iram_size);
723 #if NUM_CORES > 1
724 /* writeback cleared iedata and iramcopy areas */
725 flush_icache();
726 #endif
728 #endif /* IRAM_STEAL */
730 /* The plugin wants to stay resident after leaving its main function, e.g.
731 runs from timer or own thread. The callback is registered to later
732 instruct it to free its resources before a new plugin gets loaded. */
733 void plugin_tsr(bool (*exit_callback)(bool))
735 pfn_tsr_exit = exit_callback; /* remember the callback for later */