1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 03:31:40 +03:00

make more things work

This commit is contained in:
Bas Wijnen 2009-10-04 19:47:20 +02:00
parent 431b38acb9
commit 906f487b01
19 changed files with 872 additions and 268 deletions

138
boot-programs/buzzer.ccp Normal file
View File

@ -0,0 +1,138 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/buzzer.ccp: Piezo buzzer driver.
// 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"
class DevBuzzer:
static unsigned const pwm = 4
Kernel::Cap event
bool is_active, is_beeping
public:
DevBuzzer ():
is_active = false
is_beeping = false
gpio_as_pwm4 ()
tcu_stop_counter (pwm)
tcu_select_extalclk (pwm)
tcu_select_clk_div64 (pwm)
tcu_enable_pwm_output (pwm)
void stop ():
if !is_beeping:
return
tcu_stop_counter (pwm)
event.invoke ()
is_active = false
Kernel::free_cap (event)
void beep (unsigned freq, unsigned ms, Kernel::Cap cb):
stop ()
event = cb
unsigned full = JZ_EXTAL / 64 / freq
tcu_set_full_data (pwm, full)
tcu_set_half_data (pwm, full / 2)
tcu_set_count (pwm, 0)
tcu_start_counter (pwm)
Kernel::my_receiver.set_alarm (ms * HZ / 1000)
is_beeping = true
enum codes:
BUZZER = 32
Kernel::Num start ():
map_gpio ()
map_tcu ()
DevBuzzer buzzer
Device dev = Kernel::my_receiver.create_capability (BUZZER)
Kernel::my_parent.ocall (dev.copy (), Buzzer::ID)
Kernel::free_cap (dev)
unsigned user (~0)
unsigned next_user (0)
while true:
Kernel::wait ()
switch Kernel::recv.protected_data.h:
case ~0:
// Alarm.
buzzer.stop ()
break
case 0:
switch Kernel::recv.protected_data.l:
case BUZZER:
// Buzzer 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++, BUZZER))
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:
buzzer.stop ()
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:
kdebug ("invalid buzzer control command: ")
kdebug_num (Kernel::recv.data[0].l)
kdebug ("\n")
break
break
default:
kdebug ("invalid buzzer request\n")
break
break
case BUZZER:
// Buzzer device user request.
if Kernel::recv.protected_data.l != user:
kdebug ("invalid user requesting buzzer\n")
Kernel::recv.reply.invoke ()
break
switch Kernel::recv.data[0].l:
case Buzzer::BEEP:
// Volume is not used for this buzzer.
Kernel::Cap arg = Kernel::get_arg ()
Kernel::Cap reply = Kernel::get_reply ()
buzzer.beep (Kernel::recv.data[1].l, Kernel::recv.data[1].h, arg)
reply.invoke ()
Kernel::free_cap (arg)
Kernel::free_cap (reply)
break
case Buzzer::STOP:
kdebug ("stop\n")
buzzer.stop ()
Kernel::recv.reply.invoke ()
break
default:
kdebug ("other\n")
break
break
default:
kdebug ("unknown num: ")
kdebug_num (Kernel::recv.protected_data.h)
kdebug ("\n")

View File

@ -36,7 +36,23 @@ namespace Kernel:
Cap my_parent Cap my_parent
__recv_data_t recv __recv_data_t recv
void print_caps ():
// Assume __caps to be 16.
bool used[16]
for unsigned i = 0; i < 16; ++i:
used[i] = true
unsigned num = 0
for list *i = __first_free_cap; i; i = i->next:
used[i - __cap_admin] = false
++num
kdebug_num (num, 1)
kdebug (":")
for unsigned i = 0; i < 16; ++i:
kdebug_char (used[i] ? '#' : '.')
kdebug_char ('\n')
void free_slot (unsigned slot): void free_slot (unsigned slot):
//kdebug ("free slot\n")
__slot_admin[slot].prev = NULL __slot_admin[slot].prev = NULL
__slot_admin[slot].next = __first_free_slot __slot_admin[slot].next = __first_free_slot
if __slot_admin[slot].next: if __slot_admin[slot].next:
@ -44,6 +60,7 @@ namespace Kernel:
__first_free_slot = &__slot_admin[slot] __first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap): void free_cap (Cap cap):
//kdebug ("free cap\n")
if cap.slot () != 0: if cap.slot () != 0:
kdebug ("trying to free capability from non-0 slot\n") kdebug ("trying to free capability from non-0 slot\n")
return return
@ -55,6 +72,7 @@ namespace Kernel:
__first_free_cap = l __first_free_cap = l
unsigned alloc_slot (): unsigned alloc_slot ():
//kdebug ("alloc slot\n")
if !__first_free_slot: if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT. // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
kdebug ("out of slots!\n") kdebug ("out of slots!\n")
@ -66,6 +84,7 @@ namespace Kernel:
return ret - __slot_admin return ret - __slot_admin
Cap alloc_cap (): Cap alloc_cap ():
//kdebug ("alloc cap\n")
if !__first_free_cap: if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE // Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
kdebug ("out of capabilities!\n") kdebug ("out of capabilities!\n")

View File

