1#[macro_use]
23extern crate nix;
24
25use std::{
26 fs::OpenOptions,
27 io::{Error, ErrorKind, Result},
28 os::unix::io::{IntoRawFd, RawFd},
29};
30
31use nix::{libc::ioctl, sys::ioctl::ioctl_num_type};
32use num_derive::ToPrimitive;
33use num_traits::ToPrimitive;
34
35pub type I2CAddress = u8;
36
37pub const SG_INTERFACE_ID_ORIG: u8 = b'S';
38
39pub const SG_IO: u32 = 0x2285;
40
41#[derive(ToPrimitive)]
42pub enum DataTransferDirection {
43 ToDev = -2,
44 FromDev = -3,
45}
46
47pub const USB2642_SCSI_OPCODE: u8 = 0xcf;
48pub const USB2642_I2C_WRITE_STREAM: u8 = 0x23;
49pub const USB2642_I2C_WRITE_READ_STREAM: u8 = 0x22;
50
51pub trait USB2642I2CCommand {}
52
53#[derive(Debug, Default)]
54#[repr(C)]
55pub struct USB2642I2CWriteReadCommand {
56 scsi_vendor_command: u8,
57 scsi_vendor_action_write_read_i2c: u8,
58 i2c_write_slave_address: u8,
59 i2c_read_slave_address: u8,
60 i2c_read_data_phase_length_high: u8,
61 i2c_read_data_phase_length_low: u8,
62 i2c_write_phase_length: u8,
63 i2c_write_phase_payload: [u8; 9],
64}
65
66impl USB2642I2CWriteReadCommand {
67 pub fn new(i2c_addr: u8, write_data: &[u8], read_len: usize) -> Result<Self> {
68 if read_len > 9 {
69 return Err(Error::new(ErrorKind::InvalidInput, "read_len > 9 bytes"));
70 } else if write_data.len() > 9 {
71 return Err(Error::new(
72 ErrorKind::InvalidInput,
73 "write_data.len() > 9 bytes",
74 ));
75 }
76
77 let i2c_write_addr = i2c_addr << 1;
78 let i2c_read_addr = i2c_write_addr + 1;
79
80 let mut s = Self {
81 scsi_vendor_command: USB2642_SCSI_OPCODE,
82 scsi_vendor_action_write_read_i2c: USB2642_I2C_WRITE_READ_STREAM,
83 i2c_write_slave_address: i2c_write_addr,
84 i2c_read_slave_address: i2c_read_addr,
85 i2c_read_data_phase_length_high: ((read_len >> 8) & 0xff) as u8,
86 i2c_read_data_phase_length_low: (read_len & 0xff) as u8,
87 i2c_write_phase_length: write_data.len() as u8,
88 i2c_write_phase_payload: Default::default(),
89 };
90
91 for (i, b) in (&write_data[..write_data.len()]).iter().enumerate() {
92 s.i2c_write_phase_payload[i] = *b;
93 }
94
95 Ok(s)
96 }
97}
98
99impl USB2642I2CCommand for USB2642I2CWriteReadCommand {}
100
101#[derive(Debug, Default)]
102#[repr(C)]
103pub struct USB2642I2CWriteCommand {
104 scsi_vendor_command: u8,
105 scsi_vendor_action_write_i2c: u8,
106 i2c_slave_address: u8,
107 i2c_unused: u8,
108 i2c_data_phase_length_high: u8,
109 i2c_data_phase_length_low: u8,
110 i2c_command_phase_length: u8,
111 i2c_command_phase_payload: [u8; 9],
112}
113
114impl USB2642I2CWriteCommand {
115 pub fn new(i2c_addr: u8, write_data: &[u8]) -> Result<Self> {
116 if write_data.len() > 9 {
117 return Err(Error::new(
118 ErrorKind::InvalidInput,
119 "write_data.len() > 9 bytes",
120 ));
121 }
122
123 let i2c_write_addr = i2c_addr << 1;
124
125 let mut s = Self {
126 scsi_vendor_command: USB2642_SCSI_OPCODE,
127 scsi_vendor_action_write_i2c: USB2642_I2C_WRITE_STREAM,
128 i2c_slave_address: i2c_write_addr,
129 i2c_unused: 0,
130 i2c_data_phase_length_high: 0u8,
131 i2c_data_phase_length_low: 0u8,
132 i2c_command_phase_length: write_data.len() as u8,
133 i2c_command_phase_payload: Default::default(),
134 };
135
136 for (i, b) in (&write_data[..write_data.len()]).iter().enumerate() {
137 s.i2c_command_phase_payload[i] = *b;
138 }
139
140 Ok(s)
141 }
142}
143
144impl USB2642I2CCommand for USB2642I2CWriteCommand {}
145
146#[derive(Debug)]
147#[repr(C)]
148pub struct SgIoHdr<CMD: USB2642I2CCommand> {
149 interface_id: i32,
151 dxfer_direction: i32,
153 cmd_len: u8,
155 mx_sb_len: u8,
157 iovec_count: u16,
159 dxfer_len: u32,
161 dxferp: *mut u8,
163 cmdp: *mut CMD,
165 sbp: *mut u8,
167 timeout: u32,
169 flags: u32,
171 pack_id: i32,
173 usr_ptr: *const u8,
175 status: u8,
177 masked_status: u8,
179 msg_status: u8,
181 sb_len_wr: u8,
183 host_status: u16,
185 driver_status: u16,
187 resid: i32,
189 duration: u32,
191 info: u32,
193}
194
195impl<CMD: USB2642I2CCommand> SgIoHdr<CMD> {
196 pub fn new(
197 mut command: CMD,
198 sg_dxfer: DataTransferDirection,
199 data_buffer: *mut u8,
200 data_len: usize,
201 ) -> Self {
202 let mut sense = [0u8; 64];
203 Self {
204 interface_id: 'S' as i32,
205 dxfer_direction: sg_dxfer.to_i32().unwrap(),
206 cmd_len: std::mem::size_of::<CMD>() as u8,
207 mx_sb_len: sense.len() as u8,
208 iovec_count: 0,
209 dxfer_len: data_len as u32,
210 dxferp: data_buffer,
211 cmdp: &mut command,
212 sbp: sense.as_mut_ptr(),
213 timeout: 3000,
214 flags: 0,
215 pack_id: 0,
216 usr_ptr: std::ptr::null(),
217 status: 0,
218 masked_status: 0,
219 msg_status: 0,
220 sb_len_wr: 0,
221 host_status: 0,
222 driver_status: 0,
223 resid: 0,
224 duration: 0,
225 info: 0,
226 }
227 }
228}
229
230pub struct USB2642I2C {
231 sg_fd: RawFd,
232}
233
234impl USB2642I2C {
235 pub fn open<S: Into<String>>(sg_dev: S) -> Result<Self> {
236 let sg_fd = OpenOptions::new()
237 .read(true)
238 .write(true)
239 .open(sg_dev.into())?;
240 Ok(Self {
241 sg_fd: sg_fd.into_raw_fd(),
242 })
243 }
244
245 fn sg_ioctl<CMD: USB2642I2CCommand>(&self, sg_io_hdr: &SgIoHdr<CMD>) -> Result<()> {
246 if let Err(e) =
247 unsafe { convert_ioctl_res!(ioctl(self.sg_fd, SG_IO as ioctl_num_type, sg_io_hdr)) }
248 {
249 return Err(Error::new(ErrorKind::Other, e));
250 }
251 Ok(())
252 }
253
254 pub fn write(&mut self, i2c_addr: I2CAddress, data: &mut [u8]) -> Result<()> {
255 let command = USB2642I2CWriteCommand::new(i2c_addr, data)?;
256 let sgio = SgIoHdr::new(
257 command,
258 DataTransferDirection::ToDev,
259 std::ptr::null_mut(),
260 0,
261 );
262 self.sg_ioctl(&sgio)
263 }
264
265 pub fn write_read(
266 &mut self,
267 i2c_addr: I2CAddress,
268 data: &[u8],
269 read_len: usize,
270 ) -> Result<Vec<u8>> {
271 let command = USB2642I2CWriteReadCommand::new(i2c_addr, data, read_len)?;
272
273 let mut out_buffer = [0u8; 9];
274
275 let sgio = SgIoHdr::new(
276 command,
277 DataTransferDirection::FromDev,
278 out_buffer.as_mut_ptr(),
279 read_len,
280 );
281
282 self.sg_ioctl(&sgio)?;
283
284 Ok((&out_buffer[..read_len]).to_vec())
285 }
286}