kbd.c
Go to the documentation of this file.
00001
00043 #include "hw/hw_kbd.h"
00044
00045 #include "cfg/cfg_kbd.h"
00046 #include <cfg/debug.h>
00047 #include <cfg/module.h>
00048
00049 #include <drv/timer.h>
00050 #include <mware/event.h>
00051 #include <drv/kbd.h>
00052
00053
00054 /* Configuration sanity checks */
00055 #if !defined(CONFIG_KBD_POLL) || (CONFIG_KBD_POLL != KBD_POLL_SOFTINT)
00056     #error CONFIG_KBD_POLL must be defined to either KBD_POLL_SOFTINT
00057 #endif
00058 #if !defined(CONFIG_KBD_BEEP) || (CONFIG_KBD_BEEP != 0 && CONFIG_KBD_BEEP != 1)
00059     #error CONFIG_KBD_BEEP must be defined to either 0 or 1
00060 #endif
00061 #if !defined(CONFIG_KBD_OBSERVER) || (CONFIG_KBD_OBSERVER != 0 && CONFIG_KBD_OBSERVER != 1)
00062     #error CONFIG_KBD_OBSERVER must be defined to either 0 or 1
00063 #endif
00064 #if !defined(CONFIG_KBD_LONGPRESS) || (CONFIG_KBD_LONGPRESS != 0 && CONFIG_KBD_LONGPRESS != 1)
00065     #error CONFIG_KBD_LONGPRESS must be defined to either 0 or 1
00066 #endif
00067 
00068 #if CONFIG_KBD_BEEP
00069     #include <drv/buzzer.h>
00070 #endif
00071 
00072 #define KBD_CHECK_INTERVAL  10  
00073 #define KBD_DEBOUNCE_TIME   30  
00074 #define KBD_BEEP_TIME        5  
00076 #define KBD_REPEAT_DELAY   400  
00077 #define KBD_REPEAT_RATE    100  
00078 #define KBD_REPEAT_MAXRATE  20  
00079 #define KBD_REPEAT_ACCEL     5  
00081 #define KBD_LNG_DELAY     1000  
00085 static enum { KS_IDLE, KS_REPDELAY, KS_REPEAT } kbd_rptStatus;
00086 
00088 static Event key_pressed;
00089
00090 static volatile keymask_t kbd_buf;
00091 static volatile keymask_t kbd_cnt;
00092 static keymask_t kbd_rpt_mask;
00094 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00095 static Timer kbd_timer;
00096 #endif
00097 
00098 static List kbd_rawHandlers;
00099 static List kbd_handlers;
00101 static KbdHandler kbd_defHandler;
00102 static KbdHandler kbd_debHandler;
00103 static KbdHandler kbd_rptHandler;
00105 #if CONFIG_KBD_LONGPRESS
00106 static KbdHandler kbd_lngHandler;
00107 #endif
00108 
00109 #if CONFIG_KBD_OBSERVER
00110     #include <mware/observer.h>
00111     Subject kbd_subject;
00112 #endif
00113 
00114
00124 static void kbd_poll(void)
00125 {
00127     static keymask_t current_key;
00128
00129     struct KbdHandler *handler;
00130     keymask_t key = kbd_readkeys();
00131
00132     /* Call raw input handlers */
00133     FOREACH_NODE(handler, &kbd_rawHandlers)
00134         key = handler->hook(key);
00135
00136     /* If this key was not previously pressed */
00137     if (key != current_key)
00138     {
00139         /* Remember last key */
00140         current_key = key;
00141
00142         /* Call cooked input handlers */
00143         FOREACH_NODE(handler, &kbd_handlers)
00144             key = handler->hook(key);
00145     }
00146 }
00147
00148 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00149 
00153 static void kbd_softint(UNUSED_ARG(iptr_t, arg))
00154 {
00155     kbd_poll();
00156     timer_add(&kbd_timer);
00157 }
00158
00159 #else
00160     #error "Define keyboard poll method"
00161 
00162 #endif /* CONFIG_KBD_POLL */
00163
00178 keymask_t kbd_peek(void)
00179 {
00180     return kbd_peekMask((keymask_t)0xFFFFFFFFFFFFFFFFULL);
00181 }
00182
00183
00184 keymask_t kbd_peekMask(keymask_t mask)
00185 {
00186     keymask_t key = 0;
00187
00188 #if CONFIG_KBD_SCHED
00189     /* Let other tasks run for a while */
00190     extern void schedule(void);
00191     schedule();
00192 #endif
00193 
00194     /* Extract an event from the keyboard buffer */
00195     IRQ_DISABLE;
00196     if (kbd_cnt && (kbd_buf & mask))
00197     {
00198         key = kbd_buf & mask;
00199         kbd_buf &= ~mask;
00200         if (!kbd_buf)
00201             --kbd_cnt;
00202     }
00203     IRQ_ENABLE;
00204
00205     return key;
00206 }
00207
00213 keymask_t kbd_get(void)
00214 {
00215     return kbd_getMask((keymask_t)0xFFFFFFFFFFFFFFFFULL);
00216 }
00217
00218 keymask_t kbd_getMask(keymask_t mask)
00219 {
00220     keymask_t key;
00221
00222     #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00223         do
00224         {
00225             event_wait(&key_pressed);
00226             key = kbd_peekMask(mask);
00227         }
00228         while (!key);
00229     #else
00230         while (!(key = kbd_peekMask(mask)))
00231             cpu_relax();
00232     #endif
00233 
00234     return key;
00235 }
00236
00237
00243 keymask_t kbd_get_timeout(mtime_t timeout)
00244 {
00245     if (event_waitTimeout(&key_pressed, timeout))
00246         return kbd_peek();
00247     else
00248         return K_TIMEOUT;
00249 }
00250
00251
00252 void kbd_addHandler(struct KbdHandler *handler)
00253 {
00254     KbdHandler *node;
00255     List *list;
00256
00257     cpu_flags_t flags;
00258     IRQ_SAVE_DISABLE(flags);
00259
00260     /* Choose between raw and coocked handlers list */
00261     list = (handler->flags & KHF_RAWKEYS) ?
00262         &kbd_rawHandlers : &kbd_handlers;
00263
00264     /*
00265      * Search for the first node whose priority
00266      * is lower than the timer we want to add.
00267      */
00268     FOREACH_NODE(node,list)
00269         if (node->pri < handler->pri)
00270             break;
00271
00272     /* Enqueue handler in the handlers chain */
00273     INSERT_BEFORE(&handler->link, &node->link);
00274
00275     IRQ_RESTORE(flags);
00276 }
00277
00278
00279 void kbd_remHandler(struct KbdHandler *handler)
00280 {
00281     /* Remove the handler */
00282     ATOMIC(REMOVE(&handler->link));
00283 }
00284
00285
00292 static keymask_t kbd_defHandlerFunc(keymask_t key)
00293 {
00294     if (key)
00295     {
00296         /* Force a single event in kbd buffer */
00297         kbd_buf = key;
00298         kbd_cnt = 1;
00299         #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00300             event_do(&key_pressed);
00301         #endif
00302 
00303         #if CONFIG_KBD_OBSERVER
00304             observer_notify(&kbd_subject, KBD_EVENT_KEY, &key);
00305         #endif
00306 
00307         #if CONFIG_KBD_BEEP
00308             if (!(key & K_REPEAT))
00309                 buz_beep(KBD_BEEP_TIME);
00310         #endif
00311     }
00312
00313     /* Eat all input */
00314     return 0;
00315 }
00316
00320 static keymask_t kbd_debHandlerFunc(keymask_t key)
00321 {
00323     static keymask_t debounce_key;
00324
00326     static ticks_t debounce_time;
00327
00329     static keymask_t new_key;
00330
00331
00332     ticks_t now = timer_clock();
00333
00334     if (key != debounce_key)
00335     {
00336         /* Reset debounce timer */
00337         debounce_key = key;
00338         debounce_time = now;
00339     }
00340     else if ((new_key != debounce_key)
00341         && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
00342     {
00343         new_key = debounce_key;
00344         debounce_time = now;
00345     }
00346
00347     return new_key;
00348 }
00349
00350 #if CONFIG_KBD_LONGPRESS
00351 
00354 static keymask_t kbd_lngHandlerFunc(keymask_t key)
00355 {
00356     static ticks_t start;
00357     ticks_t now = timer_clock();
00358
00359     if (key & K_LNG_MASK)
00360     {
00361         if (now - start > ms_to_ticks(KBD_LNG_DELAY))
00362             key |= K_LONG;
00363     }
00364     else
00365         start = now;
00366     return key;
00367 }
00368 #endif
00369 
00373 keymask_t kbd_setRepeatMask(keymask_t mask)
00374 {
00375     keymask_t oldmask = kbd_rpt_mask;
00376     ATOMIC(kbd_rpt_mask = mask);
00377     return oldmask;
00378 }
00379
00383 static keymask_t kbd_rptHandlerFunc(keymask_t key)
00384 {
00385     /* Timer for keyboard repeat events. */
00386     static ticks_t repeat_time;
00387
00388     /* Current repeat rate (for acceleration). */
00389     static ticks_t repeat_rate;
00391     ticks_t now = timer_clock();
00392
00393     switch (kbd_rptStatus)
00394     {
00395         case KS_IDLE:
00396             if (key & kbd_rpt_mask)
00397             {
00398                 repeat_time = now;
00399                 kbd_rptStatus = KS_REPDELAY;
00400             }
00401             break;
00402
00403         case KS_REPDELAY:
00404             if (key & kbd_rpt_mask)
00405             {
00406                 if (now - repeat_time > ms_to_ticks(KBD_REPEAT_DELAY))
00407                 {
00408                     key = (key & kbd_rpt_mask) | K_REPEAT;
00409                     repeat_time = now;
00410                     repeat_rate = ms_to_ticks(KBD_REPEAT_RATE);
00411                     kbd_rptStatus = KS_REPEAT;
00412                 }
00413                 else
00414                     key = 0;
00415             }
00416             else
00417                 kbd_rptStatus = KS_IDLE;
00418             break;
00419
00420         case KS_REPEAT:
00421             if (key & kbd_rpt_mask)
00422             {
00423                 if (now - repeat_time > repeat_rate)
00424                 {
00425                     /* Enqueue a new event in the buffer */
00426                     key = (key & kbd_rpt_mask) | K_REPEAT;
00427                     repeat_time = now;
00428
00429                     /* Repeat rate acceleration */
00430                     if (repeat_rate > ms_to_ticks(KBD_REPEAT_MAXRATE))
00431                         repeat_rate -= ms_to_ticks(KBD_REPEAT_ACCEL);
00432                 }
00433                 else
00434                     key = 0;
00435             }
00436             else
00437                 kbd_rptStatus = KS_IDLE;
00438
00439             break;
00440     }
00441
00442     return key;
00443 }
00444
00445
00446 MOD_DEFINE(kbd)
00447
00448
00451 void kbd_init(void)
00452 {
00453 #if CONFIG_KBD_BEEP
00454     MOD_CHECK(buzzer);
00455 #endif
00456 
00457     KBD_HW_INIT;
00458
00459     /* Init handlers lists */
00460     LIST_INIT(&kbd_handlers);
00461     LIST_INIT(&kbd_rawHandlers);
00462
00463     /* Add debounce keyboard handler */
00464     kbd_debHandler.hook = kbd_debHandlerFunc;
00465     kbd_debHandler.pri = 100; /* high priority */
00466     kbd_debHandler.flags = KHF_RAWKEYS;
00467     kbd_addHandler(&kbd_debHandler);
00468
00469     #if CONFIG_KBD_LONGPRESS
00470     /* Add long pression keyboard handler */
00471     kbd_lngHandler.hook = kbd_lngHandlerFunc;
00472     kbd_lngHandler.pri = 90; /* high priority */
00473     kbd_lngHandler.flags = KHF_RAWKEYS;
00474     kbd_addHandler(&kbd_lngHandler);
00475     #endif
00476 
00477     /* Add repeat keyboard handler */
00478     kbd_rptHandler.hook = kbd_rptHandlerFunc;
00479     kbd_rptHandler.pri = 80; /* high priority */
00480     kbd_rptHandler.flags = KHF_RAWKEYS;
00481     kbd_addHandler(&kbd_rptHandler);
00482
00483     /* Add default keyboard handler */
00484     kbd_defHandler.hook = kbd_defHandlerFunc;
00485     kbd_defHandler.pri = -128; /* lowest priority */
00486     kbd_addHandler(&kbd_defHandler);
00487
00488 #if CONFIG_KBD_OBSERVER
00489     observer_InitSubject(&kbd_subject);
00490 #endif
00491 
00492 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00493 
00494     MOD_CHECK(timer);
00495     #if CONFIG_KERN
00496         MOD_CHECK(proc);
00497     #endif
00498 
00499     /* Initialize the keyboard event (key pressed) */
00500     event_initGeneric(&key_pressed);
00501
00502     /* Add kbd handler to soft timers list */
00503     event_initSoftint(&kbd_timer.expire, kbd_softint, NULL);
00504     timer_setDelay(&kbd_timer, ms_to_ticks(KBD_CHECK_INTERVAL));
00505     timer_add(&kbd_timer);
00506
00507 #else
00508     #error "Define keyboard poll method"
00509 
00510 #endif
00511 
00512     MOD_INIT(kbd);
00513 }