#pypp 0 // Iris: micro-kernel for a capability-based operating system. // boot-programs/nanonote-gpio.ccp: gpio devices on the nanonote. // Copyright 2009 Bas Wijnen // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "devices.hh" #define ARCH #include "arch.hh" //#define QI #define SCAN_INTERVAL HZ / 50 class DevKbd: static unsigned const NUM_COLS = 8 static unsigned const NUM_ROWS = 8 static unsigned const COLS_PORT = 2 static unsigned const ROWS_PORT = 3 static unsigned const ALL_COLS = 0x0003fc00 static unsigned const ALL_ROWS = 0x05fc0000 static unsigned const COLS[NUM_COLS] static unsigned const ROWS[NUM_ROWS] static unsigned const encode[NUM_ROWS][NUM_COLS] enum Keys: #ifdef QI A, B, C, D, E, F, G, H, I, J, K, L, M N, O, P, Q, R, S, T, U, V, W, X, Y, Z F1, F2, F3, F4, F5, F6, F7, F8 TAB, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, EQUAL, SPACE ESCAPE, ENTER, BACKSPACE UP, DOWN, LEFT, RIGHT CAPS, ARROW, QI, CTRL, VOLUP, VOLDOWN, SHIFT, ALT, FN #else N0, N1, N2, N3, N4, N5, N6, N7, N8, N9 A, B, C, D, E, F, G, H, I, J, K, L, M N, O, P, Q, R, S, T, U, V, W, X, Y, Z F1, F2, F3, F4 CAPS, TAB, ENTER, ESCAPE, MP3, SPACE, BACKSPACE, EQUALS UP, DOWN, LEFT, RIGHT VOLUP, VOLDOWN FN, SHIFT, CTRL, ALT #endif NUM_KEYS static char const *const names[NUM_KEYS] unsigned state[NUM_COLS] Kernel::Cap event bool is_active bool is_scanning public: unsigned size (): return NUM_KEYS unsigned get_name_size (unsigned n): if n >= NUM_KEYS: return 0 unsigned ret = 0 for char const *p = names[n]; *p; ++p: ++ret return ret void send_name (unsigned n, Kernel::Cap c, Kernel::Num offset): if n >= NUM_KEYS: c.invoke (0, 0) return unsigned data[4] char *d = (char *)data if offset.value () < get_name_size (n): unsigned o = offset.l & ~3; unsigned p for p = 0; p < 16 && names[n][p + o]; ++p: *d++ = names[n][p + o] for ; p < 16; ++p: *d++ = 0 c.invoke (Kernel::Num (data[0], data[1]), Kernel::Num (data[2], data[3])) bool scanning (): return is_scanning void inactive (): if is_active: Kernel::free_cap (event) is_active = false void check (unsigned col, unsigned rowdata): for unsigned r = 0; r < NUM_ROWS; ++r: if !((rowdata ^ state[col]) & (1 << ROWS[r])): continue unsigned code = encode[r][col] if rowdata & (1 << ROWS[r]): code |= Keyboard::RELEASE if is_active: event.invoke (code) state[col] = rowdata void delay (): for unsigned i = 0; i < 10000; ++i: gpio_set (0, 0) void scan (): unsigned r gpio_mask_irq (ROWS_PORT, ALL_ROWS) is_scanning = false if !is_active: return for unsigned c = 0; c < NUM_COLS; ++c: gpio_as_input (COLS_PORT, ALL_COLS & ~(1 << COLS[c])) gpio_as_output (COLS_PORT, 1 << COLS[c]) if c > 0: check (c - 1, r) delay () else: check (0, state[0]) delay () r = gpio_get_port (ROWS_PORT) & ALL_ROWS if r != ALL_ROWS: is_scanning = true gpio_as_output (COLS_PORT, ALL_COLS) check (NUM_COLS - 1, r) delay () r = gpio_get_port (ROWS_PORT) & ALL_ROWS unsigned high = 0, low = 0 for unsigned i = 0; i < NUM_ROWS; ++i: if r & (1 << ROWS[i]): low |= 1 << ROWS[i] else: high |= 1 << ROWS[i] gpio_as_interrupt (ROWS_PORT, high, true, true) gpio_as_interrupt (ROWS_PORT, low, false, true) gpio_unmask_irq (ROWS_PORT, ALL_ROWS) void active (Kernel::Cap cb): inactive () event = cb is_active = true for unsigned c = 0; c < NUM_COLS; ++c: state[c] = ALL_ROWS scan () DevKbd (): is_active = false gpio_as_gpio (COLS_PORT, ALL_COLS) gpio_as_gpio (ROWS_PORT, ALL_ROWS) gpio_clear (COLS_PORT, ALL_COLS) gpio_as_output (COLS_PORT, ALL_COLS) gpio_as_input (ROWS_PORT, ALL_ROWS) gpio_enable_pull (ROWS_PORT, ALL_ROWS) for unsigned i = 0; i < NUM_COLS; ++i: state[i] = ALL_ROWS scan () unsigned const DevKbd::COLS[NUM_COLS] = { 10, 11, 12, 13, 14, 15, 16, 17 } unsigned const DevKbd::ROWS[NUM_ROWS] = { 18, 19, 20, 21, 22, 23, 24, 26 } unsigned const DevKbd::encode[NUM_ROWS][NUM_COLS] = { #ifdef QI { F1, F2, F3, F4, F5, F6, F7, ~0 }, { Q, W, E, R, T, Y, U, I }, { A, S, D, F, G, H, J, K }, { ESCAPE, Z, X, C, V, B, N, M }, { TAB, CAPS, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, UP }, { O, L, EQUAL, ARROW, SPACE, QI, CTRL, LEFT }, { F8, P, BACKSPACE, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT }, { SHIFT, ALT, FN, ~0, ~0, ~0, ~0, ~0 } #else { ESCAPE, TAB, F1, F2, F3, F4, MP3, ~0 }, { N1, N2, N3, N4, N5, N6, N7, N8 }, { Q, W, E, R, T, Y, U, I }, { A, S, D, F, G, H, J, K }, { Z, X, C, V, B, N, M, UP }, { N9, O, L, ALT, CAPS, SPACE, EQUALS, LEFT }, { BACKSPACE, N0, P, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT }, { FN, SHIFT, CTRL, ~0, ~0, ~0, ~0, ~0 } #endif } char const *const DevKbd::names[NUM_KEYS] = { #ifdef QI "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "tab", "\\", "'", ",", ".", "/", "=", "space", "escape", "enter", "backspace", "up", "down", "left", "right", "caps lock", "arrow", "qi", "left control", "volume up", "volume down", "left shift", "left alt", "fn" #else "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "f1", "f2", "f3", "f4", "caps lock", "tab", "enter", "escape", "mp3", "space", "backspace", "=", "up", "down", "left", "right", "volume up", "volume down", "fn", "left shift", "left control", "left alt" #endif } class PowerButton: bool state, started Kernel::Cap cb public: void scan (): gpio_mask_irq (3, 1 << 29) bool s = gpio_get_port (3) & (1 << 29) if s != state: state = s cb.invoke (state ? Keyboard::RELEASE : 0) gpio_as_interrupt (3, 1 << 29, !state, true) gpio_unmask_irq (3, 1 << 29) PowerButton (): gpio_as_gpio (3, 29) state = true started = false void set_cb (Kernel::Cap c): if started: Kernel::free_cap (cb) else: started = true cb = c state = true scan () enum codes: KBD_DEV = 32 KBD_LIST PWR Kernel::Num start (): map_gpio () map_tcu () DevKbd kbd PowerButton pwr Device dev = Kernel::my_receiver.create_capability (KBD_DEV) Keyboard pw = Kernel::my_receiver.create_capability (PWR) Kernel::my_parent.ocall (dev.copy (), Kernel::Num (Keyboard::ID, 0)) Kernel::my_parent.ocall (pw.copy (), Kernel::Num (Keyboard::ID, 1)) Kernel::free_cap (dev) Kernel::free_cap (pw) if kbd.scanning (): Kernel::my_receiver.set_alarm (SCAN_INTERVAL) unsigned user (~0) unsigned next_user (0) List list = List (Kernel::my_receiver.create_capability (KBD_LIST)) Kernel::register_interrupt (IRQ_GPIO3) while true: Kernel::wait () switch Kernel::recv.protected_data.h: case ~0: // Alarm. kbd.scan () if kbd.scanning (): Kernel::my_receiver.set_alarm (SCAN_INTERVAL) break case 0: switch Kernel::recv.protected_data.l: case IRQ_GPIO3: // Interrupt. pwr.scan () kbd.scan () if kbd.scanning (): Kernel::my_receiver.set_alarm (SCAN_INTERVAL) Kernel::register_interrupt (IRQ_GPIO3) break case PWR: // Power button request. switch Kernel::recv.data[0].l: case Keyboard::SET_CB: pwr.set_cb (Kernel::get_arg ()) Kernel::recv.reply.invoke () break default: kdebug ("power button invalid request\n") break break case KBD_DEV: // Keyboard device control request. switch Kernel::recv.data[0].l: case Device::CREATE_USER: kdebug ("create\n") Kernel::Cap reply = Kernel::get_reply () Keyboard cap = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, KBD_DEV)) reply.invoke (0, 0, cap.copy ()) Kernel::free_cap (cap) Kernel::free_cap (reply) break case Device::DESTROY_USER: kdebug ("destroy\n") Kernel::recv.reply.invoke () break case Device::UNUSE: kdebug ("unuse\n") kbd.inactive () Kernel::recv.reply.invoke () break case Device::USE: kdebug ("use\n") Kernel::Cap reply = Kernel::get_reply () user = Kernel::my_receiver.get_protected (Kernel::recv.arg).l reply.invoke () Kernel::free_cap (reply) break default: kdebug ("other dev:") kdebug_num (Kernel::recv.data[0].l) kdebug ("\n") break break case KBD_LIST: // Keyboard name lookup. switch Kernel::recv.data[0].l: case Kernel::Caps::GET: Kernel::Cap reply = Kernel::get_reply () unsigned num = Kernel::recv.data[1].l Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (num, KBD_LIST)) reply.invoke (kbd.get_name_size (num), 0, name.copy ()) Kernel::free_cap (name) Kernel::free_cap (reply) break case Kernel::Caps::GET_SIZE: Kernel::recv.reply.invoke (kbd.size ()) break default: kdebug ("invalid list operation\n") break break default: break break case KBD_DEV: // Keyboard device user request. if Kernel::recv.protected_data.l != user: kdebug ("invalid user requesting\n") Kernel::recv.reply.invoke () break switch Kernel::recv.data[0].l: case Keyboard::SET_CB: kdebug ("set cb\n") kbd.active (Kernel::get_arg ()) Kernel::recv.reply.invoke () break case Keyboard::GET_KEYS: kdebug ("get keys\n") Kernel::recv.reply.invoke (0, 0, list) break default: kdebug ("other\n") break break case KBD_LIST: switch Kernel::recv.data[0].l: case String::GET_SIZE: Kernel::recv.reply.invoke (kbd.get_name_size (Kernel::recv.protected_data.l)) break case String::GET_CHARS: kbd.send_name (Kernel::recv.protected_data.l, Kernel::recv.reply, Kernel::recv.data[1]) break default: kdebug ("invalid string operation\n") break break default: kdebug ("unknown num: ") kdebug_num (Kernel::recv.protected_data.h) kdebug ("\n")