mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
new directory organization
This commit is contained in:
54
userspace/application/alarm.ccp
Normal file
54
userspace/application/alarm.ccp
Normal file
@@ -0,0 +1,54 @@
|
||||
#pypp 0
|
||||
// vim: set filetype=cpp : //
|
||||
#include <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
enum captypes:
|
||||
CONTROL = 1
|
||||
KBD
|
||||
INTERRUPT
|
||||
|
||||
Iris::Num start ():
|
||||
unsigned *screen = (unsigned *)0x40000000
|
||||
Iris::RTC rtc = Iris::my_parent.get_capability <Iris::RTC> ()
|
||||
Iris::Display display = Iris::my_parent.get_capability <Iris::Display> ()
|
||||
display.map_fb ((unsigned)screen)
|
||||
Iris::Font font = Iris::my_parent.get_capability <Iris::Font> ()
|
||||
font.set_display (display)
|
||||
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (KBD)
|
||||
keyboard.set_cb (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
Iris::Buzzer buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
|
||||
Iris::Event self = Iris::my_receiver.create_capability (CONTROL)
|
||||
Iris::my_parent.provide_capability <Iris::Event> (self)
|
||||
cap = Iris::my_receiver.create_capability (INTERRUPT)
|
||||
Iris::my_parent.init_done ()
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case INTERRUPT:
|
||||
// RTC alarm interrupt.
|
||||
if Iris::recv.data[0].l == ~0:
|
||||
// Not a real interrupt, just an abort notification.
|
||||
continue
|
||||
font.printf ("alarm: RTC alarm interrupt\n")
|
||||
break
|
||||
case CONTROL:
|
||||
// Store callback
|
||||
font.printf ("alarm: control event\n")
|
||||
break
|
||||
case KBD:
|
||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||
// Key release.
|
||||
Iris::poweroff ()
|
||||
else:
|
||||
// Key press.
|
||||
unsigned time = rtc.get_time ()
|
||||
rtc.set_alarm (time + 5, cap)
|
||||
unsigned alarm = rtc.get_alarm ()
|
||||
unsigned enabled = Iris::recv.data[1].l
|
||||
font.printf ("Debug: %d %d %d\n", time, alarm, enabled)
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.protected_data.l, "invalid request for alarm")
|
||||
62
userspace/application/ball.ccp
Normal file
62
userspace/application/ball.ccp
Normal file
@@ -0,0 +1,62 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/ball.ccp: Bouncing ball demo.
|
||||
// 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 <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
static unsigned *framebuffer
|
||||
static int const r = 10
|
||||
|
||||
void ball (int x, int y, unsigned colour):
|
||||
for int ty = y - r; ty < y + r; ++ty:
|
||||
if ty < 0 || ty >= 240:
|
||||
continue
|
||||
for int tx = x - r; tx < x + r; ++tx:
|
||||
if tx < 0 || tx >= 320:
|
||||
continue
|
||||
if (x - tx) * (x - tx) + (y - ty) * (y - ty) > r * r:
|
||||
continue
|
||||
framebuffer[ty * 320 + tx] = (colour)
|
||||
|
||||
Iris::Num start ():
|
||||
Iris::my_parent.init_done ()
|
||||
int colour = 0x3f30ff
|
||||
framebuffer = (unsigned *)0x15000
|
||||
Iris::Display display = Iris::my_parent.get_capability <Iris::Display> ()
|
||||
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
|
||||
int x = r, y = r, dx = 3, dy = 0
|
||||
Iris::Cap eof = Iris::my_receiver.create_capability (0)
|
||||
while true:
|
||||
display.set_eof_cb (eof)
|
||||
Iris::wait ()
|
||||
ball (x, y, 0)
|
||||
x += dx
|
||||
y += dy
|
||||
if y + r >= 240:
|
||||
dy = -dy
|
||||
y = 240 - r
|
||||
if x - r < 0:
|
||||
x = r
|
||||
dx = -dx
|
||||
if x + r >= 320:
|
||||
x = 320 - r
|
||||
dx = -dx
|
||||
if y == 240 - r && dy == 0:
|
||||
dy = -21
|
||||
++dy
|
||||
ball (x, y, colour)
|
||||
28
userspace/application/booter.ccp
Normal file
28
userspace/application/booter.ccp
Normal file
@@ -0,0 +1,28 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/booter.ccp: Boot into another kernel.
|
||||
// Copyright 2010 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 <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
Iris::Num start ():
|
||||
Iris::String data = Iris::my_parent.get_capability <Iris::String> ()
|
||||
Iris::Boot boot = Iris::my_parent.get_capability <Iris::Boot> ()
|
||||
//boot.boot (data, 0x81fff000, 0x81fff000)
|
||||
boot.boot (data, 0xa1fff000, 0xa1fff000)
|
||||
Iris::panic (0, "boot returns")
|
||||
return 0
|
||||
60
userspace/application/bsquare.ccp
Normal file
60
userspace/application/bsquare.ccp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/bsquare.ccp: Floating square demo.
|
||||
// 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 <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
static unsigned *framebuffer
|
||||
static int const r = 10
|
||||
static int colour
|
||||
|
||||
void square (int x, int y, bool print):
|
||||
for int ty = y - r; ty < y + r; ++ty:
|
||||
if ty < 0 || ty >= 240:
|
||||
continue
|
||||
for int tx = x - r; tx < x + r; ++tx:
|
||||
if tx < 0 || tx >= 320:
|
||||
continue
|
||||
framebuffer[ty * 320 + tx] = (print ? colour : 0)
|
||||
|
||||
Iris::Num start ():
|
||||
Iris::my_parent.init_done ()
|
||||
colour = 0xffff00
|
||||
framebuffer = (unsigned *)0x15000
|
||||
Iris::Display display = Iris::my_parent.get_capability <Iris::Display> (0x10001)
|
||||
int x = r, y = r, dx = 3, dy = 3
|
||||
Iris::Cap eof = Iris::my_receiver.create_capability (0)
|
||||
while true:
|
||||
display.set_eof_cb (eof)
|
||||
Iris::wait ()
|
||||
square (x, y, false)
|
||||
x += dx
|
||||
y += dy
|
||||
if y + r >= 240:
|
||||
dy = -dy
|
||||
y = 240 - r
|
||||
if x - r < 0:
|
||||
x = r
|
||||
dx = -dx
|
||||
if x + r >= 320:
|
||||
x = 320 - r
|
||||
dx = -dx
|
||||
if y - r < 0:
|
||||
y = r
|
||||
dy = -dy
|
||||
square (x, y, true)
|
||||
71
userspace/application/metronome.ccp
Normal file
71
userspace/application/metronome.ccp
Normal file
@@ -0,0 +1,71 @@
|
||||
#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"
|
||||
|
||||
Iris::Num start ():
|
||||
Iris::my_parent.init_done ()
|
||||
Iris::Buzzer buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
|
||||
Iris::Keyboard kbd = Iris::my_parent.get_capability <Iris::Keyboard> ()
|
||||
Iris::Cap key = Iris::my_receiver.create_capability (0)
|
||||
kbd.set_cb (key)
|
||||
// Frequency of the pulse train in millihertz.
|
||||
unsigned mHz = 1000
|
||||
// Frequency of single pulses in hertz.
|
||||
unsigned freq = 1000
|
||||
bool running (false)
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case ~0:
|
||||
if running:
|
||||
buzzer.beep (freq, 10, ~0)
|
||||
Iris::my_receiver.set_alarm (HZ * 1000 / mHz)
|
||||
break
|
||||
case 0:
|
||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||
break
|
||||
switch Iris::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 * 99 / 100
|
||||
break
|
||||
case Key::RIGHT:
|
||||
mHz = mHz * 101 / 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:
|
||||
Iris::my_receiver.set_alarm (0)
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("metronome: huh?\n")
|
||||
break
|
||||
58
userspace/application/test.ccp
Normal file
58
userspace/application/test.ccp
Normal file
@@ -0,0 +1,58 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/test.ccp: Testing 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 <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
bool match (char const *a, char const *b, unsigned l1, unsigned l2):
|
||||
if l1 != l2:
|
||||
return false
|
||||
for unsigned i = 0; i < l1; ++i:
|
||||
if a[i] != b[i]:
|
||||
return false
|
||||
return true
|
||||
|
||||
static bool print_name (Iris::String name, unsigned indent):
|
||||
unsigned l = name.get_size ().l
|
||||
for unsigned i = 0; i < indent; ++i:
|
||||
kdebug_char (' ')
|
||||
char part[16]
|
||||
for unsigned i = 0; i < l; i += 16:
|
||||
name.get_chars (i, part)
|
||||
for unsigned k = 0; k < 16 && i * 16 + k < l; ++k:
|
||||
kdebug_char (part[k])
|
||||
kdebug_char ('\n')
|
||||
return match (part, ".", l, 1) || match (part, "..", l, 2)
|
||||
|
||||
static void print_dir (Iris::Directory dir, unsigned indent):
|
||||
dir.lock_ro ()
|
||||
Iris::Num files = dir.get_size ()
|
||||
for Iris::Num i = 0; i.value () < files.value (); i = i.value () + 1:
|
||||
Iris::String f = dir.get_name (i)
|
||||
bool ignore = print_name (f, indent)
|
||||
if !ignore && dir.get_file_info (i, 0).l & 1:
|
||||
Iris::Directory d = dir.get_file_ro (i)
|
||||
print_dir (d, indent + 4)
|
||||
Iris::free_cap (d)
|
||||
Iris::free_cap (f)
|
||||
dir.unlock_ro ()
|
||||
|
||||
Iris::Num start ():
|
||||
Iris::Directory dir = Iris::my_parent.get_capability <Iris::Directory> ()
|
||||
print_dir (dir, 0)
|
||||
return 0
|
||||
380
userspace/boot/bootinit.ccp
Normal file
380
userspace/boot/bootinit.ccp
Normal file
@@ -0,0 +1,380 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/bootinit.ccp: Bootstrapping code.
|
||||
// Copyright 2009-2010 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 "iris.hh"
|
||||
#include <elf.h>
|
||||
|
||||
#define ELFRUN_NAME "elfrun.elf"
|
||||
#define INIT_NAME "init.elf"
|
||||
|
||||
// These numbers are only used for elfrun.
|
||||
#define NUM_SLOTS 8
|
||||
#define NUM_CAPS 32
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
static unsigned *bss_mapping
|
||||
static Iris::Page bss_page
|
||||
|
||||
// Get the initial block device and filesystem.
|
||||
static Iris::Directory receive_devices ():
|
||||
Iris::Block device
|
||||
bool have_device = false
|
||||
Iris::Cap reply[2]
|
||||
bool have_reply[2]
|
||||
have_reply[0] = false
|
||||
have_reply[1] = false
|
||||
unsigned next = 2
|
||||
while true:
|
||||
Iris::wait ()
|
||||
kdebug_num (Iris::recv.protected_data.l, 1)
|
||||
kdebug (": ")
|
||||
if Iris::recv.protected_data.l == 0:
|
||||
kdebug ("sd detect event device request\n")
|
||||
// SD detection event device request.
|
||||
// Ignore all; that will result in the driver thinking there is a card.
|
||||
Iris::recv.reply.invoke ()
|
||||
continue
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Parent::PROVIDE_CAPABILITY:
|
||||
switch Iris::recv.data[1].l:
|
||||
case Iris::Block::ID:
|
||||
case Iris::WBlock::ID:
|
||||
// Ignore other partitions.
|
||||
Iris::Cap r = Iris::get_reply ()
|
||||
if Iris::recv.data[0].h != 0:
|
||||
kdebug ("ignoring non-0 partition\n")
|
||||
else:
|
||||
if have_device:
|
||||
Iris::panic (0, "double device provided")
|
||||
device = Iris::get_arg ()
|
||||
if have_reply[next - 2]:
|
||||
kdebug ("block provided (used)\n")
|
||||
reply[next++ - 2].invoke (0, 0, device.copy ())
|
||||
Iris::free_cap (device)
|
||||
else:
|
||||
kdebug ("block provided (stored)\n")
|
||||
have_device = true
|
||||
r.invoke ()
|
||||
Iris::free_cap (r)
|
||||
break
|
||||
case Iris::Directory::ID:
|
||||
kdebug ("directory provided\n")
|
||||
Iris::Directory ret = Iris::get_arg ()
|
||||
Iris::recv.reply.invoke ()
|
||||
return ret
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[1].l, "invalid capability type provided by boot thread")
|
||||
break
|
||||
case Iris::Parent::GET_CAPABILITY:
|
||||
if Iris::recv.data[1].l == Iris::Event::ID:
|
||||
kdebug ("event requested\n")
|
||||
// Detection of sd card.
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap event = Iris::my_receiver.create_capability (0)
|
||||
reply.invoke (0, 0, event.copy ())
|
||||
Iris::free_cap (event)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
if Iris::recv.data[1].l != Iris::Block::ID && Iris::recv.data[1].l != Iris::WBlock::ID:
|
||||
Iris::panic (Iris::recv.data[1].l, "invalid capability type requested by boot thread")
|
||||
if next == Iris::recv.protected_data.l && have_device:
|
||||
kdebug ("block requested (sent)\n")
|
||||
Iris::recv.reply.invoke (0, 0, device.copy ())
|
||||
Iris::free_cap (device)
|
||||
have_device = false
|
||||
++next
|
||||
else:
|
||||
kdebug ("block requested (not sent)\n")
|
||||
reply[Iris::recv.protected_data.l - 2] = Iris::get_reply ()
|
||||
have_reply[Iris::recv.protected_data.l - 2] = true
|
||||
break
|
||||
case Iris::Parent::INIT_DONE:
|
||||
kdebug ("init done\n")
|
||||
// Ignore.
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Parent::EXIT:
|
||||
Iris::panic (Iris::recv.protected_data.l, "boot thread exits")
|
||||
default:
|
||||
Iris::panic (Iris::recv.protected_data.l, "invalid boot request")
|
||||
|
||||
static bool stringcmp (char const *s1, char const *s2, unsigned size):
|
||||
for unsigned t = 0; t < size; ++t:
|
||||
if s1[t] != s2[t]:
|
||||
return false
|
||||
return true
|
||||
|
||||
static Iris::Block find (Iris::Directory root, char const *name):
|
||||
unsigned size = 0
|
||||
while name[size]:
|
||||
++size
|
||||
Iris::Num num_files = root.get_size ()
|
||||
for Iris::Num i = 0; i.value () < num_files.value (); i = i.value () + 1:
|
||||
Iris::String n = root.get_name (i)
|
||||
char current_name[16]
|
||||
n.get_chars (0, current_name)
|
||||
Iris::free_cap (n)
|
||||
if !stringcmp (current_name, name, size):
|
||||
continue
|
||||
// Found elfrun.
|
||||
Iris::Block ret = root.get_file_ro (i)
|
||||
return ret
|
||||
Iris::panic (0, "bootfile not found")
|
||||
|
||||
static void run (Iris::Block data, Iris::Memory parent_memory, Iris::Cap parent):
|
||||
// Get the size.
|
||||
Iris::Num size = data.get_size ()
|
||||
if size.value () == 0:
|
||||
Iris::panic (0, "elfrun is empty")
|
||||
// Allocate a caps with all the pages.
|
||||
unsigned pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
Iris::Caps pages_caps = Iris::my_memory.create_caps (pages)
|
||||
unsigned slot = pages_caps.use ()
|
||||
// Map them into the address space as well.
|
||||
char *mapping = alloc_space (pages)
|
||||
// Create a memory for the program.
|
||||
Iris::Memory mem = parent_memory.create_memory ()
|
||||
// Load the file into memory and map it.
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
//kdebug_num (p)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (pages)
|
||||
//kdebug ("\n")
|
||||
Iris::set_recv_arg (Iris::Cap (slot, p))
|
||||
Iris::my_memory.create_page ()
|
||||
Iris::Page (slot, p).set_flags (Iris::Page::PAYING)
|
||||
data.get_block (p << PAGE_BITS, PAGE_SIZE, 0, Iris::Cap (slot, p))
|
||||
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
|
||||
Iris::Thread thread = mem.create_thread (NUM_SLOTS)
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
if header->e_ident[j] != ELFMAG[j]:
|
||||
Iris::panic (header->e_ident[j], "invalid ELF magic")
|
||||
return
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class:")
|
||||
kdebug_num (header->e_ident[EI_CLASS])
|
||||
kdebug (" != ")
|
||||
kdebug_num (ELFCLASS32)
|
||||
kdebug ("\n")
|
||||
Iris::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
|
||||
if header->e_type != ET_EXEC:
|
||||
Iris::panic (header->e_type, "invalid ELF type")
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
Iris::panic (header->e_machine, "invalid ELF machine")
|
||||
thread.set_pc (header->e_entry)
|
||||
thread.set_sp (0x80000000)
|
||||
for unsigned section = 0; section < header->e_shnum; ++section:
|
||||
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
|
||||
if ~shdr->sh_flags & SHF_ALLOC:
|
||||
continue
|
||||
bool readonly = !(shdr->sh_flags & SHF_WRITE)
|
||||
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
|
||||
if shdr->sh_type != SHT_NOBITS:
|
||||
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
|
||||
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
|
||||
Iris::panic (shdr->sh_size, "thread too large")
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
|
||||
unsigned idx = file_offset + section_offset
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// The address already has a mapping; assume that it is correct.
|
||||
Iris::free_cap (page)
|
||||
continue
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
unsigned f
|
||||
if readonly:
|
||||
f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
|
||||
else:
|
||||
f = Iris::Page::PAYING
|
||||
page.set_flags (f)
|
||||
Iris::Page (slot, idx).share (page, 0)
|
||||
//kdebug ("mapping at ")
|
||||
//kdebug_num (p)
|
||||
//if readonly:
|
||||
// kdebug (" (readonly)")
|
||||
//kdebug ("\n")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map page")
|
||||
return
|
||||
Iris::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
Iris::panic (0, "unwritable bss section")
|
||||
return
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// No error means there is a mapping.
|
||||
page.share (bss_page, 0)
|
||||
Iris::free_cap (page)
|
||||
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
|
||||
if a >= shdr->sh_addr + shdr->sh_size:
|
||||
break
|
||||
if a < shdr->sh_addr:
|
||||
continue
|
||||
bss_mapping[(a & ~PAGE_MASK) >> 2] = 0
|
||||
else:
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR:
|
||||
Iris::panic (Iris::recv.data[0].l, "out of memory")
|
||||
if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME):
|
||||
Iris::panic (0, "out of memory")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map bss page")
|
||||
Iris::free_cap (page)
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::my_memory.destroy (Iris::Page (slot, p))
|
||||
Iris::my_memory.destroy (pages_caps)
|
||||
Iris::free_slot (slot)
|
||||
Iris::Page stackpage = mem.create_page ()
|
||||
stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
|
||||
Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
|
||||
Iris::free_cap (stackpage)
|
||||
Iris::Caps caps = mem.create_caps (NUM_CAPS)
|
||||
thread.use (caps, 0)
|
||||
thread.set_info (Iris::Thread::A0, NUM_SLOTS)
|
||||
thread.set_info (Iris::Thread::A1, NUM_CAPS)
|
||||
Iris::Receiver receiver = mem.create_receiver ()
|
||||
receiver.set_owner (thread.copy ())
|
||||
Iris::Cap call = receiver.create_call_capability ()
|
||||
caps.set (__caps_num, caps.copy ())
|
||||
caps.set (__receiver_num, receiver.copy ())
|
||||
caps.set (__thread_num, thread.copy ())
|
||||
caps.set (__memory_num, mem.copy ())
|
||||
caps.set (__call_num, call.copy ())
|
||||
caps.set (__parent_num, parent)
|
||||
thread.run ()
|
||||
Iris::free_cap (receiver)
|
||||
Iris::free_cap (thread)
|
||||
Iris::free_cap (call)
|
||||
Iris::free_cap (caps)
|
||||
|
||||
Iris::Num start ():
|
||||
// Wait for the debugging device to be active, in case there is one.
|
||||
Iris::schedule ()
|
||||
kdebug ("Starting bootinit\n")
|
||||
init_alloc ()
|
||||
bss_mapping = (unsigned *)alloc_space (1)
|
||||
bss_page = Iris::my_memory.create_page ()
|
||||
Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
|
||||
|
||||
Iris::Memory top_memory = Iris::get_top_memory ()
|
||||
Iris::Directory root = receive_devices ()
|
||||
root.lock_ro ()
|
||||
Iris::Block run_block = find (root, ELFRUN_NAME)
|
||||
Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
|
||||
run (run_block, top_memory, parent_cap)
|
||||
Iris::wait ()
|
||||
if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY || Iris::recv.data[1].l != Iris::Elfrun::ID:
|
||||
Iris::panic (0, "elfrun doesn't provide correct capability")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Elfrun elfrun = Iris::get_arg ()
|
||||
Iris::my_caps.set (parent_cap.idx (), Iris::Cap (CAP_NONE))
|
||||
Iris::free_cap (parent_cap)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
|
||||
parent_cap = Iris::my_receiver.create_capability (0)
|
||||
Iris::Block init_block = find (root, INIT_NAME)
|
||||
Iris::Caps init_caps = elfrun.run_block (top_memory.copy (), init_block.copy (), parent_cap.copy (), 8, 63)
|
||||
|
||||
Iris::Thread init = init_caps.get (__thread_num)
|
||||
init.make_priv ()
|
||||
init.run ()
|
||||
Iris::free_cap (init)
|
||||
Iris::free_cap (init_caps)
|
||||
|
||||
bool have_root = false
|
||||
bool have_elfrun = false
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Parent::GET_CAPABILITY:
|
||||
switch Iris::recv.data[1].l:
|
||||
case Iris::Directory::ID:
|
||||
if have_root:
|
||||
Iris::panic (0, "Init requests root directory twice")
|
||||
Iris::recv.reply.invoke (0, 0, root.copy ())
|
||||
have_root = true
|
||||
break
|
||||
case Iris::Elfrun::ID:
|
||||
if have_elfrun:
|
||||
Iris::panic (0, "Init requests elfrun twice")
|
||||
Iris::recv.reply.invoke (0, 0, elfrun.copy ())
|
||||
have_elfrun = true
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "Invalid device requested by init")
|
||||
break
|
||||
case Iris::Parent::INIT_DONE:
|
||||
if Iris::recv.data[1].value () != 0:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
// Special response: kill boot threads.
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
root.unlock_ro ()
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
top_memory.destroy (Iris::my_memory)
|
||||
Iris::panic (0, "bootinit should be destroyed")
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid operation from init")
|
||||
166
userspace/boot/crt0.ccp
Normal file
166
userspace/boot/crt0.ccp
Normal file
@@ -0,0 +1,166 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/init.S: Startup code for initial Threads.
|
||||
// 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 "iris.hh"
|
||||
#include "devices.hh"
|
||||
|
||||
// For some unknown reason, gcc needs this to be defined.
|
||||
unsigned __gxx_personality_v0
|
||||
|
||||
struct list:
|
||||
list *prev, *next
|
||||
|
||||
static unsigned __slots, __caps
|
||||
static list *__slot_admin, *__cap_admin
|
||||
static list *__first_free_slot, *__first_free_cap
|
||||
|
||||
namespace Iris:
|
||||
bool enable_debug
|
||||
Caps my_caps
|
||||
Receiver my_receiver
|
||||
Thread my_thread
|
||||
Memory my_memory
|
||||
Cap my_call
|
||||
Parent my_parent
|
||||
__recv_data_t recv
|
||||
|
||||
void print_caps ():
|
||||
// __caps cannot be larger than 63.
|
||||
bool used[63]
|
||||
for unsigned i = 0; i < __caps; ++i:
|
||||
used[i] = true
|
||||
unsigned num = 0
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
if used[i - __cap_admin] == false:
|
||||
panic (0, "inconsistent userspace cap db")
|
||||
used[i - __cap_admin] = false
|
||||
++num
|
||||
kdebug_num (num, 2)
|
||||
kdebug (":")
|
||||
for unsigned i = 0; i < __caps; ++i:
|
||||
kdebug_char (used[i] ? '#' : '.')
|
||||
kdebug_char ('\n')
|
||||
|
||||
void free_slot (unsigned slot):
|
||||
//kdebug ("free slot\n")
|
||||
for list *i = __first_free_slot; i; i = i->next:
|
||||
if slot == i - __slot_admin:
|
||||
panic (0, "double free of userspace slot")
|
||||
__slot_admin[slot].prev = NULL
|
||||
__slot_admin[slot].next = __first_free_slot
|
||||
if __slot_admin[slot].next:
|
||||
__slot_admin[slot].next->prev = &__slot_admin[slot]
|
||||
__first_free_slot = &__slot_admin[slot]
|
||||
|
||||
void free_cap (Cap cap):
|
||||
if enable_debug:
|
||||
kdebug ("free cap ")
|
||||
kdebug_num (cap.idx (), 2)
|
||||
kdebug ("\n")
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
if cap.idx () == i - __cap_admin:
|
||||
panic (0, "double free of userspace cap")
|
||||
if cap.slot () != 0:
|
||||
kdebug ("trying to free capability from non-0 slot\n")
|
||||
Iris::panic (0)
|
||||
return
|
||||
list *l = &__cap_admin[cap.idx ()]
|
||||
l->prev = NULL
|
||||
l->next = __first_free_cap
|
||||
if l->next:
|
||||
l->next->prev = l
|
||||
__first_free_cap = l
|
||||
|
||||
unsigned alloc_slot ():
|
||||
//kdebug ("alloc slot\n")
|
||||
if !__first_free_slot:
|
||||
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
|
||||
kdebug ("out of slots!\n")
|
||||
Iris::panic (0)
|
||||
return ~0
|
||||
list *ret = __first_free_slot
|
||||
__first_free_slot = ret->next
|
||||
if ret->next:
|
||||
ret->next->prev = NULL
|
||||
return ret - __slot_admin
|
||||
|
||||
Cap alloc_cap ():
|
||||
if !__first_free_cap:
|
||||
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
|
||||
kdebug ("out of capabilities!\n")
|
||||
Iris::panic (0)
|
||||
return Cap (0, CAP_NONE)
|
||||
list *ret = __first_free_cap
|
||||
__first_free_cap = ret->next
|
||||
if ret->next:
|
||||
ret->next->prev = NULL
|
||||
if enable_debug:
|
||||
kdebug ("alloc cap ")
|
||||
kdebug_num (ret - __cap_admin, 2)
|
||||
kdebug ("\n")
|
||||
return Cap (0, ret - __cap_admin)
|
||||
|
||||
extern "C":
|
||||
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
|
||||
Iris::enable_debug = false
|
||||
__slots = slots
|
||||
__caps = caps
|
||||
__slot_admin = slot_admin
|
||||
__cap_admin = cap_admin
|
||||
__first_free_slot = NULL
|
||||
for unsigned i = 1; i < __slots; ++i:
|
||||
Iris::free_slot (i)
|
||||
__first_free_cap = NULL
|
||||
for unsigned i = 6; i < __caps; ++i:
|
||||
Iris::free_cap (Iris::Cap (0, i))
|
||||
Iris::my_caps = Iris::Cap (0, __caps_num)
|
||||
Iris::my_receiver = Iris::Cap (0, __receiver_num)
|
||||
Iris::my_thread = Iris::Cap (0, __thread_num)
|
||||
Iris::my_memory = Iris::Cap (0, __memory_num)
|
||||
Iris::my_call = Iris::Cap (0, __call_num)
|
||||
Iris::my_parent = Iris::Cap (0, __parent_num)
|
||||
Iris::recv.reply = Iris::alloc_cap ()
|
||||
Iris::recv.arg = Iris::alloc_cap ()
|
||||
Iris::Num ret = start ()
|
||||
Iris::my_parent.exit (ret)
|
||||
Iris::my_memory.destroy (Iris::my_thread)
|
||||
// The program no longer exists. If it somehow does, die again.
|
||||
while true:
|
||||
Iris::panic (0, "this program should no longer exist.")
|
||||
*(volatile unsigned *)~0
|
||||
|
||||
__asm__ volatile ("\t.text\n"
|
||||
"\t.globl __start\n"
|
||||
"\t.set noreorder\n"
|
||||
"__start:\n"
|
||||
"\tbal 1f\n"
|
||||
"__hack_label:\n"
|
||||
"\tnop\n"
|
||||
"\t.word _gp\n"
|
||||
"1:\n"
|
||||
"\tlw $gp, 0($ra)\n"
|
||||
"\tsll $v0, $a0, 3\n"
|
||||
"\tsll $v1, $a1, 3\n"
|
||||
"\tsubu $sp, $sp, $v0\n"
|
||||
"\tmove $a2, $sp\n"
|
||||
"\tsubu $sp, $sp, $v1\n"
|
||||
"\tmove $a3, $sp\n"
|
||||
"\tla $t9, run__main\n"
|
||||
"\tjr $t9\n"
|
||||
"\tnop\n"
|
||||
"\t.set reorder")
|
||||
628
userspace/boot/init.ccp
Normal file
628
userspace/boot/init.ccp
Normal file
@@ -0,0 +1,628 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// bootstrap/init.ccp: Bootstrapping code.
|
||||
// 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 "iris.hh"
|
||||
#include "keys.hh"
|
||||
|
||||
#define INIT_CONFIG "init.config"
|
||||
#define INIT_CONFIG_SIZE 12
|
||||
|
||||
#define NUM_SLOTS 8
|
||||
#define NUM_CAPS 32
|
||||
|
||||
enum Captype:
|
||||
SYSREQ
|
||||
PROGRAM
|
||||
FILE
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
template <typename _T> //
|
||||
struct List:
|
||||
struct Item:
|
||||
Item *prev, *next
|
||||
_T value
|
||||
_T &operator* ():
|
||||
return value
|
||||
_T *operator-> ():
|
||||
return &value
|
||||
Item *first
|
||||
Item *begin ():
|
||||
return first
|
||||
void erase (Item *i):
|
||||
if i->prev:
|
||||
i->prev->next = i->next
|
||||
else:
|
||||
first = i->next
|
||||
if i->next:
|
||||
i->next->prev = i->prev
|
||||
delete i
|
||||
Item *insert (Item *after = NULL):
|
||||
Item *ret = new Item
|
||||
if after:
|
||||
ret->prev = after->prev
|
||||
ret->next = after
|
||||
if ret->prev:
|
||||
ret->prev->next = ret
|
||||
else:
|
||||
first = ret
|
||||
after->prev = ret
|
||||
else:
|
||||
ret->prev = NULL
|
||||
ret->next = first
|
||||
first = ret
|
||||
if ret->next:
|
||||
ret->next->prev = ret
|
||||
return ret
|
||||
void init ():
|
||||
first = NULL
|
||||
List () : first (NULL):
|
||||
|
||||
struct Program
|
||||
|
||||
struct Devbase:
|
||||
char *name
|
||||
unsigned name_len
|
||||
unsigned type
|
||||
Program *client
|
||||
Iris::Cap cap
|
||||
|
||||
struct Serverdevice : public Devbase:
|
||||
unsigned index
|
||||
Program *server
|
||||
|
||||
struct Clientdevice:
|
||||
unsigned type, index
|
||||
Devbase *dev
|
||||
|
||||
static Iris::Memory top_memory
|
||||
static Iris::Directory root
|
||||
static Iris::Elfrun elfrun
|
||||
|
||||
struct Program:
|
||||
char *name
|
||||
unsigned name_len
|
||||
unsigned size
|
||||
Iris::Caps pages
|
||||
Iris::Memory memory
|
||||
Iris::Thread thread
|
||||
List <Serverdevice> server_devices
|
||||
List <Clientdevice> client_devices
|
||||
unsigned num_waiting
|
||||
bool priv
|
||||
void run ():
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (Iris::Num (PROGRAM, (unsigned)this))
|
||||
if priv:
|
||||
kdebug ("priv ")
|
||||
kdebug ("running ")
|
||||
for unsigned i = 0; i < name_len; ++i:
|
||||
kdebug_char (name[i])
|
||||
kdebug ("\n")
|
||||
Iris::Caps caps = elfrun.run_caps (top_memory, pages, cap.copy (), (size + PAGE_SIZE - 1) >> PAGE_BITS)
|
||||
Iris::free_cap (cap)
|
||||
thread = caps.get (__thread_num)
|
||||
memory = caps.get (__memory_num)
|
||||
Iris::free_cap (caps)
|
||||
if priv:
|
||||
thread.make_priv ()
|
||||
thread.run ()
|
||||
|
||||
struct File : public Devbase:
|
||||
unsigned size
|
||||
Iris::Caps pages
|
||||
|
||||
static List <Program> programs
|
||||
static List <File> files
|
||||
static Serverdevice *sysreq
|
||||
|
||||
static bool name_match (char const *name, unsigned name_len, Iris::String n):
|
||||
char nm[16]
|
||||
n.get_chars (0, nm)
|
||||
for unsigned t = 0; t < 16 && t < name_len; ++t:
|
||||
if nm[t] != name[t]:
|
||||
return false
|
||||
return true
|
||||
|
||||
static Iris::Caps load (char const *name, unsigned name_len, unsigned &size, Iris::Caps target = Iris::alloc_cap ()):
|
||||
kdebug ("loading ")
|
||||
for unsigned i = 0; i < name_len; ++i:
|
||||
kdebug_char (name[i])
|
||||
kdebug ("\n")
|
||||
root.lock_ro ()
|
||||
Iris::Num sz = root.get_size ()
|
||||
if sz.h:
|
||||
Iris::panic (sz.h, "too many files")
|
||||
for unsigned i = 0; i < sz.l; ++i:
|
||||
Iris::String n = root.get_name (i)
|
||||
if !name_match (name, name_len, n):
|
||||
Iris::free_cap (n)
|
||||
continue
|
||||
Iris::free_cap (n)
|
||||
Iris::Block file = root.get_file_ro (i)
|
||||
Iris::Num s = file.get_size ()
|
||||
if s.h:
|
||||
Iris::panic (s.h, "file is too large to load")
|
||||
size = s.l
|
||||
unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
if pages > 0:
|
||||
Iris::set_recv_arg (target)
|
||||
Iris::my_memory.create_caps (pages)
|
||||
unsigned slot = target.use ()
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::set_recv_arg (Iris::Cap (slot, p))
|
||||
file.get_block (p << PAGE_BITS)
|
||||
Iris::free_slot (slot)
|
||||
Iris::free_cap (file)
|
||||
root.unlock_ro ()
|
||||
return target
|
||||
Iris::panic (0, "file not found for init")
|
||||
return target
|
||||
|
||||
static void delspace (char *&line, unsigned &maxlen):
|
||||
while maxlen && (*line == ' ' || *line == '\t'):
|
||||
++line
|
||||
--maxlen
|
||||
if maxlen && *line == '#':
|
||||
line += maxlen
|
||||
maxlen = 0
|
||||
|
||||
static bool match (char *&line, unsigned &maxlen, char const *word):
|
||||
delspace (line, maxlen)
|
||||
char const *w = word
|
||||
char *l = line
|
||||
unsigned len = 0
|
||||
while *word:
|
||||
if *l++ != *word++:
|
||||
return false
|
||||
++len
|
||||
line = l
|
||||
maxlen -= len
|
||||
delspace (line, maxlen)
|
||||
//kdebug ("match: ")
|
||||
//kdebug (w)
|
||||
//kdebug ("\n")
|
||||
return true
|
||||
|
||||
static bool isnamechar (char c):
|
||||
if c >= 'a' && c <= 'z':
|
||||
return true
|
||||
if c >= 'A' && c <= 'Z':
|
||||
return true
|
||||
if c >= '0' && c <= '9':
|
||||
return true
|
||||
if c == '_':
|
||||
return true
|
||||
return false
|
||||
|
||||
static bool get_name (char *&line, unsigned &len, char *&name, unsigned &name_len):
|
||||
delspace (line, len)
|
||||
if !len:
|
||||
return false
|
||||
name_len = 0
|
||||
while name_len < len && isnamechar (line[name_len]):
|
||||
++name_len
|
||||
name = new char[name_len]
|
||||
//kdebug ("name: ")
|
||||
for unsigned i = 0; i < name_len; ++i:
|
||||
name[i] = line[i]
|
||||
//kdebug_char (name[i])
|
||||
//kdebug_char ('\n')
|
||||
line += name_len
|
||||
len -= name_len
|
||||
delspace (line, len)
|
||||
return true
|
||||
|
||||
static bool string_match (char const *s1, unsigned l1, char const *s2, unsigned l2):
|
||||
if l1 != l2:
|
||||
return false
|
||||
for unsigned i = 0; i < l1; ++i:
|
||||
if s1[i] != s2[i]:
|
||||
return false
|
||||
return true
|
||||
|
||||
struct Type:
|
||||
char const *name
|
||||
unsigned len
|
||||
unsigned type
|
||||
|
||||
static unsigned read_num (char *&line, unsigned &len):
|
||||
delspace (line, len)
|
||||
unsigned num = 0
|
||||
while len && *line >= '0' && *line <= '9':
|
||||
num *= 10
|
||||
num += *line - '0'
|
||||
++line
|
||||
--len
|
||||
delspace (line, len)
|
||||
return num
|
||||
|
||||
static Type types[] = {
|
||||
{ "String", 6, Iris::String::ID },
|
||||
{ "WString", 7, Iris::WString::ID },
|
||||
{ "Block", 5, Iris::Block::ID },
|
||||
{ "WBlock", 6, Iris::WBlock::ID },
|
||||
{ "Boot", 4, Iris::Boot::ID },
|
||||
{ "Device", 6, Iris::Device::ID },
|
||||
{ "Event", 5, Iris::Event::ID },
|
||||
{ "Parent", 6, Iris::Parent::ID },
|
||||
{ "Keyboard", 8, Iris::Keyboard::ID },
|
||||
{ "Buzzer", 6, Iris::Buzzer::ID },
|
||||
{ "Display", 7, Iris::Display::ID },
|
||||
{ "Font", 4, Iris::Font::ID },
|
||||
{ "Setting", 7, Iris::Setting::ID },
|
||||
{ "Directory", 9, Iris::Directory::ID },
|
||||
{ "WDirectory", 10, Iris::WDirectory::ID },
|
||||
{ "Stream", 6, Iris::Stream::ID },
|
||||
{ "UI", 2, Iris::UI::ID },
|
||||
{ "RTC", 3, Iris::RTC::ID },
|
||||
{ NULL, 0, 0 }
|
||||
}
|
||||
|
||||
static void find_type (char *&line, unsigned &len, unsigned &type, unsigned &index):
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (line, len, n, l) || !len:
|
||||
Iris::panic (0, "no name for type")
|
||||
for unsigned t = 0; types[t].len != 0; ++t:
|
||||
if string_match (types[t].name, types[t].len, n, l):
|
||||
type = types[t].type
|
||||
if len && *line == ',':
|
||||
++line
|
||||
--len
|
||||
index = read_num (line, len)
|
||||
else:
|
||||
index = 0
|
||||
return
|
||||
Iris::panic (0, "no valid type found")
|
||||
|
||||
static bool find_cap (char *&line, unsigned &len, Program **server, Devbase *&dev, bool &present):
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (line, len, n, l):
|
||||
Iris::panic (0, "no capability name found in init.config")
|
||||
for List <Program>::Item *p = programs.begin (); p; p = p->next:
|
||||
List <Serverdevice>::Item *d
|
||||
for d = (*p)->server_devices.begin (); d; d = d->next:
|
||||
if string_match (n, l, (*d)->name, (*d)->name_len):
|
||||
if server:
|
||||
*server = &**p
|
||||
dev = &**d
|
||||
present = false
|
||||
return true
|
||||
if server:
|
||||
return false
|
||||
for List <File>::Item *f = files.begin (); f; f = f->next:
|
||||
if string_match (n, l, (*f)->name, (*f)->name_len):
|
||||
dev = &**f
|
||||
present = true
|
||||
return true
|
||||
return false
|
||||
|
||||
static void parse_line (char *&line, unsigned maxlen)
|
||||
static void include (char const *name, unsigned name_len):
|
||||
unsigned size
|
||||
Iris::Caps caps = load (name, name_len, size)
|
||||
unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
char *config = alloc_space (pages)
|
||||
unsigned pages_slot = caps.use ()
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page (pages_slot, p)
|
||||
Iris::my_memory.map (page, (unsigned)&config[p << PAGE_BITS])
|
||||
char *ptr = config
|
||||
while ptr - config < size:
|
||||
parse_line (ptr, config + size - ptr)
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::my_memory.destroy (Iris::Cap (pages_slot, p))
|
||||
Iris::my_memory.destroy (caps)
|
||||
Iris::free_cap (caps)
|
||||
Iris::free_slot (pages_slot)
|
||||
|
||||
static char *get_filename (char *&line, unsigned &maxlen, unsigned &len):
|
||||
char q = *line++
|
||||
--maxlen
|
||||
len = 0
|
||||
while maxlen && *line != q:
|
||||
++line
|
||||
--maxlen
|
||||
++len
|
||||
if !maxlen:
|
||||
Iris::panic (0, "no closing quote in init.config")
|
||||
return line - len
|
||||
|
||||
static void do_load (char *&line, unsigned &maxlen, bool priv):
|
||||
Program *p = &**programs.insert ()
|
||||
if !get_name (line, maxlen, p->name, p->name_len) || !match (line, maxlen, "=") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (load)")
|
||||
unsigned l
|
||||
char *n = get_filename (line, maxlen, l)
|
||||
p->pages = load (n, l, p->size)
|
||||
p->priv = priv
|
||||
p->num_waiting = 0
|
||||
++line
|
||||
--maxlen
|
||||
|
||||
static void parse_line (char *&line, unsigned maxlen):
|
||||
char *start = line
|
||||
while maxlen && *line != '\n':
|
||||
++line
|
||||
--maxlen
|
||||
// The line to execute is from start to line.
|
||||
maxlen = line - start
|
||||
if *line == '\n':
|
||||
++line
|
||||
delspace (start, maxlen)
|
||||
if !maxlen:
|
||||
return
|
||||
if match (start, maxlen, "program"):
|
||||
// program <name> = "<filename>"
|
||||
do_load (start, maxlen, false)
|
||||
else if match (start, maxlen, "driver"):
|
||||
// driver <name> = "<filename>"
|
||||
do_load (start, maxlen, true)
|
||||
else if match (start, maxlen, "file"):
|
||||
// file <name> = "<filename>"
|
||||
File *f = &**files.insert ()
|
||||
f->type = Iris::Block::ID
|
||||
if !get_name (start, maxlen, f->name, f->name_len) || !match (start, maxlen, "=") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (file name)")
|
||||
unsigned l
|
||||
char *n = get_filename (start, maxlen, l)
|
||||
f->pages = load (n, l, f->size)
|
||||
f->cap = Iris::my_receiver.create_capability (Iris::Num (FILE, (unsigned)f))
|
||||
++line
|
||||
--maxlen
|
||||
else if match (start, maxlen, "receive"):
|
||||
// receive <name> / <type> [, <index>] = <cap>
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (receive)")
|
||||
List <Program>::Item *p
|
||||
for p = programs.begin (); p; p = p->next:
|
||||
if string_match ((*p)->name, (*p)->name_len, n, l):
|
||||
break
|
||||
if !p:
|
||||
Iris::panic (0, "program not found for receive")
|
||||
List <Serverdevice>::Item *dev = (*p)->server_devices.insert ()
|
||||
find_type (start, maxlen, (*dev)->type, (*dev)->index)
|
||||
if !match (start, maxlen, "=") || !get_name (start, maxlen, (*dev)->name, (*dev)->name_len):
|
||||
Iris::panic (1, "syntax error in init.config (receive)")
|
||||
(*dev)->server = &**p
|
||||
(*dev)->client = NULL
|
||||
(*dev)->cap = Iris::Cap ()
|
||||
else if match (start, maxlen, "sysreq"):
|
||||
Program *server
|
||||
if sysreq:
|
||||
Iris::panic (0, "double registration of sysreq")
|
||||
bool dummy
|
||||
if !find_cap (start, maxlen, &server, *(Devbase **)&sysreq, dummy):
|
||||
Iris::panic (0, "capability not found for sysreq")
|
||||
if sysreq->type != Iris::Keyboard::ID:
|
||||
kdebug ("capability for sysreq is not a keyboard\n")
|
||||
else if match (start, maxlen, "give"):
|
||||
// give <name> / <type> [, <index>] = <cap>
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (give)")
|
||||
List <Program>::Item *p
|
||||
for p = programs.begin (); p; p = p->next:
|
||||
if string_match ((*p)->name, (*p)->name_len, n, l):
|
||||
break
|
||||
if !p:
|
||||
Iris::panic (0, "program not found for give")
|
||||
List <Clientdevice>::Item *d = (*p)->client_devices.insert ()
|
||||
find_type (start, maxlen, (*d)->type, (*d)->index)
|
||||
if !match (start, maxlen, "="):
|
||||
Iris::panic (1, "syntax error in init.config (give)")
|
||||
bool present
|
||||
if !find_cap (start, maxlen, NULL, (*d)->dev, present):
|
||||
Iris::panic (0, "capability not found for give")
|
||||
if (*d)->dev->type != (*d)->type:
|
||||
kdebug ("capability type mismatch for give\n")
|
||||
if (*d)->dev->client:
|
||||
Iris::panic (0, "capability given out twice")
|
||||
(*d)->dev->client = &**p
|
||||
if !present:
|
||||
++(*p)->num_waiting
|
||||
//kdebug ("registered give device: ")
|
||||
//kdebug_num ((*d)->type)
|
||||
//kdebug ("\n")
|
||||
else if match (start, maxlen, "include"):
|
||||
unsigned name_len
|
||||
char *name = get_filename (line, maxlen, name_len)
|
||||
include (name, name_len)
|
||||
else:
|
||||
for unsigned i = 0; i < maxlen; ++i:
|
||||
kdebug_char (start[i])
|
||||
kdebug_char ('\n')
|
||||
Iris::panic (0, "invalid line in init.config")
|
||||
delspace (start, maxlen)
|
||||
if maxlen:
|
||||
kdebug ("Junk: ")
|
||||
for unsigned i = 0; i < maxlen; ++i:
|
||||
kdebug_char (start[i])
|
||||
kdebug_char ('\n')
|
||||
Iris::panic (0, "junk at end of line in init.config")
|
||||
|
||||
Iris::Num start ():
|
||||
init_alloc ()
|
||||
programs.init ()
|
||||
files.init ()
|
||||
root = Iris::my_parent.get_capability <Iris::Directory> ()
|
||||
elfrun = Iris::my_parent.get_capability <Iris::Elfrun> ()
|
||||
sysreq = NULL
|
||||
top_memory = Iris::get_top_memory ()
|
||||
include (INIT_CONFIG, INIT_CONFIG_SIZE)
|
||||
kdebug ("killing boot threads\n")
|
||||
Iris::my_parent.init_done ()
|
||||
for List <Program>::Item *p = programs.begin (); p; p = p->next:
|
||||
if !(*p)->num_waiting:
|
||||
(*p)->run ()
|
||||
if !sysreq:
|
||||
Iris::panic (0, "sysreq not registered")
|
||||
if sysreq->client:
|
||||
Iris::panic (0, "sysreq set to reserved capability")
|
||||
kdebug ("waiting for events.\n")
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case SYSREQ:
|
||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||
Iris::reboot ()
|
||||
continue
|
||||
kdebug ("sysreq event: rebooting device at release\n")
|
||||
continue
|
||||
case FILE:
|
||||
File *file = (File *)Iris::recv.protected_data.h
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Block::GET_SIZE:
|
||||
Iris::recv.reply.invoke (file->size)
|
||||
break
|
||||
case Iris::Block::GET_ALIGN_BITS:
|
||||
Iris::recv.reply.invoke (PAGE_BITS)
|
||||
break
|
||||
case Iris::Block::GET_BLOCK:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Page target = Iris::get_arg ()
|
||||
Iris::Page source = file->pages.get (Iris::recv.data[1].l >> PAGE_BITS)
|
||||
source.share (target, Iris::Page::READONLY)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (source)
|
||||
Iris::free_cap (target)
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "unknown request for init string")
|
||||
break
|
||||
case PROGRAM:
|
||||
Program *caller = (Program *)Iris::recv.protected_data.h
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Parent::GET_CAPABILITY:
|
||||
unsigned index = Iris::recv.data[0].h
|
||||
unsigned type = Iris::recv.data[1].l
|
||||
if Iris::recv.data[1].h:
|
||||
Iris::panic (Iris::recv.data[1].h, "high device requested")
|
||||
//kdebug ("requested device ")
|
||||
//kdebug_num (type)
|
||||
//kdebug (":")
|
||||
//kdebug_num (index)
|
||||
//kdebug ("\n")
|
||||
List <Clientdevice>::Item *d
|
||||
for d = caller->client_devices.begin (); d; d = d->next:
|
||||
//kdebug ("checking ")
|
||||
//kdebug_num ((*d)->type)
|
||||
//kdebug (":")
|
||||
//kdebug_num ((*d)->index)
|
||||
//kdebug ("\n")
|
||||
if (*d)->type == type && (*d)->index == index:
|
||||
break
|
||||
if !d:
|
||||
Iris::debug ("requested %x by %s\n", type, caller->name)
|
||||
Iris::panic (type, "unregistered device requested")
|
||||
Iris::recv.reply.invoke (0, 0, (*d)->dev->cap)
|
||||
//kdebug ("given device ")
|
||||
//kdebug_num (type)
|
||||
//kdebug (":")
|
||||
//kdebug_num (index)
|
||||
//kdebug ("\n")
|
||||
break
|
||||
case Iris::Parent::PROVIDE_CAPABILITY:
|
||||
if Iris::recv.data[1].h != 0:
|
||||
kdebug ("init: too high device provided\n")
|
||||
continue
|
||||
unsigned type = Iris::recv.data[1].l
|
||||
unsigned index = Iris::recv.data[0].h
|
||||
List <Serverdevice>::Item *d
|
||||
for d = caller->server_devices.begin (); d; d = d->next:
|
||||
if (*d)->type == type && (*d)->index == index:
|
||||
break
|
||||
if !d:
|
||||
Iris::debug ("caller: %s\n", caller->name)
|
||||
Iris::panic (type, "unregistered device provided")
|
||||
(*d)->cap = Iris::get_arg ()
|
||||
Iris::recv.reply.invoke ()
|
||||
if (*d)->client:
|
||||
if !--(*d)->client->num_waiting:
|
||||
(*d)->client->run ()
|
||||
//kdebug ("provided ")
|
||||
//kdebug_num ((*d)->type)
|
||||
//kdebug (":")
|
||||
//kdebug_num ((*d)->index)
|
||||
//kdebug ("\n")
|
||||
break
|
||||
case Iris::Parent::INIT_DONE:
|
||||
//kdebug ("init done\n")
|
||||
Iris::recv.reply.invoke ()
|
||||
if caller == sysreq->server:
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ)
|
||||
Iris::Keyboard (sysreq->cap).set_cb (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
kdebug ("registered sysreq\n")
|
||||
break
|
||||
case Iris::Parent::EXIT:
|
||||
kdebug ("child ")
|
||||
for unsigned i = 0; i < caller->name_len; ++i:
|
||||
kdebug_char (caller->name[i])
|
||||
kdebug (" exits with code ")
|
||||
kdebug_num (Iris::recv.data[1].h)
|
||||
kdebug (":")
|
||||
kdebug_num (Iris::recv.data[1].l)
|
||||
kdebug ("\n")
|
||||
top_memory.destroy (caller->memory)
|
||||
break
|
||||
default:
|
||||
// TODO.
|
||||
kdebug ("child request: ")
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug (" from ")
|
||||
for unsigned i = 0; i < caller->name_len; ++i:
|
||||
kdebug_char (caller->name[i])
|
||||
kdebug ("\n")
|
||||
32
userspace/boot/mkthreadlist
Executable file
32
userspace/boot/mkthreadlist
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
cat << EOF
|
||||
.globl init_start
|
||||
.globl thread_start
|
||||
.set noreorder
|
||||
.balign 0x1000
|
||||
EOF
|
||||
|
||||
for i in "$@" ; do
|
||||
cat << EOF
|
||||
${i##*/}:
|
||||
.incbin "fs/${i##*/}.elf"
|
||||
.balign 0x1000
|
||||
EOF
|
||||
done
|
||||
|
||||
cat << EOF
|
||||
end_threads:
|
||||
init_start:
|
||||
thread_start:
|
||||
EOF
|
||||
|
||||
for i in "$@" ; do
|
||||
cat << EOF
|
||||
.word ${i##*/}
|
||||
EOF
|
||||
done
|
||||
|
||||
cat << EOF
|
||||
.word end_threads
|
||||
.word 0
|
||||
EOF
|
||||
886
userspace/data/charset
Executable file
886
userspace/data/charset
Executable file
@@ -0,0 +1,886 @@
|
||||
#!/usr/bin/env python
|
||||
data = """
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . . . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. # # . # #
|
||||
. . # . . #
|
||||
+ # . + # .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . # . # .
|
||||
. # # # # #
|
||||
. # . # . .
|
||||
# # # # # .
|
||||
# . # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . # .
|
||||
. . # # # #
|
||||
. # . # . .
|
||||
. . # # # .
|
||||
. . # . # .
|
||||
. # # # # .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. # # . # .
|
||||
. # . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . # .
|
||||
. # . # # .
|
||||
. . . . . .
|
||||
|
||||
. # # . . .
|
||||
. # . # . .
|
||||
. # # . . .
|
||||
. . # . . .
|
||||
. # # . # .
|
||||
. # . # # .
|
||||
. # # # # .
|
||||
. . . . . .
|
||||
|
||||
. . # # . .
|
||||
. . . # . .
|
||||
. + # . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . + # #
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. . # . . .
|
||||
. . # # . .
|
||||
. . . . . .
|
||||
|
||||
. . # # . .
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
# # + . . .
|
||||
. . . . . .
|
||||
|
||||
. # . . # .
|
||||
. . # . # .
|
||||
. . # # . .
|
||||
. # # # # #
|
||||
. . # # . .
|
||||
. . # . # .
|
||||
. # . . # .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
# # # # # .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . # # . .
|
||||
. . # . . .
|
||||
. + # . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. # # # # .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . # . .
|
||||
. . # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . + # # .
|
||||
. # + . # .
|
||||
. # . . # .
|
||||
# . . # . .
|
||||
# . + # . .
|
||||
# # + . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . # .
|
||||
. . # # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . + # # .
|
||||
. + + . # .
|
||||
. . . . # .
|
||||
. + # . . .
|
||||
. # . . . .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # # # .
|
||||
. . . . # .
|
||||
. . . + # .
|
||||
. + # . . .
|
||||
. . . # . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # . . #
|
||||
. # . . # .
|
||||
. # # # # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # # # #
|
||||
. # . . . .
|
||||
. # # # . .
|
||||
. . . # . .
|
||||
. . . . # .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . + # .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # # # .
|
||||
. # . . # .
|
||||
. # . . # .
|
||||
. # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # # # #
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . + + . .
|
||||
. . + + . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . + # # .
|
||||
. # . . # .
|
||||
. + # # + .
|
||||
# . . # . .
|
||||
# . . # . .
|
||||
# # + . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . + # # .
|
||||
. # . . # .
|
||||
. # . + # .
|
||||
. # + # . .
|
||||
. . . # . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # . .
|
||||
. . # # . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. # # . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # . .
|
||||
. . # # . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. # # . . .
|
||||
. # . . . .
|
||||
+ # . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # + .
|
||||
. + + . . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. # # # # .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . + + . .
|
||||
+ # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . # # . .
|
||||
. . # . # .
|
||||
. . . . # .
|
||||
. . . + # .
|
||||
. . # . . .
|
||||
. . . . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . # # # .
|
||||
. . # . . #
|
||||
. # . # . #
|
||||
. # . # + #
|
||||
# . # # # .
|
||||
. # . . . .
|
||||
. # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . + # .
|
||||
. . . # . #
|
||||
. . # . . #
|
||||
. . # # # #
|
||||
. # . . # .
|
||||
. # . . # .
|
||||
# . . # . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # .
|
||||
. . . # . #
|
||||
. . # . # .
|
||||
. . # # # .
|
||||
. # . . # .
|
||||
. # . + # .
|
||||
# # # + . .
|
||||
. . . . . .
|
||||
|
||||
. . + # # .
|
||||
. . # + . #
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
+ + . + + .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # .
|
||||
. . . # . #
|
||||
. . # . . #
|
||||
. . # . . #
|
||||
. # . . # .
|
||||
. # . + # .
|
||||
# # # + . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # #
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # # . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # #
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # # . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . + # # .
|
||||
. . # + . #
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# . # # . .
|
||||
+ + . # . .
|
||||
+ # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # . #
|
||||
. . . # . #
|
||||
. . # . # .
|
||||
. . # # # .
|
||||
. # . # . .
|
||||
. # . # . .
|
||||
# . # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # #
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # #
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
# . # . . .
|
||||
# # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # . #
|
||||
. . . # . #
|
||||
. . # . # .
|
||||
. . # # + .
|
||||
. # + . . .
|
||||
. # . # . .
|
||||
# . . # . .
|
||||
. . . . . .
|
||||
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . # . # #
|
||||
. . # + # +
|
||||
. # . # . #
|
||||
. # . . . #
|
||||
# . . . # .
|
||||
# . . . # .
|
||||
+ . . # . .
|
||||
. . . . . .
|
||||
|
||||
. . # . . #
|
||||
. . # # . +
|
||||
. # + + . #
|
||||
. # . # . #
|
||||
# . + + # .
|
||||
# . . # # .
|
||||
+ . . # . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # .
|
||||
. . # + . #
|
||||
. # . . . #
|
||||
. # . . . #
|
||||
# . . . # .
|
||||
# . . + # .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # .
|
||||
. . . # . #
|
||||
. . # . . #
|
||||
. . # . + #
|
||||
. # # # + .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # .
|
||||
. . # + . #
|
||||
. # . . . #
|
||||
. # . . . #
|
||||
# . . # # .
|
||||
# . . . # .
|
||||
# # # . # .
|
||||
. . . . . .
|
||||
|
||||
. . . # # .
|
||||
. . . # . #
|
||||
. . # . . #
|
||||
. . # . + #
|
||||
. # # # + .
|
||||
. # . # . .
|
||||
# . . # . .
|
||||
. . . . . .
|
||||
|
||||
. . + # # #
|
||||
. . # + . .
|
||||
. # . . . .
|
||||
. . # # . .
|
||||
. . . # . .
|
||||
. . . . # .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. # # # # #
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . # . . #
|
||||
. . # . . #
|
||||
. # . . # .
|
||||
. # . . # .
|
||||
# . . # . .
|
||||
# . + # . .
|
||||
# # + . . .
|
||||
. . . . . .
|
||||
|
||||
. + . . . #
|
||||
. # . . . #
|
||||
+ . . . # .
|
||||
. # . . # .
|
||||
+ . . # . .
|
||||
. # + + . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . # . . +
|
||||
. . # . . +
|
||||
. # . . . #
|
||||
. # . . . #
|
||||
# . # . # .
|
||||
# + # . # .
|
||||
# + # # . .
|
||||
. . . . . .
|
||||
|
||||
. # . . . #
|
||||
. . # . . #
|
||||
. . # # + .
|
||||
. . . # . .
|
||||
. + # # . .
|
||||
. # . . # .
|
||||
# . . . # .
|
||||
. . . . . .
|
||||
|
||||
. # . . . #
|
||||
. . # . . #
|
||||
. . # # + .
|
||||
. . . # . .
|
||||
. + # . . .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . # # # #
|
||||
. . . . . #
|
||||
. . . # + .
|
||||
. . . # . .
|
||||
. + # . . .
|
||||
. # . . . .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # #
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. # . . . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . . . . .
|
||||
|
||||
. . . # # #
|
||||
. . . . . #
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . + # .
|
||||
. . + # . #
|
||||
. # . . . #
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
# # # # # .
|
||||
. . . . . .
|
||||
|
||||
. . # # . .
|
||||
. . . # . .
|
||||
. . + # . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # # + #
|
||||
. # . # # .
|
||||
. # . . # .
|
||||
# . . # . .
|
||||
. # + # . .
|
||||
. # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # # # .
|
||||
. # . . # .
|
||||
. # . . # .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # # .
|
||||
. # + . # .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. # . # . .
|
||||
. # + . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . #
|
||||
. . . . . #
|
||||
. . # # # .
|
||||
. # + . # .
|
||||
# . . # . .
|
||||
# . . # . .
|
||||
# # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . + # # .
|
||||
. # . . # .
|
||||
. # # # + .
|
||||
# . . . . .
|
||||
. # . . . .
|
||||
. # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # .
|
||||
. . . # . #
|
||||
. . # . . .
|
||||
. # # # . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # # #
|
||||
. . # . . #
|
||||
. . . # # #
|
||||
. . . . # .
|
||||
. . . + # .
|
||||
. # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # # # . .
|
||||
. # . . # .
|
||||
# . . # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . # .
|
||||
. . . . . .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . # .
|
||||
. . . . . .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
# # . . . .
|
||||
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # + # . .
|
||||
. # # + . .
|
||||
# . # + . .
|
||||
. . . . . .
|
||||
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # # #
|
||||
. . # + + #
|
||||
. . # + + #
|
||||
. # + + # .
|
||||
. # + + # .
|
||||
# + + # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # + #
|
||||
. . # # + #
|
||||
. . # . . #
|
||||
. # . . # .
|
||||
. # . . # .
|
||||
# . . # . .
|
||||
. . . # . .
|
||||
|
||||
. . . . . .
|
||||
. . + # # .
|
||||
. # + . # .
|
||||
. # . . . #
|
||||
# . . . # .
|
||||
. # . + # .
|
||||
. # # + . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # # #
|
||||
. . # . . #
|
||||
. . # . . #
|
||||
. # # # + .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . + # # #
|
||||
. # . . # .
|
||||
. # . . # .
|
||||
. # # # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # + #
|
||||
. . # # . #
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
# . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # # # #
|
||||
. # . . . .
|
||||
. . # # . .
|
||||
. . . # . .
|
||||
. . . . # .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . . # . .
|
||||
. # # # . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. # . # . .
|
||||
. # + . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # . . #
|
||||
. # . . # .
|
||||
. # . . # .
|
||||
# . . # . .
|
||||
# . + # . .
|
||||
# # + . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. + # . . +
|
||||
. # . . . #
|
||||
. + + . + #
|
||||
. # . # + .
|
||||
. # . # . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # . . +
|
||||
. # . . . #
|
||||
. # . # . #
|
||||
# . # . # .
|
||||
# . # . # .
|
||||
# # # + . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # . . #
|
||||
. . # . # .
|
||||
. . + # + .
|
||||
. + # + . .
|
||||
. # . # . .
|
||||
# . . # . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # . . #
|
||||
. # . . # .
|
||||
. . # # # .
|
||||
. . . # . .
|
||||
. . + # . .
|
||||
# # + . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. . # # # #
|
||||
. . . . # .
|
||||
. . . # + .
|
||||
. + # . . .
|
||||
. # . . . .
|
||||
# # # # . .
|
||||
. . . . . .
|
||||
|
||||
. . . + # #
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. # + . . .
|
||||
. # . . . .
|
||||
. # . . . .
|
||||
+ # # . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . # .
|
||||
. . . . # .
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
. . # . . .
|
||||
. . # . . .
|
||||
. # . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . # # +
|
||||
. . . . . #
|
||||
. . . . # .
|
||||
. . . . + #
|
||||
. . . # . .
|
||||
. . . # . .
|
||||
# # + . . .
|
||||
. . . . . .
|
||||
|
||||
. # # . . .
|
||||
. # . # . #
|
||||
. . . # # .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
. . . . . .
|
||||
|
||||
. . . . . .
|
||||
. # + # + .
|
||||
. # + # + .
|
||||
. + # + # .
|
||||
. + # + # .
|
||||
. # + # + .
|
||||
. # + # + .
|
||||
. . . . . .
|
||||
|
||||
"""
|
||||
# """ # add quotes, because vim thinks the qotes on the previous line start a string.
|
||||
|
||||
import sys
|
||||
|
||||
charsize = 25 * 4 + 1
|
||||
for c in range (128 - 32):
|
||||
for l in range (8):
|
||||
offset = 2 + c * charsize + 25 * (l >> 1) + 12 * (l & 1)
|
||||
ln = ""
|
||||
for x in range (6):
|
||||
char = data[offset + x * 2]
|
||||
if char == '.':
|
||||
sys.stdout.write (chr (0))
|
||||
elif char == '+':
|
||||
sys.stdout.write (chr (128))
|
||||
elif char == '#':
|
||||
sys.stdout.write (chr (255))
|
||||
else:
|
||||
raise "invalid character in " + str (c)
|
||||
BIN
userspace/data/courier-10+8+32.png
Normal file
BIN
userspace/data/courier-10+8+32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
userspace/data/courier.xcf
Normal file
BIN
userspace/data/courier.xcf
Normal file
Binary file not shown.
80
userspace/data/init.config
Normal file
80
userspace/data/init.config
Normal file
@@ -0,0 +1,80 @@
|
||||
# driver <name> = '<filename>' load a file into memory to be run priviledged.
|
||||
# program <name> = '<filename>' load a file into memory to be run normally.
|
||||
# file <name> = '<filename>' load a file into memory as a Block.
|
||||
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
|
||||
# sysreq <cap> use a capability as the system request keyboard.
|
||||
# give <name> / <type> [, <index>] = <cap> give this capability to this program when it requests it.
|
||||
# include <file> include a file as another config file.
|
||||
# at end of file, the initial threads are killed and the drivers and programs are run as soon as all their dependencies are provided.
|
||||
|
||||
driver driver_gpio = "gpio.elf"
|
||||
receive driver_gpio / Keyboard , 0 = keyboard
|
||||
receive driver_gpio / Keyboard , 1 = sysreq
|
||||
receive driver_gpio / Event = sdmmc_gpio
|
||||
sysreq sysreq
|
||||
|
||||
#driver driver_nand = "nand.elf"
|
||||
#receive driver_nand / WBlock = nand
|
||||
|
||||
#driver driver_ums = "usb-mass-storage.elf"
|
||||
#give driver_ums / WBlock = nand
|
||||
|
||||
#driver driver_boot = "boot.elf"
|
||||
#receive driver_boot / Boot = boot
|
||||
|
||||
#file kernel = "kernel.raw"
|
||||
#program booter = "booter.elf"
|
||||
#give booter / Block = kernel
|
||||
#give booter / Boot = boot
|
||||
|
||||
driver driver_lcd = "lcd.elf"
|
||||
receive driver_lcd / Display = display
|
||||
receive driver_lcd / Setting = display_bright
|
||||
|
||||
driver driver_buzzer = "buzzer.elf"
|
||||
receive driver_buzzer / Buzzer = buzzer
|
||||
|
||||
#program alarm = "alarm.elf"
|
||||
#receive alarm / UI = ui
|
||||
|
||||
#program gui = "gui.elf"
|
||||
#give gui / UI = ui
|
||||
#give gui / Display = display
|
||||
#give gui / Setting = display_bright
|
||||
#give gui / Buzzer = buzzer
|
||||
#give gui / Keyboard = keyboard
|
||||
|
||||
#driver sdmmc = "sd+mmc.elf"
|
||||
#receive sdmmc / WBlock = sdmmc
|
||||
#give sdmmc / Event = sdmmc_gpio
|
||||
|
||||
#program partition = "partition.elf"
|
||||
#receive partition / WBlock, 0 = p0
|
||||
#receive partition / WBlock, 1 = p1
|
||||
#receive partition / WBlock, 2 = p2
|
||||
#receive partition / WBlock, 3 = p3
|
||||
#give partition / WBlock = sdmmc
|
||||
|
||||
#program fat = "fat.elf"
|
||||
#receive fat / Directory = root
|
||||
#give fat / WBlock = p0
|
||||
|
||||
#program test = "test.elf"
|
||||
#give test / Directory = root
|
||||
|
||||
file fontfile = "font.dat"
|
||||
program font = "font.elf"
|
||||
receive font / Font = font
|
||||
give font / Block = fontfile
|
||||
#give font / Display = display
|
||||
|
||||
driver driver_rtc = "rtc.elf"
|
||||
receive driver_rtc / RTC = rtc
|
||||
|
||||
driver alarm = "alarm.elf"
|
||||
give alarm / Keyboard = keyboard
|
||||
give alarm / Display = display
|
||||
give alarm / Buzzer = buzzer
|
||||
give alarm / Font = font
|
||||
give alarm / RTC = rtc
|
||||
receive alarm / Event = alarm
|
||||
30
userspace/data/makefont
Executable file
30
userspace/data/makefont
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import os
|
||||
from PIL import Image
|
||||
|
||||
def mknum (num):
|
||||
return ''.join ([chr ((num >> (8 * i)) & 0xff) for i in range (4)])
|
||||
|
||||
im = Image.open (sys.argv[1])
|
||||
height = im.size[1]
|
||||
width, baseline, skip = [int (x) for x in os.path.splitext (sys.argv[1])[0].split ('-')[-1].split ('+')]
|
||||
num_glyphs = im.size[0] / width
|
||||
sys.stdout.write (mknum (skip + num_glyphs))
|
||||
size1 = (3 + width * height) * 4
|
||||
base = (num_glyphs + skip) * 4
|
||||
for i in range (skip):
|
||||
sys.stdout.write (mknum (base + (num_glyphs - 1) * size1))
|
||||
for i in range (skip, skip + num_glyphs):
|
||||
sys.stdout.write (mknum (base + (i - skip) * size1))
|
||||
|
||||
im = im.convert ('RGBA')
|
||||
pix = im.load ()
|
||||
#sys.stderr.write ('%d\n' % len (pix[0,0]))
|
||||
for g in range (skip, skip + num_glyphs):
|
||||
sys.stdout.write (mknum (width))
|
||||
sys.stdout.write (mknum (height))
|
||||
sys.stdout.write (mknum (baseline))
|
||||
for y in range (height):
|
||||
for x in range (width):
|
||||
sys.stdout.write (''.join ([chr (x) for x in (pix[x + (g - skip) * width, y])]))
|
||||
98
userspace/glue/buffer.ccp
Normal file
98
userspace/glue/buffer.ccp
Normal file
@@ -0,0 +1,98 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/buffer.ccp: block device buffer.
|
||||
// Copyright 2010 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 "iris.hh"
|
||||
#include "devices.hh"
|
||||
|
||||
static unsigned align
|
||||
static Iris::Page page, rpage
|
||||
static unsigned mapping, rmapping
|
||||
static Iris::Num size, current
|
||||
static Iris::String dev
|
||||
|
||||
static void read_block (Iris::Num idx):
|
||||
idx = idx.value () & PAGE_MASK
|
||||
if idx.value () == current.value ():
|
||||
return
|
||||
//kdebug ("buffering block ")
|
||||
//kdebug_num (idx.h)
|
||||
//kdebug (":")
|
||||
//kdebug_num (idx.l)
|
||||
//kdebug ("\n")
|
||||
dev.get_block (idx, PAGE_SIZE, 0, page)
|
||||
//kdebug ("buffered\n")
|
||||
current = idx
|
||||
|
||||
Iris::Num start ():
|
||||
dev = Iris::my_parent.get_capability <Iris::WString> ()
|
||||
align = dev.get_align_bits ()
|
||||
size = dev.get_size ()
|
||||
if align > PAGE_BITS:
|
||||
Iris::panic (align, "invalid alignment value for block device")
|
||||
page = Iris::my_memory.create_page ()
|
||||
rpage = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING)
|
||||
rpage.set_flags (Iris::Page::PAYING)
|
||||
mapping = 0x15000
|
||||
rmapping = 0x17000
|
||||
Iris::my_memory.map (page, mapping)
|
||||
Iris::my_memory.map (rpage, rmapping)
|
||||
current.h = ~0
|
||||
current.l = ~0
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (0)
|
||||
Iris::my_parent.provide_capability <Iris::WString> (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
Iris::my_parent.init_done ()
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::String::GET_SIZE:
|
||||
Iris::recv.reply.invoke (size)
|
||||
break
|
||||
case Iris::String::GET_ALIGN_BITS:
|
||||
// Use 16 byte alignment to make implementing GET_CHARS easier.
|
||||
Iris::recv.reply.invoke (4)
|
||||
break
|
||||
case Iris::String::GET_CHARS:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
unsigned offset = Iris::recv.data[1].l & ~PAGE_MASK & ~((1 << 4) - 1)
|
||||
read_block (Iris::recv.data[1])
|
||||
unsigned *data = (unsigned *)((char *)mapping)[offset]
|
||||
reply.invoke (Iris::Num (data[0], data[1]), Iris::Num (data[2], data[3]))
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::String::GET_BLOCK:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Page arg = Iris::get_arg ()
|
||||
unsigned offset = Iris::recv.data[1].l & ~PAGE_MASK & ~((1 << 4) - 1)
|
||||
unsigned sz = Iris::recv.data[0].h >> 16
|
||||
unsigned roffset = Iris::recv.data[0].h & 0xffff
|
||||
Iris::Num idx = Iris::recv.data[1]
|
||||
arg.set_flags (Iris::Page::FRAME | Iris::Page::PAYING)
|
||||
arg.share (rpage)
|
||||
rpage.set_flags (Iris::Page::FRAME)
|
||||
read_block (idx)
|
||||
for unsigned i = 0; i < sz; ++i:
|
||||
((char *)rmapping)[roffset + i] = ((char *)mapping)[offset + i]
|
||||
rpage.set_flags (0, Iris::Page::FRAME)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid request for buffer")
|
||||
304
userspace/glue/elfrun.ccp
Normal file
304
userspace/glue/elfrun.ccp
Normal file
@@ -0,0 +1,304 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/elfrun.ccp: Process creation server.
|
||||
// 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 "iris.hh"
|
||||
#include <elf.h>
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
static Iris::Memory parent_memory
|
||||
static Iris::Cap parent
|
||||
static unsigned slot
|
||||
static char *mapping
|
||||
static unsigned pages
|
||||
static Iris::Caps pages_caps
|
||||
static Iris::Memory mem
|
||||
static unsigned *bss_mapping
|
||||
static Iris::Page bss_page
|
||||
|
||||
static Iris::Caps map_string (Iris::Block data):
|
||||
// Get the size.
|
||||
Iris::Num size = data.get_size ()
|
||||
if size.value () == 0:
|
||||
Iris::panic (0, "data string is empty")
|
||||
// Allocate a caps with all the pages.
|
||||
pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
pages_caps = Iris::my_memory.create_caps (pages)
|
||||
slot = pages_caps.use ()
|
||||
// Map them into the address space as well.
|
||||
mapping = alloc_space (pages)
|
||||
// Create a memory for the program.
|
||||
mem = parent_memory.create_memory ()
|
||||
// Load the file into memory and map it.
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
//kdebug_num (p)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (pages)
|
||||
//kdebug ("\n")
|
||||
Iris::set_recv_arg (Iris::Cap (slot, p))
|
||||
data.get_block (p << PAGE_BITS)
|
||||
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
|
||||
|
||||
static Iris::Caps map_caps (Iris::Caps data, unsigned p):
|
||||
// Get the size.
|
||||
if p == 0:
|
||||
Iris::panic (0, "data caps is empty")
|
||||
// Allocate a new caps with all the pages for mapping locally.
|
||||
pages = p
|
||||
pages_caps = Iris::my_memory.create_caps (pages)
|
||||
slot = pages_caps.use ()
|
||||
unsigned src_slot = data.use ()
|
||||
// Map them into the address space as well.
|
||||
mapping = alloc_space (pages)
|
||||
// Create a memory for the program.
|
||||
mem = parent_memory.create_memory ()
|
||||
// Load the file into memory and map it.
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
//kdebug_num (p)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (pages)
|
||||
//kdebug ("\n")
|
||||
Iris::Page page = Iris::Cap (slot, p)
|
||||
Iris::set_recv_arg (page)
|
||||
Iris::my_memory.create_page ()
|
||||
Iris::Page (Iris::Cap (src_slot, p)).share (page)
|
||||
Iris::my_memory.map (page, (unsigned)&mapping[p << PAGE_BITS])
|
||||
Iris::free_slot (src_slot)
|
||||
|
||||
static Iris::Caps run (Iris::Caps data, Iris::Memory parent_memory, Iris::Cap parent, unsigned num_slots, unsigned num_caps):
|
||||
Iris::Thread thread = mem.create_thread (num_slots)
|
||||
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
|
||||
for unsigned j = 0; j < SELFMAG; ++j:
|
||||
if header->e_ident[j] != ELFMAG[j]:
|
||||
Iris::panic (header->e_ident[j], "invalid ELF magic")
|
||||
return Iris::Caps ()
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class:")
|
||||
kdebug_num (header->e_ident[EI_CLASS])
|
||||
kdebug (" != ")
|
||||
kdebug_num (ELFCLASS32)
|
||||
kdebug ("\n")
|
||||
Iris::panic (0)
|
||||
return Iris::Caps ()
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
|
||||
if header->e_ident[EI_VERSION] != EV_CURRENT:
|
||||
Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
|
||||
if header->e_type != ET_EXEC:
|
||||
Iris::panic (header->e_type, "invalid ELF type")
|
||||
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
|
||||
Iris::panic (header->e_machine, "invalid ELF machine")
|
||||
thread.set_pc (header->e_entry)
|
||||
thread.set_sp (0x80000000)
|
||||
for unsigned section = 0; section < header->e_shnum; ++section:
|
||||
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
|
||||
if ~shdr->sh_flags & SHF_ALLOC:
|
||||
continue
|
||||
bool readonly = !(shdr->sh_flags & SHF_WRITE)
|
||||
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
|
||||
if shdr->sh_type != SHT_NOBITS:
|
||||
//kdebug ("loading ")
|
||||
//kdebug_num (shdr->sh_addr)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (shdr->sh_size)
|
||||
//kdebug ("\n")
|
||||
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
|
||||
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
|
||||
kdebug ("thread size: ")
|
||||
kdebug_num (file_offset)
|
||||
kdebug (",")
|
||||
kdebug_num (shdr->sh_size)
|
||||
kdebug ("\n")
|
||||
Iris::panic (shdr->sh_size, "thread too large")
|
||||
return Iris::Caps ()
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
|
||||
unsigned idx = file_offset + section_offset
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// The address already has a mapping; assume that it is correct.
|
||||
Iris::free_cap (page)
|
||||
continue
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
unsigned f
|
||||
if readonly:
|
||||
f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
|
||||
else:
|
||||
f = Iris::Page::PAYING
|
||||
page.set_flags (f)
|
||||
Iris::Page (slot, idx).share (page, 0)
|
||||
//kdebug ("mapping at ")
|
||||
//kdebug_num (p)
|
||||
//if readonly:
|
||||
// kdebug (" (readonly)")
|
||||
//kdebug ("\n")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map page")
|
||||
return Iris::Caps ()
|
||||
Iris::free_cap (page)
|
||||
else:
|
||||
if readonly:
|
||||
Iris::panic (0, "unwritable bss section")
|
||||
return Iris::Caps ()
|
||||
//kdebug ("clearing ")
|
||||
//kdebug_num (shdr->sh_addr)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (shdr->sh_size)
|
||||
//kdebug ("\n")
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
Iris::Page page = mem.mapping ((void *)p)
|
||||
if Iris::recv.data[0].l == Iris::NO_ERROR:
|
||||
// No error means there is a mapping.
|
||||
page.share (bss_page, 0)
|
||||
Iris::free_cap (page)
|
||||
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
|
||||
if a >= shdr->sh_addr + shdr->sh_size:
|
||||
break
|
||||
if a < shdr->sh_addr:
|
||||
continue
|
||||
bss_mapping[(a & ~PAGE_MASK) >> 2] = 0
|
||||
else:
|
||||
Iris::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR:
|
||||
Iris::panic (Iris::recv.data[0].l, "out of memory")
|
||||
if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME):
|
||||
Iris::panic (0, "out of memory")
|
||||
if !mem.map (page, p):
|
||||
Iris::panic (0, "unable to map bss page")
|
||||
Iris::free_cap (page)
|
||||
//kdebug ("start of program:\n")
|
||||
//for unsigned i = 0; i < 0x40; i += 4:
|
||||
// kdebug_num ((unsigned)mapping + 4 * i, 3)
|
||||
// kdebug (" ==>")
|
||||
// for unsigned j = 0; j < 4; j += 1:
|
||||
// kdebug (" ")
|
||||
// kdebug_num (((unsigned *)mapping)[i + j])
|
||||
// kdebug ("\n")
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::my_memory.destroy (Iris::Page (slot, p))
|
||||
Iris::my_memory.destroy (pages_caps)
|
||||
Iris::free_slot (slot)
|
||||
Iris::free_cap (pages_caps)
|
||||
Iris::Page stackpage = mem.create_page ()
|
||||
stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
|
||||
Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
|
||||
Iris::free_cap (stackpage)
|
||||
Iris::Caps caps = mem.create_caps (num_caps)
|
||||
thread.use (caps, 0)
|
||||
thread.set_info (Iris::Thread::A0, num_slots)
|
||||
thread.set_info (Iris::Thread::A1, num_caps)
|
||||
Iris::Receiver receiver = mem.create_receiver ()
|
||||
receiver.set_owner (thread.copy ())
|
||||
Iris::Cap call = receiver.create_call_capability ()
|
||||
caps.set (__caps_num, caps.copy ())
|
||||
caps.set (__receiver_num, receiver.copy ())
|
||||
caps.set (__thread_num, thread.copy ())
|
||||
caps.set (__memory_num, mem.copy ())
|
||||
caps.set (__call_num, call.copy ())
|
||||
caps.set (__parent_num, parent.copy ())
|
||||
Iris::free_cap (receiver)
|
||||
Iris::free_cap (thread)
|
||||
Iris::free_cap (mem)
|
||||
Iris::free_cap (call)
|
||||
return caps
|
||||
|
||||
Iris::Num start ():
|
||||
kdebug ("elfrun started.\n")
|
||||
init_alloc ()
|
||||
Iris::Elfrun dev = Iris::my_receiver.create_capability (0)
|
||||
Iris::my_parent.provide_capability <Iris::Elfrun> (dev.copy ())
|
||||
Iris::free_cap (dev)
|
||||
bss_mapping = (unsigned *)alloc_space (1)
|
||||
bss_page = Iris::my_memory.create_page ()
|
||||
Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Elfrun::RUN_BLOCK:
|
||||
unsigned num_slots = Iris::recv.data[1].l
|
||||
unsigned num_caps = Iris::recv.data[1].h
|
||||
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
|
||||
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
|
||||
Iris::Block data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
|
||||
map_string (data)
|
||||
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
free_cap (ret)
|
||||
free_cap (parent_memory)
|
||||
free_cap (parent)
|
||||
free_cap (data)
|
||||
break
|
||||
case Iris::Elfrun::RUN_CAPS:
|
||||
unsigned num_slots = Iris::recv.data[1].l
|
||||
unsigned num_caps = Iris::recv.data[1].h
|
||||
unsigned p = Iris::recv.data[0].h
|
||||
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
|
||||
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
|
||||
Iris::Caps data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
|
||||
map_caps (data, p)
|
||||
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
free_cap (ret)
|
||||
free_cap (parent_memory)
|
||||
free_cap (parent)
|
||||
free_cap (data)
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "invalid operation for elfrun")
|
||||
reply.invoke (~0)
|
||||
break
|
||||
Iris::free_cap (arg)
|
||||
Iris::free_cap (reply)
|
||||
688
userspace/glue/fat.ccp
Normal file
688
userspace/glue/fat.ccp
Normal file
@@ -0,0 +1,688 @@
|
||||
#pypp 0
|
||||
#include <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
#define SECTOR_BITS 9
|
||||
#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
|
||||
#define ROOT_CLUSTER 0x7fffffff
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
_free = ret + (pages << PAGE_BITS)
|
||||
return (char *)ret
|
||||
|
||||
void *operator new[] (unsigned size):
|
||||
//kdebug ("new ")
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
void *operator new (unsigned size):
|
||||
return new char[size]
|
||||
|
||||
static Iris::WBlock dev
|
||||
static Iris::Num device_size
|
||||
static Iris::Page page
|
||||
static char *data
|
||||
static Iris::Num current_block
|
||||
static void read_block (Iris::Num idx, Iris::Page p = page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
|
||||
if p.code == page.code:
|
||||
if idx.value () == current_block.value () && offset == 0 && size == 1 << SECTOR_BITS:
|
||||
return
|
||||
current_block = idx
|
||||
//kdebug ("fat getting block: ")
|
||||
//kdebug_num (idx.h)
|
||||
//kdebug (":")
|
||||
//kdebug_num (idx.l)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("@")
|
||||
//kdebug_num (offset)
|
||||
//kdebug ("\n")
|
||||
dev.get_block (idx, size, offset, p)
|
||||
|
||||
struct Fat:
|
||||
char oem[8]
|
||||
unsigned sector_size_bits
|
||||
unsigned sectors_per_cluster_bits
|
||||
unsigned reserved_sectors
|
||||
unsigned num_fats
|
||||
unsigned root_entries
|
||||
unsigned sectors
|
||||
unsigned media
|
||||
unsigned sectors_per_fat
|
||||
unsigned sectors_per_track
|
||||
unsigned heads
|
||||
unsigned hidden_sectors
|
||||
unsigned active_fat
|
||||
bool write_all_fats
|
||||
unsigned fs_version
|
||||
unsigned root_cluster
|
||||
unsigned fsinfo_sector
|
||||
unsigned boot_backup_sector
|
||||
unsigned drive
|
||||
unsigned current_head
|
||||
unsigned volume_id
|
||||
char label[0xb]
|
||||
|
||||
unsigned bits
|
||||
unsigned clusters
|
||||
unsigned cluster_size_bits
|
||||
unsigned root_sectors
|
||||
unsigned header_sectors
|
||||
unsigned bad_clusters
|
||||
|
||||
unsigned free_clusters
|
||||
unsigned last_alloced
|
||||
|
||||
unsigned *fat
|
||||
unsigned first_free_cluster, first_bad_cluster
|
||||
|
||||
void print_num (char const *pre, unsigned data):
|
||||
kdebug ("\t")
|
||||
kdebug (pre)
|
||||
unsigned bytes = 1
|
||||
while bytes < 8 && data >> (bytes * 4):
|
||||
++bytes
|
||||
kdebug_num (data, bytes)
|
||||
kdebug ("\n")
|
||||
|
||||
void print_br ():
|
||||
kdebug ("\tOEM: '")
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
kdebug_char (oem[i])
|
||||
kdebug ("'\n")
|
||||
print_num ("bytes per sector: ", 1 << sector_size_bits)
|
||||
print_num ("sectors per cluster: ", 1 << sectors_per_cluster_bits)
|
||||
print_num ("reserved sectors: ", reserved_sectors)
|
||||
print_num ("number of fats: ", num_fats)
|
||||
print_num ("entries in root directory: ", root_entries)
|
||||
print_num ("sectors: ", sectors)
|
||||
print_num ("media descriptor: ", media)
|
||||
print_num ("sectors per fat: ", sectors_per_fat)
|
||||
print_num ("sectors per track: ", sectors_per_track)
|
||||
print_num ("heads: ", heads)
|
||||
print_num ("hidden sectors: ", hidden_sectors)
|
||||
print_num ("active_fat: ", active_fat)
|
||||
kdebug ("\twrite all: ")
|
||||
kdebug (write_all_fats ? "yes\n" : "no\n")
|
||||
print_num ("fs version: ", fs_version)
|
||||
print_num ("root cluster: ", root_cluster)
|
||||
print_num ("fsinfo sector: ", fsinfo_sector)
|
||||
print_num ("boot sector backup sector: ", boot_backup_sector)
|
||||
print_num ("drive: ", drive)
|
||||
print_num ("current head: ", current_head)
|
||||
print_num ("volume id: ", volume_id)
|
||||
kdebug ("\tlabel: '")
|
||||
for unsigned i = 0; i < 0xb; ++i:
|
||||
kdebug_char (label[i])
|
||||
kdebug ("'\n")
|
||||
print_num ("bits: ", bits)
|
||||
print_num ("clusters: ", clusters)
|
||||
print_num ("header sectors: ", header_sectors)
|
||||
|
||||
unsigned read_num (char *data, unsigned bytes):
|
||||
unsigned ret = 0
|
||||
for unsigned i = 0; i < bytes; ++i:
|
||||
ret |= (data[i] & 0xff) << (i * 8)
|
||||
return ret
|
||||
|
||||
void map_fat_cluster (unsigned c, unsigned offset = 0):
|
||||
//unsigned b = current_block.l
|
||||
read_block ((reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits)
|
||||
//if b != current_block.l:
|
||||
//for unsigned i = 0; i < 0x20; ++i:
|
||||
//kdebug (" ")
|
||||
//kdebug_num (data[i], 2)
|
||||
//kdebug ("\n")
|
||||
|
||||
unsigned make_bits (unsigned orig):
|
||||
unsigned ret
|
||||
for ret = 0; ret < 32; ++ret:
|
||||
if orig == 1 << ret:
|
||||
return ret
|
||||
//Iris::panic (orig, "non-power of 2")
|
||||
kdebug ("not a power of two, using 16\n")
|
||||
return 16
|
||||
|
||||
void reset ():
|
||||
read_block (0)
|
||||
if data[0x1fe] != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
|
||||
kdebug ("invalid boot record signature in fat device\n")
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
oem[i] = data[3 + i]
|
||||
sector_size_bits = make_bits (read_num (data + 0xb, 2))
|
||||
sectors_per_cluster_bits = make_bits (read_num (data + 0xd, 1))
|
||||
cluster_size_bits = sector_size_bits + sectors_per_cluster_bits
|
||||
reserved_sectors = read_num (data + 0xe, 2)
|
||||
num_fats = read_num (data + 0x10, 1)
|
||||
root_entries = read_num (data + 0x11, 2)
|
||||
sectors = read_num (data + 0x13, 2)
|
||||
media = read_num (data + 0x15, 1)
|
||||
sectors_per_fat = read_num (data + 0x16, 2)
|
||||
sectors_per_track = read_num (data + 0x18, 2)
|
||||
heads = read_num (data + 0x1a, 2)
|
||||
hidden_sectors = read_num (data + 0x1c, 4)
|
||||
if !sectors:
|
||||
sectors = read_num (data + 0x20, 4)
|
||||
if Iris::Num (sectors).value () << sector_size_bits > device_size.value ():
|
||||
sectors = device_size.value () >> sector_size_bits
|
||||
kdebug ("warning: limiting sectors because of limited device size\n")
|
||||
|
||||
root_sectors = (root_entries * 32 + (1 << sector_size_bits) - 1) >> sector_size_bits
|
||||
header_sectors = reserved_sectors + sectors_per_fat * num_fats + root_sectors
|
||||
clusters = (sectors - header_sectors) >> sectors_per_cluster_bits
|
||||
unsigned skip
|
||||
if clusters >= 65525:
|
||||
bits = 32
|
||||
sectors_per_fat = read_num (data + 0x24, 4)
|
||||
active_fat = read_num (data + 0x28, 2)
|
||||
write_all_fats = active_fat & 0x80
|
||||
active_fat &= 0xf
|
||||
fs_version = read_num (data + 0x2a, 2)
|
||||
root_cluster = read_num (data + 0x2c, 4)
|
||||
fsinfo_sector = read_num (data + 0x30, 2)
|
||||
boot_backup_sector = read_num (data + 0x32, 2)
|
||||
skip = 0x40 - 0x24
|
||||
else:
|
||||
if clusters < 4085:
|
||||
bits = 12
|
||||
else:
|
||||
bits = 16
|
||||
skip = 0
|
||||
active_fat = 0
|
||||
write_all_fats = true
|
||||
fs_version = 0
|
||||
root_cluster = 0
|
||||
fsinfo_sector = 0
|
||||
boot_backup_sector = 0
|
||||
unsigned fat_entries_per_sector = (8 << sector_size_bits) / bits
|
||||
unsigned fat_entries = sectors_per_fat * fat_entries_per_sector
|
||||
if clusters + 2 > fat_entries:
|
||||
clusters = fat_entries - 2
|
||||
kdebug ("warning: limiting clusters because of limited sector count\n")
|
||||
drive = read_num (data + skip + 0x24, 1)
|
||||
current_head = read_num (data + skip + 0x25, 1)
|
||||
if data[skip + 0x26] == 0x29:
|
||||
volume_id = read_num (data + skip + 0x27, 4)
|
||||
for unsigned i = 0; i < 0xb; ++i:
|
||||
label[i] = data[skip + 0x2b + i]
|
||||
char *id = data + skip + 0x36
|
||||
if id[0] != 'F' || id[1] != 'A' || id[2] != 'T' || id[5] != ' ' || id[6] != ' ' || id[7] != ' ':
|
||||
kdebug ("warning: file system type field was not 'FATxx '\n")
|
||||
else:
|
||||
switch bits:
|
||||
case 12:
|
||||
if id[3] != '1' || id[4] != '2':
|
||||
kdebug ("warning: id for fat12 is not FAT12\n")
|
||||
break
|
||||
case 16:
|
||||
if id[3] != '1' || id[4] != '6':
|
||||
kdebug ("warning: id for fat16 is not FAT16\n")
|
||||
break
|
||||
case 32:
|
||||
if id[3] != '3' || id[4] != '2':
|
||||
kdebug ("warning: id for fat32 wat not FAT32")
|
||||
break
|
||||
else:
|
||||
volume_id = 0
|
||||
for unsigned i = 0; i < 0xb; ++i:
|
||||
label[i] = 0
|
||||
if fsinfo_sector:
|
||||
read_block (fsinfo_sector << sector_size_bits)
|
||||
if (data[0] & 0xff) != 0x52 || (data[1] & 0xff) != 0x52 || (data[2] & 0xff) != 0x6a || (data[3] & 0xff) != 0x41 || (data[0x1e4] & 0xff) != 0x72 || (data[0x1e5] & 0xff) != 0x72 || (data[0x1e6] & 0xff) != 0x4a || (data[0x1e7] & 0xff) != 0x61 || (data[0x1fe] & 0xff) != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
|
||||
kdebug ("invalid signature in fsinfo structure\n")
|
||||
free_clusters = read_num (data + 0x1e8, 4)
|
||||
last_alloced = read_num (data + 0x1ec, 4)
|
||||
else:
|
||||
free_clusters = ~0
|
||||
last_alloced = ~0
|
||||
|
||||
// Now read the FAT.
|
||||
bad_clusters = 0
|
||||
fat = new unsigned[clusters]
|
||||
unsigned counted_free_clusters = 0
|
||||
first_free_cluster = ~0
|
||||
for unsigned c = 0; c < clusters; ++c:
|
||||
// reduced cluster.
|
||||
unsigned rc = c & (1 << sector_size_bits) - 1
|
||||
// The next line does nothing most of the time.
|
||||
map_fat_cluster (c)
|
||||
switch bits:
|
||||
case 12:
|
||||
fat[c] = data[(rc + 2) * 2] & 0xff
|
||||
// There may be a sector boundary in the middle of the entry, so optionally reread.
|
||||
map_fat_cluster (c, 1)
|
||||
fat[c] |= (data[(rc + 2) * 2 + 1] & 0xff) << 8
|
||||
if c & 1:
|
||||
fat[c] >>= 4
|
||||
else:
|
||||
fat[c] &= 0xfff
|
||||
break
|
||||
case 16:
|
||||
fat[c] = read_num (data + (rc + 2) * 2, 2)
|
||||
break
|
||||
case 32:
|
||||
fat[c] = read_num (data + (rc + 2) * 4, 4)
|
||||
break
|
||||
// Correct for the crazy +2 offset, and keep a list of bad and free clusters.
|
||||
if fat[c] == 0:
|
||||
// Free cluster.
|
||||
fat[c] = first_free_cluster
|
||||
first_free_cluster = c
|
||||
++counted_free_clusters
|
||||
else if fat[c] == 1:
|
||||
// Invalid value.
|
||||
Iris::panic (0, "entry is '1' in fat.")
|
||||
else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff:
|
||||
// Last cluster in chain.
|
||||
fat[c] = ~0
|
||||
//kdebug ("last cluster: ")
|
||||
//kdebug_num (c)
|
||||
//kdebug ("\n")
|
||||
else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7:
|
||||
// Bad cluster.
|
||||
fat[c] = first_bad_cluster
|
||||
first_bad_cluster = c
|
||||
++bad_clusters
|
||||
else:
|
||||
// Non-last cluster in chain.
|
||||
fat[c] -= 2
|
||||
//kdebug_num (c)
|
||||
//kdebug (" -> ")
|
||||
//kdebug_num (fat[c])
|
||||
//kdebug ("\n")
|
||||
unsigned fat_lookup (unsigned first_cluster, unsigned cluster):
|
||||
//kdebug ("looking up ")
|
||||
//kdebug_num (first_cluster)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (cluster)
|
||||
//kdebug (":")
|
||||
while cluster--:
|
||||
first_cluster = fat[first_cluster]
|
||||
//kdebug ("->")
|
||||
//kdebug_num (first_cluster)
|
||||
if first_cluster == ~0:
|
||||
//kdebug ("sector beyond end of file requested\n")
|
||||
return ~0
|
||||
//kdebug ("\n")
|
||||
return first_cluster
|
||||
struct File:
|
||||
Fat *fat
|
||||
unsigned size
|
||||
unsigned first_cluster
|
||||
char name[11]
|
||||
bool archive, readonly, system, hidden, directory, volume
|
||||
unsigned create_second, create_minute_hour, create_date, access_date, time, date
|
||||
unsigned checksum
|
||||
void load_cluster (unsigned idx, unsigned offset_in_cluster, Iris::Page p = page, unsigned offset = 0):
|
||||
unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits)
|
||||
//kdebug ("loading cluster ")
|
||||
//kdebug_num (idx)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (offset_in_cluster)
|
||||
//kdebug ("@")
|
||||
//kdebug_num (cluster)
|
||||
//kdebug (" from file\n")
|
||||
if cluster == ~0:
|
||||
kdebug ("invalid cluster requested from file\n")
|
||||
return
|
||||
read_block (((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits) + offset_in_cluster, p, fat->cluster_size_bits < PAGE_BITS ? 1 << fat->cluster_size_bits : PAGE_SIZE, offset)
|
||||
char *load_dir_entry (unsigned dir, unsigned idx):
|
||||
unsigned sector = idx >> (sector_size_bits - 5)
|
||||
unsigned num = (idx << 5) & ~BLOCK_MASK
|
||||
Iris::Num hwsector
|
||||
if dir == ROOT_CLUSTER:
|
||||
if sector < root_sectors:
|
||||
hwsector = header_sectors - root_sectors + sector
|
||||
else:
|
||||
return NULL
|
||||
else:
|
||||
unsigned entry = fat_lookup (dir, sector)
|
||||
if entry == ~0:
|
||||
return NULL
|
||||
hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits)
|
||||
read_block (hwsector.value () << sector_size_bits)
|
||||
return &data[num]
|
||||
char *find_idx (unsigned dir, unsigned *idx, unsigned *count = NULL):
|
||||
unsigned todo = *idx + 1
|
||||
char *e
|
||||
if count:
|
||||
*count = 0
|
||||
for *idx = 0; todo; ++*idx:
|
||||
e = load_dir_entry (dir, *idx)
|
||||
if !e:
|
||||
return NULL
|
||||
if (e[0xb] & 0xff) == 0xf:
|
||||
// This is part of a long filename.
|
||||
continue
|
||||
if (e[0] & 0xff) == 0xe5:
|
||||
// This is a deleted file.
|
||||
continue
|
||||
if !e[0]:
|
||||
// This is a free entry.
|
||||
continue
|
||||
if count:
|
||||
++*count
|
||||
--todo
|
||||
--*idx
|
||||
return e
|
||||
unsigned get_dir_size (unsigned dir):
|
||||
unsigned num = 0 - 2
|
||||
unsigned ret
|
||||
find_idx (dir, &num, &ret)
|
||||
return ret
|
||||
bool get_dir_entry (unsigned dir, unsigned idx, File *f):
|
||||
char *e = load_dir_entry (dir, idx)
|
||||
if !e:
|
||||
kdebug ("unable to load dir entry\n")
|
||||
return false
|
||||
f->fat = this
|
||||
//kdebug ("loading dir entry for ")
|
||||
for unsigned i = 0; i < 11; ++i:
|
||||
f->name[i] = e[i]
|
||||
//kdebug_char (f->name[i])
|
||||
//kdebug ("\n")
|
||||
f->readonly = e[0xb] & 0x1
|
||||
f->system = e[0xb] & 0x2
|
||||
f->hidden = e[0xb] & 0x4
|
||||
f->volume = e[0xb] & 0x8
|
||||
f->directory = e[0xb] & 0x10
|
||||
f->archive = e[0xb] & 0x20
|
||||
f->create_second = read_num (e + 0xd, 1)
|
||||
f->create_minute_hour = read_num (e + 0xe, 2)
|
||||
f->create_date = read_num (e + 0x10, 2)
|
||||
f->access_date = read_num (e + 0x12, 2)
|
||||
f->time = read_num (e + 0x16, 1)
|
||||
f->date = read_num (e + 0x18, 1)
|
||||
f->size = read_num (e + 0x1c, 4)
|
||||
f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2
|
||||
f->checksum = 0
|
||||
for unsigned i = 0; i < 11; ++i:
|
||||
f->checksum = ((((f->checksum & 1) << 7) | ((f->checksum & 0xfe) >> 1)) + f->name[i]) & 0xff
|
||||
//kdebug ("loaded dir entry, first cluster = ")
|
||||
//kdebug_num (f->first_cluster)
|
||||
//kdebug ("\n")
|
||||
return true
|
||||
struct LFN:
|
||||
unsigned ordinal
|
||||
unsigned name[13]
|
||||
unsigned checksum
|
||||
bool load_lfn (unsigned dir, unsigned idx, unsigned t, unsigned checksum, LFN *lfn):
|
||||
if t >= idx:
|
||||
return false
|
||||
char *e = load_dir_entry (dir, idx - t - 1)
|
||||
if (e[0xb] & 0xff) != 0xf:
|
||||
return false
|
||||
lfn->ordinal = read_num (e + 0x00, 1)
|
||||
for unsigned i = 0; i < 5; ++i:
|
||||
lfn->name[i] = read_num (e + 0x01 + 2 * i, 2)
|
||||
lfn->checksum = read_num (e + 0xd, 1)
|
||||
for unsigned i = 0; i < 6; ++i:
|
||||
lfn->name[i + 5] = read_num (e + 0xe + 2 * i, 2)
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
lfn->name[i + 11] = read_num (e + 0x1c + 2 * i, 2)
|
||||
return true
|
||||
unsigned parse_shortname (File const &f, char *name):
|
||||
if f.name[0] == ' ':
|
||||
Iris::panic (0, "fat name starts with space")
|
||||
unsigned len = 8
|
||||
while f.name[len - 1] == ' ':
|
||||
--len
|
||||
char *ptr = name
|
||||
for unsigned i = 0; i < len; ++i:
|
||||
*ptr++ = f.name[i]
|
||||
if f.name[8] == ' ':
|
||||
return len
|
||||
*ptr++ = '.'
|
||||
len = 3
|
||||
while f.name[8 + len - 1] == ' ':
|
||||
--len
|
||||
for unsigned i = 0; i < len; ++i:
|
||||
*ptr++ = f.name[8 + i]
|
||||
return ptr - name
|
||||
unsigned get_name_size (unsigned dir, unsigned idx, File const &f):
|
||||
LFN lfn
|
||||
unsigned num = 0
|
||||
if !load_lfn (dir, idx, 0, f.checksum, &lfn):
|
||||
// Not a long filename.
|
||||
char n[12]
|
||||
return parse_shortname (f, n)
|
||||
unsigned ordinal = 0
|
||||
while true:
|
||||
if !load_lfn (dir, idx, num, f.checksum, &lfn):
|
||||
Iris::panic (0, "error parsing long filename")
|
||||
if (lfn.ordinal & 0x3f) != ++ordinal:
|
||||
Iris::panic (lfn.ordinal, "error in sequence for long filename")
|
||||
if lfn.ordinal & 0x40:
|
||||
break
|
||||
++num
|
||||
unsigned i
|
||||
for i = 0; i < 13; ++i:
|
||||
if !lfn.name[i]:
|
||||
break
|
||||
return num * 13 + i
|
||||
|
||||
// Capability encoding.
|
||||
// 0:ROOT_CLUSTER = non fat-32 root directory.
|
||||
// 0:cluster = other directory.
|
||||
// cluster:index = file index from directory at cluster.
|
||||
// cluster|0x80000000:index = filename for file with index from directory at cluster.
|
||||
|
||||
Iris::Num start ():
|
||||
init_alloc ()
|
||||
current_block = ~0
|
||||
dev = Iris::my_parent.get_capability <Iris::WBlock> ()
|
||||
if dev.get_align_bits () > SECTOR_BITS:
|
||||
kdebug ("fat device doesn't support 512 byte access")
|
||||
return 1
|
||||
device_size = dev.get_size ()
|
||||
data = (char *)0x15000; //alloc_space (1)
|
||||
page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING)
|
||||
Iris::my_memory.map (page, (unsigned)data)
|
||||
|
||||
Fat fat
|
||||
|
||||
fat.reset ()
|
||||
fat.print_br ()
|
||||
|
||||
Iris::Cap root
|
||||
if fat.root_cluster:
|
||||
root = Iris::my_receiver.create_capability (Iris::Num (fat.root_cluster, 0))
|
||||
else:
|
||||
root = Iris::my_receiver.create_capability (Iris::Num (ROOT_CLUSTER, 0))
|
||||
|
||||
Iris::my_parent.provide_capability <Iris::Directory> (root.copy ())
|
||||
Iris::free_cap (root)
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
unsigned dir = Iris::recv.protected_data.h
|
||||
if dir & 0x80000000:
|
||||
dir &= ~0x80000000
|
||||
// File name.
|
||||
unsigned idx = Iris::recv.protected_data.l
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
unsigned num = Iris::recv.data[1].l
|
||||
unsigned size = Iris::recv.data[0].h >> 16
|
||||
unsigned cmd = Iris::recv.data[0].l
|
||||
Fat::File f
|
||||
if !fat.find_idx (dir, &idx):
|
||||
Iris::panic (Iris::recv.protected_data.l, "invalid index")
|
||||
if !fat.get_dir_entry (dir, idx, &f):
|
||||
Iris::panic (Iris::recv.protected_data.l, "invalid dir entry requested for filename")
|
||||
switch cmd:
|
||||
case Iris::String::GET_SIZE:
|
||||
//kdebug ("filename size requested\n")
|
||||
reply.invoke (fat.get_name_size (dir, idx, f))
|
||||
break
|
||||
case Iris::String::GET_CHARS:
|
||||
//kdebug ("filename chars requested\n")
|
||||
//kdebug ("flags: ")
|
||||
//kdebug_char (f.readonly ? 'R' : 'r')
|
||||
//kdebug_char (f.system ? 'S' : 's')
|
||||
//kdebug_char (f.hidden ? 'H' : 'h')
|
||||
//kdebug_char (f.volume ? 'V' : 'v')
|
||||
//kdebug_char (f.directory ? 'D' : 'd')
|
||||
//kdebug_char (f.archive ? 'A' : 'a')
|
||||
//kdebug_char ('\n')
|
||||
|
||||
/**/union { unsigned u[4]; char c[16]; } u
|
||||
for unsigned k = 0; k < 4; ++k:
|
||||
u.u[k] = 0
|
||||
Fat::LFN lfn
|
||||
if !fat.load_lfn (dir, idx, 0, f.checksum, &lfn):
|
||||
// Not a long filename.
|
||||
char n[12]
|
||||
unsigned len = fat.parse_shortname (f, n)
|
||||
//kdebug ("short filename: ")
|
||||
for unsigned k = 0; k + num < len; ++k:
|
||||
u.c[k] = n[k + num]
|
||||
//kdebug_char (u.c[k])
|
||||
//kdebug ("\n")
|
||||
else:
|
||||
// Very inefficient, but it works: reload everything for every character.
|
||||
//kdebug ("filename: ")
|
||||
for unsigned c = 0; c < 16; ++c:
|
||||
if !fat.load_lfn (dir, idx, (num + c) / 13, f.checksum, &lfn):
|
||||
// Filename isn't this long: keep the rest at 0.
|
||||
break
|
||||
u.c[c] = lfn.name[(num + c) % 13]
|
||||
if u.c[c] == 0:
|
||||
break
|
||||
//kdebug_char (u.c[c])
|
||||
//kdebug ("\n")
|
||||
reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3]))
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename")
|
||||
Iris::free_cap (reply)
|
||||
else if dir:
|
||||
// If it *has* a directory, it *is* a file.
|
||||
unsigned idx = Iris::recv.protected_data.l
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Num num = Iris::recv.data[1]
|
||||
unsigned size = Iris::recv.data[0].h >> 16
|
||||
unsigned offset = Iris::recv.data[0].h & 0xffff
|
||||
unsigned cmd = Iris::recv.data[0].l
|
||||
Fat::File f
|
||||
fat.get_dir_entry (dir, idx, &f)
|
||||
switch cmd:
|
||||
case Iris::Block::GET_SIZE:
|
||||
//kdebug ("file size requested\n")
|
||||
reply.invoke (f.size)
|
||||
break
|
||||
case Iris::Block::GET_ALIGN_BITS:
|
||||
//kdebug ("file align requested\n")
|
||||
reply.invoke (fat.cluster_size_bits <= PAGE_BITS ? fat.cluster_size_bits : PAGE_BITS)
|
||||
break
|
||||
case Iris::Block::GET_BLOCK:
|
||||
//kdebug ("file block requested\n")
|
||||
unsigned mask = (1 << fat.cluster_size_bits) - 1
|
||||
//kdebug ("mask = ")
|
||||
//kdebug_num (mask)
|
||||
//kdebug ("\n")
|
||||
if offset > PAGE_SIZE:
|
||||
//kdebug ("invalid offset requested\n")
|
||||
break
|
||||
if size + offset > PAGE_SIZE:
|
||||
Iris::panic (size, "invalid size requested")
|
||||
size = PAGE_SIZE - offset
|
||||
for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits:
|
||||
f.load_cluster ((num.l & ~mask) + i, num.l & mask, arg, i + offset)
|
||||
reply.invoke ()
|
||||
break
|
||||
case Iris::WBlock::TRUNCATE:
|
||||
case Iris::WBlock::SET_BLOCK:
|
||||
Iris::panic (Iris::recv.data[0].l, "writing to files not supported yet")
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid request for fat file")
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
else:
|
||||
// Directory.
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Directory::GET_SIZE:
|
||||
//kdebug ("dir size requested\n")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
reply.invoke (fat.get_dir_size (Iris::recv.protected_data.l))
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::Directory::GET_NAME:
|
||||
//kdebug ("dir name requested\n")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000))
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (ret)
|
||||
break
|
||||
case Iris::Directory::GET_FILE_RO:
|
||||
//kdebug ("dir file requested\n")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
dir = Iris::recv.protected_data.l
|
||||
unsigned idx = Iris::recv.data[1].l
|
||||
unsigned oldidx = idx
|
||||
if !fat.find_idx (dir, &idx):
|
||||
kdebug_num (oldidx)
|
||||
kdebug ("\n")
|
||||
Iris::panic (1, "file not found")
|
||||
Fat::File f
|
||||
fat.get_dir_entry (dir, idx, &f)
|
||||
Iris::Cap ret
|
||||
if f.directory:
|
||||
//kdebug ("dir provided: ")
|
||||
//kdebug_num (f.first_cluster)
|
||||
//kdebug ("\n")
|
||||
ret = Iris::my_receiver.create_capability (Iris::Num (f.first_cluster, 0))
|
||||
else:
|
||||
ret = Iris::my_receiver.create_capability (Iris::Num (idx, dir))
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (ret)
|
||||
break
|
||||
case Iris::Directory::GET_FILE_INFO:
|
||||
//kdebug ("dir file info requested\n")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
dir = Iris::recv.protected_data.l
|
||||
unsigned idx = Iris::recv.data[1].l
|
||||
unsigned oldidx = idx
|
||||
if !fat.find_idx (dir, &idx):
|
||||
kdebug_num (oldidx)
|
||||
kdebug ("\n")
|
||||
Iris::panic (2, "file not found")
|
||||
unsigned type = Iris::recv.data[0].h
|
||||
Fat::File f
|
||||
fat.get_dir_entry (dir, idx, &f)
|
||||
reply.invoke (f.directory ? 1 : 0)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::Directory::LOCK_RO:
|
||||
case Iris::Directory::UNLOCK_RO:
|
||||
//kdebug ("dir lock or unlock requested\n")
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
//kdebug ("invalid dir operation requested\n")
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
179
userspace/glue/font.ccp
Normal file
179
userspace/glue/font.ccp
Normal file
@@ -0,0 +1,179 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/font.ccp: Font manager.
|
||||
// Copyright 2012 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 screenw 320
|
||||
#define screenh 240
|
||||
|
||||
struct Glyph:
|
||||
unsigned width, height, baseline
|
||||
unsigned data[1]
|
||||
|
||||
static Iris::Display display
|
||||
static Iris::Caps caps, display_caps
|
||||
static unsigned slot, num_glyphs
|
||||
static unsigned long pages, base
|
||||
static Glyph **glyphs
|
||||
static char *fb
|
||||
static unsigned x, y
|
||||
|
||||
static unsigned read_int (unsigned addr):
|
||||
return *reinterpret_cast <unsigned *> (addr)
|
||||
|
||||
static void load_font (Iris::Block font):
|
||||
unsigned long long size = font.get_size ().value ()
|
||||
pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
caps = Iris::my_memory.create_caps (pages)
|
||||
slot = caps.use ()
|
||||
for unsigned i = 0; i < size; i += PAGE_SIZE:
|
||||
Iris::Page page = Iris::Cap (slot, i >> PAGE_BITS)
|
||||
Iris::set_recv_arg (page)
|
||||
font.get_block (i)
|
||||
Iris::my_memory.map (page, base + i)
|
||||
num_glyphs = read_int (base)
|
||||
glyphs = reinterpret_cast <Glyph **> (base + sizeof (int))
|
||||
for unsigned i = 0; i < num_glyphs; ++i:
|
||||
glyphs[i] = reinterpret_cast <Glyph *> (base + sizeof (int) + read_int (base + sizeof (int) + i * sizeof (int)))
|
||||
|
||||
static void free_font ():
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
Iris::my_memory.destroy (Iris::Cap (slot, i))
|
||||
Iris::my_memory.destroy (caps)
|
||||
Iris::free_slot (slot)
|
||||
|
||||
static unsigned draw_char (char c, unsigned &w, unsigned &h):
|
||||
if c >= num_glyphs:
|
||||
c = num_glyphs - 1
|
||||
Glyph *g = glyphs[c]
|
||||
w = g->width
|
||||
h = g->height
|
||||
for unsigned ty = 0; ty < h; ++ty:
|
||||
unsigned py = ty + y - g->baseline
|
||||
if py < 0 || py >= screenh:
|
||||
continue
|
||||
for unsigned tx = 0; tx < g->width; ++tx:
|
||||
unsigned px = tx + x
|
||||
if px < 0 || px >= screenw:
|
||||
continue
|
||||
unsigned p = g->data[ty * g->width + tx]
|
||||
unsigned red = unsigned (p) & 0xff
|
||||
unsigned green = unsigned (p >> 8) & 0xff
|
||||
unsigned blue = unsigned (p >> 16) & 0xff
|
||||
unsigned alpha = (unsigned (p >> 24) & 0xff) + 1
|
||||
if alpha == 0x100:
|
||||
fb[(py * 320 + px) * 4 + 2] = red
|
||||
fb[(py * 320 + px) * 4 + 1] = green
|
||||
fb[(py * 320 + px) * 4 + 0] = blue
|
||||
else:
|
||||
unsigned unalpha = 256 - alpha
|
||||
fb[(py * 320 + px) * 4 + 2] = (fb[(py * 320 + px) * 4 + 2] * unalpha + red * alpha) >> 8
|
||||
fb[(py * 320 + px) * 4 + 1] = (fb[(py * 320 + px) * 4 + 1] * unalpha + green * alpha) >> 8
|
||||
fb[(py * 320 + px) * 4 + 0] = (fb[(py * 320 + px) * 4 + 0] * unalpha + blue * alpha) >> 8
|
||||
return g->baseline
|
||||
|
||||
static void get_size (char c, unsigned &w, unsigned &h, unsigned &b):
|
||||
if c >= num_glyphs:
|
||||
c = num_glyphs - 1
|
||||
Glyph *g = glyphs[c]
|
||||
w = g->width
|
||||
h = g->height
|
||||
b = g->baseline
|
||||
|
||||
Iris::Num start ():
|
||||
x = 0
|
||||
y = 8
|
||||
// Random address which is large enough to store a huge file.
|
||||
base = 0x40000000
|
||||
fb = reinterpret_cast <char *> (0x20000000)
|
||||
Iris::Font self = Iris::my_receiver.create_capability (0)
|
||||
Iris::my_parent.provide_capability <Iris::Font> (self.copy ())
|
||||
Iris::free_cap (self)
|
||||
//display = Iris::my_parent.get_capability <Iris::Display> ()
|
||||
Iris::Block font = Iris::my_parent.get_capability <Iris::Block> ()
|
||||
load_font (font)
|
||||
Iris::free_cap (font)
|
||||
Iris::my_parent.init_done ()
|
||||
//display_caps = display.map_fb (reinterpret_cast <unsigned> (fb))
|
||||
bool have_display = false
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Font::SET_DISPLAY:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
if have_display:
|
||||
Iris::free_cap (display)
|
||||
have_display = true
|
||||
display = Iris::get_arg ()
|
||||
display_caps = display.map_fb (reinterpret_cast <unsigned> (fb))
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::Font::LOAD_FONT:
|
||||
free_font ()
|
||||
font = Iris::get_arg ()
|
||||
load_font (font)
|
||||
Iris::free_cap (font)
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Font::SETUP:
|
||||
// TODO: interface needs to be defined.
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Font::AT:
|
||||
if Iris::recv.data[0].h & 1:
|
||||
x += Iris::recv.data[1].l
|
||||
if x > screenw:
|
||||
x = 0
|
||||
y += 16
|
||||
if y + 16 > screenh + 8:
|
||||
y = 8
|
||||
else:
|
||||
x = Iris::recv.data[1].l
|
||||
if Iris::recv.data[0].h & 2:
|
||||
y += Iris::recv.data[1].h
|
||||
if y + 16 > screenh + 8:
|
||||
y = 8
|
||||
else:
|
||||
y = Iris::recv.data[1].h
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Font::WRITE:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
unsigned w, h
|
||||
unsigned b = draw_char (Iris::recv.data[1].l, w, h)
|
||||
x += w
|
||||
if x + w > screenw:
|
||||
x = 0
|
||||
y += h
|
||||
if y + h > screenh + b:
|
||||
y = b
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::Font::GET_POS:
|
||||
Iris::recv.reply.invoke (x, y)
|
||||
break
|
||||
case Iris::Font::GET_SIZE:
|
||||
unsigned w, h, b
|
||||
get_size (Iris::recv.data[1].l, w, h, b)
|
||||
Iris::recv.reply.invoke (Iris::Num (b, h), w)
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "invalid operation type for lcd")
|
||||
break
|
||||
268
userspace/glue/gui.ccp
Normal file
268
userspace/glue/gui.ccp
Normal file
@@ -0,0 +1,268 @@
|
||||
#pypp 0
|
||||
#include <iris.hh>
|
||||
#include <devices.hh>
|
||||
#include <keys.hh>
|
||||
|
||||
// Interface: two way, started by ui.
|
||||
|
||||
// From ui to application.
|
||||
// ~0: request reset.
|
||||
// ~1: set reply cap; send current state.
|
||||
// inum: event (with optional value) for input number num.
|
||||
|
||||
// From application to ui.
|
||||
// onum: event (with optional value) for output number num.
|
||||
|
||||
// For now, the code is hardwired to the alarm clock interface.
|
||||
enum outs:
|
||||
CURRENT_TIME
|
||||
ALARM
|
||||
|
||||
enum ins:
|
||||
TOTAL_TIME
|
||||
START
|
||||
|
||||
static Iris::Display display
|
||||
static Iris::Buzzer buzzer
|
||||
static unsigned *framebuffer
|
||||
static unsigned alarming
|
||||
|
||||
enum PD:
|
||||
UI
|
||||
KBD
|
||||
|
||||
static char const *chardef =
|
||||
".###.."
|
||||
"#...#."
|
||||
"#...#."
|
||||
"#...#."
|
||||
"#...#."
|
||||
"#...#."
|
||||
".###.."
|
||||
"......"
|
||||
|
||||
"..#..."
|
||||
"..#..."
|
||||
"..#..."
|
||||
"..#..."
|
||||
"..#..."
|
||||
"..#..."
|
||||
"..#..."
|
||||
"......"
|
||||
|
||||
".###.."
|
||||
"#...#."
|
||||
"....#."
|
||||
"...#.."
|
||||
"..#..."
|
||||
".#...."
|
||||
"#####."
|
||||
"......"
|
||||
|
||||
".###.."
|
||||
"#...#."
|
||||
"....#."
|
||||
"..##.."
|
||||
"....#."
|
||||
"#...#."
|
||||
".###.."
|
||||
"......"
|
||||
|
||||
"#...#."
|
||||
"#...#."
|
||||
"#...#."
|
||||
"#####."
|
||||
"....#."
|
||||
"....#."
|
||||
"....#."
|
||||
"......"
|
||||
|
||||
"#####."
|
||||
"#....."
|
||||
"####.."
|
||||
"....#."
|
||||
"....#."
|
||||
"....#."
|
||||
"####.."
|
||||
"......"
|
||||
|
||||
"....#."
|
||||
"...#.."
|
||||
"..#..."
|
||||
".###.."
|
||||
"#...#."
|
||||
"#...#."
|
||||
".###.."
|
||||
"......"
|
||||
|
||||
"#####."
|
||||
"....#."
|
||||
"...#.."
|
||||
"..#..."
|
||||
".#...."
|
||||
"#....."
|
||||
"#....."
|
||||
"......"
|
||||
|
||||
".###.."
|
||||
"#...#."
|
||||
"#...#."
|
||||
".###.."
|
||||
"#...#."
|
||||
"#...#."
|
||||
".###.."
|
||||
"......"
|
||||
|
||||
".###.."
|
||||
"#...#."
|
||||
"#...#."
|
||||
".###.."
|
||||
"..#..."
|
||||
".#...."
|
||||
"#....."
|
||||
"......"
|
||||
|
||||
"......"
|
||||
"......"
|
||||
"..#..."
|
||||
"......"
|
||||
"......"
|
||||
"..#..."
|
||||
"......"
|
||||
"......"
|
||||
|
||||
static void draw_pixel (unsigned x, unsigned y, bool set):
|
||||
for unsigned ty = 0; ty < 8; ++ty:
|
||||
for unsigned tx = 0; tx < 8; ++tx:
|
||||
framebuffer[320 * (y + ty) + x + tx] = (set ? 0xffffff : 0x000000)
|
||||
|
||||
static void draw_num (bool upper, unsigned x0, unsigned d):
|
||||
for unsigned y = 0; y < 8; ++y:
|
||||
for unsigned x = 0; x < 6; ++x:
|
||||
draw_pixel (x * 10 + 10 + x0 * 60, y * 10 + (upper ? 30 : 50 + 80), chardef[(d * 8 + y) * 6 + x] == '#')
|
||||
|
||||
static void draw_time (bool upper, unsigned time):
|
||||
unsigned min = time / 60
|
||||
time %= 60
|
||||
if min >= 100:
|
||||
min = 99
|
||||
time = 99
|
||||
draw_num (upper, 0, min / 10)
|
||||
draw_num (upper, 1, min % 10)
|
||||
draw_num (upper, 3, time / 10)
|
||||
draw_num (upper, 4, time % 10)
|
||||
|
||||
static void do_alarm ():
|
||||
static unsigned tune[] = { 4, 6, 6, 5, 7, 7 }
|
||||
if ++alarming > sizeof (tune) / sizeof (*tune):
|
||||
alarming = 1
|
||||
buzzer.beep (tune[alarming - 1] * 220, 300, ~0)
|
||||
Iris::my_receiver.set_alarm (HZ / 3)
|
||||
|
||||
Iris::Num start ():
|
||||
display = Iris::my_parent.get_capability <Iris::Display> ()
|
||||
Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> ()
|
||||
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
|
||||
buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
|
||||
Iris::UI app = Iris::my_parent.get_capability <Iris::UI> ()
|
||||
|
||||
framebuffer = (unsigned *)0x15000
|
||||
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
|
||||
|
||||
unsigned screen_max = bright.get_range ()
|
||||
bright.set (0)
|
||||
bool screen_on = false
|
||||
|
||||
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
|
||||
app.get_state (cb.copy ())
|
||||
Iris::free_cap (cb)
|
||||
|
||||
cb = Iris::my_receiver.create_capability (KBD)
|
||||
keyboard.set_cb (cb.copy ())
|
||||
Iris::free_cap (cb)
|
||||
|
||||
draw_num (false, 2, 10)
|
||||
draw_num (true, 2, 10)
|
||||
|
||||
unsigned total_time = 0
|
||||
alarming = 0
|
||||
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
if alarming:
|
||||
do_alarm ()
|
||||
break
|
||||
case UI:
|
||||
switch Iris::recv.data[0].l:
|
||||
case CURRENT_TIME:
|
||||
draw_time (false, Iris::recv.data[1].l)
|
||||
break
|
||||
case ALARM:
|
||||
do_alarm ()
|
||||
break
|
||||
case TOTAL_TIME | Iris::UI::INPUT:
|
||||
total_time = Iris::recv.data[1].l
|
||||
draw_time (true, total_time)
|
||||
break
|
||||
case START | Iris::UI::INPUT:
|
||||
break
|
||||
break
|
||||
case KBD:
|
||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||
break
|
||||
alarming = 0
|
||||
switch Iris::recv.data[0].l:
|
||||
case Key::VOLUME_UP:
|
||||
total_time += 60
|
||||
draw_time (true, total_time)
|
||||
app.event (TOTAL_TIME, total_time)
|
||||
break
|
||||
case Key::VOLUME_DOWN:
|
||||
if total_time < 60:
|
||||
total_time = 0
|
||||
else:
|
||||
total_time -= 60
|
||||
draw_time (true, total_time)
|
||||
app.event (TOTAL_TIME, total_time)
|
||||
break
|
||||
case Key::UP:
|
||||
total_time += 10
|
||||
draw_time (true, total_time)
|
||||
app.event (TOTAL_TIME, total_time)
|
||||
break
|
||||
case Key::DOWN:
|
||||
if total_time < 10:
|
||||
total_time = 0
|
||||
else:
|
||||
total_time -= 10
|
||||
draw_time (true, total_time)
|
||||
app.event (TOTAL_TIME, total_time)
|
||||
break
|
||||
case Key::LEFT:
|
||||
if total_time < 1:
|
||||
total_time = 0
|
||||
else:
|
||||
total_time -= 1
|
||||
draw_time (true, total_time)
|
||||
app.event (TOTAL_TIME, total_time)
|
||||
break
|
||||
case Key::RIGHT:
|
||||
total_time += 1
|
||||
draw_time (true, total_time)
|
||||
app.event (TOTAL_TIME, total_time)
|
||||
break
|
||||
case Key::ENTER:
|
||||
app.event (START)
|
||||
break
|
||||
case Key::BACKSPACE:
|
||||
screen_on = !screen_on
|
||||
if screen_on:
|
||||
bright.set (screen_max)
|
||||
else:
|
||||
bright.set (0)
|
||||
break
|
||||
122
userspace/glue/partition.ccp
Normal file
122
userspace/glue/partition.ccp
Normal file
@@ -0,0 +1,122 @@
|
||||
#pypp 0
|
||||
#include <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
#define NUM_PARTITIONS 4
|
||||
#define SECTOR_BITS 9
|
||||
#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
|
||||
|
||||
unsigned bits
|
||||
|
||||
struct Partition:
|
||||
static Iris::Num device_size
|
||||
unsigned lba_start, lba_size
|
||||
unsigned type
|
||||
bool active
|
||||
Iris::Num start, size
|
||||
static unsigned read_num (char *data):
|
||||
return data[0] & 0xff | (data[1] & 0xff) << 8 | (data[2] & 0xff) << 16 | (data[3] & 0xff) << 24
|
||||
void read (char *data):
|
||||
if data[0] == 0:
|
||||
active = false
|
||||
else:
|
||||
active = true
|
||||
if (data[0] & 0xff) != 0x80:
|
||||
kdebug ("Warning: invalid active code ")
|
||||
kdebug_num (data[0], 2)
|
||||
kdebug ("\n")
|
||||
type = data[4] & 0xff
|
||||
lba_start = read_num (data + 8)
|
||||
lba_size = read_num (data + 12)
|
||||
start = Iris::Num (lba_start).value () << SECTOR_BITS
|
||||
size = Iris::Num (lba_size).value () << SECTOR_BITS
|
||||
kdebug ("Partition read: ")
|
||||
kdebug_num (lba_start)
|
||||
kdebug ("+")
|
||||
kdebug_num (lba_size)
|
||||
kdebug ("\n")
|
||||
|
||||
Iris::Num Partition::device_size
|
||||
|
||||
static Iris::WBlock dev
|
||||
static void read_sector (Iris::Num idx, Iris::Page page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
|
||||
offset &= ~PAGE_MASK
|
||||
if size + offset > PAGE_SIZE:
|
||||
size = PAGE_SIZE - offset
|
||||
size >>= SECTOR_BITS
|
||||
idx = idx.value () >> SECTOR_BITS
|
||||
for unsigned i = 0; i < size; ++i:
|
||||
dev.get_block ((idx.value () + i) << SECTOR_BITS, 1 << SECTOR_BITS, (i << SECTOR_BITS) + offset, page)
|
||||
|
||||
Iris::Num start ():
|
||||
Partition::device_size = 0
|
||||
dev = Iris::my_parent.get_capability <Iris::WBlock> ()
|
||||
bits = dev.get_align_bits ()
|
||||
if bits > SECTOR_BITS:
|
||||
Iris::panic (bits, "partitioned device doesn't support 512 byte access\n")
|
||||
Partition::device_size = dev.get_size ()
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING)
|
||||
char *buffer = (char *)0x15000
|
||||
unsigned *ubuffer = (unsigned *)buffer
|
||||
Iris::my_memory.map (page, (unsigned)buffer)
|
||||
read_sector (0, page)
|
||||
|
||||
if buffer[0x1fe] != 0x55 || (buffer[0x1ff] & 0xff) != 0xaa:
|
||||
kdebug ("invalid mbr signature\n")
|
||||
|
||||
Partition partition[NUM_PARTITIONS]
|
||||
|
||||
Iris::Cap cap
|
||||
for unsigned i = 0; i < NUM_PARTITIONS; ++i:
|
||||
partition[i].read (buffer + 0x1be + 0x10 * i)
|
||||
cap = Iris::my_receiver.create_capability (i)
|
||||
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy (), i)
|
||||
Iris::free_cap (cap)
|
||||
|
||||
page.set_flags (0, Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
//kdebug ("partition received: ")
|
||||
//kdebug_num (Iris::recv.data[0].l)
|
||||
//kdebug ("\n")
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Block::GET_SIZE:
|
||||
Iris::recv.reply.invoke (partition[Iris::recv.protected_data.l].size)
|
||||
break
|
||||
case Iris::Block::GET_ALIGN_BITS:
|
||||
Iris::recv.reply.invoke (SECTOR_BITS)
|
||||
break
|
||||
case Iris::Block::GET_BLOCK:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Num p = Iris::recv.data[1].value () & BLOCK_MASK
|
||||
Iris::Num offset = partition[Iris::recv.protected_data.l].start.value ()
|
||||
unsigned size = Iris::recv.data[0].h >> 16
|
||||
unsigned out_offset = Iris::recv.data[0].h & 0xffff
|
||||
//kdebug ("partition sending sector ")
|
||||
//kdebug_num (offset.h)
|
||||
//kdebug (":")
|
||||
//kdebug_num (offset.l)
|
||||
//kdebug (" + ")
|
||||
//kdebug_num (p.h)
|
||||
//kdebug (":")
|
||||
//kdebug_num (p.l)
|
||||
//kdebug (" = ")
|
||||
//kdebug_num (Iris::Num (offset.value () + p.value ()).h)
|
||||
//kdebug (":")
|
||||
//kdebug_num (Iris::Num (offset.value () + p.value ()).l)
|
||||
//kdebug ("\n")
|
||||
read_sector (offset.value () + p.value (), arg, size, out_offset)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
break
|
||||
case Iris::WBlock::SET_BLOCK:
|
||||
Iris::panic (Iris::recv.data[0].l, "writing to partitions not supported yet")
|
||||
case Iris::WBlock::TRUNCATE:
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid request for partition handler")
|
||||
762
userspace/glue/usbmassstorage.ccp
Normal file
762
userspace/glue/usbmassstorage.ccp
Normal file
@@ -0,0 +1,762 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/usb-mass-storage.ccp: USB mass storage device driver.
|
||||
// Copyright 2009-2010 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 "iris.hh"
|
||||
#include "devices.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
#if 0
|
||||
States and expected interrupts:
|
||||
|
||||
IDLE: after reset or csw.
|
||||
IN interrupt: csw received, do nothing.
|
||||
OUT interrupt: cbw; handle
|
||||
-> IDLE (no data; csw sent)
|
||||
-> TX (send)
|
||||
-> RX (receive packets)
|
||||
TX: transmitting data.
|
||||
IN interrupt: host received data; send more.
|
||||
-> TX (more to send)
|
||||
RX: receiving data.
|
||||
OUT interrupt: host sent data; handle.
|
||||
-> RX (more to receive)
|
||||
-> IDLE (done receiving; send csw)
|
||||
#endif
|
||||
|
||||
extern "C":
|
||||
void *memset (char *s, int c, unsigned long n):
|
||||
Iris::debug ("memset called: %x %x->%x\n", s, n, c)
|
||||
for unsigned i = 0; i < n; ++i:
|
||||
s[i] = c
|
||||
return s
|
||||
|
||||
class Udc:
|
||||
typedef unsigned char u8
|
||||
typedef unsigned short u16
|
||||
typedef unsigned int u32
|
||||
typedef u8 string
|
||||
// The ugly stuff is because pypp doesn't support __attribute__.
|
||||
/**/struct Setup {
|
||||
u8 request_type;
|
||||
u8 request;
|
||||
u16 value;
|
||||
u16 index;
|
||||
u16 length;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Device {
|
||||
static u8 const Type = 1;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 usb_version;
|
||||
u8 dev_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
u8 max_packet_size0;
|
||||
u16 vendor;
|
||||
u16 product;
|
||||
u16 dev_version;
|
||||
string s_manufacturer;
|
||||
string s_product;
|
||||
string s_serial;
|
||||
u8 num_configurations;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Configuration {
|
||||
static u8 const Type = 2;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 total_length;
|
||||
u8 num_interfaces;
|
||||
u8 configuration_value;
|
||||
u8 configuration;
|
||||
u8 attributes;
|
||||
u8 max_power;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Interface {
|
||||
static u8 const Type = 4;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 interface;
|
||||
u8 alternate;
|
||||
u8 num_endpoints;
|
||||
u8 iface_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
string name;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Endpoint {
|
||||
static u8 const Type = 5;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 address;
|
||||
u8 attributes;
|
||||
u16 max_packet_size;
|
||||
u8 interval;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Device_Qualifier {
|
||||
static u8 const Type = 6;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 version;
|
||||
u8 dev_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
u8 max_packet_size0;
|
||||
u8 num_configurations;
|
||||
u8 reserved;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Langs {
|
||||
static u8 const Type = 3;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 lang;
|
||||
} __attribute__ ((packed))
|
||||
template <unsigned size> struct String {
|
||||
static u8 const Type = 3;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 data[size];
|
||||
} __attribute__ ((packed))
|
||||
/**/struct CBW {
|
||||
u32 sig;
|
||||
u32 tag;
|
||||
u32 length;
|
||||
u8 flags;
|
||||
u8 lun;
|
||||
u8 size;
|
||||
u8 data[16];
|
||||
enum Code {
|
||||
TEST_UNIT_READY = 0x00,
|
||||
REQUEST_SENSE = 0x03,
|
||||
FORMAT_UNIT = 0x04,
|
||||
INQUIRY = 0x12,
|
||||
RESERVE6 = 0x16,
|
||||
RELEASE6 = 0x17,
|
||||
SEND_DIAGNOSTIC = 0x1d,
|
||||
READ_CAPACITY = 0x25,
|
||||
READ10 = 0x28,
|
||||
WRITE10 = 0x2a,
|
||||
RESERVE10 = 0x56,
|
||||
RELEASE10 = 0x57
|
||||
};
|
||||
} __attribute__ ((packed))
|
||||
static unsigned const max_packet_size0 = 64
|
||||
static unsigned const max_packet_size_bulk = 64
|
||||
enum Requests:
|
||||
GET_STATUS = 0
|
||||
CLEAR_FEATURE = 1
|
||||
SET_FEATURE = 3
|
||||
SET_ADDRESS = 5
|
||||
GET_DESCRIPTOR = 6
|
||||
SET_DESCRIPTOR = 7
|
||||
GET_CONFIGURATION = 8
|
||||
SET_CONFIGURATION = 9
|
||||
GET_INTERFACE = 10
|
||||
SET_INTERFACE = 11
|
||||
SYNCH_FRAME = 12
|
||||
enum Storage_requests:
|
||||
BULK_ONLY_RESET = 0xff
|
||||
GET_MAX_LUN = 0xfe
|
||||
enum Request_types:
|
||||
STANDARD_TO_DEVICE = 0
|
||||
CLASS_TO_DEVICE = 0x20
|
||||
VENDOR_TO_DEVICE = 0x40
|
||||
STANDARD_TO_INTERFACE = 1
|
||||
CLASS_TO_INTERFACE = 0x21
|
||||
VENDOR_TO_INTERFACE = 0x41
|
||||
STANDARD_TO_ENDPOINT = 2
|
||||
CLASS_TO_ENDPOINT = 0x22
|
||||
VENDOR_TO_ENDPOINT = 0x42
|
||||
STANDARD_FROM_DEVICE = 0x80
|
||||
CLASS_FROM_DEVICE = 0xa0
|
||||
VENDOR_FROM_DEVICE = 0xc0
|
||||
STANDARD_FROM_INTERFACE = 0x81
|
||||
CLASS_FROM_INTERFACE = 0xa1
|
||||
VENDOR_FROM_INTERFACE = 0xc1
|
||||
STANDARD_FROM_ENDPOINT = 0x82
|
||||
CLASS_FROM_ENDPOINT = 0xa2
|
||||
VENDOR_FROM_ENDPOINT = 0xc2
|
||||
enum Endpoint_types:
|
||||
CONTROL = 0
|
||||
ISOCHRONOUS = 1
|
||||
BULK = 2
|
||||
INTERRUPT = 3
|
||||
enum Endpoint_features:
|
||||
ENDPOINT_HALT = 0
|
||||
/**/struct my_config {
|
||||
Configuration config;
|
||||
Interface interface;
|
||||
Endpoint endpoint[2];
|
||||
} __attribute__ ((packed))
|
||||
static Device device_descriptor
|
||||
//static Device_Qualifier device_qualifier_descriptor
|
||||
static my_config config_descriptor; //, other_config_descriptor
|
||||
static String <1> s_langs
|
||||
static String <6> s_manufacturer
|
||||
static String <16> s_product
|
||||
static String <12> s_serial
|
||||
char configuration
|
||||
unsigned get_descriptor (unsigned type, unsigned idx, unsigned len)
|
||||
unsigned handle_setup (Setup *s)
|
||||
void reset ()
|
||||
void irq_in0 ()
|
||||
void handle_rx ()
|
||||
void handle_tx ()
|
||||
void handle_cbw ()
|
||||
void send_csw ()
|
||||
unsigned big_endian (unsigned src)
|
||||
bool handle_interrupt (bool usb, bool in)
|
||||
void stall (unsigned error)
|
||||
bool stalling
|
||||
enum State:
|
||||
IDLE
|
||||
TX
|
||||
RX
|
||||
SENT_CSW
|
||||
STALL
|
||||
State state
|
||||
unsigned residue
|
||||
unsigned status
|
||||
unsigned tag
|
||||
unsigned data_done, lba, blocks
|
||||
unsigned block_bits
|
||||
Iris::WBlock block
|
||||
Iris::Page buffer_page
|
||||
// A random address to map the buffer.
|
||||
static unsigned const buffer = 0x15000
|
||||
public:
|
||||
void init (Iris::WBlock b)
|
||||
void log (unsigned c)
|
||||
void interrupt ()
|
||||
void send (unsigned ep, char const *data, unsigned length, unsigned maxlength)
|
||||
void send_padded (char const *data, unsigned length, unsigned maxlength)
|
||||
|
||||
Udc::Device Udc::device_descriptor
|
||||
Udc::my_config Udc::config_descriptor
|
||||
Udc::String <1> Udc::s_langs
|
||||
Udc::String <6> Udc::s_manufacturer
|
||||
Udc::String <16> Udc::s_product
|
||||
Udc::String <12> Udc::s_serial
|
||||
|
||||
void Udc::reset ():
|
||||
// Reset.
|
||||
UDC_TESTMODE = 0
|
||||
configuration = 0
|
||||
state = IDLE
|
||||
status = 0
|
||||
residue = 0
|
||||
// enable interrupt on bus reset.
|
||||
UDC_INTRUSBE = UDC_INTR_RESET
|
||||
// enable interrupts on endpoint 0 and in endpoint 2
|
||||
UDC_INTRINE = 1 << 0 | 1 << 2
|
||||
// and on out endpoint 1.
|
||||
UDC_INTROUTE = 1 << 1
|
||||
// exit suspend mode by reading the interrupt register.
|
||||
unsigned i = UDC_INTRUSB
|
||||
// reset all pending endpoint interrupts.
|
||||
i = UDC_INTRIN
|
||||
i = UDC_INTROUT
|
||||
UDC_INDEX = 1
|
||||
UDC_OUTMAXP = max_packet_size_bulk
|
||||
// Do this twice to flush a double-buffered fifo completely.
|
||||
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||
UDC_INDEX = 2
|
||||
UDC_INMAXP = max_packet_size_bulk
|
||||
UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
|
||||
UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
|
||||
//Iris::debug ("usb reset\n")
|
||||
|
||||
void Udc::init (Iris::WBlock b):
|
||||
block = b
|
||||
block_bits = block.get_align_bits ()
|
||||
// Set up the buffer page.
|
||||
buffer_page = Iris::my_memory.create_page ()
|
||||
buffer_page.set_flags (Iris::Page::PAYING)
|
||||
Iris::my_memory.map (buffer_page, buffer)
|
||||
// Initialize the globals. My method of compiling doesn't handle global constructors.
|
||||
device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 3, 1 }
|
||||
config_descriptor = (my_config){
|
||||
(Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 30 },
|
||||
(Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0x8, 0x6, 0x50, 0 }, {
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x82, BULK, max_packet_size_bulk, 0 }
|
||||
}
|
||||
}
|
||||
s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
|
||||
s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
|
||||
s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
|
||||
s_serial = (String <12>){ sizeof (String <12>), String <12>::Type, { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B' } }
|
||||
|
||||
cpm_start_udc ()
|
||||
// Disconnect from the bus and don't try to get high-speed.
|
||||
UDC_POWER = 0
|
||||
reset ()
|
||||
// Wait a while.
|
||||
Iris::sleep (HZ / 10)
|
||||
// Connect to the host.
|
||||
UDC_POWER = UDC_POWER_SOFTCONN
|
||||
|
||||
void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
|
||||
if maxlength < length:
|
||||
length = maxlength
|
||||
unsigned i
|
||||
for i = 0; (length - i & ~3) > 0 && i < length; i += 4:
|
||||
UDC_FIFO (ep) = ((unsigned *)data)[i / 4]
|
||||
//kdebug_num (((unsigned *)data)[i / 4], 8)
|
||||
//kdebug (" ")
|
||||
for ; i < length; ++i:
|
||||
UDC_FIFO8 (ep) = data[i]
|
||||
//kdebug_num (data[i], 2)
|
||||
//kdebug (" ")
|
||||
|
||||
void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
|
||||
UDC_INDEX = 2
|
||||
unsigned len = length < maxlength ? length : maxlength
|
||||
residue = maxlength - len
|
||||
len = (len + 3) & ~3
|
||||
send (2, data, len, maxlength)
|
||||
//Iris::debug ("sending %x, valid %x\n", maxlength, len)
|
||||
while len + 3 < maxlength:
|
||||
UDC_FIFO (2) = 0
|
||||
len += 4
|
||||
//kdebug_char ('-')
|
||||
while len < maxlength:
|
||||
UDC_FIFO8 (2) = 0
|
||||
++len
|
||||
//kdebug_char ('.')
|
||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
||||
blocks = 0
|
||||
state = TX
|
||||
|
||||
unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||
switch type:
|
||||
case Configuration::Type:
|
||||
if idx != 0:
|
||||
return false
|
||||
//Iris::debug ("get config descriptor\n")
|
||||
send (0, reinterpret_cast <char const *> (&config_descriptor), sizeof (config_descriptor), len)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
case Device::Type:
|
||||
if idx != 0:
|
||||
return false
|
||||
//Iris::debug ("get device descriptor\n")
|
||||
send (0, reinterpret_cast <char const *> (&device_descriptor), sizeof (device_descriptor), len)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
case Device_Qualifier::Type:
|
||||
//if idx != 0:
|
||||
// return false
|
||||
//send (0, reinterpret_cast <char const *> (&device_qualifier_descriptor), sizeof (device_qualifier_descriptor), len)
|
||||
//return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
//break
|
||||
return ~0
|
||||
// The 6 is an arbitrary number, except that String <6> is instantiated already.
|
||||
case String <6>::Type:
|
||||
switch idx:
|
||||
case 0:
|
||||
//Iris::debug ("get language descriptor\n")
|
||||
send (0, reinterpret_cast <char const *> (&s_langs), sizeof (s_langs), len)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
case 1:
|
||||
//Iris::debug ("get manufacturer descriptor\n")
|
||||
send (0, reinterpret_cast <char const *> (&s_manufacturer), sizeof (s_manufacturer), len)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
case 2:
|
||||
//Iris::debug ("get product descriptor\n")
|
||||
send (0, reinterpret_cast <char const *> (&s_product), sizeof (s_product), len)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
case 3:
|
||||
//Iris::debug ("get serial descriptor\n")
|
||||
send (0, reinterpret_cast <char const *> (&s_serial), sizeof (s_serial), len)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
default:
|
||||
return ~0
|
||||
default:
|
||||
return ~0
|
||||
|
||||
unsigned Udc::handle_setup (Setup *s):
|
||||
switch s->request_type:
|
||||
case STANDARD_TO_DEVICE:
|
||||
UDC_INDEX = 0
|
||||
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
switch s->request:
|
||||
case SET_ADDRESS:
|
||||
UDC_FADDR = s->value
|
||||
Iris::debug ("set address %x\n", s->value)
|
||||
return 0
|
||||
case SET_CONFIGURATION:
|
||||
if s->value >= 2:
|
||||
return ~0
|
||||
configuration = s->value
|
||||
Iris::debug ("set configuration %x\n", s->value)
|
||||
return 0
|
||||
case SET_INTERFACE:
|
||||
if s->value != 0:
|
||||
return ~0
|
||||
Iris::debug ("set interface %x\n", s->value)
|
||||
return 0
|
||||
default:
|
||||
return ~0
|
||||
case STANDARD_FROM_DEVICE:
|
||||
UDC_INDEX = 0
|
||||
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
switch s->request:
|
||||
case GET_STATUS:
|
||||
Iris::debug ("get status\t")
|
||||
send (0, "\0\0", 2, s->length)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
case GET_DESCRIPTOR:
|
||||
return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
|
||||
case GET_CONFIGURATION:
|
||||
Iris::debug ("get configuration\t")
|
||||
send (0, &configuration, 1, s->length)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
case GET_INTERFACE:
|
||||
Iris::debug ("get interface\t")
|
||||
send (0, "\0", 1, s->length)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
default:
|
||||
return ~0
|
||||
case STANDARD_TO_ENDPOINT:
|
||||
switch s->request:
|
||||
case CLEAR_FEATURE:
|
||||
switch s->value:
|
||||
case ENDPOINT_HALT:
|
||||
switch s->index:
|
||||
case 0x82:
|
||||
//Iris::debug ("in ep halt reset\n")
|
||||
UDC_INDEX = 2
|
||||
UDC_INCSR = (UDC_INCSR & ~UDC_INCSR_SENDSTALL) | UDC_INCSR_CDT
|
||||
stalling = false
|
||||
send_csw ()
|
||||
break
|
||||
case 1:
|
||||
//Iris::panic (0, "halt reset on out endpoint")
|
||||
UDC_INDEX = 1
|
||||
UDC_OUTCSR |= UDC_OUTCSR_CDT
|
||||
break
|
||||
default:
|
||||
return ~0
|
||||
return UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
default:
|
||||
return ~0
|
||||
default:
|
||||
return ~0
|
||||
case CLASS_FROM_INTERFACE:
|
||||
UDC_INDEX = 0
|
||||
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
switch s->request:
|
||||
case GET_MAX_LUN:
|
||||
//Iris::debug ("get max lun\t")
|
||||
send (0, "\0", 1, s->length)
|
||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
default:
|
||||
return ~0
|
||||
case CLASS_TO_INTERFACE:
|
||||
UDC_INDEX = 0
|
||||
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
switch s->request:
|
||||
case BULK_ONLY_RESET:
|
||||
Iris::debug ("bulk reset\n")
|
||||
state = IDLE
|
||||
return 0
|
||||
default:
|
||||
return ~0
|
||||
default:
|
||||
Iris::debug ("request: %x %x %x %x %x\n", s->request_type, s->request, s->index, s->length, s->value)
|
||||
return ~0
|
||||
|
||||
void Udc::irq_in0 ():
|
||||
// Interrupt on endpoint 0.
|
||||
UDC_INDEX = 0
|
||||
unsigned csr = UDC_CSR0
|
||||
if csr & UDC_CSR0_SENTSTALL:
|
||||
UDC_CSR0 = 0
|
||||
//Iris::debug ("stall 0 done\t")
|
||||
if csr & UDC_CSR0_SETUPEND:
|
||||
UDC_CSR0 = UDC_CSR0_SVDSETUPEND
|
||||
Iris::debug ("setup aborted\t")
|
||||
if !(csr & UDC_CSR0_OUTPKTRDY):
|
||||
//Iris::debug ("no packet 0: %x\n", csr)
|
||||
return
|
||||
UDC_INDEX = 0
|
||||
union { unsigned d[2]; Setup s; } packet
|
||||
packet.d[0] = UDC_FIFO (0)
|
||||
packet.d[1] = UDC_FIFO (0)
|
||||
if !(packet.s.request_type & 0x80) && packet.s.length > 0:
|
||||
// More data will follow; unsupported.
|
||||
Iris::debug ("packet on ep0 too long\n")
|
||||
UDC_CSR0 = UDC_CSR0_SENDSTALL
|
||||
return
|
||||
unsigned ret = handle_setup (&packet.s)
|
||||
UDC_INDEX = 0
|
||||
if ret == ~0:
|
||||
//Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
|
||||
UDC_CSR0 = UDC_CSR0_SENDSTALL
|
||||
return
|
||||
if ret:
|
||||
UDC_CSR0 = ret
|
||||
//kdebug ("done in0\n")
|
||||
|
||||
void Udc::send_csw ():
|
||||
UDC_INDEX = 2
|
||||
UDC_FIFO (2) = 0x53425355
|
||||
UDC_FIFO (2) = tag
|
||||
UDC_FIFO (2) = residue
|
||||
UDC_FIFO8 (2) = status
|
||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
||||
state = SENT_CSW
|
||||
status = 0
|
||||
residue = 0
|
||||
//kdebug ("sent csw\n")
|
||||
|
||||
void Udc::stall (unsigned error):
|
||||
if stalling:
|
||||
Iris::debug ("already stalling!\n")
|
||||
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
||||
stalling = true
|
||||
state = STALL
|
||||
|
||||
unsigned Udc::big_endian (unsigned src):
|
||||
return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
|
||||
|
||||
void Udc::handle_rx ():
|
||||
buffer_page.set_flags (Iris::Page::FRAME)
|
||||
UDC_INDEX = 1
|
||||
if !(UDC_OUTCSR & UDC_OUTCSR_OUTPKTRDY):
|
||||
Iris::panic (0, "no packet ready after out interrupt during rx")
|
||||
if UDC_OUTCOUNT != max_packet_size_bulk:
|
||||
Iris::panic (UDC_OUTCOUNT, "invalid packet size during rx")
|
||||
for unsigned t = 0; t < max_packet_size_bulk; t += 4:
|
||||
((unsigned *)buffer)[(t + data_done) >> 2] = UDC_FIFO (1)
|
||||
UDC_OUTCSR &= ~UDC_OUTCSR_OUTPKTRDY
|
||||
data_done += max_packet_size_bulk
|
||||
if data_done == 1 << block_bits:
|
||||
//Iris::debug ("writing block %x\n", lba)
|
||||
block.set_block (lba << block_bits, buffer_page, 1 << block_bits)
|
||||
data_done = 0
|
||||
--blocks
|
||||
++lba
|
||||
if blocks == 0:
|
||||
send_csw ()
|
||||
return
|
||||
|
||||
void Udc::handle_tx ():
|
||||
if blocks == 0:
|
||||
send_csw ()
|
||||
return
|
||||
if data_done == 0:
|
||||
// read block lba.
|
||||
buffer_page.set_flags (Iris::Page::FRAME)
|
||||
block.get_block (lba << block_bits, 1 << block_bits, 0, buffer_page)
|
||||
UDC_INDEX = 2
|
||||
for unsigned t = 0; t < max_packet_size_bulk; t += 4:
|
||||
UDC_FIFO (2) = ((unsigned *)buffer)[(data_done + t) >> 2]
|
||||
data_done += max_packet_size_bulk
|
||||
if data_done == 1 << block_bits:
|
||||
data_done = 0
|
||||
++lba
|
||||
--blocks
|
||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
||||
|
||||
void Udc::handle_cbw ():
|
||||
UDC_INDEX = 1
|
||||
unsigned csr = UDC_OUTCSR
|
||||
unsigned size = UDC_OUTCOUNT
|
||||
if csr & UDC_OUTCSR_SENDSTALL:
|
||||
// When stalling, do nothing else.
|
||||
//kdebug ("not responding to out during stall\n")
|
||||
UDC_OUTCSR = csr & ~UDC_OUTCSR_SENTSTALL
|
||||
return
|
||||
if !(csr & UDC_OUTCSR_OUTPKTRDY):
|
||||
// No packet; this shouldn't happen.
|
||||
Iris::panic (0, "no packet")
|
||||
return
|
||||
// expect a new cbw.
|
||||
if size != 31:
|
||||
Iris::debug ("count %d != 31\n", size)
|
||||
stall (2)
|
||||
return
|
||||
union Cbw:
|
||||
unsigned u[8]
|
||||
char b[32]
|
||||
CBW cbw
|
||||
Cbw cbw
|
||||
for unsigned i = 0; i < 7; ++i:
|
||||
cbw.u[i] = UDC_FIFO (1)
|
||||
for unsigned i = 28; i < 31; ++i:
|
||||
cbw.b[i] = UDC_FIFO8 (1)
|
||||
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
|
||||
tag = cbw.cbw.tag
|
||||
if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
|
||||
Iris::debug ("wrong cbw: sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
|
||||
stall (2)
|
||||
return
|
||||
//kdebug ("bulk cbw\t")
|
||||
#if 0
|
||||
Iris::debug ("cbw:")
|
||||
for unsigned i = 0; i < cbw.cbw.size; ++i:
|
||||
kdebug_char (' ')
|
||||
kdebug_num (cbw.cbw.data[i], 2)
|
||||
Iris::debug ("\n")
|
||||
#endif
|
||||
UDC_INDEX = 2
|
||||
bool to_host = cbw.cbw.flags & 0x80
|
||||
switch cbw.cbw.data[0]:
|
||||
case CBW::TEST_UNIT_READY:
|
||||
if to_host || cbw.cbw.length != 0:
|
||||
stall (2)
|
||||
return
|
||||
//Iris::debug ("sending ready response\t")
|
||||
send_csw ()
|
||||
break
|
||||
case CBW::REQUEST_SENSE:
|
||||
//Iris::debug ("sense requested\n")
|
||||
send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
|
||||
break
|
||||
case CBW::FORMAT_UNIT:
|
||||
Iris::panic (0, "FORMAT_UNIT isn't implemented")
|
||||
case CBW::INQUIRY:
|
||||
if !to_host:
|
||||
stall (2)
|
||||
return
|
||||
//Iris::debug ("sending inquiry response\t")
|
||||
// TODO: find out why these bytes are messed up.
|
||||
send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick \x00\x00\x04\x02", 36, cbw.cbw.length)
|
||||
break
|
||||
case CBW::RESERVE6:
|
||||
Iris::panic (0, "RESERVE6 isn't implemented")
|
||||
case CBW::RELEASE6:
|
||||
Iris::panic (0, "RELEASE6 isn't implemented")
|
||||
case CBW::SEND_DIAGNOSTIC:
|
||||
Iris::panic (0, "SEND_DIAGNOSTIC isn't implemented")
|
||||
case CBW::READ_CAPACITY:
|
||||
if !to_host:
|
||||
stall (2)
|
||||
return
|
||||
unsigned capacity[2]
|
||||
capacity[0] = big_endian ((block.get_size ().value () >> block_bits) - 1)
|
||||
capacity[1] = big_endian (1 << block_bits)
|
||||
//Iris::debug ("sending capacity: %x * %x\t", capacity[0], capacity[1])
|
||||
send_padded ((char *)capacity, 8, cbw.cbw.length)
|
||||
break
|
||||
case CBW::READ10:
|
||||
if !to_host:
|
||||
stall (2)
|
||||
return
|
||||
lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
|
||||
blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
|
||||
data_done = 0
|
||||
state = TX
|
||||
handle_tx ()
|
||||
break
|
||||
case CBW::WRITE10:
|
||||
if to_host:
|
||||
stall (2)
|
||||
return
|
||||
lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
|
||||
blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
|
||||
if blocks == 0:
|
||||
send_csw ()
|
||||
break
|
||||
state = RX
|
||||
data_done = 0
|
||||
buffer_page.set_flags (Iris::Page::FRAME)
|
||||
break
|
||||
case CBW::RESERVE10:
|
||||
Iris::panic (0, "RESERVE10 isn't implemented")
|
||||
case CBW::RELEASE10:
|
||||
Iris::panic (0, "RELEASE10 isn't implemented")
|
||||
default:
|
||||
#if 0
|
||||
Iris::debug ("unknown cbw:")
|
||||
for unsigned i = 0; i < cbw.cbw.size; ++i:
|
||||
kdebug_char (' ')
|
||||
kdebug_num (cbw.cbw.data[i], 2)
|
||||
Iris::debug ("\n")
|
||||
#endif
|
||||
residue = cbw.cbw.length
|
||||
stall (1)
|
||||
return
|
||||
|
||||
void Udc::interrupt ():
|
||||
//Iris::debug ("interrupt, state = %d\n", state)
|
||||
while true:
|
||||
bool action = false
|
||||
unsigned usb = UDC_INTRUSB
|
||||
unsigned in = UDC_INTRIN
|
||||
unsigned out = UDC_INTROUT
|
||||
if usb & 4:
|
||||
//Iris::debug ("reset\n")
|
||||
reset ()
|
||||
action = true
|
||||
if state == STALL && in & 4:
|
||||
// This must be handled here, because the state can be changed by the control request.
|
||||
//Iris::debug ("stalling\n")
|
||||
in &= ~4
|
||||
if in & 1:
|
||||
//Iris::debug ("control request\n")
|
||||
irq_in0 ()
|
||||
action = true
|
||||
if in & 4:
|
||||
//Iris::debug ("in request\n")
|
||||
// Notification of sent packet (or stall, but we don't do that on the in endpoint).
|
||||
switch state:
|
||||
case SENT_CSW:
|
||||
// csw received.
|
||||
state = IDLE
|
||||
break
|
||||
case TX:
|
||||
handle_tx ()
|
||||
break
|
||||
default:
|
||||
Iris::panic (state, "invalid state for data send")
|
||||
stall (2)
|
||||
break
|
||||
action = true
|
||||
if out & 2:
|
||||
//Iris::debug ("out request\n")
|
||||
switch state:
|
||||
case IDLE:
|
||||
handle_cbw ()
|
||||
break
|
||||
case RX:
|
||||
handle_rx ()
|
||||
break
|
||||
default:
|
||||
stall (2)
|
||||
Iris::panic (0, "invalid state for data receive")
|
||||
break
|
||||
action = true
|
||||
if !action:
|
||||
// No more interrupts to handle; this is normal, because we're looping until this happens.
|
||||
//Iris::debug ("irq done\n")
|
||||
return
|
||||
|
||||
Iris::Num start ():
|
||||
map_udc ()
|
||||
map_gpio ()
|
||||
map_cpm ()
|
||||
Udc udc
|
||||
|
||||
Iris::WBlock nand = Iris::my_parent.get_capability <Iris::WBlock> ()
|
||||
udc.init (nand)
|
||||
while true:
|
||||
Iris::register_interrupt (IRQ_UDC)
|
||||
Iris::wait ()
|
||||
udc.interrupt ()
|
||||
1
userspace/hardware
Symbolic link
1
userspace/hardware
Symbolic link
@@ -0,0 +1 @@
|
||||
nanonote
|
||||
136
userspace/nanonote/boot.ccp
Normal file
136
userspace/nanonote/boot.ccp
Normal file
@@ -0,0 +1,136 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/boot.ccp: Boot into another kernel.
|
||||
// Copyright 2010 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 <iris.hh>
|
||||
#include <devices.hh>
|
||||
|
||||
extern "C":
|
||||
extern unsigned pre_code, pre_end, post_code, post_end
|
||||
|
||||
struct args_t:
|
||||
unsigned load
|
||||
unsigned size
|
||||
unsigned entry
|
||||
unsigned source
|
||||
|
||||
Iris::Num start ():
|
||||
unsigned *loader_addr = (unsigned *)0x15000
|
||||
unsigned *page_addr = (unsigned *)0x16000
|
||||
unsigned *tmp_addr = (unsigned *)0x17000
|
||||
Iris::Boot cap = Iris::my_receiver.create_capability (0)
|
||||
Iris::my_parent.provide_capability <Iris::Boot> (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Boot::BOOT:
|
||||
Iris::Block code = Iris::get_arg ()
|
||||
unsigned load = Iris::recv.data[1].l
|
||||
unsigned entry = Iris::recv.data[1].h
|
||||
Iris::Num lsize = code.get_size ()
|
||||
if lsize.h != 0:
|
||||
Iris::panic (lsize.h, "string to boot is too large to be loaded")
|
||||
unsigned size = lsize.l
|
||||
unsigned pages = ((size + ~PAGE_MASK) >> PAGE_BITS) + 1
|
||||
unsigned phys = Iris::my_memory.alloc_range (pages)
|
||||
if phys & ~PAGE_MASK:
|
||||
Iris::panic (size, "unable to allocate space for string to load")
|
||||
unsigned target, offset
|
||||
if phys < (load & ~0xa0000000):
|
||||
Iris::debug ("pre-loading\n")
|
||||
Iris::Page pre = Iris::my_memory.create_page ()
|
||||
pre.alloc_physical (phys, true, true)
|
||||
Iris::my_memory.map (pre, (unsigned)loader_addr)
|
||||
for unsigned i = 0; i < &pre_end - &pre_code; ++i:
|
||||
loader_addr[i] = (&pre_code)[i]
|
||||
target = phys
|
||||
offset = 1
|
||||
else:
|
||||
Iris::debug ("post-loading\n")
|
||||
Iris::Page post = Iris::my_memory.create_page ()
|
||||
post.alloc_physical (phys + ((pages - 1) << PAGE_BITS), true, true)
|
||||
Iris::my_memory.map (post, (unsigned)loader_addr)
|
||||
for unsigned i = 0; i < &post_end - &post_code; ++i:
|
||||
loader_addr[i] = (&post_code)[i]
|
||||
target = phys + ((pages - 1) << PAGE_BITS)
|
||||
offset = 0
|
||||
Iris::Page tmp = Iris::my_memory.create_page ()
|
||||
tmp.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (tmp, (unsigned)tmp_addr)
|
||||
for unsigned i = 0; i < pages - 1; ++i:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.alloc_physical (phys + ((i + offset) << PAGE_BITS), true, true)
|
||||
Iris::my_memory.map (page, (unsigned)page_addr)
|
||||
code.get_block (i << PAGE_BITS, PAGE_SIZE, 0, tmp)
|
||||
for unsigned t = 0; t < PAGE_SIZE / 4; ++t:
|
||||
page_addr[t] = tmp_addr[t]
|
||||
args_t *args = (args_t *)((unsigned)loader_addr + PAGE_SIZE - sizeof (args_t))
|
||||
unsigned phys_args = target + PAGE_SIZE - sizeof (args_t)
|
||||
args->load = load
|
||||
args->entry = entry
|
||||
args->size = size
|
||||
args->source = phys + (offset << PAGE_BITS) | 0x80000000
|
||||
Iris::debug ("booting into: %x+%x->%x@%x (%x, %x)\n", args->source, args->size, args->load, args->entry, args, phys_args)
|
||||
// Everything is set up; jump to the loader.
|
||||
Iris::boot (target | 0x80000000, phys_args | 0x80000000)
|
||||
Iris::panic (0, "Iris::boot should not return, but it does")
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid commend received on boot capability")
|
||||
|
||||
asm volatile ("\t.set noreorder\n"
|
||||
"\t.globl pre_code, pre_end, post_code, post_end\n"
|
||||
"\t.text\n"
|
||||
"pre_code:\n"
|
||||
"\tlw $t0, 0($a0)\n" // t0 is the load address
|
||||
"\tlw $t1, 4($a0)\n" // t1 is the size
|
||||
"\tlw $t9, 8($a0)\n" // t9 is the entry point
|
||||
"\tlw $t2, 12($a0)\n" // t2 is the source of the loaded image
|
||||
"\tadd $t0, $t0, $t1\n" // t0 is the end of the load region
|
||||
"\tadd $t2, $t2, $t1\n" // t2 is the end of the source
|
||||
"1:\n"
|
||||
"\tlw $t3, -4($t2)\n"
|
||||
"\tsw $t3, -4($t0)\n"
|
||||
"\taddiu $t2, $t2, -4\n"
|
||||
"\taddiu $t1, $t1, -4\n"
|
||||
"\tbnez $t1, 1b\n"
|
||||
"\taddiu $t0, $t0, -4\n"
|
||||
// Done copying
|
||||
"\tjr $t9\n"
|
||||
"\tnop\n"
|
||||
"pre_end:\n"
|
||||
"\n"
|
||||
"post_code:\n"
|
||||
"\tlw $t0, 0($a0)\n" // t0 is the load address
|
||||
"\tlw $t1, 4($a0)\n" // t1 is the size
|
||||
"\tlw $t9, 8($a0)\n" // t9 is the entry point
|
||||
"\tlw $t2, 12($a0)\n" // t2 is the source of the loaded image
|
||||
"1:\n"
|
||||
"\tlw $t3, 0($t2)\n"
|
||||
"\tsw $t3, 0($t0)\n"
|
||||
"\taddiu $t2, $t2, 4\n"
|
||||
"\taddiu $t1, $t1, -4\n"
|
||||
"\tbnez $t1, 1b\n"
|
||||
"\taddiu $t0, $t0, 4\n"
|
||||
// Done copying
|
||||
"\tjr $t9\n"
|
||||
"\tnop\n"
|
||||
"post_end:\n"
|
||||
"\n"
|
||||
"\t.set reorder\n")
|
||||
97
userspace/nanonote/buzzer.ccp
Normal file
97
userspace/nanonote/buzzer.ccp
Normal file
@@ -0,0 +1,97 @@
|
||||
#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
|
||||
Iris::Cap event
|
||||
bool is_beeping
|
||||
public:
|
||||
DevBuzzer ():
|
||||
is_beeping = false
|
||||
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 ()
|
||||
Iris::free_cap (event)
|
||||
is_beeping = false
|
||||
void beep (unsigned freq, unsigned ms, Iris::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)
|
||||
Iris::my_receiver.set_alarm (ms * HZ / 1000)
|
||||
is_beeping = true
|
||||
|
||||
enum codes:
|
||||
BUZZER = 32
|
||||
|
||||
Iris::Num start ():
|
||||
map_tcu ()
|
||||
|
||||
DevBuzzer buzzer
|
||||
|
||||
Iris::Buzzer dev = Iris::my_receiver.create_capability (BUZZER)
|
||||
Iris::my_parent.provide_capability <Iris::Buzzer> (dev.copy ())
|
||||
Iris::free_cap (dev)
|
||||
Iris::my_parent.init_done ()
|
||||
while true:
|
||||
Iris::wait ()
|
||||
if Iris::recv.protected_data.h == ~0:
|
||||
// Alarm.
|
||||
buzzer.stop ()
|
||||
continue
|
||||
switch Iris::recv.protected_data.l:
|
||||
case BUZZER:
|
||||
// Buzzer device user request.
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::RESET:
|
||||
buzzer.stop ()
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Buzzer::BEEP:
|
||||
// Volume is not used by this buzzer.
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
buzzer.beep (Iris::recv.data[1].l, Iris::recv.data[1].h, arg)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::Buzzer::STOP:
|
||||
buzzer.stop ()
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("Buzzer: other\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("Buzzer: unknown num: ")
|
||||
kdebug_num (Iris::recv.protected_data.l)
|
||||
kdebug ("\n")
|
||||
299
userspace/nanonote/gpio.ccp
Normal file
299
userspace/nanonote/gpio.ccp
Normal file
@@ -0,0 +1,299 @@
|
||||
#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"
|
||||
#include "keys.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]
|
||||
static unsigned const NUM_KEYS = 58
|
||||
static unsigned const keys[NUM_KEYS]
|
||||
unsigned state[NUM_COLS]
|
||||
Iris::Cap event
|
||||
bool is_active
|
||||
bool is_scanning
|
||||
public:
|
||||
unsigned size ():
|
||||
return NUM_KEYS
|
||||
void send_keys (unsigned first, Iris::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 (Iris::Num (d[0], d[1]), Iris::Num (d[2], d[3]))
|
||||
bool scanning ():
|
||||
return is_scanning
|
||||
void inactive ():
|
||||
if is_active:
|
||||
Iris::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 |= Iris::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 (Iris::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
|
||||
{ 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_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP },
|
||||
{ Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT },
|
||||
{ Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT },
|
||||
{ Key::LEFT_SHIFT, Key::LEFT_ALT, Key::FN, ~0, ~0, ~0, ~0, ~0 }
|
||||
#else
|
||||
{ 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
|
||||
}
|
||||
unsigned const DevKbd::keys[NUM_KEYS] = {
|
||||
#ifdef QI
|
||||
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_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP,
|
||||
Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT,
|
||||
Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT,
|
||||
Key::LEFT_SHIFT, Key::LEFT_ALT, Key::FN
|
||||
#else
|
||||
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
|
||||
}
|
||||
|
||||
class Event:
|
||||
bool state, started
|
||||
unsigned pin
|
||||
Iris::Cap cb
|
||||
public:
|
||||
void scan ():
|
||||
if !started:
|
||||
return
|
||||
gpio_mask_irq (3, 1 << pin)
|
||||
bool s = gpio_get_port (3) & (1 << pin)
|
||||
if s != state:
|
||||
state = s
|
||||
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
|
||||
gpio_as_interrupt (3, 1 << pin, !state, true)
|
||||
gpio_unmask_irq (3, 1 << pin)
|
||||
Event (unsigned p):
|
||||
pin = p
|
||||
gpio_as_gpio (3, pin)
|
||||
state = true
|
||||
started = false
|
||||
void set_cb (Iris::Cap c):
|
||||
if started:
|
||||
Iris::free_cap (cb)
|
||||
else:
|
||||
started = true
|
||||
cb = c
|
||||
state = true
|
||||
scan ()
|
||||
|
||||
enum codes:
|
||||
KBD_DEV = 1
|
||||
PWR
|
||||
SDMMC
|
||||
|
||||
Iris::Num start ():
|
||||
map_gpio ()
|
||||
|
||||
DevKbd kbd
|
||||
Event pwr (29)
|
||||
Event sdmmc (0)
|
||||
|
||||
Iris::Keyboard dev = Iris::my_receiver.create_capability (KBD_DEV)
|
||||
Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR)
|
||||
Iris::Event sm = Iris::my_receiver.create_capability (SDMMC)
|
||||
Iris::my_parent.provide_capability <Iris::Keyboard> (dev.copy (), 0)
|
||||
Iris::my_parent.provide_capability <Iris::Keyboard> (pw.copy (), 1)
|
||||
Iris::my_parent.provide_capability <Iris::Event> (sm.copy ())
|
||||
Iris::free_cap (dev)
|
||||
Iris::free_cap (pw)
|
||||
Iris::free_cap (sm)
|
||||
Iris::my_parent.init_done ()
|
||||
if kbd.scanning ():
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Iris::register_interrupt (IRQ_GPIO3)
|
||||
while true:
|
||||
Iris::wait ()
|
||||
if Iris::recv.protected_data.h == ~0:
|
||||
// Alarm.
|
||||
kbd.scan ()
|
||||
if kbd.scanning ():
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
continue
|
||||
switch Iris::recv.protected_data.l:
|
||||
case 0:
|
||||
// Interrupt.
|
||||
pwr.scan ()
|
||||
kbd.scan ()
|
||||
sdmmc.scan ()
|
||||
if kbd.scanning ():
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Iris::register_interrupt (IRQ_GPIO3)
|
||||
break
|
||||
case KBD_DEV:
|
||||
// Keyboard device user request.
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Event::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
kbd.active (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::Keyboard::GET_NUM_KEYS:
|
||||
Iris::recv.reply.invoke (kbd.size ())
|
||||
break
|
||||
case Iris::Keyboard::GET_KEYS:
|
||||
kbd.send_keys (Iris::recv.data[0].l, Iris::recv.reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("keyboard other\n")
|
||||
break
|
||||
break
|
||||
case PWR:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Event::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
pwr.set_cb (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("Power button invalid request\n")
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
case SDMMC:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Event::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
sdmmc.set_cb (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("SdMmc gpio invalid request\n")
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("keyboard unknown num: ")
|
||||
kdebug_num (Iris::recv.protected_data.h)
|
||||
kdebug ("\n")
|
||||
470
userspace/nanonote/lcd.ccp
Normal file
470
userspace/nanonote/lcd.ccp
Normal file
@@ -0,0 +1,470 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/lcd.ccp: Display 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"
|
||||
|
||||
__asm__ volatile (".section .rodata\n.globl charset\ncharset:\n.incbin \"source/data/charset.data\"\n.section .text")
|
||||
extern unsigned char const charset[127-32][8][6]
|
||||
|
||||
#define assert(x) do { if (!(x)) { kdebug ("assertion failed " #x); while (true) {} } } while (0)
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
static unsigned h = 800, v = 480, fps = 60, Bpp = 2
|
||||
#define LOG_X_BASE 1
|
||||
#define LOG_Y_BASE 1
|
||||
#elif defined (NANONOTE)
|
||||
static unsigned h = 320, v = 240, fps = 60, Bpp = 4
|
||||
#define LOG_X_BASE 0
|
||||
#define LOG_Y_BASE 0
|
||||
#else
|
||||
#error unknown board
|
||||
#endif
|
||||
#define frame_size (v * h * Bpp)
|
||||
|
||||
static unsigned physical_descriptor
|
||||
|
||||
/**/struct Descriptor {
|
||||
unsigned next;
|
||||
unsigned frame;
|
||||
unsigned id;
|
||||
unsigned cmd;
|
||||
} __attribute__ ((packed))
|
||||
|
||||
#if defined (NANONOTE)
|
||||
#define SP_PORT 2
|
||||
#define SPEN 21
|
||||
#define SPDA 22
|
||||
#define SPCK 23
|
||||
|
||||
static void udelay (unsigned num):
|
||||
for unsigned i = 0; i < num * (JZ_EXTAL / 1000000); ++i:
|
||||
// set 0 does nothing, but costs at least one clock pulse.
|
||||
gpio_set (SP_PORT, 0)
|
||||
|
||||
// Register names. The registers are not named in the datasheet, and in some cases the name only describes a part of the bits in it.
|
||||
// The registers with bit 6 set have bit 7 set instead, because of the transfer method.
|
||||
enum spi_reg:
|
||||
AC = 0x00
|
||||
DC = 0x01
|
||||
BRIGHTNESS = 0x03
|
||||
FORMAT = 0x04
|
||||
BACKLIGHT1 = 0x05
|
||||
VBLANK = 0x06
|
||||
HBLANK = 0x07
|
||||
BACKLIGHT2 = 0x08
|
||||
SYNC = 0x0b
|
||||
POLARITY = 0x0c
|
||||
CONTRAST_RGB = 0x0d
|
||||
SUB_CONTRAST_R = 0x0e
|
||||
SUB_BRIGHTNESS_R= 0x0f
|
||||
SUB_CONTRAST_B = 0x10
|
||||
SUB_BRIGHTNESS_B= 0x11
|
||||
TRIM = 0x12
|
||||
COLOR = 0x13
|
||||
GAMMA = 0x16
|
||||
GAMMA1 = 0x17
|
||||
GAMMA2 = 0x18
|
||||
GAMMA3 = 0x19
|
||||
GAMMA4 = 0x1a
|
||||
INVERSION = 0xa5
|
||||
HLEVEL = 0xa6
|
||||
LLEVEL = 0xa7
|
||||
FB = 0xb1
|
||||
|
||||
static void write_reg (unsigned reg, unsigned val):
|
||||
unsigned value = (reg << 8) | (val & 0xff)
|
||||
gpio_clear (SP_PORT, 1 << SPEN)
|
||||
udelay (1)
|
||||
for unsigned i = 0; i < 16; ++i, value <<= 1:
|
||||
gpio_clear (SP_PORT, 1 << SPCK)
|
||||
if value & 0x8000:
|
||||
gpio_set (SP_PORT, 1 << SPDA)
|
||||
else:
|
||||
gpio_clear (SP_PORT, 1 << SPDA)
|
||||
udelay (4)
|
||||
gpio_set (SP_PORT, 1 << SPCK)
|
||||
udelay (4)
|
||||
gpio_set (SP_PORT, 1 << SPEN)
|
||||
udelay(4)
|
||||
#endif
|
||||
|
||||
static void reset ():
|
||||
#if defined (TRENDTAC)
|
||||
// Note that the sync pulse is part of the pre-display region.
|
||||
// Vertical timings.
|
||||
unsigned vsync = 20, vpre = 20, vpost = 0
|
||||
// Horizontal timings.
|
||||
unsigned hsync = 80, hpre = 80, hpost = 0
|
||||
|
||||
// One clock pulse per pixel.
|
||||
unsigned cpp = 1
|
||||
// Bits per pixel.
|
||||
unsigned bpp = LCD_CTRL_BPP_16
|
||||
// Configuration.
|
||||
#define MODE_TFT_GEN 0
|
||||
#define VSYNC_N (1 << 8)
|
||||
unsigned cfg = MODE_TFT_GEN | VSYNC_N
|
||||
#elif defined (NANONOTE)
|
||||
// Note that the sync pulse is part of the pre-display region.
|
||||
// Horizontal timings.
|
||||
unsigned hsync = 1, hpre = 70, hpost = 273
|
||||
// Vertical timings.
|
||||
unsigned vsync = 1, vpre = 21, vpost = 2
|
||||
// 3 clocks per pixel.
|
||||
unsigned cpp = 3
|
||||
// Bits per pixel.
|
||||
unsigned bpp = LCD_CTRL_BPP_18_24
|
||||
// Configuration.
|
||||
unsigned cfg = LCD_CFG_MODE_SERIAL_TFT | LCD_CFG_HSP | LCD_CFG_VSP | LCD_CFG_PCP
|
||||
// Set up SPI pins.
|
||||
gpio_as_output (SP_PORT, (1 << SPEN) | (1 << SPCK) | (1 << SPDA))
|
||||
gpio_set (SP_PORT, (1 << SPEN) | (1 << SPCK))
|
||||
#else
|
||||
#error unknown board
|
||||
#endif
|
||||
|
||||
// Note that the sync pulse is part of the pre-display region.
|
||||
unsigned vpe = vsync, vds = vpre, vde = vds + v, vt = vde + vpost
|
||||
unsigned hpe = hsync, hds = hpre, hde = hds + h, ht = hde + hpost
|
||||
|
||||
cpm_stop_lcd ()
|
||||
|
||||
unsigned pixclock = fps * ht * vt
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
unsigned pllout = cpm_get_pllout ()
|
||||
CPM_CFCR2 = pllout / pixclock - 1
|
||||
|
||||
unsigned val = pllout / (pixclock * 4) - 1
|
||||
assert (pllout / (val + 1) <= 150000000)
|
||||
assert (val <= 0xf)
|
||||
cpm_set_lcdclk_div (val)
|
||||
CPM_CFCR |= CPM_CFCR_UPE
|
||||
#elif defined (NANONOTE)
|
||||
unsigned val = cpm_get_pllout2 () / pixclock - 1
|
||||
//assert (val < 0x400)
|
||||
//cpm_set_pixdiv (val)
|
||||
//cpm_set_pixdiv (12)
|
||||
|
||||
val = cpm_get_pllout2 () / (pixclock * 3) - 1
|
||||
assert (val < 0x20)
|
||||
//cpm_set_ldiv (val)
|
||||
// Update dividers.
|
||||
//CPM_CPCCR |= CPM_CPCCR_CE
|
||||
#else
|
||||
#error "Unknown board"
|
||||
#endif
|
||||
|
||||
cpm_start_lcd ()
|
||||
|
||||
#ifdef NANONOTE
|
||||
// Reset the controller.
|
||||
write_reg (BACKLIGHT1, 0x1e)
|
||||
// Enable display.
|
||||
write_reg (BACKLIGHT1, 0x5e)
|
||||
// Set data to rgbrgbrgb input, with a delta color filter.
|
||||
write_reg (COLOR, 0x01)
|
||||
#endif
|
||||
|
||||
LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM
|
||||
LCD_CFG = cfg
|
||||
LCD_HSYNC = hpe
|
||||
LCD_VSYNC = vpe
|
||||
LCD_VAT = (ht << 16) | vt
|
||||
LCD_DAH = (hds << 16) | hde
|
||||
LCD_DAV = (vds << 16) | vde
|
||||
LCD_DA0 = physical_descriptor
|
||||
LCD_STATE = 0
|
||||
LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM | LCD_CTRL_ENA
|
||||
|
||||
static void putchar (unsigned x, unsigned y, unsigned ch):
|
||||
if ch < 32 || ch > 126:
|
||||
ch = 127
|
||||
ch -= 32
|
||||
for unsigned k = 0; k < 6; ++k:
|
||||
for unsigned r = 0; r < 8; ++r:
|
||||
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * h + x * 6 + k] = charset[ch][r][k] * 0x00010101
|
||||
|
||||
|
||||
static unsigned log_x = LOG_X_BASE, log_y = LOG_Y_BASE
|
||||
static void inc_logx ():
|
||||
if ++log_x >= h / 6:
|
||||
log_x = LOG_X_BASE
|
||||
if ++log_y >= v / 8:
|
||||
log_y = LOG_Y_BASE
|
||||
|
||||
static void log_char (unsigned ch):
|
||||
switch ch:
|
||||
case '\n':
|
||||
while log_x < h / 6:
|
||||
putchar (log_x++, log_y, ' ')
|
||||
inc_logx ()
|
||||
break
|
||||
default:
|
||||
putchar (log_x, log_y, ch)
|
||||
inc_logx ()
|
||||
|
||||
static void log_str (char const *str):
|
||||
while *str:
|
||||
log_char (*str++)
|
||||
|
||||
static void log_num (Iris::Num n):
|
||||
char const *encode = "0123456789abcdef"
|
||||
log_char ('[')
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
log_char (encode[(n.h >> (4 * (7 - i))) & 0xf])
|
||||
log_char (' ')
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
log_char (encode[(n.l >> (4 * (7 - i))) & 0xf])
|
||||
log_char (']')
|
||||
|
||||
static void log_msg ():
|
||||
log_str ("prot:")
|
||||
log_num (Iris::recv.protected_data)
|
||||
log_str ("data:")
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
log_num (Iris::recv.data[i])
|
||||
log_char ('\n')
|
||||
|
||||
enum captype:
|
||||
LOG = 1
|
||||
BACKLIGHT
|
||||
LCD
|
||||
|
||||
static unsigned spot (unsigned x, unsigned y, unsigned cx, unsigned cy):
|
||||
unsigned dx2 = (x - cx) * (x - cx)
|
||||
unsigned dy2 = (y - cy) * (y - cy)
|
||||
unsigned d2 = dx2 + dy2
|
||||
unsigned l = 120
|
||||
if d2 >= l * l:
|
||||
return 0
|
||||
return ((l * l - d2 - 1) << 8) / (l * l)
|
||||
|
||||
static unsigned pages
|
||||
static Descriptor descriptor __attribute__ ((aligned (16)))
|
||||
static bool is_on
|
||||
|
||||
static unsigned create (Iris::Memory mem):
|
||||
unsigned physical = mem.alloc_range (pages)
|
||||
unsigned address = 0x15000
|
||||
if physical & ~PAGE_MASK:
|
||||
Iris::panic (0, "can't allocate framebuffer")
|
||||
assert (physical & PAGE_MASK && ~physical)
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
Iris::Page p = mem.create_page ()
|
||||
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
|
||||
if address != ~0:
|
||||
mem.map (p, address + (i << PAGE_BITS))
|
||||
Iris::free_cap (p)
|
||||
return physical
|
||||
|
||||
static void destroy (unsigned physical, Iris::Memory mem):
|
||||
unsigned address = 0x15000
|
||||
if physical == ~0:
|
||||
Iris::panic (0, "unable to destroy framebuffer with wrong cap0")
|
||||
if descriptor.frame == physical && is_on:
|
||||
lcd_clr_ena ()
|
||||
#ifdef NANONOTE
|
||||
write_reg (BACKLIGHT1, 0x5e)
|
||||
#endif
|
||||
if address != ~0:
|
||||
for unsigned i = 0; i < pages; ++i:
|
||||
Iris::Page p = mem.mapping ((void *)(address + (i << PAGE_BITS)))
|
||||
mem.destroy (p)
|
||||
Iris::free_cap (p)
|
||||
|
||||
static void use (unsigned physical):
|
||||
if physical == ~0:
|
||||
Iris::panic (0, "unable to use framebuffer with wrong cap0")
|
||||
bool was_unused = descriptor.frame == 0
|
||||
descriptor.frame = physical
|
||||
unsigned dptr = (unsigned)&descriptor
|
||||
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
|
||||
if was_unused && is_on:
|
||||
lcd_set_ena ()
|
||||
#ifdef NANONOTE:
|
||||
write_reg (BACKLIGHT1, 0x5f)
|
||||
#endif
|
||||
|
||||
static void unuse (unsigned physical):
|
||||
if physical == ~0:
|
||||
Iris::panic (0, "unable to unuse framebuffer with wrong cap0")
|
||||
if descriptor.frame == physical:
|
||||
lcd_clr_ena ()
|
||||
#ifdef NANONOTE
|
||||
write_reg (BACKLIGHT1, 0x5e)
|
||||
#endif
|
||||
descriptor.frame = 0
|
||||
|
||||
Iris::Num start ():
|
||||
Iris::schedule ()
|
||||
map_lcd ()
|
||||
map_cpm ()
|
||||
#ifdef NANONOTE
|
||||
map_gpio ()
|
||||
#endif
|
||||
|
||||
pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
|
||||
unsigned physical = 0
|
||||
Iris::Page p = Iris::my_memory.mapping (&descriptor)
|
||||
unsigned paddr = p.physical_address ()
|
||||
physical_descriptor = paddr + ((unsigned)&descriptor & ~PAGE_MASK)
|
||||
Iris::free_cap (p)
|
||||
descriptor.next = physical_descriptor
|
||||
descriptor.frame = physical
|
||||
descriptor.id = 0xdeadbeef
|
||||
descriptor.cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT)
|
||||
unsigned dptr = (unsigned)&descriptor
|
||||
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
|
||||
reset ()
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
#endif
|
||||
|
||||
// Register the backlight device.
|
||||
Iris::Setting backlight = Iris::my_receiver.create_capability (BACKLIGHT)
|
||||
Iris::my_parent.provide_capability <Iris::Setting> (backlight.copy ())
|
||||
Iris::free_cap (backlight)
|
||||
|
||||
// Register the display device.
|
||||
Iris::Display display = Iris::my_receiver.create_capability (LCD)
|
||||
Iris::my_parent.provide_capability <Iris::Display> (display.copy ())
|
||||
Iris::free_cap (display)
|
||||
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
Iris::Cap eof_cb
|
||||
bool have_eof = false
|
||||
is_on = true
|
||||
while true:
|
||||
Iris::wait ()
|
||||
//log_msg ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case 0:
|
||||
have_eof = false
|
||||
eof_cb.invoke ()
|
||||
Iris::free_cap (eof_cb)
|
||||
break
|
||||
#if defined (TRENDTAC)
|
||||
case LOG:
|
||||
log_char (Iris::recv.data[0].l)
|
||||
break
|
||||
#endif
|
||||
case BACKLIGHT:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Setting::SET:
|
||||
// TODO
|
||||
unsigned state = Iris::recv.data[1].l
|
||||
if !state:
|
||||
#if defined (NANONOTE)
|
||||
if is_on:
|
||||
write_reg (BACKLIGHT1, 0x5e)
|
||||
is_on = false
|
||||
#else
|
||||
#endif
|
||||
else:
|
||||
#if defined (NANONOTE)
|
||||
if !is_on:
|
||||
write_reg (BACKLIGHT1, 0x5f)
|
||||
is_on = true
|
||||
#else
|
||||
#endif
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Setting::GET_RANGE:
|
||||
Iris::recv.reply.invoke (~0)
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "invalid operation for backlight")
|
||||
break
|
||||
break
|
||||
case LCD:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Display::SET_EOF_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
if have_eof:
|
||||
Iris::free_cap (eof_cb)
|
||||
Iris::panic (0, "replacing eof_cb")
|
||||
else:
|
||||
lcd_clr_eof ()
|
||||
Iris::register_interrupt (IRQ_LCD)
|
||||
have_eof = true
|
||||
eof_cb = arg
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::Display::MAP_FB:
|
||||
unsigned addr = Iris::recv.data[1].l
|
||||
unsigned use = Iris::recv.data[0].h
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Memory mem = Iris::get_arg ()
|
||||
unsigned physical = mem.alloc_range (pages)
|
||||
assert (physical & PAGE_MASK && ~physical)
|
||||
Iris::Caps ret = mem.create_caps (pages / 63 + 1)
|
||||
unsigned slot = ret.use ()
|
||||
for unsigned c = 0; c < pages / 63 + 1; ++c:
|
||||
Iris::Caps caps (Iris::Cap (slot, c))
|
||||
unsigned num = pages - 63 * c >= 63 ? 63 : pages - 63 * c
|
||||
Iris::set_recv_arg (caps)
|
||||
mem.create_caps (num)
|
||||
unsigned slot2 = caps.use ()
|
||||
for unsigned i = 0; i < num; ++i:
|
||||
Iris::Page p = Iris::Cap (slot2, i)
|
||||
Iris::set_recv_arg (p)
|
||||
mem.create_page ()
|
||||
p.alloc_physical (physical + ((63 * c + i) << PAGE_BITS), false, true)
|
||||
mem.map (p, addr + ((63 * c + i) << PAGE_BITS))
|
||||
Iris::free_slot (slot2)
|
||||
Iris::free_slot (slot)
|
||||
reply.invoke (0, 0, ret.copy ())
|
||||
Iris::free_cap (ret)
|
||||
Iris::free_cap (mem)
|
||||
Iris::free_cap (reply)
|
||||
if !use:
|
||||
break
|
||||
bool was_unused = descriptor.frame == 0
|
||||
descriptor.frame = physical
|
||||
unsigned dptr = (unsigned)&descriptor
|
||||
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
|
||||
if was_unused && is_on:
|
||||
lcd_set_ena ()
|
||||
#ifdef NANONOTE:
|
||||
write_reg (BACKLIGHT1, 0x5f)
|
||||
#endif
|
||||
break
|
||||
case Iris::Display::UNMAP_FB:
|
||||
Iris::panic (0, "unmap_fb isn't implemented yet")
|
||||
case Iris::Display::GET_INFO:
|
||||
Iris::panic (0, "get_info isn't implemented yet.")
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid operation for lcd")
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "invalid operation type for lcd")
|
||||
break
|
||||
180
userspace/nanonote/nand.ccp
Normal file
180
userspace/nanonote/nand.ccp
Normal file
@@ -0,0 +1,180 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/nand.ccp: NAND 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"
|
||||
|
||||
#define debug Iris::debug
|
||||
#define DELAY Iris::schedule
|
||||
#include "nand.hh"
|
||||
#undef debug
|
||||
|
||||
static unsigned *cache
|
||||
static bool dirty
|
||||
static unsigned current_block
|
||||
|
||||
static void sync ():
|
||||
//Iris::debug ("erasing %x\n", current_block << block_bits)
|
||||
erase (current_block << block_bits)
|
||||
for unsigned p = 0; p < 1 << (block_bits - page_bits); ++p:
|
||||
write ((current_block << block_bits) + (p << page_bits), (char *)&cache[p << (page_bits - 2)])
|
||||
|
||||
static void read_block (unsigned b):
|
||||
if b == current_block:
|
||||
return
|
||||
if current_block != ~0 && dirty:
|
||||
sync ()
|
||||
current_block = b
|
||||
//kdebug ("setting current block to ")
|
||||
//kdebug_num (b)
|
||||
//kdebug ("\n")
|
||||
for unsigned p = 0; p < 1 << (block_bits - 9); ++p:
|
||||
read ((b << block_bits) + (p << 9), (char *)&cache[p << (9 - 2)])
|
||||
dirty = false
|
||||
|
||||
Iris::Num start ():
|
||||
map_emc ()
|
||||
map_gpio ()
|
||||
|
||||
// Arbitrary addresses where the pages are mapped.
|
||||
command = (volatile char *)0x15000
|
||||
address = (volatile char *)0x16000
|
||||
data = (volatile char *)0x17000
|
||||
|
||||
Iris::Page data_page = Iris::my_memory.create_page ()
|
||||
Iris::Page command_page = Iris::my_memory.create_page ()
|
||||
Iris::Page address_page = Iris::my_memory.create_page ()
|
||||
|
||||
unsigned base = 0x18000000
|
||||
data_page.alloc_physical (base, false, false)
|
||||
command_page.alloc_physical (base + 0x8000, false, false)
|
||||
address_page.alloc_physical (base + 0x10000, false, false)
|
||||
|
||||
Iris::my_memory.map (data_page, (unsigned)data)
|
||||
Iris::my_memory.map (command_page, (unsigned)command)
|
||||
Iris::my_memory.map (address_page, (unsigned)address)
|
||||
|
||||
Iris::free_cap (data_page)
|
||||
Iris::free_cap (command_page)
|
||||
Iris::free_cap (address_page)
|
||||
|
||||
reset ()
|
||||
|
||||
current_block = ~0
|
||||
dirty = false
|
||||
cache = (unsigned *)0x40000000
|
||||
for unsigned p = 0; p < 1 << (block_bits - PAGE_BITS); ++p:
|
||||
Iris::Page page = Iris::my_memory.create_page ()
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (page, (unsigned)cache + (p << PAGE_BITS))
|
||||
Iris::free_cap (page)
|
||||
Iris::Page tmp = Iris::my_memory.create_page ()
|
||||
tmp.set_flags (Iris::Page::PAYING)
|
||||
unsigned *tmp_addr = (unsigned *)0x3ffff000
|
||||
Iris::my_memory.map (tmp, (unsigned)tmp_addr)
|
||||
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (0)
|
||||
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Block::GET_SIZE:
|
||||
if size_bits > 32:
|
||||
Iris::recv.reply.invoke (Iris::Num (0, 1 << (size_bits - 32)))
|
||||
else:
|
||||
Iris::recv.reply.invoke (1 << size_bits)
|
||||
break
|
||||
case Iris::Block::GET_ALIGN_BITS:
|
||||
Iris::recv.reply.invoke (9)
|
||||
break
|
||||
case Iris::Block::GET_BLOCK:
|
||||
unsigned row = Iris::recv.data[1].value () >> 9
|
||||
unsigned block = row >> (block_bits - 9)
|
||||
row &= (1 << (block_bits - 9)) - 1
|
||||
unsigned offset = Iris::recv.data[0].h & 0xe00
|
||||
unsigned size = Iris::recv.data[0].h >> 16
|
||||
if size + offset >= 0x1000:
|
||||
size = 0x1000 - offset
|
||||
#if 0
|
||||
kdebug ("get ")
|
||||
kdebug_num (block)
|
||||
kdebug (":")
|
||||
kdebug_num (row)
|
||||
kdebug ("+")
|
||||
kdebug_num (size)
|
||||
kdebug ("@")
|
||||
kdebug_num (offset)
|
||||
kdebug ("\n")
|
||||
#endif
|
||||
read_block (block)
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Page page = Iris::get_arg ()
|
||||
page.share (tmp)
|
||||
tmp.set_flags (Iris::Page::FRAME)
|
||||
for unsigned t = 0; t < size >> 2; ++t:
|
||||
tmp_addr[(offset >> 2) + t] = cache[t + (row << (9 - 2))]
|
||||
tmp.set_flags (0, Iris::Page::FRAME)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (page)
|
||||
break
|
||||
case Iris::WBlock::SET_BLOCK:
|
||||
unsigned row = Iris::recv.data[1].value () >> 9
|
||||
unsigned block = row >> (block_bits - 9)
|
||||
row &= (1 << (block_bits - 9)) - 1
|
||||
unsigned offset = Iris::recv.data[0].h & 0xe00
|
||||
unsigned size = Iris::recv.data[0].h >> 16
|
||||
if size + offset >= 0x1000:
|
||||
size = 0x1000 - offset
|
||||
#if 0
|
||||
kdebug ("set ")
|
||||
kdebug_num (block)
|
||||
kdebug (":")
|
||||
kdebug_num (row)
|
||||
kdebug ("+")
|
||||
kdebug_num (size)
|
||||
kdebug ("@")
|
||||
kdebug_num (offset)
|
||||
kdebug ("\n")
|
||||
#endif
|
||||
//kdebug_num (current_block)
|
||||
//kdebug ("/")
|
||||
read_block (block)
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Page page = Iris::get_arg ()
|
||||
page.share (tmp)
|
||||
tmp.set_flags (Iris::Page::FRAME)
|
||||
for unsigned t = 0; t < size; t += 4:
|
||||
cache[(offset + t + (row << 9)) >> 2] = tmp_addr[(offset + t) >> 2]
|
||||
tmp.set_flags (0, Iris::Page::FRAME)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (page)
|
||||
dirty = true
|
||||
//kdebug_num (current_block)
|
||||
//kdebug ("!")
|
||||
break
|
||||
case Iris::WBlock::TRUNCATE:
|
||||
default:
|
||||
Iris::recv.reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
break
|
||||
153
userspace/nanonote/rtc.ccp
Normal file
153
userspace/nanonote/rtc.ccp
Normal file
@@ -0,0 +1,153 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/rtc.ccp: real-time clock driver.
|
||||
// Copyright 2010 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"
|
||||
|
||||
static Iris::Font font
|
||||
|
||||
static void ready ():
|
||||
while !rtc_write_ready ():
|
||||
Iris::schedule ()
|
||||
|
||||
static unsigned get_second ():
|
||||
ready ()
|
||||
unsigned ret = rtc_get_second ()
|
||||
unsigned r2
|
||||
while true:
|
||||
ready ()
|
||||
r2 = rtc_get_second ()
|
||||
if ret == r2:
|
||||
return ret
|
||||
kdebug ("ret != r2\n")
|
||||
ret = r2
|
||||
|
||||
Iris::Num start ():
|
||||
map_cpm ()
|
||||
map_rtc ()
|
||||
cpm_start_rtc ()
|
||||
ready ()
|
||||
rtc_enabled ()
|
||||
if rtc_get_scratch_pattern () != 0xbeefface:
|
||||
ready ()
|
||||
rtc_set_nc1Hz_val (RTC_CLOCK)
|
||||
ready ()
|
||||
rtc_set_adjc_val (0)
|
||||
ready ()
|
||||
rtc_set_second (0)
|
||||
ready ()
|
||||
rtc_set_alarm_second (0)
|
||||
ready ()
|
||||
rtc_set_scratch_pattern (0xbeefface)
|
||||
ready ()
|
||||
rtc_disable_alarm ()
|
||||
ready ()
|
||||
rtc_clear_alarm_flag ()
|
||||
ready ()
|
||||
rtc_enable_alarm_irq ()
|
||||
ready ()
|
||||
rtc_disable_1Hz_irq ()
|
||||
ready ()
|
||||
rtc_set_hwfcr_val (0x1e0)
|
||||
ready ()
|
||||
rtc_set_hrcr_val (0xfe0)
|
||||
ready ()
|
||||
rtc_disable_alarm_wakeup ()
|
||||
Iris::RTC self = Iris::my_receiver.create_capability (1)
|
||||
Iris::my_parent.provide_capability <Iris::RTC> (self.copy ())
|
||||
Iris::free_cap (self)
|
||||
Iris::my_parent.init_done ()
|
||||
bool have_interrupt = false
|
||||
Iris::Cap interrupt
|
||||
while true:
|
||||
Iris::wait ()
|
||||
if Iris::recv.protected_data.l == 0:
|
||||
// Interrupt.
|
||||
ready ()
|
||||
rtc_disable_alarm ()
|
||||
ready ()
|
||||
rtc_disable_alarm_wakeup ()
|
||||
if have_interrupt:
|
||||
interrupt.invoke (0)
|
||||
Iris::free_cap (interrupt)
|
||||
have_interrupt = false
|
||||
continue
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::RTC::SETUP:
|
||||
ready ()
|
||||
rtc_set_nc1Hz_val (Iris::recv.data[1].l)
|
||||
ready ()
|
||||
rtc_set_adjc_val (Iris::recv.data[1].h)
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::RTC::GET_TIME:
|
||||
ready ()
|
||||
Iris::recv.reply.invoke (rtc_get_second ())
|
||||
Iris::recv.reply.invoke (0)
|
||||
break
|
||||
case Iris::RTC::SET_TIME:
|
||||
ready ()
|
||||
rtc_set_second (Iris::recv.data[1].l)
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::RTC::GET_ALARM:
|
||||
ready ()
|
||||
Iris::recv.reply.invoke (rtc_get_alarm_second (), rtc_alarm_is_enabled ())
|
||||
Iris::recv.reply.invoke (0)
|
||||
break
|
||||
case Iris::RTC::UNSET_ALARM:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
if have_interrupt:
|
||||
have_interrupt = false
|
||||
interrupt.invoke (~0)
|
||||
Iris::free_cap (interrupt)
|
||||
Iris::unregister_interrupt (IRQ_RTC)
|
||||
ready ()
|
||||
rtc_disable_alarm ()
|
||||
ready ()
|
||||
rtc_disable_alarm_wakeup ()
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
case Iris::RTC::SET_ALARM:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
unsigned alarm = Iris::recv.data[1].l
|
||||
if have_interrupt:
|
||||
Iris::debug ("not registering irq\n")
|
||||
interrupt.invoke (~0)
|
||||
Iris::free_cap (interrupt)
|
||||
else:
|
||||
Iris::debug ("registering irq\n")
|
||||
Iris::register_interrupt (IRQ_RTC)
|
||||
interrupt = arg
|
||||
have_interrupt = true
|
||||
ready ()
|
||||
rtc_set_alarm_second (alarm)
|
||||
ready ()
|
||||
rtc_clear_alarm_flag ()
|
||||
ready ()
|
||||
rtc_enable_alarm ()
|
||||
ready ()
|
||||
rtc_enable_alarm_wakeup ()
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "invalid rtc request")
|
||||
return 0
|
||||
590
userspace/nanonote/sdmmc.ccp
Normal file
590
userspace/nanonote/sdmmc.ccp
Normal file
@@ -0,0 +1,590 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/sd+mmc.ccp: sd+mmc 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 Mmc:
|
||||
public:
|
||||
enum Response_type:
|
||||
NONE = MSC_CMDAT_RESPONSE_NONE
|
||||
RD_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_READ
|
||||
WR_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE
|
||||
R1 = MSC_CMDAT_RESPONSE_R1
|
||||
R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY
|
||||
R2 = MSC_CMDAT_RESPONSE_R2
|
||||
R3 = MSC_CMDAT_RESPONSE_R3
|
||||
R4 = MSC_CMDAT_RESPONSE_R4
|
||||
R5 = MSC_CMDAT_RESPONSE_R5
|
||||
R6 = MSC_CMDAT_RESPONSE_R6
|
||||
R7 = MSC_CMDAT_RESPONSE_R7
|
||||
static unsigned const POWER_PORT = 3
|
||||
static unsigned const POWER_PIN = 2
|
||||
struct CID:
|
||||
unsigned mid
|
||||
char oid[2]
|
||||
char pnm[5]
|
||||
unsigned prv
|
||||
unsigned psn
|
||||
unsigned year
|
||||
unsigned month
|
||||
struct CSD:
|
||||
unsigned c_size
|
||||
unsigned c_size_mult
|
||||
unsigned read_bl_len, write_bl_len
|
||||
bool copy
|
||||
bool perm_write_protect
|
||||
bool tmp_write_protect
|
||||
bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL)
|
||||
void check_sd ()
|
||||
void check_sdmem ()
|
||||
void check_mmc ()
|
||||
public:
|
||||
void reset ()
|
||||
void detect ()
|
||||
void release ()
|
||||
void interrupt ()
|
||||
CID const &get_cid ():
|
||||
return cid
|
||||
unsigned get_num_blocks ():
|
||||
return num_blocks
|
||||
unsigned get_read_block_size ():
|
||||
return read_block_size
|
||||
unsigned get_block_bits ():
|
||||
return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len
|
||||
void write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
|
||||
void read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
|
||||
void wait_write ()
|
||||
void add_cb (Iris::Listitem item):
|
||||
cb_list.add_item (item)
|
||||
private:
|
||||
void set_block (unsigned block)
|
||||
unsigned current_block_num
|
||||
bool dirty
|
||||
unsigned *current_block
|
||||
unsigned rca
|
||||
bool have_sdmem, have_io
|
||||
bool hc
|
||||
CID cid
|
||||
CSD csd
|
||||
unsigned num_blocks, read_block_size
|
||||
Iris::Page buffer_page
|
||||
Iris::List cb_list
|
||||
static unsigned const buffer = 0x15000
|
||||
|
||||
bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response):
|
||||
MSC_CMD = cmd
|
||||
MSC_ARG = arg
|
||||
MSC_CMDAT = response_type
|
||||
MSC_IMASK = ~MSC_IMASK_END_CMD_RES
|
||||
Iris::register_interrupt (IRQ_MSC)
|
||||
msc_start_op ()
|
||||
Iris::wait_for_interrupt ()
|
||||
MSC_IMASK = ~0
|
||||
//kdebug ("cmd: ")
|
||||
//kdebug_num (cmd)
|
||||
unsigned stat = MSC_STAT
|
||||
//kdebug (", stat: ")
|
||||
//kdebug_num (stat)
|
||||
//kdebug ("\n")
|
||||
if stat & MSC_STAT_CRC_RES_ERR:
|
||||
Iris::panic (0, "crc error in mmc response")
|
||||
return false
|
||||
if stat & MSC_STAT_TIME_OUT_RES:
|
||||
kdebug ("time out waiting for mmc response\n")
|
||||
MSC_IREG = MSC_IREG_END_CMD_RES
|
||||
return false
|
||||
if response_type == R2:
|
||||
unsigned d = MSC_RES
|
||||
if d >> 8 != 0x3f:
|
||||
Iris::panic (d, "invalid r2 response")
|
||||
if cmd == 3:
|
||||
// Read out result.
|
||||
cid.mid = d & 0xff
|
||||
d = MSC_RES
|
||||
cid.oid[0] = d >> 8
|
||||
cid.oid[1] = d & 0xff
|
||||
d = MSC_RES
|
||||
cid.pnm[0] = d >> 8
|
||||
cid.pnm[1] = d & 0xff
|
||||
d = MSC_RES
|
||||
cid.pnm[2] = d >> 8
|
||||
cid.pnm[3] = d & 0xff
|
||||
d = MSC_RES
|
||||
cid.pnm[4] = d >> 8
|
||||
cid.prv = d & 0xff
|
||||
d = MSC_RES
|
||||
cid.psn = d << 16
|
||||
d = MSC_RES
|
||||
cid.psn |= d
|
||||
d = MSC_RES
|
||||
cid.year = 2000 + (d >> 4 & 0xff)
|
||||
cid.month = d & 0xf
|
||||
#if 1
|
||||
Iris::debug ("CID: mid=%x, oid=%x %x, pnm=%x %x %x %x %x, prv=%x, psn=%x, year=%x, month=%x\n", cid.mid, cid.oid[0], cid.oid[1], cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cid.prv, cid.psn, cid.year, cid.month)
|
||||
#endif
|
||||
else:
|
||||
// Header (8) 1.0 1.0
|
||||
// Read out csd.
|
||||
// Ignore csd_structure. 2 (+ 6) 1.0 2.0 ***
|
||||
d = MSC_RES
|
||||
// Ignore taac and nsac. 8 + 8 2.0 4.0 ***
|
||||
d = MSC_RES
|
||||
// Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 ***
|
||||
d = MSC_RES
|
||||
// Ignore rest of ccc. 4/12 0.4 6.4
|
||||
// 4 0.4 7.0
|
||||
csd.read_bl_len = (d >> 8) & 0xf
|
||||
// Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6
|
||||
// 2/12 0.2 8.0 ***
|
||||
csd.c_size = (d & 0x0003) << 10
|
||||
d = MSC_RES
|
||||
// 10/12 1.2 9.2
|
||||
csd.c_size |= d >> 6
|
||||
// Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 ***
|
||||
d = MSC_RES
|
||||
// Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6
|
||||
// 3 0.3 11.1
|
||||
csd.c_size_mult = (d >> 7) & 0x7
|
||||
// Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 ***
|
||||
d = MSC_RES
|
||||
// Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6
|
||||
// 2/4 0.4 14.0 ***
|
||||
csd.write_bl_len = (d << 2) & 0xc
|
||||
d = MSC_RES
|
||||
// 2/4 0.2 14.2
|
||||
csd.write_bl_len |= (d >> 14) & 0x3
|
||||
// Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1
|
||||
// 1 0.1 15.2
|
||||
csd.copy = d & 0x40
|
||||
// 1 0.1 15.3
|
||||
csd.perm_write_protect = d & 0x20
|
||||
// 1 0.1 15.4
|
||||
csd.tmp_write_protect = d & 0x10
|
||||
// Ignore file_format. 2 (+ 2) 0.4 16.0 ***
|
||||
read_block_size = hc ? 512 : 1 << csd.read_bl_len
|
||||
num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2)
|
||||
if hc:
|
||||
if csd.read_bl_len < 9:
|
||||
num_blocks >>= 9 - csd.read_bl_len
|
||||
else:
|
||||
num_blocks <<= csd.read_bl_len - 9
|
||||
#if 1
|
||||
Iris::debug ("CSD: size=%x<<%x, r/w len=%x/%x, %s, %s, %s\n", csd.c_size, csd.c_size_mult, csd.read_bl_len, csd.write_bl_len, csd.copy ? "copy" : "no copy", csd.perm_write_protect ? "fixed write protect" : "no fixed write protect", csd.tmp_write_protect ? "write protect" : "no write protect")
|
||||
#endif
|
||||
unsigned c_size
|
||||
unsigned c_size_mult
|
||||
unsigned read_bl_len, write_bl_len
|
||||
bool copy
|
||||
bool perm_write_protect
|
||||
bool tmp_write_protect
|
||||
else if response_type != NONE:
|
||||
unsigned r = MSC_RES
|
||||
if response_type == R3:
|
||||
if r >> 8 != 0x3f:
|
||||
Iris::panic (r, "r3 response was not 3f")
|
||||
else if r >> 8 != cmd:
|
||||
kdebug ("stat: ")
|
||||
kdebug_num (MSC_STAT)
|
||||
kdebug ("; response: ")
|
||||
kdebug_num (r)
|
||||
kdebug ("; cmd: ")
|
||||
kdebug_num (cmd)
|
||||
Iris::panic (r, "response doesn't match command")
|
||||
r <<= 24
|
||||
r |= MSC_RES << 8
|
||||
r |= MSC_RES & 0xff
|
||||
if response:
|
||||
*response = r
|
||||
else:
|
||||
//kdebug ("extra response fifo read: ")
|
||||
//for unsigned i = 0; i < 9; ++i:
|
||||
//kdebug (" ")
|
||||
//kdebug_num (MSC_RES, 4)
|
||||
//kdebug ("\n")
|
||||
MSC_IREG = MSC_IREG_END_CMD_RES
|
||||
return true
|
||||
|
||||
void Mmc::reset ():
|
||||
current_block_num = ~0
|
||||
dirty = false
|
||||
cb_list = Iris::my_memory.create_list ()
|
||||
current_block = (unsigned *)(buffer + PAGE_SIZE)
|
||||
// Create a buffer to use for data transfer.
|
||||
buffer_page = Iris::my_memory.create_page ()
|
||||
Iris::my_memory.map (buffer_page, buffer)
|
||||
// Reset all state, by faking a release event.
|
||||
release ()
|
||||
// Enable 25 MHz clock to msc.
|
||||
CPM_MSCCDR = 13
|
||||
cpm_start_msc ()
|
||||
// Enable msc pins.
|
||||
gpio_as_msc ()
|
||||
// Disable power to card.
|
||||
gpio_as_gpio (POWER_PORT, 1 << POWER_PIN)
|
||||
gpio_as_output (POWER_PORT, 1 << POWER_PIN)
|
||||
gpio_disable_pull (POWER_PORT, 1 << POWER_PIN)
|
||||
gpio_set (POWER_PORT, 1 << POWER_PIN)
|
||||
|
||||
// Stop the clock.
|
||||
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
|
||||
while MSC_STAT & MSC_STAT_CLK_EN:
|
||||
//kdebug (",")
|
||||
Iris::sleep (1)
|
||||
|
||||
// Reset controller and inserted devices.
|
||||
MSC_STRPCL = MSC_STRPCL_RESET
|
||||
while MSC_STAT & MSC_STAT_IS_RESETTING:
|
||||
//kdebug (":")
|
||||
Iris::sleep (1)
|
||||
|
||||
// Initialize registers.
|
||||
MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_1
|
||||
MSC_RESTO = 64
|
||||
MSC_RDTO = ~0
|
||||
MSC_BLKLEN = 0x200
|
||||
MSC_NOB = 0
|
||||
MSC_IREG = ~0
|
||||
MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ)
|
||||
MSC_ARG = 0
|
||||
|
||||
// Start the clock.
|
||||
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
|
||||
// Set cards, if any, to idle.
|
||||
send (0, 0, NONE)
|
||||
|
||||
// Reset SDIO device, if any. Don't do this, because it breaks for some reason.
|
||||
//send (52, 0x88000c08, R5)
|
||||
|
||||
void Mmc::check_mmc ():
|
||||
//kdebug ("checking mmc\n")
|
||||
// 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
|
||||
// 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
|
||||
// 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
|
||||
// 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
|
||||
// 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
|
||||
// 6. If the response timeout occurs, goto 9.
|
||||
// 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
|
||||
|
||||
void Mmc::check_sdmem ():
|
||||
kdebug ("checking sdmem\n")
|
||||
// 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
|
||||
// 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
|
||||
unsigned code
|
||||
hc = false
|
||||
if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa:
|
||||
kdebug ("hc\n")
|
||||
hc = true
|
||||
if !send (55, 0, R1, &code):
|
||||
check_mmc ()
|
||||
return
|
||||
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
|
||||
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
|
||||
check_mmc ()
|
||||
return
|
||||
// 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
|
||||
// 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
|
||||
unsigned retries = 100
|
||||
while !(code & (1 << 31)) && --retries:
|
||||
if !send (55, 0, R1, &code):
|
||||
return
|
||||
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
|
||||
return
|
||||
Iris::sleep (1)
|
||||
if !(code & (1 << 31)):
|
||||
Iris::panic (code, "card fails to finish setting up")
|
||||
// 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
|
||||
if !send (2, 0, R2):
|
||||
Iris::panic (0, "card failed to send CID")
|
||||
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
|
||||
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
|
||||
rca = 0
|
||||
while !rca:
|
||||
if !send (3, 0, R6, &rca):
|
||||
Iris::panic (0, "card failed to provide rca")
|
||||
rca &= 0xffff0000
|
||||
kdebug ("received rca ")
|
||||
kdebug_num (rca >> 16, 4)
|
||||
kdebug ("\n")
|
||||
have_sdmem = true
|
||||
|
||||
void Mmc::check_sd ():
|
||||
//kdebug ("checking sdio\n")
|
||||
if !send (0, 0, NONE):
|
||||
Iris::panic (0, "unable to reset cards?")
|
||||
// 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
|
||||
// 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
|
||||
unsigned code
|
||||
if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)):
|
||||
check_sdmem ()
|
||||
return
|
||||
// 4. If C-bit in the response is ready (the initialization has finished), go to 6.
|
||||
// 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
|
||||
while !(code & (1 << 31)):
|
||||
if !send (5, 1 << 20, R4, &code):
|
||||
Iris::panic (0, "invalid response to cmd 5")
|
||||
// 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else it is only a SDIO card.
|
||||
// 7. If it is a combo card, go to check SDMEM to initialize the memory part.
|
||||
have_io = true
|
||||
if code & (1 << 27):
|
||||
check_sdmem ()
|
||||
return
|
||||
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response.
|
||||
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
|
||||
rca = 0
|
||||
while rca == 0:
|
||||
if !send (3, 0, R6, &rca):
|
||||
Iris::panic (0, "unable to set rca")
|
||||
rca &= 0xffff0000
|
||||
check_mmc ()
|
||||
|
||||
void Mmc::detect ():
|
||||
kdebug ("mmc detect\n")
|
||||
gpio_clear (POWER_PORT, 1 << POWER_PIN)
|
||||
check_sd ()
|
||||
check_mmc ()
|
||||
if have_sdmem:
|
||||
if !send (9, rca, R2):
|
||||
Iris::panic (0, "unable to request csd")
|
||||
if !send (7, rca, R1B):
|
||||
Iris::panic (0, "unable to select sdmem")
|
||||
kdebug ("found device; size = ")
|
||||
kdebug_num (num_blocks)
|
||||
kdebug (" * ")
|
||||
kdebug_num (read_block_size)
|
||||
kdebug (" = ")
|
||||
kdebug_num (num_blocks * read_block_size)
|
||||
kdebug ("\n")
|
||||
// Set up buffer memory.
|
||||
for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
|
||||
Iris::Page p = Iris::my_memory.create_page ()
|
||||
p.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
Iris::my_memory.map (p, (unsigned)current_block + i)
|
||||
Iris::free_cap (p)
|
||||
Iris::Listitem item = cb_list.get_next ()
|
||||
while item.code != Iris::Cap ().code:
|
||||
Iris::Cap c = cb_list.get_cap (item)
|
||||
c.invoke (0, ~0)
|
||||
Iris::free_cap (c)
|
||||
Iris::Listitem nextitem = cb_list.get_next (item);
|
||||
Iris::free_cap (item)
|
||||
item = nextitem
|
||||
|
||||
void Mmc::release ():
|
||||
kdebug ("mmc release\n")
|
||||
gpio_set (POWER_PORT, 1 << POWER_PIN)
|
||||
have_sdmem = false
|
||||
have_io = false
|
||||
read_block_size = 0
|
||||
if num_blocks != 0:
|
||||
for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
|
||||
Iris::Page p = Iris::my_memory.mapping ((void *)((unsigned)current_block + i))
|
||||
Iris::my_memory.destroy (p)
|
||||
Iris::free_cap (p)
|
||||
if dirty:
|
||||
Iris::debug ("Warning: sd/mmc card removed before data was written to it")
|
||||
current_block_num = ~0
|
||||
dirty = false
|
||||
num_blocks = 0
|
||||
Iris::Listitem item = cb_list.get_next ()
|
||||
while item.code != Iris::Cap ().code:
|
||||
Iris::Cap c = cb_list.get_cap (item)
|
||||
c.invoke (0, ~0)
|
||||
Iris::free_cap (c)
|
||||
Iris::Listitem nextitem = cb_list.get_next (item);
|
||||
Iris::free_cap (item)
|
||||
item = nextitem
|
||||
|
||||
void Mmc::interrupt ():
|
||||
kdebug ("mmc interrupt\n")
|
||||
|
||||
void Mmc::set_block (unsigned block):
|
||||
if current_block_num == block:
|
||||
return
|
||||
if dirty && current_block_num != ~0:
|
||||
MSC_NOB = 1
|
||||
MSC_BLKLEN = 1 << csd.write_bl_len
|
||||
if !send (24, (current_block_num << csd.write_bl_len), WR_DATA):
|
||||
Iris::panic (0, "unable to send data")
|
||||
MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ
|
||||
for unsigned a = 0; a < 1 << csd.write_bl_len; a += 4:
|
||||
while MSC_STAT & MSC_STAT_DATA_FIFO_FULL:
|
||||
Iris::register_interrupt (IRQ_MSC)
|
||||
Iris::wait_for_interrupt ()
|
||||
MSC_TXFIFO = current_block[a >> 2]
|
||||
MSC_IMASK = ~0
|
||||
MSC_IREG = MSC_IREG_DATA_TRAN_DONE
|
||||
//kdebug ("done writing page\n")
|
||||
current_block_num = block
|
||||
dirty = false
|
||||
MSC_NOB = 1
|
||||
MSC_BLKLEN = 1 << 9
|
||||
for unsigned a = 0; a < 1 << csd.write_bl_len; a += 1 << 9:
|
||||
if !send (17, (block << csd.write_bl_len) + a, RD_DATA):
|
||||
Iris::panic (0, "unable to request data")
|
||||
MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ
|
||||
for unsigned aa = 0; aa < 1 << 9; aa += 4:
|
||||
while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY:
|
||||
Iris::register_interrupt (IRQ_MSC)
|
||||
Iris::wait_for_interrupt ()
|
||||
current_block[(a + aa) >> 2] = MSC_RXFIFO
|
||||
MSC_IMASK = ~0
|
||||
MSC_IREG = MSC_IREG_DATA_TRAN_DONE
|
||||
//kdebug ("done filling page\n")
|
||||
|
||||
void Mmc::read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
|
||||
if address.value () >> (csd.write_bl_len + 32):
|
||||
Iris::panic (address.h, "page too high: not supported")
|
||||
unsigned block = address.value () >> csd.write_bl_len
|
||||
unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
|
||||
set_block (block)
|
||||
unsigned blockmask = ~((1 << 9) - 1)
|
||||
size &= blockmask
|
||||
offset &= ~PAGE_MASK & ~3
|
||||
if size + offset > PAGE_SIZE:
|
||||
size = PAGE_SIZE - offset
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
page.share (buffer_page)
|
||||
buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
page.set_flags (0, Iris::Page::PAYING)
|
||||
for unsigned i = 0; i < size; i += 4:
|
||||
((unsigned *)buffer)[(offset + i) >> 2] = current_block[(start_pos + i) >> 2]
|
||||
|
||||
void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
|
||||
if address.value () >> (csd.write_bl_len + 32):
|
||||
Iris::panic (address.h, "page too high: not supported")
|
||||
unsigned block = address.value () >> csd.write_bl_len
|
||||
unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
|
||||
set_block (block)
|
||||
unsigned blockmask = ~((1 << 9) - 1)
|
||||
size &= blockmask
|
||||
offset &= ~PAGE_MASK & ~3
|
||||
if size + offset > PAGE_SIZE:
|
||||
size = PAGE_SIZE - offset
|
||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
page.share (buffer_page)
|
||||
buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||
page.set_flags (0, Iris::Page::PAYING)
|
||||
for unsigned i = 0; i < size; i += 4:
|
||||
current_block[(start_pos + i) >> 2] = ((unsigned *)buffer)[(offset + i) >> 2]
|
||||
dirty = true
|
||||
|
||||
void Mmc::wait_write ():
|
||||
MSC_IMASK = ~MSC_IMASK_PRG_DONE
|
||||
while !MSC_STAT & MSC_STAT_PRG_DONE:
|
||||
Iris::register_interrupt (IRQ_MSC)
|
||||
Iris::wait_for_interrupt ()
|
||||
MSC_IREG = MSC_IREG_PRG_DONE
|
||||
|
||||
static Mmc mmc
|
||||
|
||||
enum types:
|
||||
DETECT = 1
|
||||
REQUEST
|
||||
|
||||
Iris::Num start ():
|
||||
map_msc ()
|
||||
map_gpio ()
|
||||
map_cpm ()
|
||||
|
||||
mmc.reset ()
|
||||
|
||||
Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (DETECT)
|
||||
detect.set_cb (cap.copy ())
|
||||
cap.invoke (~0)
|
||||
Iris::free_cap (cap)
|
||||
|
||||
// Get a message from the queue. This is either the "there is no card" message, or the message we just sent.
|
||||
Iris::wait ()
|
||||
if Iris::recv.data[0].l != ~0:
|
||||
// If it was "there is no card", the message we sent is still in the queue.
|
||||
Iris::wait ()
|
||||
else:
|
||||
// Otherwise, there is a card.
|
||||
mmc.detect ()
|
||||
|
||||
cap = Iris::my_receiver.create_capability (REQUEST)
|
||||
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case 0:
|
||||
mmc.interrupt ()
|
||||
break
|
||||
case DETECT:
|
||||
if Iris::recv.data[0].l:
|
||||
mmc.detect ()
|
||||
else:
|
||||
mmc.release ()
|
||||
break
|
||||
case REQUEST:
|
||||
//kdebug ("sd+mmc request ")
|
||||
//kdebug_num (Iris::recv.data[0].l)
|
||||
//kdebug ("\n")
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Block::GET_SIZE:
|
||||
Iris::debug ("get size\n")
|
||||
unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size ()
|
||||
Iris::recv.reply.invoke (size)
|
||||
break
|
||||
case Iris::Block::GET_ALIGN_BITS:
|
||||
Iris::debug ("get align bits\n")
|
||||
Iris::recv.reply.invoke (9)
|
||||
break
|
||||
case Iris::Block::GET_BLOCK:
|
||||
//Iris::debug ("get block\n")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Page page = Iris::get_arg ()
|
||||
mmc.read_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (page)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::WBlock::SET_BLOCK:
|
||||
Iris::debug ("set block\n")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Page page = Iris::get_arg ()
|
||||
mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (page)
|
||||
Iris::free_cap (reply)
|
||||
mmc.wait_write ()
|
||||
break
|
||||
case Iris::Block::SET_CHANGE_CB:
|
||||
Iris::debug ("set change cb\n")
|
||||
Iris::Listitem item = Iris::get_arg ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
mmc.add_cb (item)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (item)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
case Iris::WBlock::TRUNCATE:
|
||||
Iris::debug ("truncate\n")
|
||||
// Fall through: don't support resizing.
|
||||
default:
|
||||
Iris::panic (0, "unexpected event for sd+mmc")
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "unexpected request source for sd+mmc")
|
||||
664
userspace/nanonote/udc.ccp
Normal file
664
userspace/nanonote/udc.ccp
Normal file
@@ -0,0 +1,664 @@
|
||||
#pypp 0
|
||||
// vim: set filetype=cpp : //
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/udc.ccp: USB device controller 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 "iris.hh"
|
||||
#include "devices.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
class Udc:
|
||||
typedef unsigned char u8
|
||||
typedef unsigned short u16
|
||||
typedef unsigned int u32
|
||||
typedef u8 string
|
||||
// The ugly stuff is because pypp doesn't support __attribute__.
|
||||
/**/struct Setup {
|
||||
u8 request_type;
|
||||
u8 request;
|
||||
u16 value;
|
||||
u16 index;
|
||||
u16 length;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Device {
|
||||
static u8 const Type = 1;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 usb_version;
|
||||
u8 dev_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
u8 max_packet_size0;
|
||||
u16 vendor;
|
||||
u16 product;
|
||||
u16 dev_version;
|
||||
string s_manufacturer;
|
||||
string s_product;
|
||||
string s_serial;
|
||||
u8 num_configurations;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Configuration {
|
||||
static u8 const Type = 2;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 total_length;
|
||||
u8 num_interfaces;
|
||||
u8 configuration_value;
|
||||
u8 configuration;
|
||||
u8 attributes;
|
||||
u8 max_power;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Interface {
|
||||
static u8 const Type = 4;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 interface;
|
||||
u8 alternate;
|
||||
u8 num_endpoints;
|
||||
u8 iface_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
string name;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Endpoint {
|
||||
static u8 const Type = 5;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 address;
|
||||
u8 attributes;
|
||||
u16 max_packet_size;
|
||||
u8 interval;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Device_Qualifier {
|
||||
static u8 const Type = 6;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 version;
|
||||
u8 dev_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
u8 max_packet_size0;
|
||||
u8 num_configurations;
|
||||
u8 reserved;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Langs {
|
||||
static u8 const Type = 3;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 lang;
|
||||
} __attribute__ ((packed))
|
||||
template <unsigned size> struct String {
|
||||
static u8 const Type = 3;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 data[size];
|
||||
} __attribute__ ((packed))
|
||||
static unsigned const max_packet_size0 = 64
|
||||
static unsigned const max_packet_size_bulk = 64
|
||||
enum Requests:
|
||||
GET_STATUS = 0
|
||||
CLEAR_FEATURE = 1
|
||||
SET_FEATURE = 3
|
||||
SET_ADDRESS = 5
|
||||
GET_DESCRIPTOR = 6
|
||||
SET_DESCRIPTOR = 7
|
||||
GET_CONFIGURATION = 8
|
||||
SET_CONFIGURATION = 9
|
||||
GET_INTERFACE = 10
|
||||
SET_INTERFACE = 11
|
||||
SYNCH_FRAME = 12
|
||||
enum Request_types:
|
||||
STANDARD_TO_DEVICE = 0
|
||||
VENDOR_TO_DEVICE = 0x40
|
||||
STANDARD_FROM_DEVICE = 0x80
|
||||
VENDOR_FROM_DEVICE = 0xc0
|
||||
enum Endpoint_types:
|
||||
CONTROL = 0
|
||||
ISOCHRONOUS = 1
|
||||
BULK = 2
|
||||
INTERRUPT = 3
|
||||
/**/struct my_config {
|
||||
Configuration config;
|
||||
Interface interface;
|
||||
Endpoint endpoint[2];
|
||||
} __attribute__ ((packed))
|
||||
static Device device_descriptor
|
||||
//static Device_Qualifier device_qualifier_descriptor
|
||||
static my_config config_descriptor; //, other_config_descriptor
|
||||
static String <1> s_langs
|
||||
static String <6> s_manufacturer
|
||||
static String <16> s_product
|
||||
enum State:
|
||||
IDLE
|
||||
TX
|
||||
RX
|
||||
State state
|
||||
char configuration
|
||||
unsigned size
|
||||
unsigned rx_request
|
||||
char const *ptr
|
||||
unsigned cmd_code, cmd_arg
|
||||
bool rebooting
|
||||
bool vendor (Setup *s, unsigned cmd)
|
||||
bool get_descriptor (unsigned type, unsigned idx, unsigned len)
|
||||
bool handle_setup (Setup *s, unsigned cmd)
|
||||
void irq_usb (unsigned cmd)
|
||||
void irq_in (unsigned cmd)
|
||||
void irq_out (unsigned cmd)
|
||||
char log_buffer[1000]
|
||||
unsigned log_buffer_size
|
||||
unsigned log_buffer_start
|
||||
Iris::Cap caller, caller_arg
|
||||
bool have_caller
|
||||
unsigned *page
|
||||
unsigned *p
|
||||
Iris::Page buffer_page
|
||||
public:
|
||||
void init ()
|
||||
void log (unsigned c)
|
||||
void interrupt (unsigned cmd)
|
||||
void send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg)
|
||||
|
||||
Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
|
||||
Udc::my_config Udc::config_descriptor = {
|
||||
(Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
|
||||
(Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
|
||||
}
|
||||
}
|
||||
Udc::String <1> Udc::s_langs = { sizeof (String <1>), String <1>::Type, { 0x0409 } }
|
||||
Udc::String <6> Udc::s_manufacturer = { sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
|
||||
Udc::String <16> Udc::s_product = { sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
|
||||
|
||||
//Udc::Device_Qualifier const Udc::device_qualifier_descriptor = { sizeof (Device_Qualifier), Device_Qualifier::Type, 0x200, 0, 0, 0, max_packet_size0, 1, 0 }
|
||||
//Udc::my_config const Udc::other_config_descriptor = {
|
||||
// (Configuration){ sizeof (Configuration), 7, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
|
||||
// (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
|
||||
// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
|
||||
// (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
|
||||
// }
|
||||
// }
|
||||
|
||||
void Udc::init ():
|
||||
// Initialize the globals. My method of compiling doesn't do that properly.
|
||||
device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
|
||||
config_descriptor = (my_config){
|
||||
(Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
|
||||
(Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
|
||||
}
|
||||
}
|
||||
s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
|
||||
s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
|
||||
s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
|
||||
have_caller = false
|
||||
log_buffer_size = 0
|
||||
log_buffer_start = 0
|
||||
cmd_code = ~0
|
||||
cmd_arg = 0
|
||||
|
||||
// Use the space which is reserved for the framebuffer, because it will not be in use.
|
||||
// Normally a normal new page should be allocated here, but new isn't implemented at this point.
|
||||
page = (unsigned *)LCD_FRAMEBUFFER_BASE
|
||||
p = page
|
||||
buffer_page = Iris::my_memory.create_page ()
|
||||
buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING)
|
||||
Iris::my_memory.map (buffer_page, (unsigned)page)
|
||||
|
||||
// Disconnect from the bus and don't try to get high-speed.
|
||||
UDC_POWER = 0
|
||||
UDC_TESTMODE = 0
|
||||
UDC_INDEX = 0
|
||||
state = IDLE
|
||||
configuration = 0
|
||||
size = 0
|
||||
// exit suspend mode by reading the interrupt register.
|
||||
cpm_start_udc ()
|
||||
// reset all pending endpoint interrupts.
|
||||
unsigned i = UDC_INTRUSB
|
||||
i = UDC_INTRIN
|
||||
i = UDC_INTROUT
|
||||
// enable interrupt on bus reset.
|
||||
UDC_INTRUSBE = UDC_INTR_RESET
|
||||
// enable interrupts on endpoint 0.
|
||||
UDC_INTRINE = 1 << 0
|
||||
// and on out endpoint 1.
|
||||
UDC_INTROUTE = 1 << 1
|
||||
// Wait a while.
|
||||
for unsigned w = 0; w < 10000; ++w:
|
||||
Iris::schedule ()
|
||||
// Connect to the host.
|
||||
UDC_POWER = UDC_POWER_SOFTCONN
|
||||
|
||||
bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
if !(s->request_type & 0x80):
|
||||
kdebug ("data to device without size\n")
|
||||
Iris::panic (0)
|
||||
return true
|
||||
if s->request == 10:
|
||||
static unsigned b[2]
|
||||
ptr = (char *)b
|
||||
size = s->length < 8 ? s->length : 8
|
||||
if cmd_code != ~0:
|
||||
b[0] = cmd_code
|
||||
b[1] = cmd_arg
|
||||
if cmd_code == Iris::Directory::LOCK_RO || cmd_code == Iris::Directory::UNLOCK_RO:
|
||||
caller.invoke ()
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("(un)lock response\n")
|
||||
cmd_code = ~0
|
||||
else:
|
||||
if log_buffer_start == log_buffer_size:
|
||||
b[0] = ~1
|
||||
b[1] = 0
|
||||
else:
|
||||
b[0] = ~0
|
||||
b[1] = (log_buffer[log_buffer_start++] & 0xff) * 0x01010101
|
||||
if log_buffer_start == log_buffer_size:
|
||||
log_buffer_start = 0
|
||||
log_buffer_size = 0
|
||||
else:
|
||||
static char const *name = "Reboot"
|
||||
ptr = name
|
||||
size = s->length < 6 ? s->length : 6
|
||||
rebooting = true
|
||||
state = TX
|
||||
return true
|
||||
|
||||
void Udc::send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg):
|
||||
if cmd_code != ~0:
|
||||
kdebug ("new code sent while old one wasn't finished.\n")
|
||||
Iris::panic (0)
|
||||
cmd_code = code
|
||||
cmd_arg = narg
|
||||
caller = reply
|
||||
caller_arg = arg
|
||||
have_caller = true
|
||||
|
||||
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||
switch type:
|
||||
case Configuration::Type:
|
||||
if idx != 0:
|
||||
return false
|
||||
ptr = reinterpret_cast <char const *> (&config_descriptor)
|
||||
size = (len < sizeof (config_descriptor) ? len : sizeof (config_descriptor))
|
||||
break
|
||||
case Device::Type:
|
||||
if idx != 0:
|
||||
return false
|
||||
ptr = reinterpret_cast <char const *> (&device_descriptor)
|
||||
size = (len < sizeof (device_descriptor) ? len : sizeof (device_descriptor))
|
||||
break
|
||||
case Device_Qualifier::Type:
|
||||
//if idx != 0:
|
||||
// return false
|
||||
//ptr = reinterpret_cast <char const *> (&device_qualifier_descriptor)
|
||||
//size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor))
|
||||
//break
|
||||
return false
|
||||
// The 6 is an arbitrary number, except that String <6> is instantiated already.
|
||||
case String <6>::Type:
|
||||
switch idx:
|
||||
case 0:
|
||||
ptr = reinterpret_cast <char const *> (&s_langs)
|
||||
size = (len < sizeof (s_langs) ? len : sizeof (s_langs))
|
||||
break
|
||||
case 1:
|
||||
ptr = reinterpret_cast <char const *> (&s_manufacturer)
|
||||
size = (len < sizeof (s_manufacturer) ? len : sizeof (s_manufacturer))
|
||||
break
|
||||
case 2:
|
||||
ptr = reinterpret_cast <char const *> (&s_product)
|
||||
size = (len < sizeof (s_product) ? len : sizeof (s_product))
|
||||
break
|
||||
default:
|
||||
return false
|
||||
break
|
||||
default:
|
||||
return false
|
||||
state = TX
|
||||
return true
|
||||
|
||||
bool Udc::handle_setup (Setup *s, unsigned cmd):
|
||||
switch s->request_type:
|
||||
case STANDARD_TO_DEVICE:
|
||||
switch s->request:
|
||||
case SET_ADDRESS:
|
||||
UDC_FADDR = s->value
|
||||
break
|
||||
case SET_CONFIGURATION:
|
||||
if s->value >= 2:
|
||||
return false
|
||||
configuration = s->value
|
||||
break
|
||||
case SET_INTERFACE:
|
||||
if s->value != 0:
|
||||
return false
|
||||
break
|
||||
default:
|
||||
return false
|
||||
UDC_OUTMAXP = 64
|
||||
UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||
UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||
break
|
||||
case STANDARD_FROM_DEVICE:
|
||||
switch s->request:
|
||||
case GET_STATUS:
|
||||
ptr = "\0\0"
|
||||
size = (s->length < 2 ? s->length : 2)
|
||||
state = TX
|
||||
break
|
||||
case GET_DESCRIPTOR:
|
||||
return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
|
||||
case GET_CONFIGURATION:
|
||||
ptr = &configuration
|
||||
size = (s->length < 1 ? s->length : 1)
|
||||
state = TX
|
||||
break
|
||||
case GET_INTERFACE:
|
||||
ptr = "\0"
|
||||
size = (s->length < 1 ? s->length : 1)
|
||||
state = TX
|
||||
break
|
||||
default:
|
||||
return false
|
||||
break
|
||||
case VENDOR_TO_DEVICE:
|
||||
case VENDOR_FROM_DEVICE:
|
||||
return vendor (s, cmd)
|
||||
default:
|
||||
return false
|
||||
return true
|
||||
|
||||
void Udc::irq_usb (unsigned cmd):
|
||||
// Reset.
|
||||
//Iris::debug ("usb reset\n")
|
||||
state = IDLE
|
||||
|
||||
void Udc::irq_in (unsigned cmd):
|
||||
// Interrupt on endpoint 0.
|
||||
unsigned csr = UDC_CSR0
|
||||
if csr & UDC_CSR0_SENTSTALL:
|
||||
csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL)
|
||||
state = IDLE
|
||||
if csr & UDC_CSR0_SETUPEND:
|
||||
csr |= UDC_CSR0_SVDSETUPEND
|
||||
state = IDLE
|
||||
switch state:
|
||||
case IDLE:
|
||||
if rebooting:
|
||||
Iris::reboot ()
|
||||
if !(csr & UDC_CSR0_OUTPKTRDY):
|
||||
return
|
||||
union { unsigned d[2]; Setup s; } packet
|
||||
packet.d[0] = UDC_FIFO (0)
|
||||
packet.d[1] = UDC_FIFO (0)
|
||||
if !(packet.s.request_type & 0x80) && packet.s.length > 0:
|
||||
// More data will follow; delay handling of packet.
|
||||
state = RX
|
||||
UDC_CSR0 = csr | UDC_CSR0_SVDOUTPKTRDY
|
||||
rx_request = packet.s.request
|
||||
return
|
||||
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
if !handle_setup (&packet.s, cmd):
|
||||
csr |= UDC_CSR0_SENDSTALL
|
||||
break
|
||||
if size == 0:
|
||||
return
|
||||
// Fall through.
|
||||
case TX:
|
||||
unsigned i
|
||||
for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4:
|
||||
UDC_FIFO (0) = *(unsigned *)ptr
|
||||
ptr += 4
|
||||
for ; size > 0 && i < max_packet_size0; ++i, --size:
|
||||
UDC_FIFO8 (0) = *ptr++
|
||||
if i == max_packet_size0:
|
||||
csr |= UDC_CSR0_INPKTRDY
|
||||
else:
|
||||
state = IDLE
|
||||
csr |= UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||
break
|
||||
case RX:
|
||||
// The protocol that is used doesn't allow large packets, so being here always means the entire packet is received.
|
||||
switch rx_request & 0xff:
|
||||
case Iris::Directory::GET_SIZE & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received dir size from server without a caller waiting\n")
|
||||
Iris::panic (0)
|
||||
unsigned size_l = UDC_FIFO (0)
|
||||
unsigned size_h = UDC_FIFO (0)
|
||||
caller.invoke (Iris::Num (size_l, size_h))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_size response\n")
|
||||
break
|
||||
case Iris::Directory::GET_NAME & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received filename from server without a caller waiting\n")
|
||||
Iris::panic (0)
|
||||
unsigned n[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
n[i] = UDC_FIFO (0)
|
||||
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
//kdebug ("get_name response\n")
|
||||
have_caller = false
|
||||
break
|
||||
case Iris::String::GET_SIZE & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received string size from server without a caller waiting\n")
|
||||
Iris::panic (0)
|
||||
unsigned size_l = UDC_FIFO (0)
|
||||
unsigned size_h = UDC_FIFO (0)
|
||||
caller.invoke (Iris::Num (size_l, size_h))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_filesize response\n")
|
||||
break
|
||||
case Iris::String::GET_CHARS & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received string char data from server without a caller waiting\n")
|
||||
Iris::panic (0)
|
||||
unsigned n[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
n[i] = UDC_FIFO (0)
|
||||
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_chars response\n")
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid vendor request: ")
|
||||
kdebug_num (rx_request)
|
||||
kdebug ("\n")
|
||||
Iris::panic (0)
|
||||
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||
state = IDLE
|
||||
break
|
||||
UDC_CSR0 = csr
|
||||
|
||||
void Udc::irq_out (unsigned cmd):
|
||||
// Interrupt on OUT endpoint 1.
|
||||
UDC_INDEX = 1
|
||||
if !have_caller:
|
||||
kdebug ("received bulk data from server without a caller waiting\n")
|
||||
Iris::panic (0)
|
||||
unsigned size = UDC_OUTCOUNT
|
||||
unsigned csr = UDC_OUTCSR
|
||||
//Iris::debug ("handling bulk interrupt for %x with %d bytes.\n", csr, size)
|
||||
csr &= ~UDC_OUTCSR_OUTPKTRDY
|
||||
for unsigned i = 0; i < size; i += 4:
|
||||
*p++ = UDC_FIFO (1)
|
||||
if p - page == PAGE_SIZE >> 2:
|
||||
buffer_page.share (caller_arg, Iris::Page::FORGET)
|
||||
buffer_page.set_flags (Iris::Page::FRAME)
|
||||
caller.invoke ()
|
||||
Iris::free_cap (caller)
|
||||
Iris::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("bulk response\n")
|
||||
p = page
|
||||
UDC_OUTCSR = csr
|
||||
UDC_INDEX = 0
|
||||
|
||||
void Udc::interrupt (unsigned cmd):
|
||||
while true:
|
||||
unsigned usb = UDC_INTRUSB
|
||||
unsigned in = UDC_INTRIN
|
||||
unsigned out = UDC_INTROUT
|
||||
if !(usb & 4) && !(in & 1) && !(out & 2):
|
||||
break
|
||||
//Iris::debug ("interrupt: %d/%d/%d\n", usb, in, out)
|
||||
if usb & 4:
|
||||
irq_usb (cmd)
|
||||
if in & 1:
|
||||
irq_in (cmd)
|
||||
if out & 2:
|
||||
irq_out (cmd)
|
||||
|
||||
void Udc::log (unsigned c):
|
||||
if log_buffer_size >= sizeof (log_buffer):
|
||||
return
|
||||
log_buffer[log_buffer_size++] = c
|
||||
|
||||
enum pdata:
|
||||
LOG = 1
|
||||
DIRECTORY
|
||||
FILE
|
||||
NAME
|
||||
|
||||
Iris::Num start ():
|
||||
map_udc ()
|
||||
map_gpio ()
|
||||
map_cpm ()
|
||||
Udc udc
|
||||
|
||||
//Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
|
||||
//__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1")
|
||||
Iris::Directory dir = Iris::my_receiver.create_capability (DIRECTORY)
|
||||
Iris::my_parent.provide_capability <Iris::Directory> (dir.copy ())
|
||||
Iris::free_cap (dir)
|
||||
udc.init ()
|
||||
Iris::register_interrupt (IRQ_UDC)
|
||||
// Don't call init_done, because this can be used as bootthread and without a parent this call will not be answered.
|
||||
//Iris::my_parent.init_done ()
|
||||
unsigned state = 0
|
||||
while true:
|
||||
Iris::wait ()
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap arg = Iris::get_arg ()
|
||||
//Iris::debug ("udc event, protected: %x\n", Iris::recv.protected_data.l)
|
||||
switch Iris::recv.protected_data.l:
|
||||
case 0:
|
||||
udc.interrupt (state)
|
||||
Iris::register_interrupt (IRQ_UDC)
|
||||
break
|
||||
case LOG:
|
||||
udc.log (Iris::recv.data[0].l)
|
||||
break
|
||||
case DIRECTORY:
|
||||
//Iris::debug ("dir request %d\n", Iris::recv.data[0].l)
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Directory::GET_NAME:
|
||||
Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (NAME, Iris::recv.data[1].l))
|
||||
reply.invoke (0, 0, name.copy ())
|
||||
Iris::free_cap (name)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
case Iris::Directory::GET_SIZE:
|
||||
case Iris::Directory::LOCK_RO:
|
||||
case Iris::Directory::UNLOCK_RO:
|
||||
state = Iris::recv.data[0].l
|
||||
if Iris::recv.data[1].h != 0:
|
||||
Iris::panic (0, "index out of supported range")
|
||||
udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
|
||||
continue
|
||||
case Iris::Directory::GET_FILE_RO:
|
||||
if Iris::recv.data[1].h != 0:
|
||||
kdebug ("index out of supported range\n")
|
||||
Iris::panic (0)
|
||||
//kdebug ("sending file\n")
|
||||
Iris::Cap file = Iris::my_receiver.create_capability (Iris::Num (FILE, Iris::recv.data[1].l))
|
||||
reply.invoke (0, 0, file.copy ())
|
||||
Iris::free_cap (file)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
case Iris::Directory::GET_FILE_INFO:
|
||||
default:
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case FILE:
|
||||
//Iris::debug ("file request %d\n", Iris::recv.data[0].l)
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Block::GET_BLOCK:
|
||||
if Iris::recv.data[0].h != PAGE_SIZE << 16:
|
||||
Iris::panic (0, "unsupported get_block arguments for boot usb device driver")
|
||||
// Fall through.
|
||||
case Iris::Block::GET_SIZE:
|
||||
udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.h, reply, arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case NAME:
|
||||
//Iris::debug ("name request %d\n", Iris::recv.data[0].l)
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::String::GET_SIZE:
|
||||
reply.invoke (16)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
case Iris::String::GET_CHARS:
|
||||
state = Iris::recv.data[0].l
|
||||
udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.h, reply, arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Iris::ERR_INVALID_OPERATION)
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
continue
|
||||
default:
|
||||
kdebug ("other request:")
|
||||
kdebug_num (Iris::recv.protected_data.l)
|
||||
kdebug ("\n")
|
||||
udc.log ('~')
|
||||
char digit[] = "0123456789abcdef"
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
udc.log (digit[(Iris::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
|
||||
udc.log ('\n')
|
||||
break
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (arg)
|
||||
323
userspace/trendtac/trendtac-gpio.ccp
Normal file
323
userspace/trendtac/trendtac-gpio.ccp
Normal file
@@ -0,0 +1,323 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/gpio.ccp: GPIO driver, controlling all devices without special hardware.
|
||||
// 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"
|
||||
|
||||
// Interval between polls for keyboard events (when keys are pressed)
|
||||
#define ALARM_INTERVAL (HZ / 50)
|
||||
|
||||
// GPIO pins for the devices (port.pin)
|
||||
|
||||
// keyboard
|
||||
// Cols = 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14, 3.15, 3.29
|
||||
// Rows = 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7
|
||||
// For some reason, it only works if the rows are input and the columns are output.
|
||||
// interrupts: yes, with all columns set to output 0, the first key press can be detected as an interrupt; some other events also trigger interrupts.
|
||||
|
||||
// touchpad buttons
|
||||
// Left: 0.16
|
||||
// Right: 0.13
|
||||
// interrupts: yes, for any change.
|
||||
|
||||
// Lock leds
|
||||
// Num lock: 2.22
|
||||
// Caps lock: 0.27
|
||||
// Scroll lock: 0.9
|
||||
// interrupts: no, output only.
|
||||
|
||||
// interrupt summary
|
||||
// Port 0: pin 0, 1, 2, 3, 4, 5, 6, 7: keyboard; 13, 16: touchpad
|
||||
// Port 1: None.
|
||||
// Port 2: None.
|
||||
// Port 3: None.
|
||||
|
||||
enum event_type:
|
||||
KEYBOARD_EVENT
|
||||
TOUCHPAD_EVENT
|
||||
NUM_EVENTS
|
||||
|
||||
static Iris::Cap events[NUM_EVENTS]
|
||||
|
||||
static void event (event_type type, unsigned data):
|
||||
events[type].invoke (data)
|
||||
|
||||
static void set_cb (event_type type):
|
||||
Iris::free_cap (events[type])
|
||||
events[type] = Iris::get_arg ()
|
||||
|
||||
class DevKeyboard:
|
||||
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
|
||||
unsigned keys[GPIO_KBD_NUM_COLS]
|
||||
bool scanning
|
||||
void parse (unsigned col, unsigned data):
|
||||
for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
|
||||
if (data ^ keys[col]) & (1 << row):
|
||||
unsigned code = encode[col][row]
|
||||
if data & (1 << row):
|
||||
code |= Keyboard::RELEASE
|
||||
event (KEYBOARD_EVENT, code)
|
||||
keys[col] = data
|
||||
// If any keys are pressed, scanning is required.
|
||||
if data != GPIO_KBD_ROW_MASK:
|
||||
scanning = true
|
||||
public:
|
||||
bool is_scanning ():
|
||||
return scanning
|
||||
void scan ():
|
||||
// Disable interrupts during scan.
|
||||
GPIO_GPIER (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
|
||||
// All columns are input.
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
|
||||
int const cols[GPIO_KBD_NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 }
|
||||
unsigned dir = GPIO_GPDIR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
|
||||
unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
|
||||
// Set scanning to false before first parse.
|
||||
scanning = false
|
||||
// Clear all pins. This is only required once, because it's done at the end of the loop as well.
|
||||
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
|
||||
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
|
||||
// Set pin to output.
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
|
||||
// Delay for stabalization.
|
||||
for unsigned i = 0; i < 100; ++i:
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
|
||||
// Read the result.
|
||||
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
|
||||
// Generate events.
|
||||
parse (col, data)
|
||||
// Set pin to get rid of capacitance effects.
|
||||
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
|
||||
// Delay to make the above trick work.
|
||||
for unsigned i = 0; i < 100; ++i:
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
|
||||
// Pin is set to input at the start of the loop.
|
||||
// set all to 0.
|
||||
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
|
||||
// set all to output.
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
|
||||
// Delay for stabalization.
|
||||
for unsigned i = 0; i < 100; ++i:
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
|
||||
// Set interrupts.
|
||||
unsigned data = GPIO_GPDR (GPIO_KBD_ROW_PORT)
|
||||
for unsigned i = 0; i < 8; ++i:
|
||||
if data & (1 << i):
|
||||
gpio_irq_low (GPIO_KBD_ROW_PORT, i)
|
||||
else:
|
||||
gpio_irq_high (GPIO_KBD_ROW_PORT, i)
|
||||
// Reenable interrupts.
|
||||
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
|
||||
DevKeyboard ():
|
||||
// Set all columns to output without pull-ups when set as input.
|
||||
GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
|
||||
GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK
|
||||
|
||||
// Set all rows to input and enable the pull-ups.
|
||||
GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
|
||||
GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
|
||||
// Initialize things in the same way as when a new callback is set up.
|
||||
send_initial ()
|
||||
void send_initial ():
|
||||
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
|
||||
keys[col] = 0xff
|
||||
scan ()
|
||||
|
||||
enum Keys:
|
||||
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, F5, F6, F7, F8, F9, F10
|
||||
SPACE, TAB, ENTER, LBRACE, RBRACE, COMMA, PERIOD, MINUS, EQUAL, SLASH, BACKSLASH, SEMICOLON, EXTRA, BACKQUOTE, QUOTE
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ
|
||||
LSHIFT, RSHIFT, CTRL, ALT
|
||||
CAPS, NUM
|
||||
NONE = ~Keyboard::RELEASE
|
||||
|
||||
unsigned const DevKeyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
|
||||
{ PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 },
|
||||
{ Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
|
||||
{ W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
|
||||
{ E, F3, D, F4, C, NONE, NONE, N3 },
|
||||
{ R, T, F, G, V, B, N5, N4 },
|
||||
{ U, Y, J, H, M, N, N6, N7 },
|
||||
{ I, RBRACE, K, F6, COMMA, NONE, EQUAL, N8 },
|
||||
{ O, F7, L, NONE, PERIOD, MENU, F8, N9 },
|
||||
{ NONE, NONE, NONE, SPACE, NUM, NONE, DELETE, NONE },
|
||||
{ NONE, BACKSPACE, NONE, NONE, ENTER, NONE, F9, NONE },
|
||||
{ NONE, NONE, NONE, ALT, NONE, NONE, NONE, SYSRQ },
|
||||
{ P, LBRACE, SEMICOLON, QUOTE, BACKSLASH, SLASH, MINUS, N0 },
|
||||
{ NONE, ZZZ, NONE, NONE, NONE, NONE, NONE, F10 },
|
||||
{ NONE, NONE, NONE, NONE, NONE, NONE, F2, NONE },
|
||||
{ NONE, NONE, NONE, NONE, NONE, NONE, INSERT, NONE },
|
||||
{ NONE, NONE, UP, DOWN, LEFT, RIGHT, NONE, NONE },
|
||||
{ NONE, LSHIFT, RSHIFT, NONE, NONE, NONE, F1, FN }}
|
||||
|
||||
class Touchpad:
|
||||
unsigned old_state
|
||||
public:
|
||||
void check_events ():
|
||||
unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
|
||||
if state & (1 << GPIO_TP_LEFT):
|
||||
gpio_irq_low (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
|
||||
event (TOUCHPAD_EVENT, 0)
|
||||
else:
|
||||
gpio_irq_high (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
|
||||
event (TOUCHPAD_EVENT, 0 | Keyboard::RELEASE)
|
||||
if state & (1 << GPIO_TP_RIGHT):
|
||||
gpio_irq_low (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
|
||||
event (TOUCHPAD_EVENT, 1)
|
||||
else:
|
||||
gpio_irq_high (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
|
||||
event (TOUCHPAD_EVENT, 1 | Keyboard::RELEASE)
|
||||
old_state = state
|
||||
// Ack interrupts.
|
||||
//GPIO_GPFR (GPIO_TP_LEFT_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
|
||||
Touchpad ():
|
||||
// Set pins to input with pull-ups.
|
||||
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
|
||||
gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
|
||||
GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
|
||||
// See if they are already pressed. Also set up interrupts. This is done like when a new callback is registered.
|
||||
send_initial ()
|
||||
void send_initial ():
|
||||
old_state = 0
|
||||
check_events ()
|
||||
|
||||
class Lockleds:
|
||||
// Note that num lock is in port 2. The others are in port 0.
|
||||
public:
|
||||
Lockleds ():
|
||||
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
|
||||
gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS)
|
||||
gpio_as_output (GPIO_SCROLL_PORT, GPIO_SCROLL)
|
||||
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
|
||||
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
|
||||
void set (unsigned state):
|
||||
if state & 4:
|
||||
GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM)
|
||||
else:
|
||||
GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM
|
||||
if state & 2:
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS)
|
||||
else:
|
||||
GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS
|
||||
if state & 1:
|
||||
GPIO_GPDR (GPIO_SCROLL_PORT) &= ~(1 << GPIO_SCROLL)
|
||||
else:
|
||||
GPIO_GPDR (GPIO_SCROLL_PORT) |= 1 << GPIO_SCROLL
|
||||
|
||||
// Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
|
||||
class Pwm:
|
||||
public:
|
||||
Pwm ():
|
||||
GPIO_GPDIR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
|
||||
PWM_PER (0) = 300
|
||||
void set_backlight (unsigned level):
|
||||
if level > 300:
|
||||
level = 300
|
||||
PWM_DUT (0) = level
|
||||
if level:
|
||||
PWM_CTR (0) = 0x80
|
||||
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
|
||||
else:
|
||||
PWM_CTR (0) = 0x00
|
||||
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE)
|
||||
// TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
|
||||
|
||||
enum codes:
|
||||
KEYBOARD = 1
|
||||
TOUCHPAD
|
||||
LOCKLEDS
|
||||
PWM
|
||||
|
||||
Iris::Num start ():
|
||||
map_gpio ()
|
||||
map_pwm0 ()
|
||||
|
||||
for unsigned i = 0; i < NUM_EVENTS; ++i:
|
||||
events[i] = Iris::alloc_cap ()
|
||||
|
||||
DevKeyboard kbd
|
||||
Touchpad tp
|
||||
Lockleds leds
|
||||
Pwm pwm
|
||||
|
||||
Iris::Cap c = Iris::my_receiver.create_capability (KEYBOARD)
|
||||
Iris::my_parent.provide_capability <Keyboard> (c.copy (), 0)
|
||||
Iris::free_cap (c)
|
||||
c = Iris::my_receiver.create_capability (TOUCHPAD)
|
||||
Iris::my_parent.provide_capability <Keyboard> (c.copy (), 1)
|
||||
Iris::free_cap (c)
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
if kbd.is_scanning ():
|
||||
Iris::my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
|
||||
// Enable interrupts. All are in port 0.
|
||||
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
|
||||
Iris::register_interrupt (IRQ_GPIO0)
|
||||
|
||||
while true:
|
||||
Iris::schedule ()
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
kbd.scan ()
|
||||
if kbd.is_scanning ():
|
||||
Iris::my_receiver.set_alarm (ALARM_INTERVAL)
|
||||
break
|
||||
case 0:
|
||||
// Always scan keyboard and touchpad on any interrupt.
|
||||
kbd.scan ()
|
||||
tp.check_events ()
|
||||
// Reregister the interrupt.
|
||||
Iris::register_interrupt (IRQ_GPIO0)
|
||||
break
|
||||
case KEYBOARD:
|
||||
set_cb (KEYBOARD_EVENT)
|
||||
Iris::recv.reply.invoke ()
|
||||
kbd.send_initial ()
|
||||
event (KEYBOARD_EVENT, ~0)
|
||||
break
|
||||
case TOUCHPAD:
|
||||
set_cb (TOUCHPAD_EVENT)
|
||||
Iris::recv.reply.invoke ()
|
||||
tp.send_initial ()
|
||||
event (TOUCHPAD_EVENT, ~0)
|
||||
break
|
||||
case LOCKLEDS:
|
||||
leds.set (Iris::recv.data[0].l)
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case PWM:
|
||||
pwm.set_backlight (Iris::recv.data[0].l)
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid gpio operation ")
|
||||
kdebug_num (Iris::recv.protected_data.l)
|
||||
kdebug ("\n")
|
||||
break
|
||||
Reference in New Issue
Block a user