Skip to main content

android_usb_serial/
transport.rs

1//! USB transport abstraction (nusb or fake).
2//!
3//! Drivers talk only through [`Transport`]. Production code uses
4//! [`crate::NusbTransport`]; tests use [`crate::FakeTransport`] behind `fake-transport`.
5
6use crate::error::{ReadOutcome, Result};
7use std::sync::Arc;
8
9/// USB request direction IN bit.
10pub const USB_DIR_IN: u8 = 0x80;
11/// USB request direction OUT.
12pub const USB_DIR_OUT: u8 = 0x00;
13/// bmRequestType type = class.
14pub const USB_TYPE_CLASS: u8 = 0x20;
15/// bmRequestType recipient = interface.
16pub const USB_RECIP_INTERFACE: u8 = 0x01;
17/// bmRequestType recipient = device.
18pub const USB_RECIP_DEVICE: u8 = 0x00;
19
20/// USB interface class/subclass/protocol summary used for probing.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct InterfaceInfo {
23    pub id: u8,
24    pub class: u8,
25    pub subclass: u8,
26    pub protocol: u8,
27}
28
29/// Endpoint descriptor fields needed by drivers.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub struct EndpointInfo {
32    pub address: u8,
33    pub attributes: u8,
34    pub max_packet_size: u16,
35    pub interval: u8,
36}
37
38impl EndpointInfo {
39    /// IN vs OUT from the address bit.
40    pub fn direction(&self) -> u8 {
41        self.address & USB_DIR_IN
42    }
43
44    pub fn is_bulk_in(&self) -> bool {
45        self.direction() == USB_DIR_IN && (self.attributes & 0x03) == 2
46    }
47
48    pub fn is_bulk_out(&self) -> bool {
49        self.direction() == USB_DIR_OUT && (self.attributes & 0x03) == 2
50    }
51
52    pub fn is_interrupt_in(&self) -> bool {
53        self.direction() == USB_DIR_IN && (self.attributes & 0x03) == 3
54    }
55}
56
57/// USB control transfer request.
58#[derive(Debug, Clone)]
59pub struct ControlRequest {
60    pub request_type: u8,
61    pub request: u8,
62    pub value: u16,
63    pub index: u16,
64    pub data: Vec<u8>,
65    pub timeout_ms: u32,
66}
67
68impl ControlRequest {
69    /// Vendor OUT (host → device), `bmRequestType = 0x40`.
70    pub fn vendor_out(request: u8, value: u16, index: u16, data: Vec<u8>) -> Self {
71        Self {
72            request_type: 0x40,
73            request,
74            value,
75            index,
76            data,
77            timeout_ms: 5000,
78        }
79    }
80
81    /// Vendor IN; `data` length is the wLength buffer size.
82    pub fn vendor_in(request: u8, value: u16, index: u16, length: usize) -> Self {
83        Self {
84            request_type: 0xC0,
85            request,
86            value,
87            index,
88            data: vec![0; length],
89            timeout_ms: 5000,
90        }
91    }
92
93    /// Class OUT to interface.
94    pub fn class_out(request: u8, value: u16, index: u16, data: Vec<u8>) -> Self {
95        Self {
96            request_type: USB_TYPE_CLASS | USB_RECIP_INTERFACE,
97            request,
98            value,
99            index,
100            data,
101            timeout_ms: 5000,
102        }
103    }
104
105    /// Class IN from interface.
106    pub fn class_in(request: u8, value: u16, index: u16, length: usize) -> Self {
107        Self {
108            request_type: USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
109            request,
110            value,
111            index,
112            data: vec![0; length],
113            timeout_ms: 5000,
114        }
115    }
116}
117
118/// Owned bulk (or interrupt) IN pipe.
119pub trait BulkIn: Send {
120    fn read(&mut self, buf: &mut [u8], timeout_ms: u32) -> Result<ReadOutcome>;
121    fn cancel_all(&mut self);
122    fn clear_halt(&mut self) -> Result<()>;
123}
124
125/// Owned bulk OUT pipe.
126pub trait BulkOut: Send {
127    fn write(&mut self, data: &[u8], timeout_ms: u32) -> Result<usize>;
128    fn clear_halt(&mut self) -> Result<()>;
129}
130
131/// USB device view used by all chip drivers.
132pub trait Transport: Send + Sync {
133    fn raw_device_descriptor(&self) -> [u8; 18];
134    fn raw_descriptors(&self) -> Vec<u8>;
135    fn device_class(&self) -> u8;
136    fn interfaces(&self) -> Vec<InterfaceInfo>;
137    fn endpoints(&self, interface: u8) -> Vec<EndpointInfo>;
138    fn claim_interface(&self, interface: u8) -> Result<()>;
139    fn release_interface(&self, interface: u8) -> Result<()>;
140    fn control_out(&self, req: &ControlRequest) -> Result<usize>;
141    fn control_in(&self, req: &ControlRequest) -> Result<Vec<u8>>;
142    fn open_bulk_in(&self, endpoint: u8, max_packet_size: u16) -> Result<Box<dyn BulkIn>>;
143    fn open_bulk_out(&self, endpoint: u8, max_packet_size: u16) -> Result<Box<dyn BulkOut>>;
144    fn open_interrupt_in(&self, endpoint: u8, max_packet_size: u16) -> Result<Box<dyn BulkIn>>;
145}
146
147/// Shared ownership of a [`Transport`] (typically wrapped once per open).
148pub type SharedTransport = Arc<dyn Transport>;
149
150/// Parse USB control setup fields from `request_type`.
151pub fn parse_control_recipient(request_type: u8) -> (u8, bool) {
152    let direction_in = request_type & 0x80 != 0;
153    let recipient = request_type & 0x1f;
154    (recipient, direction_in)
155}
156
157/// Device recipient in `bmRequestType`.
158pub fn is_device_recipient(request_type: u8) -> bool {
159    (request_type & 0x1f) == USB_RECIP_DEVICE
160}
161
162/// Interface recipient in `bmRequestType`.
163pub fn is_interface_recipient(request_type: u8) -> bool {
164    (request_type & 0x1f) == USB_RECIP_INTERFACE
165}