4 * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
5 * Copyright 1999, 2003 Bernardo Innocenti
6 * This file is part of DevLib - See README.devlib for information.
11 * \author Bernardo Innocenti <bernie@develer.com>
12 * \author Stefano Fedrigo <aleph@develer.com>
13 * \author Francesco Sacchi <batt@develer.com>
15 * \brief Keyboard driver (implementation)
20 *#* Revision 1.3 2006/02/17 21:15:42 bernie
21 *#* Add MOD_CHECK() checks.
23 *#* Revision 1.2 2006/02/10 12:36:20 bernie
24 *#* Add preliminary FreeRTOS support; Enforce CONFIG_* definitions.
26 *#* Revision 1.1 2005/06/27 21:28:45 bernie
27 *#* Import generic keyboard driver.
33 #include <drv/timer.h>
35 #include <drv/buzzer.h>
37 #include <cfg/debug.h>
38 #include <cfg/module.h>
40 /* Configuration sanity checks */
41 #if !defined(CONFIG_KBD_POLL) || (CONFIG_KBD_POLL != KBD_POLL_SOFTINT && CONFIG_KBD_POLL != CONFIG_POLL_FREERTOS)
42 #error CONFIG_KBD_POLL must be defined to either KBD_POLL_SOFTINT or CONFIG_POLL_FREERTOS
46 #define KBD_CHECK_INTERVAL 10 /*!< (ms) Timing for kbd softint */
47 #define KBD_DEBOUNCE_TIME 30 /*!< (ms) Debounce time */
48 #define KBD_BEEP_TIME 5 /*!< (ms) Duration of keybeep */
50 #define KBD_REPEAT_DELAY 400 /*!< (ms) Keyboard repeat delay for first character */
51 #define KBD_REPEAT_RATE 100 /*!< (ms) Initial interchar delay for keyboard repeat */
52 #define KBD_REPEAT_MAXRATE 20 /*!< (ms) Minimum delay for keyboard repeat */
53 #define KBD_REPEAT_ACCEL 5 /*!< (ms) Keyboard repeat speed increase */
55 #define KBD_LNG_DELAY 1000 /*!< (ms) Keyboard long pression keys delay */
58 /*! Status for keyboard repeat state machine */
59 static enum { KS_IDLE, KS_REPDELAY, KS_REPEAT } kbd_rptStatus;
62 static volatile keymask_t kbd_buf; /*!< Single entry keyboard buffer */
63 static volatile keymask_t kbd_cnt; /*!< Number of keypress events in \c kbd_buf */
65 static Timer kbd_timer; /*!< Keyboard softtimer */
67 static List kbd_rawHandlers; /*!< Raw keyboard handlers */
68 static List kbd_handlers; /*!< Cooked keyboard handlers */
70 static KbdHandler kbd_defHandler; /*!< The default keyboard handler */
71 static KbdHandler kbd_debHandler; /*!< The debounce keyboard handler */
72 static KbdHandler kbd_rptHandler; /*!< Auto-repeat keyboard handler */
74 static KbdHandler kbd_lngHandler; /*!< Long pression keys handler */
80 * Poll keyboard and dispatch keys to handlers.
82 * Read the key states and invoke all keyboard
83 * handlers to process the new state.
85 * Call this function periodically using a software
86 * timer, an interrupt or a process.
88 static void kbd_poll(void)
90 /*! Currently depressed key */
91 static keymask_t current_key;
93 struct KbdHandler *handler;
94 keymask_t key = kbd_readkeys();
96 /* Call raw input handlers */
97 FOREACHNODE(handler, &kbd_rawHandlers)
98 key = handler->hook(key);
100 /* If this key was not previously pressed */
101 if (key != current_key)
103 /* Remember last key */
106 /* Call cooked input handlers */
107 FOREACHNODE(handler, &kbd_handlers)
108 key = handler->hook(key);
112 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
115 * Keyboard soft-irq handler.
117 static void kbd_softint(UNUSED_ARG(iptr_t, arg))
120 timer_add(&kbd_timer);
123 #elif CONFIG_KBD_POLL == CONFIG_POLL_FREERTOS
125 #include "FreeRTOS.h"
128 static portTASK_FUNCTION(kbd_poll, arg)
133 timer_delay(KBD_CHECK_INTERVAL);
137 #endif /* CONFIG_KBD_POLL */
140 * \brief Read a key from the keyboard buffer.
142 * When a key is kept depressed between calls of this function a value
143 * is returned only after the time specified with KBD_REPAT_DELAY to
144 * avoid too fast keyboard repeat.
146 * \note This function is \b not interrupt safe!
148 * \return The mask of depressed keys or 0 if no keys are depressed.
151 keymask_t kbd_peek(void)
156 extern void schedule(void);
159 /* Extract an event from the keyboard buffer */
173 * Wait for a keypress and return the mask of depressed keys.
175 * \note This function is \b not interrupt safe!
177 keymask_t kbd_get(void)
181 while (!(key = kbd_peek())) {}
187 * Wait up to \c timeout ms for a keypress
188 * and return the mask of depressed keys, or K_TIMEOUT
189 * if the timeout was reacked.
191 keymask_t kbd_get_timeout(mtime_t timeout)
195 ticks_t start = timer_clock();
196 ticks_t stop = ms_to_ticks(timeout);
199 if ((key = kbd_peek()))
202 while (timer_clock() - start < stop);
208 void kbd_addHandler(struct KbdHandler *handler)
214 IRQ_SAVE_DISABLE(flags);
216 /* Choose between raw and coocked handlers list */
217 list = (handler->flags & KHF_RAWKEYS) ?
218 &kbd_rawHandlers : &kbd_handlers;
221 * Search for the first node whose priority
222 * is lower than the timer we want to add.
224 FOREACHNODE(node,list)
225 if (node->pri < handler->pri)
228 /* Enqueue handler in the handlers chain */
229 INSERTBEFORE(&handler->link, &node->link);
235 void kbd_remHandler(struct KbdHandler *handler)
237 /* Remove the handler */
238 ATOMIC(REMOVE(&handler->link));
243 * This is the default key handler, called after
244 * all other handlers have had their chance to
245 * do their special processing. This handler
246 * pushes all input in the keyboard FIFO buffer.
248 static keymask_t kbd_defHandlerFunc(keymask_t key)
252 /* Force a single event in kbd buffer */
257 if (!(key & K_REPEAT))
258 buz_beep(KBD_BEEP_TIME);
267 * Handle keyboard debounce
269 static keymask_t kbd_debHandlerFunc(keymask_t key)
271 /*! Buffer for debounce */
272 static keymask_t debounce_key;
274 /*! Timer for keyboard debounce */
275 static ticks_t debounce_time;
277 /*! Key aquired after debounce */
278 static keymask_t new_key;
281 ticks_t now = timer_clock();
283 if (key != debounce_key)
285 /* Reset debounce timer */
289 else if ((new_key != debounce_key)
290 && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
292 new_key = debounce_key;
301 * Handle long pression keys
303 static keymask_t kbd_lngHandlerFunc(keymask_t key)
306 ticks_t now = timer_clock();
308 if (key & K_LNG_MASK)
316 stop = now + ms_to_ticks(KBD_LNG_DELAY);
322 * Handle keyboard repeat
324 static keymask_t kbd_rptHandlerFunc(keymask_t key)
326 /*! Timer for keyboard repeat events */
327 static ticks_t repeat_time;
329 static ticks_t repeat_rate; /*! Current repeat rate (for acceleration) */
331 ticks_t now = timer_clock();
333 switch (kbd_rptStatus)
336 if (key & K_RPT_MASK)
339 kbd_rptStatus = KS_REPDELAY;
344 if (key & K_RPT_MASK)
346 if (now - repeat_time > ms_to_ticks(KBD_REPEAT_DELAY))
348 key = (key & K_RPT_MASK) | K_REPEAT;
350 repeat_rate = ms_to_ticks(KBD_REPEAT_RATE);
351 kbd_rptStatus = KS_REPEAT;
357 kbd_rptStatus = KS_IDLE;
361 if (key & K_RPT_MASK)
363 if (now - repeat_time > repeat_rate)
365 /* Enqueue a new event in the buffer */
366 key = (key & K_RPT_MASK) | K_REPEAT;
369 /* Repeat rate acceleration */
370 if (repeat_rate > ms_to_ticks(KBD_REPEAT_MAXRATE))
371 repeat_rate -= ms_to_ticks(KBD_REPEAT_ACCEL);
377 kbd_rptStatus = KS_IDLE;
389 * Initialize keyboard ports and softtimer
397 /* Init handlers lists */
398 LIST_INIT(&kbd_handlers);
399 LIST_INIT(&kbd_rawHandlers);
401 /* Add debounce keyboard handler */
402 kbd_debHandler.hook = kbd_debHandlerFunc;
403 kbd_debHandler.pri = 100; /* high priority */
404 kbd_debHandler.flags = KHF_RAWKEYS;
405 kbd_addHandler(&kbd_debHandler);
408 /* Add long pression keyboard handler */
409 kbd_lngHandler.hook = kbd_lngHandlerFunc;
410 kbd_lngHandler.pri = 90; /* high priority */
411 kbd_lngHandler.flags = KHF_RAWKEYS;
412 kbd_addHandler(&kbd_lngHandler);
415 /* Add repeat keyboard handler */
416 kbd_rptHandler.hook = kbd_rptHandlerFunc;
417 kbd_rptHandler.pri = 80; /* high priority */
418 kbd_rptHandler.flags = KHF_RAWKEYS;
419 kbd_addHandler(&kbd_rptHandler);
421 /* Add default keyboard handler */
422 kbd_defHandler.hook = kbd_defHandlerFunc;
423 kbd_defHandler.pri = -128; /* lowest priority */
424 kbd_addHandler(&kbd_defHandler);
426 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
430 /* Add kbd handler to soft timers list */
431 event_initSoftInt(&kbd_timer.expire, kbd_softint, 0);
432 timer_setDelay(&kbd_timer, ms_to_ticks(KBD_CHECK_INTERVAL));
433 timer_add(&kbd_timer);
435 #elif CONFIG_KBD_POLL == CONFIG_POLL_FREERTOS
437 /* Create a timer specific thread */
438 xTaskCreate(kbd_poll, "kbd_poll", CONFIG_STACK_KBD,
439 NULL, CONFIG_PRI_KBD, NULL);
442 #error "Define keyboard poll method"