1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-04-21 12:27:27 +03:00

fix bugs; work on userspace

This commit is contained in:
Bas Wijnen
2009-10-10 01:31:10 +02:00
parent 906f487b01
commit afb496f20b
19 changed files with 615 additions and 267 deletions

View File

@@ -23,10 +23,9 @@
class DevBuzzer:
static unsigned const pwm = 4
Kernel::Cap event
bool is_active, is_beeping
bool is_beeping
public:
DevBuzzer ():
is_active = false
is_beeping = false
gpio_as_pwm4 ()
tcu_stop_counter (pwm)
@@ -38,8 +37,8 @@ class DevBuzzer:
return
tcu_stop_counter (pwm)
event.invoke ()
is_active = false
Kernel::free_cap (event)
is_beeping = false
void beep (unsigned freq, unsigned ms, Kernel::Cap cb):
stop ()
event = cb
@@ -115,12 +114,11 @@ Kernel::Num start ():
break
switch Kernel::recv.data[0].l:
case Buzzer::BEEP:
// Volume is not used for this buzzer.
// Volume is not used by 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:

View File

@@ -17,6 +17,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "iris.hh"
#include "devices.hh"
// For some unknown reason, gcc needs this to be defined.
unsigned __gxx_personality_v0
@@ -33,7 +34,7 @@ namespace Kernel:
Thread my_thread
Memory my_memory
Cap my_call
Cap my_parent
Parent my_parent
__recv_data_t recv
void print_caps ():

View File

