Wheel acceleration for e200. A general acceleration interface intended for use on...
[Rockbox.git] / firmware / drivers / button.c
blob715d4d3025ea030c53c02797931a878d1c851ffd
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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
24 #include <stdlib.h>
25 #include "config.h"
26 #include "system.h"
27 #include "button.h"
28 #include "kernel.h"
29 #include "thread.h"
30 #include "backlight.h"
31 #include "serial.h"
32 #include "power.h"
33 #include "powermgmt.h"
34 #include "button-target.h"
36 #ifdef HAVE_REMOTE_LCD
37 #include "lcd-remote.h"
38 #endif
40 #if 0
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
46 #endif
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 */
55 #endif
56 #ifdef HAVE_BACKLIGHT
57 static bool filter_first_keypress;
58 #ifdef HAVE_REMOTE_LCD
59 static bool remote_filter_first_keypress;
60 #endif
61 #endif /* HAVE_BACKLIGHT */
62 #ifdef HAVE_HEADPHONE_DETECTION
63 bool phones_present = false;
64 #endif
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)
79 static int count = 0;
80 static int repeat_speed = REPEAT_INTERVAL_START;
81 static int repeat_count = 0;
82 static bool repeat = false;
83 static bool post = false;
84 #ifdef HAVE_BACKLIGHT
85 static bool skip_release = false;
86 #ifdef HAVE_REMOTE_LCD
87 static bool skip_remote_release = false;
88 #endif
89 #endif
90 int diff;
91 int btn;
93 #ifdef HAS_SERIAL_REMOTE
94 /* Post events for the remote control */
95 btn = remote_control_rx();
96 if(btn)
98 queue_post(&button_queue, btn, 0);
100 #endif
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;
110 } else {
111 if ( phones_present )
113 queue_post(&button_queue, SYS_PHONE_UNPLUGGED, 0);
114 phones_present = false;
117 #endif
119 btn = button_read();
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);
130 else
131 skip_remote_release = false;
132 else
133 #endif
134 if(!skip_release)
135 queue_post(&button_queue, BUTTON_REL | diff, 0);
136 else
137 skip_release = false;
138 #else
139 queue_post(&button_queue, BUTTON_REL | diff, 0);
140 #endif
142 else
144 if ( btn )
146 /* normal keypress */
147 if ( btn != lastbtn )
149 post = true;
150 repeat = false;
151 repeat_speed = REPEAT_INTERVAL_START;
153 else /* repeat? */
155 if ( repeat )
157 if (!post)
158 count--;
159 if (count == 0) {
160 post = true;
161 /* yes we have repeat */
162 if (repeat_speed > REPEAT_INTERVAL_FINISH)
163 repeat_speed--;
164 count = repeat_speed;
166 repeat_count++;
168 /* Send a SYS_POWEROFF event if we have a device
169 which doesn't shut down easily with the OFF
170 key */
171 #ifdef HAVE_SW_POWEROFF
172 if ((btn == POWEROFF_BUTTON
173 #ifdef RC_POWEROFF_BUTTON
174 || btn == RC_POWEROFF_BUTTON
175 #endif
176 ) &&
177 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
178 !charger_inserted() &&
179 #endif
180 repeat_count > POWEROFF_COUNT)
182 /* Tell the main thread that it's time to
183 power off */
184 sys_poweroff();
186 /* Safety net for players without hardware
187 poweroff */
188 if(repeat_count > POWEROFF_COUNT * 10)
189 power_off();
191 #endif
194 else
196 if (count++ > REPEAT_START)
198 post = true;
199 repeat = true;
200 repeat_count = 0;
201 /* initial repeat */
202 count = REPEAT_INTERVAL_START;
206 if ( post )
208 if (repeat)
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;
218 #endif
219 skip_release = false;
220 #endif
221 post = false;
224 else
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)
232 #endif
234 queue_post(&button_queue, btn, 0);
235 else
236 skip_remote_release = true;
238 else
239 #endif
240 if (!filter_first_keypress || is_backlight_on()
241 #if BUTTON_REMOTE
242 || (btn&BUTTON_REMOTE)
243 #endif
245 queue_post(&button_queue, btn, 0);
246 else
247 skip_release = true;
248 #else /* no backlight, nothing to skip */
249 queue_post(&button_queue, btn, 0);
250 #endif
251 post = false;
253 #ifdef HAVE_REMOTE_LCD
254 if(btn & BUTTON_REMOTE)
255 remote_backlight_on();
256 else
257 #endif
258 backlight_on();
260 reset_poweroff_timer();
263 else
265 repeat = false;
266 count = 0;
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)
279 cpu_boost(true);
280 boosted = true;
282 else if (!state && boosted)
284 cpu_boost(false);
285 boosted = false;
288 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
290 long button_get(bool block)
292 struct event ev;
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)
298 button_boost(false);
299 else if (pending_count > 2)
300 button_boost(true);
301 #endif
303 if ( block || pending_count )
305 queue_wait(&button_queue, &ev);
307 #if 0
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)
311 return BUTTON_NONE;
312 #endif
313 button_data = ev.data;
314 return ev.id;
317 return BUTTON_NONE;
320 long button_get_w_tmo(int ticks)
322 struct event ev;
324 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
325 /* Be sure to keep boosted state. */
326 if (!queue_empty(&button_queue))
327 return button_get(true);
329 button_boost(false);
330 #endif
332 queue_wait_w_tmo(&button_queue, &ev, ticks);
333 if (ev.id == SYS_TIMEOUT)
334 ev.id = BUTTON_NONE;
335 else
336 button_data = ev.data;
338 return ev.id;
341 intptr_t button_get_data(void)
343 return button_data;
346 void button_init(void)
348 /* hardware inits */
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);
357 button_read();
358 lastbtn = button_read();
359 tick_add_task(button_tick);
360 reset_poweroff_timer();
362 #ifdef HAVE_LCD_BITMAP
363 flipped = false;
364 #endif
365 #ifdef HAVE_BACKLIGHT
366 filter_first_keypress = false;
367 #ifdef HAVE_REMOTE_LCD
368 remote_filter_first_keypress = false;
369 #endif
370 #endif
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)
379 int newbutton;
381 newbutton = button &
382 ~(BUTTON_LEFT | BUTTON_RIGHT
383 #if defined(BUTTON_UP) && defined(BUTTON_DOWN)
384 | BUTTON_UP | BUTTON_DOWN
385 #endif
386 #if defined(BUTTON_SCROLL_UP) && defined(BUTTON_SCROLL_DOWN)
387 | BUTTON_SCROLL_UP | BUTTON_SCROLL_DOWN
388 #endif
389 #if CONFIG_KEYPAD == RECORDER_PAD
390 | BUTTON_F1 | BUTTON_F3
391 #endif
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;
403 #endif
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;
409 #endif
410 #if CONFIG_KEYPAD == RECORDER_PAD
411 if (button & BUTTON_F1)
412 newbutton |= BUTTON_F3;
413 if (button & BUTTON_F3)
414 newbutton |= BUTTON_F1;
415 #endif
417 return newbutton;
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);
431 flipped = flip;
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;
447 #endif
448 #endif
451 * Get button pressed from hardware
453 static int button_read(void)
455 int btn = button_read_device();
456 int retval;
458 #ifdef HAVE_LCD_BITMAP
459 if (btn && flipped)
460 btn = button_flip(btn); /* swap upside down */
461 #endif
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)
466 retval = lastbtn;
467 else
468 retval = btn;
469 last_read = btn;
471 return retval;
475 int button_status(void)
477 return lastbtn;
480 void button_clear_queue(void)
482 queue_clear(&button_queue);
485 #ifdef HAVE_SCROLLWHEEL
487 * data:
488 * [31] Use acceleration
489 * [30:24] Message post count (skipped + 1) (1-127)
490 * [23:0] Velocity - clicks/uS - 0.24 fixed point
492 * factor:
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;
507 if (v > 1)
508 delta *= v;
511 return delta;
513 #endif /* HAVE_SCROLLWHEEL */