summaryrefslogtreecommitdiff
path: root/firmware/target/hosted/ibasso/button-ibasso.c
diff options
context:
space:
mode:
authorUdo Schläpfer <rockbox-2014.10@desktopwarrior.net>2015-02-02 21:44:29 +0100
committerUdo Schläpfer <rockbox-2014.10@desktopwarrior.net>2015-02-02 21:57:55 +0100
commitdbabd0d9c34a33bc0c51243ec37f230d117db955 (patch)
tree46de348929ce739702a230a2587fdb5539585753 /firmware/target/hosted/ibasso/button-ibasso.c
parentcef17e3d59ad93f766e8ee23b1610540a33dfe5e (diff)
downloadrockbox-dbabd0d9c34a33bc0c51243ec37f230d117db955.tar.gz
rockbox-dbabd0d9c34a33bc0c51243ec37f230d117db955.zip
iBasso DX50/DX90: Major code cleanup and reorganization.
Reorganization - Separated iBasso devices from PLATFORM_ANDROID. These are now standlone hosted targets. Most device specific code is in the firmware/target/hosted/ibasso directory. - No dependency on Android SDK, only the Android NDK is needed. 32 bit Android NDK and Android API Level 16. - Separate implementation for each device where feasible. Code cleanup - Rewrite of existing code, from simple reformat to complete reimplementation. - New backlight interface, seperating backlight from touchscreen. - Rewrite of device button handler, removing unneeded code and fixing memory leaks. - New Debug messages interface logging to Android adb logcat (DEBUGF, panicf, logf). - Rewrite of lcd device handler, removing unneeded code and fixing memory leaks. - Rewrite of audiohw device handler/pcm interface, removing unneeded code and fixing memory leaks, enabling 44.1/48kHz pthreaded playback. - Rewrite of power and powermng, proper shutdown, using batterylog results (see http://gerrit.rockbox.org/r/#/c/1047/). - Rewrite of configure (Android NDK) and device specific config. - Rewrite of the Android NDK specific Makefile. Misc - All plugins/games/demos activated. - Update tinyalsa to latest from https://github.com/tinyalsa/tinyalsa. Includes - http://gerrit.rockbox.org/r/#/c/993/ - http://gerrit.rockbox.org/r/#/c/1010/ - http://gerrit.rockbox.org/r/#/c/1035/ Does not include http://gerrit.rockbox.org/r/#/c/1007/ due to new backlight interface and new option for hold switch, touchscreen, physical button interaction. Rockbox needs the iBasso DX50/DX90 loader for startup, see http://gerrit.rockbox.org/r/#/c/1099/ The loader expects Rockbox to be installed in /mnt/sdcard/.rockbox/. If /mnt/sdcard/ is accessed as USB mass storage device, Rockbox will exit gracefully and the loader will restart Rockbox on USB disconnect. Tested on iBasso DX50. Compiled (not tested) for iBasso DX90. Compiled (not tested) for PLATFORM_ANDROID. Change-Id: I5f5e22e68f5b4cf29c28e2b40b2c265f2beb7ab7
Diffstat (limited to 'firmware/target/hosted/ibasso/button-ibasso.c')
-rw-r--r--firmware/target/hosted/ibasso/button-ibasso.c420
1 files changed, 420 insertions, 0 deletions
diff --git a/firmware/target/hosted/ibasso/button-ibasso.c b/firmware/target/hosted/ibasso/button-ibasso.c
new file mode 100644
index 0000000000..1694992ea4
--- /dev/null
+++ b/firmware/target/hosted/ibasso/button-ibasso.c
@@ -0,0 +1,420 @@
1/***************************************************************************
2 * __________ __ ___
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
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
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <dirent.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <stdbool.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32#include <linux/input.h>
33#include <sys/inotify.h>
34#include <sys/limits.h>
35#include <sys/poll.h>
36
37#include "config.h"
38#include "backlight.h"
39#include "button.h"
40#include "debug.h"
41#include "panic.h"
42#include "settings.h"
43#include "touchscreen.h"
44
45#include "button-ibasso.h"
46#include "button-target.h"
47#include "debug-ibasso.h"
48#include "sysfs-ibasso.h"
49
50
51#define EVENT_TYPE_BUTTON 1
52
53/* /dev/input/event0 */
54#define EVENT_CODE_BUTTON_LINEOUT 113
55#define EVENT_CODE_BUTTON_SPDIF 114
56#define EVENT_CODE_BUTTON_HOLD 115
57
58/* /dev/input/event1 */
59#define EVENT_CODE_BUTTON_SDCARD 143
60
61
62#define EVENT_TYPE_TOUCHSCREEN 3
63
64/* /dev/input/event2 */
65#define EVENT_CODE_TOUCHSCREEN_X 53
66#define EVENT_CODE_TOUCHSCREEN_Y 54
67#define EVENT_CODE_TOUCHSCREEN 57
68
69#define EVENT_VALUE_TOUCHSCREEN_PRESS 1
70#define EVENT_VALUE_TOUCHSCREEN_RELEASE -1
71
72
73/*
74 Changing bit, when hold switch is toggled.
75 Bit is off when hold switch is engaged.
76*/
77#define HOLD_SWITCH_BIT 16
78
79/*
80 Changing bit, when coaxial out is plugged.
81 Bit is off when coaxial out is plugged in.
82*/
83#define COAX_BIT 32
84
85/*
86 Changing bit, when line out is plugged.
87 Bit is off when line out is plugged in.
88*/
89#define SPDIF_BIT 64
90
91
92/* State of the hold switch; true: hold switch engaged. */
93static bool _hold = false;
94
95
96/* See button.h. */
97bool button_hold(void)
98{
99 char hold_state;
100 if(! sysfs_get_char(SYSFS_HOLDKEY, &hold_state))
101 {
102 DEBUGF("ERROR %s: Can not get hold switch state.", __func__);
103 hold_state = HOLD_SWITCH_BIT;
104 }
105
106 /*DEBUGF("%s: hold_state: %d, %c.", __func__, hold_state, hold_state);*/
107
108 /*bool coax_connected = ! (hold_state & COAX_BIT);
109 bool spdif_connected = ! (hold_state & SPDIF_BIT);*/
110
111 _hold = ! (hold_state & HOLD_SWITCH_BIT);
112
113 /*DEBUGF("%s: _hold: %d, coax_connected: %d, spdif_connected: %d.", __func__, _hold, coax_connected, spdif_connected);*/
114
115 return _hold;
116}
117
118
119/* Input devices monitored with poll API. */
120static struct pollfd* _fds = NULL;
121
122
123/* Number of input devices monitored with poll API. */
124static nfds_t _nfds = 0;
125
126
127/* The names of the devices in _fds. */
128static char** _device_names = NULL;
129
130
131/* Open device device_name and add it to the list of polled devices. */
132static bool open_device(const char* device_name)
133{
134 int fd = open(device_name, O_RDONLY);
135 if(fd == -1)
136 {
137 DEBUGF("ERROR %s: open failed on %s.", __func__, device_name);
138 return false;
139 }
140
141 struct pollfd* new_fds = realloc(_fds, sizeof(struct pollfd) * (_nfds + 1));
142 if(new_fds == NULL)
143 {
144 DEBUGF("ERROR %s: realloc for _fds failed.", __func__);
145 panicf("ERROR %s: realloc for _fds failed.", __func__);
146 return false;
147 }
148
149 _fds = new_fds;
150 _fds[_nfds].fd = fd;
151 _fds[_nfds].events = POLLIN;
152
153 char** new_device_names = realloc(_device_names, sizeof(char*) * (_nfds + 1));
154 if(new_device_names == NULL)
155 {
156 DEBUGF("ERROR %s: realloc for _device_names failed.", __func__);
157 panicf("ERROR %s: realloc for _device_names failed.", __func__);
158 return false;
159 }
160
161 _device_names = new_device_names;
162 _device_names[_nfds] = strdup(device_name);
163 if(_device_names[_nfds] == NULL)
164 {
165 DEBUGF("ERROR %s: strdup failed.", __func__);
166 panicf("ERROR %s: strdup failed.", __func__);
167 return false;
168 }
169
170 ++_nfds;
171
172 DEBUGF("DEBUG %s: Opened device %s.", __func__, device_name);
173
174 return true;
175}
176
177
178/* See button.h. */
179void button_init_device(void)
180{
181 TRACE;
182
183 if((_fds != NULL) || (_nfds != 0) || (_device_names != NULL))
184 {
185 DEBUGF("ERROR %s: Allready initialized.", __func__);
186 panicf("ERROR %s: Allready initialized.", __func__);
187 return;
188 }
189
190 /* The input device directory. */
191 static const char device_path[] = "/dev/input";
192
193 /* Path delimeter. */
194 static const char delimeter[] = "/";
195
196 /* Open all devices in device_path. */
197 DIR* dir = opendir(device_path);
198 if(dir == NULL)
199 {
200 DEBUGF("ERROR %s: opendir failed: errno: %d.", __func__, errno);
201 panicf("ERROR %s: opendir failed: errno: %d.", __func__, errno);
202 return;
203 }
204
205 char device_name[PATH_MAX];
206 strcpy(device_name, device_path);
207 strcat(device_name, delimeter);
208 char* device_name_idx = device_name + strlen(device_name);
209
210 struct dirent* dir_entry;
211 while((dir_entry = readdir(dir)))
212 {
213 if( ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '\0'))
214 || ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '.') && (dir_entry->d_name[2] == '\0')))
215 {
216 continue;
217 }
218
219 strcpy(device_name_idx, dir_entry->d_name);
220
221 /* Open and add device to _fds. */
222 open_device(device_name);
223 }
224
225 closedir(dir);
226
227 /* Sanity check. */
228 if(_nfds < 2)
229 {
230 DEBUGF("ERROR %s: No input devices.", __func__);
231 panicf("ERROR %s: No input devices.", __func__);
232 return;
233 }
234
235 /*
236 Hold switch has a separate interface for its state.
237 Input events just report that it has been toggled, but not the state.
238 */
239 button_hold();
240}
241
242
243/* Last known touchscreen coordinates. */
244static int _last_x = 0;
245static int _last_y = 0;
246
247
248/* Last known touchscreen state. */
249static enum
250{
251 TOUCHSCREEN_STATE_UNKNOWN = 0,
252 TOUCHSCREEN_STATE_UP,
253 TOUCHSCREEN_STATE_DOWN
254} _last_touch_state = TOUCHSCREEN_STATE_UNKNOWN;
255
256
257static bool handle_touchscreen_event(__u16 code, __s32 value)
258{
259 bool read_more = false;
260
261 switch(code)
262 {
263 case EVENT_CODE_TOUCHSCREEN_X:
264 {
265 _last_x = value;
266
267 /* x -> next will be y. */
268 read_more = true;
269
270 break;
271 }
272
273 case EVENT_CODE_TOUCHSCREEN_Y:
274 {
275 _last_y = value;
276 break;
277 }
278
279 case EVENT_CODE_TOUCHSCREEN:
280 {
281 if(value == EVENT_VALUE_TOUCHSCREEN_PRESS)
282 {
283 _last_touch_state = TOUCHSCREEN_STATE_DOWN;
284
285 /* Press -> next will be x. */
286 read_more = true;
287 }
288 else
289 {
290 _last_touch_state = TOUCHSCREEN_STATE_UP;
291 }
292 break;
293 }
294 }
295
296 return read_more;
297}
298
299
300/* Last known hardware buttons pressed. */
301static int _last_btns = BUTTON_NONE;
302
303
304/* See button.h. */
305int button_read_device(int *data)
306{
307 bool read_more = true;
308 while(read_more)
309 {
310 read_more = false;
311
312 /* Poll all input devices. */
313 poll(_fds, _nfds, 0);
314
315 for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx)
316 {
317 if(! (_fds[fds_idx].revents & POLLIN))
318 {
319 continue;
320 }
321
322 struct input_event event;
323 if(read(_fds[fds_idx].fd, &event, sizeof(event)) < (int) sizeof(event))
324 {
325 DEBUGF("ERROR %s: Read of input devices failed.", __func__);
326 continue;
327 }
328
329 /*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);*/
330
331 switch(event.type)
332 {
333 case EVENT_TYPE_BUTTON:
334 {
335 if(event.code == EVENT_CODE_BUTTON_HOLD)
336 {
337 /* Hold switch toggled, update hold switch state. */
338 button_hold();
339 backlight_hold_changed(_hold);
340
341 _last_btns = BUTTON_NONE;
342 break;
343 }
344
345 _last_btns = handle_button_event(event.code, event.value, _last_btns);
346
347 if(_hold)
348 {
349 /* Hold switch engaged. Ignore all button events. */
350 _last_btns = BUTTON_NONE;
351 }
352
353 /*DEBUGF("DEBUG %s: _last_btns: %#8.8x", __func__, _last_btns);*/
354 break;
355 }
356
357 case EVENT_TYPE_TOUCHSCREEN:
358 {
359 if(_hold)
360 {
361 /* Hold switch engaged, ignore all touchscreen events. */
362 _last_touch_state = TOUCHSCREEN_STATE_UNKNOWN;
363 _last_btns = BUTTON_NONE;
364 }
365 else
366 {
367 read_more = handle_touchscreen_event(event.code, event.value);
368 /*DEBUGF("DEBUG %s: _last_touch_state: %d, _last_x: %d, _last_y: %d, read_more: %s", __func__, _last_touch_state, _last_x, _last_y, read_more ? "true" : "false");*/
369 }
370 break;
371 }
372 }
373 }
374 }
375
376 /*
377 Get grid button/coordinates based on the current touchscreen mode
378 Caveat: The caller seemingly depends on *data always being filled with
379 the last known touchscreen position, so always call
380 touchscreen_to_pixels().
381 */
382 int touch = touchscreen_to_pixels(_last_x, _last_y, data);
383
384 if(_last_touch_state == TOUCHSCREEN_STATE_DOWN)
385 {
386 return _last_btns | touch;
387 }
388
389 /*DEBUGF("DEBUG %s: _last_btns: %#8.8x.", __func__, _last_btns);*/
390
391 return _last_btns;
392}
393
394
395void button_close_device(void)
396{
397 TRACE;
398
399 if(_fds)
400 {
401 for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx)
402 {
403 close(_fds[fds_idx].fd);
404 }
405 free(_fds);
406 _fds = NULL;
407 }
408
409 if(_device_names)
410 {
411 for(nfds_t fds_idx = 0; fds_idx < _nfds; ++fds_idx)
412 {
413 free(_device_names[fds_idx]);
414 }
415 free(_device_names);
416 _device_names = NULL;
417 }
418
419 _nfds = 0;
420}