kbd.c
Go to the documentation of this file.00001
00044 #include "hw/hw_kbd.h"
00045
00046 #include "cfg/cfg_kbd.h"
00047 #include <cfg/debug.h>
00048 #include <cfg/module.h>
00049
00050 #include <drv/timer.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
00087
00088 static volatile keymask_t kbd_buf;
00089 static volatile keymask_t kbd_cnt;
00090 static keymask_t kbd_rpt_mask;
00092 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00093 static Timer kbd_timer;
00094 #endif
00095
00096 static List kbd_rawHandlers;
00097 static List kbd_handlers;
00099 static KbdHandler kbd_defHandler;
00100 static KbdHandler kbd_debHandler;
00101 static KbdHandler kbd_rptHandler;
00103 #if CONFIG_KBD_LONGPRESS
00104 static KbdHandler kbd_lngHandler;
00105 #endif
00106
00107 #if CONFIG_KBD_OBSERVER
00108 #include <mware/observer.h>
00109 Subject kbd_subject;
00110 #endif
00111
00112
00122 static void kbd_poll(void)
00123 {
00125 static keymask_t current_key;
00126
00127 struct KbdHandler *handler;
00128 keymask_t key = kbd_readkeys();
00129
00130
00131 FOREACH_NODE(handler, &kbd_rawHandlers)
00132 key = handler->hook(key);
00133
00134
00135 if (key != current_key)
00136 {
00137
00138 current_key = key;
00139
00140
00141 FOREACH_NODE(handler, &kbd_handlers)
00142 key = handler->hook(key);
00143 }
00144 }
00145
00146 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00147
00151 static void kbd_softint(UNUSED_ARG(iptr_t, arg))
00152 {
00153 kbd_poll();
00154 timer_add(&kbd_timer);
00155 }
00156
00157 #else
00158 #error "Define keyboard poll method"
00159
00160 #endif
00161
00176 keymask_t kbd_peek(void)
00177 {
00178 keymask_t key = 0;
00179
00180 #if CONFIG_KBD_SCHED
00181
00182 extern void schedule(void);
00183 schedule();
00184 #endif
00185
00186
00187 IRQ_DISABLE;
00188 if (kbd_cnt)
00189 {
00190 --kbd_cnt;
00191 key = kbd_buf;
00192 }
00193 IRQ_ENABLE;
00194
00195 return key;
00196 }
00197
00203 keymask_t kbd_get(void)
00204 {
00205 keymask_t key;
00206
00207 while (!(key = kbd_peek())) {}
00208
00209 return key;
00210 }
00211
00212
00218 keymask_t kbd_get_timeout(mtime_t timeout)
00219 {
00220 keymask_t key;
00221
00222 ticks_t start = timer_clock();
00223 ticks_t stop = ms_to_ticks(timeout);
00224 do
00225 {
00226 if ((key = kbd_peek()))
00227 return key;
00228 }
00229 while (timer_clock() - start < stop);
00230
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
00283 #if CONFIG_KBD_OBSERVER
00284 observer_notify(&kbd_subject, KBD_EVENT_KEY, &key);
00285 #endif
00286
00287 #if CONFIG_KBD_BEEP
00288 if (!(key & K_REPEAT))
00289 buz_beep(KBD_BEEP_TIME);
00290 #endif
00291 }
00292
00293
00294 return 0;
00295 }
00296
00300 static keymask_t kbd_debHandlerFunc(keymask_t key)
00301 {
00303 static keymask_t debounce_key;
00304
00306 static ticks_t debounce_time;
00307
00309 static keymask_t new_key;
00310
00311
00312 ticks_t now = timer_clock();
00313
00314 if (key != debounce_key)
00315 {
00316
00317 debounce_key = key;
00318 debounce_time = now;
00319 }
00320 else if ((new_key != debounce_key)
00321 && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
00322 {
00323 new_key = debounce_key;
00324 debounce_time = now;
00325 }
00326
00327 return new_key;
00328 }
00329
00330 #if CONFIG_KBD_LONGPRESS
00331
00334 static keymask_t kbd_lngHandlerFunc(keymask_t key)
00335 {
00336 static ticks_t start;
00337 ticks_t now = timer_clock();
00338
00339 if (key & K_LNG_MASK)
00340 {
00341 if (now - start > ms_to_ticks(KBD_LNG_DELAY))
00342 key |= K_LONG;
00343 }
00344 else
00345 start = now;
00346 return key;
00347 }
00348 #endif
00349
00353 keymask_t kbd_setRepeatMask(keymask_t mask)
00354 {
00355 keymask_t oldmask = kbd_rpt_mask;
00356 ATOMIC(kbd_rpt_mask = mask);
00357 return oldmask;
00358 }
00359
00363 static keymask_t kbd_rptHandlerFunc(keymask_t key)
00364 {
00365
00366 static ticks_t repeat_time;
00367
00368
00369 static ticks_t repeat_rate;
00371 ticks_t now = timer_clock();
00372
00373 switch (kbd_rptStatus)
00374 {
00375 case KS_IDLE:
00376 if (key & kbd_rpt_mask)
00377 {
00378 repeat_time = now;
00379 kbd_rptStatus = KS_REPDELAY;
00380 }
00381 break;
00382
00383 case KS_REPDELAY:
00384 if (key & kbd_rpt_mask)
00385 {
00386 if (now - repeat_time > ms_to_ticks(KBD_REPEAT_DELAY))
00387 {
00388 key = (key & kbd_rpt_mask) | K_REPEAT;
00389 repeat_time = now;
00390 repeat_rate = ms_to_ticks(KBD_REPEAT_RATE);
00391 kbd_rptStatus = KS_REPEAT;
00392 }
00393 else
00394 key = 0;
00395 }
00396 else
00397 kbd_rptStatus = KS_IDLE;
00398 break;
00399
00400 case KS_REPEAT:
00401 if (key & kbd_rpt_mask)
00402 {
00403 if (now - repeat_time > repeat_rate)
00404 {
00405
00406 key = (key & kbd_rpt_mask) | K_REPEAT;
00407 repeat_time = now;
00408
00409
00410 if (repeat_rate > ms_to_ticks(KBD_REPEAT_MAXRATE))
00411 repeat_rate -= ms_to_ticks(KBD_REPEAT_ACCEL);
00412 }
00413 else
00414 key = 0;
00415 }
00416 else
00417 kbd_rptStatus = KS_IDLE;
00418
00419 break;
00420 }
00421
00422 return key;
00423 }
00424
00425
00426 MOD_DEFINE(kbd)
00427
00428
00431 void kbd_init(void)
00432 {
00433 #if CONFIG_KBD_BEEP
00434 MOD_CHECK(buzzer);
00435 #endif
00436
00437 KBD_HW_INIT;
00438
00439
00440 LIST_INIT(&kbd_handlers);
00441 LIST_INIT(&kbd_rawHandlers);
00442
00443
00444 kbd_debHandler.hook = kbd_debHandlerFunc;
00445 kbd_debHandler.pri = 100;
00446 kbd_debHandler.flags = KHF_RAWKEYS;
00447 kbd_addHandler(&kbd_debHandler);
00448
00449 #if CONFIG_KBD_LONGPRESS
00450
00451 kbd_lngHandler.hook = kbd_lngHandlerFunc;
00452 kbd_lngHandler.pri = 90;
00453 kbd_lngHandler.flags = KHF_RAWKEYS;
00454 kbd_addHandler(&kbd_lngHandler);
00455 #endif
00456
00457
00458 kbd_rptHandler.hook = kbd_rptHandlerFunc;
00459 kbd_rptHandler.pri = 80;
00460 kbd_rptHandler.flags = KHF_RAWKEYS;
00461 kbd_addHandler(&kbd_rptHandler);
00462
00463
00464 kbd_defHandler.hook = kbd_defHandlerFunc;
00465 kbd_defHandler.pri = -128;
00466 kbd_addHandler(&kbd_defHandler);
00467
00468 #if CONFIG_KBD_OBSERVER
00469 observer_InitSubject(&kbd_subject);
00470 #endif
00471
00472 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00473
00474 MOD_CHECK(timer);
00475
00476
00477 event_initSoftint(&kbd_timer.expire, kbd_softint, NULL);
00478 timer_setDelay(&kbd_timer, ms_to_ticks(KBD_CHECK_INTERVAL));
00479 timer_add(&kbd_timer);
00480
00481 #else
00482 #error "Define keyboard poll method"
00483
00484 #endif
00485
00486 MOD_INIT(kbd);
00487 }