[calypso] Rework of keypad interrupt handler.

The keys are correctly detected and debounced. There is no delay_ms in the
interrupt handler anymore.

When a key is pressed, the columns of the keypad are polled and debounced
via timer interrupt. If no key is pressed, the timer interrupt is ignored
again.
This commit is contained in:
Andreas.Eversberg 2010-07-18 12:56:48 +00:00
parent 0f184d1dfe
commit 8d2ed53b45
3 changed files with 83 additions and 32 deletions

View File

@ -113,10 +113,33 @@ int main(void)
void key_handler(enum key_codes code, enum key_states state)
{
char test[16];
if (state != PRESSED)
return;
switch (code) {
case KEY_0:
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4:
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
sprintf(test, "%d", code - KEY_0);
display_puts(test);
break;
case KEY_STAR:
sprintf(test, "*", 0);
display_puts(test);
break;
case KEY_HASH:
sprintf(test, "#", 0);
display_puts(test);
break;
default:
break;
}

View File

@ -53,13 +53,14 @@ void emit_key(uint8_t key, uint8_t state)
}
}
volatile uint32_t lastbuttons;
volatile uint32_t lastbuttons = 0;
#define BTN_TO_KEY(name) \
((diff & BTN_##name) == BTN_##name) \
{ \
key = KEY_##name; \
diff = diff & ~BTN_##name; \
state = (buttons & BTN_##name) ? PRESSED : RELEASED; \
}
void dispatch_buttons(uint32_t buttons)
@ -69,11 +70,6 @@ void dispatch_buttons(uint32_t buttons)
if (buttons == lastbuttons)
return;
if (buttons > lastbuttons)
state = PRESSED;
else
state = RELEASED;
uint32_t diff = buttons ^ lastbuttons;
uint8_t key=KEY_INV;
@ -105,21 +101,24 @@ void dispatch_buttons(uint32_t buttons)
printf("\nunknown keycode: 0x%08x\n", diff);
break;
}
if ( key == KEY_POWER )
diff = 0;
emit_key(key, state);
}
lastbuttons = buttons;
}
static uint8_t polling = 0;
static void keypad_irq(__unused enum irq_nr nr)
{
keypad_poll();
/* enable polling */
polling = 1;
irq_disable(IRQ_KEYPAD_GPIO);
}
void keypad_init(uint8_t interrupts)
{
lastbuttons = 0;
polling = 0;
writew(0, KBD_GPIO_MASKIT);
writew(0, KBC_REG);
@ -137,32 +136,57 @@ void keypad_set_handler(key_handler_t handler)
void keypad_poll()
{
uint16_t reg;
uint16_t col;
uint32_t buttons;
static uint16_t reg;
static uint16_t col;
static uint32_t buttons = 0, debounce1 = 0, debounce2 = 0;
// putchar('\n');
buttons = 0x0;
//scan for BTN_POWER
writew(0xff, KBC_REG);
delay_ms(1);
reg = readw(KBR_LATCH_REG);
// printd("%02x ", (~reg & 0x1f));
buttons = buttons | ((~reg & 0x1f) << 20 );
if (!polling)
return;
//scan for muxed keys if not powerbtn
if ((~reg & 0x1f) != 0x10)
for (col=0;col<4;col++)
{
writew(0x1f & ~(0x1 << col ), KBC_REG);
delay_ms(1);
reg = readw(KBR_LATCH_REG);
buttons = buttons | ((~reg & 0x1f) << (col * 5 ));
// printd("%02x ", (~reg & 0x1f));
/* start polling */
if (polling == 1) {
writew(0x1f & ~0x1, KBC_REG); /* first col */
col = 0;
polling = 2;
return;
}
//enable keypad irq via master 'or' gate (needs col lines low in idle to work)
writew(0, KBC_REG);
dispatch_buttons(buttons);
/* enable keypad irq after the signal settles */
if (polling == 3) {
irq_enable(IRQ_KEYPAD_GPIO);
polling = 0;
return;
}
reg = readw(KBR_LATCH_REG);
buttons = (buttons & ~(0x1f << (col * 5)))
| ((~reg & 0x1f) << (col * 5 ));
/* if key is released, stay in column for faster debounce */
if ((debounce1 | debounce2) & ~buttons) {
debounce2 = debounce1;
debounce1 = buttons;
return;
}
col++;
if (col > 4) {
col = 0;
/* if power button, ignore other states */
if (buttons & BTN_POWER)
buttons = lastbuttons | BTN_POWER;
else if (lastbuttons & BTN_POWER)
buttons = lastbuttons & ~BTN_POWER;
dispatch_buttons(buttons);
if (buttons == 0) {
writew(0x0, KBC_REG);
polling = 3;
return;
}
}
if (col == 4)
writew(0xff, KBC_REG);
else
writew(0x1f & ~(0x1 << col ), KBC_REG);
}

View File

@ -27,6 +27,8 @@
#include <calypso/timer.h>
#include <calypso/irq.h>
#include <keypad.h>
static LLIST_HEAD(timer_list);
unsigned long volatile jiffies;
@ -189,6 +191,8 @@ static void timer_irq(enum irq_nr irq)
{
/* we only increment jiffies here. FIXME: does this need to be atomic? */
jiffies++;
keypad_poll();
}
void timer_init(void)