opentitanlib/transport/hyperdebug/
uart.rs1use std::rc::Rc;
6
7use anyhow::{Context, Result};
8use rusb::{Direction, Recipient, RequestType};
9use serialport::Parity;
10
11use super::UartInterface;
12use crate::io::uart::{FlowControl, Uart, UartError};
13use crate::transport::TransportError;
14use crate::transport::common::uart::{SerialPortUart, SoftwareFlowControl};
15use crate::transport::hyperdebug::Inner;
16
17const UART_BAUD: u32 = 115200;
18
19pub struct HyperdebugUart {
20 inner: Rc<Inner>,
21 usb_interface: u8,
22 supports_clearing_queues: bool,
23 serial_port: SoftwareFlowControl<SerialPortUart>,
24}
25
26#[allow(dead_code)]
27enum ControlRequest {
28 ReqParity = 0,
29 SetParity = 1,
30 ReqBaud = 2,
31 SetBaud = 3,
32 Break = 4,
33 ClearQueues = 5,
34}
35
36#[allow(dead_code)]
38const CLEAR_RX_FIFO: u16 = 0x0001;
39#[allow(dead_code)]
41const CLEAR_TX_FIFO: u16 = 0x0002;
42
43impl HyperdebugUart {
44 pub fn open(
45 inner: &Rc<Inner>,
46 uart_interface: &UartInterface,
47 supports_clearing_queues: bool,
48 ) -> Result<Self> {
49 Ok(Self {
50 inner: Rc::clone(inner),
51 usb_interface: uart_interface.interface,
52 supports_clearing_queues,
53 serial_port: SoftwareFlowControl::new(SerialPortUart::open(
54 uart_interface
55 .tty
56 .to_str()
57 .ok_or(TransportError::UnicodePathError)?,
58 UART_BAUD,
59 )?),
60 })
61 }
62}
63
64impl Uart for HyperdebugUart {
65 fn get_baudrate(&self) -> Result<u32> {
66 let usb_handle = self.inner.usb_device.borrow();
67 let mut data = [0u8, 0u8];
68 usb_handle.read_control(
69 rusb::request_type(Direction::In, RequestType::Vendor, Recipient::Interface),
70 ControlRequest::ReqBaud as u8,
71 0,
72 self.usb_interface as u16,
73 &mut data,
74 )?;
75 Ok(u16::from_le_bytes(data) as u32 * 100)
76 }
77
78 fn set_baudrate(&self, baudrate: u32) -> Result<()> {
79 let usb_handle = self.inner.usb_device.borrow();
80 let compressed_baudrate: u16 = ((baudrate + 50) / 100).try_into()?;
81 let decompressed_baudrate = compressed_baudrate as u32 * 100;
82 if decompressed_baudrate != baudrate {
83 log::warn!(
84 "Warning: accuracy loss when setting baud rate. UART will use {} Bd instead of {}",
85 decompressed_baudrate,
86 baudrate
87 );
88 }
89 usb_handle.write_control(
90 rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface),
91 ControlRequest::SetBaud as u8,
92 compressed_baudrate,
93 self.usb_interface as u16,
94 &[],
95 )?;
96 Ok(())
97 }
98
99 fn get_flow_control(&self) -> Result<FlowControl> {
100 self.serial_port.get_flow_control()
101 }
102
103 fn set_flow_control(&self, flow_control: bool) -> Result<()> {
104 self.serial_port.set_flow_control(flow_control)
105 }
106
107 fn get_device_path(&self) -> Result<String> {
108 self.serial_port.get_device_path()
109 }
110
111 fn poll_read(
112 &self,
113 cx: &mut std::task::Context<'_>,
114 buf: &mut [u8],
115 ) -> std::task::Poll<Result<usize>> {
116 self.serial_port.poll_read(cx, buf)
117 }
118
119 fn write(&self, buf: &[u8]) -> Result<()> {
120 self.serial_port.write(buf)
121 }
122
123 fn clear_rx_buffer(&self) -> Result<()> {
124 if self.supports_clearing_queues {
125 let usb_handle = self.inner.usb_device.borrow();
126 usb_handle.write_control(
127 rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface),
128 ControlRequest::ClearQueues as u8,
129 CLEAR_RX_FIFO,
130 self.usb_interface as u16,
131 &[],
132 )?;
133 }
134 self.serial_port.clear_rx_buffer()
135 }
136
137 fn set_break(&self, enable: bool) -> Result<()> {
138 let usb_handle = self.inner.usb_device.borrow();
139 usb_handle
140 .write_control(
141 rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface),
142 ControlRequest::Break as u8,
143 if enable { 0xFFFF } else { 0 },
144 self.usb_interface as u16,
145 &[],
146 )
147 .context("Setting break condition")?;
148 Ok(())
149 }
150
151 fn set_parity(&self, parity: Parity) -> Result<()> {
152 let parity_code = match parity {
154 Parity::None => 0,
155 Parity::Odd => 1,
156 Parity::Even => 2,
157 };
158
159 let usb_handle = self.inner.usb_device.borrow();
160 usb_handle.write_control(
161 rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface),
162 ControlRequest::SetParity as u8,
163 parity_code,
164 self.usb_interface as u16,
165 &[],
166 )?;
167 Ok(())
168 }
169
170 fn get_parity(&self) -> Result<Parity> {
171 let usb_handle = self.inner.usb_device.borrow();
172 let mut data = [0u8, 0u8];
173 usb_handle.read_control(
174 rusb::request_type(Direction::In, RequestType::Vendor, Recipient::Interface),
175 ControlRequest::ReqParity as u8,
176 0,
177 self.usb_interface as u16,
178 &mut data,
179 )?;
180 match u16::from_le_bytes(data) {
182 0 => Ok(Parity::None),
183 1 => Ok(Parity::Odd),
184 2 => Ok(Parity::Even),
185 _ => Err(UartError::ReadError("Unknown parity value".to_string()).into()),
186 }
187 }
188}