summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUdo Schläpfer <rockbox-2014.10@desktopwarrior.net>2015-02-02 21:00:14 +0100
committerUdo Schläpfer <rockbox-2014.10@desktopwarrior.net>2015-02-02 21:01:00 +0100
commitcef17e3d59ad93f766e8ee23b1610540a33dfe5e (patch)
treea2d615ae1ada0a586a1b7cf33737d0436fdb4300
parenta312ca1c5002f70c7e8cf9fcb802bbf7689dfca2 (diff)
downloadrockbox-cef17e3d59ad93f766e8ee23b1610540a33dfe5e.tar.gz
rockbox-cef17e3d59ad93f766e8ee23b1610540a33dfe5e.zip
iBasso DX50/DX90: Rockbox loader, replacement for original firmware MangoPlayer.
This loader is needed to use Rockbox on iBasso DX50/DX90 devices. It replaces /system/bin/MangoPlayer. It expects - the original firmware MangoPlayer as /system/bin/MangoPlayer_original - the chooser.bmp file as /system/chooser.bmp - the rbmissing.bmp file as /system/rbmissing.bmp - the usb.bmp file as /system/usb.bmp - Rockbox in /mnt/sdcard/.rockbox/ (internal device storage accessable via USB) On first boot or if the device is booted with the hold switch engaged (upper, locked position) this loader will let the user choose between Rockbox and the orginal firmware MangoPlayer. It remembers the last choice and will start the choosen player an following boots. In the chooser screen - the device can be powered off with a power button long press. - Rockbox can be startet with the "Next/Fast Forward" button or by touching the right part of the touchscreen. - the orginal firmware MangoPlayer can be startet with the "Previous/Rewind" button or by touching the left part of the touchscreen. If Rockbox can not be found/executed than a "Rockbox is missing" screen will be shown and the orginal firmware MangoPlayer will be started after 30 seconds. This loader will (try to) restart Rockbox or the orginal firmware MangoPlayer if something unexpected happens. This loader can be installed via a customized firmware image (update.img) or manually via the Android Debug Bridge (if you get adbd started on the device). This is a rewrite and code clean up of the original submission, eliminating the need for a custom Android Vold. This loader "knows", when Rockbox has exited due to a USB mass storage connection remounting /mnt/sdcard and acts accordingly, displaying a "USB connection" screen while waiting to restart Rockbox. Change-Id: I2698e173437f9c7aa1ff40649a290220e2ee0439
-rw-r--r--rbutil/ibassoboot/jni/Android.mk8
-rw-r--r--rbutil/ibassoboot/jni/ibassodualboot.c906
-rw-r--r--rbutil/ibassoboot/jni/rbmissing.bmpbin0 -> 230454 bytes
-rw-r--r--rbutil/ibassoboot/jni/usb.bmpbin0 -> 230454 bytes
4 files changed, 627 insertions, 287 deletions
diff --git a/rbutil/ibassoboot/jni/Android.mk b/rbutil/ibassoboot/jni/Android.mk
index 1d1566d8c0..9cd667c5b9 100644
--- a/rbutil/ibassoboot/jni/Android.mk
+++ b/rbutil/ibassoboot/jni/Android.mk
@@ -3,4 +3,12 @@ include $(CLEAR_VARS)
3 3
4LOCAL_MODULE := MangoPlayer 4LOCAL_MODULE := MangoPlayer
5LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c 5LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c
6
7TARGET_ARCH=arm
8TARGET_PLATFORM=android-14
9TARGET_ARCH_ABI=armeabi
10
11#LOCAL_CFLAGS := -DDEBUG
12#LOCAL_LDLIBS := -llog
13
6include $(BUILD_EXECUTABLE) 14include $(BUILD_EXECUTABLE)
diff --git a/rbutil/ibassoboot/jni/ibassodualboot.c b/rbutil/ibassoboot/jni/ibassodualboot.c
index 3f20bbeecf..0458ff1b71 100644
--- a/rbutil/ibassoboot/jni/ibassodualboot.c
+++ b/rbutil/ibassoboot/jni/ibassodualboot.c
@@ -1,13 +1,15 @@
1/*************************************************************************** 1/***************************************************************************
2 * __________ __ ___. 2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$
9 * 8 *
10 * Copyright (C) 2014 by Ilia Sergachev 9 * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
10 * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
11 * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
12 * Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
11 * 13 *
12 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -19,421 +21,751 @@
19 * 21 *
20 ****************************************************************************/ 22 ****************************************************************************/
21 23
24
22#include <dirent.h> 25#include <dirent.h>
23#include <errno.h>
24#include <fcntl.h> 26#include <fcntl.h>
25 27#include <pthread.h>
28#include <stdbool.h>
29#include <stdlib.h>
30#include <unistd.h>
26#include <linux/fb.h> 31#include <linux/fb.h>
27#include <linux/input.h> 32#include <linux/input.h>
28#include <linux/reboot.h> 33#include <sys/mman.h>
34#include <sys/poll.h>
35#include <sys/reboot.h>
36#include <sys/socket.h>
37#include <sys/un.h>
38#include <sys/wait.h>
29 39
30#include <stdbool.h> 40#include "qdbmp.h"
31#include <string.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <stdlib.h>
35 41
36#include <time.h>
37 42
38#include <sys/limits.h> 43/*- Android logcat ------------------------------------------------------------------------------*/
39#include <sys/mman.h>
40#include <sys/inotify.h>
41#include <sys/ioctl.h>
42#include <sys/poll.h>
43#include <sys/stat.h>
44#include <sys/time.h>
45#include <sys/types.h>
46 44
47#include <unistd.h>
48 45
49#include "qdbmp.h" 46#ifdef DEBUG
47#include <android/log.h>
48
49
50static const char log_tag[] = "Rockbox Boot";
50 51
51 52
52#define MIN_TIME 1395606821 53void debugf(const char *fmt, ...)
53#define TIME_FILE "/data/time_store" 54{
54#define TIME_CHECK_PERIOD 60 /* seconds */ 55 va_list ap;
55#define VOLD_LINK "/data/vold" 56 va_start(ap, fmt);
56#define PLAYER_FILE "/data/chosen_player" 57 __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, fmt, ap);
57#define NOASK_FLAG "/data/no_ask_once" 58 va_end(ap);
58#define POLL_MS 10 59}
60
61
62void ldebugf(const char* file, int line, const char *fmt, ...)
63{
64 va_list ap;
65 /* 13: 5 literal chars and 8 chars for the line number. */
66 char buf[strlen(file) + strlen(fmt) + 13];
67 snprintf(buf, sizeof(buf), "%s (%d): %s", file, line, fmt);
68 va_start(ap, fmt);
69 __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, buf, ap);
70 va_end(ap);
71}
72
73
74void debug_trace(const char* function)
75{
76 static const char trace_tag[] = "TRACE: ";
77 char msg[strlen(trace_tag) + strlen(function) + 1];
78 snprintf(msg, sizeof(msg), "%s%s", trace_tag, function);
79 __android_log_write(ANDROID_LOG_DEBUG, log_tag, msg);
80}
81
82
83#define DEBUGF debugf
84#define TRACE debug_trace(__func__)
85#else
86#define DEBUGF(...)
87#define TRACE
88#endif /* DEBUG */
59 89
60 90
61#define KEYCODE_HEADPHONES 114 91/*- Vold monitor --------------------------------------------------------------------------------*/
62#define KEYCODE_HOLD 115
63#define KEYCODE_PWR 116
64#define KEYCODE_PWR_LONG 117
65#define KEYCODE_SD 143
66#define KEYCODE_VOLPLUS 158
67#define KEYCODE_VOLMINUS 159
68#define KEYCODE_PREV 160
69#define KEYCODE_NEXT 162
70#define KEYCODE_PLAY 161
71 92
72#define KEY_HOLD_OFF 16
73 93
74void checktime() 94/*
95 Without this socket iBasso Vold will not start.
96 iBasso Vold uses this to send status messages about storage devices.
97*/
98static const char VOLD_MONITOR_SOCKET_NAME[] = "UNIX_domain";
99static int _vold_monitor_socket_fd = -1;
100
101
102static void vold_monitor_open_socket(void)
75{ 103{
76 time_t t_stored=0, t_current=time(NULL); 104 TRACE;
105
106 unlink(VOLD_MONITOR_SOCKET_NAME);
107
108 _vold_monitor_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
77 109
78 FILE *f = fopen(TIME_FILE, "r"); 110 if(_vold_monitor_socket_fd < 0)
79 if(f!=NULL)
80 { 111 {
81 fscanf(f, "%ld", &t_stored); 112 _vold_monitor_socket_fd = -1;
82 fclose(f); 113 return;
83 } 114 }
84 115
85 printf("stored time: %ld, current time: %ld\n", t_stored, t_current); 116 struct sockaddr_un addr;
86 117 memset(&addr, 0, sizeof(addr));
87 if(t_stored<MIN_TIME) 118 addr.sun_family = AF_UNIX;
88 t_stored=MIN_TIME; 119 strncpy(addr.sun_path, VOLD_MONITOR_SOCKET_NAME, sizeof(addr.sun_path) - 1);
89 120
90 if(t_stored<t_current) 121 if(bind(_vold_monitor_socket_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
91 { 122 {
92 f = fopen(TIME_FILE, "w"); 123 close(_vold_monitor_socket_fd);
93 fprintf(f, "%ld", t_current); 124 unlink(VOLD_MONITOR_SOCKET_NAME);
94 fclose(f); 125 _vold_monitor_socket_fd = -1;
126 return;
95 } 127 }
96 else 128
129 if(listen(_vold_monitor_socket_fd, 1) < 0)
97 { 130 {
98 t_stored += TIME_CHECK_PERIOD; 131 close(_vold_monitor_socket_fd);
99 struct tm *t = localtime(&t_stored); 132 unlink(VOLD_MONITOR_SOCKET_NAME);
100 struct timeval tv = {mktime(t), 0}; 133 _vold_monitor_socket_fd = -1;
101 settimeofday(&tv, 0); 134 return;
102 } 135 }
103} 136}
104 137
105 138
106static struct pollfd *ufds; 139/*
107static char **device_names; 140 bionic does not have pthread_cancel.
108static int nfds; 141 0: Vold monitor thread stopped/ending.
142 1: Vold monitor thread started/running.
143*/
144static volatile sig_atomic_t _vold_monitor_active = 0;
145
146
147/* true: sdcard not mounted. */
148static bool _sdcard_not_mounted = true;
149
150
151/* Mutex for sdcard mounted flag. */
152static pthread_mutex_t _sdcard_mount_mtx = PTHREAD_MUTEX_INITIALIZER;
109 153
110 154
155/* Signal condition for sdcard mounted flag. */
156static pthread_cond_t _sdcard_mount_cond = PTHREAD_COND_INITIALIZER;
111 157
112static int open_device(const char *device, int print_flags) 158
159static void* vold_monitor_run(void* nothing)
113{ 160{
114 int fd; 161 _vold_monitor_active = 1;
115 struct pollfd *new_ufds;
116 char **new_device_names;
117 162
118 fd = open(device, O_RDWR); 163 (void) nothing;
119 if(fd < 0) 164
120 { 165 DEBUGF("DEBUG %s: Thread start.", __func__);
121 fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
122 return -1;
123 }
124 166
125 new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); 167 vold_monitor_open_socket();
126 if(new_ufds == NULL) 168 if(_vold_monitor_socket_fd < 0)
127 { 169 {
128 fprintf(stderr, "out of memory\n"); 170 DEBUGF("ERROR %s: Thread end: No socket.", __func__);
129 return -1; 171
172 _vold_monitor_active = 0;
173 return 0;
130 } 174 }
131 ufds = new_ufds; 175
132 new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); 176 struct pollfd fds[1];
133 if(new_device_names == NULL) 177 fds[0].fd = _vold_monitor_socket_fd;
178 fds[0].events = POLLIN;
179
180 while(_vold_monitor_active == 1)
134 { 181 {
135 fprintf(stderr, "out of memory\n"); 182 poll(fds, 1, 10);
136 return -1; 183 if(! (fds[0].revents & POLLIN))
184 {
185 continue;
186 }
187
188 int socket_fd = accept(_vold_monitor_socket_fd, NULL, NULL);
189
190 if(socket_fd < 0)
191 {
192 DEBUGF("ERROR %s: accept failed.", __func__);
193
194 continue;
195 }
196
197 while(true)
198 {
199 char msg[1024];
200 memset(msg, 0, sizeof(msg));
201 int length = read(socket_fd, msg, sizeof(msg));
202
203 if(length <= 0)
204 {
205 close(socket_fd);
206 break;
207 }
208
209 DEBUGF("DEBUG %s: msg: %s", __func__, msg);
210
211 if(strcmp(msg, "Volume flash /mnt/sdcard state changed from 3 (Checking) to 4 (Mounted)") == 0)
212 {
213 pthread_mutex_lock(&_sdcard_mount_mtx);
214 _sdcard_not_mounted = false;
215 pthread_cond_signal(&_sdcard_mount_cond);
216 pthread_mutex_unlock(&_sdcard_mount_mtx);
217 }
218 }
137 } 219 }
138 device_names = new_device_names;
139 220
140 ufds[nfds].fd = fd; 221 close(_vold_monitor_socket_fd);
141 ufds[nfds].events = POLLIN; 222 unlink(VOLD_MONITOR_SOCKET_NAME);
142 device_names[nfds] = strdup(device); 223 _vold_monitor_socket_fd = -1;
143 nfds++; 224
225 DEBUGF("DEBUG %s: Thread end.", __func__);
144 226
227 _vold_monitor_active = 0;
145 return 0; 228 return 0;
146} 229}
147 230
148 231
232/* Vold monitor thread. */
233static pthread_t _vold_monitor_thread;
149 234
150static int scan_dir(const char *dirname, int print_flags) 235
236static void vold_monitor_start(void)
151{ 237{
152 char devname[PATH_MAX]; 238 TRACE;
153 char *filename; 239
154 DIR *dir; 240 if(_vold_monitor_active == 0)
155 struct dirent *de;
156 dir = opendir(dirname);
157 if(dir == NULL)
158 return -1;
159 strcpy(devname, dirname);
160 filename = devname + strlen(devname);
161 *filename++ = '/';
162 while((de = readdir(dir)))
163 { 241 {
164 if(de->d_name[0] == '.' && 242 pthread_create(&_vold_monitor_thread, NULL, vold_monitor_run, NULL);
165 (de->d_name[1] == '\0' ||
166 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
167 continue;
168 strcpy(filename, de->d_name);
169 open_device(devname, print_flags);
170 } 243 }
171 closedir(dir);
172 return 0;
173} 244}
174 245
175 246
176 247static void vold_monitor_stop(void)
177void button_init_device(void)
178{ 248{
179 int res; 249 TRACE;
180 int print_flags = 0; 250
181 const char *device = NULL; 251 if(_vold_monitor_active == 1)
182 const char *device_path = "/dev/input";
183
184 nfds = 1;
185 ufds = calloc(1, sizeof(ufds[0]));
186 ufds[0].fd = inotify_init();
187 ufds[0].events = POLLIN;
188 if(device)
189 {
190 res = open_device(device, print_flags);
191 if(res < 0) {
192 fprintf(stderr, "open device failed\n");
193 }
194 }
195 else
196 { 252 {
197 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE); 253 _vold_monitor_active = 0;
198 if(res < 0) 254 int ret = pthread_join(_vold_monitor_thread, NULL);
199 { 255 DEBUGF("DEBUG %s: Thread joined: ret: %d.", __func__, ret);
200 fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
201 }
202 res = scan_dir(device_path, print_flags);
203 if(res < 0)
204 {
205 fprintf(stderr, "scan dir failed for %s\n", device_path);
206 }
207 } 256 }
208} 257}
209 258
210 259
211int draw() 260/*- Input handler -------------------------------------------------------------------------------*/
261
262
263/* Input devices monitored with poll API. */
264static struct pollfd* _fds = NULL;
265
266
267/* Number of input devices monitored with poll API. */
268static nfds_t _nfds = 0;
269
270
271/* The names of the devices in _fds. */
272static char** _device_names = NULL;
273
274
275/* Open device device_name and add it to the list of polled devices. */
276static void open_device(const char* device_name)
212{ 277{
213 int fbfd = 0; 278 int fd = open(device_name, O_RDONLY);
214 struct fb_var_screeninfo vinfo; 279 if(fd == -1)
215 struct fb_fix_screeninfo finfo;
216 long int screensize = 0;
217 char *fbp = 0;
218 int x = 0, y = 0;
219 long int location = 0;
220
221 /* Open the file for reading and writing */
222 fbfd = open("/dev/graphics/fb0", O_RDWR);
223 if (fbfd == -1)
224 { 280 {
225 perror("Error: cannot open framebuffer device"); 281 DEBUGF("ERROR %s: open failed on %s.", __func__, device_name);
226 exit(1); 282 exit(-1);
227 } 283 }
228 /* Get fixed screen information */ 284
229 if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) 285 struct pollfd* new_fds = realloc(_fds, sizeof(struct pollfd) * (_nfds + 1));
286 if(new_fds == NULL)
230 { 287 {
231 perror("Error reading fixed information"); 288 DEBUGF("ERROR %s: realloc for _fds failed.", __func__);
232 exit(2); 289 exit(-1);
233 } 290 }
234 291
235 /* Get variable screen information */ 292 _fds = new_fds;
236 if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) 293 _fds[_nfds].fd = fd;
294 _fds[_nfds].events = POLLIN;
295
296 char** new_device_names = realloc(_device_names, sizeof(char*) * (_nfds + 1));
297 if(new_device_names == NULL)
237 { 298 {
238 perror("Error reading variable information"); 299 DEBUGF("ERROR %s: realloc for _device_names failed.", __func__);
239 exit(3); 300 exit(-1);
240 } 301 }
241 302
242 /* Figure out the size of the screen in bytes */ 303 _device_names = new_device_names;
243 screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; 304 _device_names[_nfds] = strdup(device_name);
244 305 if(_device_names[_nfds] == NULL)
245 vinfo.xres = vinfo.xres_virtual = vinfo.width = 320;
246 vinfo.yres = vinfo.yres_virtual = vinfo.height = 240;
247 vinfo.xoffset = vinfo.yoffset = vinfo.sync = vinfo.vmode = 0;
248 vinfo.pixclock = 104377;
249 vinfo.left_margin = 20;
250 vinfo.right_margin = 50;
251 vinfo.upper_margin = 2;
252 vinfo.lower_margin = 4;
253 vinfo.hsync_len = 10;
254 vinfo.vsync_len = 2;
255 vinfo.red.offset = 11;
256 vinfo.red.length = 5;
257 vinfo.red.msb_right = 0;
258 vinfo.green.offset = 5;
259 vinfo.green.length = 6;
260 vinfo.green.msb_right = 0;
261 vinfo.blue.offset = 0;
262 vinfo.blue.length = 5;
263 vinfo.blue.msb_right = 0;
264 vinfo.transp.offset = vinfo.transp.length = vinfo.transp.msb_right = 0;
265 vinfo.nonstd = 4;
266
267 if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
268 { 306 {
269 perror("fbset(ioctl)"); 307 DEBUGF("ERROR %s: strdup failed.", __func__);
270 exit(4); 308 exit(-1);
271 } 309 }
272 310
311 ++_nfds;
273 312
274 /* Map the device to memory */ 313 DEBUGF("DEBUG %s: Opened device %s.", __func__, device_name);
275 fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, 314}
276 fbfd, 0); 315
277 if ((int)fbp == -1) 316
317static void button_init_device(void)
318{
319 TRACE;
320
321 if((_fds != NULL) || (_nfds != 0) || (_device_names != NULL))
278 { 322 {
279 perror("Error: failed to map framebuffer device to memory"); 323 DEBUGF("ERROR %s: Allready initialized.", __func__);
280 exit(4); 324 return;
281 } 325 }
282 326
283 BMP* bmp = BMP_ReadFile("/system/rockbox/chooser.bmp"); 327 /* The input device directory. */
284 BMP_CHECK_ERROR( stderr, -1 ); 328 static const char device_path[] = "/dev/input";
285 329
286 UCHAR r, g, b; 330 /* Path delimeter. */
287 unsigned short int t; 331 static const char delimeter[] = "/";
288 332
289 for (y = 0; y < 240; y++) 333 /* Open all devices in device_path. */
290 for (x = 0; x < 320; x++) 334 DIR* dir = opendir(device_path);
291 { 335 if(dir == NULL)
292 location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + 336 {
293 (y+vinfo.yoffset) * finfo.line_length; 337 DEBUGF("ERROR %s: opendir failed: errno: %d.", __func__, errno);
338 exit(errno);
339 }
294 340
295 BMP_GetPixelRGB(bmp, x, y, &r, &g, &b); 341 char device_name[PATH_MAX];
296 t = (r>>3)<<11 | (g>>2) << 5 | (b>>3); 342 strcpy(device_name, device_path);
297 *((unsigned short int*)(fbp + location)) = t; 343 strcat(device_name, delimeter);
344 char* device_name_idx = device_name + strlen(device_name);
345
346 struct dirent* dir_entry;
347 while((dir_entry = readdir(dir)))
348 {
349 if( ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '\0'))
350 || ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '.') && (dir_entry->d_name[2] == '\0')))
351 {
352 continue;
298 } 353 }
299 354
300 BMP_Free( bmp ); 355 strcpy(device_name_idx, dir_entry->d_name);
301 356
302 munmap(fbp, screensize); 357 /* Open and add device to _fds. */
303 close(fbfd); 358 open_device(device_name);
304 return 0; 359 }
360
361 closedir(dir);
362
363 /* Sanity check. */
364 if(_nfds < 2)
365 {
366 DEBUGF("ERROR %s: No input devices.", __func__);
367 exit(-1);
368 }
305} 369}
306 370
307 371
308int choose_player() 372#define EVENT_TYPE_BUTTON 1
373
374
375#define EVENT_CODE_BUTTON_PWR_LONG 117
376#define EVENT_CODE_BUTTON_REV 160
377#define EVENT_CODE_BUTTON_NEXT 162
378
379
380#define EVENT_TYPE_TOUCHSCREEN 3
381
382
383#define EVENT_CODE_TOUCHSCREEN_X 53
384
385
386enum user_choice
309{ 387{
310 int i; 388 CHOICE_NONE = -1,
311 int res; 389 CHOICE_MANGO,
312 struct input_event event; 390 CHOICE_ROCKBOX,
391 CHOICE_POWEROFF
392};
313 393
314 while(true) 394
395static int get_user_choice(void)
396{
397 TRACE;
398
399 button_init_device();
400
401 enum user_choice choice = CHOICE_NONE;
402
403 while(choice == CHOICE_NONE)
315 { 404 {
316 poll(ufds, nfds, POLL_MS); 405 /* Poll all input devices. */
317 for(i = 1; i < nfds; i++) 406 poll(_fds, _nfds, 0);
407
408 nfds_t fds_idx = 0;
409 for( ; fds_idx < _nfds; ++fds_idx)
318 { 410 {
319 if(ufds[i].revents & POLLIN) 411 if(! (_fds[fds_idx].revents & POLLIN))
320 { 412 {
321 res = read(ufds[i].fd, &event, sizeof(event)); 413 continue;
322 if(res < (int)sizeof(event)) 414 }
323 { 415
324 fprintf(stderr, "could not get event\n"); 416 struct input_event event;
325 } 417 if(read(_fds[fds_idx].fd, &event, sizeof(event)) < (int) sizeof(event))
326 if(event.type==1) 418 {
419 DEBUGF("ERROR %s: Read of input devices failed.", __func__);
420 continue;
421 }
422
423 DEBUGF("DEBUG %s: device: %s, event.type: %d, event.code: %d, event.value: %d", __func__, _device_names[fds_idx], event.type, event.code, event.value);
424
425 if(event.type == EVENT_TYPE_BUTTON)
426 {
427 switch(event.code)
327 { 428 {
328 if(event.code==KEYCODE_NEXT) 429 case EVENT_CODE_BUTTON_REV:
329 { 430 {
330 puts("rockbox!"); 431 choice = CHOICE_MANGO;
331 return 1; 432 break;
332 } 433 }
333 else if(event.code==KEYCODE_PREV) 434
435 case EVENT_CODE_BUTTON_NEXT:
334 { 436 {
335 puts("mango!"); 437 choice = CHOICE_ROCKBOX;
336 return 0; 438 break;
337 } 439 }
338 else if(event.code==KEYCODE_PWR || event.code==KEYCODE_PWR_LONG) 440
441 case EVENT_CODE_BUTTON_PWR_LONG:
339 { 442 {
340 reboot(LINUX_REBOOT_CMD_POWER_OFF); 443 choice = CHOICE_POWEROFF;
444 break;
341 } 445 }
342 } 446 }
343 else if(event.type==3) 447 }
448 else if((event.type == EVENT_TYPE_TOUCHSCREEN) && (event.code == EVENT_CODE_TOUCHSCREEN_X))
449 {
450 if(event.value < 160)
344 { 451 {
345 if(event.code==53) //x coord 452 choice = CHOICE_MANGO;
346 { 453 }
347 if(event.value<160) 454 else
348 { 455 {
349 puts("mango!"); 456 choice = CHOICE_ROCKBOX;
350 return 0;
351 }
352 else
353 {
354 puts("rockbox!");
355 return 1;
356 }
357 }
358 } 457 }
359 } 458 }
360 } 459 }
361 } 460 }
362 return true; 461
462 if(_fds)
463 {
464 nfds_t fds_idx = 0;
465 for( ; fds_idx < _nfds; ++fds_idx)
466 {
467 close(_fds[fds_idx].fd);
468 }
469 free(_fds);
470 _fds = NULL;
471 }
472
473 if(_device_names)
474 {
475 nfds_t fds_idx = 0;
476 for( ; fds_idx < _nfds; ++fds_idx)
477 {
478 free(_device_names[fds_idx]);
479 }
480 free(_device_names);
481 _device_names = NULL;
482 }
483
484 _nfds = 0;
485
486 return choice;
363} 487}
364 488
365bool check_for_hold() 489
490/*
491 Changing bit, when hold switch is toggled.
492 Bit is off when hold switch is engaged.
493*/
494#define HOLD_SWITCH_BIT 16
495
496
497static bool check_for_hold(void)
366{ 498{
367 FILE *f = fopen("/sys/class/axppower/holdkey", "r"); 499 TRACE;
368 char x; 500
369 fscanf(f, "%c", &x); 501 char hold_state;
502
503 FILE* f = fopen("/sys/class/axppower/holdkey", "r");
504 fscanf(f, "%c", &hold_state);
370 fclose(f); 505 fclose(f);
371 506
372 if(x & KEY_HOLD_OFF) 507 return(! (hold_state & HOLD_SWITCH_BIT));
373 return false;
374 else
375 return true;
376} 508}
377 509
510
511/*- Display -------------------------------------------------------------------------------------*/
512
513
514static void draw(const char* file)
515{
516 DEBUGF("DEBUG %s: file: %s.", __func__, file);
517
518 int dev_fd = open("/dev/graphics/fb0", O_RDWR);
519 if(dev_fd == -1)
520 {
521 DEBUGF("ERROR %s: open failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
522 exit(errno);
523 }
524
525 /* Get fixed screen information. */
526 struct fb_fix_screeninfo finfo;
527 if(ioctl(dev_fd, FBIOGET_FSCREENINFO, &finfo) < 0)
528 {
529 DEBUGF("ERROR %s: ioctl FBIOGET_FSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
530 exit(errno);
531 }
532
533 /* Get the changeable information. */
534 struct fb_var_screeninfo vinfo;
535 if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
536 {
537 DEBUGF("ERROR %s: ioctl FBIOGET_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
538 exit(errno);
539 }
540
541 DEBUGF("DEBUG %s: bits_per_pixel: %u, width: %u, height: %u.", __func__, vinfo.bits_per_pixel, vinfo.width, vinfo.height);
542
543 size_t screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
544
545 /* ToDo: Is this needed? */
546 vinfo.xres = 320;
547 vinfo.xres_virtual = 320;
548 vinfo.width = 320;
549 vinfo.yres = 240;
550 vinfo.yres_virtual = 240;
551 vinfo.height = 240;
552 vinfo.xoffset = 0;
553 vinfo.yoffset = 0;
554 vinfo.sync = 0;
555 vinfo.vmode = 0;
556 vinfo.pixclock = 104377;
557 vinfo.left_margin = 20;
558 vinfo.right_margin = 50;
559 vinfo.upper_margin = 2;
560 vinfo.lower_margin = 4;
561 vinfo.hsync_len = 10;
562 vinfo.vsync_len = 2;
563 vinfo.red.offset = 11;
564 vinfo.red.length = 5;
565 vinfo.red.msb_right = 0;
566 vinfo.green.offset = 5;
567 vinfo.green.length = 6;
568 vinfo.green.msb_right = 0;
569 vinfo.blue.offset = 0;
570 vinfo.blue.length = 5;
571 vinfo.blue.msb_right = 0;
572 vinfo.transp.offset = 0;
573 vinfo.transp.length = 0;
574 vinfo.transp.msb_right = 0;
575 vinfo.nonstd = 4;
576 if(ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0)
577 {
578 DEBUGF("ERROR %s: ioctl FBIOPUT_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
579 exit(errno);
580 }
581
582 /* Map the device to memory. */
583 char* dev_fb = (char*) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
584 if(dev_fb == MAP_FAILED)
585 {
586 DEBUGF("ERROR %s: mmap failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
587 exit(errno);
588 }
589
590 BMP* bmp = BMP_ReadFile(file);
591 if(BMP_GetError() != BMP_OK )
592 {
593 DEBUGF("ERROR %s: BMP_ReadFile failed on %s: %d.", __func__, file, BMP_GetError());
594 exit(BMP_GetError());
595 }
596
597 int y = 0;
598 for( ; y < 240; ++y)
599 {
600 int x = 0;
601 for( ; x < 320; ++x)
602 {
603 long int position = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8 )
604 + (y + vinfo.yoffset) * finfo.line_length;
605 UCHAR r, g, b;
606 BMP_GetPixelRGB(bmp, x, y, &r, &g, &b);
607 unsigned short int pixel = (r >> 3) << 11 | (g >> 2) << 5 | (b >> 3);
608 *((unsigned short int*)(dev_fb + position)) = pixel;
609 }
610 }
611
612 BMP_Free(bmp);
613 munmap(dev_fb, screensize);
614 close(dev_fd);
615}
616
617
618/*-----------------------------------------------------------------------------------------------*/
619
620
621static const char ROCKBOX_BIN[] = "/mnt/sdcard/.rockbox/rockbox";
622static const char OF_PLAYER_BIN[] = "/system/bin/MangoPlayer_original";
623static const char PLAYER_FILE[] = "/data/chosen_player";
624
625
378int main(int argc, char **argv) 626int main(int argc, char **argv)
379{ 627{
380 FILE *f; 628 TRACE;
381 int last_chosen_player = -1; 629
630 /*
631 Create the iBasso Vold socket and monitor it.
632 Do this early to not block Vold.
633 */
634 vold_monitor_start();
382 635
383 f = fopen(PLAYER_FILE, "r"); 636 int last_chosen_player = CHOICE_NONE;
384 if(f!=NULL) 637
638 FILE* f = fopen(PLAYER_FILE, "r");
639 if(f != NULL)
385 { 640 {
386 fscanf(f, "%d", &last_chosen_player); 641 fscanf(f, "%d", &last_chosen_player);
387 fclose(f); 642 fclose(f);
388 } 643 }
389 bool ask = (access(VOLD_LINK, F_OK) == -1) || ((access(NOASK_FLAG, F_OK) == -1) && check_for_hold()) || (last_chosen_player==-1);
390 644
391 if(ask) 645 DEBUGF("DEBUG %s: Current player choice: %d.", __func__, last_chosen_player);
646
647 if(check_for_hold() || (last_chosen_player == CHOICE_NONE))
392 { 648 {
393 draw(); 649 draw("/system/chooser.bmp");
394 button_init_device();
395 int player_chosen_now = choose_player();
396 650
397 if(last_chosen_player!=player_chosen_now) 651 enum user_choice choice = get_user_choice();
652
653 if(choice == CHOICE_POWEROFF)
398 { 654 {
399 f = fopen(PLAYER_FILE, "w"); 655 reboot(RB_POWER_OFF);
400 fprintf(f, "%d", player_chosen_now); 656 while(true)
401 fclose(f); 657 {
658 sleep(1);
659 }
402 } 660 }
403 661
404 if(last_chosen_player!=player_chosen_now || (access(VOLD_LINK, F_OK) == -1)) 662 if(choice != last_chosen_player)
405 { 663 {
406 system("rm "VOLD_LINK); 664 last_chosen_player = choice;
407
408 if(player_chosen_now)
409 system("ln -s /system/bin/vold_rockbox "VOLD_LINK);
410 else
411 system("ln -s /system/bin/vold_original "VOLD_LINK);
412 665
413 system("touch "NOASK_FLAG); 666 f = fopen(PLAYER_FILE, "w");
414 system("reboot"); 667 fprintf(f, "%d", last_chosen_player);
668 fclose(f);
415 } 669 }
416 last_chosen_player = player_chosen_now; 670
671 DEBUGF("DEBUG %s: New player choice: %d.", __func__, last_chosen_player);
417 } 672 }
418 673
419 system("rm "NOASK_FLAG); 674 /* true, Rockbox was started at least once. */
675 bool rockboxStarted = false;
420 676
421 while(1) 677 while(true)
422 { 678 {
423 if(last_chosen_player) 679 /* Excecute OF MangoPlayer or Rockbox and restart it if it crashes. */
680
681 if(last_chosen_player == CHOICE_ROCKBOX)
424 { 682 {
425// system("/system/bin/openadb"); 683 if(rockboxStarted)
426 system("/system/rockbox/lib/rockbox"); 684 {
685 /*
686 At this point it is assumed, that Rockbox has exited due to a USB connection
687 triggering a remount of the internal storage for mass storage access.
688 Rockbox will eventually restart, when /mnt/sdcard becomes available again.
689 */
690 draw("/system/usb.bmp");
691 }
692
693 pthread_mutex_lock(&_sdcard_mount_mtx);
694 while(_sdcard_not_mounted)
695 {
696 DEBUGF("DEBUG %s: Waiting on /mnt/sdcard/.", __func__);
697
698 pthread_cond_wait(&_sdcard_mount_cond, &_sdcard_mount_mtx);
699
700 DEBUGF("DEBUG %s: /mnt/sdcard/ available.", __func__);
701 }
702 pthread_mutex_unlock(&_sdcard_mount_mtx);
703
704 /* To be able to execute rockbox. */
705 system("mount -o remount,exec /mnt/sdcard");
706
707 /* This symlink is needed mainly to keep themes functional. */
708 system("ln -s /mnt/sdcard/.rockbox /.rockbox");
709
710 if(access(ROCKBOX_BIN, X_OK) != -1)
711 {
712 /* Start Rockbox. */
713
714 /* Rockbox has its own vold monitor. */
715 vold_monitor_stop();
716
717 DEBUGF("DEBUG %s: Excecuting %s.", __func__, ROCKBOX_BIN);
718
719 int ret_code = system(ROCKBOX_BIN);
720 rockboxStarted = true;
721
722 DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
723
724 if(WIFEXITED(ret_code) && (WEXITSTATUS(ret_code) == 42))
725 {
726 /*
727 Rockbox terminated to prevent a froced shutdown due to a USB connection
728 triggering a remount of the internal storage for mass storage access.
729 */
730 _sdcard_not_mounted = true;
731 }
732 /* else Rockbox crashed ... */
733
734 vold_monitor_start();
735 }
736 else
737 {
738 /* Rockbox executable missing. Show info screen for 30 seconds. */
739 draw("/system/rbmissing.bmp");
740 sleep(30);
741
742 /* Do not block Vold, so stop after sleep. */
743 vold_monitor_stop();
744
745#ifdef DEBUG
746 system("setprop persist.sys.usb.config adb");
747 system("setprop persist.usb.debug 1");
748#endif
749
750 DEBUGF("DEBUG %s: Rockbox missing, excecuting %s.", __func__, OF_PLAYER_BIN);
751
752 /* Start OF MangoPlayer. */
753 int ret_code = system(OF_PLAYER_BIN);
754
755 DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
756 }
427 } 757 }
428 else 758 else /* if(last_chosen_player == CHOICE_MANGO) */
429// system("/system/bin/closeadb"); 759 {
430 system("/system/bin/MangoPlayer_original"); 760 vold_monitor_stop();
761
762 DEBUGF("DEBUG %s: Excecuting %s.", __func__, OF_PLAYER_BIN);
431 763
432 sleep(1); 764 int ret_code = system(OF_PLAYER_BIN);
765
766 DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
767 }
433 } 768 }
434 769
435 return 0; 770 return 0;
436} 771}
437
438
439
diff --git a/rbutil/ibassoboot/jni/rbmissing.bmp b/rbutil/ibassoboot/jni/rbmissing.bmp
new file mode 100644
index 0000000000..1e97066d8c
--- /dev/null
+++ b/rbutil/ibassoboot/jni/rbmissing.bmp
Binary files differ
diff --git a/rbutil/ibassoboot/jni/usb.bmp b/rbutil/ibassoboot/jni/usb.bmp
new file mode 100644
index 0000000000..c462de2236
--- /dev/null
+++ b/rbutil/ibassoboot/jni/usb.bmp
Binary files differ