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
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
00133 FOREACH_NODE(handler, &kbd_rawHandlers)
00134 key = handler->hook(key);
00135
00136
00137 if (key != current_key)
00138 {
00139
00140 current_key = key;
00141
00142
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
00163
00178 keymask_t kbd_peek(void)
00179 {
00180 keymask_t key = 0;
00181
00182 #if CONFIG_KBD_SCHED
00183
00184 extern void schedule(void);
00185 schedule();
00186 #endif
00187
00188
00189 IRQ_DISABLE;
00190 if (kbd_cnt)
00191 {
00192 --kbd_cnt;
00193 key = kbd_buf;
00194 }
00195 IRQ_ENABLE;
00196
00197 return key;
00198 }
00199
00205 keymask_t kbd_get(void)
00206 {
00207 keymask_t key;
00208
00209 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00210 event_wait(&key_pressed);
00211 key = kbd_peek();
00212 #else
00213 while (!(key = kbd_peek()))
00214 cpu_relax();
00215 #endif
00216
00217 return key;
00218 }
00219
00220
00226 keymask_t kbd_get_timeout(mtime_t timeout)
00227 {
00228 if (event_waitTimeout(&key_pressed, timeout))
00229 return kbd_peek();
00230 else
00231 return K_TIMEOUT;
00232 }
00233
00234
00235 void kbd_addHandler(struct KbdHandler *handler)
00236 {
00237 KbdHandler *node;
00238 List *list;
00239
00240 cpu_flags_t flags;
00241 IRQ_SAVE_DISABLE(flags);
00242
00243
00244 list = (handler->flags & KHF_RAWKEYS) ?
00245 &kbd_rawHandlers : &kbd_handlers;
00246
00247
00248
00249
00250
00251 FOREACH_NODE(node,list)
00252 if (node->pri < handler->pri)
00253 break;
00254
00255
00256 INSERT_BEFORE(&handler->link, &node->link);
00257
00258 IRQ_RESTORE(flags);
00259 }
00260
00261
00262 void kbd_remHandler(struct KbdHandler *handler)
00263 {
00264
00265 ATOMIC(REMOVE(&handler->link));
00266 }
00267
00268
00275 static keymask_t kbd_defHandlerFunc(keymask_t key)
00276 {
00277 if (key)
00278 {
00279
00280 kbd_buf = key;
00281 kbd_cnt = 1;
00282 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00283 event_do(&key_pressed);
00284 #endif
00285
00286 #if CONFIG_KBD_OBSERVER
00287 observer_notify(&kbd_subject, KBD_EVENT_KEY, &key);
00288 #endif
00289
00290 #if CONFIG_KBD_BEEP
00291 if (!(key & K_REPEAT))
00292 buz_beep(KBD_BEEP_TIME);
00293 #endif
00294 }
00295
00296
00297 return 0;
00298 }
00299
00303 static keymask_t kbd_debHandlerFunc(keymask_t key)
00304 {
00306 static keymask_t debounce_key;
00307
00309 static ticks_t debounce_time;
00310
00312 static keymask_t new_key;
00313
00314
00315 ticks_t now = timer_clock();
00316
00317 if (key != debounce_key)
00318 {
00319
00320 debounce_key = key;
00321 debounce_time = now;
00322 }
00323 else if ((new_key != debounce_key)
00324 && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
00325 {
00326 new_key = debounce_key;
00327 debounce_time = now;
00328 }
00329
00330 return new_key;
00331 }
00332
00333 #if CONFIG_KBD_LONGPRESS
00334
00337 static keymask_t kbd_lngHandlerFunc(keymask_t key)
00338 {
00339 static ticks_t start;
00340 ticks_t now = timer_clock();
00341
00342 if (key & K_LNG_MASK)
00343 {
00344 if (now - start > ms_to_ticks(KBD_LNG_DELAY))
00345 key |= K_LONG;
00346 }
00347 else
00348 start = now;
00349 return key;
00350 }
00351 #endif
00352
00356 keymask_t kbd_setRepeatMask(keymask_t mask)
00357 {
00358 keymask_t oldmask = kbd_rpt_mask;
00359 ATOMIC(kbd_rpt_mask = mask);
00360 return oldmask;
00361 }
00362
00366 static keymask_t kbd_rptHandlerFunc(keymask_t key)
00367 {
00368
00369 static ticks_t repeat_time;
00370
00371
00372 static ticks_t repeat_rate;
00374 ticks_t now = timer_clock();
00375
00376 switch (kbd_rptStatus)
00377 {
00378 case KS_IDLE:
00379 if (key & kbd_rpt_mask)
00380 {
00381 repeat_time = now;
00382 kbd_rptStatus = KS_REPDELAY;
00383 }
00384 break;
00385
00386 case KS_REPDELAY:
00387 if (key & kbd_rpt_mask)
00388 {
00389 if (now - repeat_time > ms_to_ticks(KBD_REPEAT_DELAY))
00390 {
00391 key = (key & kbd_rpt_mask) | K_REPEAT;
00392 repeat_time = now;
00393 repeat_rate = ms_to_ticks(KBD_REPEAT_RATE);
00394 kbd_rptStatus = KS_REPEAT;
00395 }
00396 else
00397 key = 0;
00398 }
00399 else
00400 kbd_rptStatus = KS_IDLE;
00401 break;
00402
00403 case KS_REPEAT:
00404 if (key & kbd_rpt_mask)
00405 {
00406 if (now - repeat_time > repeat_rate)
00407 {
00408
00409 key = (key & kbd_rpt_mask) | K_REPEAT;
00410 repeat_time = now;
00411
00412
00413 if (repeat_rate > ms_to_ticks(KBD_REPEAT_MAXRATE))
00414 repeat_rate -= ms_to_ticks(KBD_REPEAT_ACCEL);
00415 }
00416 else
00417 key = 0;
00418 }
00419 else
00420 kbd_rptStatus = KS_IDLE;
00421
00422 break;
00423 }
00424
00425 return key;
00426 }
00427
00428
00429 MOD_DEFINE(kbd)
00430
00431
00434 void kbd_init(void)
00435 {
00436 #if CONFIG_KBD_BEEP
00437 MOD_CHECK(buzzer);
00438 #endif
00439
00440 KBD_HW_INIT;
00441
00442
00443 LIST_INIT(&kbd_handlers);
00444 LIST_INIT(&kbd_rawHandlers);
00445
00446
00447 kbd_debHandler.hook = kbd_debHandlerFunc;
00448 kbd_debHandler.pri = 100;
00449 kbd_debHandler.flags = KHF_RAWKEYS;
00450 kbd_addHandler(&kbd_debHandler);
00451
00452 #if CONFIG_KBD_LONGPRESS
00453
00454 kbd_lngHandler.hook = kbd_lngHandlerFunc;
00455 kbd_lngHandler.pri = 90;
00456 kbd_lngHandler.flags = KHF_RAWKEYS;
00457 kbd_addHandler(&kbd_lngHandler);
00458 #endif
00459
00460
00461 kbd_rptHandler.hook = kbd_rptHandlerFunc;
00462 kbd_rptHandler.pri = 80;
00463 kbd_rptHandler.flags = KHF_RAWKEYS;
00464 kbd_addHandler(&kbd_rptHandler);
00465
00466
00467 kbd_defHandler.hook = kbd_defHandlerFunc;
00468 kbd_defHandler.pri = -128;
00469 kbd_addHandler(&kbd_defHandler);
00470
00471 #if CONFIG_KBD_OBSERVER
00472 observer_InitSubject(&kbd_subject);
00473 #endif
00474
00475 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00476
00477 MOD_CHECK(timer);
00478 #if CONFIG_KERN
00479 MOD_CHECK(proc);
00480 #endif
00481
00482
00483 event_initGeneric(&key_pressed);
00484
00485
00486 event_initSoftint(&kbd_timer.expire, kbd_softint, NULL);
00487 timer_setDelay(&kbd_timer, ms_to_ticks(KBD_CHECK_INTERVAL));
00488 timer_add(&kbd_timer);
00489
00490 #else
00491 #error "Define keyboard poll method"
00492
00493 #endif
00494
00495 MOD_INIT(kbd);
00496 }