@@ -1,271 +0,0 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/devices.hhp: interfaces for core devices.
// 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 __IRIS_DEVICES_HH
#define __IRIS_DEVICES_HH
#include "iris.hh"
// List interface.
template <typename _T> //
struct List : public Kernel::Caps:
List (Kernel::Caps c = Kernel::Cap ()) : Kernel::Caps (c):
List <_T> create (unsigned size, Kernel::Memory mem = Kernel::my_memory):
return List <_T> (mem.create_caps (size))
void set (unsigned idx, _T value):
return Kernel::Caps::set (idx, value)
_T get (unsigned idx):
return _T (Kernel::Caps::get (idx))
/// A block of data with a size and content. Any character can be stored in it (including '\0').
struct String : public Kernel::Cap:
String (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
GET_SIZE = 0x2001
GET_CHARS
GET_PAGE
ID
/// Get the size of the string.
Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
/// Get exactly 16 characters. The index must be word-aligned.
char *get_chars (Kernel::Num idx, char buffer[16]):
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
unsigned *b = (unsigned *)buffer
b[0] = Kernel::recv.data[0].l
b[1] = Kernel::recv.data[0].h
b[2] = Kernel::recv.data[1].l
b[3] = Kernel::recv.data[1].h
return buffer
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
Cap get_page (Kernel::Num idx, Kernel::Page ret = Kernel::my_memory.create_page ()):
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
return ret
/// A writable String.
struct WString : public String:
WString (Kernel::Cap c = Kernel::Cap ()) : String (c):
enum request:
TRUNCATE = String::ID
SET_CHARS
SET_PAGE
ID
/// Set the size of the string. Strings may have a limit to this setting.
void truncate (Kernel::Num size):
call (CAP_MASTER_DIRECT | TRUNCATE, size)
/// Set exactly 4 characters. The index must be word-aligned.
void set_chars (Kernel::Num idx, char buffer[4]):
call (Kernel::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
void set_page (Kernel::Num idx, Kernel::Page page):
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.
struct Keyboard : public Kernel::Cap:
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
SET_CB = Device::ID
GET_KEYS
ID
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
enum constant:
RELEASE = 1 << 31
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
void set_cb (Kernel::Cap 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.
List <String> get_keys ():
icall (CAP_MASTER_DIRECT | GET_KEYS)
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.
struct Display : public Kernel::Cap:
Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
EOF_CB = Buzzer::ID
CREATE_FB
USE_FB
GET_INFO
ID
// 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.
void set_eof_cb (Kernel::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | EOF_CB)
// Create a framebuffer for the display. When not in use, it can be freed by the user.
// The pages must be cappages holding Page capabilities. They are filled by the display.
// The passed numbers must be 0 or match a mode that the device can use.
// The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer.
unsigned create_framebuffer (unsigned w = 0, unsigned h = 0, unsigned mode = 0):
return icall (Kernel::Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Kernel::Num ((w << 16) | h, mode)).l
// Use a framebuffer. The address must have been returned from display_create_framebuffer.
// w, h and mode must match the values given at creation time.
// unuse_cb is called the next time this operation is requested for this display.
void use_framebuffer (unsigned addr, Kernel::Cap unuse_cb = Kernel::Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0):
ocall (unuse_cb, Kernel::Num (CAP_MASTER_DIRECT | USE_FB, addr), Kernel::Num ((w << 16) | h, mode))
// Get information about the display.
void get_info ():
// TODO: Interface is to be designed.
// File system interface.
// filesystem-related interfaces: file, directory, stream, seekable, mappable.
// Normal files implement at least stream or seekable file. Directories implement directory.
struct File : public Kernel::Cap:
File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
INFO = Display::ID
CLOSE
MAP_HANDLE
ID
// Get information about the file.
Kernel::Num get_info (unsigned type):
return icall (Kernel::Num (CAP_MASTER_DIRECT | INFO, type))
// Close a file. If this is a directory, it implicitly closes all files opened from it.
void close ():
call (CAP_MASTER_DIRECT | CLOSE)
// Map a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
File map_handle ():
icall (CAP_MASTER_DIRECT | MAP_HANDLE)
return Kernel::get_arg ()
// Directory interface.
struct Directory : public File:
Directory (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request:
GET_SIZE = File::ID
GET_NAME
GET_FILE
GET_FILE_INFO
CREATE_FILE
DELETE_FILE
ID
// Get the number of entries in this directory.
Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename. The return value is the size of the string, the page is filled with the string itself.
String get_name (Kernel::Num idx):
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
return Kernel::get_arg ()
// Get the file.
File get_file (Kernel::Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
return Kernel::get_arg ()
// Get file info. This returns the same information as file_get_info, without opening the file.
Kernel::Num get_file_info (Kernel::Num idx, unsigned type):
return icall (Kernel::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
// Create a new file. After this, any index may map to a different file.
File create_file (String name):
icall (CAP_MASTER_DIRECT | CREATE_FILE)
return Kernel::get_arg ()
// Delete a file. After this, any index may map to a different file.
void delete_file (Kernel::Num idx):
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Stream interface.
struct Stream : public File:
Stream (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request:
READ = Directory::ID
WRITE
ID
// Try to read size bytes. Returns the number of bytes successfully read.
Kernel::Num read (Kernel::Num size):
return icall (CAP_MASTER_DIRECT | READ, size)
// Try to write size bytes. Returns the number of bytes successfully written.
Kernel::Num write (String s, Kernel::Num size):
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
// Seekable file interface.
struct Seekable : public File:
Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c):
enum request:
READ = Stream::ID
WRITE
TRUNCATE
ID
// Try to read size bytes from position idx. Returns the number of bytes successfully read.
Kernel::Num read (Kernel::Num idx, unsigned size):
return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, size), idx)
// Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written.
Kernel::Num write (Kernel::Num idx, String s):
return ocall (s, CAP_MASTER_DIRECT | WRITE, idx)
// Truncate file to size idx. The file is extended with zeroes if it gets longer.
void truncate (Kernel::Num idx):
call (CAP_MASTER_DIRECT | TRUNCATE, idx)
// Mappable file interface.
struct Mappable : public Seekable:
Mappable (Kernel::Cap c = Kernel::Cap ()) : Seekable (c):
// TODO: to be designed.
// Block device interface.
struct Block_device : public Mappable:
Block_device (Kernel::Cap c = Kernel::Cap ()) : Mappable (c):
// TODO: to be designed.
// TODO.
// Sound interface.
// Usb interfaces (port, device).
// Pointer interface. (Only movement; buttons follow keyboard interface.)
// Network interface.
// Camera interface.
// Terminal interfaces.
#endif

View File

@@ -19,28 +19,50 @@
#include "devices.hh"
#include "iris.hh"
static Keyboard kbd, sysreq
static Buzzer buzzer
static Keyboard sysreq
static Device kbd_dev, buz_dev
static List <String> kbd_names
static unsigned slot
// Event types.
enum type:
MEMORY
KBDDEV
KBD
KEYNAMES
SYSREQ
KBDDEV
BUZDEV
BUZZER
static void user_reply (Kernel::Cap target, unsigned dev):
switch dev:
case Keyboard::ID:
// keyboard user
kdebug ("keyboard requested\n")
Kernel::Cap kbd = kbd_dev.create_user (Kernel::Cap ())
kbd_dev.use (kbd)
target.invoke (0, 0, kbd.copy ())
Kernel::free_cap (kbd)
break
case Buzzer::ID:
// buzzer user
kdebug ("buzzer requested\n")
Kernel::Cap buzzer = buz_dev.create_user (Kernel::Cap ())
buz_dev.use (buzzer)
kdebug ("invoking reply: ")
kdebug_num (target.code)
kdebug ("\n")
target.invoke (0, 0, buzzer.copy ())
Kernel::free_cap (buzzer)
break
default:
kdebug ("invalid id requested:")
kdebug_num (dev)
kdebug_char ('\n')
break
static void setup ():
unsigned state = 0
Kernel::Caps caps = Kernel::my_memory.create_caps (32)
slot = caps.use ()
Kernel::set_recv_arg (Kernel::Cap (slot, MEMORY))
Kernel::Cap driver_memory = Kernel::my_memory.create_memory ()
Kernel::Caps slot0 = Kernel::my_thread.get_caps (0)
Kernel::Cap user
unsigned device
while true:
Kernel::wait ()
Kernel::Cap reply = Kernel::get_reply ()
@@ -59,44 +81,38 @@ static void setup ():
default:
kdebug ("unexpected keyboard\n")
break
reply.invoke ()
Kernel::free_cap (reply)
break
case Buzzer::ID:
caps.set (BUZDEV, arg.copy ())
buz_dev = Kernel::Cap (slot, BUZDEV)
reply.invoke ()
Kernel::free_cap (reply)
break
case Parent::GET_DEVICE:
user = reply
device = Kernel::recv.data[1].l
slot0.print (reply.idx ())
break
default:
kdebug ("unknown setup request for init\n")
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
kdebug ("unknown setup request for init\n")
continue
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
if ++state == 3:
if ++state == 4:
break
// sysreq
kdebug ("using sysreq\n")
Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ)
sysreq.set_cb (cb.copy ())
// keyboard user
Kernel::set_recv_arg (Kernel::Cap (slot, KBD))
kbd = kbd_dev.create_user (driver_memory)
kbd_dev.use (kbd)
// 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\nE& B=UDLR+-F^CA"
// First user reply.
kdebug ("sending first user reply\n")
user_reply (user, device)
Kernel::free_cap (user)
Kernel::Num start ():
setup ()
@@ -112,20 +128,11 @@ Kernel::Num start ():
else:
kdebug ("pressed.\n\n")
break
case KBD:
unsigned code = Kernel::recv.data[0].l
if code & Keyboard::RELEASE:
kdebug_char ('-')
else:
kdebug_char ('+')
buzzer.beep (2000, 100, 0)
String name = kbd_names.get (code & ~Keyboard::RELEASE)
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)
default:
if Kernel::recv.data[0].l != Parent::GET_DEVICE:
kdebug ("invalid call from user\n")
break
Kernel::Cap reply = Kernel::get_reply ()
user_reply (reply, Kernel::recv.data[1].l)
Kernel::free_cap (reply)
break

View File

@@ -27,9 +27,15 @@ extern unsigned char const charset[127-32][6]
#define assert(x) do { while (!(x)) kdebug ("assertion failed " #x); } while (0)
#if defined (TRENDTAC)
// For now, support only 16 bpp.
// Screen is 800x480 tft.
static unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
#else if defined (NANONOTE)
static unsigned h = 320, v = 240, fps = 70, Bpp = 3
#else
#error unknown board
#endif
#define frame_size (v * h * Bpp)
static unsigned physical_descriptor
@@ -40,21 +46,49 @@ struct Descriptor:
unsigned id
unsigned cmd
#if defined (TRENDTAC)
static void reset ():
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
LCD_VSYNC = vs
LCD_HSYNC = hs
LCD_DAV = (vs << 16) | (vs + v)
LCD_DAH = (hs << 16) | (hs + h)
LCD_VAT = ((hs + h) << 16) | (vs + v)
#if defined (TRENDTAC)
unsigned fps = 60
// Vertical timings.
unsigned vps = 0, vpe = vps + 20, vds = vpe, vde = vds + v, vt = vde
// Horizontal timings.
unsigned hps = 0, hpe = hps + 80, hds = hpe, hde = hds + h, ht = hde
unsigned extra = 0
// Bits per pixel.
unsigned bpp = LCD_CTRL_BPP_16
// Configuration.
#define MODE_TFT_GEN 0
#define VSYNC_N (1 << 8)
LCD_CFG = MODE_TFT_GEN | VSYNC_N
unsigned cfg = MODE_TFT_GEN | VSYNC_N
#elif defined (NANONOTE)
unsigned fps = 70
// Vertical timings.
unsigned vps = 0, vpe = vps + 1, vds = vpe + 20, vde = vds + v, vt = vde + 1
// Horizontal timings.
unsigned hps = 0, hpe = hps + 1, hds = hpe + 140, hde = hds + h, ht = hde + 273
// 3 bytes per pixel, so for the display area 2 extra clocks are sent.
unsigned extra = 2
// Bits per pixel.
unsigned bpp = LCD_CTRL_BPP_18_24
// Configuration.
unsigned cfg = LCD_CFG_MODE_TFT_SERIAL_TFT | LCD_CFG_PCP | LCD_CFG_HSP | LCD_CFG_VSP
#else
#error unknown board
#endif
LCD_CTRL = bpp | LCD_CTRL_BST_16
LCD_VSYNC = (vps << 16) | vpe
LCD_HSYNC = (hps << 16) | hpe
LCD_DAV = (vds << 16) | vde
LCD_DAH = (hds << 16) | hde
LCD_VAT = (ht << 16) | vt
LCD_CFG = cfg
cpm_stop_lcd ()
unsigned pixclock = fps * (hs + h) * (vs + v)
unsigned pixclock = fps * (ht + extra * (hde - hds)) * vt
#if defined (TRENDTAC)
unsigned pllout = cpm_get_pllout ()
CPM_CFCR2 = pllout / pixclock - 1
@@ -63,18 +97,29 @@ static void reset ():
assert (val <= 0xf)
cpm_set_lcdclk_div (val)
CPM_CFCR |= CPM_CFCR_UPE
#elif defined (NANONOTE)
unsigned val = cpm_get_pllout2 () / pclk - 1
if val > 0x3ff:
kdebug ("pixel clock too large\n")
Kernel::panic ()
return
cpm_set_pixdiv (val);
val = cpm_get_pllout () / (pixclock * 3)
if val > 0x1f:
kdebug ("pixel divider too large\n")
Kernel::panic ()
return
cpm_set_ldiv (val)
// Update dividers.
CPM_CPCCR |= CPM_CPCCR_CE
#endif
cpm_start_lcd ()
LCD_DA0 = physical_descriptor
lcd_set_ena ()
lcd_enable_eof_intr ()
#elif defined (NANONOTE)
static void reset ():
// TODO
#else
#error unknown board
#endif
static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff, unsigned bg = 0x0000):
if ch < 32 || ch > 126:
@@ -83,19 +128,19 @@ static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff,
unsigned lookup[2] = { bg, fg }
for unsigned k = 0; k < 6; ++k:
for unsigned r = 0; r < 8; ++r:
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * 800 + x * 6 + k] = lookup[charset[ch][k] & (1 << r) ? 1 : 0]
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * h + x * 6 + k] = lookup[charset[ch][k] & (1 << r) ? 1 : 0]
static unsigned log_x = 1, log_y = 1
static void inc_logx ():
if ++log_x >= 800 / 6:
if ++log_x >= h / 6:
log_x = 1
if ++log_y >= 480 / 8:
if ++log_y >= v / 8:
log_y = 1
static void log_char (unsigned ch):
switch ch:
case '\n':
while log_x < 800 / 6:
while log_x < h / 6:
putchar (log_x++, log_y, ' ')
inc_logx ()
break
@@ -138,22 +183,22 @@ Kernel::Num start ():
p.alloc_physical (physical + i * PAGE_SIZE, false, true)
Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE)
Kernel::free_cap (p)
for unsigned y = 0; y < 480; ++y:
unsigned g = (y << 6) / 480
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
for unsigned x = 0; x < 800; ++x:
unsigned r = (x << 5) / 800
unsigned b = ((9 * x * x + 25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
for unsigned y = 0; y < v; ++y:
unsigned g = (y << 6) / v
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * h * h + 25 * v * v)
for unsigned x = 0; x < h; ++x:
unsigned r = (x << 5) / h
unsigned b = ((9 * x * x + 25 * y * y) << 5) / (9 * h * h + 25 * v * v)
if r != olr:
olr = r
r = 0x1f
unsigned oyb = b
if y > 0:
oyb = ((9 * x * x + 25 * (y - 1) * (y - 1)) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
oyb = ((9 * x * x + 25 * (y - 1) * (y - 1)) << 5) / (9 * h * h + 25 * v * v)
if b != ob || b != oyb:
ob = b
b = 0x1f
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
LCD_FRAMEBUFFER_BASE[y * h + x] = (r << 11) | (g << 5) | (b)
Kernel::Page p = Kernel::my_memory.mapping (&descriptor)
physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
Kernel::free_cap (p)
@@ -166,11 +211,12 @@ Kernel::Num start ():
reset ()
Kernel::Cap logcap = Kernel::my_receiver.create_capability (Init::LCD_LOG)
#if defined (TRENDTAC)
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
#endif
((Init)Kernel::my_parent).register_lcd ()
Kernel::Cap eof_cb = Kernel::alloc_cap ()
Kernel::Cap eof_cb
bool have_eof = false
while true:
Kernel::wait ()
//log_msg ()
@@ -180,11 +226,15 @@ Kernel::Num start ():
eof_cb.invoke ()
break
case Init::LCD_SET_EOF_CB:
Kernel::free_cap (eof_cb)
eof_cb = Kernel::recv.arg
Kernel::recv.arg = Kernel::alloc_cap ()
Kernel::recv.reply.invoke ()
if have_eof:
Kernel::free_cap (eof_cb)
else:
have_eof = true
eof_cb = Kernel::get_arg ()
Kernel::Cap reply = Kernel::get_reply ()
Kernel::register_interrupt (IRQ_LCD)
reply.invoke ()
Kernel::free_cap (reply)
break
case Init::LCD_LOG:
log_char (Kernel::recv.data[0].l)

View File

@@ -0,0 +1,70 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/metronome.ccp: Userspace program.
// 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"
#include "keys.hh"
Kernel::Num start ():
kdebug ("metronome started\n")
Buzzer buzzer = Kernel::my_parent.get_device <Buzzer> ()
Keyboard kbd = Kernel::my_parent.get_device <Keyboard> ()
Kernel::Cap key = Kernel::my_receiver.create_capability (0)
kbd.set_cb (key)
unsigned mHz = 1000
unsigned freq = 1000
Kernel::my_receiver.set_alarm (1)
bool running (true)
while true:
Kernel::wait ()
switch Kernel::recv.protected_data.l:
case ~0:
if running:
buzzer.beep (freq, 10, ~0)
Kernel::my_receiver.set_alarm (HZ * 1000 / mHz)
break
case 0:
if Kernel::recv.data[0].l & Keyboard::RELEASE:
break
switch Kernel::recv.data[0].l:
case Key::VOLUME_UP:
freq = freq * 11 / 10
break
case Key::VOLUME_DOWN:
freq = freq * 9 / 10
break
case Key::LEFT:
mHz = mHz * 101 / 100
break
case Key::RIGHT:
mHz = mHz * 99 / 100
break
case Key::UP:
mHz = mHz * 11 / 10
break
case Key::DOWN:
mHz = mHz * 9 / 10
break
case Key::P:
running = !running
if running:
Kernel::my_receiver.set_alarm (1)
break
break
default:
kdebug ("huh?\n")
break

View File

@@ -19,6 +19,7 @@
#include "devices.hh"
#define ARCH
#include "arch.hh"
#include "keys.hh"
//#define QI
#define SCAN_INTERVAL HZ / 50
@@ -33,27 +34,8 @@ class DevKbd:
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]
static unsigned const NUM_KEYS = 58
static unsigned const keys[NUM_KEYS]
unsigned state[NUM_COLS]
Kernel::Cap event
bool is_active
@@ -61,27 +43,14 @@ class DevKbd:
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]))
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 ():
@@ -155,43 +124,44 @@ 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 }
{ 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
{ 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 }
{ 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
}
char const *const DevKbd::names[NUM_KEYS] = {
unsigned const DevKbd::keys[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"
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
"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"
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
}
@@ -222,12 +192,10 @@ class PowerButton:
enum codes:
KBD_DEV = 32
KBD_LIST
PWR
Kernel::Num start ():
map_gpio ()
map_tcu ()
DevKbd kbd
PowerButton pwr
@@ -242,7 +210,6 @@ Kernel::Num start ():
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 ()
@@ -307,24 +274,6 @@ Kernel::Num start ():
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
@@ -337,29 +286,23 @@ Kernel::Num start ():
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 ())
Kernel::recv.reply.invoke ()
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")
Kernel::recv.reply.invoke (0, 0, list)
kbd.send_keys (Kernel::recv.data[0].l, Kernel::recv.reply)
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)