rockusb/
nusb.rs

1use crate::operation::{OperationSteps, UsbStep};
2pub use nusb::transfer::TransferError;
3use nusb::{
4    DeviceInfo,
5    transfer::{ControlOut, ControlType, Recipient, RequestBuffer},
6};
7use thiserror::Error;
8
9/// Error indicate a device is not available
10#[derive(Debug, Error)]
11#[error("Device is not available: {error}")]
12pub struct DeviceUnavalable {
13    #[from]
14    pub error: nusb::Error,
15}
16
17/// List rockchip devices
18pub fn devices() -> std::result::Result<impl Iterator<Item = DeviceInfo>, nusb::Error> {
19    Ok(nusb::list_devices()?.filter(|d| d.vendor_id() == 0x2207))
20}
21
22impl From<TransferError> for crate::device::Error<TransferError> {
23    fn from(value: TransferError) -> Self {
24        Self::UsbError(value)
25    }
26}
27
28/// nusb based Transport for rockusb operation
29pub struct Transport {
30    interface: nusb::Interface,
31    ep_in: u8,
32    ep_out: u8,
33}
34
35impl crate::device::TransportAsync for Transport {
36    type TransportError = TransferError;
37    async fn handle_operation<O, T>(
38        &mut self,
39        mut operation: O,
40    ) -> crate::device::DeviceResultAsync<T, Self>
41    where
42        O: OperationSteps<T>,
43    {
44        loop {
45            let step = operation.step();
46            match step {
47                UsbStep::WriteBulk { data } => {
48                    let _written = self
49                        .interface
50                        .bulk_out(self.ep_out, data.to_vec())
51                        .await
52                        .into_result()?;
53                }
54                UsbStep::ReadBulk { data } => {
55                    let req = RequestBuffer::new(data.len());
56                    let read = self
57                        .interface
58                        .bulk_in(self.ep_in, req)
59                        .await
60                        .into_result()?;
61                    data.copy_from_slice(&read);
62                }
63                UsbStep::WriteControl {
64                    request_type,
65                    request,
66                    value,
67                    index,
68                    data,
69                } => {
70                    let (control_type, recipient) = (
71                        match (request_type >> 5) & 0x03 {
72                            0 => ControlType::Standard,
73                            1 => ControlType::Class,
74                            2 => ControlType::Vendor,
75                            _ => ControlType::Standard,
76                        },
77                        match request_type & 0x1f {
78                            0 => Recipient::Device,
79                            1 => Recipient::Interface,
80                            2 => Recipient::Endpoint,
81                            3 => Recipient::Other,
82                            _ => Recipient::Device,
83                        },
84                    );
85                    let data = ControlOut {
86                        control_type,
87                        recipient,
88                        request,
89                        value,
90                        index,
91                        data,
92                    };
93                    self.interface.control_out(data).await.into_result()?;
94                }
95                UsbStep::Finished(r) => break r.map_err(|e| e.into()),
96            }
97        }
98    }
99}
100
101impl Transport {
102    fn new(
103        device: nusb::Device,
104        interface: u8,
105        ep_in: u8,
106        ep_out: u8,
107    ) -> std::result::Result<Self, DeviceUnavalable> {
108        let interface = device.claim_interface(interface)?;
109        Ok(Self {
110            interface,
111            ep_in,
112            ep_out,
113        })
114    }
115}
116
117pub type Device = crate::device::DeviceAsync<Transport>;
118impl Device {
119    /// Create a new transport from a device info
120    pub fn from_usb_device_info(
121        info: nusb::DeviceInfo,
122    ) -> std::result::Result<Self, DeviceUnavalable> {
123        let device = info.open()?;
124        Self::from_usb_device(device)
125    }
126
127    /// Create a new transport from an existing device
128    pub fn from_usb_device(device: nusb::Device) -> std::result::Result<Self, DeviceUnavalable> {
129        for config in device.clone().configurations() {
130            for interface in config.interface_alt_settings() {
131                let output = interface.endpoints().find(|e| {
132                    e.direction() == nusb::transfer::Direction::Out
133                        && e.transfer_type() == nusb::transfer::EndpointType::Bulk
134                });
135                let input = interface.endpoints().find(|e| {
136                    e.direction() == nusb::transfer::Direction::In
137                        && e.transfer_type() == nusb::transfer::EndpointType::Bulk
138                });
139
140                if let (Some(input), Some(output)) = (input, output) {
141                    return Ok(Device::new(Transport::new(
142                        device,
143                        interface.interface_number(),
144                        input.address(),
145                        output.address(),
146                    )?));
147                }
148            }
149        }
150        Err(DeviceUnavalable {
151            error: nusb::Error::new(std::io::ErrorKind::NotFound, "Device not found"),
152        })
153    }
154}