summaryrefslogtreecommitdiff
path: root/firmware/target/hosted/ibasso/button-ibasso.c
diff options
context:
space:
mode:
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}