musb 0.3.0

musb(Mentor USB) regs and `embassy-usb-driver`, `usb-device` impl
Documentation
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, AtomicU16, Ordering};
use core::task::Poll;

use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver as driver;
use embassy_usb_driver::{
    Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
};

use crate::*;
use crate::info::ENDPOINTS;

mod endpoint;
pub use endpoint::Endpoint;

#[path = "driver.rs"]
mod usb_driver;
pub use usb_driver::MusbDriver;

mod bus;
pub use bus::Bus;

mod control_pipe;
pub use control_pipe::ControlPipe;

const NEW_AW: AtomicWaker = AtomicWaker::new();

static BUS_WAKER: AtomicWaker = NEW_AW;

static EP_TX_WAKERS: [AtomicWaker; ENDPOINTS.len()] = [NEW_AW; ENDPOINTS.len()];
static EP_RX_WAKERS: [AtomicWaker; ENDPOINTS.len()] = [NEW_AW; ENDPOINTS.len()];

static IRQ_RESET: AtomicBool = AtomicBool::new(false);
static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false);
static IRQ_RESUME: AtomicBool = AtomicBool::new(false);
static EP_TX_ENABLED: AtomicU16 = AtomicU16::new(0);
static EP_RX_ENABLED: AtomicU16 = AtomicU16::new(0);

#[inline(always)]
pub unsafe fn on_interrupt<T: MusbInstance>() {
    let regs = T::regs();
    let intrusb = regs.intrusb().read();
    let intrtx = regs.intrtx().read();
    let intrrx = regs.intrrx().read();
    trace!("musb/on_interrupt: intrusb: {:b}, intrtx: {:b}, intrrx: {:b}", intrusb.0, intrtx.0, intrrx.0);

    if intrusb.reset() {
        IRQ_RESET.store(true, Ordering::SeqCst);
        BUS_WAKER.wake();
    }
    if intrusb.suspend() {
        IRQ_SUSPEND.store(true, Ordering::SeqCst);
        BUS_WAKER.wake();
    }
    if intrusb.resume() {
        IRQ_RESUME.store(true, Ordering::SeqCst);
        BUS_WAKER.wake();
    }
    
    if intrtx.ep_tx(0) {
        EP_TX_WAKERS[0].wake();
        EP_RX_WAKERS[0].wake();
    }

    for index in 1..ENDPOINTS.len() {
        if intrtx.ep_tx(index) {
            EP_TX_WAKERS[index].wake();
        }
        if intrrx.ep_rx(index) {
            EP_RX_WAKERS[index].wake();
        }

        // TODO: move to another location
        // T::regs().index().write(|w| w.set_index(index as _));
        // if T::regs().txcsrl().read().under_run(){
        //     T::regs().txcsrl().modify(|w| w.set_under_run(false));
        //     warn!("Underrun: ep {}", index);
        // }
    }
}

pub trait Dir {
    fn dir() -> Direction;
}

/// Marker type for the "IN" direction.
pub enum In {}
impl Dir for In {
    fn dir() -> Direction {
        Direction::In
    }
}

/// Marker type for the "OUT" direction.
pub enum Out {}
impl Dir for Out {
    fn dir() -> Direction {
        Direction::Out
    }
}