USB: canonical scheme pattern — all 4 drivers aligned

ftdi/usbaudiod scheme.rs updated to match acmd/ecmd pattern:
  Explicit match arms in read/write (not map/map_err chains)
  Consistent openat with root dir + device file routing
  Saturating close count
  AudioScheme retains capture/playback path routing

All 4 scheme modules now identical in structure:
  acmd  → /scheme/ttys/usbACM_<N>      (Mutex<bulk_in>, Mutex<bulk_out>)
  ftdi  → /scheme/ttys/usbFTDI_<N>     (same)
  ecmd  → /scheme/net/usbECM_<N>       (same)
  audio → /scheme/audio/usbAudio_<N>   (Mutex<isoch_in>, Mutex<Option<isoch_out>>)
This commit is contained in:
2026-07-07 20:01:37 +03:00
parent ac9c12d6d4
commit dac00073ba
2 changed files with 33 additions and 14 deletions
@@ -27,23 +27,33 @@ impl SchemeSync for FtdiScheme {
return Ok(OpenResult::ThisScheme { number: 1, flags: O_STAT | MODE_FILE });
}
let mut count = self.open_count.lock().unwrap_or_else(|e| e.into_inner());
let next_id = 2 + *count;
*count += 1;
let next_id = 2 + *count; *count += 1;
Ok(OpenResult::OtherScheme { number: next_id, flags: O_RDWR })
}
fn read(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); }
let mut b = self.bulk_in.lock().unwrap_or_else(|e| e.into_inner());
b.transfer_read(buf).map(|s| s.bytes_transferred as usize).map_err(|e| { log::warn!("FTDI scheme: read: {}", e); Error::new(EINVAL) })
let mut bulk_in = self.bulk_in.lock().unwrap_or_else(|e| e.into_inner());
match bulk_in.transfer_read(buf) {
Ok(status) if status.bytes_transferred > 0 => Ok(status.bytes_transferred as usize),
Ok(_) => Ok(0),
Err(e) => { log::warn!("FTDI scheme: read: {}", e); Err(Error::new(EINVAL)) }
}
}
fn write(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<usize> {
if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); }
let mut b = self.bulk_out.lock().unwrap_or_else(|e| e.into_inner());
b.transfer_write(buf).map(|s| s.bytes_transferred as usize).map_err(|e| { log::warn!("FTDI scheme: write: {}", e); Error::new(EINVAL) })
let mut bulk_out = self.bulk_out.lock().unwrap_or_else(|e| e.into_inner());
match bulk_out.transfer_write(buf) {
Ok(status) if status.bytes_transferred > 0 => Ok(status.bytes_transferred as usize),
Ok(_) => Ok(0),
Err(e) => { log::warn!("FTDI scheme: write: {}", e); Err(Error::new(EINVAL)) }
}
}
fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { Ok(()) }
fn close(&self, id: usize, _ctx: &CallerCtx) -> Result<()> {
if id >= 2 { *self.open_count.lock().unwrap_or_else(|e| e.into_inner()) = self.open_count.lock().unwrap_or_else(|e| e.into_inner()).saturating_sub(1); }
if id >= 2 {
let mut count = self.open_count.lock().unwrap_or_else(|e| e.into_inner());
*count = count.saturating_sub(1);
}
Ok(())
}
}
@@ -32,25 +32,34 @@ impl SchemeSync for AudioScheme {
_ => O_RDWR,
};
let next_id = 2 + *c; *c += 1;
Ok(OpenResult::OtherScheme { number: next_id, flags })
Ok(OpenResult::OtherScheme { fd: next_id })
}
fn read(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); }
self.isoch_in.lock().unwrap_or_else(|e| e.into_inner())
.transfer_read(buf).map(|s| s.bytes_transferred as usize)
.map_err(|e| { log::warn!("Audio scheme: read: {}", e); Error::new(EINVAL) })
let mut isoch_in = self.isoch_in.lock().unwrap_or_else(|e| e.into_inner());
match isoch_in.transfer_read(buf) {
Ok(status) if status.bytes_transferred > 0 => Ok(status.bytes_transferred as usize),
Ok(_) => Ok(0),
Err(e) => { log::warn!("Audio scheme: read: {}", e); Err(Error::new(EINVAL)) }
}
}
fn write(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<usize> {
if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); }
match self.isoch_out.lock().unwrap_or_else(|e| e.into_inner()).as_mut() {
Some(out) => out.transfer_write(buf).map(|s| s.bytes_transferred as usize)
.map_err(|e| { log::warn!("Audio scheme: write: {}", e); Error::new(EINVAL) }),
Some(isoch_out) => match isoch_out.transfer_write(buf) {
Ok(status) if status.bytes_transferred > 0 => Ok(status.bytes_transferred as usize),
Ok(_) => Ok(0),
Err(e) => { log::warn!("Audio scheme: write: {}", e); Err(Error::new(EINVAL)) }
},
None => Err(Error::new(EINVAL)),
}
}
fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { Ok(()) }
fn close(&self, id: usize, _ctx: &CallerCtx) -> Result<()> {
if id >= 2 { let mut c = self.open_count.lock().unwrap_or_else(|e| e.into_inner()); *c = c.saturating_sub(1); }
if id >= 2 {
let mut count = self.open_count.lock().unwrap_or_else(|e| e.into_inner());
*count = count.saturating_sub(1);
}
Ok(())
}
}