use super::constants::*;
use crate::endpoint::Endpoint;
use crate::usb_transfer::{BufferSlice, BulkTransfer, ControlTransfer};
use std::fmt;
use std::io;
use std::io::{Error, ErrorKind};
#[derive(Debug)]
#[repr(C)]
pub struct UsbFsUrb {
typ: u8,
pub endpoint: u8,
pub status: i32,
flags: u32,
pub buffer: *mut u8,
pub buffer_length: i32,
pub actual_length: i32,
start_frame: i32,
stream_id: i32,
error_count: i32,
signr: u32,
pub(crate) usercontext: *mut u8,
}
impl UsbFsUrb {
pub fn new(typ: u8, ep: Endpoint, ptr: *mut u8, length: usize, user: *mut u8) -> Self {
UsbFsUrb {
typ,
endpoint: ep.into(),
status: 0,
flags: 0,
buffer: ptr,
buffer_length: length as i32,
actual_length: 0,
start_frame: 0,
stream_id: 0,
error_count: 0,
signr: 0,
usercontext: user,
}
}
}
impl fmt::Display for UsbFsUrb {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "type: 0x{:02X}", self.typ)?;
writeln!(f, "endpoint: 0x{:02X}", self.endpoint)?;
writeln!(f, "status: 0x{0:08X} == {0}", self.status)?;
writeln!(f, "flags: 0x{:08X}", self.flags)?;
writeln!(f, "buffer: {:X?}", self.buffer)?;
writeln!(f, "buffer_length: {}", self.buffer_length)?;
writeln!(f, "actual_length: {}", self.actual_length)?;
writeln!(f, "start_frame: {}", self.start_frame)?;
writeln!(f, "stream_id: {}", self.stream_id)?;
writeln!(f, "signr: {}", self.signr)?;
writeln!(f, "usercontext: {:X?}", self.usercontext)
}
}
impl From<BulkTransfer> for UsbFsUrb {
fn from(bulk: BulkTransfer) -> Self {
let bulk = Box::new(bulk);
UsbFsUrb::new(
USBFS_URB_TYPE_BULK,
bulk.endpoint,
bulk.buffer,
bulk.buffer_length,
Box::into_raw(bulk) as *mut u8,
)
}
}
impl From<ControlTransfer> for UsbFsUrb {
fn from(ctrl: ControlTransfer) -> Self {
let ctrl = Box::new(ctrl);
UsbFsUrb::new(
USBFS_URB_TYPE_CONTROL,
Endpoint::new(0),
ctrl.buffer,
ctrl.buffer_length as usize,
Box::into_raw(ctrl) as *mut u8,
)
}
}
pub(crate) fn bulk_from_urb(urb: UsbFsUrb) -> io::Result<BulkTransfer> {
let ep = Endpoint::new(urb.endpoint);
if !ep.is_bulk() {
return Err(Error::new(
ErrorKind::InvalidInput,
"Invalid URB Not Bulk warning possibly leaking userdata",
));
}
if urb.usercontext.is_null() {
return Err(Error::new(
ErrorKind::InvalidInput,
"Invalid URB usercontext is NULL?",
));
}
let mut bulk = *unsafe { Box::from_raw(urb.usercontext as *mut BulkTransfer) };
if u8::from(bulk.endpoint) != urb.endpoint {
return Err(Error::new(
ErrorKind::InvalidInput,
"Endpoint not match corrupt URB?",
));
}
assert!(urb.buffer_length as usize == bulk.buffer_length);
bulk.actual_length = urb.actual_length as usize;
assert!(bulk.actual_length <= bulk.buffer_length);
Ok(bulk)
}
pub(crate) fn control_from_urb(urb: UsbFsUrb) -> io::Result<ControlTransfer> {
let ep = Endpoint::new(urb.endpoint);
if !ep.is_control() {
return Err(Error::new(
ErrorKind::InvalidInput,
"Invalid URB Not not control contextdata is leaked",
));
}
if urb.usercontext.is_null() {
return Err(Error::new(
ErrorKind::InvalidInput,
"Invalid URB usercontext is NULL?",
));
}
let mut control = *unsafe { Box::from_raw(urb.usercontext as *mut ControlTransfer) };
assert!(urb.buffer_length as u16 == control.buffer_length);
control.actual_length = urb.actual_length as u16;
assert!(control.actual_length <= control.buffer_length);
Ok(control)
}
impl BufferSlice for BulkTransfer {
fn buffer_from_raw<'a>(&self) -> &'a [u8] {
if (self.endpoint.is_bulk_in() && self.actual_length == 0)
|| (self.endpoint.is_bulk_out() && self.buffer_length == 0)
{
return &[];
}
assert!(self.actual_length <= self.buffer_length);
assert!(self.buffer_length <= self.buffer_capacity);
if self.endpoint.is_bulk_in() {
unsafe { std::slice::from_raw_parts(self.buffer, self.actual_length as usize) }
} else {
unsafe { std::slice::from_raw_parts(self.buffer, self.buffer_length as usize) }
}
}
}
impl BufferSlice for ControlTransfer {
fn buffer_from_raw<'a>(&self) -> &'a [u8] {
if self.actual_length == 0 {
return &[];
}
assert!(self.actual_length <= self.buffer_length - 8);
unsafe { std::slice::from_raw_parts(self.buffer.offset(8), self.actual_length as usize) }
}
}