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 }
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)