#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" #include "keys.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] static unsigned const NUM_KEYS = 58 static unsigned const keys[NUM_KEYS] unsigned state[NUM_COLS] Kernel::Cap event bool is_active bool is_scanning public: unsigned size (): return NUM_KEYS void send_keys (unsigned first, Kernel::Cap target): unsigned d[4] unsigned i for i = 0; first + i < NUM_KEYS && i < 4; ++i: d[i] = keys[first + i] for ; i < 4; ++i: d[i] = ~0 target.invoke (Kernel::Num (d[0], d[1]), Kernel::Num (d[2], d[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 { Key::F1, Key::F2, Key::F3, Key::F4, Key::F5, Key::F6, Key::F7, ~0 }, { Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I }, { Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K }, { Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M }, { Key::TAB, Key::CAPS, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP }, { Key::O, Key::L, Key::EQUAL, Key::ARROW, Key::SPACE, Key::QI, Key::CTRL, Key::LEFT }, { Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT }, { Key::SHIFT, Key::ALT, Key::FN, ~0, ~0, ~0, ~0, ~0 } #else { Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0, ~0 }, { Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8 }, { Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I }, { Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K }, { Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M, Key::UP }, { Key::N9, Key::O, Key::L, Key::LEFT_ALT, Key::CAPS_LOCK, Key::SPACE, Key::EQUALS, Key::LEFT }, { Key::BACKSPACE, Key::N0, Key::P, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT }, { Key::FN, Key::LEFT_SHIFT, Key::LEFT_CONTROL, ~0, ~0, ~0, ~0, ~0 } #endif } unsigned const DevKbd::keys[NUM_KEYS] = { #ifdef QI Key::F1, Key::F2, Key::F3, Key::F4, Key::F5, Key::F6, Key::F7, Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I, Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K, Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M, Key::TAB, Key::CAPS, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP, Key::O, Key::L, Key::EQUAL, Key::ARROW, Key::SPACE, Key::QI, Key::CTRL, Key::LEFT, Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT, Key::SHIFT, Key::ALT, Key::FN #else Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0, Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8, Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I, Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M, Key::UP, Key::N9, Key::O, Key::L, Key::LEFT_ALT, Key::CAPS_LOCK, Key::SPACE, Key::EQUALS, Key::LEFT, Key::BACKSPACE, Key::N0, Key::P, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT, Key::FN, Key::LEFT_SHIFT, Key::LEFT_CONTROL #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 PWR Kernel::Num start (): Kernel::schedule () map_gpio () DevKbd kbd PowerButton pwr Device dev = Kernel::my_receiver.create_capability (KBD_DEV) Keyboard pw = Kernel::my_receiver.create_capability (PWR) Kernel::my_parent.provide_device (dev.copy (), 0) Kernel::my_parent.provide_device (pw.copy (), 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) 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 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") Kernel::Cap reply = Kernel::get_reply () kbd.active (Kernel::get_arg ()) reply.invoke () Kernel::free_cap (reply) break case Keyboard::GET_NUM_KEYS: kdebug ("get #keys\n") Kernel::recv.reply.invoke (kbd.size ()) break case Keyboard::GET_KEYS: kdebug ("get keys\n") kbd.send_keys (Kernel::recv.data[0].l, Kernel::recv.reply) break default: kdebug ("other\n") break break default: kdebug ("unknown num: ") kdebug_num (Kernel::recv.protected_data.h) kdebug ("\n")