mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-16 17:20:36 +02:00
433 lines
16 KiB
Plaintext
433 lines
16 KiB
Plaintext
#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"
|
|
|
|
namespace Iris:
|
|
// Caplist interface.
|
|
template <typename _T> //
|
|
struct Caplist : public Iris::Caps:
|
|
Caplist (Iris::Caps c = Iris::Cap ()) : Iris::Caps (c):
|
|
Caplist <_T> create (unsigned size, Iris::Memory mem = Iris::my_memory):
|
|
return Caplist <_T> (mem.create_caps (size))
|
|
void set (unsigned idx, _T value):
|
|
return Iris::Caps::set (idx, value)
|
|
_T get (unsigned idx):
|
|
return _T (Iris::Caps::get (idx))
|
|
|
|
/// A block of data with a size and content. Any character can be stored in it (including '\0').
|
|
struct String : public Iris::Cap:
|
|
String (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
GET_SIZE = 0x2001
|
|
GET_CHARS
|
|
GET_PAGE
|
|
ID
|
|
/// Get the size of the string.
|
|
Iris::Num get_size ():
|
|
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
|
/// Get exactly 16 characters. The index must be word-aligned.
|
|
char *get_chars (Iris::Num idx, char buffer[16]):
|
|
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
|
|
unsigned *b = (unsigned *)buffer
|
|
b[0] = Iris::recv.data[0].l
|
|
b[1] = Iris::recv.data[0].h
|
|
b[2] = Iris::recv.data[1].l
|
|
b[3] = Iris::recv.data[1].h
|
|
return buffer
|
|
/// Helper function for get_page.
|
|
static Iris::Page _create_paying_page ():
|
|
Iris::Page ret = Iris::my_memory.create_page ()
|
|
ret.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
|
|
return ret
|
|
/// 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 (Iris::Num idx, Iris::Page ret = _create_paying_page ()):
|
|
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
|
|
return ret
|
|
|
|
/// A writable String.
|
|
struct WString : public String:
|
|
WString (Iris::Cap c = Iris::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 (Iris::Num size):
|
|
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
|
/// Set exactly 4 characters. The index must be word-aligned.
|
|
void set_chars (Iris::Num idx, char buffer[4]):
|
|
call (Iris::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 (Iris::Num idx, Iris::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 Iris::Cap:
|
|
Device (Iris::Cap c = Iris::Cap ()) : Iris::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.
|
|
Iris::Cap create_user (Iris::Memory storage, unsigned arg1 = 0, Iris::Num arg2 = 0):
|
|
iocall (storage, Iris::Num (CAP_MASTER_DIRECT | CREATE_USER, arg1), arg2)
|
|
return Iris::get_arg ()
|
|
// Destroy a user. It is made inactive if it was active.
|
|
void destroy_user (Iris::Cap user):
|
|
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
|
|
// Make user inactive.
|
|
void unuse (Iris::Cap user):
|
|
ocall (user, CAP_MASTER_DIRECT | UNUSE)
|
|
// Make user active. It makes the previous active user inactive.
|
|
void use (Iris::Cap user):
|
|
ocall (user, CAP_MASTER_DIRECT | USE)
|
|
// Convenience function for threads implementing a device.
|
|
static void host (unsigned id, unsigned ¤t_user, Iris::Cap &reply, Iris::Cap &arg, unsigned capssize = 3, unsigned (*create)(Iris::Memory mem, Iris::Caps caps) = NULL, void (*destroy)(unsigned id, Iris::Caps caps) = NULL, void (*use)(unsigned id, Iris::Caps caps) = NULL, void (*unuse)(unsigned id, Iris::Caps caps) = NULL):
|
|
static unsigned last_user
|
|
switch Iris::recv.data[0].l:
|
|
case Device::CREATE_USER:
|
|
Iris::Memory mem (arg)
|
|
Iris::Caps caps = mem.create_caps (capssize)
|
|
unsigned user
|
|
if create:
|
|
user = create (mem, caps)
|
|
else:
|
|
// Increment last_user; skip 0.
|
|
// FIXME: if this really wraps, it is possible that two users share their id.
|
|
if !++last_user:
|
|
++last_user
|
|
user = last_user
|
|
Iris::Cap c = Iris::my_receiver.create_capability (Iris::Num (user, id))
|
|
caps.set (0, c.copy ())
|
|
caps.set (1, mem.copy ())
|
|
reply.invoke (0, 0, caps.copy ())
|
|
Iris::free_cap (c)
|
|
Iris::free_cap (caps)
|
|
Iris::free_cap (reply)
|
|
Iris::free_cap (arg)
|
|
break
|
|
case Device::DESTROY_USER:
|
|
Iris::Caps caps (arg)
|
|
Iris::Cap c = caps.get (0)
|
|
Iris::Num user = Iris::my_receiver.get_protected (c)
|
|
Iris::free_cap (c)
|
|
if user.h != id:
|
|
Iris::panic (user.h, "invalid id for destroy")
|
|
// TODO: unuse.
|
|
if destroy:
|
|
destroy (user.l, caps)
|
|
reply.invoke ()
|
|
Iris::free_cap (reply)
|
|
Iris::free_cap (arg)
|
|
break
|
|
case Device::USE:
|
|
Iris::Caps caps (arg)
|
|
Iris::Cap c = caps.get (0)
|
|
Iris::Num user = Iris::my_receiver.get_protected (c)
|
|
Iris::free_cap (c)
|
|
if user.h != id:
|
|
Iris::panic (user.h, "invalid id for use")
|
|
// TODO: send unuse signal.
|
|
current_user = user.l
|
|
if use:
|
|
use (user.l, caps)
|
|
c = caps.get (2)
|
|
c.invoke (1)
|
|
Iris::free_cap (c)
|
|
reply.invoke ()
|
|
Iris::free_cap (reply)
|
|
Iris::free_cap (arg)
|
|
break
|
|
case Device::UNUSE:
|
|
Iris::Caps caps (arg)
|
|
Iris::Cap c = caps.get (0)
|
|
Iris::Num user = Iris::my_receiver.get_protected (c)
|
|
Iris::free_cap (c)
|
|
if user.h != id:
|
|
Iris::panic (user.h, "invalid id for unuse")
|
|
if unuse:
|
|
unuse (user.l, caps)
|
|
if user.l == current_user:
|
|
c = caps.get (2)
|
|
c.invoke (0)
|
|
Iris::free_cap (c)
|
|
current_user = 0
|
|
reply.invoke ()
|
|
Iris::free_cap (reply)
|
|
Iris::free_cap (arg)
|
|
break
|
|
default:
|
|
kdebug ("invalid request\n")
|
|
reply.invoke (~0)
|
|
Iris::free_cap (reply)
|
|
Iris::free_cap (arg)
|
|
break
|
|
|
|
struct Elfrun : public Iris::Cap:
|
|
Elfrun (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
RUN_STRING = Device::ID
|
|
RUN_CAPS
|
|
ID
|
|
enum arg_pos:
|
|
PARENT_MEMORY
|
|
DATA
|
|
PARENT
|
|
Iris::Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
|
|
Iris::Caps caps = Iris::my_memory.create_caps (3)
|
|
caps.set (PARENT_MEMORY, parent_memory)
|
|
caps.set (DATA, data)
|
|
caps.set (PARENT, parent)
|
|
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Iris::Num (num_slots, num_caps))
|
|
Iris::Caps ret = Iris::get_arg ()
|
|
Iris::my_memory.destroy (caps)
|
|
Iris::free_cap (caps)
|
|
return ret
|
|
Iris::Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
|
|
Iris::Caps caps = Iris::my_memory.create_caps (3)
|
|
caps.set (PARENT_MEMORY, parent_memory)
|
|
caps.set (DATA, data)
|
|
caps.set (PARENT, parent)
|
|
iocall (caps.copy (), Iris::Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Iris::Num (num_slots, num_caps))
|
|
Iris::Caps ret = Iris::get_arg ()
|
|
Iris::my_memory.destroy (caps)
|
|
Iris::free_cap (caps)
|
|
return ret
|
|
|
|
// Interface for talking to the parent process.
|
|
struct Parent : public Iris::Cap:
|
|
Parent (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
GET_DEVICE = Elfrun::ID
|
|
PROVIDE_DEVICE
|
|
WAIT
|
|
GET_MEMORY
|
|
PROVIDE_MEMORY
|
|
INIT_DONE
|
|
EXIT
|
|
ID
|
|
// Get a device handle.
|
|
template <typename _T> _T get_device (unsigned num = 0):
|
|
icall (Iris::Num (CAP_MASTER_DIRECT | GET_DEVICE, num), _T::ID)
|
|
return Iris::get_arg ()
|
|
// Provide a device handle.
|
|
template <typename _T> void provide_device (Device dev, unsigned num = 0):
|
|
ocall (dev, Iris::Num (CAP_MASTER_DIRECT | PROVIDE_DEVICE, num), _T::ID)
|
|
// Wait until a device is used by the caller again.
|
|
template <typename _T> void wait (unsigned num = 0):
|
|
call (Iris::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
|
|
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
|
|
Iris::Memory get_memory (Iris::Cap target):
|
|
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
|
|
return Iris::get_arg ()
|
|
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
|
|
Iris::Cap provide_memory (unsigned limit):
|
|
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
|
|
return Iris::get_arg ()
|
|
// Signal the parent that the initialisation phase is over.
|
|
void init_done (Iris::Num stage = 0):
|
|
call (CAP_MASTER_DIRECT | INIT_DONE, stage)
|
|
// Exit the program. The parent does not reply, but kills the process.
|
|
void exit (Iris::Num code):
|
|
call (CAP_MASTER_DIRECT | EXIT, code)
|
|
|
|
// Keyboard interface.
|
|
struct Keyboard : public Iris::Cap:
|
|
Keyboard (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
SET_CB = Parent::ID
|
|
GET_NUM_KEYS
|
|
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 (Iris::Cap cb):
|
|
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
|
// Get the number of keys on the keyboard.
|
|
unsigned get_num_keys ():
|
|
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
|
|
// Get the keycodes for the keys. The reply sends 4 key codes (32 bit each).
|
|
void get_keys (unsigned first):
|
|
call (CAP_MASTER_DIRECT | GET_KEYS, first)
|
|
|
|
// Buzzer interface.
|
|
struct Buzzer : public Iris::Cap:
|
|
Buzzer (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
BEEP = Keyboard::ID
|
|
STOP
|
|
ID
|
|
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
|
|
void beep (unsigned freq, unsigned ms, unsigned volume, Iris::Cap cb = Iris::Cap ()):
|
|
ocall (cb, Iris::Num (CAP_MASTER_DIRECT | BEEP, volume), Iris::Num (freq, ms))
|
|
// Abort current beep, if any.
|
|
void stop ():
|
|
call (CAP_MASTER_DIRECT | STOP)
|
|
|
|
// Display interface.
|
|
struct Display : public Iris::Cap:
|
|
Display (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
SET_EOF_CB = Buzzer::ID
|
|
MAP_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 (Iris::Cap cb):
|
|
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
|
|
// Map the framebuffer into memory.
|
|
void map_fb (unsigned address):
|
|
call (CAP_MASTER_DIRECT | MAP_FB, address)
|
|
// Get information about the display.
|
|
void get_info ():
|
|
// TODO: Interface is to be designed.
|
|
Iris::panic (0, "using undefined interface Display::get_info ()")
|
|
|
|
// Numerical setting, such as a display backlight.
|
|
struct Setting : public Iris::Cap:
|
|
Setting (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
SET = Display::ID
|
|
GET_RANGE
|
|
ID
|
|
// Set a new value.
|
|
void set (unsigned value):
|
|
call (CAP_MASTER_DIRECT | SET, value)
|
|
// Get the maximum value for this setting. Using a higher value with SET gives undefined results.
|
|
unsigned get_range ():
|
|
return call (CAP_MASTER_DIRECT | GET_RANGE).l
|
|
|
|
// File system interface.
|
|
// filesystem-related interfaces: directory, stream, seekable.
|
|
// Normal files implement stream and/or seekable. Directories implement directory.
|
|
// Seekable is not a class, it is identical to [W]String.
|
|
|
|
// Directory interface.
|
|
struct Directory : public Iris::Cap:
|
|
Directory (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
GET_SIZE = Setting::ID
|
|
GET_NAME
|
|
GET_FILE_RO
|
|
GET_FILE_INFO
|
|
LOCK_RO
|
|
UNLOCK_RO
|
|
ID
|
|
// Get the number of entries in this directory.
|
|
Iris::Num get_size ():
|
|
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
|
// Get the filename.
|
|
String get_name (Iris::Num idx):
|
|
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
|
|
return Iris::get_arg ()
|
|
// Get the file.
|
|
Iris::Cap get_file_ro (Iris::Num idx):
|
|
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
|
|
return Iris::get_arg ()
|
|
// Get file info. TODO: define possible types.
|
|
Iris::Num get_file_info (Iris::Num idx, unsigned type):
|
|
return icall (Iris::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
|
|
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
|
|
void lock_ro ():
|
|
call (CAP_MASTER_DIRECT | LOCK_RO)
|
|
// Release a read-only lock. Write operations can only be done when the directory is locked.
|
|
void unlock_ro ():
|
|
call (CAP_MASTER_DIRECT | UNLOCK_RO)
|
|
struct WDirectory : public Directory:
|
|
WDirectory (Iris::Cap c = Iris::Cap ()) : Directory (c):
|
|
enum request:
|
|
GET_FILE = Directory::ID
|
|
CREATE_FILE
|
|
DELETE_FILE
|
|
LOCK
|
|
UNLOCK
|
|
ID
|
|
// Get the file.
|
|
Iris::Cap get_file (Iris::Num idx):
|
|
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
|
|
return Iris::get_arg ()
|
|
// Create a new file. After this, any index may map to a different file.
|
|
Iris::Cap create_file (String name):
|
|
icall (CAP_MASTER_DIRECT | CREATE_FILE)
|
|
return Iris::get_arg ()
|
|
// Delete a file. After this, any index may map to a different file.
|
|
void delete_file (Iris::Num idx):
|
|
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
|
// Lock the directory. Write operations can only be done when the directory is locked.
|
|
void lock ():
|
|
call (CAP_MASTER_DIRECT | LOCK)
|
|
// Unlock the directory. Write operations can only be done when the directory is locked.
|
|
void unlock ():
|
|
call (CAP_MASTER_DIRECT | UNLOCK)
|
|
|
|
// A filesystem turns a String into a Directory.
|
|
struct Filesystem : public Device:
|
|
Filesystem (Iris::Cap c = Iris::Cap ()) : Device (c):
|
|
enum request:
|
|
USE_DEVICE = WDirectory::ID
|
|
USE_DEVICE_RO
|
|
ID
|
|
WDirectory use_device (WString dev):
|
|
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
|
|
return Iris::get_arg ()
|
|
Directory use_device_ro (String dev):
|
|
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
|
|
return Iris::get_arg ()
|
|
|
|
// Stream interface.
|
|
struct Stream : public Iris::Cap:
|
|
Stream (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
|
enum request:
|
|
READ = Filesystem::ID
|
|
WRITE
|
|
ID
|
|
// Try to read size bytes. Returns the number of bytes successfully read.
|
|
Iris::Num read (Iris::Num size, bool block):
|
|
return icall (Iris::Num (CAP_MASTER_DIRECT | READ, block), size)
|
|
// Try to write size bytes. Returns the number of bytes successfully written.
|
|
Iris::Num write (String s, Iris::Num size):
|
|
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
|
|
|
|
|
|
|
|
// Block device interface.
|
|
struct Block_device : public WString:
|
|
Block_device (Iris::Cap c = Iris::Cap ()) : WString (c):
|
|
// TODO: to be designed.
|
|
|
|
|
|
// TODO.
|
|
// Sound interface.
|
|
// Usb interfaces (port, device).
|
|
// Pointer interface. (Only movement; buttons follow keyboard interface.)
|
|
// Network interface.
|
|
// Camera interface.
|
|
|
|
#endif
|