@ -39,7 +39,7 @@ struct String : public Kernel::Cap:
GET_SIZE = 0x2001 GET_SIZE = 0x2001
GET_CHARS GET_CHARS
GET_PAGE GET_PAGE
_END_MARKER ID
/// Get the size of the string. /// Get the size of the string.
Kernel::Num get_size (): Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE) return call (CAP_MASTER_DIRECT | GET_SIZE)
@ -61,10 +61,10 @@ struct String : public Kernel::Cap:
struct WString : public String: struct WString : public String:
WString (Kernel::Cap c = Kernel::Cap ()) : String (c): WString (Kernel::Cap c = Kernel::Cap ()) : String (c):
enum request: enum request:
TRUNCATE = String::_END_MARKER TRUNCATE = String::ID
SET_CHARS SET_CHARS
SET_PAGE SET_PAGE
_END_MARKER ID
/// Set the size of the string. Strings may have a limit to this setting. /// Set the size of the string. Strings may have a limit to this setting.
void truncate (Kernel::Num size): void truncate (Kernel::Num size):
call (CAP_MASTER_DIRECT | TRUNCATE, size) call (CAP_MASTER_DIRECT | TRUNCATE, size)
@ -75,17 +75,41 @@ struct WString : public String:
void set_page (Kernel::Num idx, Kernel::Page page): void set_page (Kernel::Num idx, Kernel::Page page):
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx) ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
// Every process which wants to be switchable through a terminal must implement this interface.
struct Device : public Kernel::Cap:
Device (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
CREATE_USER = WString::ID
DESTROY_USER
UNUSE
USE
ID
// Create a new user for this device. It will not be the active user.
// The provided storage must allow object creation; no other actions may be used by the terminal.
Kernel::Cap create_user (Kernel::Memory storage):
iocall (storage, CAP_MASTER_DIRECT | CREATE_USER)
return Kernel::get_arg ()
// Destroy a user. It must not be active.
void destroy_user (Kernel::Cap user):
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
// Make user inactive.
void unuse (Kernel::Cap user):
ocall (user, CAP_MASTER_DIRECT | UNUSE)
// Make user active.
void use (Kernel::Cap user):
ocall (user, CAP_MASTER_DIRECT | USE)
// Keyboard interface. // Keyboard interface.
struct Keyboard : public Kernel::Cap: struct Keyboard : public Kernel::Cap:
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request: enum request:
SET_CB = WString::_END_MARKER SET_CB = Device::ID
GET_KEYS GET_KEYS
_END_MARKER ID
// At event: the callback is called with a keycode. One bit defines if it's a press or release event. // At event: the callback is called with a keycode. One bit defines if it's a press or release event.
enum constant: enum constant:
RELEASE = 1 << 31 RELEASE = 1 << 31
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events. // Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
void set_cb (Kernel::Cap cb): void set_cb (Kernel::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_CB) ocall (cb, CAP_MASTER_DIRECT | SET_CB)
// Get a list of keys on this keyboard. The key codes start at zero with no gaps. // Get a list of keys on this keyboard. The key codes start at zero with no gaps.
@ -93,15 +117,29 @@ struct Keyboard : public Kernel::Cap:
icall (CAP_MASTER_DIRECT | GET_KEYS) icall (CAP_MASTER_DIRECT | GET_KEYS)
return List <String> (Kernel::get_arg ()) return List <String> (Kernel::get_arg ())
// Buzzer interface.
struct Buzzer : public Kernel::Cap:
Buzzer (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
BEEP = Keyboard::ID
STOP
ID
// Emit a beep of specified frequency, time and volume. Volume may not be supported.
void beep (unsigned freq, unsigned ms, unsigned volume, Kernel::Cap cb = Kernel::Cap ()):
ocall (cb, Kernel::Num (CAP_MASTER_DIRECT | BEEP, volume), Kernel::Num (freq, ms))
// Abort current beep, if any.
void stop ():
call (CAP_MASTER_DIRECT | STOP)
// Display interface. // Display interface.
struct Display : public Kernel::Cap: struct Display : public Kernel::Cap:
Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request: enum request:
EOF_CB = Keyboard::_END_MARKER EOF_CB = Buzzer::ID
CREATE_FB CREATE_FB
USE_FB USE_FB
GET_INFO GET_INFO
_END_MARKER ID
// Register an end-of-frame callback. // Register an end-of-frame callback.
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events. // At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
void set_eof_cb (Kernel::Cap cb): void set_eof_cb (Kernel::Cap cb):
@ -129,10 +167,10 @@ struct Display : public Kernel::Cap:
struct File : public Kernel::Cap: struct File : public Kernel::Cap:
File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request: enum request:
INFO = Display::_END_MARKER INFO = Display::ID
CLOSE CLOSE
MAP_HANDLE MAP_HANDLE
_END_MARKER ID
// Get information about the file. // Get information about the file.
Kernel::Num get_info (unsigned type): Kernel::Num get_info (unsigned type):
return icall (Kernel::Num (CAP_MASTER_DIRECT | INFO, type)) return icall (Kernel::Num (CAP_MASTER_DIRECT | INFO, type))
@ -148,13 +186,13 @@ struct File : public Kernel::Cap:
struct Directory : public File: struct Directory : public File:
Directory (Kernel::Cap c = Kernel::Cap ()) : File (c): Directory (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request: enum request:
GET_SIZE = File::_END_MARKER GET_SIZE = File::ID
GET_NAME GET_NAME
GET_FILE GET_FILE
GET_FILE_INFO GET_FILE_INFO
CREATE_FILE CREATE_FILE
DELETE_FILE DELETE_FILE
_END_MARKER ID
// Get the number of entries in this directory. // Get the number of entries in this directory.
Kernel::Num get_size (): Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE) return call (CAP_MASTER_DIRECT | GET_SIZE)
@ -181,9 +219,9 @@ struct Directory : public File:
struct Stream : public File: struct Stream : public File:
Stream (Kernel::Cap c = Kernel::Cap ()) : File (c): Stream (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request: enum request:
READ = Directory::_END_MARKER READ = Directory::ID
WRITE WRITE
_END_MARKER ID
// Try to read size bytes. Returns the number of bytes successfully read. // Try to read size bytes. Returns the number of bytes successfully read.
Kernel::Num read (Kernel::Num size): Kernel::Num read (Kernel::Num size):
return icall (CAP_MASTER_DIRECT | READ, size) return icall (CAP_MASTER_DIRECT | READ, size)
@ -195,10 +233,10 @@ struct Stream : public File:
struct Seekable : public File: struct Seekable : public File:
Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c): Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request: enum request:
READ = Stream::_END_MARKER READ = Stream::ID
WRITE WRITE
TRUNCATE TRUNCATE
_END_MARKER ID
// Try to read size bytes from position idx. Returns the number of bytes successfully read. // Try to read size bytes from position idx. Returns the number of bytes successfully read.
Kernel::Num read (Kernel::Num idx, unsigned size): Kernel::Num read (Kernel::Num idx, unsigned size):
return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, size), idx) return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, size), idx)

