1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-04-21 12:27:27 +03:00

Add unbricking method

This commit is contained in:
Bas Wijnen
2010-10-10 10:46:12 +02:00
parent 5f9fd7cc0f
commit 9aff93c300
8 changed files with 405 additions and 312 deletions

View File

@@ -30,7 +30,7 @@ static bool dirty
static unsigned current_block
static void sync ():
Iris::debug ("erasing %x\n", current_block << block_bits)
//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)])

View File

@@ -28,20 +28,15 @@ IDLE: after reset or csw.
IN interrupt: csw received, do nothing.
OUT interrupt: cbw; handle
-> IDLE (no data; csw sent)
-> CSW (data sent in one packet)
-> TX (more than one packet to send)
-> TX (send)
-> RX (receive packets)
TX: transmitting data.
IN interrupt: host received data; send more.
-> TX (more to send)
-> CSW (last data has now been sent)
RX: receiving data.
OUT interrupt: host sent data; handle.
-> RX (more to receive)
-> IDLE (done receiving; send csw)
CSW: waiting to transmit csw.
IN interrupt: TX is done; send csw
-> IDLE
#endif
extern "C":
@@ -218,17 +213,27 @@ class Udc:
char configuration
unsigned get_descriptor (unsigned type, unsigned idx, unsigned len)
unsigned handle_setup (Setup *s)
void irq_usb ()
void reset ()
void irq_in0 ()
void irq_out ()
void handle_rx ()
void handle_tx ()
void handle_cbw ()
void send_csw ()
unsigned big_endian (unsigned src)
bool handle_interrupt (bool usb, bool in)
void stall (unsigned error)
bool stalling[3]
bool stalling
enum State:
IDLE
TX
RX
SENT_CSW
STALL
State state
unsigned residue
unsigned status
unsigned tag
unsigned data_done, lba, blocks
unsigned block_bits
Iris::WBlock block
Iris::Page buffer_page
@@ -248,6 +253,35 @@ Udc::String <6> Udc::s_manufacturer
Udc::String <16> Udc::s_product
Udc::String <12> Udc::s_serial
void Udc::reset ():
// Reset.
UDC_TESTMODE = 0
configuration = 0
state = IDLE
status = 0
residue = 0
// enable interrupt on bus reset.
UDC_INTRUSBE = UDC_INTR_RESET
// enable interrupts on endpoint 0 and in endpoint 2
UDC_INTRINE = 1 << 0 | 1 << 2
// and on out endpoint 1.
UDC_INTROUTE = 1 << 1
// exit suspend mode by reading the interrupt register.
unsigned i = UDC_INTRUSB
// reset all pending endpoint interrupts.
i = UDC_INTRIN
i = UDC_INTROUT
UDC_INDEX = 1
UDC_OUTMAXP = max_packet_size_bulk
// Do this twice to flush a double-buffered fifo completely.
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
UDC_INDEX = 2
UDC_INMAXP = max_packet_size_bulk
UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
//Iris::debug ("usb reset\n")
void Udc::init (Iris::WBlock b):
block = b
block_bits = block.get_align_bits ()
@@ -272,37 +306,12 @@ void Udc::init (Iris::WBlock b):
cpm_start_udc ()
// Disconnect from the bus and don't try to get high-speed.
UDC_POWER = 0
UDC_TESTMODE = 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_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.
i = UDC_INTRIN
i = UDC_INTROUT
// enable interrupt on bus reset.
UDC_INTRUSBE = UDC_INTR_RESET
// enable interrupts on endpoint 0 and in endpoint 2
UDC_INTRINE = 1 << 0 | 1 << 2
// and on out endpoint 1.
UDC_INTROUTE = 1 << 1
reset ()
// Wait a while.
Iris::sleep (HZ / 10)
// Connect to the host.
UDC_POWER = UDC_POWER_SOFTCONN
// Initialize cbw state
status = 0
residue = 0
void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
if maxlength < length:
length = maxlength
@@ -318,8 +327,6 @@ void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxleng
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
residue = maxlength - len
len = (len + 3) & ~3
@@ -328,48 +335,14 @@ void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
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 ('-')
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")
while len < maxlength:
UDC_FIFO8 (2) = 0
++len
//kdebug_char ('.')
UDC_INCSR |= UDC_INCSR_INPKTRDY
blocks = 0
state = TX
unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
switch type:
@@ -424,18 +397,18 @@ unsigned Udc::handle_setup (Setup *s):
switch s->request:
case SET_ADDRESS:
UDC_FADDR = s->value
//Iris::debug ("set address %x\n", s->value)
Iris::debug ("set address %x\n", s->value)
return 0
case SET_CONFIGURATION:
if s->value >= 2:
return ~0
configuration = s->value
//Iris::debug ("set configuration %x\n", s->value)
Iris::debug ("set configuration %x\n", s->value)
return 0
case SET_INTERFACE:
if s->value != 0:
return ~0
//Iris::debug ("set interface %x\n", s->value)
Iris::debug ("set interface %x\n", s->value)
return 0
default:
return ~0
@@ -444,17 +417,17 @@ unsigned Udc::handle_setup (Setup *s):
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
switch s->request:
case GET_STATUS:
//Iris::debug ("get status\t")
Iris::debug ("get status\t")
send (0, "\0\0", 2, s->length)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case GET_DESCRIPTOR:
return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
case GET_CONFIGURATION:
//Iris::debug ("get configuration\t")
Iris::debug ("get configuration\t")
send (0, &configuration, 1, s->length)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
case GET_INTERFACE:
//Iris::debug ("get interface\t")
Iris::debug ("get interface\t")
send (0, "\0", 1, s->length)
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
default:
@@ -466,16 +439,16 @@ 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
UDC_INCSR = (UDC_INCSR & ~UDC_INCSR_SENDSTALL) | UDC_INCSR_CDT
stalling = false
send_csw ()
break
case 1:
Iris::debug ("out ep halt reset\n")
//Iris::panic (0, "halt reset on out endpoint")
UDC_INDEX = 1
UDC_OUTCSR &= ~UDC_OUTCSR_SENDSTALL
stalling[1] = false
UDC_OUTCSR |= UDC_OUTCSR_CDT
break
default:
return ~0
@@ -499,7 +472,8 @@ unsigned Udc::handle_setup (Setup *s):
UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
switch s->request:
case BULK_ONLY_RESET:
//Iris::debug ("bulk reset\n")
Iris::debug ("bulk reset\n")
state = IDLE
return 0
default:
return ~0
@@ -507,52 +481,32 @@ unsigned Udc::handle_setup (Setup *s):
Iris::debug ("request: %x %x %x %x %x\n", s->request_type, s->request, s->index, s->length, s->value)
return ~0
void Udc::irq_usb ():
// Reset.
// enable interrupts on endpoint 0 and in endpoint 2
UDC_INTRINE = 1 << 0 | 1 << 2
// and on out endpoint 1.
UDC_INTROUTE = 1 << 1
UDC_INDEX = 1
// 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_INDEX = 2
UDC_INMAXP = max_packet_size_bulk
UDC_INCSR |= UDC_INCSR_CDT
//Iris::debug ("usb reset\n")
void Udc::irq_in0 ():
// Interrupt on endpoint 0.
UDC_INDEX = 0
unsigned csr = UDC_CSR0
if csr & UDC_CSR0_SENTSTALL:
UDC_CSR0 = 0
//Iris::debug ("stall done\t")
//Iris::debug ("stall 0 done\t")
if csr & UDC_CSR0_SETUPEND:
UDC_CSR0 = UDC_CSR0_SVDSETUPEND
//Iris::debug ("setup aborted\t")
Iris::debug ("setup aborted\t")
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)
if !(packet.s.request_type & 0x80) && packet.s.length > 0:
// More data will follow; unsupported.
//Iris::debug ("packet on ep0 too long\n")
Iris::debug ("packet on ep0 too long\n")
UDC_CSR0 = UDC_CSR0_SENDSTALL
return
unsigned ret = handle_setup (&packet.s)
UDC_INDEX = 0
if ret == ~0:
Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
//Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
UDC_CSR0 = UDC_CSR0_SENDSTALL
return
if ret:
@@ -566,79 +520,73 @@ void Udc::send_csw ():
UDC_FIFO (2) = residue
UDC_FIFO8 (2) = status
UDC_INCSR |= UDC_INCSR_INPKTRDY
state = SENT_CSW
status = 0
residue = 0
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:
if !handle_interrupt (usb & 4, in & 1):
return
if in & 4:
break
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
if stalling[index]:
if stalling:
Iris::debug ("already stalling!\n")
if index == 1:
UDC_OUTCSR |= UDC_OUTCSR_SENDSTALL
else:
UDC_INCSR |= UDC_INCSR_SENDSTALL
stalling[index] = true
while stalling[index]:
//Iris::debug ("stalling %d\n", index)
Iris::register_interrupt (IRQ_UDC)
Iris::wait_for_interrupt (IRQ_UDC)
kdebug ("stalling interrupt\n")
unsigned usb = UDC_INTRUSB
unsigned in = UDC_INTRIN
if in & 4:
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)
if usb & 4 || in & 1:
//kdebug ("stuff\n")
if !handle_interrupt (usb & 4, in & 1):
return
unsigned out = UDC_INTROUT
if out & 2:
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
//kdebug ("done stalling\n")
if index == 2:
status = error
send_csw ()
UDC_INCSR |= UDC_INCSR_SENDSTALL
stalling = true
state = STALL
unsigned Udc::big_endian (unsigned src):
return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
void Udc::irq_out ():
void Udc::handle_rx ():
buffer_page.set_flags (Iris::Page::FRAME)
UDC_INDEX = 1
if !(UDC_OUTCSR & UDC_OUTCSR_OUTPKTRDY):
Iris::panic (0, "no packet ready after out interrupt during rx")
if UDC_OUTCOUNT != max_packet_size_bulk:
Iris::panic (UDC_OUTCOUNT, "invalid packet size during rx")
for unsigned t = 0; t < max_packet_size_bulk; t += 4:
((unsigned *)buffer)[(t + data_done) >> 2] = UDC_FIFO (1)
UDC_OUTCSR &= ~UDC_OUTCSR_OUTPKTRDY
data_done += max_packet_size_bulk
if data_done == 1 << block_bits:
//Iris::debug ("writing block %x\n", lba)
block.set_block (lba << block_bits, buffer_page, 1 << block_bits)
data_done = 0
--blocks
++lba
if blocks == 0:
send_csw ()
return
void Udc::handle_tx ():
if blocks == 0:
send_csw ()
return
if data_done == 0:
// read block lba.
buffer_page.set_flags (Iris::Page::FRAME)
block.get_block (lba << block_bits, 1 << block_bits, 0, buffer_page)
UDC_INDEX = 2
for unsigned t = 0; t < max_packet_size_bulk; t += 4:
UDC_FIFO (2) = ((unsigned *)buffer)[(data_done + t) >> 2]
data_done += max_packet_size_bulk
if data_done == 1 << block_bits:
data_done = 0
++lba
--blocks
UDC_INCSR |= UDC_INCSR_INPKTRDY
void Udc::handle_cbw ():
UDC_INDEX = 1
unsigned csr = UDC_OUTCSR
unsigned size = UDC_OUTCOUNT
if !(csr & UDC_OUTCSR_OUTPKTRDY):
// No packet, just a notification.
kdebug ("no packet\n")
return
if csr & UDC_OUTCSR_SENDSTALL:
// When stalling, do nothing else.
//kdebug ("not responding to out during stall\n")
UDC_OUTCSR = csr & ~UDC_OUTCSR_SENTSTALL
return
if !(csr & UDC_OUTCSR_OUTPKTRDY):
// No packet; this shouldn't happen.
Iris::panic (0, "no packet")
return
// expect a new cbw.
if size != 31:
Iris::debug ("count %d != 31\n", size)
@@ -656,10 +604,17 @@ void Udc::irq_out ():
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
tag = cbw.cbw.tag
if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
Iris::debug ("sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
Iris::debug ("wrong cbw: sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
stall (2)
return
//kdebug ("bulk cbw\t")
#if 0
Iris::debug ("cbw:")
for unsigned i = 0; i < cbw.cbw.size; ++i:
kdebug_char (' ')
kdebug_num (cbw.cbw.data[i], 2)
Iris::debug ("\n")
#endif
UDC_INDEX = 2
bool to_host = cbw.cbw.flags & 0x80
switch cbw.cbw.data[0]:
@@ -673,7 +628,6 @@ void Udc::irq_out ():
case CBW::REQUEST_SENSE:
//Iris::debug ("sense requested\n")
send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
send_csw ()
break
case CBW::FORMAT_UNIT:
Iris::panic (0, "FORMAT_UNIT isn't implemented")
@@ -682,8 +636,8 @@ void Udc::irq_out ():
stall (2)
return
//Iris::debug ("sending inquiry response\t")
// TODO: find out why these bytes are messed up.
send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick \x00\x00\x04\x02", 36, cbw.cbw.length)
send_csw ()
break
case CBW::RESERVE6:
Iris::panic (0, "RESERVE6 isn't implemented")
@@ -700,118 +654,94 @@ void Udc::irq_out ():
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\n", lba + i)
// read block lba + i.
buffer_page.set_flags (Iris::Page::FRAME)
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
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\n")
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 ()
if !to_host:
stall (2)
return
lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
data_done = 0
state = TX
handle_tx ()
break
case CBW::WRITE10:
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 ()
if to_host:
stall (2)
return
lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
if blocks == 0:
send_csw ()
break
state = RX
data_done = 0
buffer_page.set_flags (Iris::Page::FRAME)
break
case CBW::RESERVE10:
Iris::panic (0, "RESERVE10 isn't implemented")
case CBW::RELEASE10:
Iris::panic (0, "RELEASE10 isn't implemented")
default:
Iris::debug ("cbw:")
#if 0
Iris::debug ("unknown cbw:")
for unsigned i = 0; i < cbw.cbw.size; ++i:
kdebug_char (' ')
kdebug_num (cbw.cbw.data[i], 2)
Iris::debug ("\n")
#endif
residue = cbw.cbw.length
stall (1)
return
bool Udc::handle_interrupt (bool usb, bool in):
if usb:
//Iris::debug ("usb\t")
// reset.
irq_usb ()
return false
if in:
//Iris::debug ("control\t")
// control request
irq_in0 ()
return true
void Udc::interrupt ():
Iris::debug ("interrupt\n")
//Iris::debug ("interrupt, state = %d\n", state)
while true:
bool action = false
unsigned usb = UDC_INTRUSB
unsigned in = UDC_INTRIN
bool action = false
if in & 4:
Iris::panic (0, "data request during idle\n")
if usb & 4 || in & 1:
handle_interrupt (usb & 4, in & 1)
action = true
unsigned out = UDC_INTROUT
if usb & 4:
//Iris::debug ("reset\n")
reset ()
action = true
if state == STALL && in & 4:
// This must be handled here, because the state can be changed by the control request.
//Iris::debug ("stalling\n")
in &= ~4
if in & 1:
//Iris::debug ("control request\n")
irq_in0 ()
action = true
if in & 4:
//Iris::debug ("in request\n")
// Notification of sent packet (or stall, but we don't do that on the in endpoint).
switch state:
case SENT_CSW:
// csw received.
state = IDLE
break
case TX:
handle_tx ()
break
default:
Iris::panic (state, "invalid state for data send")
stall (2)
break
action = true
if out & 2:
irq_out ()
//Iris::debug ("out request\n")
switch state:
case IDLE:
handle_cbw ()
break
case RX:
handle_rx ()
break
default:
stall (2)
Iris::panic (0, "invalid state for data receive")
break
action = true
if !action:
// No more interrupts to handle; this is normal, because we're looping until this happens.