1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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
32 #include "backlight.h"
35 #include "powermgmt.h"
37 #include "button-sdl.h"
39 #include "button-target.h"
42 #ifdef HAVE_REMOTE_LCD
43 #include "lcd-remote.h"
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
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 */
63 static bool filter_first_keypress
;
64 #ifdef HAVE_REMOTE_LCD
65 static bool remote_filter_first_keypress
;
67 #endif /* HAVE_BACKLIGHT */
68 #ifdef HAVE_HEADPHONE_DETECTION
69 static bool phones_present
= false;
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
);
84 static int button_read(void);
87 #ifdef HAVE_TOUCHSCREEN
88 static int last_touchscreen_touch
;
89 static int lastdata
= 0;
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);
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;
120 #ifdef HAVE_BUTTON_DATA
126 #if defined(HAS_SERIAL_REMOTE) && !defined(SIMULATOR)
127 /* Post events for the remote control */
128 btn
= remote_control_rx();
131 queue_post(&button_queue
, btn
, 0);
135 #ifdef HAVE_BUTTON_DATA
136 btn
= button_read(&data
);
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
,
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
);
161 skip_remote_release
= false;
165 queue_post(&button_queue
, BUTTON_REL
| diff
, data
);
167 skip_release
= false;
169 queue_post(&button_queue
, BUTTON_REL
| diff
, data
);
176 /* normal keypress */
177 if ( btn
!= lastbtn
)
181 repeat_speed
= REPEAT_INTERVAL_START
;
191 /* yes we have repeat */
192 if (repeat_speed
> REPEAT_INTERVAL_FINISH
)
194 count
= repeat_speed
;
198 /* Send a SYS_POWEROFF event if we have a device
199 which doesn't shut down easily with the OFF
201 #ifdef HAVE_SW_POWEROFF
202 if ((btn
& POWEROFF_BUTTON
203 #ifdef RC_POWEROFF_BUTTON
204 || btn
== RC_POWEROFF_BUTTON
207 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
208 !charger_inserted() &&
210 repeat_count
> POWEROFF_COUNT
)
212 /* Tell the main thread that it's time to
216 /* Safety net for players without hardware
218 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
219 if(repeat_count
> POWEROFF_COUNT
* 10)
228 if (count
++ > REPEAT_START
)
234 count
= REPEAT_INTERVAL_START
;
242 /* Only post repeat events if the queue is empty,
243 * to avoid afterscroll effects. */
244 if (queue_empty(&button_queue
))
246 queue_post(&button_queue
, BUTTON_REPEAT
| btn
, data
);
247 #ifdef HAVE_BACKLIGHT
248 #ifdef HAVE_REMOTE_LCD
249 skip_remote_release
= false;
251 skip_release
= false;
258 #ifdef HAVE_BACKLIGHT
259 #ifdef HAVE_REMOTE_LCD
260 if (btn
& BUTTON_REMOTE
) {
261 if (!remote_filter_first_keypress
262 || is_remote_backlight_on(false)
263 #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
264 || (remote_type()==REMOTETYPE_H300_NONLCD
)
267 queue_post(&button_queue
, btn
, data
);
269 skip_remote_release
= true;
273 if (!filter_first_keypress
|| is_backlight_on(false)
275 || (btn
& BUTTON_REMOTE
)
278 queue_post(&button_queue
, btn
, data
);
281 #else /* no backlight, nothing to skip */
282 queue_post(&button_queue
, btn
, data
);
286 #ifdef HAVE_REMOTE_LCD
287 if(btn
& BUTTON_REMOTE
)
288 remote_backlight_on();
293 #ifdef HAVE_BUTTON_LIGHT
298 reset_poweroff_timer();
307 lastbtn
= btn
& ~(BUTTON_REL
| BUTTON_REPEAT
);
308 #ifdef HAVE_BUTTON_DATA
313 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
314 static void button_boost(bool state
)
316 static bool boosted
= false;
318 if (state
&& !boosted
)
323 else if (!state
&& boosted
)
329 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
331 int button_queue_count( void )
333 return queue_count(&button_queue
);
336 long button_get(bool block
)
338 struct queue_event ev
;
339 int pending_count
= queue_count(&button_queue
);
341 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
342 /* Control the CPU boost trying to keep queue empty. */
343 if (pending_count
== 0)
345 else if (pending_count
> 2)
349 if ( block
|| pending_count
)
351 queue_wait(&button_queue
, &ev
);
354 /* Ignore if the event was too old and for simplicity, just
355 * wait for a new button_get() request. */
356 if (current_tick
- ev
.tick
> MAX_EVENT_AGE
)
359 button_data
= ev
.data
;
366 long button_get_w_tmo(int ticks
)
368 struct queue_event ev
;
370 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
371 /* Be sure to keep boosted state. */
372 if (!queue_empty(&button_queue
))
373 return button_get(true);
378 queue_wait_w_tmo(&button_queue
, &ev
, ticks
);
379 if (ev
.id
== SYS_TIMEOUT
)
382 button_data
= ev
.data
;
386 intptr_t button_get_data(void)
391 void button_init(void)
393 /* Init used objects first */
394 queue_init(&button_queue
, true);
396 #ifdef HAVE_BUTTON_DATA
400 button_init_device();
402 #ifdef HAVE_BUTTON_DATA
404 lastbtn
= button_read(&temp
);
407 lastbtn
= button_read();
410 reset_poweroff_timer();
412 #ifdef HAVE_LCD_BITMAP
415 #ifdef HAVE_BACKLIGHT
416 filter_first_keypress
= false;
417 #ifdef HAVE_REMOTE_LCD
418 remote_filter_first_keypress
= false;
421 #ifdef HAVE_TOUCHSCREEN
422 last_touchscreen_touch
= 0xffff;
424 /* Start polling last */
425 tick_add_task(button_tick
);
428 #ifdef BUTTON_DRIVER_CLOSE
429 void button_close(void)
431 tick_remove_task(button_tick
);
433 #endif /* BUTTON_DRIVER_CLOSE */
437 * helper function to swap LEFT/RIGHT, UP/DOWN (if present), and F1/F3 (Recorder)
439 static int button_flip(int button
)
441 int newbutton
= button
;
443 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
445 ~(BUTTON_LEFT
| BUTTON_RIGHT
446 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
447 | BUTTON_UP
| BUTTON_DOWN
449 #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD)
450 | BUTTON_SCROLL_BACK
| BUTTON_SCROLL_FWD
452 #if CONFIG_KEYPAD == RECORDER_PAD
453 | BUTTON_F1
| BUTTON_F3
455 #if CONFIG_KEYPAD == SANSA_C200_PAD
456 | BUTTON_VOL_UP
| BUTTON_VOL_DOWN
458 #if CONFIG_KEYPAD == PHILIPS_SA9200_PAD
459 | BUTTON_VOL_UP
| BUTTON_VOL_DOWN
460 | BUTTON_NEXT
| BUTTON_PREV
464 if (button
& BUTTON_LEFT
)
465 newbutton
|= BUTTON_RIGHT
;
466 if (button
& BUTTON_RIGHT
)
467 newbutton
|= BUTTON_LEFT
;
468 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
469 if (button
& BUTTON_UP
)
470 newbutton
|= BUTTON_DOWN
;
471 if (button
& BUTTON_DOWN
)
472 newbutton
|= BUTTON_UP
;
474 #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD)
475 if (button
& BUTTON_SCROLL_BACK
)
476 newbutton
|= BUTTON_SCROLL_FWD
;
477 if (button
& BUTTON_SCROLL_FWD
)
478 newbutton
|= BUTTON_SCROLL_BACK
;
480 #if CONFIG_KEYPAD == RECORDER_PAD
481 if (button
& BUTTON_F1
)
482 newbutton
|= BUTTON_F3
;
483 if (button
& BUTTON_F3
)
484 newbutton
|= BUTTON_F1
;
486 #if CONFIG_KEYPAD == SANSA_C200_PAD
487 if (button
& BUTTON_VOL_UP
)
488 newbutton
|= BUTTON_VOL_DOWN
;
489 if (button
& BUTTON_VOL_DOWN
)
490 newbutton
|= BUTTON_VOL_UP
;
492 #if CONFIG_KEYPAD == PHILIPS_SA9200_PAD
493 if (button
& BUTTON_VOL_UP
)
494 newbutton
|= BUTTON_VOL_DOWN
;
495 if (button
& BUTTON_VOL_DOWN
)
496 newbutton
|= BUTTON_VOL_UP
;
497 if (button
& BUTTON_NEXT
)
498 newbutton
|= BUTTON_PREV
;
499 if (button
& BUTTON_PREV
)
500 newbutton
|= BUTTON_NEXT
;
502 #endif /* !SIMULATOR */
507 * set the flip attribute
508 * better only call this when the queue is empty
510 void button_set_flip(bool flip
)
512 if (flip
!= flipped
) /* not the current setting */
514 /* avoid race condition with the button_tick() */
515 int oldlevel
= disable_irq_save();
516 lastbtn
= button_flip(lastbtn
);
518 restore_irq(oldlevel
);
521 #endif /* HAVE_LCD_FLIP */
523 #ifdef HAVE_BACKLIGHT
524 void set_backlight_filter_keypress(bool value
)
526 filter_first_keypress
= value
;
528 #ifdef HAVE_REMOTE_LCD
529 void set_remote_backlight_filter_keypress(bool value
)
531 remote_filter_first_keypress
= value
;
537 * Get button pressed from hardware
539 #ifdef HAVE_BUTTON_DATA
540 static int button_read(int *data
)
542 int btn
= button_read_device(data
);
544 static int button_read(void)
546 int btn
= button_read_device();
552 btn
= button_flip(btn
); /* swap upside down */
553 #endif /* HAVE_LCD_FLIP */
555 #ifdef HAVE_TOUCHSCREEN
556 if (btn
& BUTTON_TOUCHSCREEN
)
557 last_touchscreen_touch
= current_tick
;
559 /* Filter the button status. It is only accepted if we get the same
560 status twice in a row. */
561 #ifndef HAVE_TOUCHSCREEN
562 if (btn
!= last_read
)
572 int button_status(void)
577 #ifdef HAVE_BUTTON_DATA
578 int button_status_wdata(int *pdata
)
585 void button_clear_queue(void)
587 queue_clear(&button_queue
);
590 #ifdef HAVE_TOUCHSCREEN
591 int touchscreen_last_touch(void)
593 return last_touchscreen_touch
;
597 #ifdef HAVE_WHEEL_ACCELERATION
598 /* WHEEL_ACCEL_FACTOR = 2^16 / WHEEL_ACCEL_START */
599 #define WHEEL_ACCEL_FACTOR (1<<16)/WHEEL_ACCEL_START
602 * [31] Use acceleration
603 * [30:24] Message post count (skipped + 1) (1-127)
604 * [23:0] Velocity - degree/sec
606 * WHEEL_ACCEL_FACTOR:
607 * Value in degree/sec -- configurable via settings -- above which
608 * the accelerated scrolling starts. Factor is internally scaled by
609 * 1<<16 in respect to the following 32bit integer operations.
611 int button_apply_acceleration(const unsigned int data
)
613 int delta
= (data
>> 24) & 0x7f;
615 if ((data
& (1 << 31)) != 0)
617 /* read driver's velocity from data */
618 unsigned int v
= data
& 0xffffff;
620 /* v = 28.4 fixed point */
621 v
= (WHEEL_ACCEL_FACTOR
* v
)>>(16-4);
623 /* Calculate real numbers item to scroll based upon acceleration
624 * setting, use correct roundoff */
625 #if (WHEEL_ACCELERATION == 1)
626 v
= (v
*v
+ (1<< 7))>> 8;
627 #elif (WHEEL_ACCELERATION == 2)
628 v
= (v
*v
*v
+ (1<<11))>>12;
629 #elif (WHEEL_ACCELERATION == 3)
630 v
= (v
*v
*v
*v
+ (1<<15))>>16;
639 #endif /* HAVE_WHEEL_ACCELERATION */