View File

@ -18,84 +18,114 @@
#include "devices.hh" #include "devices.hh"
#include "iris.hh" #include "iris.hh"
#include "init.hh"
static Keyboard kbd, tp static Keyboard kbd, sysreq
static Display lcd static Buzzer buzzer
static Kernel::Cap lockleds, pwm static Device kbd_dev, buz_dev
static List <String> kbd_names
static unsigned slot
// Event types. // Event types.
enum type: enum type:
KBD = 0x10000 MEMORY
TP KBDDEV
KBD
KEYNAMES
SYSREQ
BUZDEV
BUZZER
static void setup (): static void setup ():
unsigned state = 0 unsigned state = 0
Kernel::Caps my_caps = Kernel::my_memory.create_caps (4 + 1) Kernel::Caps caps = Kernel::my_memory.create_caps (32)
unsigned my_slot = my_caps.use () slot = caps.use ()
unsigned slot = Kernel::alloc_slot () Kernel::set_recv_arg (Kernel::Cap (slot, MEMORY))
Kernel::Cap driver_memory = Kernel::my_memory.create_memory ()
while true: while true:
Kernel::wait () Kernel::wait ()
Kernel::Cap reply = Kernel::get_reply () Kernel::Cap reply = Kernel::get_reply ()
Kernel::Caps caps = Kernel::get_arg () Kernel::Cap arg = Kernel::get_arg ()
switch Kernel::recv.data[0].value (): switch Kernel::recv.data[0].l:
case Init::REGISTER_GPIO: case Keyboard::ID:
caps.use (slot) switch Kernel::recv.data[0].h:
for unsigned i = 0; i < 4; ++i: case 0:
my_caps.set (i, Kernel::Cap (slot, i).copy ()) caps.set (KBDDEV, arg.copy ())
kbd = Kernel::Cap (my_slot, 0) kbd_dev = Kernel::Cap (slot, KBDDEV)
tp = Kernel::Cap (my_slot, 1) break
lockleds = Kernel::Cap (my_slot, 2) case 1:
pwm = Kernel::Cap (my_slot, 3) caps.set (SYSREQ, arg.copy ())
sysreq = Kernel::Cap (slot, SYSREQ)
break
default:
kdebug ("unexpected keyboard\n")
break
break break
case Init::REGISTER_LCD: case Buzzer::ID:
caps.use (slot) caps.set (BUZDEV, arg.copy ())
my_caps.set (4, Kernel::Cap (slot, 0).copy ()) buz_dev = Kernel::Cap (slot, BUZDEV)
lcd = Kernel::Cap (my_slot, 4)
break break
default: default:
Kernel::free_cap (reply)
Kernel::free_cap (arg)
kdebug ("unknown setup request for init\n") kdebug ("unknown setup request for init\n")
continue continue
reply.invoke () reply.invoke ()
Kernel::free_cap (caps)
Kernel::free_cap (reply) Kernel::free_cap (reply)
if ++state == 2: Kernel::free_cap (arg)
if ++state == 3:
break break
Kernel::free_cap (my_caps) // sysreq
Kernel::free_slot (slot) Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ)
Kernel::schedule () sysreq.set_cb (cb.copy ())
Kernel::Cap kc = Kernel::my_receiver.create_capability (KBD) // keyboard user
kbd.set_cb (kc) Kernel::set_recv_arg (Kernel::Cap (slot, KBD))
Kernel::Cap tc = Kernel::my_receiver.create_capability (TP) kbd = kbd_dev.create_user (driver_memory)
tp.set_cb (tc) kbd_dev.use (kbd)
pwm.call (1) // keyboard callback
Kernel::set_recv_arg (cb)
Kernel::my_receiver.create_capability (KBD)
kbd.set_cb (cb.copy ())
// keyboard name list
Kernel::set_recv_arg (Kernel::Cap (slot, KEYNAMES))
kbd_names = kbd.get_keys ()
// buzzer user
Kernel::set_recv_arg (Kernel::Cap (slot, BUZZER))
buzzer = buz_dev.create_user (driver_memory)
buz_dev.use (buzzer)
// clean up.
Kernel::free_cap (cb)
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":" //char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$*T\nE& B=UDLR+-F^CA"
Kernel::Num start (): Kernel::Num start ():
kdebug ("init started\n")
setup () setup ()
kdebug ("init set up\n") kdebug ("init set up\n")
while true: while true:
kdebug ("init waiting\n")
Kernel::wait () Kernel::wait ()
kdebug ("init done waiting\n")
switch Kernel::recv.protected_data.value (): switch Kernel::recv.protected_data.value ():
case SYSREQ:
unsigned code = Kernel::recv.data[0].l
kdebug ("\n\nSystem request ")
if code & Keyboard::RELEASE:
kdebug ("released.\n\n")
else:
kdebug ("pressed.\n\n")
break
case KBD: case KBD:
unsigned code = Kernel::recv.data[0].l unsigned code = Kernel::recv.data[0].l
if code & Keyboard::RELEASE: if code & Keyboard::RELEASE:
break kdebug_char ('-')
kdebug_char (decode_kbd[code])
if code == 0:
Kernel::Caps ().print (~0)
break
case TP:
unsigned leds = 0
if Kernel::recv.data[0].l & 1:
leds |= 0x1
else: else:
leds |= 0x4 kdebug_char ('+')
if !(Kernel::recv.data[0].l & Keyboard::RELEASE): buzzer.beep (2000, 100, 0)
leds |= 0x2 String name = kbd_names.get (code & ~Keyboard::RELEASE)
lockleds.call (leds) unsigned size = name.get_size ().l
char buffer[16]
for unsigned i = 0; i < size; i += 16:
name.get_chars (i, buffer)
for unsigned k = 0; k < size - i && k < 16; ++k:
kdebug_char (buffer[k])
kdebug_char ('\n')
Kernel::free_cap (name)
break break

View File

