#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] Iris::Cap event bool is_active bool is_scanning public: unsigned size (): return NUM_KEYS void send_keys (unsigned first, Iris::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 (Iris::Num (d[0], d[1]), Iris::Num (d[2], d[3])) bool scanning (): return is_scanning void inactive (): if is_active: Iris::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 |= Iris::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 (Iris::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_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP }, { Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT }, { Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT }, { Key::LEFT_SHIFT, Key::LEFT_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_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP, Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT, Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT, Key::LEFT_SHIFT, Key::LEFT_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 Event: bool state, started unsigned pin Iris::Cap cb public: void scan (): if !started: return gpio_mask_irq (3, 1 << pin) bool s = gpio_get_port (3) & (1 << pin) if s != state: state = s cb.invoke (state ? Iris::Keyboard::RELEASE : 0) gpio_as_interrupt (3, 1 << pin, !state, true) gpio_unmask_irq (3, 1 << pin) Event (unsigned p): pin = p gpio_as_gpio (3, pin) state = true started = false void set_cb (Iris::Cap c): if started: Iris::free_cap (cb) else: started = true cb = c state = true scan () enum codes: KBD_DEV = 1 PWR SDMMC Iris::Num start (): map_gpio () DevKbd kbd Event pwr (29) Event sdmmc (0) Iris::Keyboard dev = Iris::my_receiver.create_capability (KBD_DEV) Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR) Iris::Event sm = Iris::my_receiver.create_capability (SDMMC) Iris::my_parent.provide_capability (dev.copy (), 0) Iris::my_parent.provide_capability (pw.copy (), 1) Iris::my_parent.provide_capability (sm.copy ()) Iris::free_cap (dev) Iris::free_cap (pw) Iris::free_cap (sm) Iris::my_parent.init_done () if kbd.scanning (): Iris::my_receiver.set_alarm (SCAN_INTERVAL) Iris::register_interrupt (IRQ_GPIO3) while true: Iris::wait () if Iris::recv.protected_data.h == ~0: // Alarm. kbd.scan () if kbd.scanning (): Iris::my_receiver.set_alarm (SCAN_INTERVAL) continue switch Iris::recv.protected_data.l: case 0: // Interrupt. pwr.scan () kbd.scan () sdmmc.scan () if kbd.scanning (): Iris::my_receiver.set_alarm (SCAN_INTERVAL) Iris::register_interrupt (IRQ_GPIO3) break case KBD_DEV: // Keyboard device user request. switch Iris::recv.data[0].l: case Iris::Device::RESET: Iris::recv.reply.invoke () break case Iris::Event::SET_CB: Iris::Cap reply = Iris::get_reply () kbd.active (Iris::get_arg ()) reply.invoke () Iris::free_cap (reply) break case Iris::Keyboard::GET_NUM_KEYS: Iris::recv.reply.invoke (kbd.size ()) break case Iris::Keyboard::GET_KEYS: kbd.send_keys (Iris::recv.data[0].l, Iris::recv.reply) break default: kdebug ("keyboard other\n") break break case PWR: switch Iris::recv.data[0].l: case Iris::Device::RESET: Iris::recv.reply.invoke () break case Iris::Event::SET_CB: Iris::Cap reply = Iris::get_reply () pwr.set_cb (Iris::get_arg ()) reply.invoke () Iris::free_cap (reply) break default: kdebug ("Power button invalid request\n") kdebug_num (Iris::recv.data[0].l) kdebug ("\n") break break case SDMMC: switch Iris::recv.data[0].l: case Iris::Device::RESET: Iris::recv.reply.invoke () break case Iris::Event::SET_CB: Iris::Cap reply = Iris::get_reply () sdmmc.set_cb (Iris::get_arg ()) reply.invoke () Iris::free_cap (reply) break default: kdebug ("SdMmc gpio invalid request\n") kdebug_num (Iris::recv.data[0].l) kdebug ("\n") break break default: kdebug ("keyboard unknown num: ") kdebug_num (Iris::recv.protected_data.h) kdebug ("\n")