The Poweroff menu entry is only for Players
[kugel-rb.git] / apps / plugin.c
blobaf6770213dabbfde21dc287f7346c230cb9286aa
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 <stdbool.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <atoi.h>
23 #include <timefuncs.h>
24 #include <ctype.h>
25 #include "debug.h"
26 #include "button.h"
27 #include "lcd.h"
28 #include "dir.h"
29 #include "file.h"
30 #include "kernel.h"
31 #include "sprintf.h"
32 #include "screens.h"
33 #include "misc.h"
34 #include "mas.h"
35 #include "plugin.h"
36 #include "lang.h"
37 #include "keyboard.h"
38 #include "mpeg.h"
39 #include "buffer.h"
40 #include "mp3_playback.h"
41 #include "backlight.h"
42 #include "ata.h"
43 #include "talk.h"
44 #include "mp3data.h"
45 #include "powermgmt.h"
47 #ifdef HAVE_LCD_BITMAP
48 #include "peakmeter.h"
49 #include "widgets.h"
50 #endif
52 #ifdef SIMULATOR
53 #include <debug.h>
54 #ifdef WIN32
55 #include "plugin-win32.h"
56 #else
57 #include <dlfcn.h>
58 #endif
59 #define PREFIX(_x_) sim_ ## _x_
60 #else
61 #define PREFIX(_x_) _x_
62 #endif
64 #define PLUGIN_BUFFER_SIZE 0x8000
66 #ifdef SIMULATOR
67 static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
68 #else
69 extern unsigned char pluginbuf[];
70 #include "bitswap.h"
71 #endif
73 static bool plugin_loaded = false;
74 static int plugin_size = 0;
75 #ifndef SIMULATOR
76 static void (*pfn_timer)(void) = NULL; /* user timer handler */
77 #endif
78 static void (*pfn_tsr_exit)(void) = NULL; /* TSR exit callback */
80 static int plugin_test(int api_version, int model, int memsize);
82 static const struct plugin_api rockbox_api = {
83 PLUGIN_API_VERSION,
85 plugin_test,
87 /* lcd */
88 lcd_clear_display,
89 lcd_puts,
90 lcd_puts_scroll,
91 lcd_stop_scroll,
92 lcd_set_contrast,
93 #ifdef HAVE_LCD_CHARCELLS
94 lcd_define_pattern,
95 lcd_get_locked_pattern,
96 lcd_unlock_pattern,
97 lcd_putc,
98 lcd_put_cursor,
99 lcd_remove_cursor,
100 lcd_icon,
101 #else
102 lcd_putsxy,
103 lcd_puts_style,
104 lcd_bitmap,
105 lcd_drawline,
106 lcd_clearline,
107 lcd_drawpixel,
108 lcd_clearpixel,
109 lcd_setfont,
110 font_get,
111 lcd_clearrect,
112 lcd_fillrect,
113 lcd_drawrect,
114 lcd_invertrect,
115 lcd_getstringsize,
116 lcd_update,
117 lcd_update_rect,
118 scrollbar,
119 checkbox,
120 &lcd_framebuffer[0][0],
121 lcd_blit,
122 #ifndef SIMULATOR
123 lcd_roll,
124 #endif
125 #endif
126 backlight_on,
127 backlight_off,
128 splash,
130 /* button */
131 button_get,
132 button_get_w_tmo,
133 button_status,
134 button_clear_queue,
136 /* file */
137 (open_func)PREFIX(open),
138 PREFIX(close),
139 (read_func)read,
140 lseek,
141 (creat_func)PREFIX(creat),
142 (write_func)write,
143 PREFIX(remove),
144 PREFIX(rename),
145 ftruncate,
146 PREFIX(filesize),
147 fprintf,
148 read_line,
149 settings_parseline,
150 #ifndef SIMULATOR
151 ata_sleep,
152 #endif
154 /* dir */
155 PREFIX(opendir),
156 PREFIX(closedir),
157 PREFIX(readdir),
159 /* kernel */
160 PREFIX(sleep),
161 yield,
162 usb_screen,
163 &current_tick,
164 default_event_handler,
165 create_thread,
166 remove_thread,
167 reset_poweroff_timer,
169 /* strings and memory */
170 snprintf,
171 strcpy,
172 strncpy,
173 strlen,
174 strrchr,
175 strcmp,
176 strcasecmp,
177 memset,
178 memcpy,
179 #ifndef SIMULATOR
180 _ctype_,
181 #endif
182 atoi,
184 /* sound */
185 mpeg_sound_set,
186 #ifndef SIMULATOR
187 mp3_play_data,
188 mp3_play_pause,
189 mp3_play_stop,
190 mp3_is_playing,
191 bitswap,
192 #endif
194 /* playback control */
195 mpeg_play,
196 mpeg_stop,
197 mpeg_pause,
198 mpeg_resume,
199 mpeg_next,
200 mpeg_prev,
201 mpeg_ff_rewind,
202 mpeg_next_track,
203 playlist_amount,
204 mpeg_status,
205 mpeg_has_changed_track,
206 mpeg_current_track,
208 /* MAS communication */
209 #ifndef SIMULATOR
210 mas_readmem,
211 mas_writemem,
212 mas_readreg,
213 mas_writereg,
214 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
215 mas_codec_writereg,
216 mas_codec_readreg,
217 #endif
218 #endif
220 /* misc */
221 srand,
222 rand,
223 (qsort_func)qsort,
224 kbd_input,
225 get_time,
226 set_time,
227 plugin_get_buffer,
228 plugin_get_mp3_buffer,
229 #ifndef SIMULATOR
230 plugin_register_timer,
231 plugin_unregister_timer,
232 #endif
233 plugin_tsr,
234 #if defined(DEBUG) || defined(SIMULATOR)
235 debugf,
236 #endif
237 &global_settings,
238 backlight_set_timeout,
239 mp3info,
240 count_mp3_frames,
241 create_xing_header,
242 battery_level,
244 /* new stuff at the end, sort into place next time
245 the API gets incompatible */
247 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
248 mpeg_set_pitch,
250 peak_meter_scale_value,
251 peak_meter_set_use_dbfs,
252 peak_meter_get_use_dbfs,
253 #endif
254 #ifdef HAVE_LCD_BITMAP
255 lcd_puts_scroll_style,
256 #endif
257 mpeg_flush_and_reload_tracks,
258 strncasecmp,
259 mpeg_get_file_pos,
260 find_next_frame,
261 mpeg_get_last_header,
262 #ifndef SIMULATOR
263 system_memory_guard,
264 #endif
267 int plugin_load(const char* plugin, void* parameter)
269 enum plugin_status (*plugin_start)(struct plugin_api* api, void* param);
270 int rc;
271 char buf[64];
272 #ifdef SIMULATOR
273 void* pd;
274 char path[256];
275 #else
276 int fd;
277 #endif
278 #ifdef HAVE_LCD_BITMAP
279 int xm,ym;
280 #endif
282 if (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */
284 pfn_tsr_exit(); /* force it to exit now */
285 pfn_tsr_exit = NULL;
288 #ifdef HAVE_LCD_BITMAP
289 lcd_clear_display();
290 xm = lcd_getxmargin();
291 ym = lcd_getymargin();
292 lcd_setmargins(0,0);
293 lcd_update();
294 #else
295 lcd_clear_display();
296 #endif
297 #ifdef SIMULATOR
298 snprintf(path, sizeof path, "archos%s", plugin);
300 pd = dlopen(path, RTLD_NOW);
301 if (!pd) {
302 snprintf(buf, sizeof buf, str(LANG_PLUGIN_CANT_OPEN), plugin);
303 splash(HZ*2, true, buf);
304 DEBUGF("dlopen(%s): %s\n",path,dlerror());
305 dlclose(pd);
306 return -1;
309 plugin_start = dlsym(pd, "plugin_start");
310 if (!plugin_start) {
311 plugin_start = dlsym(pd, "_plugin_start");
312 if (!plugin_start) {
313 splash(HZ*2, true, "Can't find entry point");
314 dlclose(pd);
315 return -1;
318 #else
319 fd = open(plugin, O_RDONLY);
320 if (fd < 0) {
321 snprintf(buf, sizeof buf, str(LANG_PLUGIN_CANT_OPEN), plugin);
322 splash(HZ*2, true, buf);
323 return fd;
326 plugin_start = (void*)&pluginbuf;
327 plugin_size = read(fd, plugin_start, PLUGIN_BUFFER_SIZE);
328 close(fd);
329 if (plugin_size < 0) {
330 /* read error */
331 snprintf(buf, sizeof buf, str(LANG_READ_FAILED), plugin);
332 splash(HZ*2, true, buf);
333 return -1;
335 if (plugin_size == 0) {
336 /* loaded a 0-byte plugin, implying it's not for this model */
337 splash(HZ*2, true, str(LANG_PLUGIN_WRONG_MODEL));
338 return -1;
340 #endif
342 plugin_loaded = true;
343 rc = plugin_start((struct plugin_api*) &rockbox_api, parameter);
344 /* explicitly casting the pointer here to avoid touching every plugin. */
346 button_clear_queue();
348 plugin_loaded = false;
350 switch (rc) {
351 case PLUGIN_OK:
352 break;
354 case PLUGIN_USB_CONNECTED:
355 return PLUGIN_USB_CONNECTED;
357 case PLUGIN_WRONG_API_VERSION:
358 splash(HZ*2, true, str(LANG_PLUGIN_WRONG_VERSION));
359 break;
361 case PLUGIN_WRONG_MODEL:
362 splash(HZ*2, true, str(LANG_PLUGIN_WRONG_MODEL));
363 break;
365 default:
366 splash(HZ*2, true, str(LANG_PLUGIN_ERROR));
367 break;
370 #ifdef SIMULATOR
371 dlclose(pd);
372 #endif
374 #ifdef HAVE_LCD_BITMAP
375 /* restore margins */
376 lcd_setmargins(xm,ym);
377 #endif
379 return PLUGIN_OK;
382 /* Returns a pointer to the portion of the plugin buffer that is not already
383 being used. If no plugin is loaded, returns the entire plugin buffer */
384 void* plugin_get_buffer(int* buffer_size)
386 int buffer_pos;
388 if (plugin_loaded)
390 if (plugin_size >= PLUGIN_BUFFER_SIZE)
391 return NULL;
393 *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size;
394 buffer_pos = plugin_size;
396 else
398 *buffer_size = PLUGIN_BUFFER_SIZE;
399 buffer_pos = 0;
402 return &pluginbuf[buffer_pos];
405 /* Returns a pointer to the mp3 buffer.
406 Playback gets stopped, to avoid conflicts. */
407 void* plugin_get_mp3_buffer(int* buffer_size)
409 #ifdef SIMULATOR
410 static unsigned char buf[1700*1024];
411 *buffer_size = sizeof(buf);
412 return buf;
413 #else
414 mpeg_stop();
415 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
416 *buffer_size = mp3end - mp3buf;
417 return mp3buf;
418 #endif
421 #ifndef SIMULATOR
422 /* Register a periodic time callback, called every "cycles" CPU clocks.
423 Note that this function will be called in interrupt context! */
424 int plugin_register_timer(int cycles, int prio, void (*timer_callback)(void))
426 int phi = 0; /* bits for the prescaler */
427 int prescale = 1;
429 while (cycles > 0x10000)
430 { /* work out the smallest prescaler that makes it fit */
431 phi++;
432 prescale *= 2;
433 cycles /= 2;
436 if (prescale > 8 || cycles == 0 || prio < 1 || prio > 15)
437 return 0; /* error, we can't do such period, bad argument */
439 and_b(~0x10, &TSTR); /* Stop the timer 4 */
440 and_b(~0x10, &TSNC); /* No synchronization */
441 and_b(~0x10, &TMDR); /* Operate normally */
443 pfn_timer = timer_callback; /* install 2nd level ISR */
445 and_b(~0x01, &TSR4);
446 TIER4 = 0xF9; /* Enable GRA match interrupt */
448 GRA4 = (unsigned short)(cycles - 1);
449 TCR4 = 0x20 | phi; /* clear at GRA match, set prescaler */
450 IPRD = (IPRD & 0xFF0F) | prio << 4; /* interrupt priority */
451 or_b(0x10, &TSTR); /* start timer 4 */
453 return cycles * prescale; /* return the actual period, in CPU clocks */
456 /* disable the user timer */
457 void plugin_unregister_timer(void)
459 and_b(~0x10, &TSTR); /* stop the timer 4 */
460 IPRD = (IPRD & 0xFF0F); /* disable interrupt */
461 pfn_timer = NULL;
464 /* interrupt handler for user timer */
465 #pragma interrupt
466 void IMIA4(void)
468 if (pfn_timer != NULL)
469 pfn_timer(); /* call the user timer function */
470 and_b(~0x01, &TSR4); /* clear the interrupt */
472 #endif /* #ifndef SIMULATOR */
474 /* The plugin wants to stay resident after leaving its main function, e.g.
475 runs from timer or own thread. The callback is registered to later
476 instruct it to free its resources before a new plugin gets loaded. */
477 void plugin_tsr(void (*exit_callback)(void))
479 pfn_tsr_exit = exit_callback; /* remember the callback for later */
483 static int plugin_test(int api_version, int model, int memsize)
485 if (api_version < PLUGIN_MIN_API_VERSION ||
486 api_version > PLUGIN_API_VERSION)
487 return PLUGIN_WRONG_API_VERSION;
489 if (model != MODEL)
490 return PLUGIN_WRONG_MODEL;
492 if (memsize != MEM)
493 return PLUGIN_WRONG_MODEL;
495 return PLUGIN_OK;