@ -1,60 +0,0 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.hhp: interface for init task.
// 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/>.
#ifndef __INIT_HH
#define __INIT_HH
#include "iris.hh"
struct Init : public Kernel::Cap:
Init (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
REGISTER_GPIO = 0x1000
REGISTER_LCD
enum protected_codes:
GPIO_KEYBOARD = 32
GPIO_TOUCHPAD
GPIO_LOCKLEDS
GPIO_PWM
LCD_SET_EOF_CB
LOG
void register_gpio ():
Kernel::Caps c = Kernel::my_memory.create_caps (4)
unsigned slot = c.use ()
Kernel::set_recv_arg (Kernel::Cap (slot, 0))
Kernel::my_receiver.create_capability (GPIO_KEYBOARD)
Kernel::set_recv_arg (Kernel::Cap (slot, 1))
Kernel::my_receiver.create_capability (GPIO_TOUCHPAD)
Kernel::set_recv_arg (Kernel::Cap (slot, 2))
Kernel::my_receiver.create_capability (GPIO_LOCKLEDS)
Kernel::set_recv_arg (Kernel::Cap (slot, 3))
Kernel::my_receiver.create_capability (GPIO_PWM)
ocall (c, CAP_MASTER_DIRECT | REGISTER_GPIO)
Kernel::my_memory.destroy (c)
Kernel::free_cap (c)
Kernel::free_slot (slot)
void register_lcd ():
Kernel::Caps c = Kernel::my_memory.create_caps (1)
unsigned slot = c.use ()
Kernel::set_recv_arg (Kernel::Cap (slot, 0))
Kernel::my_receiver.create_capability (LCD_SET_EOF_CB)
ocall (c, CAP_MASTER_DIRECT | REGISTER_LCD)
Kernel::my_memory.destroy (c)
Kernel::free_cap (c)
Kernel::free_slot (slot)
#endif

View File

@ -0,0 +1,366 @@
#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")

View File

@ -17,7 +17,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "devices.hh" #include "devices.hh"
#include "init.hh"
#define ARCH #define ARCH
#include "arch.hh" #include "arch.hh"
@ -130,6 +129,7 @@ class Udc:
char configuration char configuration
unsigned size unsigned size
char const *ptr char const *ptr
bool rebooting
bool vendor (Setup *s) bool vendor (Setup *s)
bool get_descriptor (unsigned type, unsigned idx, unsigned len) bool get_descriptor (unsigned type, unsigned idx, unsigned len)
bool handle_setup (Setup *s) bool handle_setup (Setup *s)
@ -149,7 +149,6 @@ Udc::my_config const Udc::config_descriptor = {
Udc::String <7> const Udc::s_manufacturer = { sizeof (String <7>), String <7>::Type, { 'I', 'n', 'g', 'e', 'n', 'i', 'c' } } Udc::String <7> const Udc::s_manufacturer = { sizeof (String <7>), String <7>::Type, { 'I', 'n', 'g', 'e', 'n', 'i', 'c' } }
Udc::String <22> const Udc::s_product = { sizeof (String <22>), String <22>::Type, { 'J', 'Z', '4', '7', '4', '0', ' ', 'U', 'S', 'B', ' ', 'B', 'o', 'o', 't', ' ', 'D', 'e', 'v', 'i', 'c', 'e'} } Udc::String <22> const Udc::s_product = { sizeof (String <22>), String <22>::Type, { 'J', 'Z', '4', '7', '4', '0', ' ', 'U', 'S', 'B', ' ', 'B', 'o', 'o', 't', ' ', 'D', 'e', 'v', 'i', 'c', 'e'} }
void Udc::init (): void Udc::init ():
kdebug ("udc: init\n")
state = IDLE state = IDLE
configuration = 0 configuration = 0
size = 0 size = 0
@ -165,19 +164,16 @@ void Udc::init ():
UDC_INDEX = 0 UDC_INDEX = 0
bool Udc::vendor (Setup *s): bool Udc::vendor (Setup *s):
kdebug ("udc: vendor\n")
if s->request_type & 0x80: if s->request_type & 0x80:
kdebug ("udc: vendorsend\n")
static char const *name = "abcdefgh" static char const *name = "abcdefgh"
ptr = name ptr = name
size = 8 size = 8
state = TX state = TX
rebooting = true
return true return true
kdebug ("udc: vendorrecv\n")
return true return true
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
kdebug ("udc: getdesc\n")
switch type: switch type:
case Configuration::Type: case Configuration::Type:
if idx != 1: if idx != 1:
@ -268,7 +264,6 @@ bool Udc::handle_setup (Setup *s):
return true return true
void Udc::interrupt (): void Udc::interrupt ():
kdebug ("udc: inter\n")
unsigned i = UDC_INTRUSB unsigned i = UDC_INTRUSB
if i & UDC_INTR_RESET: if i & UDC_INTR_RESET:
kdebug ("udc: reset\n") kdebug ("udc: reset\n")
@ -276,7 +271,6 @@ void Udc::interrupt ():
return return
i = UDC_INTRIN i = UDC_INTRIN
if i & (1 << 0): if i & (1 << 0):
kdebug ("udc: ep0\n")
// Interrupt on endpoint 0. // Interrupt on endpoint 0.
unsigned csr = UDC_CSR0 unsigned csr = UDC_CSR0
if csr & UDC_CSR0_SENTSTALL: if csr & UDC_CSR0_SENTSTALL:
@ -287,10 +281,10 @@ void Udc::interrupt ():
state = IDLE state = IDLE
switch state: switch state:
case IDLE: case IDLE:
kdebug ("udc: idle\n") if rebooting:
Kernel::reboot ()
if !(csr & UDC_CSR0_OUTPKTRDY): if !(csr & UDC_CSR0_OUTPKTRDY):
return return
kdebug ("udc: packet\n")
union { unsigned d[2]; Setup s; } packet union { unsigned d[2]; Setup s; } packet
packet.d[0] = UDC_FIFO (0) packet.d[0] = UDC_FIFO (0)
packet.d[1] = UDC_FIFO (0) packet.d[1] = UDC_FIFO (0)
@ -327,30 +321,41 @@ void Udc::interrupt ():
UDC_CSR0 = csr UDC_CSR0 = csr
void Udc::log (unsigned c): void Udc::log (unsigned c):
kdebug ("udc: log\n") kdebug ("udc: log ")
kdebug_char (c)
kdebug ("\n")
enum pdata:
LOG = 32
Kernel::Num start (): Kernel::Num start ():
map_udc () map_udc ()
map_gpio ()
Udc udc Udc udc
kdebug ("udc: start\n")
udc.init () udc.init ()
kdebug ("udc: done init\n") Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
Kernel::Cap logcap = Kernel::my_receiver.create_capability (Init::LOG)
kdebug ("udc: made cap\n")
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory") __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
kdebug ("udc: registered cap\n")
Kernel::register_interrupt (IRQ_UDC) Kernel::register_interrupt (IRQ_UDC)
kdebug ("udc: registered interrupt\n") //Kernel::my_receiver.set_alarm (HZ)
while true: while true:
kdebug ("udc: waiting\n")
Kernel::wait () Kernel::wait ()
switch Kernel::recv.protected_data.l: switch Kernel::recv.protected_data.l:
case ~0:
// alarm.
Kernel::my_receiver.set_alarm (HZ)
kdebug ("alarm; d =")
unsigned mask[4] = { 0x00000000, 0xfe000000, 0x09c00000, 0x3dfc8055 }
for unsigned i = 0; i < 4; ++i:
kdebug (" ")
kdebug_num (gpio_get_port (i) & mask[i])
kdebug ("\n")
break
case IRQ_UDC: case IRQ_UDC:
udc.interrupt () udc.interrupt ()
Kernel::register_interrupt (IRQ_UDC) Kernel::register_interrupt (IRQ_UDC)
break break
case Init::LOG: case LOG:
udc.log (Kernel::recv.data[0].l) udc.log (Kernel::recv.data[0].l)
break break
default: default:

View File

@ -168,6 +168,15 @@ static kCaps reply_caps, replied_caps
static kReceiver *reply_target static kReceiver *reply_target
static Kernel::Num reply_protected static Kernel::Num reply_protected
static void reply_num (Kernel::Num num):
kCapability::Context c
c.data[0] = num
c.data[1] = 0
if reply_target:
reply_target->send_message (reply_protected, &c)
else:
dpanic (0, "nothing to reply to")
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0): static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
kCapability::Context c kCapability::Context c
c.data[0] = Kernel::Num (num1, num2) c.data[0] = Kernel::Num (num1, num2)
@ -208,6 +217,13 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK: case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs) reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
return return
case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK:
if !c->arg.valid () || c->arg->target != receiver:
dpanic (0, "wrong argument for get_protected")
reply_num (~0)
return
reply_num (c->arg->protected_data)
return
case Kernel::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK: case Kernel::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK:
reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0) reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
return return
@ -517,6 +533,8 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
kPage *page = (kPage *)c->arg->protected_data.l kPage *page = (kPage *)c->arg->protected_data.l
reply_num (page->frame & ~0xc0000000) reply_num (page->frame & ~0xc0000000)
return return
case Kernel::Thread::PRIV_REBOOT & REQUEST_MASK:
arch_reboot ()
case Kernel::Thread::PRIV_PANIC & REQUEST_MASK: case Kernel::Thread::PRIV_PANIC & REQUEST_MASK:
panic (c->data[1].l, "panic requested by thread") panic (c->data[1].l, "panic requested by thread")
reply_num (~0) reply_num (~0)

