mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-29 02:39:53 +02:00
trying to simplify things, not working yet
This commit is contained in:
parent
61d76aaefb
commit
3a38ea2944
@ -152,9 +152,6 @@ class Udc:
|
|||||||
REQUEST_SENSE = 0x03
|
REQUEST_SENSE = 0x03
|
||||||
};
|
};
|
||||||
} __attribute__ ((packed))
|
} __attribute__ ((packed))
|
||||||
union Cbw:
|
|
||||||
unsigned u[8]
|
|
||||||
CBW cbw
|
|
||||||
static unsigned const max_packet_size0 = 64
|
static unsigned const max_packet_size0 = 64
|
||||||
static unsigned const max_packet_size_bulk = 64
|
static unsigned const max_packet_size_bulk = 64
|
||||||
enum Requests:
|
enum Requests:
|
||||||
@ -215,30 +212,23 @@ class Udc:
|
|||||||
unsigned handle_setup (Setup *s)
|
unsigned handle_setup (Setup *s)
|
||||||
void irq_usb ()
|
void irq_usb ()
|
||||||
void irq_in0 ()
|
void irq_in0 ()
|
||||||
void irq_in2 ()
|
|
||||||
void irq_out ()
|
void irq_out ()
|
||||||
void send_csw ()
|
void send_csw ()
|
||||||
void parse_cbw ()
|
|
||||||
unsigned big_endian (unsigned src)
|
unsigned big_endian (unsigned src)
|
||||||
enum State:
|
bool handle_interrupt (bool usb, bool in)
|
||||||
IDLE
|
void stall (unsigned error)
|
||||||
IDLE_WAIT
|
bool stalling[3]
|
||||||
RX
|
|
||||||
TX
|
|
||||||
CSW
|
|
||||||
SEND_CSW
|
|
||||||
State state
|
|
||||||
Cbw cbw
|
|
||||||
unsigned residue
|
unsigned residue
|
||||||
unsigned status
|
unsigned status
|
||||||
|
unsigned tag
|
||||||
unsigned block_bits
|
unsigned block_bits
|
||||||
Iris::WBlock block
|
Iris::WBlock block
|
||||||
public:
|
public:
|
||||||
void init (Iris::WBlock b)
|
void init (Iris::WBlock b)
|
||||||
void log (unsigned c)
|
void log (unsigned c)
|
||||||
void interrupt ()
|
void interrupt ()
|
||||||
unsigned send (unsigned ep, char const *data, unsigned length, unsigned maxlength)
|
void send (unsigned ep, char const *data, unsigned length, unsigned maxlength)
|
||||||
unsigned send_padded (unsigned ep, char const *data, unsigned length, unsigned maxlength)
|
void send_padded (char const *data, unsigned length, unsigned maxlength)
|
||||||
|
|
||||||
Udc::Device Udc::device_descriptor
|
Udc::Device Udc::device_descriptor
|
||||||
Udc::my_config Udc::config_descriptor
|
Udc::my_config Udc::config_descriptor
|
||||||
@ -268,7 +258,6 @@ void Udc::init (Iris::WBlock b):
|
|||||||
// Disconnect from the bus and don't try to get high-speed.
|
// Disconnect from the bus and don't try to get high-speed.
|
||||||
UDC_POWER = 0
|
UDC_POWER = 0
|
||||||
UDC_TESTMODE = 0
|
UDC_TESTMODE = 0
|
||||||
UDC_INDEX = 0
|
|
||||||
configuration = 0
|
configuration = 0
|
||||||
// exit suspend mode by reading the interrupt register.
|
// exit suspend mode by reading the interrupt register.
|
||||||
unsigned i = UDC_INTRUSB
|
unsigned i = UDC_INTRUSB
|
||||||
@ -279,41 +268,64 @@ void Udc::init (Iris::WBlock b):
|
|||||||
UDC_INTRUSBE = UDC_INTR_RESET
|
UDC_INTRUSBE = UDC_INTR_RESET
|
||||||
// enable interrupt on control endpoint.
|
// enable interrupt on control endpoint.
|
||||||
UDC_INTRINE = 1 << 0
|
UDC_INTRINE = 1 << 0
|
||||||
|
// Set max packet sizes.
|
||||||
|
UDC_INDEX = 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.
|
||||||
UDC_POWER = UDC_POWER_SOFTCONN
|
UDC_POWER = UDC_POWER_SOFTCONN
|
||||||
|
|
||||||
// Initialize cbw state
|
// Initialize cbw state
|
||||||
state = IDLE
|
|
||||||
status = 0
|
status = 0
|
||||||
residue = 0
|
residue = 0
|
||||||
|
|
||||||
unsigned Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
|
void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
|
||||||
if maxlength < length:
|
if maxlength < length:
|
||||||
length = maxlength
|
length = maxlength
|
||||||
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_char ('#')
|
kdebug_num (((unsigned *)data)[i / 4], 8)
|
||||||
|
kdebug (" ")
|
||||||
for ; i < length; ++i:
|
for ; i < length; ++i:
|
||||||
UDC_FIFO8 (ep) = data[i]
|
UDC_FIFO8 (ep) = data[i]
|
||||||
kdebug_char ('+')
|
kdebug_num (data[i], 2)
|
||||||
return ep == 0 ? UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND : 0
|
kdebug (" ")
|
||||||
|
|
||||||
unsigned Udc::send_padded (unsigned ep, char const *data, unsigned length, unsigned maxlength):
|
void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
|
||||||
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
|
||||||
send (ep, data, len, maxlength)
|
send (2, data, len, maxlength)
|
||||||
while len + 3 < maxlength:
|
while len + 3 < maxlength:
|
||||||
UDC_FIFO (ep) = 0
|
UDC_FIFO (2) = 0
|
||||||
len += 4
|
len += 4
|
||||||
kdebug_char ('-')
|
kdebug_char ('-')
|
||||||
while len < maxlength:
|
while len < maxlength:
|
||||||
UDC_FIFO8 (ep) = 0
|
UDC_FIFO8 (2) = 0
|
||||||
++len
|
++len
|
||||||
kdebug_char ('.')
|
kdebug_char ('.')
|
||||||
|
UDC_INDEX = 2
|
||||||
|
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
||||||
|
while true:
|
||||||
|
Iris::register_interrupt (IRQ_UDC)
|
||||||
|
Iris::wait_for_interrupt (IRQ_UDC)
|
||||||
|
kdebug ("interrupt pad\n")
|
||||||
|
unsigned usb = UDC_INTRUSB
|
||||||
|
unsigned in = UDC_INTRIN
|
||||||
|
unsigned out = UDC_INTROUT
|
||||||
|
if usb & 4 || in & 1:
|
||||||
|
kdebug ("general interrupt pad\n")
|
||||||
|
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")
|
||||||
|
|
||||||
unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||||
switch type:
|
switch type:
|
||||||
@ -321,16 +333,19 @@ unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
|||||||
if idx != 0:
|
if idx != 0:
|
||||||
return false
|
return false
|
||||||
Iris::debug ("get config descriptor\n")
|
Iris::debug ("get config descriptor\n")
|
||||||
return 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
|
||||||
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")
|
||||||
return 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
|
||||||
case Device_Qualifier::Type:
|
case Device_Qualifier::Type:
|
||||||
//if idx != 0:
|
//if idx != 0:
|
||||||
// return false
|
// return false
|
||||||
//return send (0, reinterpret_cast <char const *> (&device_qualifier_descriptor), sizeof (device_qualifier_descriptor), len)
|
//send (0, reinterpret_cast <char const *> (&device_qualifier_descriptor), sizeof (device_qualifier_descriptor), len)
|
||||||
|
//return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
//break
|
//break
|
||||||
return ~0
|
return ~0
|
||||||
// The 6 is an arbitrary number, except that String <6> is instantiated already.
|
// The 6 is an arbitrary number, except that String <6> is instantiated already.
|
||||||
@ -338,16 +353,20 @@ unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
|||||||
switch idx:
|
switch idx:
|
||||||
case 0:
|
case 0:
|
||||||
Iris::debug ("get language descriptor\n")
|
Iris::debug ("get language descriptor\n")
|
||||||
return 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
|
||||||
case 1:
|
case 1:
|
||||||
Iris::debug ("get manufacturer descriptor\n")
|
Iris::debug ("get manufacturer descriptor\n")
|
||||||
return 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
|
||||||
case 2:
|
case 2:
|
||||||
Iris::debug ("get product descriptor\n")
|
Iris::debug ("get product descriptor\n")
|
||||||
return 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
|
||||||
case 3:
|
case 3:
|
||||||
Iris::debug ("get serial descriptor\n")
|
Iris::debug ("get serial descriptor\n")
|
||||||
return 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
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
default:
|
default:
|
||||||
@ -378,15 +397,18 @@ unsigned Udc::handle_setup (Setup *s):
|
|||||||
switch s->request:
|
switch s->request:
|
||||||
case GET_STATUS:
|
case GET_STATUS:
|
||||||
Iris::debug ("get status\n")
|
Iris::debug ("get status\n")
|
||||||
return send (0, "\0\0", 2, s->length)
|
send (0, "\0\0", 2, s->length)
|
||||||
|
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\n")
|
||||||
return send (0, &configuration, 1, s->length)
|
send (0, &configuration, 1, s->length)
|
||||||
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
case GET_INTERFACE:
|
case GET_INTERFACE:
|
||||||
Iris::debug ("get interface\n")
|
Iris::debug ("get interface\n")
|
||||||
return send (0, "\0", 1, s->length)
|
send (0, "\0", 1, s->length)
|
||||||
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
case STANDARD_TO_ENDPOINT:
|
case STANDARD_TO_ENDPOINT:
|
||||||
@ -399,15 +421,13 @@ unsigned Udc::handle_setup (Setup *s):
|
|||||||
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 | UDC_INCSR_SENTSTALL)
|
||||||
if state == CSW:
|
stalling[2] = false
|
||||||
state = SEND_CSW
|
|
||||||
return 0
|
return 0
|
||||||
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 | UDC_OUTCSR_SENTSTALL)
|
||||||
if state == CSW:
|
stalling[1] = false
|
||||||
state = SEND_CSW
|
|
||||||
return 0
|
return 0
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
@ -419,14 +439,14 @@ unsigned Udc::handle_setup (Setup *s):
|
|||||||
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\n")
|
||||||
return send (0, "\0", 1, s->length)
|
send (0, "\0", 1, s->length)
|
||||||
|
return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
case CLASS_TO_INTERFACE:
|
case CLASS_TO_INTERFACE:
|
||||||
switch s->request:
|
switch s->request:
|
||||||
case BULK_ONLY_RESET:
|
case BULK_ONLY_RESET:
|
||||||
Iris::debug ("bulk reset\n")
|
Iris::debug ("bulk reset\n")
|
||||||
state = IDLE
|
|
||||||
return 0
|
return 0
|
||||||
default:
|
default:
|
||||||
return ~0
|
return ~0
|
||||||
@ -441,26 +461,21 @@ void Udc::irq_usb ():
|
|||||||
// and on out endpoint 1.
|
// and on out endpoint 1.
|
||||||
UDC_INTROUTE = 1 << 1
|
UDC_INTROUTE = 1 << 1
|
||||||
UDC_INDEX = 1
|
UDC_INDEX = 1
|
||||||
UDC_OUTMAXP = max_packet_size_bulk
|
|
||||||
// Do this twice to flush a double-buffered fifo completely.
|
// 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_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
|
||||||
UDC_INDEX = 0
|
|
||||||
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
|
||||||
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)
|
csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL)
|
||||||
if csr & UDC_CSR0_SETUPEND:
|
if csr & UDC_CSR0_SETUPEND:
|
||||||
csr |= UDC_CSR0_SVDSETUPEND
|
csr |= UDC_CSR0_SVDSETUPEND
|
||||||
if state == SEND_CSW:
|
|
||||||
send_csw ()
|
|
||||||
state = IDLE_WAIT
|
|
||||||
if !(csr & UDC_CSR0_OUTPKTRDY):
|
if !(csr & UDC_CSR0_OUTPKTRDY):
|
||||||
kdebug ("packet sent 0\n")
|
kdebug ("packet sent 0\n")
|
||||||
return
|
return
|
||||||
@ -476,10 +491,8 @@ void Udc::irq_in0 ():
|
|||||||
csr &= ~(UDC_CSR0_SETUPEND | UDC_CSR0_SENDSTALL | UDC_CSR0_SENTSTALL)
|
csr &= ~(UDC_CSR0_SETUPEND | UDC_CSR0_SENDSTALL | UDC_CSR0_SENTSTALL)
|
||||||
unsigned ret = handle_setup (&packet.s)
|
unsigned ret = handle_setup (&packet.s)
|
||||||
UDC_INDEX = 1
|
UDC_INDEX = 1
|
||||||
UDC_OUTMAXP = max_packet_size_bulk
|
|
||||||
UDC_OUTCSR |= UDC_OUTCSR_CDT
|
UDC_OUTCSR |= UDC_OUTCSR_CDT
|
||||||
UDC_INDEX = 2
|
UDC_INDEX = 2
|
||||||
UDC_INMAXP = max_packet_size_bulk
|
|
||||||
UDC_INCSR |= UDC_INCSR_CDT
|
UDC_INCSR |= UDC_INCSR_CDT
|
||||||
UDC_INDEX = 0
|
UDC_INDEX = 0
|
||||||
if ret == ~0:
|
if ret == ~0:
|
||||||
@ -487,115 +500,64 @@ void Udc::irq_in0 ():
|
|||||||
UDC_CSR0 = csr | UDC_CSR0_SENDSTALL
|
UDC_CSR0 = csr | UDC_CSR0_SENDSTALL
|
||||||
return
|
return
|
||||||
UDC_CSR0 = csr | ret
|
UDC_CSR0 = csr | ret
|
||||||
|
kdebug ("done in0\n")
|
||||||
|
|
||||||
void Udc::send_csw ():
|
void Udc::send_csw ():
|
||||||
UDC_INDEX = 2
|
UDC_INDEX = 2
|
||||||
UDC_FIFO (2) = 0x53425355
|
UDC_FIFO (2) = 0x53425355
|
||||||
UDC_FIFO (2) = cbw.cbw.tag
|
UDC_FIFO (2) = tag
|
||||||
UDC_FIFO (2) = residue
|
UDC_FIFO (2) = residue
|
||||||
UDC_FIFO8 (2) = status
|
UDC_FIFO8 (2) = status
|
||||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
||||||
status = 0
|
status = 0
|
||||||
residue = 0
|
residue = 0
|
||||||
|
while true:
|
||||||
|
Iris::register_interrupt (IRQ_UDC)
|
||||||
|
Iris::wait_for_interrupt (IRQ_UDC)
|
||||||
|
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")
|
||||||
state = IDLE_WAIT
|
|
||||||
|
void Udc::stall (unsigned error):
|
||||||
|
unsigned index = UDC_INDEX
|
||||||
|
if index == 1:
|
||||||
|
UDC_OUTCSR |= UDC_OUTCSR_SENDSTALL
|
||||||
|
else:
|
||||||
|
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
||||||
|
stalling[index] = true
|
||||||
|
kdebug ("stalling\n")
|
||||||
|
while stalling[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 usb & 4 || in & 1:
|
||||||
|
kdebug ("stuff\n")
|
||||||
|
if !handle_interrupt (usb & 4, in & 1):
|
||||||
|
return
|
||||||
|
if in & 4:
|
||||||
|
kdebug ("in interrupt ignored while waiting for stall reset\n")
|
||||||
|
unsigned out = UDC_INTROUT
|
||||||
|
if out & 2:
|
||||||
|
Iris::panic (0, "out interrupt while waiting for stall reset")
|
||||||
|
kdebug ("no stuff\n")
|
||||||
|
UDC_INDEX = index
|
||||||
|
if index == 2:
|
||||||
|
status = error
|
||||||
|
send_csw ()
|
||||||
|
|
||||||
unsigned Udc::big_endian (unsigned src):
|
unsigned Udc::big_endian (unsigned src):
|
||||||
return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
|
return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
|
||||||
|
|
||||||
void Udc::parse_cbw ():
|
|
||||||
UDC_INDEX = 2
|
|
||||||
bool to_host = cbw.cbw.flags & 0x80
|
|
||||||
switch cbw.cbw.data[0]:
|
|
||||||
case CBW::INQUIRY:
|
|
||||||
if !to_host:
|
|
||||||
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
|
||||||
status = 2
|
|
||||||
state = CSW
|
|
||||||
return
|
|
||||||
Iris::debug ("sending inquiry response\n")
|
|
||||||
send_padded (2, "\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick 0 ", 36, cbw.cbw.length)
|
|
||||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
|
||||||
state = CSW
|
|
||||||
return
|
|
||||||
case CBW::TEST_UNIT_READY:
|
|
||||||
if to_host || cbw.cbw.length != 0:
|
|
||||||
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
|
||||||
status = 2
|
|
||||||
state = CSW
|
|
||||||
return
|
|
||||||
Iris::debug ("sending ready response\n")
|
|
||||||
send_csw ()
|
|
||||||
return
|
|
||||||
case CBW::READ_CAPACITY:
|
|
||||||
if !to_host:
|
|
||||||
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
|
||||||
status = 2
|
|
||||||
state = CSW
|
|
||||||
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\n", capacity[0], capacity[1])
|
|
||||||
send_padded (2, (char *)capacity, 8, cbw.cbw.length)
|
|
||||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
|
||||||
state = CSW
|
|
||||||
return
|
|
||||||
case CBW::REQUEST_SENSE:
|
|
||||||
Iris::debug ("sense requested\n")
|
|
||||||
send_padded (2, "\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
|
|
||||||
UDC_INCSR |= UDC_INCSR_INPKTRDY
|
|
||||||
state = CSW
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
Iris::debug ("cbw:")
|
|
||||||
for unsigned i = 0; i < cbw.cbw.size; ++i:
|
|
||||||
kdebug_char (' ')
|
|
||||||
kdebug_num (cbw.cbw.data[i], 2)
|
|
||||||
Iris::debug ("\n")
|
|
||||||
UDC_INCSR |= UDC_INCSR_SENDSTALL
|
|
||||||
residue = cbw.cbw.length
|
|
||||||
status = 1
|
|
||||||
state = CSW
|
|
||||||
return
|
|
||||||
// TODO.
|
|
||||||
|
|
||||||
void Udc::irq_in2 ():
|
|
||||||
UDC_INDEX = 2
|
|
||||||
unsigned csr = UDC_INCSR
|
|
||||||
if csr & UDC_INCSR_SENDSTALL:
|
|
||||||
// When stalling, do nothing else.
|
|
||||||
kdebug ("stalling\n")
|
|
||||||
UDC_INDEX = 0
|
|
||||||
return
|
|
||||||
switch state:
|
|
||||||
case IDLE_WAIT:
|
|
||||||
// data has been received.
|
|
||||||
kdebug ("bulk data was sent\n")
|
|
||||||
state = IDLE
|
|
||||||
break
|
|
||||||
case IDLE:
|
|
||||||
// This should not happen.
|
|
||||||
Iris::debug ("in interrupt while idle\n")
|
|
||||||
break
|
|
||||||
case TX:
|
|
||||||
// TODO: transmit more.
|
|
||||||
kdebug ("bulk transmit\n")
|
|
||||||
break
|
|
||||||
case RX:
|
|
||||||
// This should not be possible.
|
|
||||||
Iris::debug ("in interrupt while receiving\n")
|
|
||||||
UDC_INCSR = csr | UDC_INCSR_SENDSTALL
|
|
||||||
status = 2
|
|
||||||
state = CSW
|
|
||||||
break
|
|
||||||
case CSW:
|
|
||||||
// The host is now ready to receive the csw; send it.
|
|
||||||
kdebug ("bulk send csw\n")
|
|
||||||
send_csw ()
|
|
||||||
break
|
|
||||||
UDC_INDEX = 0
|
|
||||||
|
|
||||||
void Udc::irq_out ():
|
void Udc::irq_out ():
|
||||||
UDC_INDEX = 1
|
UDC_INDEX = 1
|
||||||
unsigned csr = UDC_OUTCSR
|
unsigned csr = UDC_OUTCSR
|
||||||
@ -606,48 +568,83 @@ void Udc::irq_out ():
|
|||||||
return
|
return
|
||||||
if csr & UDC_OUTCSR_SENDSTALL:
|
if csr & UDC_OUTCSR_SENDSTALL:
|
||||||
// When stalling, do nothing else.
|
// When stalling, do nothing else.
|
||||||
UDC_INDEX = 0
|
kdebug ("not responding to out during stall\n")
|
||||||
|
UDC_OUTCSR &= ~UDC_OUTCSR_SENTSTALL
|
||||||
return
|
return
|
||||||
switch state:
|
// expect a new cbw.
|
||||||
case IDLE_WAIT:
|
if size != 31:
|
||||||
Iris::debug ("out interrupt while idle waiting\n")
|
Iris::debug ("count %d != 31\n", size)
|
||||||
break
|
stall (2)
|
||||||
case IDLE:
|
return
|
||||||
// expect a new cbw.
|
union Cbw:
|
||||||
if size != 31:
|
unsigned u[8]
|
||||||
Iris::debug ("count %d != 31\n", UDC_OUTCOUNT)
|
CBW cbw
|
||||||
UDC_OUTCSR = csr | UDC_OUTCSR_SENDSTALL
|
Cbw cbw
|
||||||
status = 2
|
for unsigned i = 0; i < 8; ++i:
|
||||||
state = CSW
|
cbw.u[i] = UDC_FIFO (1)
|
||||||
|
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)
|
||||||
|
stall (2)
|
||||||
|
return
|
||||||
|
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
|
||||||
|
kdebug ("bulk cbw\n")
|
||||||
|
UDC_INDEX = 2
|
||||||
|
bool to_host = cbw.cbw.flags & 0x80
|
||||||
|
switch cbw.cbw.data[0]:
|
||||||
|
case CBW::INQUIRY:
|
||||||
|
if !to_host:
|
||||||
|
stall (2)
|
||||||
break
|
break
|
||||||
for unsigned i = 0; i < 8; ++i:
|
Iris::debug ("sending inquiry response\n")
|
||||||
cbw.u[i] = UDC_FIFO (1)
|
send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick 0 ", 36, cbw.cbw.length)
|
||||||
if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
|
send_csw ()
|
||||||
Iris::debug ("sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
|
break
|
||||||
UDC_OUTCSR = csr | UDC_OUTCSR_SENDSTALL
|
case CBW::TEST_UNIT_READY:
|
||||||
status = 2
|
if to_host || cbw.cbw.length != 0:
|
||||||
state = CSW
|
stall (2)
|
||||||
|
return
|
||||||
|
Iris::debug ("sending ready response\n")
|
||||||
|
send_csw ()
|
||||||
|
break
|
||||||
|
case CBW::READ_CAPACITY:
|
||||||
|
if !to_host:
|
||||||
|
stall (2)
|
||||||
break
|
break
|
||||||
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
|
unsigned capacity[2]
|
||||||
kdebug ("bulk cbw\n")
|
capacity[0] = big_endian ((block.get_size ().value () >> block_bits) - 1)
|
||||||
parse_cbw ()
|
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 ()
|
||||||
break
|
break
|
||||||
case TX:
|
case CBW::REQUEST_SENSE:
|
||||||
// This should be impossible.
|
Iris::debug ("sense requested\n")
|
||||||
Iris::debug ("out interrupt while transmitting\n")
|
send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
|
||||||
UDC_OUTCSR = csr | UDC_OUTCSR_SENDSTALL
|
send_csw ()
|
||||||
break
|
break
|
||||||
case RX:
|
default:
|
||||||
// TODO: Handle the data.
|
Iris::debug ("cbw:")
|
||||||
kdebug ("bulk rx\n")
|
for unsigned i = 0; i < cbw.cbw.size; ++i:
|
||||||
UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
|
kdebug_char (' ')
|
||||||
|
kdebug_num (cbw.cbw.data[i], 2)
|
||||||
|
Iris::debug ("\n")
|
||||||
|
residue = cbw.cbw.length
|
||||||
|
stall (1)
|
||||||
break
|
break
|
||||||
case CSW:
|
// TODO.
|
||||||
// This should be impossible.
|
|
||||||
Iris::debug ("out interrupt while csw-waiting\n")
|
bool Udc::handle_interrupt (bool usb, bool in):
|
||||||
UDC_OUTCSR = csr | UDC_OUTCSR_SENDSTALL
|
if usb:
|
||||||
break
|
Iris::debug ("usb\t")
|
||||||
UDC_INDEX = 0
|
// reset.
|
||||||
|
irq_usb ()
|
||||||
|
return false
|
||||||
|
if in:
|
||||||
|
Iris::debug ("control\t")
|
||||||
|
// control request
|
||||||
|
irq_in0 ()
|
||||||
|
return true
|
||||||
|
|
||||||
void Udc::interrupt ():
|
void Udc::interrupt ():
|
||||||
while true:
|
while true:
|
||||||
@ -658,21 +655,10 @@ void Udc::interrupt ():
|
|||||||
// No more interrupts to handle; this is normal, because we're looping until this happens.
|
// No more interrupts to handle; this is normal, because we're looping until this happens.
|
||||||
Iris::debug ("irq done\n")
|
Iris::debug ("irq done\n")
|
||||||
return
|
return
|
||||||
if usb & 4:
|
|
||||||
Iris::debug ("usb\t")
|
|
||||||
// reset.
|
|
||||||
irq_usb ()
|
|
||||||
if in & 1:
|
|
||||||
Iris::debug ("control\t")
|
|
||||||
// control request
|
|
||||||
irq_in0 ()
|
|
||||||
if in & 4:
|
if in & 4:
|
||||||
Iris::debug ("in\t")
|
Iris::debug ("ignoring data request during idle\n")
|
||||||
// bulk in done
|
handle_interrupt (usb & 4, in & 1)
|
||||||
irq_in2 ()
|
|
||||||
if out & 2:
|
if out & 2:
|
||||||
Iris::debug ("out\t")
|
|
||||||
// bulk out waiting
|
|
||||||
irq_out ()
|
irq_out ()
|
||||||
|
|
||||||
Iris::Num start ():
|
Iris::Num start ():
|
||||||
|
Loading…
Reference in New Issue
Block a user