diff options
Diffstat (limited to 'rbutil/ibassoboot')
-rw-r--r-- | rbutil/ibassoboot/jni/Android.mk | 8 | ||||
-rw-r--r-- | rbutil/ibassoboot/jni/ibassodualboot.c | 906 | ||||
-rw-r--r-- | rbutil/ibassoboot/jni/rbmissing.bmp | bin | 0 -> 230454 bytes | |||
-rw-r--r-- | rbutil/ibassoboot/jni/usb.bmp | bin | 0 -> 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 | ||
4 | LOCAL_MODULE := MangoPlayer | 4 | LOCAL_MODULE := MangoPlayer |
5 | LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c | 5 | LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c |
6 | |||
7 | TARGET_ARCH=arm | ||
8 | TARGET_PLATFORM=android-14 | ||
9 | TARGET_ARCH_ABI=armeabi | ||
10 | |||
11 | #LOCAL_CFLAGS := -DDEBUG | ||
12 | #LOCAL_LDLIBS := -llog | ||
13 | |||
6 | include $(BUILD_EXECUTABLE) | 14 | include $(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 | |||
50 | static const char log_tag[] = "Rockbox Boot"; | ||
50 | 51 | ||
51 | 52 | ||
52 | #define MIN_TIME 1395606821 | 53 | void 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 | |||
62 | void 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 | |||
74 | void 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 | ||
74 | void checktime() | 94 | /* |
95 | Without this socket iBasso Vold will not start. | ||
96 | iBasso Vold uses this to send status messages about storage devices. | ||
97 | */ | ||
98 | static const char VOLD_MONITOR_SOCKET_NAME[] = "UNIX_domain"; | ||
99 | static int _vold_monitor_socket_fd = -1; | ||
100 | |||
101 | |||
102 | static 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 | ||
106 | static struct pollfd *ufds; | 139 | /* |
107 | static char **device_names; | 140 | bionic does not have pthread_cancel. |
108 | static int nfds; | 141 | 0: Vold monitor thread stopped/ending. |
142 | 1: Vold monitor thread started/running. | ||
143 | */ | ||
144 | static volatile sig_atomic_t _vold_monitor_active = 0; | ||
145 | |||
146 | |||
147 | /* true: sdcard not mounted. */ | ||
148 | static bool _sdcard_not_mounted = true; | ||
149 | |||
150 | |||
151 | /* Mutex for sdcard mounted flag. */ | ||
152 | static pthread_mutex_t _sdcard_mount_mtx = PTHREAD_MUTEX_INITIALIZER; | ||
109 | 153 | ||
110 | 154 | ||
155 | /* Signal condition for sdcard mounted flag. */ | ||
156 | static pthread_cond_t _sdcard_mount_cond = PTHREAD_COND_INITIALIZER; | ||
111 | 157 | ||
112 | static int open_device(const char *device, int print_flags) | 158 | |
159 | static 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. */ | ||
233 | static pthread_t _vold_monitor_thread; | ||
149 | 234 | ||
150 | static int scan_dir(const char *dirname, int print_flags) | 235 | |
236 | static 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 | 247 | static void vold_monitor_stop(void) | |
177 | void 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 | ||
211 | int draw() | 260 | /*- Input handler -------------------------------------------------------------------------------*/ |
261 | |||
262 | |||
263 | /* Input devices monitored with poll API. */ | ||
264 | static struct pollfd* _fds = NULL; | ||
265 | |||
266 | |||
267 | /* Number of input devices monitored with poll API. */ | ||
268 | static nfds_t _nfds = 0; | ||
269 | |||
270 | |||
271 | /* The names of the devices in _fds. */ | ||
272 | static char** _device_names = NULL; | ||
273 | |||
274 | |||
275 | /* Open device device_name and add it to the list of polled devices. */ | ||
276 | static 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 | |
317 | static 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 | ||
308 | int 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 | |||
386 | enum 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 | |
395 | static 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 | ||
365 | bool 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 | |||
497 | static 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 | |||
514 | static 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 | |||
621 | static const char ROCKBOX_BIN[] = "/mnt/sdcard/.rockbox/rockbox"; | ||
622 | static const char OF_PLAYER_BIN[] = "/system/bin/MangoPlayer_original"; | ||
623 | static const char PLAYER_FILE[] = "/data/chosen_player"; | ||
624 | |||
625 | |||
378 | int main(int argc, char **argv) | 626 | int 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 | |||