View File

@ -129,6 +129,7 @@ namespace Kernel:
struct Page struct Page
struct Memory struct Memory
void print_caps ()
unsigned alloc_slot () unsigned alloc_slot ()
Cap alloc_cap () Cap alloc_cap ()
void free_slot (unsigned slot) void free_slot (unsigned slot)
@ -256,6 +257,7 @@ namespace Kernel:
CREATE_CAPABILITY CREATE_CAPABILITY
CREATE_CALL_CAPABILITY CREATE_CALL_CAPABILITY
CREATE_ASYNC_CALL_CAPABILITY CREATE_ASYNC_CALL_CAPABILITY
GET_PROTECTED
GET_REPLY_PROTECTED_DATA GET_REPLY_PROTECTED_DATA
SET_REPLY_PROTECTED_DATA SET_REPLY_PROTECTED_DATA
GET_ALARM GET_ALARM
@ -272,6 +274,8 @@ namespace Kernel:
Cap create_capability (Num protected_data): Cap create_capability (Num protected_data):
icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data) icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
return get_arg () return get_arg ()
Num get_protected (Kernel::Cap target):
return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED)
Num get_reply_protected_data (): Num get_reply_protected_data ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA) return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
void set_reply_protected_data (Num data): void set_reply_protected_data (Num data):
@ -309,6 +313,7 @@ namespace Kernel:
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner. // This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
SET_OWNER SET_OWNER
DBG_SEND DBG_SEND
PRIV_REBOOT
PRIV_PANIC PRIV_PANIC
// These get/set_info are not arch-specific. // These get/set_info are not arch-specific.
enum info_type: enum info_type:
@ -478,6 +483,8 @@ namespace Kernel:
return get_arg () return get_arg ()
inline void dbg_send (unsigned code, unsigned bits = 32): inline void dbg_send (unsigned code, unsigned bits = 32):
my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits)) my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits))
inline void reboot ():
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT)
inline void panic (unsigned code): inline void panic (unsigned code):
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code) my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code)

View File

@ -263,6 +263,7 @@ void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address)
kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly) kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly)
void kPage_arch_update_mapping (kPage *page) void kPage_arch_update_mapping (kPage *page)
void arch_register_interrupt (unsigned num, kReceiverP r) void arch_register_interrupt (unsigned num, kReceiverP r)
void arch_reboot ()
bool kMemory::map (kPage *page, unsigned address, bool readonly = false): bool kMemory::map (kPage *page, unsigned address, bool readonly = false):
return kMemory_arch_map (this, page, address, readonly) return kMemory_arch_map (this, page, address, readonly)

