Files
RedBear-OS/recipes/drivers/graphics/ihdgd/src/device/aux.rs
T
vasilito b9874d0941 feat: USB storage read/write proof + full Red Bear OS tree sync
Add redbear-usb-storage-check in-guest binary that validates USB mass
storage read and write I/O: discovers /scheme/disk/ devices, writes a
test pattern to sector 2048, reads it back, verifies match, restores
original content. Updates test-usb-storage-qemu.sh with write-proof
verification step.

Includes all accumulated Red Bear OS work: kernel patches, relibc
patches, driver infrastructure, DRM/GPU, KDE recipes, firmware,
validation tooling, build system hardening, and documentation.
2026-05-03 23:03:24 +01:00

170 lines
5.5 KiB
Rust

use common::{io::Io, timeout::Timeout};
use embedded_hal::blocking::i2c::{self, Operation, SevenBitAddress, Transactional};
use super::ddi::*;
pub struct Aux<'a> {
ddi: &'a mut Ddi,
}
impl<'a> Aux<'a> {
pub fn new(ddi: &'a mut Ddi) -> Self {
Self { ddi }
}
}
impl<'a> Transactional for Aux<'a> {
type Error = ();
fn exec(&mut self, addr7: SevenBitAddress, full_ops: &mut [Operation<'_>]) -> Result<(), ()> {
// Break ops into 16-byte chunks that will fit into aux data
let mut ops = Vec::new();
for op in full_ops.iter_mut() {
match op {
Operation::Read(buf) => {
for chunk in buf.chunks_mut(16) {
ops.push(Operation::Read(chunk));
}
}
Operation::Write(buf) => {
for chunk in buf.chunks(16) {
ops.push(Operation::Write(chunk));
}
}
}
}
let ops_len = ops.len();
for (i, op) in ops.iter_mut().enumerate() {
// Write header and data
let mut header = 0;
match op {
Operation::Read(_) => {
header |= 1 << 4;
}
Operation::Write(_) => (),
}
if (i + 1) < ops_len {
// Middle of transaction
header |= 1 << 6;
}
let mut aux_datas = [0u8; 20];
let mut aux_data_i = 0;
aux_datas[aux_data_i] = header;
aux_data_i += 1;
//TODO: what is this byte?
aux_datas[aux_data_i] = 0;
aux_data_i += 1;
aux_datas[aux_data_i] = addr7;
aux_data_i += 1;
match op {
Operation::Read(buf) => {
if !buf.is_empty() {
aux_datas[aux_data_i] = (buf.len() - 1) as u8;
aux_data_i += 1;
}
}
Operation::Write(buf) => {
if !buf.is_empty() {
aux_datas[aux_data_i] = (buf.len() - 1) as u8;
aux_data_i += 1;
for b in buf.iter() {
aux_datas[aux_data_i] = *b;
aux_data_i += 1;
}
}
}
}
// Write data to registers (big endian, dword access only)
for (i, chunk) in aux_datas.chunks(4).enumerate() {
let mut bytes = [0; 4];
bytes[..chunk.len()].copy_from_slice(&chunk);
self.ddi.aux_datas[i].write(u32::from_be_bytes(bytes));
}
let mut v = self.ddi.aux_ctl.read();
// Set length
v &= !DDI_AUX_CTL_SIZE_MASK;
v |= (aux_data_i as u32) << DDI_AUX_CTL_SIZE_SHIFT;
// Set timeout
v &= !DDI_AUX_CTL_TIMEOUT_MASK;
v |= DDI_AUX_CTL_TIMEOUT_4000US;
// Set I/O select to legacy (cleared)
//TODO: TBT support?
v &= !DDI_AUX_CTL_IO_SELECT;
// Start transaction
v |= DDI_AUX_CTL_BUSY;
self.ddi.aux_ctl.write(v);
// Wait while busy
let timeout = Timeout::from_secs(1);
while self.ddi.aux_ctl.readf(DDI_AUX_CTL_BUSY) {
timeout.run().map_err(|()| {
log::debug!(
"AUX I2C transaction wait timeout 0x{:08X}",
self.ddi.aux_ctl.read()
);
()
})?;
}
// Read result
v = self.ddi.aux_ctl.read();
if (v & DDI_AUX_CTL_TIMEOUT_ERROR) != 0 {
log::debug!("AUX I2C transaction timeout error");
return Err(());
}
if (v & DDI_AUX_CTL_RECEIVE_ERROR) != 0 {
log::debug!("AUX I2C transaction receive error");
return Err(());
}
if (v & DDI_AUX_CTL_DONE) == 0 {
log::debug!("AUX I2C transaction done not set");
return Err(());
}
// Read data from registers (big endian, dword access only)
for (i, chunk) in aux_datas.chunks_mut(4).enumerate() {
let bytes = self.ddi.aux_datas[i].read().to_be_bytes();
chunk.copy_from_slice(&bytes[..chunk.len()]);
}
aux_data_i = 0;
let response = aux_datas[aux_data_i];
if response != 0 {
log::debug!("AUX I2C unexpected response {:02X}", response);
return Err(());
}
aux_data_i += 1;
match op {
Operation::Read(buf) => {
if !buf.is_empty() {
for b in buf.iter_mut() {
*b = aux_datas[aux_data_i];
aux_data_i += 1;
}
}
}
Operation::Write(_) => (),
}
}
Ok(())
}
}
impl<'a> i2c::WriteRead for Aux<'a> {
type Error = ();
fn write_read(
&mut self,
addr7: SevenBitAddress,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), ()> {
self.exec(
addr7,
&mut [Operation::Write(bytes), Operation::Read(buffer)],
)
}
}