From 5f9fd7cc0fc70e048e661849d3ff4c0ed2d5acff Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Thu, 7 Oct 2010 09:52:04 +0200 Subject: [PATCH] mass storage sort of working, but not nice --- Makefile | 6 +- alloc.ccp | 27 +++++++ invoke.ccp | 33 ++------ kernel.hhp | 1 + mips/nand.hhp | 52 ++++++++---- mips/nanonote/nand-boot.ccp | 36 +++++++++ source/init.ccp | 6 +- source/nand.ccp | 65 ++++++++++----- source/usb-mass-storage.ccp | 153 +++++++++++++++++++++++++----------- 9 files changed, 264 insertions(+), 115 deletions(-) diff --git a/Makefile b/Makefile index 164b4ef..d16ee00 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,8 @@ headers = kernel.hh iris.hh devices.hh ui.hh keys.hh $(arch_headers) iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources) BUILT_SOURCES = $(iris_sources) $(boot_sources) +STRIPFLAG = -S + # Include arch-specific rules. include Makefile.arch @@ -45,11 +47,11 @@ PYPP = /usr/bin/pypp %.elf: boot-programs/crt0.o boot-programs/%.o $(LD) $(LDFLAGS) $(filter %.o,$^) -o $@ - $(OBJCOPY) -S $(OBJCOPYFLAGS) $@ + $(OBJCOPY) $(STRIPFLAG) $(OBJCOPYFLAGS) $@ fs/%.elf: source/crt0.o source/%.o fs/init.config $(LD) $(LDFLAGS) $(filter %.o,$^) -o $@ - $(OBJCOPY) -S $(OBJCOPYFLAGS) $@ + $(OBJCOPY) $(STRIPFLAG) $(OBJCOPYFLAGS) $@ fs/%: % test -d fs || mkdir fs diff --git a/alloc.ccp b/alloc.ccp index cef1e81..c5d34eb 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -517,12 +517,39 @@ void kMemory::free_memory (kMemory *mem): panic (0, "kernel memory leak: memory still in use") free_obj (mem, (void **)&memories) +void kPage::check_payment (): + kPage *p + for p = this; p; p = p->share_prev: + if p->flags & Iris::Page::PAYING: + return + for p = share_next; p; p = p->share_next: + if p->flags & Iris::Page::PAYING: + return + // No kPage is paying for this frame anymore. + raw_pfree (frame) + kPage *next + for p = share_prev, next = (p ? p->share_prev : NULL); p; p = next, next = p->share_prev: + p->frame = NULL + p->share_prev = NULL + p->share_next = NULL + p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME) + kPage_arch_update_mapping (p) + for p = this, next = p->share_next; p; p = next, next = p->share_next: + p->frame = NULL + p->share_prev = NULL + p->share_next = NULL + p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME) + kPage_arch_update_mapping (p) + void kPage::forget (): if share_prev || share_next: if share_prev: share_prev->share_next = share_next if share_next: share_next->share_prev = share_prev + share_next->check_payment () + else: + share_prev->check_payment () share_prev = NULL share_next = NULL else: diff --git a/invoke.ccp b/invoke.ccp index 265b0eb..d387300 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -577,30 +577,6 @@ static void thread_invoke (unsigned cmd, unsigned target, Iris::Num protected_da reply_num (0) return -static void page_check_payment (kPage *page): - kPage *p - for p = page; p; p = p->share_prev: - if p->flags & Iris::Page::PAYING: - return - for p = page->share_next; p; p = p->share_next: - if p->flags & Iris::Page::PAYING: - return - // No kPage is paying for this frame anymore. - raw_pfree (page->frame) - kPage *next - for p = page->share_prev, next = (p ? p->share_prev : NULL); p; p = next, next = p->share_prev: - p->frame = NULL - p->share_prev = NULL - p->share_next = NULL - p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME) - kPage_arch_update_mapping (p) - for p = page, next = p->share_next; p; p = next, next = p->share_next: - p->frame = NULL - p->share_prev = NULL - p->share_next = NULL - p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME) - kPage_arch_update_mapping (p) - static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c): kPage *page = (kPage *)protected_data.l switch cmd & ~Iris::Page::READONLY: @@ -653,7 +629,7 @@ static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data page->share_prev->share_next = page->share_next page->share_next = NULL page->share_prev = NULL - page_check_payment (other) + other->check_payment () else: t->flags |= Iris::Page::FRAME t->frame = raw_zalloc () @@ -697,7 +673,7 @@ static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data page->share_prev = NULL page->share_next = NULL page->forget () - page_check_payment (t) + t->check_payment () else: t->share_prev = page->share_prev t->share_next = page @@ -727,7 +703,7 @@ static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data if ~page->flags & old & Iris::Page::PAYING: // Decrease the use counter in any case. page->address_space->unuse () - page_check_payment (page) + page->check_payment () // If we start paying, increase the use counter. if page->flags & ~old & Iris::Page::PAYING: @@ -747,6 +723,9 @@ static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data else: page->frame = page->address_space->zalloc () kPage_arch_update_mapping (page) + // If we lose a frame, handle it. + if old & ~page->flags & Iris::Page::FRAME: + page->forget () break default: dpanic (0, "invalid page operation") diff --git a/kernel.hhp b/kernel.hhp index 7928558..0781a02 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -171,6 +171,7 @@ struct kPage : public kObject: kPageP share_prev, share_next kPage_arch arch void forget () + void check_payment () struct kCaps : public kObject: _slot_data first_slot diff --git a/mips/nand.hhp b/mips/nand.hhp index 092d6b3..eed9c17 100644 --- a/mips/nand.hhp +++ b/mips/nand.hhp @@ -20,6 +20,9 @@ // The following defines are taken from mtd/nand.h in the Linux source. // Everything not in the nand datasheet is thrown out. +//#define dbgl() debug ("%s:%d\n", __PRETTY_FUNCTION__, __LINE__) +#define dbgl() + // Standard NAND flash commands #define CMD_READ0 0 #define CMD_READSTART 0x30 @@ -118,7 +121,7 @@ static void reset (): static bool read (unsigned a, char *buffer): unsigned column = a & ((1 << page_bits) - 1) unsigned row = a >> page_bits - debug ("reading %x:", a) + //debug ("reading %x:", a) // Read oob information first. char error[12] // Spare space (starts at 1 << page_bits) @@ -145,18 +148,20 @@ static bool read (unsigned a, char *buffer): valid = true break if !valid: - debug ("invalid page for nand read: %x\n", a) + //debug ("invalid page for nand read: %x\n", a) + for unsigned i = 0; i < 1 << (9 - 2); ++i: + ((unsigned *)buffer)[i] = ~0 return false col = (1 << page_bits) + 6 + 9 * (column >> 9) cmd (CMD_RNDOUT) addr (col) addr (col >> 8) cmd (CMD_RNDOUTSTART) - debug ("parity data:") + //debug ("parity data:") for unsigned t = 0; t < 9; ++t: error[t] = rdata () - debug (" %x", error[t] & 0xff) - debug ("\n") + //debug (" %x", error[t] & 0xff) + //debug ("\n") cmd (CMD_RNDOUT) addr (column) addr (column >> 8) @@ -168,10 +173,8 @@ static bool read (unsigned a, char *buffer): for unsigned t = 0; t < 9; ++t: ((volatile char *)&EMC_NFPAR (0))[t] = error[t] EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY - debug ("before\n") while !(EMC_NFINTS & EMC_NFINTS_DECF): DELAY () - debug ("after\n") unsigned ints = EMC_NFINTS if ints & EMC_NFINTS_UNCOR: debug ("uncorrectable error in nand at %x\n", a) @@ -191,16 +194,17 @@ static bool read (unsigned a, char *buffer): buffer[byte + 1] = data >> 8 for unsigned i = 0; i < 0x10; ++i: if (buffer[i] & 0xff) < 0x10: - debug (" 0") + //debug (" 0") else: - debug (" ") - debug ("%x", buffer[i] & 0xff) - debug ("\n") + //debug (" ") + //debug ("%x", buffer[i] & 0xff) + //debug ("\n") return true static void write (unsigned a, char *buffer): + dbgl () unsigned row = a >> page_bits - //debug ("writing: %x/%x: ", a, row) + //debug ("writing: %x/%x\n", a, row) cmd (CMD_SEQIN) addr (0) addr (0) @@ -208,7 +212,9 @@ static void write (unsigned a, char *buffer): addr (row >> 8) addr (row >> 16) char ecc[4][12] + dbgl () for unsigned i = 0; i < 0x4; ++i: + dbgl () bool all_ff = true EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING | EMC_NFECR_ERST //debug ("writing data from %x\n", (unsigned)buffer + i * 0x200) @@ -219,15 +225,19 @@ static void write (unsigned a, char *buffer): if !all_ff: while !(EMC_NFINTS & EMC_NFINTS_ENCF): DELAY () + dbgl () for unsigned t = 0; t < 9; ++t: ecc[i][t] = ((volatile char *)&EMC_NFPAR (0))[t] + dbgl () //debug ("parity for %x:", i * 0x200 + a) //for unsigned t = 0; t < 9; ++t: //debug (" %x", ecc[i][t] & 0xff) //kdebug ("\n") else: + dbgl () for unsigned t = 0; t < 9; ++t: ecc[i][t] = 0xff + dbgl () // Spare space (starts at 1 << page_bits) // 0: unused // 2: detect valid data (at least 1 byte == 0 means valid) @@ -243,9 +253,11 @@ static void write (unsigned a, char *buffer): for unsigned i = 0; i < 4; ++i: for unsigned j = 0; j < 9; ++j: wdata (ecc[i][j]) + dbgl () cmd (CMD_PAGEPROG) // Wait at least 100 ns. DELAY () + dbgl () cmd (CMD_READ0) addr (0) addr (0) @@ -253,7 +265,9 @@ static void write (unsigned a, char *buffer): addr (row >> 8) addr (row >> 16) cmd (CMD_READSTART) + dbgl () for unsigned i = 0; i < 4; ++i: + dbgl () EMC_NFINTS = 0 EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST for unsigned t = 0; t < 0x200; ++t: @@ -278,22 +292,26 @@ static void write (unsigned a, char *buffer): unsigned offset= bit & 7 unsigned byte = bit / 8 debug ("error detected by parity: %x on %x+%d\n", mask, byte, offset) + dbgl () for unsigned i = 0; i < 6; ++i: if rdata () != 0: debug ("extra data not 0 at byte %d\n", i) + dbgl () for unsigned i = 0; i < 4; ++i: for unsigned j = 0; j < 9; ++j: unsigned r = rdata () & 0xff if r != (ecc[i][j] & 0xff): debug ("ecc doesn't match: %x != %x\n", r, ecc[i][j] & 0xff) - debug ("nand program %x:", a) + dbgl () + //debug ("nand program %x:", a) for unsigned i = 0; i < 0x10; ++i: if (buffer[i] & 0xff) < 0x10: - debug (" 0") + //debug (" 0") else: - debug (" ") - debug ("%x", buffer[i] & 0xff) - debug ("\n") + //debug (" ") + //debug ("%x", buffer[i] & 0xff) + dbgl () + //debug ("\n") static void erase (unsigned a): unsigned row = a >> page_bits diff --git a/mips/nanonote/nand-boot.ccp b/mips/nanonote/nand-boot.ccp index f379054..02ae948 100644 --- a/mips/nanonote/nand-boot.ccp +++ b/mips/nanonote/nand-boot.ccp @@ -19,6 +19,8 @@ asm volatile ("\t.set noreorder\n" "\t.text\n" "\t.globl __start\n" + "\t.globl addr_0\n" + "addr_0:\n" "\t.word ~0\n" "__start:\n" "\tbal 1f\n" @@ -33,6 +35,40 @@ asm volatile ("\t.set noreorder\n" "\tla $t9, nandboot_start\n" "\tjr $t9\n" "\tnop\n" + "\t.fill 0x1b8 - (. - addr_0)\n" + "\t.word 0xd2b9e1a8\n" // Disk signature. + "\t.short 0x0000\n" + + "\t.byte 0x00\n" // bootable: no. + "\t.byte 0x00, 0x02, 0x00\n" // first sector chs. + "\t.byte 0x83\n" // type. + "\t.byte 0x08, 0x18, 0x00\n" // last sector chs. + "\t.byte 0x01, 0x00, 0x00, 0x00\n" // first sector, lba. + "\t.byte 0xff, 0x01, 0x00, 0x00\n" // size, lba. + + "\t.byte 0x00\n" // bootable: no. + "\t.byte 0x08, 0x19, 0x00\n" // first sector chs. + "\t.byte 0x83\n" // type. + "\t.byte 0x05, 0xe1, 0xf3\n" // last sector chs. + "\t.byte 0x00, 0x02, 0x00, 0x00\n" // first sector, lba: 256 kB. + "\t.byte 0x00, 0xfe, 0x1f, 0x00\n" // size, lba: 1 GB - first. + + "\t.byte 0\n" // bootable: no. + "\t.byte 0, 0, 0\n" // first sector chs. + "\t.byte 0\n" // type. + "\t.byte 0, 0, 0\n" // last sector chs. + "\t.byte 0, 0, 0, 0\n" // first sector, lba. + "\t.byte 0, 0, 0, 0\n" // size, lba. + + "\t.byte 0\n" // bootable: no. + "\t.byte 0, 0, 0\n" // first sector chs. + "\t.byte 0\n" // type. + "\t.byte 0, 0, 0\n" // last sector chs. + "\t.byte 0, 0, 0, 0\n" // first sector, lba. + "\t.byte 0, 0, 0, 0\n" // size, lba. + + "\t.byte 0x55, 0xaa\n" // mbr signature. + "\t.set reorder") #define __KERNEL__ diff --git a/source/init.ccp b/source/init.ccp index 0505eb6..ed03fe0 100644 --- a/source/init.ccp +++ b/source/init.ccp @@ -249,11 +249,11 @@ static bool get_name (char *&line, unsigned &len, char *&name, unsigned &name_le while name_len < len && isnamechar (line[name_len]): ++name_len name = new char[name_len] - kdebug ("name: ") + //kdebug ("name: ") for unsigned i = 0; i < name_len; ++i: name[i] = line[i] - kdebug_char (name[i]) - kdebug_char ('\n') + //kdebug_char (name[i]) + //kdebug_char ('\n') line += name_len len -= name_len delspace (line, len) diff --git a/source/nand.ccp b/source/nand.ccp index 77ccd1f..511e874 100644 --- a/source/nand.ccp +++ b/source/nand.ccp @@ -20,22 +20,30 @@ #define ARCH #include "arch.hh" -#define debug //Iris::debug +#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 (): - debug ("erasing %x\n", current_block << block_bits) - //erase (current_block << block_bits) - for unsigned p = 0; p < 1 << (block_bits - 9); ++p: - debug ("writing %x\n", (current_block << block_bits) + (p << 9)) - //write ((current_block << block_bits) + (p << 9), &cache[p << (9 - 2)]) + 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 @@ -103,21 +111,28 @@ Iris::Num start (): unsigned row = Iris::recv.data[1].value () >> 9 unsigned block = row >> (block_bits - 9) row &= (1 << (block_bits - 9)) - 1 - if block != current_block: - if current_block != ~0 && dirty: - sync () - current_block = block - read_block (block) 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[(offset >> 2) + t + (row << 9)] + tmp_addr[(offset >> 2) + t] = cache[t + (row << (9 - 2))] tmp.set_flags (0, Iris::Page::FRAME) reply.invoke () Iris::free_cap (reply) @@ -126,26 +141,38 @@ Iris::Num start (): case Iris::WBlock::SET_BLOCK: unsigned row = Iris::recv.data[1].value () >> 9 unsigned block = row >> (block_bits - 9) - if block != current_block: - if current_block != ~0 && dirty: - sync () - current_block = block - read_block (block) + 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 >> 2; ++t: - cache[(offset >> 2) + t + (row << 9)] = tmp_addr[(offset >> 2) + t] + 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: diff --git a/source/usb-mass-storage.ccp b/source/usb-mass-storage.ccp index 1c51279..49ae4b1 100644 --- a/source/usb-mass-storage.ccp +++ b/source/usb-mass-storage.ccp @@ -281,9 +281,8 @@ void Udc::init (Iris::WBlock b): UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF UDC_INDEX = 2 UDC_INMAXP = max_packet_size_bulk - UDC_INCSRH = UDC_INCSRH_MODE - UDC_INCSR = UDC_INCSR_CDT | UDC_INCSR_FF - UDC_INCSR = UDC_INCSR_CDT | UDC_INCSR_FF + UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF + UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF // exit suspend mode by reading the interrupt register. unsigned i = UDC_INTRUSB // reset all pending endpoint interrupts. @@ -325,31 +324,52 @@ void Udc::send_padded (char const *data, unsigned length, unsigned 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 + if len % max_packet_size_bulk == 0: + // This doesn't ever happen, because the largest packet we send is smaller than max_packet_size_bulk. + Iris::debug ("sending at len %x\n", len) + UDC_INCSR |= UDC_INCSR_INPKTRDY + while true: + Iris::register_interrupt (IRQ_UDC) + Iris::wait_for_interrupt (IRQ_UDC) + kdebug ("interrupt pad0\n") + unsigned usb = UDC_INTRUSB + unsigned in = UDC_INTRIN + if usb & 4 || in & 1: + //kdebug ("general interrupt pad0\t") + if !handle_interrupt (usb & 4, in & 1): + return + unsigned out = UDC_INTROUT + if out & 2: + Iris::panic (0, "out interrupt while waiting for in") + if in & 4: + break //kdebug_char ('-') - while len < maxlength: - UDC_FIFO8 (2) = 0 - ++len - //kdebug_char ('.') - UDC_INCSR |= UDC_INCSR_INPKTRDY - while true: - Iris::register_interrupt (IRQ_UDC) - Iris::wait_for_interrupt (IRQ_UDC) - //kdebug ("interrupt pad\t") - unsigned usb = UDC_INTRUSB - unsigned in = UDC_INTRIN - unsigned out = UDC_INTROUT - if usb & 4 || in & 1: - //kdebug ("general interrupt pad\t") - if !handle_interrupt (usb & 4, in & 1): - return - if out & 2: - Iris::panic (0, "out interrupt while waiting for in") - if in & 4: - break - //kdebug ("done interrupt pad\n") + if len % max_packet_size_bulk != 0 || len < maxlength: + while len < maxlength: + UDC_FIFO8 (2) = 0 + ++len + //kdebug_char ('.') + UDC_INCSR |= UDC_INCSR_INPKTRDY + while true: + Iris::register_interrupt (IRQ_UDC) + Iris::wait_for_interrupt (IRQ_UDC) + kdebug ("interrupt pad\t") + unsigned usb = UDC_INTRUSB + unsigned in = UDC_INTRIN + if usb & 4 || in & 1: + //kdebug ("general interrupt pad\t") + if !handle_interrupt (usb & 4, in & 1): + return + unsigned out = UDC_INTROUT + if out & 2: + Iris::panic (0, "out interrupt while waiting for in") + if in & 4: + break + //kdebug ("done interrupt pad\n") unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): switch type: @@ -446,22 +466,20 @@ unsigned Udc::handle_setup (Setup *s): case ENDPOINT_HALT: switch s->index: case 0x82: - //Iris::debug ("in ep halt reset\n") + Iris::debug ("in ep halt reset\n") UDC_INDEX = 2 UDC_INCSR &= ~UDC_INCSR_SENDSTALL stalling[2] = false break case 1: - //Iris::debug ("out ep halt reset\n") + Iris::debug ("out ep halt reset\n") UDC_INDEX = 1 UDC_OUTCSR &= ~UDC_OUTCSR_SENDSTALL stalling[1] = false break default: return ~0 - UDC_INDEX = 0 - UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY - return 0 + return UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY default: return ~0 default: @@ -518,6 +536,11 @@ void Udc::irq_in0 (): if !(csr & UDC_CSR0_OUTPKTRDY): //Iris::debug ("no packet 0: %x\n", csr) return + UDC_INDEX = 1 + UDC_OUTCSR |= UDC_OUTCSR_CDT + UDC_INDEX = 2 + UDC_INCSR |= UDC_INCSR_CDT + UDC_INDEX = 0 union { unsigned d[2]; Setup s; } packet packet.d[0] = UDC_FIFO (0) packet.d[1] = UDC_FIFO (0) @@ -526,10 +549,6 @@ void Udc::irq_in0 (): //Iris::debug ("packet on ep0 too long\n") UDC_CSR0 = UDC_CSR0_SENDSTALL return - UDC_INDEX = 1 - UDC_OUTCSR |= UDC_OUTCSR_CDT - UDC_INDEX = 2 - UDC_INCSR |= UDC_INCSR_CDT unsigned ret = handle_setup (&packet.s) UDC_INDEX = 0 if ret == ~0: @@ -552,6 +571,7 @@ void Udc::send_csw (): while true: Iris::register_interrupt (IRQ_UDC) Iris::wait_for_interrupt (IRQ_UDC) + kdebug ("interrupt csw\n") unsigned usb = UDC_INTRUSB unsigned in = UDC_INTRIN if usb & 4 || in & 1: @@ -562,7 +582,7 @@ void Udc::send_csw (): unsigned out = UDC_INTROUT if out & 2: Iris::panic (0, "out interrupt while waiting for in after csw") - //kdebug ("sent csw\n") + kdebug ("sent csw\n") void Udc::stall (unsigned error): unsigned index = UDC_INDEX @@ -574,14 +594,16 @@ void Udc::stall (unsigned error): UDC_INCSR |= UDC_INCSR_SENDSTALL stalling[index] = true while stalling[index]: - //kdebug ("stalling\t") + //Iris::debug ("stalling %d\n", index) Iris::register_interrupt (IRQ_UDC) Iris::wait_for_interrupt (IRQ_UDC) - //kdebug ("stalling interrupt\n") + kdebug ("stalling interrupt\n") unsigned usb = UDC_INTRUSB unsigned in = UDC_INTRIN if in & 4: - //kdebug ("stall has been sent to in endpoint\n") + if index != 2: + Iris::panic (0, "stalling on out, but in responds") + kdebug ("stall has been sent to in endpoint\n") UDC_INDEX = 2 UDC_INCSR &= ~UDC_INCSR_SENTSTALL //Iris::debug ("csr: %x\n", UDC_INCSR) @@ -591,10 +613,12 @@ void Udc::stall (unsigned error): return unsigned out = UDC_INTROUT if out & 2: - //kdebug ("stall has been sent to out endpoint\n") + if index != 1: + Iris::panic (0, "stalling on in, but out responds") + kdebug ("stall has been sent to out endpoint\n") UDC_INDEX = 1 UDC_OUTCSR &= ~UDC_OUTCSR_SENTSTALL - UDC_INDEX = index + //kdebug ("done stalling\n") if index == 2: status = error send_csw () @@ -608,7 +632,7 @@ void Udc::irq_out (): unsigned size = UDC_OUTCOUNT if !(csr & UDC_OUTCSR_OUTPKTRDY): // No packet, just a notification. - //kdebug ("no packet\n") + kdebug ("no packet\n") return if csr & UDC_OUTCSR_SENDSTALL: // When stalling, do nothing else. @@ -647,7 +671,7 @@ void Udc::irq_out (): send_csw () break case CBW::REQUEST_SENSE: - //Iris::debug ("sense requested\t") + //Iris::debug ("sense requested\n") send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length) send_csw () break @@ -682,10 +706,10 @@ void Udc::irq_out (): unsigned lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5] unsigned blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8] for unsigned i = 0; i < blocks; ++i: - //Iris::debug ("reading block %d:", lba + i) + //Iris::debug ("reading block %d\n", lba + i) // read block lba + i. buffer_page.set_flags (Iris::Page::FRAME) - block.get_block (lba << block_bits, 1 << block_bits, 0, buffer_page) + block.get_block ((lba + i) << block_bits, 1 << block_bits, 0, buffer_page) for unsigned p = 0; p < 1 << block_bits; p += max_packet_size_bulk: //Iris::debug (" %d", p) UDC_INDEX = 2 @@ -696,7 +720,7 @@ void Udc::irq_out (): while true: Iris::register_interrupt (IRQ_UDC) Iris::wait_for_interrupt (IRQ_UDC) - //kdebug ("interrupt read10\t") + kdebug ("interrupt read10\n") unsigned usb = UDC_INTRUSB unsigned in = UDC_INTRIN unsigned out = UDC_INTROUT @@ -711,7 +735,43 @@ void Udc::irq_out (): send_csw () break case CBW::WRITE10: - Iris::panic (0, "WRITE10 isn't implemented") + unsigned lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5] + unsigned blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8] + for unsigned i = 0; i < blocks; ++i: + //Iris::debug ("writing block %d\n", lba + i) + // write block lba + i. + buffer_page.set_flags (Iris::Page::FRAME) + //Iris::debug ("@%x:", (lba + i) << block_bits) + for unsigned p = 0; p < 1 << block_bits; p += max_packet_size_bulk: + while true: + Iris::register_interrupt (IRQ_UDC) + Iris::wait_for_interrupt (IRQ_UDC) + Iris::debug (".") + unsigned usb = UDC_INTRUSB + unsigned in = UDC_INTRIN + unsigned out = UDC_INTROUT + if usb & 4 || in & 1: + if !handle_interrupt (usb & 4, in & 1): + return + if out & 2: + break + if in & 4: + Iris::panic (0, "in interrupt while waiting for out") + UDC_INDEX = 1 + if !(UDC_OUTCSR & UDC_OUTCSR_OUTPKTRDY): + Iris::panic (0, "no packet ready after out interrupt in write10") + if UDC_OUTCOUNT != max_packet_size_bulk: + Iris::panic (UDC_OUTCOUNT, "invalid packet size in write10") + for unsigned t = 0; t < max_packet_size_bulk; t += 4: + ((unsigned *)buffer)[(p + t) >> 2] = UDC_FIFO (1) + //kdebug (" ") + //kdebug_num (((unsigned *)buffer)[(p + t) >> 2], 8) + UDC_OUTCSR &= ~UDC_OUTCSR_OUTPKTRDY + //kdebug ("\n") + //Iris::debug ("setting block %x@%x+%x\n", lba + i << block_bits, 0, 1 << block_bits) + block.set_block ((lba + i) << block_bits, buffer_page, 1 << block_bits) + send_csw () + break case CBW::RESERVE10: Iris::panic (0, "RESERVE10 isn't implemented") case CBW::RELEASE10: @@ -725,7 +785,6 @@ void Udc::irq_out (): residue = cbw.cbw.length stall (1) return - // TODO. bool Udc::handle_interrupt (bool usb, bool in): if usb: @@ -740,7 +799,7 @@ bool Udc::handle_interrupt (bool usb, bool in): return true void Udc::interrupt (): - //Iris::debug ("interrupt\n") + Iris::debug ("interrupt\n") while true: unsigned usb = UDC_INTRUSB unsigned in = UDC_INTRIN