mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
usb fs mostly working
This commit is contained in:
@@ -38,17 +38,17 @@ namespace Kernel:
|
||||
__recv_data_t recv
|
||||
|
||||
void print_caps ():
|
||||
// Assume __caps to be 16.
|
||||
bool used[16]
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
// Assume __caps to be 32.
|
||||
bool used[32]
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
used[i] = true
|
||||
unsigned num = 0
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
used[i - __cap_admin] = false
|
||||
++num
|
||||
kdebug_num (num, 1)
|
||||
kdebug_num (num, 2)
|
||||
kdebug (":")
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
kdebug_char (used[i] ? '#' : '.')
|
||||
kdebug_char ('\n')
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace Kernel:
|
||||
if !__first_free_slot:
|
||||
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
|
||||
kdebug ("out of slots!\n")
|
||||
Kernel::panic (0)
|
||||
return ~0
|
||||
list *ret = __first_free_slot
|
||||
__first_free_slot = ret->next
|
||||
@@ -89,6 +90,7 @@ namespace Kernel:
|
||||
if !__first_free_cap:
|
||||
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
|
||||
kdebug ("out of capabilities!\n")
|
||||
Kernel::panic (0)
|
||||
return Cap (0, CAP_NONE)
|
||||
list *ret = __first_free_cap
|
||||
__first_free_cap = ret->next
|
||||
@@ -116,7 +118,7 @@ extern "C":
|
||||
Kernel::recv.reply = Kernel::alloc_cap ()
|
||||
Kernel::recv.arg = Kernel::alloc_cap ()
|
||||
Kernel::Num ret = start ()
|
||||
Kernel::my_parent.invoke (~0, ret)
|
||||
Kernel::my_parent.exit (ret)
|
||||
Kernel::my_memory.destroy (Kernel::my_thread)
|
||||
// The program no longer exists. If it somehow does, generate an address fault.
|
||||
while true:
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
#include <elf.h>
|
||||
|
||||
#define NUM_SLOTS 4
|
||||
#define NUM_CAPS 16
|
||||
#define NUM_CAPS 32
|
||||
|
||||
static unsigned _free
|
||||
extern unsigned _end
|
||||
|
||||
void init_alloc ():
|
||||
_free = _end
|
||||
_free = (unsigned)&_end
|
||||
|
||||
char *alloc_space (unsigned pages):
|
||||
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
||||
@@ -37,18 +37,20 @@ char *alloc_space (unsigned pages):
|
||||
void *operator new[] (unsigned size):
|
||||
void *ret = (void *)_free
|
||||
size = (size + 3) & ~3
|
||||
unsigned rest = PAGE_SIZE - (size & ~PAGE_MASK)
|
||||
if rest <= size:
|
||||
_free += size
|
||||
return ret
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) & PAGE_MASK
|
||||
char *space = alloc_space (pages)
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Kernel::Page page = Kernel::my_memory.create_page ()
|
||||
page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
Kernel::my_memory.map (page, (unsigned)&space[p << PAGE_BITS])
|
||||
Kernel::free_cap (page)
|
||||
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
||||
if rest < size:
|
||||
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
char *space = alloc_space (pages)
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Kernel::Page page = Kernel::my_memory.create_page ()
|
||||
page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
Kernel::my_memory.map (page, (unsigned)&space[p << PAGE_BITS])
|
||||
Kernel::free_cap (page)
|
||||
_free += size
|
||||
//kdebug_num ((unsigned)ret)
|
||||
//kdebug ("+")
|
||||
//kdebug_num (size)
|
||||
//kdebug ("\n")
|
||||
return ret
|
||||
|
||||
struct file:
|
||||
@@ -72,8 +74,8 @@ static Directory receive_devices ():
|
||||
String data
|
||||
Filesystem fs
|
||||
bool have_data = false, have_fs = false
|
||||
Device fs_dev, data_dev
|
||||
for unsigned i = 0; i < 2; ++i:
|
||||
Device dev
|
||||
Kernel::wait ()
|
||||
if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
|
||||
kdebug ("Invalid bootstrap request.\n")
|
||||
@@ -83,23 +85,17 @@ static Directory receive_devices ():
|
||||
if have_data:
|
||||
kdebug ("duplicate device.\n")
|
||||
Kernel::panic (0)
|
||||
dev = Kernel::get_arg ()
|
||||
have_data = true
|
||||
data_dev = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
data = dev.create_user (Kernel::my_memory)
|
||||
dev.use (data)
|
||||
Kernel::free_cap (dev)
|
||||
have_data = true
|
||||
break
|
||||
case Filesystem::ID:
|
||||
if have_fs:
|
||||
kdebug ("duplicate filesystem.\n")
|
||||
Kernel::panic (0)
|
||||
dev = Kernel::get_arg ()
|
||||
have_fs = true
|
||||
fs = dev.create_user (Kernel::my_memory)
|
||||
dev.use (fs)
|
||||
Kernel::free_cap (dev)
|
||||
fs_dev = Kernel::get_arg ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
have_fs = true
|
||||
break
|
||||
default:
|
||||
kdebug ("unexpected device: ")
|
||||
@@ -107,35 +103,58 @@ static Directory receive_devices ():
|
||||
kdebug_char ('\n')
|
||||
Kernel::panic (0)
|
||||
// Initialize the root file system.
|
||||
data = data_dev.create_user (Kernel::my_memory)
|
||||
data_dev.use (data)
|
||||
fs = fs_dev.create_user (Kernel::my_memory)
|
||||
fs_dev.use (fs)
|
||||
Directory root = fs.use_device_ro (data.copy ())
|
||||
Kernel::free_cap (data)
|
||||
Kernel::free_cap (fs)
|
||||
Kernel::free_cap (data_dev)
|
||||
Kernel::free_cap (fs_dev)
|
||||
return root
|
||||
|
||||
// Make a list of all files.
|
||||
static void list_files (Directory root):
|
||||
Kernel::Num fullsize = root.get_size ()
|
||||
if fullsize.h != 0:
|
||||
kdebug ("Too many files in bootstrap directory.\n")
|
||||
kdebug ("Too many files in bootstrap directory:")
|
||||
kdebug_num (fullsize.h)
|
||||
kdebug (":")
|
||||
kdebug_num (fullsize.l)
|
||||
kdebug ("\n")
|
||||
Kernel::panic (0)
|
||||
num_files = fullsize.l
|
||||
kdebug ("files in directory: ")
|
||||
kdebug_num (num_files)
|
||||
kdebug ("\n")
|
||||
files = new file[num_files]
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files * 2)
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files)
|
||||
unsigned slot = Kernel::alloc_slot ()
|
||||
caps.use (slot)
|
||||
Kernel::free_cap (caps)
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, i * 2))
|
||||
String n = root.get_name (i)
|
||||
n.get_chars (0, files[i].name)
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, i * 2 + 1))
|
||||
kdebug ("file: ")
|
||||
for unsigned j = 0; j < 16; ++j:
|
||||
if files[i].name[j] != 0:
|
||||
kdebug_char (files[i].name[j])
|
||||
kdebug_char ('\n')
|
||||
Kernel::free_cap (n)
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, i))
|
||||
files[i].string = root.get_file_ro (i)
|
||||
Kernel::Num fullsize = files[i].string.get_size ()
|
||||
if fullsize.h != 0:
|
||||
kdebug ("initial file size too large.\n")
|
||||
kdebug ("initial file size too large: ")
|
||||
kdebug_num (fullsize.h)
|
||||
kdebug (":")
|
||||
kdebug_num (fullsize.l)
|
||||
kdebug (".\n")
|
||||
Kernel::panic (0)
|
||||
files[i].size = fullsize.l
|
||||
if max_pages < (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK:
|
||||
max_pages = (fullsize.l + PAGE_SIZE - 1) & PAGE_MASK
|
||||
if max_pages < (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS:
|
||||
max_pages = (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
|
||||
// Sort the list of files.
|
||||
static bool is_less (file *f1, file *f2):
|
||||
@@ -163,11 +182,17 @@ static void sort ():
|
||||
|
||||
static void run (file *f, bool priv):
|
||||
Kernel::Memory mem = top_memory.create_memory ()
|
||||
unsigned num_pages = (f->size + PAGE_SIZE - 1) & PAGE_MASK
|
||||
unsigned num_pages = (f->size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
for unsigned p = 0; p < num_pages; ++p:
|
||||
kdebug_num (p)
|
||||
kdebug ("/")
|
||||
kdebug_num (num_pages)
|
||||
kdebug ("\n")
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, p))
|
||||
mem.create_page ()
|
||||
Kernel::my_memory.create_page ()
|
||||
Kernel::Page (slot, p).set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING)
|
||||
f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p))
|
||||
kdebug_line ()
|
||||
Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
|
||||
Kernel::Thread thread = mem.create_thread (NUM_SLOTS)
|
||||
if priv:
|
||||
@@ -179,7 +204,11 @@ static void run (file *f, bool priv):
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_CLASS] != ELFCLASS32:
|
||||
kdebug ("invalid ELF class\n")
|
||||
kdebug ("invalid ELF class:")
|
||||
kdebug_num (header->e_ident[EI_CLASS])
|
||||
kdebug (" != ")
|
||||
kdebug_num (ELFCLASS32)
|
||||
kdebug ("\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
if header->e_ident[EI_DATA] != ELFDATA2LSB:
|
||||
@@ -200,18 +229,24 @@ static void run (file *f, bool priv):
|
||||
return
|
||||
thread.set_pc (header->e_entry)
|
||||
thread.set_sp (0x80000000)
|
||||
kdebug_line ()
|
||||
for unsigned section = 0; section < header->e_shnum; ++section:
|
||||
kdebug_line ()
|
||||
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
|
||||
if ~shdr->sh_flags & SHF_ALLOC:
|
||||
continue
|
||||
kdebug_line ()
|
||||
bool readonly = !(shdr->sh_flags & SHF_WRITE)
|
||||
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
|
||||
kdebug_line ()
|
||||
if shdr->sh_type != SHT_NOBITS:
|
||||
kdebug_line ()
|
||||
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
|
||||
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
|
||||
kdebug ("thread too large\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
kdebug_line ()
|
||||
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
|
||||
@@ -220,22 +255,39 @@ static void run (file *f, bool priv):
|
||||
// The address already has a mapping; assume that it is correct.
|
||||
Kernel::free_cap (page)
|
||||
continue
|
||||
Kernel::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
page.set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING)
|
||||
Kernel::Page (slot, idx).share (page, 0)
|
||||
kdebug ("mapping at ")
|
||||
kdebug_num (p)
|
||||
kdebug ("\n")
|
||||
if !mem.map (page, p, readonly):
|
||||
kdebug ("unable to map page\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::free_cap (page)
|
||||
kdebug_line ()
|
||||
else:
|
||||
kdebug_line ()
|
||||
if readonly:
|
||||
kdebug ("unwritable bss section\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
kdebug_line ()
|
||||
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
|
||||
Kernel::Page page = mem.mapping ((void *)p)
|
||||
if Kernel::recv.data[0].l == Kernel::NO_ERROR:
|
||||
// No error means there is no mapping.
|
||||
// No error means there is a mapping.
|
||||
Kernel::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
|
||||
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
|
||||
else:
|
||||
Kernel::free_cap (page)
|
||||
page = mem.create_page ()
|
||||
if Kernel::recv.data[0].l != Kernel::NO_ERROR:
|
||||
kdebug ("out of memory\n")
|
||||
@@ -250,56 +302,103 @@ static void run (file *f, bool priv):
|
||||
Kernel::panic (0)
|
||||
return
|
||||
Kernel::free_cap (page)
|
||||
else:
|
||||
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
|
||||
((unsigned *)&mapping[p])[(a & ~PAGE_MASK) >> 2] = 0
|
||||
kdebug_line ()
|
||||
kdebug_line ()
|
||||
for unsigned p = 0; p <= num_pages; ++p:
|
||||
mem.destroy (Kernel::Page (slot, p))
|
||||
Kernel::my_memory.destroy (Kernel::Page (slot, p))
|
||||
kdebug_line ()
|
||||
Kernel::Page stackpage = mem.create_page ()
|
||||
kdebug_line ()
|
||||
stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
|
||||
kdebug_line ()
|
||||
if Kernel::recv.data[0].l != Kernel::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
|
||||
kdebug ("unable to map initial stack page\n")
|
||||
Kernel::panic (0)
|
||||
return
|
||||
kdebug_line ()
|
||||
Kernel::free_cap (stackpage)
|
||||
Kernel::Caps caps = mem.create_caps (NUM_CAPS)
|
||||
kdebug_line ()
|
||||
thread.use (caps, 0)
|
||||
thread.set_info (Kernel::Thread::A0, NUM_SLOTS)
|
||||
thread.set_info (Kernel::Thread::A1, NUM_CAPS)
|
||||
kdebug_line ()
|
||||
Kernel::Receiver receiver = mem.create_receiver ()
|
||||
receiver.set_owner (thread.copy ())
|
||||
Kernel::Cap call = receiver.create_call_capability ()
|
||||
Kernel::Cap parent = Kernel::my_receiver.create_capability (++current_thread)
|
||||
kdebug_line ()
|
||||
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 ())
|
||||
kdebug_line ()
|
||||
thread.run ()
|
||||
kdebug_line ()
|
||||
Kernel::free_cap (receiver)
|
||||
Kernel::free_cap (thread)
|
||||
Kernel::free_cap (mem)
|
||||
Kernel::free_cap (call)
|
||||
Kernel::free_cap (parent)
|
||||
kdebug_line ()
|
||||
Kernel::print_caps ()
|
||||
|
||||
static void dump_devices ():
|
||||
kdebug ("String: ")
|
||||
kdebug_num (String::ID, 3)
|
||||
kdebug ("\nWString: ")
|
||||
kdebug_num (WString::ID, 3)
|
||||
kdebug ("\nDevice: ")
|
||||
kdebug_num (Device::ID, 3)
|
||||
kdebug ("\nParent: ")
|
||||
kdebug_num (Parent::ID, 3)
|
||||
kdebug ("\nKeyboard: ")
|
||||
kdebug_num (Keyboard::ID, 3)
|
||||
kdebug ("\nBuzzer: ")
|
||||
kdebug_num (Buzzer::ID, 3)
|
||||
kdebug ("\nDisplay: ")
|
||||
kdebug_num (Display::ID, 3)
|
||||
kdebug ("\nSetting: ")
|
||||
kdebug_num (Setting::ID, 3)
|
||||
kdebug ("\nDirectory: ")
|
||||
kdebug_num (Directory::ID, 3)
|
||||
kdebug ("\nWDirectory: ")
|
||||
kdebug_num (WDirectory::ID, 3)
|
||||
kdebug ("\nFilesystem: ")
|
||||
kdebug_num (Filesystem::ID, 3)
|
||||
kdebug ("\nStream: ")
|
||||
kdebug_num (Stream::ID, 3)
|
||||
kdebug ("\n")
|
||||
|
||||
Kernel::Num start ():
|
||||
// Wait for the debugging device to be active, in case there is one.
|
||||
Kernel::schedule ()
|
||||
init_alloc ()
|
||||
dump_devices ()
|
||||
top_memory = Kernel::get_top_memory ()
|
||||
Directory root = receive_devices ()
|
||||
root.lock_ro ()
|
||||
kdebug_line ()
|
||||
list_files (root)
|
||||
kdebug_line ()
|
||||
sort ()
|
||||
kdebug_line ()
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages)
|
||||
kdebug ("max pages: ")
|
||||
kdebug_num (max_pages)
|
||||
kdebug ("\n")
|
||||
slot = caps.use ()
|
||||
mapping = alloc_space (max_pages)
|
||||
for unsigned i = 0; i < num_files; ++i:
|
||||
kdebug_line ()
|
||||
run (&files[index[i]], files[index[i]].name[0] == '#')
|
||||
kdebug_line ()
|
||||
kdebug_line ()
|
||||
root.unlock_ro ()
|
||||
kdebug_line ()
|
||||
Kernel::free_slot (slot)
|
||||
kdebug_line ()
|
||||
Kernel::my_memory.destroy (caps)
|
||||
kdebug_line ()
|
||||
return 0
|
||||
|
||||
@@ -108,7 +108,7 @@ class Udc:
|
||||
u16 data[size];
|
||||
} __attribute__ ((packed))
|
||||
static unsigned const max_packet_size0 = 64
|
||||
static unsigned const max_packet_size_bulk = 512
|
||||
static unsigned const max_packet_size_bulk = 64
|
||||
enum Requests:
|
||||
GET_STATUS = 0
|
||||
CLEAR_FEATURE = 1
|
||||
@@ -149,28 +149,29 @@ class Udc:
|
||||
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
|
||||
Kernel::Cap caller
|
||||
Kernel::Cap caller, caller_arg
|
||||
bool have_caller
|
||||
unsigned *page
|
||||
unsigned *p
|
||||
Kernel::Page buffer_page
|
||||
public:
|
||||
void init ()
|
||||
void log (unsigned c)
|
||||
void interrupt (unsigned cmd)
|
||||
void send (unsigned code, unsigned arg)
|
||||
void set_caller (Kernel::Cap c):
|
||||
if have_caller:
|
||||
kdebug ("set_caller double-called\n")
|
||||
Kernel::panic (0)
|
||||
caller = c
|
||||
have_caller = true
|
||||
void send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::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 = {
|
||||
@@ -212,53 +213,43 @@ void Udc::init ():
|
||||
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 = Kernel::my_memory.create_page ()
|
||||
buffer_page.set_flags (Kernel::Page::FRAME | Kernel::Page::PAYING, Kernel::Page::FRAME | Kernel::Page::PAYING)
|
||||
Kernel::my_memory.map (buffer_page, (unsigned)page)
|
||||
|
||||
// Disconnect from the bus and don't try to get high-speed.
|
||||
UDC_POWER &= ~(UDC_POWER_SOFTCONN | UDC_POWER_HSENAB)
|
||||
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 ()
|
||||
unsigned i = UDC_INTRUSB
|
||||
// reset all pending endpoint interrupts.
|
||||
unsigned i = UDC_INTRUSB
|
||||
i = UDC_INTRIN
|
||||
i = UDC_INTROUT
|
||||
// enable interrupt on bus reset.
|
||||
UDC_INTRUSB = UDC_INTR_RESET
|
||||
UDC_INTRUSBE = UDC_INTR_RESET
|
||||
// enable interrupts on endpoint 0.
|
||||
UDC_INTRINE |= 1 << 0
|
||||
UDC_INDEX = 0
|
||||
UDC_INTRINE = 1 << 0
|
||||
// and on out endpoint 1.
|
||||
UDC_INTROUTE = 1 << 1
|
||||
// Wait a while.
|
||||
for unsigned w = 0; w < 10000; ++w:
|
||||
Kernel::schedule ()
|
||||
// Connect to the host.
|
||||
UDC_POWER |= UDC_POWER_SOFTCONN
|
||||
UDC_POWER = UDC_POWER_SOFTCONN
|
||||
|
||||
bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
if !(s->request_type & 0x80):
|
||||
switch s->request:
|
||||
case Directory::GET_SIZE:
|
||||
if !have_caller:
|
||||
kdebug ("received size from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
unsigned size_l = UDC_FIFO (0)
|
||||
unsigned size_h = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (size_l, size_h))
|
||||
have_caller = false
|
||||
break
|
||||
case Directory::GET_NAME:
|
||||
if !have_caller:
|
||||
kdebug ("received size from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
unsigned n[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
n[i] = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3]))
|
||||
have_caller = false
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid vendor request\n")
|
||||
Kernel::panic (0)
|
||||
kdebug ("data to device without size\n")
|
||||
Kernel::panic (0)
|
||||
return true
|
||||
if s->request == 10:
|
||||
static unsigned b[2]
|
||||
@@ -267,6 +258,12 @@ bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
if cmd_code != ~0:
|
||||
b[0] = cmd_code
|
||||
b[1] = cmd_arg
|
||||
if cmd_code == Directory::LOCK_RO || cmd_code == Directory::UNLOCK_RO:
|
||||
caller.invoke ()
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("(un)lock response\n")
|
||||
cmd_code = ~0
|
||||
else:
|
||||
if log_buffer_start == log_buffer_size:
|
||||
@@ -286,12 +283,15 @@ bool Udc::vendor (Setup *s, unsigned cmd):
|
||||
state = TX
|
||||
return true
|
||||
|
||||
void Udc::send (unsigned code, unsigned arg):
|
||||
if code != ~0:
|
||||
void Udc::send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::Cap arg):
|
||||
if cmd_code != ~0:
|
||||
kdebug ("new code sent while old one wasn't finished.\n")
|
||||
Kernel::panic (0)
|
||||
cmd_code = code
|
||||
cmd_arg = arg
|
||||
cmd_arg = narg
|
||||
caller = reply
|
||||
caller_arg = arg
|
||||
have_caller = true
|
||||
|
||||
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||
switch type:
|
||||
@@ -355,6 +355,9 @@ bool Udc::handle_setup (Setup *s, unsigned cmd):
|
||||
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:
|
||||
@@ -385,69 +388,165 @@ bool Udc::handle_setup (Setup *s, unsigned cmd):
|
||||
return false
|
||||
return true
|
||||
|
||||
void Udc::interrupt (unsigned cmd):
|
||||
unsigned i = UDC_INTRUSB
|
||||
if i & UDC_INTR_RESET:
|
||||
void Udc::irq_usb (unsigned cmd):
|
||||
// Reset.
|
||||
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
|
||||
return
|
||||
i = UDC_INTRIN
|
||||
if i & (1 << 0):
|
||||
// Interrupt on endpoint 0.
|
||||
UDC_INDEX = 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:
|
||||
Kernel::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)
|
||||
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
|
||||
if csr & UDC_CSR0_SETUPEND:
|
||||
csr |= UDC_CSR0_SVDSETUPEND
|
||||
state = IDLE
|
||||
switch state:
|
||||
case IDLE:
|
||||
if rebooting:
|
||||
Kernel::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
|
||||
case RX:
|
||||
// Not supported.
|
||||
csr |= UDC_CSR0_SVDOUTPKTRDY | UDC_CSR0_SENDSTALL
|
||||
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
|
||||
break
|
||||
UDC_CSR0 = csr
|
||||
unsigned i = UDC_INTROUT
|
||||
if i & (1 << 1):
|
||||
// Interrupt on OUT endpoint 1.
|
||||
UDC_INDEX = 1
|
||||
unsigned csr = UDC_OUTCSR
|
||||
if !csr & UDC_CSR_OUTPKTRDY:
|
||||
kdebug ("unrecognized interrupt on bulk out ep 1\n")
|
||||
return
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
*p++ = UDC_FIFO (1)
|
||||
if p - page == PAGE_SIZE:
|
||||
// TODO: notify caller; reset buffer.
|
||||
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 Directory::GET_SIZE & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received dir size from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
unsigned size_l = UDC_FIFO (0)
|
||||
unsigned size_h = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (size_l, size_h))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_size response\n")
|
||||
break
|
||||
case Directory::GET_NAME & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received filename from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
unsigned n[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
n[i] = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3]))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
//kdebug ("get_name response\n")
|
||||
have_caller = false
|
||||
break
|
||||
case ::String::GET_SIZE & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received string size from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
unsigned size_l = UDC_FIFO (0)
|
||||
unsigned size_h = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (size_l, size_h))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_filesize response\n")
|
||||
break
|
||||
case ::String::GET_CHARS & 0xff:
|
||||
if !have_caller:
|
||||
kdebug ("received string char data from server without a caller waiting\n")
|
||||
Kernel::panic (0)
|
||||
unsigned n[4]
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
n[i] = UDC_FIFO (0)
|
||||
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3]))
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::free_cap (caller_arg)
|
||||
have_caller = false
|
||||
//kdebug ("get_chars response\n")
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid vendor request: ")
|
||||
kdebug_num (rx_request)
|
||||
kdebug ("\n")
|
||||
Kernel::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")
|
||||
Kernel::panic (0)
|
||||
unsigned size = UDC_OUTCOUNT
|
||||
unsigned csr = UDC_OUTCSR
|
||||
//kdebug ("handling bulk interrupt for ")
|
||||
//kdebug_num (csr)
|
||||
//kdebug (" with ")
|
||||
//kdebug_num (size)
|
||||
//kdebug (" bytes.\n")
|
||||
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, Kernel::Page::FORGET)
|
||||
buffer_page.set_flags (Kernel::Page::FRAME, Kernel::Page::FRAME)
|
||||
caller.invoke ()
|
||||
Kernel::free_cap (caller)
|
||||
Kernel::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
|
||||
//kdebug ("interrupt: ")
|
||||
//kdebug_num (usb, 1)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (in, 1)
|
||||
//kdebug ("/")
|
||||
//kdebug_num (out, 1)
|
||||
//kdebug ("\n")
|
||||
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):
|
||||
@@ -459,6 +558,8 @@ enum pdata:
|
||||
FS
|
||||
DATA
|
||||
DIRECTORY
|
||||
FILE
|
||||
NAME
|
||||
|
||||
Kernel::Num start ():
|
||||
map_udc ()
|
||||
@@ -466,18 +567,23 @@ Kernel::Num start ():
|
||||
map_cpm ()
|
||||
Udc udc
|
||||
|
||||
Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
//Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
|
||||
//__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
udc.init ()
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
Device fs_dev = Kernel::my_receiver.create_capability (FS)
|
||||
Kernel::my_parent.provide_device <Directory> (fs_dev)
|
||||
Device data_dev = Kernel::my_receiver.create_capability (DATA)
|
||||
Kernel::my_parent.provide_device <Filesystem> (fs_dev.copy ())
|
||||
Kernel::my_parent.provide_device <String> (data_dev.copy ())
|
||||
Kernel::free_cap (fs_dev)
|
||||
Kernel::free_cap (data_dev)
|
||||
unsigned data_current_user = 0, fs_current_user = 0
|
||||
unsigned next_user
|
||||
unsigned state = 0
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
@@ -489,10 +595,10 @@ Kernel::Num start ():
|
||||
udc.log (Kernel::recv.data[0].l)
|
||||
break
|
||||
case FS:
|
||||
Device::host (FS, fs_current_user, reply)
|
||||
Device::host (FS, fs_current_user, reply, arg)
|
||||
continue
|
||||
case DATA:
|
||||
Device::host (DATA, data_current_user, reply)
|
||||
Device::host (DATA, data_current_user, reply, arg)
|
||||
continue
|
||||
default:
|
||||
udc.log ('~')
|
||||
@@ -501,19 +607,22 @@ Kernel::Num start ():
|
||||
udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
|
||||
udc.log ('\n')
|
||||
break
|
||||
break
|
||||
case DATA:
|
||||
if data_current_user != Kernel::recv.protected_data.l:
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case String::GET_SIZE:
|
||||
case String::GET_CHARS:
|
||||
case ::String::GET_SIZE:
|
||||
case ::String::GET_CHARS:
|
||||
reply.invoke (0)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
case String::GET_PAGE:
|
||||
case ::String::GET_PAGE:
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case FS:
|
||||
@@ -526,30 +635,79 @@ Kernel::Num start ():
|
||||
reply.invoke (0, 0, dir.copy ())
|
||||
Kernel::free_cap (dir)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case DIRECTORY:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Directory::GET_SIZE:
|
||||
case Directory::GET_NAME:
|
||||
Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, NAME))
|
||||
reply.invoke (0, 0, name.copy ())
|
||||
Kernel::free_cap (name)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
case Directory::GET_SIZE:
|
||||
case Directory::LOCK_RO:
|
||||
case Directory::UNLOCK_RO:
|
||||
state = Kernel::recv.data[0].l
|
||||
if Kernel::recv.data[1].h != 0:
|
||||
kdebug ("index out of supported range\n")
|
||||
Kernel::panic (0)
|
||||
udc.send (Kernel::recv.data[0].l, Kernel::recv.data[1].l)
|
||||
Kernel::free_cap (reply)
|
||||
udc.send (Kernel::recv.data[0].l, Kernel::recv.data[1].l, reply, arg)
|
||||
continue
|
||||
case Directory::GET_FILE_RO:
|
||||
//TODO
|
||||
if Kernel::recv.data[1].h != 0:
|
||||
kdebug ("index out of supported range\n")
|
||||
Kernel::panic (0)
|
||||
//kdebug ("sending file\n")
|
||||
Kernel::Cap file = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, FILE))
|
||||
reply.invoke (0, 0, file.copy ())
|
||||
Kernel::free_cap (file)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
case Directory::GET_FILE_INFO:
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case FILE:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case ::String::GET_SIZE:
|
||||
case ::String::GET_CHARS:
|
||||
case ::String::GET_PAGE:
|
||||
udc.send (Kernel::recv.data[0].l | ((Kernel::recv.data[1].l >> PAGE_BITS) << 16), Kernel::recv.protected_data.l, reply, arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
break
|
||||
case NAME:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case ::String::GET_SIZE:
|
||||
reply.invoke (16)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
case ::String::GET_CHARS:
|
||||
state = Kernel::recv.data[0].l
|
||||
udc.send (Directory::GET_NAME, Kernel::recv.protected_data.l, reply, arg)
|
||||
continue
|
||||
default:
|
||||
reply.invoke (Kernel::ERR_INVALID_OPERATION)
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
continue
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
|
||||
Reference in New Issue
Block a user