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"
36 #include "button-target.h"
38 #ifdef HAVE_REMOTE_LCD
39 #include "lcd-remote.h"
44 /* Older than MAX_EVENT_AGE button events are going to be ignored.
45 * Used to prevent for example volume going up uncontrollable when events
46 * are getting queued and UI is lagging too much.
48 #define MAX_EVENT_AGE HZ
51 struct event_queue button_queue
;
53 static long lastbtn
; /* Last valid button status */
54 static long last_read
; /* Last button status, for debouncing/filtering */
55 static intptr_t button_data
; /* data value from last message dequeued */
56 #ifdef HAVE_LCD_BITMAP
57 static bool flipped
; /* buttons can be flipped to match the LCD flip */
60 static bool filter_first_keypress
;
61 #ifdef HAVE_REMOTE_LCD
62 static bool remote_filter_first_keypress
;
64 #endif /* HAVE_BACKLIGHT */
65 #ifdef HAVE_HEADPHONE_DETECTION
66 static bool phones_present
= false;
69 /* how long until repeat kicks in, in ticks */
70 #define REPEAT_START 30
72 /* the speed repeat starts at, in ticks */
73 #define REPEAT_INTERVAL_START 16
75 /* speed repeat finishes at, in ticks */
76 #define REPEAT_INTERVAL_FINISH 5
78 #ifdef HAVE_BUTTON_DATA
79 static int button_read(int *data
);
81 static int button_read(void);
84 #if defined(HAVE_HEADPHONE_DETECTION)
85 static struct timeout hp_detect_timeout
; /* Debouncer for headphone plug/unplug */
86 /* This callback can be used for many different functions if needed -
87 just check to which object tmo points */
88 static bool btn_detect_callback(struct timeout
*tmo
)
90 /* Try to post only transistions */
91 const long id
= tmo
->data
? SYS_PHONE_PLUGGED
: SYS_PHONE_UNPLUGGED
;
92 queue_remove_from_head(&button_queue
, id
);
93 queue_post(&button_queue
, id
, 0);
98 static void button_tick(void)
100 static int count
= 0;
101 static int repeat_speed
= REPEAT_INTERVAL_START
;
102 static int repeat_count
= 0;
103 static bool repeat
= false;
104 static bool post
= false;
105 #ifdef HAVE_BACKLIGHT
106 static bool skip_release
= false;
107 #ifdef HAVE_REMOTE_LCD
108 static bool skip_remote_release
= false;
113 #ifdef HAVE_BUTTON_DATA
119 #ifdef HAS_SERIAL_REMOTE
120 /* Post events for the remote control */
121 btn
= remote_control_rx();
124 queue_post(&button_queue
, btn
, 0);
128 #ifdef HAVE_BUTTON_DATA
129 btn
= button_read(&data
);
134 #if defined(HAVE_HEADPHONE_DETECTION)
135 if (headphones_inserted() != phones_present
)
137 /* Use the autoresetting oneshot to debounce the detection signal */
138 phones_present
= !phones_present
;
139 timeout_register(&hp_detect_timeout
, btn_detect_callback
,
144 /* Find out if a key has been released */
145 diff
= btn
^ lastbtn
;
146 if(diff
&& (btn
& diff
) == 0)
148 #ifdef HAVE_BACKLIGHT
149 #ifdef HAVE_REMOTE_LCD
150 if(diff
& BUTTON_REMOTE
)
151 if(!skip_remote_release
)
152 queue_post(&button_queue
, BUTTON_REL
| diff
, data
);
154 skip_remote_release
= false;
158 queue_post(&button_queue
, BUTTON_REL
| diff
, data
);
160 skip_release
= false;
162 queue_post(&button_queue
, BUTTON_REL
| diff
, data
);
169 /* normal keypress */
170 if ( btn
!= lastbtn
)
174 repeat_speed
= REPEAT_INTERVAL_START
;
184 /* yes we have repeat */
185 if (repeat_speed
> REPEAT_INTERVAL_FINISH
)
187 count
= repeat_speed
;
191 /* Send a SYS_POWEROFF event if we have a device
192 which doesn't shut down easily with the OFF
194 #ifdef HAVE_SW_POWEROFF
195 if ((btn
== POWEROFF_BUTTON
196 #ifdef RC_POWEROFF_BUTTON
197 || btn
== RC_POWEROFF_BUTTON
200 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
201 !charger_inserted() &&
203 repeat_count
> POWEROFF_COUNT
)
205 /* Tell the main thread that it's time to
209 /* Safety net for players without hardware
211 if(repeat_count
> POWEROFF_COUNT
* 10)
219 if (count
++ > REPEAT_START
)
225 count
= REPEAT_INTERVAL_START
;
233 /* Only post repeat events if the queue is empty,
234 * to avoid afterscroll effects. */
235 if (queue_empty(&button_queue
))
237 queue_post(&button_queue
, BUTTON_REPEAT
| btn
, data
);
238 #ifdef HAVE_BACKLIGHT
239 #ifdef HAVE_REMOTE_LCD
240 skip_remote_release
= false;
242 skip_release
= false;
249 #ifdef HAVE_BACKLIGHT
250 #ifdef HAVE_REMOTE_LCD
251 if (btn
& BUTTON_REMOTE
) {
252 if (!remote_filter_first_keypress
253 || is_remote_backlight_on(false)
254 #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
255 || (remote_type()==REMOTETYPE_H300_NONLCD
)
258 queue_post(&button_queue
, btn
, data
);
260 skip_remote_release
= true;
264 if (!filter_first_keypress
|| is_backlight_on(false)
266 || (btn
& BUTTON_REMOTE
)
269 queue_post(&button_queue
, btn
, data
);
272 #else /* no backlight, nothing to skip */
273 queue_post(&button_queue
, btn
, data
);
277 #ifdef HAVE_REMOTE_LCD
278 if(btn
& BUTTON_REMOTE
)
279 remote_backlight_on();
284 #ifdef HAVE_BUTTON_LIGHT
289 reset_poweroff_timer();
298 lastbtn
= btn
& ~(BUTTON_REL
| BUTTON_REPEAT
);
301 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
302 static void button_boost(bool state
)
304 static bool boosted
= false;
306 if (state
&& !boosted
)
311 else if (!state
&& boosted
)
317 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
319 int button_queue_count( void )
321 return queue_count(&button_queue
);
324 long button_get(bool block
)
326 struct queue_event ev
;
327 int pending_count
= queue_count(&button_queue
);
329 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
330 /* Control the CPU boost trying to keep queue empty. */
331 if (pending_count
== 0)
333 else if (pending_count
> 2)
337 if ( block
|| pending_count
)
339 queue_wait(&button_queue
, &ev
);
342 /* Ignore if the event was too old and for simplicity, just
343 * wait for a new button_get() request. */
344 if (current_tick
- ev
.tick
> MAX_EVENT_AGE
)
347 button_data
= ev
.data
;
354 long button_get_w_tmo(int ticks
)
356 struct queue_event ev
;
358 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
359 /* Be sure to keep boosted state. */
360 if (!queue_empty(&button_queue
))
361 return button_get(true);
366 queue_wait_w_tmo(&button_queue
, &ev
, ticks
);
367 if (ev
.id
== SYS_TIMEOUT
)
370 button_data
= ev
.data
;
375 intptr_t button_get_data(void)
380 void button_init(void)
382 /* Init used objects first */
383 queue_init(&button_queue
, true);
385 #ifdef HAVE_BUTTON_DATA
389 button_init_device();
391 #ifdef HAVE_BUTTON_DATA
393 lastbtn
= button_read(&temp
);
396 lastbtn
= button_read();
399 reset_poweroff_timer();
401 #ifdef HAVE_LCD_BITMAP
404 #ifdef HAVE_BACKLIGHT
405 filter_first_keypress
= false;
406 #ifdef HAVE_REMOTE_LCD
407 remote_filter_first_keypress
= false;
411 /* Start polling last */
412 tick_add_task(button_tick
);
415 #ifdef BUTTON_DRIVER_CLOSE
416 void button_close(void)
418 tick_remove_task(button_tick
);
420 #endif /* BUTTON_DRIVER_CLOSE */
422 #ifdef HAVE_LCD_BITMAP /* only bitmap displays can be flipped */
424 * helper function to swap LEFT/RIGHT, UP/DOWN (if present), and F1/F3 (Recorder)
426 static int button_flip(int button
)
431 ~(BUTTON_LEFT
| BUTTON_RIGHT
432 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
433 | BUTTON_UP
| BUTTON_DOWN
435 #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD)
436 | BUTTON_SCROLL_BACK
| BUTTON_SCROLL_FWD
438 #if CONFIG_KEYPAD == RECORDER_PAD
439 | BUTTON_F1
| BUTTON_F3
443 if (button
& BUTTON_LEFT
)
444 newbutton
|= BUTTON_RIGHT
;
445 if (button
& BUTTON_RIGHT
)
446 newbutton
|= BUTTON_LEFT
;
447 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
448 if (button
& BUTTON_UP
)
449 newbutton
|= BUTTON_DOWN
;
450 if (button
& BUTTON_DOWN
)
451 newbutton
|= BUTTON_UP
;
453 #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD)
454 if (button
& BUTTON_SCROLL_BACK
)
455 newbutton
|= BUTTON_SCROLL_FWD
;
456 if (button
& BUTTON_SCROLL_FWD
)
457 newbutton
|= BUTTON_SCROLL_BACK
;
459 #if CONFIG_KEYPAD == RECORDER_PAD
460 if (button
& BUTTON_F1
)
461 newbutton
|= BUTTON_F3
;
462 if (button
& BUTTON_F3
)
463 newbutton
|= BUTTON_F1
;
470 * set the flip attribute
471 * better only call this when the queue is empty
473 void button_set_flip(bool flip
)
475 if (flip
!= flipped
) /* not the current setting */
477 /* avoid race condition with the button_tick() */
478 int oldlevel
= disable_irq_save();
479 lastbtn
= button_flip(lastbtn
);
481 restore_irq(oldlevel
);
484 #endif /* HAVE_LCD_BITMAP */
486 #ifdef HAVE_BACKLIGHT
487 void set_backlight_filter_keypress(bool value
)
489 filter_first_keypress
= value
;
491 #ifdef HAVE_REMOTE_LCD
492 void set_remote_backlight_filter_keypress(bool value
)
494 remote_filter_first_keypress
= value
;
500 * Get button pressed from hardware
502 #ifdef HAVE_BUTTON_DATA
503 static int button_read(int *data
)
505 int btn
= button_read_device(data
);
507 static int button_read(void)
509 int btn
= button_read_device();
513 #ifdef HAVE_LCD_BITMAP
515 btn
= button_flip(btn
); /* swap upside down */
518 /* Filter the button status. It is only accepted if we get the same
519 status twice in a row. */
520 #ifndef HAVE_TOUCHPAD
521 if (btn
!= last_read
)
532 int button_status(void)
537 void button_clear_queue(void)
539 queue_clear(&button_queue
);
542 #endif /* SIMULATOR */
544 #ifdef HAVE_SCROLLWHEEL
545 /* WHEEL_ACCEL_FACTOR = 2^16 / WHEEL_ACCEL_START */
546 #define WHEEL_ACCEL_FACTOR (1<<16)/WHEEL_ACCEL_START
549 * [31] Use acceleration
550 * [30:24] Message post count (skipped + 1) (1-127)
551 * [23:0] Velocity - degree/sec
553 * WHEEL_ACCEL_FACTOR:
554 * Value in degree/sec -- configurable via settings -- above which
555 * the accelerated scrolling starts. Factor is internally scaled by
556 * 1<<16 in respect to the following 32bit integer operations.
558 int button_apply_acceleration(const unsigned int data
)
560 int delta
= (data
>> 24) & 0x7f;
562 if ((data
& (1 << 31)) != 0)
564 /* read driver's velocity from data */
565 unsigned int v
= data
& 0xffffff;
567 /* v = 28.4 fixed point */
568 v
= (WHEEL_ACCEL_FACTOR
* v
)>>(16-4);
570 /* Calculate real numbers item to scroll based upon acceleration
571 * setting, use correct roundoff */
572 #if (WHEEL_ACCELERATION == 1)
573 v
= (v
*v
+ (1<< 7))>> 8;
574 #elif (WHEEL_ACCELERATION == 2)
575 v
= (v
*v
*v
+ (1<<11))>>12;
576 #elif (WHEEL_ACCELERATION == 3)
577 v
= (v
*v
*v
*v
+ (1<<15))>>16;
586 #endif /* HAVE_SCROLLWHEEL */