2009-10-04 20:47:20 +03:00
|
|
|
#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 <wijnen@debian.org>
|
|
|
|
//
|
|
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "devices.hh"
|
|
|
|
#define ARCH
|
|
|
|
#include "arch.hh"
|
2009-10-10 02:31:10 +03:00
|
|
|
#include "keys.hh"
|
2009-10-04 20:47:20 +03:00
|
|
|
|
|
|
|
//#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]
|
2009-10-10 02:31:10 +03:00
|
|
|
static unsigned const NUM_KEYS = 58
|
|
|
|
static unsigned const keys[NUM_KEYS]
|
2009-10-04 20:47:20 +03:00
|
|
|
unsigned state[NUM_COLS]
|
|
|
|
Kernel::Cap event
|
|
|
|
bool is_active
|
|
|
|
bool is_scanning
|
|
|
|
public:
|
|
|
|
unsigned size ():
|
|
|
|
return NUM_KEYS
|
2009-10-10 02:31:10 +03:00
|
|
|
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]))
|
2009-10-04 20:47:20 +03:00
|
|
|
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
|
2009-10-10 02:31:10 +03:00
|
|
|
{ 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 }
|
2009-10-04 20:47:20 +03:00
|
|
|
#else
|
2009-10-10 02:31:10 +03:00
|
|
|
{ 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 }
|
2009-10-04 20:47:20 +03:00
|
|
|
#endif
|
|
|
|
}
|
2009-10-10 02:31:10 +03:00
|
|
|
unsigned const DevKbd::keys[NUM_KEYS] = {
|
2009-10-04 20:47:20 +03:00
|
|
|
#ifdef QI
|
2009-10-10 02:31:10 +03:00
|
|
|
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
|
2009-10-04 20:47:20 +03:00
|
|
|
#else
|
2009-10-10 02:31:10 +03:00
|
|
|
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
|
2009-10-04 20:47:20 +03:00
|
|
|
#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 ():
|
2009-12-26 15:17:06 +02:00
|
|
|
Kernel::schedule ()
|
2009-10-04 20:47:20 +03:00
|
|
|
map_gpio ()
|
|
|
|
|
|
|
|
DevKbd kbd
|
|
|
|
PowerButton pwr
|
|
|
|
|
|
|
|
Device dev = Kernel::my_receiver.create_capability (KBD_DEV)
|
|
|
|
Keyboard pw = Kernel::my_receiver.create_capability (PWR)
|
2009-10-31 10:32:23 +02:00
|
|
|
Kernel::my_parent.provide_device <Keyboard> (dev.copy (), 0)
|
|
|
|
Kernel::my_parent.provide_device <Keyboard> (pw.copy (), 1)
|
2009-10-04 20:47:20 +03:00
|
|
|
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:
|
|
|
|
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:
|
|
|
|
Kernel::recv.reply.invoke ()
|
|
|
|
break
|
|
|
|
case Device::UNUSE:
|
|
|
|
kbd.inactive ()
|
|
|
|
Kernel::recv.reply.invoke ()
|
|
|
|
break
|
|
|
|
case Device::USE:
|
|
|
|
Kernel::Cap reply = Kernel::get_reply ()
|
|
|
|
user = Kernel::my_receiver.get_protected (Kernel::recv.arg).l
|
|
|
|
reply.invoke ()
|
|
|
|
Kernel::free_cap (reply)
|
|
|
|
break
|
|
|
|
default:
|
2009-12-27 01:12:35 +02:00
|
|
|
kdebug ("gpio other dev:")
|
2009-10-04 20:47:20 +03:00
|
|
|
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:
|
2009-10-10 02:31:10 +03:00
|
|
|
Kernel::Cap reply = Kernel::get_reply ()
|
2009-10-04 20:47:20 +03:00
|
|
|
kbd.active (Kernel::get_arg ())
|
2009-10-10 02:31:10 +03:00
|
|
|
reply.invoke ()
|
|
|
|
Kernel::free_cap (reply)
|
|
|
|
break
|
|
|
|
case Keyboard::GET_NUM_KEYS:
|
|
|
|
Kernel::recv.reply.invoke (kbd.size ())
|
2009-10-04 20:47:20 +03:00
|
|
|
break
|
|
|
|
case Keyboard::GET_KEYS:
|
2009-10-10 02:31:10 +03:00
|
|
|
kbd.send_keys (Kernel::recv.data[0].l, Kernel::recv.reply)
|
2009-10-04 20:47:20 +03:00
|
|
|
break
|
|
|
|
default:
|
2009-12-27 01:12:35 +02:00
|
|
|
kdebug ("keyboard other\n")
|
2009-10-04 20:47:20 +03:00
|
|
|
break
|
|
|
|
break
|
|
|
|
default:
|
2009-12-27 01:12:35 +02:00
|
|
|
kdebug ("keyboard unknown num: ")
|
2009-10-04 20:47:20 +03:00
|
|
|
kdebug_num (Kernel::recv.protected_data.h)
|
|
|
|
kdebug ("\n")
|