mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-10 06:07:28 +03:00
mass storage nand almost working
This commit is contained in:
parent
3a38ea2944
commit
87acc47fd9
@ -220,11 +220,13 @@ bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address):
|
|||||||
mem->unmap (table->page[idx])
|
mem->unmap (table->page[idx])
|
||||||
table->entrylo[idx] = make_entry_lo (page)
|
table->entrylo[idx] = make_entry_lo (page)
|
||||||
table->page[idx] = page
|
table->page[idx] = page
|
||||||
//kdebug ("mapped ")
|
#if 0
|
||||||
//kdebug_num (page->frame)
|
kdebug ("mapped ")
|
||||||
//kdebug (" at address ")
|
kdebug_num (page->frame)
|
||||||
//kdebug_num (address)
|
kdebug (" at address ")
|
||||||
//kdebug ('\n')
|
kdebug_num (address)
|
||||||
|
kdebug ('\n')
|
||||||
|
#endif
|
||||||
page->mapping = address
|
page->mapping = address
|
||||||
page->arch.next_mapped = mem->arch.shadow[address >> 21]
|
page->arch.next_mapped = mem->arch.shadow[address >> 21]
|
||||||
if page->arch.next_mapped:
|
if page->arch.next_mapped:
|
||||||
|
@ -80,6 +80,9 @@ static unsigned rdata ():
|
|||||||
static void reset ():
|
static void reset ():
|
||||||
// Set up.
|
// Set up.
|
||||||
gpio_as_nand ()
|
gpio_as_nand ()
|
||||||
|
gpio_as_gpio (2, 1 << 30)
|
||||||
|
gpio_as_input (2, 1 << 30)
|
||||||
|
gpio_enable_pull (2, 1 << 30)
|
||||||
EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1
|
EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1
|
||||||
|
|
||||||
// Reset nand.
|
// Reset nand.
|
||||||
@ -149,11 +152,11 @@ static bool read (unsigned a, char *buffer):
|
|||||||
addr (col)
|
addr (col)
|
||||||
addr (col >> 8)
|
addr (col >> 8)
|
||||||
cmd (CMD_RNDOUTSTART)
|
cmd (CMD_RNDOUTSTART)
|
||||||
//debug ("parity data:")
|
debug ("parity data:")
|
||||||
for unsigned t = 0; t < 9; ++t:
|
for unsigned t = 0; t < 9; ++t:
|
||||||
error[t] = rdata ()
|
error[t] = rdata ()
|
||||||
//debug (" %x", error[t] & 0xff)
|
debug (" %x", error[t] & 0xff)
|
||||||
//debug ("\n")
|
debug ("\n")
|
||||||
cmd (CMD_RNDOUT)
|
cmd (CMD_RNDOUT)
|
||||||
addr (column)
|
addr (column)
|
||||||
addr (column >> 8)
|
addr (column >> 8)
|
||||||
@ -165,8 +168,10 @@ static bool read (unsigned a, char *buffer):
|
|||||||
for unsigned t = 0; t < 9; ++t:
|
for unsigned t = 0; t < 9; ++t:
|
||||||
((volatile char *)&EMC_NFPAR (0))[t] = error[t]
|
((volatile char *)&EMC_NFPAR (0))[t] = error[t]
|
||||||
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY
|
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY
|
||||||
|
debug ("before\n")
|
||||||
while !(EMC_NFINTS & EMC_NFINTS_DECF):
|
while !(EMC_NFINTS & EMC_NFINTS_DECF):
|
||||||
DELAY ()
|
DELAY ()
|
||||||
|
debug ("after\n")
|
||||||
unsigned ints = EMC_NFINTS
|
unsigned ints = EMC_NFINTS
|
||||||
if ints & EMC_NFINTS_UNCOR:
|
if ints & EMC_NFINTS_UNCOR:
|
||||||
debug ("uncorrectable error in nand at %x\n", a)
|
debug ("uncorrectable error in nand at %x\n", a)
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#define ARCH
|
#define ARCH
|
||||||
#include "arch.hh"
|
#include "arch.hh"
|
||||||
|
|
||||||
#define debug Iris::debug
|
#define debug //Iris::debug
|
||||||
#define DELAY Iris::schedule
|
#define DELAY Iris::schedule
|
||||||
#include "nand.hh"
|
#include "nand.hh"
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ Iris::Num start ():
|
|||||||
for unsigned p = 0; p < 1 << (block_bits - PAGE_BITS); ++p:
|
for unsigned p = 0; p < 1 << (block_bits - PAGE_BITS); ++p:
|
||||||
Iris::Page page = Iris::my_memory.create_page ()
|
Iris::Page page = Iris::my_memory.create_page ()
|
||||||
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
||||||
Iris::my_memory.map (page, (unsigned)cache + p << PAGE_BITS)
|
Iris::my_memory.map (page, (unsigned)cache + (p << PAGE_BITS))
|
||||||
Iris::free_cap (page)
|
Iris::free_cap (page)
|
||||||
Iris::Page tmp = Iris::my_memory.create_page ()
|
Iris::Page tmp = Iris::my_memory.create_page ()
|
||||||
tmp.set_flags (Iris::Page::PAYING)
|
tmp.set_flags (Iris::Page::PAYING)
|
||||||
|
@ -146,10 +146,18 @@ class Udc:
|
|||||||
u8 size;
|
u8 size;
|
||||||
u8 data[16];
|
u8 data[16];
|
||||||
enum Code {
|
enum Code {
|
||||||
INQUIRY = 0x12,
|
|
||||||
TEST_UNIT_READY = 0x00,
|
TEST_UNIT_READY = 0x00,
|
||||||
|
REQUEST_SENSE = 0x03,
|
||||||
|
FORMAT_UNIT = 0x04,
|
||||||
|
INQUIRY = 0x12,
|
||||||
|
RESERVE6 = 0x16,
|
||||||
|
RELEASE6 = 0x17,
|
||||||
|
SEND_DIAGNOSTIC = 0x1d,
|
||||||
READ_CAPACITY = 0x25,
|
READ_CAPACITY = 0x25,
|
||||||
REQUEST_SENSE = 0x03
|
READ10 = 0x28,
|
||||||
|
WRITE10 = 0x2a,
|
||||||
|
RESERVE10 = 0x56,
|
||||||
|
RELEASE10 = 0x57
|
||||||
};
|
};
|
||||||
} __attribute__ ((packed))
|
} __attribute__ ((packed))
|
||||||
static unsigned const max_packet_size0 = 64
|
static unsigned const max_packet_size0 = 64
|
||||||
@ -223,6 +231,9 @@ class Udc:
|
|||||||
unsigned tag
|
unsigned tag
|
||||||
unsigned block_bits
|
unsigned block_bits
|
||||||
Iris::WBlock block
|
Iris::WBlock block
|
||||||
|
Iris::Page buffer_page
|
||||||
|
// A random address to map the buffer.
|
||||||
|
static unsigned const buffer = 0x15000
|
||||||
public:
|
public:
|
||||||
void init (Iris::WBlock b)
|
void init (Iris::WBlock b)
|
||||||
void log (unsigned c)
|
void log (unsigned c)
|
||||||
@ -240,6 +251,10 @@ Udc::String <12> Udc::s_serial
|
|||||||
void Udc::init (Iris::WBlock b):
|
void Udc::init (Iris::WBlock b):
|
||||||
block = b
|
block = b
|
||||||
block_bits = block.get_align_bits ()
|
block_bits = block.get_align_bits ()
|
||||||
|
// Set up the buffer page.
|
||||||
|
buffer_page = Iris::my_memory.create_page ()
|
||||||
|
buffer_page.set_flags (Iris::Page::PAYING)
|
||||||
|
Iris::my_memory.map (buffer_page, buffer)
|
||||||
// Initialize the globals. My method of compiling doesn't handle global constructors.
|
// Initialize the globals. My method of compiling doesn't handle global constructors.
|
||||||
device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 3, 1 }
|
device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 3, 1 }
|
||||||
config_descriptor = (my_config){
|
config_descriptor = (my_config){
|
||||||
@ -259,6 +274,16 @@ void Udc::init (Iris::WBlock b):
|
|||||||
UDC_POWER = 0
|
UDC_POWER = 0
|
||||||
UDC_TESTMODE = 0
|
UDC_TESTMODE = 0
|
||||||
configuration = 0
|
configuration = 0
|
||||||
|
// Set max packet sizes.
|
||||||
|
UDC_INDEX = 1
|
||||||
|
UDC_OUTMAXP = max_packet_size_bulk
|
||||||
|
UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||||
|
UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||||
|
UDC_INDEX = 2
|
||||||
|
UDC_INMAXP = max_packet_size_bulk
|
||||||
|
UDC_INCSRH = UDC_INCSRH_MODE
|
||||||
|
UDC_INCSR = UDC_INCSR_CDT | UDC_INCSR_FF
|
||||||
|
UDC_INCSR = UDC_INCSR_CDT | UDC_INCSR_FF
|
||||||
// exit suspend mode by reading the interrupt register.
|
// exit suspend mode by reading the interrupt register.
|
||||||
unsigned i = UDC_INTRUSB
|
unsigned i = UDC_INTRUSB
|
||||||
// reset all pending endpoint interrupts.
|
// reset all pending endpoint interrupts.
|
||||||
@ -266,13 +291,10 @@ void Udc::init (Iris::WBlock b):
|
|||||||
i = UDC_INTROUT
|
i = UDC_INTROUT
|
||||||
// enable interrupt on bus reset.
|
// enable interrupt on bus reset.
|
||||||
UDC_INTRUSBE = UDC_INTR_RESET
|
UDC_INTRUSBE = UDC_INTR_RESET
|
||||||
// enable interrupt on control endpoint.
|
// enable interrupts on endpoint 0 and in endpoint 2
|
||||||
UDC_INTRINE = 1 << 0
|
UDC_INTRINE = 1 << 0 | 1 << 2
|
||||||
// Set max packet sizes.
|
// and on out endpoint 1.
|
||||||
UDC_INDEX = 1
|
UDC_INTROUTE = 1 << 1
|
||||||
UDC_OUTMAXP = max_packet_size_bulk
|
|
||||||
UDC_INDEX = 2
|
|
||||||
UDC_INMAXP = max_packet_size_bulk
|
|
||||||
// Wait a while.
|
// Wait a while.
|
||||||
Iris::sleep (HZ / 10)
|
Iris::sleep (HZ / 10)
|
||||||
// Connect to the host.
|
// Connect to the host.
|
||||||
@ -288,14 +310,17 @@ void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxleng
|
|||||||
unsigned i
|
unsigned i
|
||||||
for i = 0; (length - i & ~3) > 0 && i < length; i += 4:
|
for i = 0; (length - i & ~3) > 0 && i < length; i += 4:
|
||||||
UDC_FIFO (ep) = ((unsigned *)data)[i / 4]
|
UDC_FIFO (ep) = ((unsigned *)data)[i / 4]
|
||||||
kdebug_num (((unsigned *)data)[i / 4], 8)
|
//kdebug_num (((unsigned *)data)[i / 4], 8)
|
||||||
kdebug (" ")
|
//kdebug (" ")
|
||||||
for ; i < length; ++i:
|
for ; i < length; ++i:
|
||||||
UDC_FIFO8 (ep) = data[i]
|
UDC_FIFO8 (ep) = data[i]
|
||||||
kdebug_num (data[i], 2)
|
//kdebug_num (data[i], 2)
|
||||||
kdebug (" ")
|
//kdebug (" ")
|
||||||
|
|
||||||
void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
|
void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
|
||||||
|
UDC_INDEX = 2
|
||||||
|
if UDC_INCSR & UDC_INCSR_INPKTRDY:
|
||||||
|
Iris::panic (0, "sending padded not possible because a packet is already waiting.\n")
|
||||||
unsigned len = length < maxlength ? length : maxlength
|
unsigned len = length < maxlength ? length : maxlength
|
||||||
residue = maxlength - len
|
residue = maxlength - len
|
||||||
len = (len + 3) & ~3
|
len = (len + 3) & ~3
|
||||||
@ -303,42 +328,41 @@ void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
|
|||||||
while len + 3 < maxlength:
|
while len + 3 < maxlength:
|
||||||
UDC_FIFO (2) = 0
|
UDC_FIFO (2) = 0
|
||||||
len += 4
|
len += 4
|
||||||
kdebug_char ('-')
|
//kdebug_char ('-')
|
||||||
while len < maxlength:
|
while len < maxlength:
|
||||||
UDC_FIFO8 (2) = 0
|
UDC_FIFO8 (2) = 0
|
||||||
++len
|
++len
|
||||||
kdebug_char ('.')
|
//kdebug_char ('.')
|
||||||
UDC_INDEX = 2
|
|
||||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
||||||
while true:
|
while true:
|
||||||
Iris::register_interrupt (IRQ_UDC)
|
Iris::register_interrupt (IRQ_UDC)
|
||||||
Iris::wait_for_interrupt (IRQ_UDC)
|
Iris::wait_for_interrupt (IRQ_UDC)
|
||||||
kdebug ("interrupt pad\n")
|
//kdebug ("interrupt pad\t")
|
||||||
unsigned usb = UDC_INTRUSB
|
unsigned usb = UDC_INTRUSB
|
||||||
unsigned in = UDC_INTRIN
|
unsigned in = UDC_INTRIN
|
||||||
unsigned out = UDC_INTROUT
|
unsigned out = UDC_INTROUT
|
||||||
if usb & 4 || in & 1:
|
if usb & 4 || in & 1:
|
||||||
kdebug ("general interrupt pad\n")
|
//kdebug ("general interrupt pad\t")
|
||||||
if !handle_interrupt (usb & 4, in & 1):
|
if !handle_interrupt (usb & 4, in & 1):
|
||||||
return
|
return
|
||||||
if out & 2:
|
if out & 2:
|
||||||
Iris::panic (0, "out interrupt while waiting for in")
|
Iris::panic (0, "out interrupt while waiting for in")
|
||||||
if in & 4:
|
if in & 4:
|
||||||
break
|
break
|
||||||
kdebug ("done interrupt pad\n")
|
//kdebug ("done interrupt pad\n")
|
||||||
|
|
||||||
unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||||
switch type:
|
switch type:
|
||||||
case Configuration::Type:
|
case Configuration::Type:
|
||||||
if idx != 0:
|
if idx != 0:
|
||||||
return false
|
return false
|
||||||
Iris::debug ("get config descriptor\n")
|
//Iris::debug ("get config descriptor\n")
|
||||||
send (0, reinterpret_cast <char const *> (&config_descriptor), sizeof (config_descriptor), len)
|
send (0, reinterpret_cast <char const *> (&config_descriptor), sizeof (config_descriptor), len)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case Device::Type:
|
case Device::Type:
|
||||||
if idx != 0:
|
if idx != 0:
|
||||||
return false
|
return false
|
||||||
Iris::debug ("get device descriptor\n")
|
//Iris::debug ("get device descriptor\n")
|
||||||
send (0, reinterpret_cast <char const *> (&device_descriptor), sizeof (device_descriptor), len)
|
send (0, reinterpret_cast <char const *> (&device_descriptor), sizeof (device_descriptor), len)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case Device_Qualifier::Type:
|
case Device_Qualifier::Type:
|
||||||
@ -352,19 +376,19 @@ unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
|||||||
case String <6>::Type:
|
case String <6>::Type:
|
||||||
switch idx:
|
switch idx:
|
||||||
case 0:
|
case 0:
|
||||||
Iris::debug ("get language descriptor\n")
|
//Iris::debug ("get language descriptor\n")
|
||||||
send (0, reinterpret_cast <char const *> (&s_langs), sizeof (s_langs), len)
|
send (0, reinterpret_cast <char const *> (&s_langs), sizeof (s_langs), len)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case 1:
|
case 1:
|
||||||
Iris::debug ("get manufacturer descriptor\n")
|
//Iris::debug ("get manufacturer descriptor\n")
|
||||||
send (0, reinterpret_cast <char const *> (&s_manufacturer), sizeof (s_manufacturer), len)
|
send (0, reinterpret_cast <char const *> (&s_manufacturer), sizeof (s_manufacturer), len)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case 2:
|
case 2:
|
||||||
Iris::debug ("get product descriptor\n")
|
//Iris::debug ("get product descriptor\n")
|
||||||
send (0, reinterpret_cast <char const *> (&s_product), sizeof (s_product), len)
|
send (0, reinterpret_cast <char const *> (&s_product), sizeof (s_product), len)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case 3:
|
case 3:
|
||||||
Iris::debug ("get serial descriptor\n")
|
//Iris::debug ("get serial descriptor\n")
|
||||||
send (0, reinterpret_cast <char const *> (&s_serial), sizeof (s_serial), len)
|
send (0, reinterpret_cast <char const *> (&s_serial), sizeof (s_serial), len)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
default:
|
default:
|
||||||
@ -375,38 +399,42 @@ unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
|||||||
unsigned Udc::handle_setup (Setup *s):
|
unsigned Udc::handle_setup (Setup *s):
|
||||||
switch s->request_type:
|
switch s->request_type:
|
||||||
case STANDARD_TO_DEVICE:
|
case STANDARD_TO_DEVICE:
|
||||||
|
UDC_INDEX = 0
|
||||||
|
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||||
switch s->request:
|
switch s->request:
|
||||||
case SET_ADDRESS:
|
case SET_ADDRESS:
|
||||||
UDC_FADDR = s->value
|
UDC_FADDR = s->value
|
||||||
Iris::debug ("set address %x\n", s->value)
|
//Iris::debug ("set address %x\n", s->value)
|
||||||
return 0
|
return 0
|
||||||
case SET_CONFIGURATION:
|
case SET_CONFIGURATION:
|
||||||
if s->value >= 2:
|
if s->value >= 2:
|
||||||
return ~0
|
return ~0
|
||||||
configuration = s->value
|
configuration = s->value
|
||||||
Iris::debug ("set configuration %x\n", s->value)
|
//Iris::debug ("set configuration %x\n", s->value)
|
||||||
return 0
|
return 0
|
||||||
case SET_INTERFACE:
|
case SET_INTERFACE:
|
||||||
if s->value != 0:
|
if s->value != 0:
|
||||||
return ~0
|
return ~0
|
||||||
Iris::debug ("set interface %x\n", s->value)
|
//Iris::debug ("set interface %x\n", s->value)
|
||||||
return 0
|
return 0
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
case STANDARD_FROM_DEVICE:
|
case STANDARD_FROM_DEVICE:
|
||||||
|
UDC_INDEX = 0
|
||||||
|
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||||
switch s->request:
|
switch s->request:
|
||||||
case GET_STATUS:
|
case GET_STATUS:
|
||||||
Iris::debug ("get status\n")
|
//Iris::debug ("get status\t")
|
||||||
send (0, "\0\0", 2, s->length)
|
send (0, "\0\0", 2, s->length)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case GET_DESCRIPTOR:
|
case GET_DESCRIPTOR:
|
||||||
return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
|
return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
|
||||||
case GET_CONFIGURATION:
|
case GET_CONFIGURATION:
|
||||||
Iris::debug ("get configuration\n")
|
//Iris::debug ("get configuration\t")
|
||||||
send (0, &configuration, 1, s->length)
|
send (0, &configuration, 1, s->length)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case GET_INTERFACE:
|
case GET_INTERFACE:
|
||||||
Iris::debug ("get interface\n")
|
//Iris::debug ("get interface\t")
|
||||||
send (0, "\0", 1, s->length)
|
send (0, "\0", 1, s->length)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
default:
|
default:
|
||||||
@ -418,35 +446,42 @@ unsigned Udc::handle_setup (Setup *s):
|
|||||||
case ENDPOINT_HALT:
|
case ENDPOINT_HALT:
|
||||||
switch s->index:
|
switch s->index:
|
||||||
case 0x82:
|
case 0x82:
|
||||||
Iris::debug ("in ep halt reset\n")
|
//Iris::debug ("in ep halt reset\n")
|
||||||
UDC_INDEX = 2
|
UDC_INDEX = 2
|
||||||
UDC_INCSR &= ~(UDC_INCSR_SENDSTALL | UDC_INCSR_SENTSTALL)
|
UDC_INCSR &= ~UDC_INCSR_SENDSTALL
|
||||||
stalling[2] = false
|
stalling[2] = false
|
||||||
return 0
|
break
|
||||||
case 1:
|
case 1:
|
||||||
Iris::debug ("out ep halt reset\n")
|
//Iris::debug ("out ep halt reset\n")
|
||||||
UDC_INDEX = 1
|
UDC_INDEX = 1
|
||||||
UDC_OUTCSR &= ~(UDC_OUTCSR_SENDSTALL | UDC_OUTCSR_SENTSTALL)
|
UDC_OUTCSR &= ~UDC_OUTCSR_SENDSTALL
|
||||||
stalling[1] = false
|
stalling[1] = false
|
||||||
return 0
|
break
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
|
UDC_INDEX = 0
|
||||||
|
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||||
|
return 0
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
case CLASS_FROM_INTERFACE:
|
case CLASS_FROM_INTERFACE:
|
||||||
|
UDC_INDEX = 0
|
||||||
|
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||||
switch s->request:
|
switch s->request:
|
||||||
case GET_MAX_LUN:
|
case GET_MAX_LUN:
|
||||||
Iris::debug ("get max lun\n")
|
//Iris::debug ("get max lun\t")
|
||||||
send (0, "\0", 1, s->length)
|
send (0, "\0", 1, s->length)
|
||||||
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
case CLASS_TO_INTERFACE:
|
case CLASS_TO_INTERFACE:
|
||||||
|
UDC_INDEX = 0
|
||||||
|
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
||||||
switch s->request:
|
switch s->request:
|
||||||
case BULK_ONLY_RESET:
|
case BULK_ONLY_RESET:
|
||||||
Iris::debug ("bulk reset\n")
|
//Iris::debug ("bulk reset\n")
|
||||||
return 0
|
return 0
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
@ -462,45 +497,48 @@ void Udc::irq_usb ():
|
|||||||
UDC_INTROUTE = 1 << 1
|
UDC_INTROUTE = 1 << 1
|
||||||
UDC_INDEX = 1
|
UDC_INDEX = 1
|
||||||
// Do this twice to flush a double-buffered fifo completely.
|
// Do this twice to flush a double-buffered fifo completely.
|
||||||
|
UDC_OUTMAXP = max_packet_size_bulk
|
||||||
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||||
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
|
||||||
UDC_INDEX = 2
|
UDC_INDEX = 2
|
||||||
|
UDC_INMAXP = max_packet_size_bulk
|
||||||
UDC_INCSR |= UDC_INCSR_CDT
|
UDC_INCSR |= UDC_INCSR_CDT
|
||||||
Iris::debug ("usb reset\n")
|
//Iris::debug ("usb reset\n")
|
||||||
|
|
||||||
void Udc::irq_in0 ():
|
void Udc::irq_in0 ():
|
||||||
// Interrupt on endpoint 0.
|
// Interrupt on endpoint 0.
|
||||||
UDC_INDEX = 0
|
UDC_INDEX = 0
|
||||||
unsigned csr = UDC_CSR0
|
unsigned csr = UDC_CSR0
|
||||||
if csr & UDC_CSR0_SENTSTALL:
|
if csr & UDC_CSR0_SENTSTALL:
|
||||||
csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL)
|
UDC_CSR0 = 0
|
||||||
|
//Iris::debug ("stall done\t")
|
||||||
if csr & UDC_CSR0_SETUPEND:
|
if csr & UDC_CSR0_SETUPEND:
|
||||||
csr |= UDC_CSR0_SVDSETUPEND
|
UDC_CSR0 = UDC_CSR0_SVDSETUPEND
|
||||||
|
//Iris::debug ("setup aborted\t")
|
||||||
if !(csr & UDC_CSR0_OUTPKTRDY):
|
if !(csr & UDC_CSR0_OUTPKTRDY):
|
||||||
kdebug ("packet sent 0\n")
|
//Iris::debug ("no packet 0: %x\n", csr)
|
||||||
return
|
return
|
||||||
union { unsigned d[2]; Setup s; } packet
|
union { unsigned d[2]; Setup s; } packet
|
||||||
packet.d[0] = UDC_FIFO (0)
|
packet.d[0] = UDC_FIFO (0)
|
||||||
packet.d[1] = UDC_FIFO (0)
|
packet.d[1] = UDC_FIFO (0)
|
||||||
if !(packet.s.request_type & 0x80) && packet.s.length > 0:
|
if !(packet.s.request_type & 0x80) && packet.s.length > 0:
|
||||||
// More data will follow; unsupported.
|
// More data will follow; unsupported.
|
||||||
Iris::debug ("packet on ep0 too long\n")
|
//Iris::debug ("packet on ep0 too long\n")
|
||||||
UDC_CSR0 = csr | UDC_CSR0_SENDSTALL
|
UDC_CSR0 = UDC_CSR0_SENDSTALL
|
||||||
return
|
return
|
||||||
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
|
|
||||||
csr &= ~(UDC_CSR0_SETUPEND | UDC_CSR0_SENDSTALL | UDC_CSR0_SENTSTALL)
|
|
||||||
unsigned ret = handle_setup (&packet.s)
|
|
||||||
UDC_INDEX = 1
|
UDC_INDEX = 1
|
||||||
UDC_OUTCSR |= UDC_OUTCSR_CDT
|
UDC_OUTCSR |= UDC_OUTCSR_CDT
|
||||||
UDC_INDEX = 2
|
UDC_INDEX = 2
|
||||||
UDC_INCSR |= UDC_INCSR_CDT
|
UDC_INCSR |= UDC_INCSR_CDT
|
||||||
|
unsigned ret = handle_setup (&packet.s)
|
||||||
UDC_INDEX = 0
|
UDC_INDEX = 0
|
||||||
if ret == ~0:
|
if ret == ~0:
|
||||||
Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
|
Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
|
||||||
UDC_CSR0 = csr | UDC_CSR0_SENDSTALL
|
UDC_CSR0 = UDC_CSR0_SENDSTALL
|
||||||
return
|
return
|
||||||
UDC_CSR0 = csr | ret
|
if ret:
|
||||||
kdebug ("done in0\n")
|
UDC_CSR0 = ret
|
||||||
|
//kdebug ("done in0\n")
|
||||||
|
|
||||||
void Udc::send_csw ():
|
void Udc::send_csw ():
|
||||||
UDC_INDEX = 2
|
UDC_INDEX = 2
|
||||||
@ -524,32 +562,38 @@ void Udc::send_csw ():
|
|||||||
unsigned out = UDC_INTROUT
|
unsigned out = UDC_INTROUT
|
||||||
if out & 2:
|
if out & 2:
|
||||||
Iris::panic (0, "out interrupt while waiting for in after csw")
|
Iris::panic (0, "out interrupt while waiting for in after csw")
|
||||||
kdebug ("sent csw\n")
|
//kdebug ("sent csw\n")
|
||||||
|
|
||||||
void Udc::stall (unsigned error):
|
void Udc::stall (unsigned error):
|
||||||
unsigned index = UDC_INDEX
|
unsigned index = UDC_INDEX
|
||||||
|
if stalling[index]:
|
||||||
|
Iris::debug ("already stalling!\n")
|
||||||
if index == 1:
|
if index == 1:
|
||||||
UDC_OUTCSR |= UDC_OUTCSR_SENDSTALL
|
UDC_OUTCSR |= UDC_OUTCSR_SENDSTALL
|
||||||
else:
|
else:
|
||||||
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
||||||
stalling[index] = true
|
stalling[index] = true
|
||||||
kdebug ("stalling\n")
|
|
||||||
while stalling[index]:
|
while stalling[index]:
|
||||||
|
//kdebug ("stalling\t")
|
||||||
Iris::register_interrupt (IRQ_UDC)
|
Iris::register_interrupt (IRQ_UDC)
|
||||||
Iris::wait_for_interrupt (IRQ_UDC)
|
Iris::wait_for_interrupt (IRQ_UDC)
|
||||||
kdebug ("stalling interrupt\n")
|
//kdebug ("stalling interrupt\n")
|
||||||
unsigned usb = UDC_INTRUSB
|
unsigned usb = UDC_INTRUSB
|
||||||
unsigned in = UDC_INTRIN
|
unsigned in = UDC_INTRIN
|
||||||
|
if in & 4:
|
||||||
|
//kdebug ("stall has been sent to in endpoint\n")
|
||||||
|
UDC_INDEX = 2
|
||||||
|
UDC_INCSR &= ~UDC_INCSR_SENTSTALL
|
||||||
|
//Iris::debug ("csr: %x\n", UDC_INCSR)
|
||||||
if usb & 4 || in & 1:
|
if usb & 4 || in & 1:
|
||||||
kdebug ("stuff\n")
|
//kdebug ("stuff\n")
|
||||||
if !handle_interrupt (usb & 4, in & 1):
|
if !handle_interrupt (usb & 4, in & 1):
|
||||||
return
|
return
|
||||||
if in & 4:
|
|
||||||
kdebug ("in interrupt ignored while waiting for stall reset\n")
|
|
||||||
unsigned out = UDC_INTROUT
|
unsigned out = UDC_INTROUT
|
||||||
if out & 2:
|
if out & 2:
|
||||||
Iris::panic (0, "out interrupt while waiting for stall reset")
|
//kdebug ("stall has been sent to out endpoint\n")
|
||||||
kdebug ("no stuff\n")
|
UDC_INDEX = 1
|
||||||
|
UDC_OUTCSR &= ~UDC_OUTCSR_SENTSTALL
|
||||||
UDC_INDEX = index
|
UDC_INDEX = index
|
||||||
if index == 2:
|
if index == 2:
|
||||||
status = error
|
status = error
|
||||||
@ -564,12 +608,12 @@ void Udc::irq_out ():
|
|||||||
unsigned size = UDC_OUTCOUNT
|
unsigned size = UDC_OUTCOUNT
|
||||||
if !(csr & UDC_OUTCSR_OUTPKTRDY):
|
if !(csr & UDC_OUTCSR_OUTPKTRDY):
|
||||||
// No packet, just a notification.
|
// No packet, just a notification.
|
||||||
kdebug ("no packet\n")
|
//kdebug ("no packet\n")
|
||||||
return
|
return
|
||||||
if csr & UDC_OUTCSR_SENDSTALL:
|
if csr & UDC_OUTCSR_SENDSTALL:
|
||||||
// When stalling, do nothing else.
|
// When stalling, do nothing else.
|
||||||
kdebug ("not responding to out during stall\n")
|
//kdebug ("not responding to out during stall\n")
|
||||||
UDC_OUTCSR &= ~UDC_OUTCSR_SENTSTALL
|
UDC_OUTCSR = csr & ~UDC_OUTCSR_SENTSTALL
|
||||||
return
|
return
|
||||||
// expect a new cbw.
|
// expect a new cbw.
|
||||||
if size != 31:
|
if size != 31:
|
||||||
@ -578,51 +622,100 @@ void Udc::irq_out ():
|
|||||||
return
|
return
|
||||||
union Cbw:
|
union Cbw:
|
||||||
unsigned u[8]
|
unsigned u[8]
|
||||||
|
char b[32]
|
||||||
CBW cbw
|
CBW cbw
|
||||||
Cbw cbw
|
Cbw cbw
|
||||||
for unsigned i = 0; i < 8; ++i:
|
for unsigned i = 0; i < 7; ++i:
|
||||||
cbw.u[i] = UDC_FIFO (1)
|
cbw.u[i] = UDC_FIFO (1)
|
||||||
|
for unsigned i = 28; i < 31; ++i:
|
||||||
|
cbw.b[i] = UDC_FIFO8 (1)
|
||||||
|
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
|
||||||
tag = cbw.cbw.tag
|
tag = cbw.cbw.tag
|
||||||
if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
|
if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
|
||||||
Iris::debug ("sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
|
Iris::debug ("sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
|
||||||
stall (2)
|
stall (2)
|
||||||
return
|
return
|
||||||
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
|
//kdebug ("bulk cbw\t")
|
||||||
kdebug ("bulk cbw\n")
|
|
||||||
UDC_INDEX = 2
|
UDC_INDEX = 2
|
||||||
bool to_host = cbw.cbw.flags & 0x80
|
bool to_host = cbw.cbw.flags & 0x80
|
||||||
switch cbw.cbw.data[0]:
|
switch cbw.cbw.data[0]:
|
||||||
case CBW::INQUIRY:
|
|
||||||
if !to_host:
|
|
||||||
stall (2)
|
|
||||||
break
|
|
||||||
Iris::debug ("sending inquiry response\n")
|
|
||||||
send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick 0 ", 36, cbw.cbw.length)
|
|
||||||
send_csw ()
|
|
||||||
break
|
|
||||||
case CBW::TEST_UNIT_READY:
|
case CBW::TEST_UNIT_READY:
|
||||||
if to_host || cbw.cbw.length != 0:
|
if to_host || cbw.cbw.length != 0:
|
||||||
stall (2)
|
stall (2)
|
||||||
return
|
return
|
||||||
Iris::debug ("sending ready response\n")
|
//Iris::debug ("sending ready response\t")
|
||||||
send_csw ()
|
|
||||||
break
|
|
||||||
case CBW::READ_CAPACITY:
|
|
||||||
if !to_host:
|
|
||||||
stall (2)
|
|
||||||
break
|
|
||||||
unsigned capacity[2]
|
|
||||||
capacity[0] = big_endian ((block.get_size ().value () >> block_bits) - 1)
|
|
||||||
capacity[1] = big_endian (1 << block_bits)
|
|
||||||
Iris::debug ("sending capacity: %x * %x\n", capacity[0], capacity[1])
|
|
||||||
send_padded ((char *)capacity, 8, cbw.cbw.length)
|
|
||||||
send_csw ()
|
send_csw ()
|
||||||
break
|
break
|
||||||
case CBW::REQUEST_SENSE:
|
case CBW::REQUEST_SENSE:
|
||||||
Iris::debug ("sense requested\n")
|
//Iris::debug ("sense requested\t")
|
||||||
send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
|
send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
|
||||||
send_csw ()
|
send_csw ()
|
||||||
break
|
break
|
||||||
|
case CBW::FORMAT_UNIT:
|
||||||
|
Iris::panic (0, "FORMAT_UNIT isn't implemented")
|
||||||
|
case CBW::INQUIRY:
|
||||||
|
if !to_host:
|
||||||
|
stall (2)
|
||||||
|
return
|
||||||
|
//Iris::debug ("sending inquiry response\t")
|
||||||
|
send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick \x00\x00\x04\x02", 36, cbw.cbw.length)
|
||||||
|
send_csw ()
|
||||||
|
break
|
||||||
|
case CBW::RESERVE6:
|
||||||
|
Iris::panic (0, "RESERVE6 isn't implemented")
|
||||||
|
case CBW::RELEASE6:
|
||||||
|
Iris::panic (0, "RELEASE6 isn't implemented")
|
||||||
|
case CBW::SEND_DIAGNOSTIC:
|
||||||
|
Iris::panic (0, "SEND_DIAGNOSTIC isn't implemented")
|
||||||
|
case CBW::READ_CAPACITY:
|
||||||
|
if !to_host:
|
||||||
|
stall (2)
|
||||||
|
return
|
||||||
|
unsigned capacity[2]
|
||||||
|
capacity[0] = big_endian ((block.get_size ().value () >> block_bits) - 1)
|
||||||
|
capacity[1] = big_endian (1 << block_bits)
|
||||||
|
//Iris::debug ("sending capacity: %x * %x\t", capacity[0], capacity[1])
|
||||||
|
send_padded ((char *)capacity, 8, cbw.cbw.length)
|
||||||
|
send_csw ()
|
||||||
|
break
|
||||||
|
case CBW::READ10:
|
||||||
|
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)
|
||||||
|
// read block lba + i.
|
||||||
|
buffer_page.set_flags (Iris::Page::FRAME)
|
||||||
|
block.get_block (lba << 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
|
||||||
|
for unsigned t = 0; t < max_packet_size_bulk; t += 4:
|
||||||
|
UDC_FIFO (2) = ((unsigned *)buffer)[(p + t) >> 2]
|
||||||
|
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
||||||
|
//Iris::debug ("\n")
|
||||||
|
while true:
|
||||||
|
Iris::register_interrupt (IRQ_UDC)
|
||||||
|
Iris::wait_for_interrupt (IRQ_UDC)
|
||||||
|
//kdebug ("interrupt read10\t")
|
||||||
|
unsigned usb = UDC_INTRUSB
|
||||||
|
unsigned in = UDC_INTRIN
|
||||||
|
unsigned out = UDC_INTROUT
|
||||||
|
if usb & 4 || in & 1:
|
||||||
|
//kdebug ("general interrupt read10\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
|
||||||
|
send_csw ()
|
||||||
|
break
|
||||||
|
case CBW::WRITE10:
|
||||||
|
Iris::panic (0, "WRITE10 isn't implemented")
|
||||||
|
case CBW::RESERVE10:
|
||||||
|
Iris::panic (0, "RESERVE10 isn't implemented")
|
||||||
|
case CBW::RELEASE10:
|
||||||
|
Iris::panic (0, "RELEASE10 isn't implemented")
|
||||||
default:
|
default:
|
||||||
Iris::debug ("cbw:")
|
Iris::debug ("cbw:")
|
||||||
for unsigned i = 0; i < cbw.cbw.size; ++i:
|
for unsigned i = 0; i < cbw.cbw.size; ++i:
|
||||||
@ -631,35 +724,40 @@ void Udc::irq_out ():
|
|||||||
Iris::debug ("\n")
|
Iris::debug ("\n")
|
||||||
residue = cbw.cbw.length
|
residue = cbw.cbw.length
|
||||||
stall (1)
|
stall (1)
|
||||||
break
|
return
|
||||||
// TODO.
|
// TODO.
|
||||||
|
|
||||||
bool Udc::handle_interrupt (bool usb, bool in):
|
bool Udc::handle_interrupt (bool usb, bool in):
|
||||||
if usb:
|
if usb:
|
||||||
Iris::debug ("usb\t")
|
//Iris::debug ("usb\t")
|
||||||
// reset.
|
// reset.
|
||||||
irq_usb ()
|
irq_usb ()
|
||||||
return false
|
return false
|
||||||
if in:
|
if in:
|
||||||
Iris::debug ("control\t")
|
//Iris::debug ("control\t")
|
||||||
// control request
|
// control request
|
||||||
irq_in0 ()
|
irq_in0 ()
|
||||||
return true
|
return true
|
||||||
|
|
||||||
void Udc::interrupt ():
|
void Udc::interrupt ():
|
||||||
|
//Iris::debug ("interrupt\n")
|
||||||
while true:
|
while true:
|
||||||
unsigned usb = UDC_INTRUSB
|
unsigned usb = UDC_INTRUSB
|
||||||
unsigned in = UDC_INTRIN
|
unsigned in = UDC_INTRIN
|
||||||
unsigned out = UDC_INTROUT
|
bool action = false
|
||||||
if !(usb & 4) && !(in & 5) && !(out & 2):
|
|
||||||
// No more interrupts to handle; this is normal, because we're looping until this happens.
|
|
||||||
Iris::debug ("irq done\n")
|
|
||||||
return
|
|
||||||
if in & 4:
|
if in & 4:
|
||||||
Iris::debug ("ignoring data request during idle\n")
|
Iris::panic (0, "data request during idle\n")
|
||||||
handle_interrupt (usb & 4, in & 1)
|
if usb & 4 || in & 1:
|
||||||
|
handle_interrupt (usb & 4, in & 1)
|
||||||
|
action = true
|
||||||
|
unsigned out = UDC_INTROUT
|
||||||
if out & 2:
|
if out & 2:
|
||||||
irq_out ()
|
irq_out ()
|
||||||
|
action = true
|
||||||
|
if !action:
|
||||||
|
// No more interrupts to handle; this is normal, because we're looping until this happens.
|
||||||
|
//Iris::debug ("irq done\n")
|
||||||
|
return
|
||||||
|
|
||||||
Iris::Num start ():
|
Iris::Num start ():
|
||||||
map_udc ()
|
map_udc ()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user