summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/hosted/maemo/maemo-thread.c220
-rw-r--r--firmware/target/hosted/maemo/maemo-thread.h36
-rw-r--r--firmware/target/hosted/maemo/pcm-gstreamer.c459
-rw-r--r--firmware/target/hosted/sdl/app/button-application.c16
-rw-r--r--firmware/target/hosted/sdl/button-sdl.c27
-rw-r--r--firmware/target/hosted/sdl/button-sdl.h2
-rw-r--r--firmware/target/hosted/sdl/lcd-bitmap.c14
-rw-r--r--firmware/target/hosted/sdl/system-sdl.c50
8 files changed, 822 insertions, 2 deletions
diff --git a/firmware/target/hosted/maemo/maemo-thread.c b/firmware/target/hosted/maemo/maemo-thread.c
new file mode 100644
index 0000000000..f655ed597e
--- /dev/null
+++ b/firmware/target/hosted/maemo/maemo-thread.c
@@ -0,0 +1,220 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 by Thomas Jarosch
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22
23#include <libhal.h>
24#include <libosso.h>
25#include <SDL_thread.h>
26
27#include "config.h"
28#include "system.h"
29#include "kernel.h"
30#include "thread.h"
31#include "power.h"
32#include "debug.h"
33#include "button.h"
34
35/* Battery status information */
36#define BME_UDI "/org/freedesktop/Hal/devices/bme"
37#define BATTERY_PERCENTAGE "battery.charge_level.percentage"
38#define BATTER_REMAINING_TIME "battery.remaining_time"
39
40/* Bluetooth headset support */
41#define BT_HEADSET_UDI "/org/freedesktop/Hal/devices/computer_logicaldev_input_1"
42
43GMainLoop *maemo_main_loop = NULL;
44osso_context_t *maemo_osso_ctx = NULL;
45
46volatile int maemo_display_on = 1;
47volatile int maemo_battery_level = 0;
48volatile int maemo_remaining_time_sec = 0;
49
50extern void send_battery_level_event(void);
51extern int last_sent_battery_level;
52extern int battery_percent;
53
54void display_status_callback(osso_display_state_t state, gpointer data)
55{
56 (void)data;
57
58 if (state == OSSO_DISPLAY_OFF)
59 maemo_display_on = 0;
60 else
61 maemo_display_on = 1;
62}
63
64
65void get_battery_values(LibHalContext *ctx)
66{
67 /* Get initial battery percentage and remaining time */
68 maemo_battery_level = libhal_device_get_property_int(
69 ctx, BME_UDI,
70 BATTERY_PERCENTAGE, NULL);
71
72 maemo_remaining_time_sec = libhal_device_get_property_int(
73 ctx, BME_UDI,
74 BATTER_REMAINING_TIME, NULL);
75
76 DEBUGF("[maemo] Battery percentage: %d, remaining_time_sec: %d\n", maemo_battery_level, maemo_remaining_time_sec);
77}
78
79static void on_battery_changed (LibHalContext *ctx,
80 const char *udi,
81 const char *key,
82 dbus_bool_t is_removed,
83 dbus_bool_t is_added)
84{
85 (void)is_removed;
86 (void)is_added;
87
88 if (!g_str_equal (udi, BME_UDI))
89 return;
90
91 if (!g_str_equal (key, BATTERY_PERCENTAGE) && !g_str_equal (key, BATTER_REMAINING_TIME))
92 return;
93
94 get_battery_values(ctx);
95}
96
97static void on_bt_button_pressed(LibHalContext *ctx,
98 const char *udi,
99 const char *condition_name,
100 const char *condition_detail)
101{
102 (void)ctx;
103
104 if (!g_str_equal (udi, BT_HEADSET_UDI) || !g_str_equal(condition_name, "ButtonPressed"))
105 return;
106
107 sim_enter_irq_handler();
108
109 if (g_str_equal(condition_detail, "play-cd") || g_str_equal(condition_detail, "pause-cd"))
110 queue_post(&button_queue, BUTTON_MULTIMEDIA_PLAYPAUSE, 0);
111 else if (g_str_equal(condition_detail, "stop-cd"))
112 queue_post(&button_queue, BUTTON_MULTIMEDIA_STOP, 0);
113 else if (g_str_equal(condition_detail, "next-song"))
114 queue_post(&button_queue, BUTTON_MULTIMEDIA_NEXT, 0);
115 else if (g_str_equal(condition_detail, "previous-song"))
116 queue_post(&button_queue, BUTTON_MULTIMEDIA_PREV, 0);
117 else if (g_str_equal(condition_detail, "fast-forward"))
118 queue_post(&button_queue, BUTTON_MULTIMEDIA_FFWD, 0);
119 else if (g_str_equal(condition_detail, "rewind"))
120 queue_post(&button_queue, BUTTON_MULTIMEDIA_REW, 0);
121
122 sim_exit_irq_handler();
123}
124
125int maemo_thread_func (void *wait_for_osso_startup)
126{
127 maemo_main_loop = g_main_loop_new (NULL, FALSE);
128
129 /* Register display callback */
130 maemo_osso_ctx = osso_initialize ("rockbox", "666", FALSE, NULL);
131 osso_hw_set_display_event_cb(maemo_osso_ctx, display_status_callback, NULL);
132
133 /* Register battery status callback */
134 LibHalContext *hal_ctx;
135 hal_ctx = libhal_ctx_new();
136
137 DBusConnection *system_bus = (DBusConnection*)osso_get_sys_dbus_connection(maemo_osso_ctx);
138 libhal_ctx_set_dbus_connection(hal_ctx, system_bus);
139
140 libhal_ctx_init(hal_ctx, NULL);
141 libhal_ctx_set_device_property_modified (hal_ctx, on_battery_changed);
142 libhal_device_add_property_watch (hal_ctx, BME_UDI, NULL);
143
144 /* Work around libhal API issue: We need to add a property watch
145 to get the condition change callback working */
146 libhal_device_add_property_watch (hal_ctx, BT_HEADSET_UDI, NULL);
147 libhal_ctx_set_device_condition(hal_ctx, on_bt_button_pressed);
148
149 get_battery_values(hal_ctx);
150
151 /* let system_init proceed */
152 SDL_SemPost((SDL_sem *)wait_for_osso_startup);
153
154 g_main_loop_run (maemo_main_loop);
155
156 /* Cleanup */
157 osso_deinitialize (maemo_osso_ctx);
158 libhal_device_remove_property_watch (hal_ctx, BT_HEADSET_UDI, NULL);
159 libhal_device_remove_property_watch (hal_ctx, BME_UDI, NULL);
160 libhal_ctx_shutdown (hal_ctx, NULL);
161 libhal_ctx_free(hal_ctx);
162
163 return 0;
164}
165
166/** Rockbox battery related functions */
167void battery_status_update(void)
168{
169 battery_percent = maemo_battery_level;
170 send_battery_level_event();
171}
172
173/* Returns true if any power input is connected - charging-capable
174 * or not. */
175bool power_input_present(void)
176{
177 return false;
178}
179
180unsigned battery_voltage(void)
181{
182 return 0;
183}
184
185/* Returns battery level in percent */
186int battery_level(void)
187{
188 battery_status_update();
189 return maemo_battery_level;
190}
191
192/* Return remaining battery time in minutes */
193int battery_time(void)
194{
195 battery_status_update();
196 return maemo_remaining_time_sec / 60;
197}
198
199bool battery_level_safe(void)
200{
201 return battery_level() >= 5;
202}
203
204/** Rockbox stubs */
205void set_poweroff_timeout(int timeout)
206{
207 (void)timeout;
208}
209
210void reset_poweroff_timer(void)
211{
212}
213
214void shutdown_hw(void)
215{
216}
217
218void cancel_shutdown(void)
219{
220}
diff --git a/firmware/target/hosted/maemo/maemo-thread.h b/firmware/target/hosted/maemo/maemo-thread.h
new file mode 100644
index 0000000000..a0996b4945
--- /dev/null
+++ b/firmware/target/hosted/maemo/maemo-thread.h
@@ -0,0 +1,36 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 by Thomas Jarosch
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __MAEMO_THREAD_H__
22#define __MAEMO_THREAD_H__
23
24#include <glib.h>
25#include <libosso.h>
26
27extern osso_context_t *maemo_osso_ctx;
28extern GMainLoop *maemo_main_loop;
29
30extern volatile int maemo_display_on;
31extern volatile int maemo_has_input_focus;
32
33int maemo_thread_func(void *unused);
34void pcm_shutdown_gstreamer(void);
35
36#endif
diff --git a/firmware/target/hosted/maemo/pcm-gstreamer.c b/firmware/target/hosted/maemo/pcm-gstreamer.c
new file mode 100644
index 0000000000..e3e40f0619
--- /dev/null
+++ b/firmware/target/hosted/maemo/pcm-gstreamer.c
@@ -0,0 +1,459 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 by Thomas Jarosch
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22
23#include "autoconf.h"
24
25#include <stdbool.h>
26#include "config.h"
27#include "debug.h"
28#include "sound.h"
29#include "audiohw.h"
30#include "system.h"
31#include "settings.h"
32#include "debug.h"
33
34#include "playback.h"
35#include "kernel.h"
36
37#include <SDL.h>
38#include <glib.h>
39#include <gst/gst.h>
40#include <gst/app/gstappsrc.h>
41#include <linux/types.h>
42
43/* Maemo5: N900 specific libplayback support */
44#include <libplayback/playback.h>
45#include <dbus/dbus-glib.h>
46#include <dbus/dbus-glib-lowlevel.h>
47#include "maemo-thread.h"
48
49#ifdef HAVE_RECORDING
50#include "audiohw.h"
51#ifdef HAVE_SPDIF_IN
52#include "spdif.h"
53#endif
54#endif
55
56#include "pcm.h"
57#include "pcm_sampr.h"
58
59/*#define LOGF_ENABLE*/
60#include "logf.h"
61
62#ifdef DEBUG
63#include <stdio.h>
64extern bool debug_audio;
65#endif
66
67#if CONFIG_CODEC == SWCODEC
68
69/* Declarations for libplayblack */
70pb_playback_t *playback = NULL;
71void playback_state_req_handler(pb_playback_t *pb,
72 enum pb_state_e req_state,
73 pb_req_t *ext_req,
74 void *data);
75void playback_state_req_callback(pb_playback_t *pb,
76 enum pb_state_e granted_state,
77 const char *reason,
78 pb_req_t *req,
79 void *data);
80bool playback_granted = false;
81
82/* Gstreamer related vars */
83GstCaps *gst_audio_caps = NULL;
84GstElement *gst_pipeline = NULL;
85GstElement *gst_appsrc = NULL;
86GstElement *gst_volume = NULL;
87GstElement *gst_pulsesink = NULL;
88GstBus *gst_bus = NULL;
89static int bus_watch_id = 0;
90GMainLoop *pcm_loop = NULL;
91
92static __u8* pcm_data = NULL;
93static size_t pcm_data_size = 0;
94
95static int inside_feed_data = 0;
96
97void pcm_play_lock(void)
98{
99}
100
101void pcm_play_unlock(void)
102{
103}
104
105void pcm_dma_apply_settings(void)
106{
107}
108
109void pcm_play_dma_start(const void *addr, size_t size)
110{
111 pcm_data = (__u8 *) addr;
112 pcm_data_size = size;
113
114 if (playback_granted)
115 {
116 /* Start playing now */
117 if (!inside_feed_data)
118 gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_PLAYING);
119 else
120 DEBUGF("ERROR: dma_start called while inside feed_data\n");
121 } else
122 {
123 /* N900: Request change to playing state */
124 pb_playback_req_state (playback,
125 PB_STATE_PLAY,
126 playback_state_req_callback,
127 NULL);
128 }
129}
130
131void pcm_play_dma_stop(void)
132{
133 if (inside_feed_data)
134 g_signal_emit_by_name (gst_appsrc, "end-of-stream", NULL);
135 else
136 gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
137}
138
139void pcm_play_dma_pause(bool pause)
140{
141 if (inside_feed_data)
142 {
143 if (pause)
144 g_signal_emit_by_name (gst_appsrc, "end-of-stream", NULL);
145 else
146 DEBUGF("ERROR: Called dma_pause(0) while inside feed_data\n");
147 } else
148 {
149 if (pause)
150 gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
151 else
152 gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_PLAYING);
153 }
154}
155
156size_t pcm_get_bytes_waiting(void)
157{
158 return pcm_data_size;
159}
160
161static void feed_data(GstElement * appsrc, guint size_hint, void *unused)
162{
163 (void)size_hint;
164 (void)unused;
165
166 /* Make sure we don't trigger a gst_element_set_state() call
167 from inside gstreamer's stream thread as it will deadlock */
168 inside_feed_data = 1;
169
170 pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
171
172 if (pcm_data_size != 0)
173 {
174 GstBuffer *buffer = gst_buffer_new ();
175 GstFlowReturn ret;
176
177 GST_BUFFER_DATA (buffer) = pcm_data;
178 GST_BUFFER_SIZE (buffer) = pcm_data_size;
179
180 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
181 gst_buffer_unref (buffer);
182
183 if (ret != 0)
184 DEBUGF("push-buffer error result: %d\n", ret);
185 } else
186 {
187 DEBUGF("feed_data: No Data.\n");
188 g_signal_emit_by_name (appsrc, "end-of-stream", NULL);
189 }
190
191 inside_feed_data = 0;
192}
193
194const void * pcm_play_dma_get_peak_buffer(int *count)
195{
196 uintptr_t addr = (uintptr_t)pcm_data;
197 *count = pcm_data_size / 4;
198 return (void *)((addr + 2) & ~3);
199}
200
201
202static gboolean
203gst_bus_message (GstBus * bus, GstMessage * message, void *unused)
204{
205 (void)bus;
206 (void)unused;
207
208 DEBUGF(" [gst] got BUS message %s\n",
209 gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
210
211 switch (GST_MESSAGE_TYPE (message)) {
212 case GST_MESSAGE_ERROR:
213 {
214 GError *err;
215 gchar *debug;
216 gst_message_parse_error (message, &err, &debug);
217
218 DEBUGF("[gst] Received error: Src: %s, msg: %s\n", GST_MESSAGE_SRC_NAME(message), err->message);
219
220 g_error_free (err);
221 g_free (debug);
222 }
223
224 g_main_loop_quit (pcm_loop);
225 break;
226 case GST_MESSAGE_EOS:
227 gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
228 break;
229 case GST_MESSAGE_STATE_CHANGED:
230 {
231 GstState old_state, new_state;
232
233 gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
234 DEBUGF("[gst] Element %s changed state from %s to %s.\n",
235 GST_MESSAGE_SRC_NAME(message),
236 gst_element_state_get_name (old_state),
237 gst_element_state_get_name (new_state));
238 break;
239 }
240 default:
241 break;
242 }
243
244 return TRUE;
245}
246
247void maemo_configure_appsrc(void)
248{
249 /* Block push-buffer until there is enough room */
250 g_object_set (G_OBJECT(gst_appsrc), "block", TRUE, NULL);
251
252 g_object_set(G_OBJECT(gst_appsrc), "format", GST_FORMAT_BYTES, NULL);
253
254 gst_audio_caps = gst_caps_new_simple("audio/x-raw-int", "width", G_TYPE_INT, (gint)16, "depth", G_TYPE_INT, (gint)16, "channels" ,G_TYPE_INT, (gint)2,
255 "signed",G_TYPE_BOOLEAN,1,
256 "rate",G_TYPE_INT,44100,"endianness",G_TYPE_INT,(gint)1234,NULL);
257
258 g_object_set (G_OBJECT(gst_appsrc), "caps", gst_audio_caps, NULL);
259
260 gst_app_src_set_stream_type(GST_APP_SRC(gst_appsrc),
261 GST_APP_STREAM_TYPE_STREAM);
262
263 /* configure the appsrc, we will push data into the appsrc from the
264 * mainloop. */
265 g_signal_connect (gst_appsrc, "need-data", G_CALLBACK (feed_data), NULL);
266}
267
268/* Init libplayback: Grant access rights to
269 play audio while the phone is in silent mode */
270void maemo_init_libplayback(void)
271{
272 DBusConnection *session_bus_raw = (DBusConnection*)osso_get_dbus_connection(maemo_osso_ctx);
273
274 playback = pb_playback_new_2(session_bus_raw,
275 PB_CLASS_MEDIA,
276 PB_FLAG_AUDIO,
277 PB_STATE_STOP,
278 playback_state_req_handler,
279 NULL);
280
281 pb_playback_set_stream(playback, "Playback Stream");
282}
283
284/**
285 * Gets called by the policy framework if an important
286 * event arrives: Incoming calls etc.
287 */
288void maemo_tell_rockbox_to_stop_audio(void)
289{
290 sim_enter_irq_handler();
291 queue_broadcast(SYS_CALL_INCOMING, 0);
292 sim_exit_irq_handler();
293
294 osso_system_note_infoprint(maemo_osso_ctx, "Stopping rockbox playback", NULL);
295}
296
297void playback_state_req_handler(pb_playback_t *pb,
298 enum pb_state_e req_state,
299 pb_req_t *ext_req,
300 void *data)
301{
302 (void)pb;
303 (void)ext_req;
304 (void)data;
305
306 DEBUGF("External state change request: state: %s, data: %p\n",
307 pb_state_to_string(req_state), data);
308
309 if (req_state == PB_STATE_STOP && playback_granted)
310 {
311 DEBUGF("Stopping playback, might be an incoming call\n");
312
313 playback_granted = false;
314 maemo_tell_rockbox_to_stop_audio();
315 }
316}
317
318/**
319 * Callback for our own state change request.
320 */
321void playback_state_req_callback(pb_playback_t *pb, enum pb_state_e granted_state, const char *reason, pb_req_t *req, void *data)
322{
323 (void)data;
324 (void)reason;
325
326 DEBUGF("State request callback: granted_state: %s, reason: %s\n",
327 pb_state_to_string(granted_state), reason);
328
329 /* We are allowed to play audio */
330 if (granted_state == PB_STATE_PLAY)
331 {
332 DEBUGF("Playback granted. Start playing...\n");
333 playback_granted = true;
334 if (!inside_feed_data)
335 gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_PLAYING);
336 } else
337 {
338 DEBUGF("Can't start playing. Throwing away play request\n");
339
340 playback_granted = false;
341 maemo_tell_rockbox_to_stop_audio();
342 }
343
344 pb_playback_req_completed(pb, req);
345}
346
347void pcm_play_dma_init(void)
348{
349 maemo_init_libplayback();
350
351 GMainContext *ctx = g_main_loop_get_context(maemo_main_loop);
352 pcm_loop = g_main_loop_new (ctx, true);
353
354 gst_init (NULL, NULL);
355
356 gst_pipeline = gst_pipeline_new ("rockbox");
357
358 gst_appsrc = gst_element_factory_make ("appsrc", NULL);
359 gst_volume = gst_element_factory_make ("volume", NULL);
360 gst_pulsesink = gst_element_factory_make ("pulsesink", NULL);
361
362 /* Connect elements */
363 gst_bin_add_many (GST_BIN (gst_pipeline),
364 gst_appsrc, gst_volume, gst_pulsesink, NULL);
365 gst_element_link_many (gst_appsrc, gst_volume, gst_pulsesink, NULL);
366
367 /* Connect to gstreamer bus of the pipeline */
368 gst_bus = gst_pipeline_get_bus (GST_PIPELINE (gst_pipeline));
369 bus_watch_id = gst_bus_add_watch (gst_bus, (GstBusFunc) gst_bus_message, NULL);
370
371 maemo_configure_appsrc();
372}
373
374void pcm_shutdown_gstreamer(void)
375{
376 /* Try to stop playing */
377 gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
378
379 /* Make sure we are really stopped. This should return almost instantly,
380 so we wait up to ten seconds and just continue otherwise */
381 gst_element_get_state (GST_ELEMENT(gst_pipeline), NULL, NULL, GST_SECOND * 10);
382
383 g_source_remove (bus_watch_id);
384 g_object_unref(gst_bus);
385 gst_bus = NULL;
386
387 gst_object_unref (gst_pipeline);
388 gst_pipeline = NULL;
389
390 /* Shutdown libplayback and gstreamer */
391 pb_playback_destroy (playback);
392 gst_deinit();
393
394 g_main_loop_quit(pcm_loop);
395 g_main_loop_unref (pcm_loop);
396}
397
398void pcm_postinit(void)
399{
400}
401
402void pcm_set_mixer_volume(int volume)
403{
404 /* gstreamer volume range is from 0.00 to 1.00 */
405 gdouble gst_vol = (gdouble)(volume - VOLUME_MIN) / (gdouble)VOLUME_RANGE;
406
407 g_object_set (G_OBJECT(gst_volume), "volume", gst_vol, NULL);
408}
409
410
411#ifdef HAVE_RECORDING
412void pcm_rec_lock(void)
413{
414}
415
416void pcm_rec_unlock(void)
417{
418}
419
420void pcm_rec_dma_init(void)
421{
422}
423
424void pcm_rec_dma_close(void)
425{
426}
427
428void pcm_rec_dma_start(void *start, size_t size)
429{
430 (void)start;
431 (void)size;
432}
433
434void pcm_rec_dma_stop(void)
435{
436}
437
438const void * pcm_rec_dma_get_peak_buffer(void)
439{
440 return NULL;
441}
442
443void audiohw_set_recvol(int left, int right, int type)
444{
445 (void)left;
446 (void)right;
447 (void)type;
448}
449
450#ifdef HAVE_SPDIF_IN
451unsigned long spdif_measure_frequency(void)
452{
453 return 0;
454}
455#endif
456
457#endif /* HAVE_RECORDING */
458
459#endif /* CONFIG_CODEC == SWCODEC */
diff --git a/firmware/target/hosted/sdl/app/button-application.c b/firmware/target/hosted/sdl/app/button-application.c
index 2ad09dc373..72f4a1770d 100644
--- a/firmware/target/hosted/sdl/app/button-application.c
+++ b/firmware/target/hosted/sdl/app/button-application.c
@@ -30,6 +30,9 @@ int key_to_button(int keyboard_key)
30 int new_btn = BUTTON_NONE; 30 int new_btn = BUTTON_NONE;
31 switch (keyboard_key) 31 switch (keyboard_key)
32 { 32 {
33#if (CONFIG_PLATFORM & PLATFORM_MAEMO4)
34 case SDLK_ESCAPE:
35#endif
33 case SDLK_KP7: 36 case SDLK_KP7:
34 new_btn = BUTTON_TOPLEFT; 37 new_btn = BUTTON_TOPLEFT;
35 break; 38 break;
@@ -37,6 +40,9 @@ int key_to_button(int keyboard_key)
37 case SDLK_UP: 40 case SDLK_UP:
38 new_btn = BUTTON_TOPMIDDLE; 41 new_btn = BUTTON_TOPMIDDLE;
39 break; 42 break;
43#if (CONFIG_PLATFORM & PLATFORM_MAEMO4)
44 case SDLK_F7:
45#endif
40 case SDLK_KP9: 46 case SDLK_KP9:
41 new_btn = BUTTON_TOPRIGHT; 47 new_btn = BUTTON_TOPRIGHT;
42 break; 48 break;
@@ -44,6 +50,10 @@ int key_to_button(int keyboard_key)
44 case SDLK_LEFT: 50 case SDLK_LEFT:
45 new_btn = BUTTON_MIDLEFT; 51 new_btn = BUTTON_MIDLEFT;
46 break; 52 break;
53#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
54 case SDLK_RETURN:
55 case SDLK_KP_ENTER:
56#endif
47 case SDLK_KP5: 57 case SDLK_KP5:
48 new_btn = BUTTON_CENTER; 58 new_btn = BUTTON_CENTER;
49 break; 59 break;
@@ -51,6 +61,9 @@ int key_to_button(int keyboard_key)
51 case SDLK_RIGHT: 61 case SDLK_RIGHT:
52 new_btn = BUTTON_MIDRIGHT; 62 new_btn = BUTTON_MIDRIGHT;
53 break; 63 break;
64#if (CONFIG_PLATFORM & PLATFORM_MAEMO4)
65 case SDLK_F6:
66#endif
54 case SDLK_KP1: 67 case SDLK_KP1:
55 new_btn = BUTTON_BOTTOMLEFT; 68 new_btn = BUTTON_BOTTOMLEFT;
56 break; 69 break;
@@ -58,6 +71,9 @@ int key_to_button(int keyboard_key)
58 case SDLK_DOWN: 71 case SDLK_DOWN:
59 new_btn = BUTTON_BOTTOMMIDDLE; 72 new_btn = BUTTON_BOTTOMMIDDLE;
60 break; 73 break;
74#if (CONFIG_PLATFORM & PLATFORM_MAEMO4)
75 case SDLK_F8:
76#endif
61 case SDLK_KP3: 77 case SDLK_KP3:
62 new_btn = BUTTON_BOTTOMRIGHT; 78 new_btn = BUTTON_BOTTOMRIGHT;
63 break; 79 break;
diff --git a/firmware/target/hosted/sdl/button-sdl.c b/firmware/target/hosted/sdl/button-sdl.c
index 3321a01bc6..25dad09341 100644
--- a/firmware/target/hosted/sdl/button-sdl.c
+++ b/firmware/target/hosted/sdl/button-sdl.c
@@ -67,6 +67,8 @@ struct event_queue button_queue;
67 67
68static int btn = 0; /* Hopefully keeps track of currently pressed keys... */ 68static int btn = 0; /* Hopefully keeps track of currently pressed keys... */
69 69
70int sdl_app_has_input_focus = 1;
71
70#ifdef HAS_BUTTON_HOLD 72#ifdef HAS_BUTTON_HOLD
71bool hold_button_state = false; 73bool hold_button_state = false;
72bool button_hold(void) { 74bool button_hold(void) {
@@ -209,11 +211,34 @@ static void mouse_event(SDL_MouseButtonEvent *event, bool button_up)
209 211
210static bool event_handler(SDL_Event *event) 212static bool event_handler(SDL_Event *event)
211{ 213{
214 SDLKey ev_key;
215
212 switch(event->type) 216 switch(event->type)
213 { 217 {
218 case SDL_ACTIVEEVENT:
219 if (event->active.state & SDL_APPINPUTFOCUS)
220 {
221 if (event->active.gain == 1)
222 sdl_app_has_input_focus = 1;
223 else
224 sdl_app_has_input_focus = 0;
225 }
226 break;
214 case SDL_KEYDOWN: 227 case SDL_KEYDOWN:
215 case SDL_KEYUP: 228 case SDL_KEYUP:
216 button_event(event->key.keysym.sym, event->type == SDL_KEYDOWN); 229 ev_key = event->key.keysym.sym;
230#if (CONFIG_PLATFORM & PLATFORM_MAEMO5)
231 /* N900 with shared up/down cursor mapping. Seen on the German,
232 Finnish, Italian, French and Russian version. Probably more. */
233 if (event->key.keysym.mod & KMOD_MODE)
234 {
235 if (ev_key == SDLK_LEFT)
236 ev_key = SDLK_UP;
237 else if (ev_key == SDLK_RIGHT)
238 ev_key = SDLK_DOWN;
239 }
240#endif
241 button_event(ev_key, event->type == SDL_KEYDOWN);
217 break; 242 break;
218#ifdef HAVE_TOUCHSCREEN 243#ifdef HAVE_TOUCHSCREEN
219 case SDL_MOUSEMOTION: 244 case SDL_MOUSEMOTION:
diff --git a/firmware/target/hosted/sdl/button-sdl.h b/firmware/target/hosted/sdl/button-sdl.h
index e6fcb9ea83..6b7f632eaf 100644
--- a/firmware/target/hosted/sdl/button-sdl.h
+++ b/firmware/target/hosted/sdl/button-sdl.h
@@ -26,6 +26,8 @@
26#include <stdbool.h> 26#include <stdbool.h>
27#include "config.h" 27#include "config.h"
28 28
29extern int sdl_app_has_input_focus;
30
29bool button_hold(void); 31bool button_hold(void);
30#undef button_init_device 32#undef button_init_device
31void button_init_device(void); 33void button_init_device(void);
diff --git a/firmware/target/hosted/sdl/lcd-bitmap.c b/firmware/target/hosted/sdl/lcd-bitmap.c
index 7058b26e8c..4c296924af 100644
--- a/firmware/target/hosted/sdl/lcd-bitmap.c
+++ b/firmware/target/hosted/sdl/lcd-bitmap.c
@@ -22,8 +22,12 @@
22#include "debug.h" 22#include "debug.h"
23#include "sim-ui-defines.h" 23#include "sim-ui-defines.h"
24#include "system.h" 24#include "system.h"
25#include "button-sdl.h"
25#include "lcd-sdl.h" 26#include "lcd-sdl.h"
26#include "screendump.h" 27#include "screendump.h"
28#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
29#include "maemo-thread.h"
30#endif
27 31
28SDL_Surface* lcd_surface; 32SDL_Surface* lcd_surface;
29 33
@@ -123,6 +127,16 @@ void lcd_update(void)
123 127
124void lcd_update_rect(int x_start, int y_start, int width, int height) 128void lcd_update_rect(int x_start, int y_start, int width, int height)
125{ 129{
130#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
131 /* Don't update display if not shown */
132 if (!maemo_display_on)
133 return;
134
135 /* Don't update if we don't have the input focus */
136 if (!sdl_app_has_input_focus)
137 return;
138#endif
139
126 sdl_update_rect(lcd_surface, x_start, y_start, width, height, 140 sdl_update_rect(lcd_surface, x_start, y_start, width, height,
127 LCD_WIDTH, LCD_HEIGHT, get_lcd_pixel); 141 LCD_WIDTH, LCD_HEIGHT, get_lcd_pixel);
128 sdl_gui_update(lcd_surface, x_start, y_start, width, 142 sdl_gui_update(lcd_surface, x_start, y_start, width,
diff --git a/firmware/target/hosted/sdl/system-sdl.c b/firmware/target/hosted/sdl/system-sdl.c
index b900d38b43..9ea25c1014 100644
--- a/firmware/target/hosted/sdl/system-sdl.c
+++ b/firmware/target/hosted/sdl/system-sdl.c
@@ -40,6 +40,13 @@
40#include "panic.h" 40#include "panic.h"
41#include "debug.h" 41#include "debug.h"
42 42
43#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
44#include <glib.h>
45#include <glib-object.h>
46#include "maemo-thread.h"
47
48#endif
49
43SDL_Surface *gui_surface; 50SDL_Surface *gui_surface;
44 51
45bool background = true; /* use backgrounds by default */ 52bool background = true; /* use backgrounds by default */
@@ -82,9 +89,13 @@ static int sdl_event_thread(void * param)
82{ 89{
83 SDL_InitSubSystem(SDL_INIT_VIDEO); 90 SDL_InitSubSystem(SDL_INIT_VIDEO);
84 91
92#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
93 SDL_sem *wait_for_maemo_startup;
94#endif
85 SDL_Surface *picture_surface = NULL; 95 SDL_Surface *picture_surface = NULL;
86 int width, height; 96 int width, height;
87 int depth; 97 int depth;
98 Uint32 flags;
88 99
89 /* Try and load the background image. If it fails go without */ 100 /* Try and load the background image. If it fails go without */
90 if (background) { 101 if (background) {
@@ -121,10 +132,21 @@ static int sdl_event_thread(void * param)
121 if (depth < 8) 132 if (depth < 8)
122 depth = 16; 133 depth = 16;
123 134
124 if ((gui_surface = SDL_SetVideoMode(width * display_zoom, height * display_zoom, depth, SDL_HWSURFACE|SDL_DOUBLEBUF)) == NULL) { 135 flags = SDL_HWSURFACE|SDL_DOUBLEBUF;
136#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
137 /* Fullscreen mode for maemo app */
138 flags |= SDL_FULLSCREEN;
139#endif
140
141 if ((gui_surface = SDL_SetVideoMode(width * display_zoom, height * display_zoom, depth, flags)) == NULL) {
125 panicf("%s", SDL_GetError()); 142 panicf("%s", SDL_GetError());
126 } 143 }
127 144
145#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
146 /* Hide mouse cursor on real touchscreen device */
147 SDL_ShowCursor(SDL_DISABLE);
148#endif
149
128 SDL_WM_SetCaption(UI_TITLE, NULL); 150 SDL_WM_SetCaption(UI_TITLE, NULL);
129 151
130 if (background && picture_surface != NULL) 152 if (background && picture_surface != NULL)
@@ -133,10 +155,30 @@ static int sdl_event_thread(void * param)
133 /* let system_init proceed */ 155 /* let system_init proceed */
134 SDL_SemPost((SDL_sem *)param); 156 SDL_SemPost((SDL_sem *)param);
135 157
158#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
159 /* Start maemo thread: Listen to display on/off events and battery monitoring */
160 wait_for_maemo_startup = SDL_CreateSemaphore(0); /* 0-count so it blocks */
161 SDL_Thread *maemo_thread = SDL_CreateThread(maemo_thread_func, wait_for_maemo_startup);
162#endif
163
136 /* 164 /*
137 * finally enter the button loop */ 165 * finally enter the button loop */
138 gui_message_loop(); 166 gui_message_loop();
139 167
168#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
169 /* Ensure maemo thread is up and running */
170 SDL_SemWait(wait_for_maemo_startup);
171 SDL_DestroySemaphore(wait_for_maemo_startup);
172
173#if (CONFIG_PLATFORM & PLATFORM_MAEMO5)
174 pcm_shutdown_gstreamer();
175#endif
176
177 g_main_loop_quit (maemo_main_loop);
178 g_main_loop_unref(maemo_main_loop);
179 SDL_WaitThread(maemo_thread, NULL);
180#endif
181
140 if(picture_surface) 182 if(picture_surface)
141 SDL_FreeSurface(picture_surface); 183 SDL_FreeSurface(picture_surface);
142 184
@@ -161,6 +203,12 @@ void system_init(void)
161{ 203{
162 SDL_sem *s; 204 SDL_sem *s;
163 205
206#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
207 /* Make glib thread safe */
208 g_thread_init(NULL);
209 g_type_init();
210#endif
211
164 if (SDL_Init(SDL_INIT_TIMER)) 212 if (SDL_Init(SDL_INIT_TIMER))
165 panicf("%s", SDL_GetError()); 213 panicf("%s", SDL_GetError());
166 214