View File

@ -289,3 +289,15 @@ void arch_register_interrupt (unsigned num, kReceiver *r):
intc_unmask_irq (num) intc_unmask_irq (num)
else: else:
intc_mask_irq (num) intc_mask_irq (num)
void arch_reboot ():
// Wait for serial port to be done.
while !(UART0_LSR & UARTLSR_TEMT):
// Reboot.
wdt_select_extalclk ()
wdt_select_clk_div1 ()
wdt_set_data (1)
wdt_set_count (0)
wdt_start ()
// Wait for wdt to trigger reboot.
while true:

View File

@ -17,7 +17,7 @@
load = 0x80000000 load = 0x80000000
ARCH_CXXFLAGS = -DNUM_THREADS=2 ARCH_CXXFLAGS = -DNUM_THREADS=4
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
CROSS = mipsel-linux-gnu- CROSS = mipsel-linux-gnu-
OBJDUMP = $(CROSS)objdump OBJDUMP = $(CROSS)objdump
@ -28,7 +28,7 @@ LDFLAGS = --omagic -Ttext $(load)
arch_iris_sources = mips/interrupts.cc mips/arch.cc arch_iris_sources = mips/interrupts.cc mips/arch.cc
boot_sources = mips/init.cc mips/nanonote/board.cc boot_sources = mips/init.cc mips/nanonote/board.cc
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
boot_threads = init udc boot_threads = init udc nanonote-gpio buzzer
test: iris.raw nanonote-boot test: iris.raw nanonote-boot
./nanonote-boot iris.raw 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8') ./nanonote-boot iris.raw 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')
@ -50,7 +50,7 @@ mips/entry.o: $(boot_threads)
mips/init.o: TARGET_FLAGS = -I/usr/include mips/init.o: TARGET_FLAGS = -I/usr/include
$(boot_threads): TARGET_FLAGS = -I. $(boot_threads): TARGET_FLAGS = -I.
$(boot_threads): LDFLAGS = -EL $(boot_threads): LDFLAGS = -EL
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh boot-programs/init.hh $(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh
lcd: boot-programs/charset.data lcd: boot-programs/charset.data
boot-programs/charset.data: boot-programs/charset boot-programs/charset.data: boot-programs/charset
@ -63,4 +63,4 @@ boot-programs/charset.data: boot-programs/charset
iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources)) iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources))
$(LD) $(LDFLAGS) $^ -o $@ $(LD) $(LDFLAGS) $^ -o $@
ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) boot_programs/init.hh boot_programs/devices.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) boot_programs/devices.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw

View File

@ -29,6 +29,7 @@ void board_init ():
gpio_as_aic () gpio_as_aic ()
gpio_as_lcd_16bit () gpio_as_lcd_16bit ()
gpio_as_msc () gpio_as_msc ()
setup_sdram ()
// Set up keyboard: this breaks uart receive. // Set up keyboard: this breaks uart receive.
gpio_as_gpio (3, 0x05fc0000) gpio_as_gpio (3, 0x05fc0000)
tcu_stop_counter (0) tcu_stop_counter (0)

View File

@ -117,7 +117,7 @@ static void __map_io (unsigned physical, unsigned mapping):
#define map_intc() do { __map_io (INTC_PHYSICAL, INTC_BASE); } while (0) #define map_intc() do { __map_io (INTC_PHYSICAL, INTC_BASE); } while (0)
#define map_tcu() do { __map_io (TCU_PHYSICAL, TCU_BASE); } while (0) #define map_tcu() do { __map_io (TCU_PHYSICAL, TCU_BASE); } while (0)
#define map_wdt() do { __map_io (WDT_PHYSICAL, WDT_BASE); } while (0) #define map_wdt() do { __map_io (WDT_PHYSICAL, WDT_BASE); } while (0)
#define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (0) #define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (1)
#define map_gpio() do { __map_io (GPIO_PHYSICAL, GPIO_BASE); } while (0) #define map_gpio() do { __map_io (GPIO_PHYSICAL, GPIO_BASE); } while (0)
#define map_aic() do { __map_io (AIC_PHYSICAL, AIC_BASE); } while (0) #define map_aic() do { __map_io (AIC_PHYSICAL, AIC_BASE); } while (0)
#define map_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0) #define map_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0)
@ -2322,7 +2322,7 @@ static void gpio_as_interrupt (unsigned p, unsigned pins, bool high, bool level)
if high: if high:
GPIO_PXDIRS (p) = pins GPIO_PXDIRS (p) = pins
else: else:
GPIO_PXDIRS (p) = pins GPIO_PXDIRC (p) = pins
GPIO_PXFLGC (p) = pins GPIO_PXFLGC (p) = pins
static void gpio_set (unsigned p, unsigned pins): static void gpio_set (unsigned p, unsigned pins):
@ -3577,4 +3577,103 @@ static void cim_enable_nongated_clock_mode ():
static void setup_sdram ():
// SDRAM BANK Number: 1, 2
unsigned CONFIG_NR_DRAM_BANKS = 1
// CAS latency: 2 or 3
unsigned SDRAM_CASL = 3
// SDRAM Timings, unit: ns
// RAS# Active Time
unsigned SDRAM_TRAS = 45
// RAS# to CAS# Delay
unsigned SDRAM_RCD = 20
// RAS# Precharge Time
unsigned SDRAM_TPC = 20
// Write Latency Time
unsigned SDRAM_TRWL = 7
// Refresh period: 4096 refresh cycles/64ms
unsigned SDRAM_TREF = 15625
unsigned dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns
unsigned cas_latency_sdmr[2] = { EMC_SDMR_CAS_2, EMC_SDMR_CAS_3 }
unsigned cas_latency_dmcr[2] = { 1 << EMC_DMCR_TCL_BIT, 2 << EMC_DMCR_TCL_BIT }
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}
cpu_clk = 225000000
gpio_as_sdram_32bit ()
unsigned SDRAM_BW16 = 0
unsigned SDRAM_BANK4 = 1
unsigned SDRAM_ROW = 13
unsigned SDRAM_COL = 9
mem_clk = cpu_clk * div[cpm_get_cdiv()] / div[cpm_get_mdiv()]
EMC_BCR = 0
EMC_RTCSR = 0
unsigned SDRAM_ROW0 = 11
unsigned SDRAM_COL0 = 8
unsigned SDRAM_BANK40 = 0
dmcr0 = ((SDRAM_ROW0-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL0-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK40<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
// Basic DMCR value
dmcr = ((SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK4<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
// SDRAM timimg
ns = 1000000000 / mem_clk
tmp = SDRAM_TRAS / ns
if tmp < 4:
tmp = 4
if tmp > 11:
tmp = 11
dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT)
tmp = SDRAM_RCD/ns
if tmp > 3:
tmp = 3
dmcr |= (tmp << EMC_DMCR_RCD_BIT)
tmp = SDRAM_TPC/ns
if tmp > 7:
tmp = 7
dmcr |= (tmp << EMC_DMCR_TPC_BIT)
tmp = SDRAM_TRWL/ns
if tmp > 3:
tmp = 3
dmcr |= (tmp << EMC_DMCR_TRWL_BIT)
tmp = (SDRAM_TRAS + SDRAM_TPC)/ns
if tmp > 14:
tmp = 14
dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT)
// SDRAM mode value
sdmode = EMC_SDMR_BT_SEQ | EMC_SDMR_OM_NORMAL | EMC_SDMR_BL_4 | cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)];
// Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0
EMC_DMCR = dmcr
REG8(EMC_SDMR0|sdmode) = 0
// Wait for precharge, > 200us
tmp = (cpu_clk / 1000000) * 1000
volatile unsigned t = tmp
while t--:
// Stage 2. Enable auto-refresh
EMC_DMCR = dmcr | EMC_DMCR_RFSH
tmp = SDRAM_TREF/ns
tmp = tmp/64 + 1
if tmp > 0xff:
tmp = 0xff
EMC_RTCOR = tmp
EMC_RTCNT = 0
// Divisor is 64, CKO/64
EMC_RTCSR = EMC_RTCSR_CKS_64
// Wait for number of auto-refresh cycles
tmp = (cpu_clk / 1000000) * 1000
t = tmp
while t--:
// Stage 3. Mode Register Set
EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET
REG8(EMC_SDMR0|sdmode) = 0
// Set back to basic DMCR value
EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET
#endif #endif

