hardware 0.0.9

A no_std bare-metal hardware abstraction layer — all port I/O, memory and swap allocations are guarded at runtime. Do not consider this dependency stable before x.1.x
Documentation
#[derive(Copy, Clone, PartialEq)]
pub enum StreamDirection {
    Output,
    Input,
}

#[derive(Copy, Clone)]
pub struct StreamDescriptor {
    pub index: u8,
    pub direction: StreamDirection,
    pub base_reg: usize,
    pub buffer_addr: u64,
    pub buffer_len: u32,
    pub format: u32,
    pub running: bool,
}

pub const SD_CTL: usize = 0x00;
pub const SD_STS: usize = 0x03;
pub const SD_LPIB: usize = 0x04;
pub const SD_CBL: usize = 0x08;
pub const SD_LVI: usize = 0x0C;
pub const SD_FMT: usize = 0x12;
pub const SD_BDPL: usize = 0x18;
pub const SD_BDPU: usize = 0x1C;

pub fn stream_offset(index: u8) -> usize {
    0x80 + (index as usize) * 0x20
}

pub fn start(base: usize, sd: &mut StreamDescriptor) {
    let off = stream_offset(sd.index);
    let ctl = super::hw::read_reg(base, off + SD_CTL);
    super::hw::write_reg(base, off + SD_CTL, ctl | 0x02);
    sd.running = true;
}

pub fn stop(base: usize, sd: &mut StreamDescriptor) {
    let off = stream_offset(sd.index);
    let ctl = super::hw::read_reg(base, off + SD_CTL);
    super::hw::write_reg(base, off + SD_CTL, ctl & !0x02);
    sd.running = false;
}

pub fn reset(base: usize, sd: &mut StreamDescriptor) {
    let off = stream_offset(sd.index);
    super::hw::write_reg(base, off + SD_CTL, 0x01);
    let mut timeout = 1000u32;
    while (super::hw::read_reg(base, off + SD_CTL) & 0x01) == 0 && timeout > 0 {
        timeout -= 1;
    }
    super::hw::write_reg(base, off + SD_CTL, 0x00);
    timeout = 1000;
    while (super::hw::read_reg(base, off + SD_CTL) & 0x01) != 0 && timeout > 0 {
        timeout -= 1;
    }
    sd.running = false;
}

pub fn position(base: usize, sd: &StreamDescriptor) -> u32 {
    super::hw::read_reg(base, stream_offset(sd.index) + SD_LPIB)
}

pub fn set_format(base: usize, sd: &mut StreamDescriptor, fmt: u32) {
    let off = stream_offset(sd.index);
    super::hw::write_reg(base, off + SD_FMT, fmt);
    sd.format = fmt;
}

pub fn set_buffer(base: usize, sd: &mut StreamDescriptor, addr: u64, len: u32) {
    let off = stream_offset(sd.index);
    super::hw::write_reg(base, off + SD_BDPL, addr as u32);
    super::hw::write_reg(base, off + SD_BDPU, (addr >> 32) as u32);
    super::hw::write_reg(base, off + SD_CBL, len);
    sd.buffer_addr = addr;
    sd.buffer_len = len;
}