1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Daniel Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 * Rockbox button functions
30 #include "backlight.h"
33 #include "powermgmt.h"
34 #include "button-target.h"
36 #ifdef HAVE_REMOTE_LCD
37 #include "lcd-remote.h"
41 /* Older than MAX_EVENT_AGE button events are going to be ignored.
42 * Used to prevent for example volume going up uncontrollable when events
43 * are getting queued and UI is lagging too much.
45 #define MAX_EVENT_AGE HZ
48 struct event_queue button_queue
;
50 static long lastbtn
; /* Last valid button status */
51 static long last_read
; /* Last button status, for debouncing/filtering */
52 static intptr_t button_data
; /* data value from last message dequeued */
53 #ifdef HAVE_LCD_BITMAP
54 static bool flipped
; /* buttons can be flipped to match the LCD flip */
57 static bool filter_first_keypress
;
58 #ifdef HAVE_REMOTE_LCD
59 static bool remote_filter_first_keypress
;
61 #endif /* HAVE_BACKLIGHT */
62 #ifdef HAVE_HEADPHONE_DETECTION
63 bool phones_present
= false;
66 /* how long until repeat kicks in, in ticks */
67 #define REPEAT_START 30
69 /* the speed repeat starts at, in ticks */
70 #define REPEAT_INTERVAL_START 16
72 /* speed repeat finishes at, in ticks */
73 #define REPEAT_INTERVAL_FINISH 5
75 static int button_read(void);
77 static void button_tick(void)
80 static int repeat_speed
= REPEAT_INTERVAL_START
;
81 static int repeat_count
= 0;
82 static bool repeat
= false;
83 static bool post
= false;
85 static bool skip_release
= false;
86 #ifdef HAVE_REMOTE_LCD
87 static bool skip_remote_release
= false;
93 #ifdef HAS_SERIAL_REMOTE
94 /* Post events for the remote control */
95 btn
= remote_control_rx();
98 queue_post(&button_queue
, btn
, 0);
102 #ifdef HAVE_HEADPHONE_DETECTION
103 if ( headphones_inserted() )
105 if (! phones_present
)
107 queue_post(&button_queue
, SYS_PHONE_PLUGGED
, 0);
108 phones_present
= true;
111 if ( phones_present
)
113 queue_post(&button_queue
, SYS_PHONE_UNPLUGGED
, 0);
114 phones_present
= false;
121 /* Find out if a key has been released */
122 diff
= btn
^ lastbtn
;
123 if(diff
&& (btn
& diff
) == 0)
125 #ifdef HAVE_BACKLIGHT
126 #ifdef HAVE_REMOTE_LCD
127 if(diff
& BUTTON_REMOTE
)
128 if(!skip_remote_release
)
129 queue_post(&button_queue
, BUTTON_REL
| diff
, 0);
131 skip_remote_release
= false;
135 queue_post(&button_queue
, BUTTON_REL
| diff
, 0);
137 skip_release
= false;
139 queue_post(&button_queue
, BUTTON_REL
| diff
, 0);
146 /* normal keypress */
147 if ( btn
!= lastbtn
)
151 repeat_speed
= REPEAT_INTERVAL_START
;
161 /* yes we have repeat */
162 if (repeat_speed
> REPEAT_INTERVAL_FINISH
)
164 count
= repeat_speed
;
168 /* Send a SYS_POWEROFF event if we have a device
169 which doesn't shut down easily with the OFF
171 #ifdef HAVE_SW_POWEROFF
172 if ((btn
== POWEROFF_BUTTON
173 #ifdef RC_POWEROFF_BUTTON
174 || btn
== RC_POWEROFF_BUTTON
177 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
178 !charger_inserted() &&
180 repeat_count
> POWEROFF_COUNT
)
182 /* Tell the main thread that it's time to
186 /* Safety net for players without hardware
188 if(repeat_count
> POWEROFF_COUNT
* 10)
196 if (count
++ > REPEAT_START
)
202 count
= REPEAT_INTERVAL_START
;
210 /* Only post repeat events if the queue is empty,
211 * to avoid afterscroll effects. */
212 if (queue_empty(&button_queue
))
214 queue_post(&button_queue
, BUTTON_REPEAT
| btn
, 0);
215 #ifdef HAVE_BACKLIGHT
216 #ifdef HAVE_REMOTE_LCD
217 skip_remote_release
= false;
219 skip_release
= false;
226 #ifdef HAVE_BACKLIGHT
227 #ifdef HAVE_REMOTE_LCD
228 if (btn
& BUTTON_REMOTE
) {
229 if (!remote_filter_first_keypress
|| is_remote_backlight_on()
230 #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
231 || (remote_type()==REMOTETYPE_H300_NONLCD
)
234 queue_post(&button_queue
, btn
, 0);
236 skip_remote_release
= true;
240 if (!filter_first_keypress
|| is_backlight_on()
242 || (btn
&BUTTON_REMOTE
)
245 queue_post(&button_queue
, btn
, 0);
248 #else /* no backlight, nothing to skip */
249 queue_post(&button_queue
, btn
, 0);
253 #ifdef HAVE_REMOTE_LCD
254 if(btn
& BUTTON_REMOTE
)
255 remote_backlight_on();
260 reset_poweroff_timer();
269 lastbtn
= btn
& ~(BUTTON_REL
| BUTTON_REPEAT
);
272 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
273 static void button_boost(bool state
)
275 static bool boosted
= false;
277 if (state
&& !boosted
)
282 else if (!state
&& boosted
)
288 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
290 long button_get(bool block
)
293 int pending_count
= queue_count(&button_queue
);
295 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
296 /* Control the CPU boost trying to keep queue empty. */
297 if (pending_count
== 0)
299 else if (pending_count
> 2)
303 if ( block
|| pending_count
)
305 queue_wait(&button_queue
, &ev
);
308 /* Ignore if the event was too old and for simplicity, just
309 * wait for a new button_get() request. */
310 if (current_tick
- ev
.tick
> MAX_EVENT_AGE
)
313 button_data
= ev
.data
;
320 long button_get_w_tmo(int ticks
)
324 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
325 /* Be sure to keep boosted state. */
326 if (!queue_empty(&button_queue
))
327 return button_get(true);
332 queue_wait_w_tmo(&button_queue
, &ev
, ticks
);
333 if (ev
.id
== SYS_TIMEOUT
)
336 button_data
= ev
.data
;
341 intptr_t button_get_data(void)
346 void button_init(void)
349 button_init_device();
351 queue_init(&button_queue
, true);
353 /* Enable less protection which would kill IRQ handler. Writing queue is
354 * no longer core-wise thread safe. */
355 queue_set_irq_safe(&button_queue
, true);
358 lastbtn
= button_read();
359 tick_add_task(button_tick
);
360 reset_poweroff_timer();
362 #ifdef HAVE_LCD_BITMAP
365 #ifdef HAVE_BACKLIGHT
366 filter_first_keypress
= false;
367 #ifdef HAVE_REMOTE_LCD
368 remote_filter_first_keypress
= false;
373 #ifdef HAVE_LCD_BITMAP /* only bitmap displays can be flipped */
375 * helper function to swap LEFT/RIGHT, UP/DOWN (if present), and F1/F3 (Recorder)
377 static int button_flip(int button
)
382 ~(BUTTON_LEFT
| BUTTON_RIGHT
383 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
384 | BUTTON_UP
| BUTTON_DOWN
386 #if defined(BUTTON_SCROLL_UP) && defined(BUTTON_SCROLL_DOWN)
387 | BUTTON_SCROLL_UP
| BUTTON_SCROLL_DOWN
389 #if CONFIG_KEYPAD == RECORDER_PAD
390 | BUTTON_F1
| BUTTON_F3
394 if (button
& BUTTON_LEFT
)
395 newbutton
|= BUTTON_RIGHT
;
396 if (button
& BUTTON_RIGHT
)
397 newbutton
|= BUTTON_LEFT
;
398 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
399 if (button
& BUTTON_UP
)
400 newbutton
|= BUTTON_DOWN
;
401 if (button
& BUTTON_DOWN
)
402 newbutton
|= BUTTON_UP
;
404 #if defined(BUTTON_SCROLL_UP) && defined(BUTTON_SCROLL_DOWN)
405 if (button
& BUTTON_SCROLL_UP
)
406 newbutton
|= BUTTON_SCROLL_DOWN
;
407 if (button
& BUTTON_SCROLL_DOWN
)
408 newbutton
|= BUTTON_SCROLL_UP
;
410 #if CONFIG_KEYPAD == RECORDER_PAD
411 if (button
& BUTTON_F1
)
412 newbutton
|= BUTTON_F3
;
413 if (button
& BUTTON_F3
)
414 newbutton
|= BUTTON_F1
;
421 * set the flip attribute
422 * better only call this when the queue is empty
424 void button_set_flip(bool flip
)
426 if (flip
!= flipped
) /* not the current setting */
428 /* avoid race condition with the button_tick() */
429 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
430 lastbtn
= button_flip(lastbtn
);
432 set_irq_level(oldlevel
);
435 #endif /* HAVE_LCD_BITMAP */
437 #ifdef HAVE_BACKLIGHT
438 void set_backlight_filter_keypress(bool value
)
440 filter_first_keypress
= value
;
442 #ifdef HAVE_REMOTE_LCD
443 void set_remote_backlight_filter_keypress(bool value
)
445 remote_filter_first_keypress
= value
;
451 * Get button pressed from hardware
453 static int button_read(void)
455 int btn
= button_read_device();
458 #ifdef HAVE_LCD_BITMAP
460 btn
= button_flip(btn
); /* swap upside down */
463 /* Filter the button status. It is only accepted if we get the same
464 status twice in a row. */
465 if (btn
!= last_read
)
475 int button_status(void)
480 void button_clear_queue(void)
482 queue_clear(&button_queue
);
485 #ifdef HAVE_SCROLLWHEEL
488 * [31] Use acceleration
489 * [30:24] Message post count (skipped + 1) (1-127)
490 * [23:0] Velocity - clicks/uS - 0.24 fixed point
493 * Wheel acceleration scaling factor - x.24 fixed point -
494 * no greater than what will not overflow 64 bits when multiplied
495 * by the driver's maximum velocity in (clicks/usec)^2 in 0.24
497 int button_apply_acceleration(unsigned int data
, unsigned int factor
)
499 int delta
= (data
>> 24) & 0x7f;
501 if ((data
& (1 << 31)) != 0)
503 unsigned int v
= data
& 0xffffff;
505 v
= factor
* (unsigned long long)v
*v
/ 0xffffffffffffull
;
513 #endif /* HAVE_SCROLLWHEEL */