View File

@ -132,6 +132,13 @@ nanonote::nanonote (unsigned skip):
if !find_device (skip): if !find_device (skip):
std::cerr << "unable to find NanoNote device.\n"; std::cerr << "unable to find NanoNote device.\n";
throw "unable to find NanoNote device"; throw "unable to find NanoNote device";
// Get info will reset the device if it has already booted into Iris.
get_cpu_info ()
usb_close (handle)
sleep (1)
if !find_device (skip):
std::cerr << "unable to find NanoNote device again.\n";
throw "unable to find NanoNote device again";
void nanonote::get_cpu_info (): void nanonote::get_cpu_info ():
char buffer[8] char buffer[8]
@ -141,14 +148,12 @@ void nanonote::get_cpu_info ():
cpu_info = std::string (buffer, 8) cpu_info = std::string (buffer, 8)
void nanonote::request (requests r, unsigned data): void nanonote::request (requests r, unsigned data):
std::cerr << "requesting " << r << " (data = " << std::hex << data << ")" << std::endl
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, r, (data >> 16) & 0xffff, data & 0xffff, NULL, 0, timeout) < 0: if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, r, (data >> 16) & 0xffff, data & 0xffff, NULL, 0, timeout) < 0:
std::cerr << "unable to send control message to NanoNote: " << usb_strerror () << ".\n" std::cerr << "unable to send control message to NanoNote: " << usb_strerror () << ".\n"
throw "unable to send control message to NanoNote" throw "unable to send control message to NanoNote"
void nanonote::send_file (unsigned address, unsigned size, char const *data): void nanonote::send_file (unsigned address, unsigned size, char const *data):
request (VR_SET_DATA_ADDRESS, address) request (VR_SET_DATA_ADDRESS, address)
//request (VR_SET_DATA_LENGTH, size)
char const *ptr = data char const *ptr = data
while ptr - data < size: while ptr - data < size:
int ret = usb_bulk_write (handle, out_ep, ptr, size - (ptr - data), timeout) int ret = usb_bulk_write (handle, out_ep, ptr, size - (ptr - data), timeout)
@ -158,20 +163,12 @@ void nanonote::send_file (unsigned address, unsigned size, char const *data):
ptr += ret ptr += ret
void nanonote::boot (std::string const &data, unsigned load, unsigned start): void nanonote::boot (std::string const &data, unsigned load, unsigned start):
get_cpu_info ()
std::cerr << "info: " << cpu_info << std::endl
send_file (stage1_load, stage1_size, stage1) send_file (stage1_load, stage1_size, stage1)
request (VR_PROGRAM_START1, stage1_start) request (VR_PROGRAM_START1, stage1_start)
usleep (100) usleep (100)
send_file (load, data.size (), data.data ()) send_file (load, data.size (), data.data ())
request (VR_FLUSH_CACHES) request (VR_FLUSH_CACHES)
request (VR_PROGRAM_START2, start) request (VR_PROGRAM_START2, start)
sleep (1)
get_cpu_info ()
std::cerr << "info: ";
for unsigned i = 0; i < cpu_info.size (); ++i:
std::cerr << std::setfill ('0') << std::setw (2) << std::hex << (cpu_info[i] & 0xff);
std::cerr << std::endl
int main (int argc, char **argv): int main (int argc, char **argv):
if argc != 3: if argc != 3:

View File

