1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-17 06:47:11 +02:00
iris/boot-programs/nanonote-gpio.ccp
2009-10-04 19:47:20 +02:00

367 lines
11 KiB
COBOL

#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"
//#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 <String> list = List <String> (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")