use crate::{
buffer::Buffer,
qh::Qh,
ral,
ral::endpoint_control,
td::{Status, Td},
};
use usb_device::{
endpoint::{EndpointAddress, EndpointType},
UsbDirection, UsbError,
};
pub struct Endpoint {
address: EndpointAddress,
qh: &'static mut Qh,
td: &'static mut Td,
buffer: Buffer,
kind: EndpointType,
}
impl Endpoint {
pub fn new(
address: EndpointAddress,
qh: &'static mut Qh,
td: &'static mut Td,
buffer: Buffer,
kind: EndpointType,
) -> Self {
let max_packet_size = buffer.len();
qh.set_zero_length_termination(false);
qh.set_max_packet_len(max_packet_size);
qh.set_interrupt_on_setup(
EndpointType::Control == kind && address.direction() == UsbDirection::Out,
);
td.set_terminate();
td.clear_status();
Endpoint {
address,
qh,
td,
buffer,
kind,
}
}
pub fn enable_zlt(&mut self) {
self.qh.set_zero_length_termination(true);
}
pub fn is_primed(&self, usb: &ral::usb::Instance) -> bool {
(match self.address.direction() {
UsbDirection::In => ral::read_reg!(ral::usb, usb, ENDPTSTAT, ETBR),
UsbDirection::Out => ral::read_reg!(ral::usb, usb, ENDPTSTAT, ERBR),
} & (1 << self.address.index()))
!= 0
}
pub fn check_errors(&self) -> Result<(), UsbError> {
let status = self.td.status();
if status.contains(Status::TRANSACTION_ERROR)
| status.contains(Status::DATA_BUFFER_ERROR)
| status.contains(Status::HALTED)
{
Err(UsbError::InvalidState)
} else {
Ok(())
}
}
pub fn initialize(&mut self, usb: &ral::usb::Instance) {
if self.address.index() != 0 {
let endptctrl = endpoint_control::register(usb, self.address.index());
match self.address.direction() {
UsbDirection::In => {
ral::modify_reg!(endpoint_control, &endptctrl, ENDPTCTRL, TXE: 0, TXT: EndpointType::Bulk as u32)
}
UsbDirection::Out => {
ral::modify_reg!(endpoint_control, &endptctrl, ENDPTCTRL, RXE: 0, RXT: EndpointType::Bulk as u32)
}
}
}
}
pub fn address(&self) -> EndpointAddress {
self.address
}
pub fn max_packet_len(&self) -> usize {
self.qh.max_packet_len()
}
pub fn has_setup(&self, usb: &ral::usb::Instance) -> bool {
ral::read_reg!(ral::usb, usb, ENDPTSETUPSTAT) & (1 << self.address.index()) != 0
}
pub fn read_setup(&mut self, usb: &ral::usb::Instance) -> u64 {
ral::write_reg!(ral::usb, usb, ENDPTSETUPSTAT, 1 << self.address.index());
loop {
ral::modify_reg!(ral::usb, usb, USBCMD, SUTW: 1);
let setup = self.qh.setup();
if ral::read_reg!(ral::usb, usb, USBCMD, SUTW == 1) {
ral::modify_reg!(ral::usb, usb, USBCMD, SUTW: 0);
return setup;
}
}
}
pub fn read(&mut self, buffer: &mut [u8]) -> usize {
let size = self
.qh
.max_packet_len()
.min(buffer.len())
.min(self.td.bytes_transferred());
self.buffer.volatile_read(&mut buffer[..size])
}
pub fn write(&mut self, buffer: &[u8]) -> usize {
let size = self.qh.max_packet_len().min(buffer.len());
let written = self.buffer.volatile_write(&buffer[..size]);
self.buffer.clean_invalidate_dcache(size);
written
}
pub fn clear_complete(&mut self, usb: &ral::usb::Instance) {
match self.address.direction() {
UsbDirection::In => {
ral::write_reg!(ral::usb, usb, ENDPTCOMPLETE, ETCE: 1 << self.address.index())
}
UsbDirection::Out => {
ral::write_reg!(ral::usb, usb, ENDPTCOMPLETE, ERCE: 1 << self.address.index())
}
}
}
pub fn schedule_transfer(&mut self, usb: &ral::usb::Instance, size: usize) {
self.td.set_terminate();
self.td.set_buffer(self.buffer.as_ptr_mut(), size);
self.td.set_interrupt_on_complete(true);
self.td.set_active();
self.td.clean_invalidate_dcache();
self.qh.overlay_mut().set_next(self.td);
self.qh.overlay_mut().clear_status();
self.qh.clean_invalidate_dcache();
match self.address.direction() {
UsbDirection::In => {
ral::write_reg!(ral::usb, usb, ENDPTPRIME, PETB: 1 << self.address.index())
}
UsbDirection::Out => {
ral::write_reg!(ral::usb, usb, ENDPTPRIME, PERB: 1 << self.address.index())
}
}
while ral::read_reg!(ral::usb, usb, ENDPTPRIME) != 0 {}
}
pub fn set_stalled(&mut self, usb: &ral::usb::Instance, stall: bool) {
let endptctrl = endpoint_control::register(usb, self.address.index());
match self.address.direction() {
UsbDirection::In => {
ral::modify_reg!(endpoint_control, &endptctrl, ENDPTCTRL, TXS: stall as u32)
}
UsbDirection::Out => {
ral::modify_reg!(endpoint_control, &endptctrl, ENDPTCTRL, RXS: stall as u32)
}
}
}
pub fn is_stalled(&self, usb: &ral::usb::Instance) -> bool {
let endptctrl = endpoint_control::register(usb, self.address.index());
match self.address.direction() {
UsbDirection::In => ral::read_reg!(endpoint_control, &endptctrl, ENDPTCTRL, TXS == 1),
UsbDirection::Out => ral::read_reg!(endpoint_control, &endptctrl, ENDPTCTRL, RXS == 1),
}
}
pub fn enable(&mut self, usb: &ral::usb::Instance) {
if self.address.index() != 0 {
let endptctrl = endpoint_control::register(usb, self.address.index());
match self.address.direction() {
UsbDirection::In => {
ral::modify_reg!(endpoint_control, &endptctrl, ENDPTCTRL, TXE: 1, TXR: 1, TXT: self.kind as u32)
}
UsbDirection::Out => {
ral::modify_reg!(endpoint_control, &endptctrl, ENDPTCTRL, RXE: 1, RXR: 1, RXT: self.kind as u32)
}
}
}
}
pub fn is_enabled(&self, usb: &ral::usb::Instance) -> bool {
if self.address.index() == 0 {
return true;
}
let endptctrl = endpoint_control::register(usb, self.address.index());
match self.address.direction() {
UsbDirection::In => ral::read_reg!(endpoint_control, &endptctrl, ENDPTCTRL, TXE == 1),
UsbDirection::Out => ral::read_reg!(endpoint_control, &endptctrl, ENDPTCTRL, RXE == 1),
}
}
pub fn clear_nack(&mut self, usb: &ral::usb::Instance) {
match self.address.direction() {
UsbDirection::In => {
ral::write_reg!(ral::usb, usb, ENDPTNAK, EPTN: 1 << self.address.index())
}
UsbDirection::Out => {
ral::write_reg!(ral::usb, usb, ENDPTNAK, EPRN: 1 << self.address.index())
}
}
}
}