100957b77a4f480083f426fd1b730ac1f58cbcec
[kugel-rb.git] / firmware / drivers / button.c
blob100957b77a4f480083f426fd1b730ac1f58cbcec
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Daniel Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * Rockbox button functions
26 #include <stdlib.h>
27 #include "config.h"
28 #include "system.h"
29 #include "button.h"
30 #include "kernel.h"
31 #include "thread.h"
32 #include "backlight.h"
33 #include "serial.h"
34 #include "power.h"
35 #include "powermgmt.h"
36 #ifdef SIMULATOR
37 #include "button-sdl.h"
38 #else
39 #include "button-target.h"
40 #endif
42 #ifdef HAVE_REMOTE_LCD
43 #include "lcd-remote.h"
44 #endif
46 #if 0
47 /* Older than MAX_EVENT_AGE button events are going to be ignored.
48 * Used to prevent for example volume going up uncontrollable when events
49 * are getting queued and UI is lagging too much.
51 #define MAX_EVENT_AGE HZ
52 #endif
54 struct event_queue button_queue;
56 static long lastbtn; /* Last valid button status */
57 static long last_read; /* Last button status, for debouncing/filtering */
58 static intptr_t button_data; /* data value from last message dequeued */
59 #ifdef HAVE_LCD_BITMAP
60 static bool flipped; /* buttons can be flipped to match the LCD flip */
61 #endif
62 #ifdef HAVE_BACKLIGHT
63 static bool filter_first_keypress;
64 #ifdef HAVE_REMOTE_LCD
65 static bool remote_filter_first_keypress;
66 #endif
67 #endif /* HAVE_BACKLIGHT */
68 #ifdef HAVE_HEADPHONE_DETECTION
69 static bool phones_present = false;
70 #endif
72 /* how long until repeat kicks in, in ticks */
73 #define REPEAT_START 30
75 /* the speed repeat starts at, in ticks */
76 #define REPEAT_INTERVAL_START 16
78 /* speed repeat finishes at, in ticks */
79 #define REPEAT_INTERVAL_FINISH 5
81 #ifdef HAVE_BUTTON_DATA
82 static int button_read(int *data);
83 #else
84 static int button_read(void);
85 #endif
87 #ifdef HAVE_TOUCHSCREEN
88 static int last_touchscreen_touch;
89 static int lastdata = 0;
90 #endif
91 #if defined(HAVE_HEADPHONE_DETECTION)
92 static struct timeout hp_detect_timeout; /* Debouncer for headphone plug/unplug */
93 /* This callback can be used for many different functions if needed -
94 just check to which object tmo points */
95 static int btn_detect_callback(struct timeout *tmo)
97 /* Try to post only transistions */
98 const long id = tmo->data ? SYS_PHONE_PLUGGED : SYS_PHONE_UNPLUGGED;
99 queue_remove_from_head(&button_queue, id);
100 queue_post(&button_queue, id, 0);
101 return 0;
103 #endif
105 static void button_tick(void)
107 static int count = 0;
108 static int repeat_speed = REPEAT_INTERVAL_START;
109 static int repeat_count = 0;
110 static bool repeat = false;
111 static bool post = false;
112 #ifdef HAVE_BACKLIGHT
113 static bool skip_release = false;
114 #ifdef HAVE_REMOTE_LCD
115 static bool skip_remote_release = false;
116 #endif
117 #endif
118 int diff;
119 int btn;
120 #ifdef HAVE_BUTTON_DATA
121 int data = 0;
122 #else
123 const int data = 0;
124 #endif
126 #if defined(HAS_SERIAL_REMOTE) && !defined(SIMULATOR)
127 /* Post events for the remote control */
128 btn = remote_control_rx();
129 if(btn)
131 queue_post(&button_queue, btn, 0);
133 #endif
135 #ifdef HAVE_BUTTON_DATA
136 btn = button_read(&data);
137 #else
138 btn = button_read();
139 #endif
141 #if defined(HAVE_HEADPHONE_DETECTION)
142 if (headphones_inserted() != phones_present)
144 /* Use the autoresetting oneshot to debounce the detection signal */
145 phones_present = !phones_present;
146 timeout_register(&hp_detect_timeout, btn_detect_callback,
147 HZ, phones_present);
149 #endif
151 /* Find out if a key has been released */
152 diff = btn ^ lastbtn;
153 if(diff && (btn & diff) == 0)
155 #ifdef HAVE_BACKLIGHT
156 #ifdef HAVE_REMOTE_LCD
157 if(diff & BUTTON_REMOTE)
158 if(!skip_remote_release)
159 queue_post(&button_queue, BUTTON_REL | diff, data);
160 else
161 skip_remote_release = false;
162 else
163 #endif
164 if(!skip_release)
165 queue_post(&button_queue, BUTTON_REL | diff, data);
166 else
167 skip_release = false;
168 #else
169 queue_post(&button_queue, BUTTON_REL | diff, data);
170 #endif
172 else
174 if ( btn )
176 /* normal keypress */
177 if ( btn != lastbtn )
179 post = true;
180 repeat = false;
181 repeat_speed = REPEAT_INTERVAL_START;
183 else /* repeat? */
185 if ( repeat )
187 if (!post)
188 count--;
189 if (count == 0) {
190 post = true;
191 /* yes we have repeat */
192 if (repeat_speed > REPEAT_INTERVAL_FINISH)
193 repeat_speed--;
194 count = repeat_speed;
196 repeat_count++;
198 /* Send a SYS_POWEROFF event if we have a device
199 which doesn't shut down easily with the OFF
200 key */
201 #ifdef HAVE_SW_POWEROFF
202 if ((btn == POWEROFF_BUTTON
203 #ifdef RC_POWEROFF_BUTTON
204 || btn == RC_POWEROFF_BUTTON
205 #endif
206 ) &&
207 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
208 #if CONFIG_CHARGING >= CHARGING_MONITOR
209 !charging_state() &&
210 #else
211 !charger_inserted() &&
212 #endif
213 #endif
214 repeat_count > POWEROFF_COUNT)
216 /* Tell the main thread that it's time to
217 power off */
218 sys_poweroff();
220 /* Safety net for players without hardware
221 poweroff */
222 #ifndef SIMULATOR
223 if(repeat_count > POWEROFF_COUNT * 10)
224 power_off();
225 #endif
227 #endif
230 else
232 if (count++ > REPEAT_START)
234 post = true;
235 repeat = true;
236 repeat_count = 0;
237 /* initial repeat */
238 count = REPEAT_INTERVAL_START;
242 if ( post )
244 if (repeat)
246 /* Only post repeat events if the queue is empty,
247 * to avoid afterscroll effects. */
248 if (queue_empty(&button_queue))
250 queue_post(&button_queue, BUTTON_REPEAT | btn, data);
251 #ifdef HAVE_BACKLIGHT
252 #ifdef HAVE_REMOTE_LCD
253 skip_remote_release = false;
254 #endif
255 skip_release = false;
256 #endif
257 post = false;
260 else
262 #ifdef HAVE_BACKLIGHT
263 #ifdef HAVE_REMOTE_LCD
264 if (btn & BUTTON_REMOTE) {
265 if (!remote_filter_first_keypress
266 || is_remote_backlight_on(false)
267 #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
268 || (remote_type()==REMOTETYPE_H300_NONLCD)
269 #endif
271 queue_post(&button_queue, btn, data);
272 else
273 skip_remote_release = true;
275 else
276 #endif
277 if (!filter_first_keypress || is_backlight_on(false)
278 #if BUTTON_REMOTE
279 || (btn & BUTTON_REMOTE)
280 #endif
282 queue_post(&button_queue, btn, data);
283 else
284 skip_release = true;
285 #else /* no backlight, nothing to skip */
286 queue_post(&button_queue, btn, data);
287 #endif
288 post = false;
290 #ifdef HAVE_REMOTE_LCD
291 if(btn & BUTTON_REMOTE)
292 remote_backlight_on();
293 else
294 #endif
296 backlight_on();
297 #ifdef HAVE_BUTTON_LIGHT
298 buttonlight_on();
299 #endif
302 reset_poweroff_timer();
305 else
307 repeat = false;
308 count = 0;
311 lastbtn = btn & ~(BUTTON_REL | BUTTON_REPEAT);
312 #ifdef HAVE_BUTTON_DATA
313 lastdata = data;
314 #endif
317 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
318 static void button_boost(bool state)
320 static bool boosted = false;
322 if (state && !boosted)
324 cpu_boost(true);
325 boosted = true;
327 else if (!state && boosted)
329 cpu_boost(false);
330 boosted = false;
333 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
335 int button_queue_count( void )
337 return queue_count(&button_queue);
340 long button_get(bool block)
342 struct queue_event ev;
343 int pending_count = queue_count(&button_queue);
345 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
346 /* Control the CPU boost trying to keep queue empty. */
347 if (pending_count == 0)
348 button_boost(false);
349 else if (pending_count > 2)
350 button_boost(true);
351 #endif
353 if ( block || pending_count )
355 queue_wait(&button_queue, &ev);
357 #if 0
358 /* Ignore if the event was too old and for simplicity, just
359 * wait for a new button_get() request. */
360 if (current_tick - ev.tick > MAX_EVENT_AGE)
361 return BUTTON_NONE;
362 #endif
363 button_data = ev.data;
364 return ev.id;
367 return BUTTON_NONE;
370 long button_get_w_tmo(int ticks)
372 struct queue_event ev;
374 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
375 /* Be sure to keep boosted state. */
376 if (!queue_empty(&button_queue))
377 return button_get(true);
379 button_boost(false);
380 #endif
382 queue_wait_w_tmo(&button_queue, &ev, ticks);
383 if (ev.id == SYS_TIMEOUT)
384 ev.id = BUTTON_NONE;
385 else
386 button_data = ev.data;
387 return ev.id;
390 intptr_t button_get_data(void)
392 return button_data;
395 void button_init(void)
397 /* Init used objects first */
398 queue_init(&button_queue, true);
400 #ifdef HAVE_BUTTON_DATA
401 int temp;
402 #endif
403 /* hardware inits */
404 button_init_device();
406 #ifdef HAVE_BUTTON_DATA
407 button_read(&temp);
408 lastbtn = button_read(&temp);
409 #else
410 button_read();
411 lastbtn = button_read();
412 #endif
414 reset_poweroff_timer();
416 #ifdef HAVE_LCD_BITMAP
417 flipped = false;
418 #endif
419 #ifdef HAVE_BACKLIGHT
420 filter_first_keypress = false;
421 #ifdef HAVE_REMOTE_LCD
422 remote_filter_first_keypress = false;
423 #endif
424 #endif
425 #ifdef HAVE_TOUCHSCREEN
426 last_touchscreen_touch = 0xffff;
427 #endif
428 /* Start polling last */
429 tick_add_task(button_tick);
432 #ifndef SIMULATOR
433 #ifdef BUTTON_DRIVER_CLOSE
434 void button_close(void)
436 tick_remove_task(button_tick);
438 #endif /* BUTTON_DRIVER_CLOSE */
440 #ifdef HAVE_LCD_FLIP
442 * helper function to swap LEFT/RIGHT, UP/DOWN (if present), and F1/F3 (Recorder)
444 static int button_flip(int button)
446 int newbutton;
448 newbutton = button &
449 ~(BUTTON_LEFT | BUTTON_RIGHT
450 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
451 | BUTTON_UP | BUTTON_DOWN
452 #endif
453 #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD)
454 | BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD
455 #endif
456 #if CONFIG_KEYPAD == RECORDER_PAD
457 | BUTTON_F1 | BUTTON_F3
458 #endif
459 #if CONFIG_KEYPAD == SANSA_C200_PAD
460 | BUTTON_VOL_UP | BUTTON_VOL_DOWN
461 #endif
462 #if CONFIG_KEYPAD == PHILIPS_SA9200_PAD
463 | BUTTON_VOL_UP | BUTTON_VOL_DOWN
464 | BUTTON_NEXT | BUTTON_PREV
465 #endif
468 if (button & BUTTON_LEFT)
469 newbutton |= BUTTON_RIGHT;
470 if (button & BUTTON_RIGHT)
471 newbutton |= BUTTON_LEFT;
472 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
473 if (button & BUTTON_UP)
474 newbutton |= BUTTON_DOWN;
475 if (button & BUTTON_DOWN)
476 newbutton |= BUTTON_UP;
477 #endif
478 #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD)
479 if (button & BUTTON_SCROLL_BACK)
480 newbutton |= BUTTON_SCROLL_FWD;
481 if (button & BUTTON_SCROLL_FWD)
482 newbutton |= BUTTON_SCROLL_BACK;
483 #endif
484 #if CONFIG_KEYPAD == RECORDER_PAD
485 if (button & BUTTON_F1)
486 newbutton |= BUTTON_F3;
487 if (button & BUTTON_F3)
488 newbutton |= BUTTON_F1;
489 #endif
490 #if CONFIG_KEYPAD == SANSA_C200_PAD
491 if (button & BUTTON_VOL_UP)
492 newbutton |= BUTTON_VOL_DOWN;
493 if (button & BUTTON_VOL_DOWN)
494 newbutton |= BUTTON_VOL_UP;
495 #endif
496 #if CONFIG_KEYPAD == PHILIPS_SA9200_PAD
497 if (button & BUTTON_VOL_UP)
498 newbutton |= BUTTON_VOL_DOWN;
499 if (button & BUTTON_VOL_DOWN)
500 newbutton |= BUTTON_VOL_UP;
501 if (button & BUTTON_NEXT)
502 newbutton |= BUTTON_PREV;
503 if (button & BUTTON_PREV)
504 newbutton |= BUTTON_NEXT;
505 #endif
507 return newbutton;
511 * set the flip attribute
512 * better only call this when the queue is empty
514 void button_set_flip(bool flip)
516 if (flip != flipped) /* not the current setting */
518 /* avoid race condition with the button_tick() */
519 int oldlevel = disable_irq_save();
520 lastbtn = button_flip(lastbtn);
521 flipped = flip;
522 restore_irq(oldlevel);
525 #endif /* HAVE_LCD_FLIP */
526 #endif /* SIMULATOR */
528 #ifdef HAVE_BACKLIGHT
529 void set_backlight_filter_keypress(bool value)
531 filter_first_keypress = value;
533 #ifdef HAVE_REMOTE_LCD
534 void set_remote_backlight_filter_keypress(bool value)
536 remote_filter_first_keypress = value;
538 #endif
539 #endif
542 * Get button pressed from hardware
544 #ifdef HAVE_BUTTON_DATA
545 static int button_read(int *data)
547 int btn = button_read_device(data);
548 #else
549 static int button_read(void)
551 int btn = button_read_device();
552 #endif
553 int retval;
555 #ifdef HAVE_LCD_FLIP
556 if (btn && flipped)
557 btn = button_flip(btn); /* swap upside down */
558 #endif /* HAVE_LCD_FLIP */
560 #ifdef HAVE_TOUCHSCREEN
561 if (btn & BUTTON_TOUCHSCREEN)
562 last_touchscreen_touch = current_tick;
563 #endif
564 /* Filter the button status. It is only accepted if we get the same
565 status twice in a row. */
566 #ifndef HAVE_TOUCHSCREEN
567 if (btn != last_read)
568 retval = lastbtn;
569 else
570 #endif
571 retval = btn;
572 last_read = btn;
574 return retval;
577 int button_status(void)
579 return lastbtn;
582 #ifdef HAVE_BUTTON_DATA
583 int button_status_wdata(int *pdata)
585 *pdata = lastdata;
586 return lastbtn;
588 #endif
590 void button_clear_queue(void)
592 queue_clear(&button_queue);
595 #ifdef HAVE_TOUCHSCREEN
596 int touchscreen_last_touch(void)
598 return last_touchscreen_touch;
600 #endif
602 #ifdef HAVE_WHEEL_ACCELERATION
603 /* WHEEL_ACCEL_FACTOR = 2^16 / WHEEL_ACCEL_START */
604 #define WHEEL_ACCEL_FACTOR (1<<16)/WHEEL_ACCEL_START
606 * data:
607 * [31] Use acceleration
608 * [30:24] Message post count (skipped + 1) (1-127)
609 * [23:0] Velocity - degree/sec
611 * WHEEL_ACCEL_FACTOR:
612 * Value in degree/sec -- configurable via settings -- above which
613 * the accelerated scrolling starts. Factor is internally scaled by
614 * 1<<16 in respect to the following 32bit integer operations.
616 int button_apply_acceleration(const unsigned int data)
618 int delta = (data >> 24) & 0x7f;
620 if ((data & (1 << 31)) != 0)
622 /* read driver's velocity from data */
623 unsigned int v = data & 0xffffff;
625 /* v = 28.4 fixed point */
626 v = (WHEEL_ACCEL_FACTOR * v)>>(16-4);
628 /* Calculate real numbers item to scroll based upon acceleration
629 * setting, use correct roundoff */
630 #if (WHEEL_ACCELERATION == 1)
631 v = (v*v + (1<< 7))>> 8;
632 #elif (WHEEL_ACCELERATION == 2)
633 v = (v*v*v + (1<<11))>>12;
634 #elif (WHEEL_ACCELERATION == 3)
635 v = (v*v*v*v + (1<<15))>>16;
636 #endif
638 if (v > 1)
639 delta *= v;
642 return delta;
644 #endif /* HAVE_WHEEL_ACCELERATION */