mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-29 21:12:25 +02:00
add partial nand and sd/mmc drivers
This commit is contained in:
parent
8c7cac36e6
commit
6bf41032d8
6
Makefile
6
Makefile
@ -23,7 +23,7 @@ CC = $(CROSS)gcc
|
|||||||
LD = $(CROSS)ld
|
LD = $(CROSS)ld
|
||||||
OBJCOPY = $(CROSS)objcopy
|
OBJCOPY = $(CROSS)objcopy
|
||||||
|
|
||||||
headers = kernel.hh iris.hh ui.hh $(arch_headers)
|
headers = kernel.hh iris.hh devices.hh ui.hh $(arch_headers)
|
||||||
iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
|
iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
|
||||||
BUILT_SOURCES = $(iris_sources) $(boot_sources)
|
BUILT_SOURCES = $(iris_sources) $(boot_sources)
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ clean:
|
|||||||
|
|
||||||
debug:
|
debug:
|
||||||
stty -F $(SERIAL) raw 9600
|
stty -F $(SERIAL) raw 9600
|
||||||
cat $(SERIAL)
|
while : ; do cat $(SERIAL) ; done
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
.PRECIOUS: iris.hh kernel.hh ui.hh boot-programs/crt0.o
|
.PRECIOUS: $(headers) boot-programs/crt0.o source/crt0.o
|
||||||
|
201
devices.hhp
201
devices.hhp
@ -24,66 +24,66 @@
|
|||||||
namespace Iris:
|
namespace Iris:
|
||||||
// Caplist interface.
|
// Caplist interface.
|
||||||
template <typename _T> //
|
template <typename _T> //
|
||||||
struct Caplist : public Iris::Caps:
|
struct Caplist : public Caps:
|
||||||
Caplist (Iris::Caps c = Iris::Cap ()) : Iris::Caps (c):
|
Caplist (Caps c = Cap ()) : Caps (c):
|
||||||
Caplist <_T> create (unsigned size, Iris::Memory mem = Iris::my_memory):
|
Caplist <_T> create (unsigned size, Memory mem = my_memory):
|
||||||
return Caplist <_T> (mem.create_caps (size))
|
return Caplist <_T> (mem.create_caps (size))
|
||||||
void set (unsigned idx, _T value):
|
void set (unsigned idx, _T value):
|
||||||
return Iris::Caps::set (idx, value)
|
return Caps::set (idx, value)
|
||||||
_T get (unsigned idx):
|
_T get (unsigned idx):
|
||||||
return _T (Iris::Caps::get (idx))
|
return _T (Caps::get (idx))
|
||||||
|
|
||||||
/// A block of data with a size and content. Any character can be stored in it (including '\0').
|
/// A block of data with a size and content. Any character can be stored in it (including '\0').
|
||||||
struct String : public Iris::Cap:
|
struct String : public Cap:
|
||||||
String (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
String (Cap c = Cap ()) : Cap (c):
|
||||||
enum request:
|
enum request:
|
||||||
GET_SIZE = 0x2001
|
GET_SIZE = 0x2001
|
||||||
GET_CHARS
|
GET_CHARS
|
||||||
GET_PAGE
|
GET_PAGE
|
||||||
ID
|
ID
|
||||||
/// Get the size of the string.
|
/// Get the size of the string.
|
||||||
Iris::Num get_size ():
|
Num get_size ():
|
||||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||||
/// Get exactly 16 characters. The index must be word-aligned.
|
/// Get exactly 16 characters. The index must be word-aligned.
|
||||||
char *get_chars (Iris::Num idx, char buffer[16]):
|
char *get_chars (Num idx, char buffer[16]):
|
||||||
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
|
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
|
||||||
unsigned *b = (unsigned *)buffer
|
unsigned *b = (unsigned *)buffer
|
||||||
b[0] = Iris::recv.data[0].l
|
b[0] = recv.data[0].l
|
||||||
b[1] = Iris::recv.data[0].h
|
b[1] = recv.data[0].h
|
||||||
b[2] = Iris::recv.data[1].l
|
b[2] = recv.data[1].l
|
||||||
b[3] = Iris::recv.data[1].h
|
b[3] = recv.data[1].h
|
||||||
return buffer
|
return buffer
|
||||||
/// Helper function for get_page.
|
/// Helper function for get_page.
|
||||||
static Iris::Page _create_paying_page ():
|
static Page _create_paying_page ():
|
||||||
Iris::Page ret = Iris::my_memory.create_page ()
|
Page ret = my_memory.create_page ()
|
||||||
ret.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
|
ret.set_flags (Page::PAYING, Page::PAYING)
|
||||||
return ret
|
return ret
|
||||||
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
|
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
|
||||||
Cap get_page (Iris::Num idx, Iris::Page ret = _create_paying_page ()):
|
Cap get_page (Num idx, Page ret = _create_paying_page ()):
|
||||||
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
|
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
/// A writable String.
|
/// A writable String.
|
||||||
struct WString : public String:
|
struct WString : public String:
|
||||||
WString (Iris::Cap c = Iris::Cap ()) : String (c):
|
WString (Cap c = Cap ()) : String (c):
|
||||||
enum request:
|
enum request:
|
||||||
TRUNCATE = String::ID
|
TRUNCATE = String::ID
|
||||||
SET_CHARS
|
SET_CHARS
|
||||||
SET_PAGE
|
SET_PAGE
|
||||||
ID
|
ID
|
||||||
/// Set the size of the string. Strings may have a limit to this setting.
|
/// Set the size of the string. Strings may have a limit to this setting.
|
||||||
void truncate (Iris::Num size):
|
void truncate (Num size):
|
||||||
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
||||||
/// Set exactly 4 characters. The index must be word-aligned.
|
/// Set exactly 4 characters. The index must be word-aligned.
|
||||||
void set_chars (Iris::Num idx, char buffer[4]):
|
void set_chars (Num idx, char buffer[4]):
|
||||||
call (Iris::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
|
call (Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
|
||||||
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
|
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
|
||||||
void set_page (Iris::Num idx, Iris::Page page):
|
void set_page (Num idx, Page page):
|
||||||
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
|
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
|
||||||
|
|
||||||
// Every process which wants to be switchable through a terminal must implement this interface.
|
// Every process which wants to be switchable through a terminal must implement this interface.
|
||||||
struct Device : public Iris::Cap:
|
struct Device : public Cap:
|
||||||
Device (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
Device (Cap c = Cap ()) : Cap (c):
|
||||||
enum request:
|
enum request:
|
||||||
RESET = WString::ID
|
RESET = WString::ID
|
||||||
ID
|
ID
|
||||||
@ -91,40 +91,49 @@ namespace Iris:
|
|||||||
void reset ():
|
void reset ():
|
||||||
call (CAP_MASTER_DIRECT | RESET)
|
call (CAP_MASTER_DIRECT | RESET)
|
||||||
|
|
||||||
struct Elfrun : public Iris::Cap:
|
struct Event : public Device:
|
||||||
Elfrun (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
Event (Cap c = Cap ()) : Device (c):
|
||||||
enum request:
|
enum request:
|
||||||
RUN_STRING = Device::ID
|
SET_CB = Device::ID
|
||||||
|
ID
|
||||||
|
// Set the event callback. Pending event emit to the new callback immediately.
|
||||||
|
void set_cb (Cap cb):
|
||||||
|
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||||
|
|
||||||
|
struct Elfrun : public Cap:
|
||||||
|
Elfrun (Cap c = Cap ()) : Cap (c):
|
||||||
|
enum request:
|
||||||
|
RUN_STRING = Event::ID
|
||||||
RUN_CAPS
|
RUN_CAPS
|
||||||
ID
|
ID
|
||||||
enum arg_pos:
|
enum arg_pos:
|
||||||
PARENT_MEMORY
|
PARENT_MEMORY
|
||||||
DATA
|
DATA
|
||||||
PARENT
|
PARENT
|
||||||
Iris::Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
|
Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
|
||||||
Iris::Caps caps = Iris::my_memory.create_caps (3)
|
Caps caps = my_memory.create_caps (3)
|
||||||
caps.set (PARENT_MEMORY, parent_memory)
|
caps.set (PARENT_MEMORY, parent_memory)
|
||||||
caps.set (DATA, data)
|
caps.set (DATA, data)
|
||||||
caps.set (PARENT, parent)
|
caps.set (PARENT, parent)
|
||||||
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Iris::Num (num_slots, num_caps))
|
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Num (num_slots, num_caps))
|
||||||
Iris::Caps ret = Iris::get_arg ()
|
Caps ret = get_arg ()
|
||||||
Iris::my_memory.destroy (caps)
|
my_memory.destroy (caps)
|
||||||
Iris::free_cap (caps)
|
free_cap (caps)
|
||||||
return ret
|
return ret
|
||||||
Iris::Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
|
Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
|
||||||
Iris::Caps caps = Iris::my_memory.create_caps (3)
|
Caps caps = my_memory.create_caps (3)
|
||||||
caps.set (PARENT_MEMORY, parent_memory)
|
caps.set (PARENT_MEMORY, parent_memory)
|
||||||
caps.set (DATA, data)
|
caps.set (DATA, data)
|
||||||
caps.set (PARENT, parent)
|
caps.set (PARENT, parent)
|
||||||
iocall (caps.copy (), Iris::Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Iris::Num (num_slots, num_caps))
|
iocall (caps.copy (), Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Num (num_slots, num_caps))
|
||||||
Iris::Caps ret = Iris::get_arg ()
|
Caps ret = get_arg ()
|
||||||
Iris::my_memory.destroy (caps)
|
my_memory.destroy (caps)
|
||||||
Iris::free_cap (caps)
|
free_cap (caps)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
// Interface for talking to the parent process.
|
// Interface for talking to the parent process.
|
||||||
struct Parent : public Iris::Cap:
|
struct Parent : public Cap:
|
||||||
Parent (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
Parent (Cap c = Cap ()) : Cap (c):
|
||||||
enum request:
|
enum request:
|
||||||
GET_CAPABILITY = Elfrun::ID
|
GET_CAPABILITY = Elfrun::ID
|
||||||
PROVIDE_CAPABILITY
|
PROVIDE_CAPABILITY
|
||||||
@ -136,43 +145,39 @@ namespace Iris:
|
|||||||
ID
|
ID
|
||||||
// Get a handle.
|
// Get a handle.
|
||||||
template <typename _T> _T get_capability (unsigned num = 0):
|
template <typename _T> _T get_capability (unsigned num = 0):
|
||||||
icall (Iris::Num (CAP_MASTER_DIRECT | GET_CAPABILITY, num), _T::ID)
|
icall (Num (CAP_MASTER_DIRECT | GET_CAPABILITY, num), _T::ID)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
// Provide a device handle.
|
// Provide a device handle.
|
||||||
template <typename _T> void provide_capability (Cap cap, unsigned num = 0):
|
template <typename _T> void provide_capability (Cap cap, unsigned num = 0):
|
||||||
ocall (cap, Iris::Num (CAP_MASTER_DIRECT | PROVIDE_CAPABILITY, num), _T::ID)
|
ocall (cap, Num (CAP_MASTER_DIRECT | PROVIDE_CAPABILITY, num), _T::ID)
|
||||||
// Wait until a device is used by the caller again.
|
// Wait until a device is used by the caller again.
|
||||||
template <typename _T> void wait (unsigned num = 0):
|
template <typename _T> void wait (unsigned num = 0):
|
||||||
call (Iris::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
|
call (Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
|
||||||
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
|
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
|
||||||
Iris::Memory get_memory (Iris::Cap target):
|
Memory get_memory (Cap target):
|
||||||
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
|
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
|
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
|
||||||
Iris::Cap provide_memory (unsigned limit):
|
Cap provide_memory (unsigned limit):
|
||||||
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
|
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
// Signal the parent that the initialisation phase is over.
|
// Signal the parent that the initialisation phase is over.
|
||||||
void init_done (Iris::Num stage = 0):
|
void init_done (Num stage = 0):
|
||||||
call (CAP_MASTER_DIRECT | INIT_DONE, stage)
|
call (CAP_MASTER_DIRECT | INIT_DONE, stage)
|
||||||
// Exit the program. The parent does not reply, but kills the process.
|
// Exit the program. The parent does not reply, but kills the process.
|
||||||
void exit (Iris::Num code):
|
void exit (Num code):
|
||||||
call (CAP_MASTER_DIRECT | EXIT, code)
|
call (CAP_MASTER_DIRECT | EXIT, code)
|
||||||
|
|
||||||
// Keyboard interface.
|
// Keyboard interface.
|
||||||
struct Keyboard : public Device:
|
struct Keyboard : public Event:
|
||||||
Keyboard (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
|
Keyboard (Cap c = Cap ()) : Event (c):
|
||||||
enum request:
|
enum request:
|
||||||
SET_CB = Parent::ID
|
GET_NUM_KEYS = Parent::ID
|
||||||
GET_NUM_KEYS
|
|
||||||
GET_KEYS
|
GET_KEYS
|
||||||
ID
|
ID
|
||||||
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
|
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
|
||||||
enum constant:
|
enum constant:
|
||||||
RELEASE = 1 << 31
|
RELEASE = 1 << 31
|
||||||
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
|
|
||||||
void set_cb (Iris::Cap cb):
|
|
||||||
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
|
||||||
// Get the number of keys on the keyboard.
|
// Get the number of keys on the keyboard.
|
||||||
unsigned get_num_keys ():
|
unsigned get_num_keys ():
|
||||||
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
|
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
|
||||||
@ -182,21 +187,21 @@ namespace Iris:
|
|||||||
|
|
||||||
// Buzzer interface.
|
// Buzzer interface.
|
||||||
struct Buzzer : public Device:
|
struct Buzzer : public Device:
|
||||||
Buzzer (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
|
Buzzer (Cap c = Cap ()) : Device (c):
|
||||||
enum request:
|
enum request:
|
||||||
BEEP = Keyboard::ID
|
BEEP = Keyboard::ID
|
||||||
STOP
|
STOP
|
||||||
ID
|
ID
|
||||||
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
|
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
|
||||||
void beep (unsigned freq, unsigned ms, unsigned volume, Iris::Cap cb = Iris::Cap ()):
|
void beep (unsigned freq, unsigned ms, unsigned volume, Cap cb = Cap ()):
|
||||||
ocall (cb, Iris::Num (CAP_MASTER_DIRECT | BEEP, volume), Iris::Num (freq, ms))
|
ocall (cb, Num (CAP_MASTER_DIRECT | BEEP, volume), Num (freq, ms))
|
||||||
// Abort current beep, if any.
|
// Abort current beep, if any.
|
||||||
void stop ():
|
void stop ():
|
||||||
call (CAP_MASTER_DIRECT | STOP)
|
call (CAP_MASTER_DIRECT | STOP)
|
||||||
|
|
||||||
// Display interface.
|
// Display interface.
|
||||||
struct Display : public Device:
|
struct Display : public Device:
|
||||||
Display (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
|
Display (Cap c = Cap ()) : Device (c):
|
||||||
enum request:
|
enum request:
|
||||||
SET_EOF_CB = Buzzer::ID
|
SET_EOF_CB = Buzzer::ID
|
||||||
MAP_FB
|
MAP_FB
|
||||||
@ -205,22 +210,22 @@ namespace Iris:
|
|||||||
ID
|
ID
|
||||||
// Register an end-of-frame callback.
|
// Register an end-of-frame callback.
|
||||||
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
|
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
|
||||||
void set_eof_cb (Iris::Cap cb):
|
void set_eof_cb (Cap cb):
|
||||||
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
|
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
|
||||||
// Map the framebuffer into memory.
|
// Map the framebuffer into memory.
|
||||||
Iris::Caps map_fb (unsigned address, Iris::Memory mem = Iris::my_memory, bool use = true):
|
Caps map_fb (unsigned address, Memory mem = my_memory, bool use = true):
|
||||||
iocall (mem, Iris::Num (CAP_MASTER_DIRECT | MAP_FB, use ? 1 : 0), address)
|
iocall (mem, Num (CAP_MASTER_DIRECT | MAP_FB, use ? 1 : 0), address)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
void unmap_fb (Iris::Caps caps):
|
void unmap_fb (Caps caps):
|
||||||
ocall (caps, CAP_MASTER_DIRECT | UNMAP_FB)
|
ocall (caps, CAP_MASTER_DIRECT | UNMAP_FB)
|
||||||
// Get information about the display.
|
// Get information about the display.
|
||||||
void get_info ():
|
void get_info ():
|
||||||
// TODO: Interface is to be designed.
|
// TODO: Interface is to be designed.
|
||||||
Iris::panic (0, "using undefined interface Display::get_info ()")
|
panic (0, "using undefined interface Display::get_info ()")
|
||||||
|
|
||||||
// Numerical setting, such as a display backlight.
|
// Numerical setting, such as a display backlight.
|
||||||
struct Setting : public Iris::Device:
|
struct Setting : public Device:
|
||||||
Setting (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
|
Setting (Cap c = Cap ()) : Device (c):
|
||||||
enum request:
|
enum request:
|
||||||
SET = Display::ID
|
SET = Display::ID
|
||||||
GET_RANGE
|
GET_RANGE
|
||||||
@ -238,8 +243,8 @@ namespace Iris:
|
|||||||
// Seekable is not a class, it is identical to [W]String.
|
// Seekable is not a class, it is identical to [W]String.
|
||||||
|
|
||||||
// Directory interface.
|
// Directory interface.
|
||||||
struct Directory : public Iris::Cap:
|
struct Directory : public Cap:
|
||||||
Directory (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
Directory (Cap c = Cap ()) : Cap (c):
|
||||||
enum request:
|
enum request:
|
||||||
GET_SIZE = Setting::ID
|
GET_SIZE = Setting::ID
|
||||||
GET_NAME
|
GET_NAME
|
||||||
@ -249,19 +254,19 @@ namespace Iris:
|
|||||||
UNLOCK_RO
|
UNLOCK_RO
|
||||||
ID
|
ID
|
||||||
// Get the number of entries in this directory.
|
// Get the number of entries in this directory.
|
||||||
Iris::Num get_size ():
|
Num get_size ():
|
||||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||||
// Get the filename.
|
// Get the filename.
|
||||||
String get_name (Iris::Num idx):
|
String get_name (Num idx):
|
||||||
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
|
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
// Get the file.
|
// Get the file.
|
||||||
Iris::Cap get_file_ro (Iris::Num idx):
|
Cap get_file_ro (Num idx):
|
||||||
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
|
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
// Get file info. TODO: define possible types.
|
// Get file info. TODO: define possible types.
|
||||||
Iris::Num get_file_info (Iris::Num idx, unsigned type):
|
Num get_file_info (Num idx, unsigned type):
|
||||||
return icall (Iris::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
|
return icall (Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
|
||||||
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
|
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
|
||||||
void lock_ro ():
|
void lock_ro ():
|
||||||
call (CAP_MASTER_DIRECT | LOCK_RO)
|
call (CAP_MASTER_DIRECT | LOCK_RO)
|
||||||
@ -269,7 +274,7 @@ namespace Iris:
|
|||||||
void unlock_ro ():
|
void unlock_ro ():
|
||||||
call (CAP_MASTER_DIRECT | UNLOCK_RO)
|
call (CAP_MASTER_DIRECT | UNLOCK_RO)
|
||||||
struct WDirectory : public Directory:
|
struct WDirectory : public Directory:
|
||||||
WDirectory (Iris::Cap c = Iris::Cap ()) : Directory (c):
|
WDirectory (Cap c = Cap ()) : Directory (c):
|
||||||
enum request:
|
enum request:
|
||||||
GET_FILE = Directory::ID
|
GET_FILE = Directory::ID
|
||||||
CREATE_FILE
|
CREATE_FILE
|
||||||
@ -278,15 +283,15 @@ namespace Iris:
|
|||||||
UNLOCK
|
UNLOCK
|
||||||
ID
|
ID
|
||||||
// Get the file.
|
// Get the file.
|
||||||
Iris::Cap get_file (Iris::Num idx):
|
Cap get_file (Num idx):
|
||||||
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
|
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
// Create a new file. After this, any index may map to a different file.
|
// Create a new file. After this, any index may map to a different file.
|
||||||
Iris::Cap create_file (String name):
|
Cap create_file (String name):
|
||||||
icall (CAP_MASTER_DIRECT | CREATE_FILE)
|
icall (CAP_MASTER_DIRECT | CREATE_FILE)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
// Delete a file. After this, any index may map to a different file.
|
// Delete a file. After this, any index may map to a different file.
|
||||||
void delete_file (Iris::Num idx):
|
void delete_file (Num idx):
|
||||||
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
|
||||||
// Lock the directory. Write operations can only be done when the directory is locked.
|
// Lock the directory. Write operations can only be done when the directory is locked.
|
||||||
void lock ():
|
void lock ():
|
||||||
@ -297,34 +302,34 @@ namespace Iris:
|
|||||||
|
|
||||||
// A filesystem turns a String into a Directory.
|
// A filesystem turns a String into a Directory.
|
||||||
struct Filesystem : public Device:
|
struct Filesystem : public Device:
|
||||||
Filesystem (Iris::Cap c = Iris::Cap ()) : Device (c):
|
Filesystem (Cap c = Cap ()) : Device (c):
|
||||||
enum request:
|
enum request:
|
||||||
USE_DEVICE = WDirectory::ID
|
USE_DEVICE = WDirectory::ID
|
||||||
USE_DEVICE_RO
|
USE_DEVICE_RO
|
||||||
ID
|
ID
|
||||||
WDirectory use_device (WString dev):
|
WDirectory use_device (WString dev):
|
||||||
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
|
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
Directory use_device_ro (String dev):
|
Directory use_device_ro (String dev):
|
||||||
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
|
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
|
||||||
return Iris::get_arg ()
|
return get_arg ()
|
||||||
|
|
||||||
// Stream interface.
|
// Stream interface.
|
||||||
struct Stream : public Iris::Cap:
|
struct Stream : public Cap:
|
||||||
Stream (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
Stream (Cap c = Cap ()) : Cap (c):
|
||||||
enum request:
|
enum request:
|
||||||
READ = Filesystem::ID
|
READ = Filesystem::ID
|
||||||
WRITE
|
WRITE
|
||||||
ID
|
ID
|
||||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
// Try to read size bytes. Returns the number of bytes successfully read.
|
||||||
Iris::Num read (Iris::Num size, bool block):
|
Num read (Num size, bool block):
|
||||||
return icall (Iris::Num (CAP_MASTER_DIRECT | READ, block), size)
|
return icall (Num (CAP_MASTER_DIRECT | READ, block), size)
|
||||||
// Try to write size bytes. Returns the number of bytes successfully written.
|
// Try to write size bytes. Returns the number of bytes successfully written.
|
||||||
Iris::Num write (String s, Iris::Num size):
|
Num write (String s, Num size):
|
||||||
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
|
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
|
||||||
|
|
||||||
struct UI : public Iris::Cap:
|
struct UI : public Cap:
|
||||||
UI (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
|
UI (Cap c = Cap ()) : Cap (c):
|
||||||
enum request:
|
enum request:
|
||||||
GET_STATE = Stream::ID
|
GET_STATE = Stream::ID
|
||||||
EVENT
|
EVENT
|
||||||
@ -332,16 +337,16 @@ namespace Iris:
|
|||||||
ID
|
ID
|
||||||
enum constant:
|
enum constant:
|
||||||
INPUT = 1 << 31
|
INPUT = 1 << 31
|
||||||
void get_state (Iris::Cap cap):
|
void get_state (Cap cap):
|
||||||
ocall (cap, CAP_MASTER_DIRECT | GET_STATE)
|
ocall (cap, CAP_MASTER_DIRECT | GET_STATE)
|
||||||
void event (unsigned code, unsigned value = 0):
|
void event (unsigned code, unsigned value = 0):
|
||||||
call (Iris::Num (CAP_MASTER_DIRECT | EVENT, code), value)
|
call (Num (CAP_MASTER_DIRECT | EVENT, code), value)
|
||||||
void exit ():
|
void exit ():
|
||||||
call (CAP_MASTER_DIRECT | EXIT)
|
call (CAP_MASTER_DIRECT | EXIT)
|
||||||
|
|
||||||
// Block device interface.
|
// Block device interface.
|
||||||
struct Block_device : public WString:
|
struct Block_device : public WString:
|
||||||
Block_device (Iris::Cap c = Iris::Cap ()) : WString (c):
|
Block_device (Cap c = Cap ()) : WString (c):
|
||||||
// TODO: to be designed.
|
// TODO: to be designed.
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
driver driver_gpio = "gpio.elf"
|
driver driver_gpio = "gpio.elf"
|
||||||
program alarm = "alarm.elf"
|
program alarm = "alarm.elf"
|
||||||
program gui = "gui.elf"
|
program gui = "gui.elf"
|
||||||
|
#driver nand = "nand.elf"
|
||||||
|
driver sdmmc = "sd+mmc.elf"
|
||||||
|
|
||||||
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
|
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
|
||||||
receive driver_lcd / Display = display
|
receive driver_lcd / Display = display
|
||||||
@ -12,7 +14,9 @@
|
|||||||
receive driver_buzzer / Buzzer = buzzer
|
receive driver_buzzer / Buzzer = buzzer
|
||||||
receive driver_gpio / Keyboard , 0 = keyboard
|
receive driver_gpio / Keyboard , 0 = keyboard
|
||||||
receive driver_gpio / Keyboard , 1 = sysreq
|
receive driver_gpio / Keyboard , 1 = sysreq
|
||||||
|
receive driver_gpio / Event = sdmmc_gpio
|
||||||
receive alarm / UI = ui
|
receive alarm / UI = ui
|
||||||
|
receive sdmmc / WString = sdmmc
|
||||||
|
|
||||||
# sysreq <cap> use a capability as the system request keyboard.
|
# sysreq <cap> use a capability as the system request keyboard.
|
||||||
sysreq sysreq
|
sysreq sysreq
|
||||||
@ -23,6 +27,7 @@
|
|||||||
give gui / Setting = display_bright
|
give gui / Setting = display_bright
|
||||||
give gui / Buzzer = buzzer
|
give gui / Buzzer = buzzer
|
||||||
give gui / Keyboard = keyboard
|
give gui / Keyboard = keyboard
|
||||||
|
give sdmmc / Event = sdmmc_gpio
|
||||||
|
|
||||||
# include <file> include a file as another config file.
|
# include <file> include a file as another config file.
|
||||||
|
|
||||||
|
@ -27,9 +27,9 @@ LDFLAGS = --omagic -Ttext $(load)
|
|||||||
|
|
||||||
arch_iris_sources = mips/interrupts.cc mips/arch.cc
|
arch_iris_sources = mips/interrupts.cc mips/arch.cc
|
||||||
boot_sources = mips/init.cc mips/nanonote/board.cc
|
boot_sources = mips/init.cc mips/nanonote/board.cc
|
||||||
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh devices.hh
|
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
|
||||||
boot_threads = bootinit udc
|
boot_threads = bootinit udc
|
||||||
programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui
|
programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui nand sd+mmc
|
||||||
|
|
||||||
all: test
|
all: test
|
||||||
|
|
||||||
|
@ -46,6 +46,13 @@ void board_init ():
|
|||||||
// Use some gpio pins for lcd.
|
// Use some gpio pins for lcd.
|
||||||
gpio_as_gpio (2, (1 << 21) | (1 << 22) | (1 << 23))
|
gpio_as_gpio (2, (1 << 21) | (1 << 22) | (1 << 23))
|
||||||
gpio_as_output (2, (1 << 21) | (1 << 22) | (1 << 23))
|
gpio_as_output (2, (1 << 21) | (1 << 22) | (1 << 23))
|
||||||
|
// And some for sd/mmc.
|
||||||
|
gpio_as_gpio (3, (1 << 0) | (1 << 2))
|
||||||
|
gpio_as_output (3, 1 << 2)
|
||||||
|
gpio_as_input (3, 1 << 0)
|
||||||
|
gpio_disable_pull (3, (1 << 0) | (1 << 2))
|
||||||
|
// Disable power to sd/mmc by default.
|
||||||
|
gpio_set (3, 1 << 2)
|
||||||
// Set up keyboard: this breaks uart receive.
|
// Set up keyboard: this breaks uart receive.
|
||||||
gpio_as_gpio (3, 0x05fc0000)
|
gpio_as_gpio (3, 0x05fc0000)
|
||||||
// Set up timed interrupts.
|
// Set up timed interrupts.
|
||||||
|
@ -120,6 +120,7 @@ static void __map_io (unsigned physical, unsigned mapping):
|
|||||||
#define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (1)
|
#define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (1)
|
||||||
#define map_gpio() do { __map_io (GPIO_PHYSICAL, GPIO_BASE); } while (0)
|
#define map_gpio() do { __map_io (GPIO_PHYSICAL, GPIO_BASE); } while (0)
|
||||||
#define map_aic() do { __map_io (AIC_PHYSICAL, AIC_BASE); } while (0)
|
#define map_aic() do { __map_io (AIC_PHYSICAL, AIC_BASE); } while (0)
|
||||||
|
#define map_msc() do { __map_io (MSC_PHYSICAL, MSC_BASE); } while (0)
|
||||||
#define map_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0)
|
#define map_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0)
|
||||||
#define map_i2c() do { __map_io (I2C_PHYSICAL, I2C_BASE); } while (0)
|
#define map_i2c() do { __map_io (I2C_PHYSICAL, I2C_BASE); } while (0)
|
||||||
#define map_ssi() do { __map_io (SSI_PHYSICAL, SSI_BASE); } while (0)
|
#define map_ssi() do { __map_io (SSI_PHYSICAL, SSI_BASE); } while (0)
|
||||||
@ -3140,14 +3141,8 @@ static void msc_set_cmdat_res_format(unsigned r):
|
|||||||
#define msc_rd_rxfifo() ( MSC_RXFIFO )
|
#define msc_rd_rxfifo() ( MSC_RXFIFO )
|
||||||
#define msc_wr_txfifo(v) ( MSC_TXFIFO = v )
|
#define msc_wr_txfifo(v) ( MSC_TXFIFO = v )
|
||||||
|
|
||||||
static void msc_reset():
|
|
||||||
MSC_STRPCL = MSC_STRPCL_RESET
|
|
||||||
while MSC_STAT & MSC_STAT_IS_RESETTING:
|
|
||||||
|
|
||||||
#define msc_start_clk() (MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START)
|
#define msc_start_clk() (MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START)
|
||||||
|
|
||||||
#define msc_stop_clk() (MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP)
|
|
||||||
|
|
||||||
#define MMC_CLK 19169200
|
#define MMC_CLK 19169200
|
||||||
#define SD_CLK 24576000
|
#define SD_CLK 24576000
|
||||||
|
|
||||||
|
@ -12,11 +12,12 @@ enum Outs:
|
|||||||
ALARM
|
ALARM
|
||||||
NUM_OUTS
|
NUM_OUTS
|
||||||
|
|
||||||
static UI <NUM_INS, NUM_OUTS> ui
|
typedef UI <NUM_INS, NUM_OUTS> ui_t
|
||||||
static UI <NUM_INS, NUM_OUTS>::in <unsigned> total_time
|
static ui_t ui
|
||||||
static UI <NUM_INS, NUM_OUTS>::in_event do_start
|
static ui_t::in <unsigned> total_time
|
||||||
static UI <NUM_INS, NUM_OUTS>::out <unsigned> current_time
|
static ui_t::in_event do_start
|
||||||
static UI <NUM_INS, NUM_OUTS>::out_event do_alarm
|
static ui_t::out <unsigned> current_time
|
||||||
|
static ui_t::out_event do_alarm
|
||||||
|
|
||||||
static bool ticking
|
static bool ticking
|
||||||
|
|
||||||
@ -56,7 +57,8 @@ Iris::Num start ():
|
|||||||
switch Iris::recv.protected_data.l:
|
switch Iris::recv.protected_data.l:
|
||||||
case ~0:
|
case ~0:
|
||||||
// alarm.
|
// alarm.
|
||||||
current_time = current_time - 1
|
if current_time:
|
||||||
|
current_time = current_time - 1
|
||||||
if !current_time:
|
if !current_time:
|
||||||
do_alarm ()
|
do_alarm ()
|
||||||
ticking = false
|
ticking = false
|
||||||
|
@ -137,7 +137,7 @@ extern "C":
|
|||||||
Iris::recv.reply = Iris::alloc_cap ()
|
Iris::recv.reply = Iris::alloc_cap ()
|
||||||
Iris::recv.arg = Iris::alloc_cap ()
|
Iris::recv.arg = Iris::alloc_cap ()
|
||||||
Iris::Num ret = start ()
|
Iris::Num ret = start ()
|
||||||
Iris::my_parent.invoke (~0, ret)
|
Iris::my_parent.exit (ret)
|
||||||
Iris::my_memory.destroy (Iris::my_thread)
|
Iris::my_memory.destroy (Iris::my_thread)
|
||||||
// The program no longer exists. If it somehow does, generate an address fault.
|
// The program no longer exists. If it somehow does, generate an address fault.
|
||||||
while true:
|
while true:
|
||||||
|
@ -25,6 +25,7 @@ enum ins:
|
|||||||
static Iris::Display display
|
static Iris::Display display
|
||||||
static Iris::Buzzer buzzer
|
static Iris::Buzzer buzzer
|
||||||
static unsigned *framebuffer
|
static unsigned *framebuffer
|
||||||
|
static unsigned alarming
|
||||||
|
|
||||||
enum PD:
|
enum PD:
|
||||||
UI
|
UI
|
||||||
@ -151,38 +152,57 @@ static void draw_time (bool upper, unsigned time):
|
|||||||
draw_num (upper, 3, time / 10)
|
draw_num (upper, 3, time / 10)
|
||||||
draw_num (upper, 4, time % 10)
|
draw_num (upper, 4, time % 10)
|
||||||
|
|
||||||
static void beep ():
|
static void do_alarm ():
|
||||||
buzzer.beep (4 * 440, 1000, ~0)
|
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 ():
|
Iris::Num start ():
|
||||||
Iris::my_parent.init_done ()
|
Iris::my_parent.init_done ()
|
||||||
|
|
||||||
display = Iris::my_parent.get_capability <Iris::Display> ()
|
display = Iris::my_parent.get_capability <Iris::Display> ()
|
||||||
Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> ()
|
Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> ()
|
||||||
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
|
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
|
||||||
buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
|
buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
|
||||||
Iris::UI app = Iris::my_parent.get_capability <Iris::UI> ()
|
Iris::UI app = Iris::my_parent.get_capability <Iris::UI> ()
|
||||||
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
|
|
||||||
framebuffer = (unsigned *)0x15000
|
framebuffer = (unsigned *)0x15000
|
||||||
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
|
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
|
||||||
bright.set (bright.get_range ())
|
|
||||||
|
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 ())
|
app.get_state (cb.copy ())
|
||||||
Iris::free_cap (cb)
|
Iris::free_cap (cb)
|
||||||
|
|
||||||
cb = Iris::my_receiver.create_capability (KBD)
|
cb = Iris::my_receiver.create_capability (KBD)
|
||||||
keyboard.set_cb (cb.copy ())
|
keyboard.set_cb (cb.copy ())
|
||||||
Iris::free_cap (cb)
|
Iris::free_cap (cb)
|
||||||
|
|
||||||
draw_num (false, 2, 10)
|
draw_num (false, 2, 10)
|
||||||
draw_num (true, 2, 10)
|
draw_num (true, 2, 10)
|
||||||
|
|
||||||
unsigned total_time = 0
|
unsigned total_time = 0
|
||||||
|
alarming = 0
|
||||||
while true:
|
while true:
|
||||||
Iris::wait ()
|
Iris::wait ()
|
||||||
switch Iris::recv.protected_data.l:
|
switch Iris::recv.protected_data.l:
|
||||||
|
case ~0:
|
||||||
|
// Alarm.
|
||||||
|
if alarming:
|
||||||
|
do_alarm ()
|
||||||
|
break
|
||||||
case UI:
|
case UI:
|
||||||
switch Iris::recv.data[0].l:
|
switch Iris::recv.data[0].l:
|
||||||
case CURRENT_TIME:
|
case CURRENT_TIME:
|
||||||
draw_time (false, Iris::recv.data[1].l)
|
draw_time (false, Iris::recv.data[1].l)
|
||||||
break
|
break
|
||||||
case ALARM:
|
case ALARM:
|
||||||
beep ()
|
do_alarm ()
|
||||||
break
|
break
|
||||||
case TOTAL_TIME | Iris::UI::INPUT:
|
case TOTAL_TIME | Iris::UI::INPUT:
|
||||||
total_time = Iris::recv.data[1].l
|
total_time = Iris::recv.data[1].l
|
||||||
@ -194,6 +214,7 @@ Iris::Num start ():
|
|||||||
case KBD:
|
case KBD:
|
||||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||||
break
|
break
|
||||||
|
alarming = 0
|
||||||
switch Iris::recv.data[0].l:
|
switch Iris::recv.data[0].l:
|
||||||
case Key::VOLUME_UP:
|
case Key::VOLUME_UP:
|
||||||
total_time += 60
|
total_time += 60
|
||||||
@ -236,3 +257,11 @@ Iris::Num start ():
|
|||||||
break
|
break
|
||||||
case Key::ENTER:
|
case Key::ENTER:
|
||||||
app.event (START)
|
app.event (START)
|
||||||
|
break
|
||||||
|
case Key::BACKSPACE:
|
||||||
|
screen_on = !screen_on
|
||||||
|
if screen_on:
|
||||||
|
bright.set (screen_max)
|
||||||
|
else:
|
||||||
|
bright.set (0)
|
||||||
|
break
|
||||||
|
@ -269,6 +269,7 @@ static Type types[] = {
|
|||||||
{ "String", 6, Iris::String::ID },
|
{ "String", 6, Iris::String::ID },
|
||||||
{ "WString", 7, Iris::WString::ID },
|
{ "WString", 7, Iris::WString::ID },
|
||||||
{ "Device", 6, Iris::Device::ID },
|
{ "Device", 6, Iris::Device::ID },
|
||||||
|
{ "Event", 5, Iris::Event::ID },
|
||||||
{ "Parent", 6, Iris::Parent::ID },
|
{ "Parent", 6, Iris::Parent::ID },
|
||||||
{ "Keyboard", 8, Iris::Keyboard::ID },
|
{ "Keyboard", 8, Iris::Keyboard::ID },
|
||||||
{ "Buzzer", 6, Iris::Buzzer::ID },
|
{ "Buzzer", 6, Iris::Buzzer::ID },
|
||||||
|
199
source/nand.ccp
Normal file
199
source/nand.ccp
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
#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"
|
||||||
|
|
||||||
|
// The following defines are taken from mtd/nand.h in the Linux source.
|
||||||
|
|
||||||
|
// Standard NAND flash commands
|
||||||
|
#define CMD_READ0 0
|
||||||
|
#define CMD_READ1 1
|
||||||
|
#define CMD_RNDOUT 5
|
||||||
|
#define CMD_PAGEPROG 0x10
|
||||||
|
#define CMD_READOOB 0x50
|
||||||
|
#define CMD_ERASE1 0x60
|
||||||
|
#define CMD_STATUS 0x70
|
||||||
|
#define CMD_STATUS_MULTI 0x71
|
||||||
|
#define CMD_SEQIN 0x80
|
||||||
|
#define CMD_RNDIN 0x85
|
||||||
|
#define CMD_READID 0x90
|
||||||
|
#define CMD_ERASE2 0xd0
|
||||||
|
#define CMD_RESET 0xff
|
||||||
|
|
||||||
|
// Extended commands for large page devices
|
||||||
|
#define CMD_READSTART 0x30
|
||||||
|
#define CMD_RNDOUTSTART 0xE0
|
||||||
|
#define CMD_CACHEDPROG 0x15
|
||||||
|
|
||||||
|
// Extended commands for AG-AND device
|
||||||
|
// Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
|
||||||
|
// there is no way to distinguish that from NAND_CMD_READ0
|
||||||
|
// until the remaining sequence of commands has been completed
|
||||||
|
// so add a high order bit and mask it off in the command.
|
||||||
|
#define CMD_DEPLETE1 0x100
|
||||||
|
#define CMD_DEPLETE2 0x38
|
||||||
|
#define CMD_STATUS_MULTI 0x71
|
||||||
|
#define CMD_STATUS_ERROR 0x72
|
||||||
|
// multi-bank error status (banks 0-3)
|
||||||
|
#define CMD_STATUS_ERROR0 0x73
|
||||||
|
#define CMD_STATUS_ERROR1 0x74
|
||||||
|
#define CMD_STATUS_ERROR2 0x75
|
||||||
|
#define CMD_STATUS_ERROR3 0x76
|
||||||
|
#define CMD_STATUS_RESET 0x7f
|
||||||
|
#define CMD_STATUS_CLEAR 0xff
|
||||||
|
|
||||||
|
#define CMD_NONE -1
|
||||||
|
|
||||||
|
// Status bits
|
||||||
|
#define STATUS_FAIL 0x01
|
||||||
|
#define STATUS_FAIL_N1 0x02
|
||||||
|
#define STATUS_TRUE_READY 0x20
|
||||||
|
#define STATUS_READY 0x40
|
||||||
|
#define STATUS_WP 0x80
|
||||||
|
|
||||||
|
static volatile char *command
|
||||||
|
static volatile char *address
|
||||||
|
static volatile char *data
|
||||||
|
|
||||||
|
static unsigned page_bits
|
||||||
|
static unsigned redundant_bits
|
||||||
|
static unsigned block_bits
|
||||||
|
static unsigned word_size
|
||||||
|
|
||||||
|
static void unbusy ():
|
||||||
|
while !(gpio_get_port (2) & (1 << 30)):
|
||||||
|
Iris::schedule ()
|
||||||
|
|
||||||
|
static void reset ():
|
||||||
|
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)
|
||||||
|
|
||||||
|
// Set up.
|
||||||
|
gpio_as_nand ()
|
||||||
|
EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1
|
||||||
|
|
||||||
|
// Reset nand.
|
||||||
|
*command = CMD_RESET
|
||||||
|
unbusy ()
|
||||||
|
|
||||||
|
*command = CMD_READID
|
||||||
|
*address = 0
|
||||||
|
unsigned d = *data
|
||||||
|
//unsigned maker = d
|
||||||
|
d = *data
|
||||||
|
//unsigned device = d
|
||||||
|
d = *data
|
||||||
|
//unsigned internal_chip_number = 1 << (d & 0x3)
|
||||||
|
//unsigned cell_type = 2 << ((d >> 2) & 0x3)
|
||||||
|
//unsigned simultaneously_programmed_pages = 1 << ((d >> 4) & 0x3)
|
||||||
|
//bool can_interleave_program_between_chips = d & 0x40
|
||||||
|
//bool can_cache_program = d & 0x80
|
||||||
|
d = *data
|
||||||
|
page_bits = 10 + (d & 3)
|
||||||
|
kdebug ("page bits: ")
|
||||||
|
kdebug_num (page_bits)
|
||||||
|
kdebug ("\n")
|
||||||
|
redundant_bits = (d & 4 ? 4 : 3)
|
||||||
|
block_bits = 64 + ((d >> 4) & 3)
|
||||||
|
word_size = (d & 0x40 ? 16 : 8)
|
||||||
|
//unsigned serial_access_minimum = (d & 0x80 ? 25 : 50)
|
||||||
|
d = *data
|
||||||
|
//unsigned num_planes = 1 << ((d >> 2) & 3)
|
||||||
|
//unsigned plane_bits = 26 + ((d >> 4) & 7)
|
||||||
|
|
||||||
|
static void read (unsigned a, char *buffer):
|
||||||
|
unsigned column = a & ((1 << page_bits) - 1)
|
||||||
|
unsigned row = a >> page_bits
|
||||||
|
kdebug ("reading: ")
|
||||||
|
kdebug_num (a)
|
||||||
|
kdebug ("/")
|
||||||
|
kdebug_num (row)
|
||||||
|
kdebug ("/")
|
||||||
|
kdebug_num (column)
|
||||||
|
kdebug (": ")
|
||||||
|
*command = CMD_READ0
|
||||||
|
*address = column
|
||||||
|
*address = column >> 8
|
||||||
|
*address = row
|
||||||
|
*address = row >> 8
|
||||||
|
*address = row >> 16
|
||||||
|
*command = CMD_READSTART
|
||||||
|
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST
|
||||||
|
// Wait for nand to be ready.
|
||||||
|
unbusy ()
|
||||||
|
for unsigned t = 0; t < 0x200; ++t:
|
||||||
|
buffer[t] = *data
|
||||||
|
char error[9]
|
||||||
|
unsigned errcol = (1 << page_bits) + (column >> 5)
|
||||||
|
*command = CMD_RNDOUT
|
||||||
|
*address = errcol
|
||||||
|
*address = errcol >> 8
|
||||||
|
*command = CMD_RNDOUTSTART
|
||||||
|
for unsigned t = 0; t < 9; ++t:
|
||||||
|
error[t] = *data
|
||||||
|
EMC_NFPAR (0) = ((unsigned *)error)[0]
|
||||||
|
EMC_NFPAR (1) = ((unsigned *)error)[1]
|
||||||
|
EMC_NFPAR (2) = error[9]
|
||||||
|
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY
|
||||||
|
while !(EMC_NFINTS & EMC_NFINTS_DECF):
|
||||||
|
Iris::schedule ()
|
||||||
|
// delay...
|
||||||
|
//Iris::schedule ()
|
||||||
|
unsigned errs = (EMC_NFINTS & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT
|
||||||
|
|
||||||
|
Iris::Num start ():
|
||||||
|
for unsigned i = 0; i < 30; ++i:
|
||||||
|
Iris::schedule ()
|
||||||
|
map_emc ()
|
||||||
|
map_gpio ()
|
||||||
|
|
||||||
|
command = (volatile char *)0x15000
|
||||||
|
address = (volatile char *)0x16000
|
||||||
|
data = (volatile char *)0x17000
|
||||||
|
|
||||||
|
reset ()
|
||||||
|
|
||||||
|
char buffer[0x200]
|
||||||
|
|
||||||
|
// Send nand contents to serial port.
|
||||||
|
for unsigned a = 0; a < 0x4000; a += 0x200:
|
||||||
|
read (a, buffer)
|
||||||
|
//for unsigned s = 0; s < 0x10; ++s:
|
||||||
|
for unsigned t = 0; t < 0x10; ++t:
|
||||||
|
kdebug (" ")
|
||||||
|
kdebug_num (buffer[0 * 0x20 + t], 2)
|
||||||
|
kdebug ("\n")
|
||||||
|
//kdebug ("\n")
|
||||||
|
// Exit.
|
||||||
|
return 0
|
@ -165,22 +165,24 @@ unsigned const DevKbd::keys[NUM_KEYS] = {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
class PowerButton:
|
class Event:
|
||||||
bool state, started
|
bool state, started
|
||||||
|
unsigned pin
|
||||||
Iris::Cap cb
|
Iris::Cap cb
|
||||||
public:
|
public:
|
||||||
void scan ():
|
void scan ():
|
||||||
if !started:
|
if !started:
|
||||||
return
|
return
|
||||||
gpio_mask_irq (3, 1 << 29)
|
gpio_mask_irq (3, 1 << pin)
|
||||||
bool s = gpio_get_port (3) & (1 << 29)
|
bool s = gpio_get_port (3) & (1 << pin)
|
||||||
if s != state:
|
if s != state:
|
||||||
state = s
|
state = s
|
||||||
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
|
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
|
||||||
gpio_as_interrupt (3, 1 << 29, !state, true)
|
gpio_as_interrupt (3, 1 << pin, !state, true)
|
||||||
gpio_unmask_irq (3, 1 << 29)
|
gpio_unmask_irq (3, 1 << pin)
|
||||||
PowerButton ():
|
Event (unsigned p):
|
||||||
gpio_as_gpio (3, 29)
|
pin = p
|
||||||
|
gpio_as_gpio (3, pin)
|
||||||
state = true
|
state = true
|
||||||
started = false
|
started = false
|
||||||
void set_cb (Iris::Cap c):
|
void set_cb (Iris::Cap c):
|
||||||
@ -195,19 +197,24 @@ class PowerButton:
|
|||||||
enum codes:
|
enum codes:
|
||||||
KBD_DEV = 32
|
KBD_DEV = 32
|
||||||
PWR
|
PWR
|
||||||
|
SDMMC
|
||||||
|
|
||||||
Iris::Num start ():
|
Iris::Num start ():
|
||||||
map_gpio ()
|
map_gpio ()
|
||||||
|
|
||||||
DevKbd kbd
|
DevKbd kbd
|
||||||
PowerButton pwr
|
Event pwr (29)
|
||||||
|
Event sdmmc (0)
|
||||||
|
|
||||||
Iris::Device dev = Iris::my_receiver.create_capability (KBD_DEV)
|
Iris::Keyboard dev = Iris::my_receiver.create_capability (KBD_DEV)
|
||||||
Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR)
|
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> (dev.copy (), 0)
|
||||||
Iris::my_parent.provide_capability <Iris::Keyboard> (pw.copy (), 1)
|
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 (dev)
|
||||||
Iris::free_cap (pw)
|
Iris::free_cap (pw)
|
||||||
|
Iris::free_cap (sm)
|
||||||
Iris::my_parent.init_done ()
|
Iris::my_parent.init_done ()
|
||||||
if kbd.scanning ():
|
if kbd.scanning ():
|
||||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||||
@ -225,6 +232,7 @@ Iris::Num start ():
|
|||||||
// Interrupt.
|
// Interrupt.
|
||||||
pwr.scan ()
|
pwr.scan ()
|
||||||
kbd.scan ()
|
kbd.scan ()
|
||||||
|
sdmmc.scan ()
|
||||||
if kbd.scanning ():
|
if kbd.scanning ():
|
||||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||||
Iris::register_interrupt (IRQ_GPIO3)
|
Iris::register_interrupt (IRQ_GPIO3)
|
||||||
@ -235,7 +243,7 @@ Iris::Num start ():
|
|||||||
case Iris::Device::RESET:
|
case Iris::Device::RESET:
|
||||||
Iris::recv.reply.invoke ()
|
Iris::recv.reply.invoke ()
|
||||||
break
|
break
|
||||||
case Iris::Keyboard::SET_CB:
|
case Iris::Event::SET_CB:
|
||||||
Iris::Cap reply = Iris::get_reply ()
|
Iris::Cap reply = Iris::get_reply ()
|
||||||
kbd.active (Iris::get_arg ())
|
kbd.active (Iris::get_arg ())
|
||||||
reply.invoke ()
|
reply.invoke ()
|
||||||
@ -256,7 +264,7 @@ Iris::Num start ():
|
|||||||
case Iris::Device::RESET:
|
case Iris::Device::RESET:
|
||||||
Iris::recv.reply.invoke ()
|
Iris::recv.reply.invoke ()
|
||||||
break
|
break
|
||||||
case Iris::Keyboard::SET_CB:
|
case Iris::Event::SET_CB:
|
||||||
Iris::Cap reply = Iris::get_reply ()
|
Iris::Cap reply = Iris::get_reply ()
|
||||||
pwr.set_cb (Iris::get_arg ())
|
pwr.set_cb (Iris::get_arg ())
|
||||||
reply.invoke ()
|
reply.invoke ()
|
||||||
@ -268,6 +276,23 @@ Iris::Num start ():
|
|||||||
kdebug ("\n")
|
kdebug ("\n")
|
||||||
break
|
break
|
||||||
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:
|
default:
|
||||||
kdebug ("keyboard unknown num: ")
|
kdebug ("keyboard unknown num: ")
|
||||||
kdebug_num (Iris::recv.protected_data.h)
|
kdebug_num (Iris::recv.protected_data.h)
|
||||||
|
184
source/sd+mmc.ccp
Normal file
184
source/sd+mmc.ccp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#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:
|
||||||
|
static unsigned const PORT = 3
|
||||||
|
static unsigned const PIN = 2
|
||||||
|
bool check_sdio ()
|
||||||
|
void check_sdmem ()
|
||||||
|
void check_mmc ()
|
||||||
|
public:
|
||||||
|
void reset ()
|
||||||
|
void detect ()
|
||||||
|
void release ()
|
||||||
|
void interrupt ()
|
||||||
|
|
||||||
|
void Mmc::reset ():
|
||||||
|
// Enable slow clock to msc.
|
||||||
|
CPM_MSCCDR = ~0
|
||||||
|
cpm_start_msc ()
|
||||||
|
// Enable msc pins.
|
||||||
|
gpio_as_msc ()
|
||||||
|
// Disable power to card.
|
||||||
|
gpio_as_gpio (PORT, 1 << PIN)
|
||||||
|
gpio_as_output (PORT, 1 << PIN)
|
||||||
|
gpio_disable_pull (PORT, 1 << PIN)
|
||||||
|
gpio_set (PORT, 1 << PIN)
|
||||||
|
|
||||||
|
// Stop the clock.
|
||||||
|
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
|
||||||
|
while MSC_STAT & MSC_STAT_CLK_EN:
|
||||||
|
Iris::schedule ()
|
||||||
|
|
||||||
|
// Initialize registers.
|
||||||
|
MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_128
|
||||||
|
MSC_RESTO = 64
|
||||||
|
MSC_RDTO = ~0
|
||||||
|
MSC_BLKLEN = 0x200
|
||||||
|
MSC_NOB = 0
|
||||||
|
MSC_IMASK = ~0
|
||||||
|
MSC_ARG = 0
|
||||||
|
|
||||||
|
// Reset controller and inserted devices.
|
||||||
|
MSC_STRPCL = MSC_STRPCL_RESET
|
||||||
|
while MSC_STAT & MSC_STAT_IS_RESETTING:
|
||||||
|
Iris::schedule ()
|
||||||
|
|
||||||
|
// Start the clock.
|
||||||
|
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
|
||||||
|
// Set cards, if any, to idle.
|
||||||
|
MSC_CMD = 0
|
||||||
|
MSC_CMDAT = MSC_CMDAT_RESPONSE_NONE
|
||||||
|
msc_start_op ()
|
||||||
|
while !msc_ireg_end_cmd_res ():
|
||||||
|
Iris::schedule ()
|
||||||
|
msc_ireg_clear_end_cmd_res ()
|
||||||
|
|
||||||
|
// Reset SDIO device, if any.
|
||||||
|
MSC_CMD = 52
|
||||||
|
MSC_ARG = 0x88000C08
|
||||||
|
MSC_CMDAT = MSC_CMDAT_RESPONSE_R5
|
||||||
|
msc_start_op ()
|
||||||
|
while !msc_ireg_end_cmd_res ():
|
||||||
|
Iris::schedule ()
|
||||||
|
msc_ireg_clear_end_cmd_res ()
|
||||||
|
|
||||||
|
bool Mmc::check_sdio ():
|
||||||
|
// 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.
|
||||||
|
// 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.
|
||||||
|
// 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.
|
||||||
|
// 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.
|
||||||
|
// 10. Go to check MMC, because we can assure that there is no SDMEM card.
|
||||||
|
return false
|
||||||
|
|
||||||
|
void Mmc::check_sdmem ():
|
||||||
|
// 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.
|
||||||
|
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
|
||||||
|
// 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.
|
||||||
|
// 7. Send CMD2 (ALL_SEND_CID) to get the card 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.
|
||||||
|
// 10. Go to check MMC.
|
||||||
|
|
||||||
|
void Mmc::check_mmc ():
|
||||||
|
// 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.
|
||||||
|
// 8. If there are other MMC cards, then go to 5.
|
||||||
|
|
||||||
|
void Mmc::detect ():
|
||||||
|
kdebug ("mmc detect\n")
|
||||||
|
gpio_clear (PORT, 1 << PIN)
|
||||||
|
if check_sdio ():
|
||||||
|
check_sdmem ()
|
||||||
|
check_mmc ()
|
||||||
|
|
||||||
|
void Mmc::release ():
|
||||||
|
kdebug ("mmc release\n")
|
||||||
|
gpio_set (PORT, 1 << PIN)
|
||||||
|
|
||||||
|
void Mmc::interrupt ():
|
||||||
|
kdebug ("mmc interrupt\n")
|
||||||
|
|
||||||
|
|
||||||
|
enum types:
|
||||||
|
DETECT
|
||||||
|
REQUEST
|
||||||
|
|
||||||
|
Iris::Num start ():
|
||||||
|
map_msc ()
|
||||||
|
map_gpio ()
|
||||||
|
map_cpm ()
|
||||||
|
|
||||||
|
Mmc mmc
|
||||||
|
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::WString> (cap.copy ())
|
||||||
|
Iris::free_cap (cap)
|
||||||
|
|
||||||
|
Iris::my_parent.init_done ()
|
||||||
|
|
||||||
|
while true:
|
||||||
|
Iris::wait ()
|
||||||
|
switch Iris::recv.protected_data.l:
|
||||||
|
case DETECT:
|
||||||
|
if Iris::recv.data[0].l:
|
||||||
|
mmc.detect ()
|
||||||
|
else:
|
||||||
|
mmc.release ()
|
||||||
|
break
|
||||||
|
case IRQ_MSC:
|
||||||
|
mmc.interrupt ()
|
||||||
|
break
|
||||||
|
case REQUEST:
|
||||||
|
kdebug ("sd+mmc request\n")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
Iris::panic (0, "unexpected request source for sd+mmc")
|
Loading…
Reference in New Issue
Block a user