Flip the balance setting list on scrollwheel targets so it feels more natural
[Rockbox.git] / apps / plugin.c
blob1935297a2645cf9fc4ecf102755cc23a54703fdc
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 char *plugin_get_current_filename(void);
69 extern struct thread_entry threads[MAXTHREADS];
71 static const struct plugin_api rockbox_api = {
73 /* lcd */
74 lcd_set_contrast,
75 lcd_update,
76 lcd_clear_display,
77 lcd_setmargins,
78 lcd_getstringsize,
79 lcd_putsxy,
80 lcd_puts,
81 lcd_puts_scroll,
82 lcd_stop_scroll,
83 #ifdef HAVE_LCD_CHARCELLS
84 lcd_define_pattern,
85 lcd_get_locked_pattern,
86 lcd_unlock_pattern,
87 lcd_putc,
88 lcd_put_cursor,
89 lcd_remove_cursor,
90 lcd_icon,
91 lcd_double_height,
92 #else
93 lcd_set_drawmode,
94 lcd_get_drawmode,
95 lcd_setfont,
96 lcd_drawpixel,
97 lcd_drawline,
98 lcd_hline,
99 lcd_vline,
100 lcd_drawrect,
101 lcd_fillrect,
102 lcd_mono_bitmap_part,
103 lcd_mono_bitmap,
104 #if LCD_DEPTH > 1
105 lcd_set_foreground,
106 lcd_get_foreground,
107 lcd_set_background,
108 lcd_get_background,
109 lcd_bitmap_part,
110 lcd_bitmap,
111 lcd_get_backdrop,
112 lcd_set_backdrop,
113 #endif
114 #if LCD_DEPTH == 16
115 lcd_bitmap_transparent_part,
116 lcd_bitmap_transparent,
117 #endif
118 bidi_l2v,
119 font_get_bits,
120 font_load,
121 lcd_puts_style,
122 lcd_puts_scroll_style,
123 &lcd_framebuffer[0][0],
124 lcd_blit,
125 lcd_update_rect,
126 gui_scrollbar_draw,
127 font_get,
128 font_getstringsize,
129 font_get_width,
130 screen_clear_area,
131 #endif
132 backlight_on,
133 backlight_off,
134 backlight_set_timeout,
135 gui_syncsplash,
136 #ifdef HAVE_REMOTE_LCD
137 /* remote lcd */
138 lcd_remote_set_contrast,
139 lcd_remote_clear_display,
140 lcd_remote_puts,
141 lcd_remote_puts_scroll,
142 lcd_remote_stop_scroll,
143 lcd_remote_set_drawmode,
144 lcd_remote_get_drawmode,
145 lcd_remote_setfont,
146 lcd_remote_getstringsize,
147 lcd_remote_drawpixel,
148 lcd_remote_drawline,
149 lcd_remote_hline,
150 lcd_remote_vline,
151 lcd_remote_drawrect,
152 lcd_remote_fillrect,
153 lcd_remote_mono_bitmap_part,
154 lcd_remote_mono_bitmap,
155 lcd_remote_putsxy,
156 lcd_remote_puts_style,
157 lcd_remote_puts_scroll_style,
158 &lcd_remote_framebuffer[0][0],
159 lcd_remote_update,
160 lcd_remote_update_rect,
162 remote_backlight_on,
163 remote_backlight_off,
164 #endif
165 #if NB_SCREENS == 2
166 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
167 #else
168 {&screens[SCREEN_MAIN]},
169 #endif
170 #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
171 lcd_remote_set_foreground,
172 lcd_remote_get_foreground,
173 lcd_remote_set_background,
174 lcd_remote_get_background,
175 lcd_remote_bitmap_part,
176 lcd_remote_bitmap,
177 #endif
179 #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
180 lcd_yuv_blit,
181 #endif
182 /* list */
183 gui_synclist_init,
184 gui_synclist_set_nb_items,
185 gui_synclist_set_icon_callback,
186 gui_synclist_get_nb_items,
187 gui_synclist_get_sel_pos,
188 gui_synclist_draw,
189 gui_synclist_select_item,
190 gui_synclist_add_item,
191 gui_synclist_del_item,
192 gui_synclist_limit_scroll,
193 gui_synclist_flash,
194 gui_synclist_do_button,
195 gui_synclist_set_title,
197 /* button */
198 button_get,
199 button_get_w_tmo,
200 button_status,
201 button_clear_queue,
202 #ifdef HAS_BUTTON_HOLD
203 button_hold,
204 #endif
206 /* file */
207 (open_func)PREFIX(open),
208 close,
209 (read_func)read,
210 PREFIX(lseek),
211 (creat_func)PREFIX(creat),
212 (write_func)write,
213 PREFIX(remove),
214 PREFIX(rename),
215 PREFIX(ftruncate),
216 PREFIX(filesize),
217 fdprintf,
218 read_line,
219 settings_parseline,
220 #ifndef SIMULATOR
221 ata_sleep,
222 ata_disk_is_active,
223 #endif
224 ata_spindown,
225 reload_directory,
226 create_numbered_filename,
228 /* dir */
229 opendir,
230 closedir,
231 readdir,
232 mkdir,
233 rmdir,
235 /* kernel/ system */
236 PREFIX(sleep),
237 yield,
238 #ifdef HAVE_PRIORITY_SCHEDULING
239 priority_yield,
240 #endif
241 &current_tick,
242 default_event_handler,
243 default_event_handler_ex,
244 threads,
245 create_thread,
246 remove_thread,
247 reset_poweroff_timer,
248 #ifndef SIMULATOR
249 system_memory_guard,
250 &cpu_frequency,
252 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
253 #ifdef CPU_BOOST_LOGGING
254 cpu_boost_,
255 #else
256 cpu_boost,
257 #endif
258 #endif
259 #endif
260 timer_register,
261 timer_unregister,
262 timer_set_period,
264 queue_init,
265 queue_delete,
266 queue_post,
267 queue_wait_w_tmo,
268 usb_acknowledge,
269 #ifdef RB_PROFILE
270 profile_thread,
271 profstop,
272 profile_func_enter,
273 profile_func_exit,
274 #endif
276 #ifdef SIMULATOR
277 /* special simulator hooks */
278 #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH < 8
279 sim_lcd_ex_init,
280 sim_lcd_ex_update_rect,
281 #endif
282 #endif
284 /* strings and memory */
285 snprintf,
286 vsnprintf,
287 strcpy,
288 strncpy,
289 strlen,
290 strrchr,
291 strcmp,
292 strncmp,
293 strcasecmp,
294 strncasecmp,
295 memset,
296 memcpy,
297 memmove,
298 _ctype_,
299 atoi,
300 strchr,
301 strcat,
302 memchr,
303 memcmp,
304 strcasestr,
305 strtok_r,
306 /* unicode stuff */
307 utf8decode,
308 iso_decode,
309 utf16LEdecode,
310 utf16BEdecode,
311 utf8encode,
312 utf8length,
313 utf8seek,
315 /* sound */
316 #if CONFIG_CODEC == SWCODEC
317 sound_default,
318 #endif
319 sound_set,
321 sound_min,
322 sound_max,
323 #ifndef SIMULATOR
324 mp3_play_data,
325 mp3_play_pause,
326 mp3_play_stop,
327 mp3_is_playing,
328 #if CONFIG_CODEC != SWCODEC
329 bitswap,
330 #endif
331 #endif
332 #if CONFIG_CODEC == SWCODEC
333 &audio_master_sampr_list[0],
334 &hw_freq_sampr[0],
335 pcm_apply_settings,
336 pcm_play_data,
337 pcm_play_stop,
338 pcm_set_frequency,
339 pcm_is_playing,
340 pcm_is_paused,
341 pcm_play_pause,
342 pcm_get_bytes_waiting,
343 pcm_calculate_peaks,
344 #ifdef HAVE_RECORDING
345 &rec_freq_sampr[0],
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 #endif /* HAVE_RECORDING */
354 #if INPUT_SRC_CAPS != 0
355 audio_set_output_source,
356 audio_set_input_source,
357 #endif
358 #endif /* CONFIG_CODEC == SWCODEC */
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 /* statusbars */
403 &statusbars,
404 gui_syncstatusbar_draw,
405 /* options */
406 find_setting,
407 option_screen,
408 set_option,
409 set_bool_options,
410 set_int,
411 set_bool,
412 #ifdef HAVE_LCD_COLOR
413 set_color,
414 #endif
416 /* action handling */
417 get_custom_action,
418 get_action,
419 action_userabort,
421 /* power */
422 battery_level,
423 battery_level_safe,
424 battery_time,
425 #ifndef SIMULATOR
426 battery_voltage,
427 #endif
428 #if CONFIG_CHARGING
429 charger_inserted,
430 # if CONFIG_CHARGING == CHARGING_MONITOR
431 charging_state,
432 # endif
433 #endif
434 #ifdef HAVE_USB_POWER
435 usb_powered,
436 #endif
438 /* misc */
439 srand,
440 rand,
441 (qsort_func)qsort,
442 kbd_input,
443 get_time,
444 set_time,
445 #if CONFIG_RTC
446 mktime,
447 #endif
448 plugin_get_buffer,
449 plugin_get_audio_buffer,
450 plugin_tsr,
451 plugin_get_current_filename,
452 #ifdef IRAM_STEAL
453 plugin_iram_init,
454 #endif
455 #if defined(DEBUG) || defined(SIMULATOR)
456 debugf,
457 #endif
458 #ifdef ROCKBOX_HAS_LOGF
459 _logf,
460 #endif
461 &global_settings,
462 &global_status,
463 mp3info,
464 count_mp3_frames,
465 create_xing_header,
466 find_next_frame,
467 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
468 peak_meter_scale_value,
469 peak_meter_set_use_dbfs,
470 peak_meter_get_use_dbfs,
471 #endif
472 #ifdef HAVE_LCD_BITMAP
473 read_bmp_file,
474 screen_dump_set_hook,
475 #endif
476 show_logo,
477 tree_get_context,
478 set_current_file,
479 set_dirfilter,
481 #ifdef HAVE_WHEEL_POSITION
482 wheel_status,
483 wheel_send_events,
484 #endif
486 #ifdef IRIVER_H100_SERIES
487 /* Routines for the iriver_flash -plugin. */
488 detect_original_firmware,
489 detect_flashed_ramimage,
490 detect_flashed_romimage,
491 #endif
492 /* new stuff at the end, sort into place next time
493 the API gets incompatible */
495 #if (CONFIG_CODEC == SWCODEC)
496 spinlock_init,
497 spinlock_lock,
498 spinlock_unlock,
500 codec_load_file,
501 get_codec_filename,
502 get_metadata,
503 #endif
504 led,
507 int plugin_load(const char* plugin, void* parameter)
509 int rc;
510 struct plugin_header *hdr;
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 (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */
528 if (pfn_tsr_exit(!strcmp(current_plugin, plugin)) == false )
530 /* not allowing another plugin to load */
531 return PLUGIN_OK;
533 pfn_tsr_exit = NULL;
534 plugin_loaded = false;
537 gui_syncsplash(0, ID2P(LANG_WAIT));
538 strcpy(current_plugin, plugin);
540 #ifdef SIMULATOR
541 hdr = sim_plugin_load((char *)plugin, &pd);
542 if (pd == NULL) {
543 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
544 return -1;
546 if (hdr == NULL
547 || hdr->magic != PLUGIN_MAGIC
548 || hdr->target_id != TARGET_ID) {
549 sim_plugin_close(pd);
550 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
551 return -1;
553 if (hdr->api_version > PLUGIN_API_VERSION
554 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
555 sim_plugin_close(pd);
556 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
557 return -1;
559 #else
560 fd = open(plugin, O_RDONLY);
561 if (fd < 0) {
562 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
563 return fd;
566 readsize = read(fd, pluginbuf, PLUGIN_BUFFER_SIZE);
567 close(fd);
569 if (readsize < 0) {
570 gui_syncsplash(HZ*2, str(LANG_READ_FAILED), plugin);
571 return -1;
573 hdr = (struct plugin_header *)pluginbuf;
575 if ((unsigned)readsize <= sizeof(struct plugin_header)
576 || hdr->magic != PLUGIN_MAGIC
577 || hdr->target_id != TARGET_ID
578 || hdr->load_addr != pluginbuf
579 || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE) {
580 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
581 return -1;
583 if (hdr->api_version > PLUGIN_API_VERSION
584 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
585 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
586 return -1;
588 plugin_size = hdr->end_addr - pluginbuf;
590 /* zero out bss area only, above guards end of pluginbuf */
591 if (plugin_size > readsize)
592 memset(pluginbuf + readsize, 0, plugin_size - readsize);
593 #endif
595 plugin_loaded = true;
597 xm = lcd_getxmargin();
598 ym = lcd_getymargin();
599 lcd_setmargins(0,0);
601 #if defined HAVE_LCD_BITMAP && LCD_DEPTH > 1
602 old_backdrop = lcd_get_backdrop();
603 #endif
604 lcd_clear_display();
605 lcd_update();
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 #endif /* HAVE_LCD_BITMAP */
636 /* restore margins */
637 lcd_setmargins(xm,ym);
638 lcd_clear_display();
639 lcd_update();
641 #ifdef HAVE_REMOTE_LCD
642 #if LCD_REMOTE_DEPTH > 1
643 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG,
644 LCD_REMOTE_DEFAULT_BG);
645 #else
646 lcd_remote_set_drawmode(DRMODE_SOLID);
647 #endif
648 lcd_remote_setmargins(rxm, rym);
649 lcd_remote_clear_display();
650 lcd_remote_update();
651 #endif
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(size_t *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(size_t *buffer_size)
701 #if CONFIG_CODEC == SWCODEC
702 return audio_get_buffer(true, 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);
720 #if NUM_CORES > 1
721 /* writeback cleared iedata and iramcopy areas */
722 flush_icache();
723 #endif
725 #endif /* IRAM_STEAL */
727 /* The plugin wants to stay resident after leaving its main function, e.g.
728 runs from timer or own thread. The callback is registered to later
729 instruct it to free its resources before a new plugin gets loaded. */
730 void plugin_tsr(bool (*exit_callback)(bool))
732 pfn_tsr_exit = exit_callback; /* remember the callback for later */
735 char *plugin_get_current_filename(void)
737 return current_plugin;