@ -20,15 +20,6 @@
#define __KERNEL #define __KERNEL
#include "jz4740.hh" #include "jz4740.hh"
#define CONFIG_NR_DRAM_BANKS 1 // SDRAM BANK Number: 1, 2
#define SDRAM_CASL 3 // CAS latency: 2 or 3
// SDRAM Timings, unit: ns
#define SDRAM_TRAS 45 // RAS# Active Time
#define SDRAM_RCD 20 // RAS# to CAS# Delay
#define SDRAM_TPC 20 // RAS# Precharge Time
#define SDRAM_TRWL 7 // Write Latency Time
#define SDRAM_TREF 15625 // Refresh period: 4096 refresh cycles/64ms
asm volatile (".set noreorder\n" asm volatile (".set noreorder\n"
"\t.globl __start\n" "\t.globl __start\n"
"\t.text\n" "\t.text\n"
@ -51,102 +42,5 @@ extern "C":
void start_cpp () void start_cpp ()
void start_cpp (): void start_cpp ():
unsigned dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns setup_sdram ()
unsigned cas_latency_sdmr[2] = { EMC_SDMR_CAS_2, EMC_SDMR_CAS_3 }
unsigned cas_latency_dmcr[2] = { 1 << EMC_DMCR_TCL_BIT, 2 << EMC_DMCR_TCL_BIT }
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}
cpu_clk = 225000000
gpio_as_sdram_32bit ()
unsigned SDRAM_BW16 = 0
unsigned SDRAM_BANK4 = 1
unsigned SDRAM_ROW = 13
unsigned SDRAM_COL = 9
mem_clk = cpu_clk * div[cpm_get_cdiv()] / div[cpm_get_mdiv()]
EMC_BCR = 0
EMC_RTCSR = 0
#define SDRAM_ROW0 11
#define SDRAM_COL0 8
#define SDRAM_BANK40 0
dmcr0 = ((SDRAM_ROW0-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL0-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK40<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
// Basic DMCR value
dmcr = ((SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK4<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
// SDRAM timimg
ns = 1000000000 / mem_clk
tmp = SDRAM_TRAS / ns
if tmp < 4:
tmp = 4
if tmp > 11:
tmp = 11
dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT)
tmp = SDRAM_RCD/ns
if tmp > 3:
tmp = 3
dmcr |= (tmp << EMC_DMCR_RCD_BIT)
tmp = SDRAM_TPC/ns
if tmp > 7:
tmp = 7
dmcr |= (tmp << EMC_DMCR_TPC_BIT)
tmp = SDRAM_TRWL/ns
if tmp > 3:
tmp = 3
dmcr |= (tmp << EMC_DMCR_TRWL_BIT)
tmp = (SDRAM_TRAS + SDRAM_TPC)/ns
if tmp > 14:
tmp = 14
dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT)
// SDRAM mode value
sdmode = EMC_SDMR_BT_SEQ | EMC_SDMR_OM_NORMAL | EMC_SDMR_BL_4 | cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)];
// Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0
EMC_DMCR = dmcr
REG8(EMC_SDMR0|sdmode) = 0
// Wait for precharge, > 200us
tmp = (cpu_clk / 1000000) * 1000
volatile unsigned t = tmp
while t--:
// Stage 2. Enable auto-refresh
EMC_DMCR = dmcr | EMC_DMCR_RFSH
tmp = SDRAM_TREF/ns
tmp = tmp/64 + 1
if tmp > 0xff:
tmp = 0xff
EMC_RTCOR = tmp
EMC_RTCNT = 0
// Divisor is 64, CKO/64
EMC_RTCSR = EMC_RTCSR_CKS_64
// Wait for number of auto-refresh cycles
tmp = (cpu_clk / 1000000) * 1000
t = tmp
while t--:
// Stage 3. Mode Register Set
EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET
REG8(EMC_SDMR0|sdmode) = 0
// Set back to basic DMCR value
EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET
// everything is ok now: return to boot loader to load stage 2. // everything is ok now: return to boot loader to load stage 2.
pll_init ()
cpm_start_all ()
gpio_as_uart0 ()
UART0_IER = 0
UART0_FCR = 0
UART0_MCR = 0
UART0_SIRCR = 0
UART0_UMR = 0
UART0_UACR = 0
UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 | UARTLCR_DLAB
unsigned uart_div = 3000000 / 16 / 9600
UART0_DLHR = uart_div >> 8
UART0_DLLR = uart_div
UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1
UART0_FCR = UARTFCR_UUE | UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS

View File

@ -27,7 +27,15 @@ thread0:
thread1: thread1:
.incbin "udc" .incbin "udc"
.balign 0x1000
thread2: thread2:
.incbin "nanonote-gpio"
.balign 0x1000
thread3:
.incbin "buzzer"
thread4:
// Everything from here may be freed after kernel initialization. // Everything from here may be freed after kernel initialization.
init_start: init_start:
@ -36,3 +44,5 @@ thread_start:
.word thread0 .word thread0
.word thread1 .word thread1
.word thread2 .word thread2
.word thread3
.word thread4

View File

@ -77,6 +77,9 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag
dbg_log_num (n) dbg_log_num (n)
dbg_log_char ('\n') dbg_log_char ('\n')
// If no log capability is registered, the machine just hangs. // If no log capability is registered, the machine just hangs.
#ifdef USE_SERIAL
arch_reboot ()
#endif
#endif #endif
#ifndef NDEBUG #ifndef NDEBUG
void dbg_send (unsigned num, unsigned bits): void dbg_send (unsigned num, unsigned bits):

26
plan
View File

@ -1,2 +1,28 @@
caps zonder size limit? caps zonder size limit?
invoke ipc: try sync; try receiver memory; try caller memory; fail. invoke ipc: try sync; try receiver memory; try caller memory; fail.
memories map:
top
- lcd
- keyboard
- sound
- led
- udc
- battery
- beeper
- msc
- nand
- filesystem
- network
- top session manager
- - user session
- - - program container
- - - - driver emulation
- - - - driver emulation
- - - - program
- - - program container
- - - - driver emulation
- - - - program
- - user session
...