feat(UsbBus): implement write and read methods and borrow poll method implementation from atmega_usbd
This commit is contained in:
parent
4ca8c4e8cf
commit
e9d661e9e3
168
src/lib.rs
168
src/lib.rs
|
@ -1,7 +1,173 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
mod types;
|
mod types;
|
||||||
|
fn poll(&self) -> PollResult {
|
||||||
|
free(|cs| {
|
||||||
|
let usb = self.usb.borrow(cs);
|
||||||
|
|
||||||
use types::*;
|
let (usbint, udint, udien) = (usb.usbint.read(), usb.udint.read(), usb.udien.read());
|
||||||
|
if usbint.vbusti().bit_is_set() {
|
||||||
|
usb.usbint.write(|w| w.vbusti().clear_bit());
|
||||||
|
if usb.usbsta.read().vbus().bit_is_set() {
|
||||||
|
return PollResult::Resume;
|
||||||
|
} else {
|
||||||
|
return PollResult::Suspend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if udint.suspi().bit_is_set() && udien.suspe().bit_is_set() {
|
||||||
|
return PollResult::Suspend;
|
||||||
|
}
|
||||||
|
if udint.wakeupi().bit_is_set() && udien.wakeupe().bit_is_set() {
|
||||||
|
return PollResult::Resume;
|
||||||
|
}
|
||||||
|
if udint.eorsti().bit_is_set() {
|
||||||
|
return PollResult::Reset;
|
||||||
|
}
|
||||||
|
if udint.sofi().bit_is_set() {
|
||||||
|
usb.udint.write(|w| w.sofi().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can only query endpoints while clock is running
|
||||||
|
// (e.g. not in suspend state)
|
||||||
|
if usb.usbcon.read().frzclk().bit_is_clear() {
|
||||||
|
let (mut ep_out, mut ep_setup, mut ep_in_complete) = (0u8, 0u8, 0u8);
|
||||||
|
|
||||||
|
for (index, _ep) in self
|
||||||
|
.ep_table
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_i, e)| e.is_allocated)
|
||||||
|
{
|
||||||
|
if self.select_endpoint(cs, index).is_err() {
|
||||||
|
// Endpoint selection has stopped working...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ueintx = usb.ueintx.read();
|
||||||
|
if ueintx.rxouti().bit_is_set() {
|
||||||
|
ep_out |= 1 << index;
|
||||||
|
}
|
||||||
|
if ueintx.rxstpi().bit_is_set() {
|
||||||
|
ep_setup |= 1 << index;
|
||||||
|
}
|
||||||
|
if ueintx.txini().bit_is_set() {
|
||||||
|
ep_in_complete |= 1 << index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ep_out | ep_setup | ep_in_complete != 0 {
|
||||||
|
return PollResult::Data {
|
||||||
|
ep_out: ep_out as u16,
|
||||||
|
ep_in_complete: ep_in_complete as u16,
|
||||||
|
ep_setup: ep_setup as u16,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PollResult::None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self, ep_addr: EndpointAddress, buf: &mut [u8]) -> UsbResult<usize> {
|
||||||
|
free(|cs| {
|
||||||
|
let usb = self.usb.borrow(cs);
|
||||||
|
|
||||||
|
match self.select_endpoint(cs, ep_addr.index()) {
|
||||||
|
Ok(()) => {
|
||||||
|
let target_endpoint = self.ep_table[ep_addr.index()];
|
||||||
|
|
||||||
|
let ueintx = usb.ueintx.read();
|
||||||
|
|
||||||
|
if ueintx.rxouti().bit_is_clear() {
|
||||||
|
return Err(UsbError::WouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_endpoint.ep_type == 0 {
|
||||||
|
let bytes_count_to_read: usize = (usb.uebchx.read().bits() as usize) << 8
|
||||||
|
| (usb.uebclx.read().bits() as usize);
|
||||||
|
|
||||||
|
if bytes_count_to_read > buf.len() {
|
||||||
|
return Err(UsbError::BufferOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
for slot in &mut buf[..bytes_count_to_read] {
|
||||||
|
*slot = usb.uedatx.read().bits();
|
||||||
|
}
|
||||||
|
|
||||||
|
usb.ueintx
|
||||||
|
.write(|w| w.rxouti().clear_bit().rxstpi().clear_bit());
|
||||||
|
|
||||||
|
Ok(bytes_count_to_read)
|
||||||
|
} else {
|
||||||
|
usb.ueintx.write(|w| w.rxouti().clear_bit());
|
||||||
|
|
||||||
|
let mut bytes_read = 0;
|
||||||
|
for slot in buf {
|
||||||
|
if usb.ueintx.read().rwal().bit_is_clear() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*slot = usb.uedatx.read().bits();
|
||||||
|
bytes_read += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if usb.ueintx.read().rwal().bit_is_set() {
|
||||||
|
return Err(UsbError::BufferOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
usb.ueintx.write(|w| w.fifocon().clear_bit());
|
||||||
|
Ok(bytes_read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn write(&self, ep_addr: EndpointAddress, buf: &[u8]) -> UsbResult<usize> {
|
||||||
|
free(|cs| {
|
||||||
|
let usb = self.usb.borrow(cs);
|
||||||
|
|
||||||
|
match self.select_endpoint(cs, ep_addr.index()) {
|
||||||
|
Ok(()) => {
|
||||||
|
let target_endpoint = self.ep_table[ep_addr.index()];
|
||||||
|
|
||||||
|
let ueintx = usb.ueintx.read();
|
||||||
|
|
||||||
|
if ueintx.rxouti().bit_is_clear() {
|
||||||
|
return Err(UsbError::WouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_endpoint.ep_type == 0 {
|
||||||
|
let bytes_count_to_read: usize = (usb.uebchx.read().bits() as usize) << 8
|
||||||
|
| (usb.uebclx.read().bits() as usize);
|
||||||
|
|
||||||
|
if bytes_count_to_read > buf.len() {
|
||||||
|
return Err(UsbError::BufferOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.iter()
|
||||||
|
.for_each(|&byte| usb.uedatx.write(|w| w.bits(byte)));
|
||||||
|
|
||||||
|
usb.ueintx
|
||||||
|
.write(|w| w.rxouti().clear_bit().rxstpi().clear_bit());
|
||||||
|
|
||||||
|
Ok(bytes_count_to_read)
|
||||||
|
} else {
|
||||||
|
usb.ueintx
|
||||||
|
.write(|w| w.txini().clear_bit().rxouti().clear_bit());
|
||||||
|
|
||||||
|
for &byte in buf {
|
||||||
|
if usb.ueintx.read().rwal().bit_is_set() {
|
||||||
|
return Err(UsbError::BufferOverflow);
|
||||||
|
} else {
|
||||||
|
usb.uedatx.write(|w| w.bits(byte));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usb.ueintx
|
||||||
|
.write(|w| w.fifocon().clear_bit().rxouti().clear_bit());
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue