Add a color (2 colors can be now defined for a machine).
[temp2RGB.git] / src / piix4_i2c.rs
1 // Partial implementation for PCI IDE ISA Xcelerator.
2 // https://www.kernel.org/doc/html/latest/i2c/summary.html
3
4 use std::time::Duration;
5
6 use crate::{timer, wrapper_winring0};
7
8 pub const I2C_BLOCK_MAX: usize = 32;
9
10 #[repr(u16)]
11 #[derive(Clone, Copy, Debug)]
12 enum TransactionType {
13 I2cSmbusQuick = 0,
14 I2cSmbusByte = 1,
15 I2cSmbusByteData = 2,
16 I2cSmbusWordData = 3,
17 I2cSmbusProcCall = 4,
18 I2cSmbusBlockData = 5,
19 I2cSmbusI2cBlockBroken = 6,
20 I2cSmbusBlockProcCall = 7, /* SMBus 2.0 */
21 I2cSmbusI2cBlockData = 8,
22 }
23
24 #[repr(u16)]
25 #[derive(Clone, Copy, Debug)]
26 enum Piix4TransactionType {
27 Piix4Quick = 0x00,
28 Piix4Byte = 0x04,
29 Piix4ByteData = 0x08,
30 Piix4WordData = 0x0C,
31 Piix4BlockData = 0x14,
32 }
33
34 // PIIX4 SMBus address offsets
35
36 #[repr(u16)]
37 #[derive(Clone, Copy, Debug)]
38 enum SMBusAddressOffsets {
39 Smbhststs = 0,
40 Smbhslvsts = 1,
41 Smbhstcnt = 2,
42 Smbhstcmd = 3,
43 Smbhstadd = 4,
44 Smbhstdat0 = 5,
45 Smbhstdat1 = 6,
46 Smbblkdat = 7,
47 Smbslvcnt = 8,
48 Smbshdwcmd = 9,
49 Smbslvevt = 0xA,
50 Smbslvdat = 0xC,
51 }
52
53 #[repr(u8)]
54 #[derive(Clone, Copy)]
55 enum AccessType {
56 Write = 0,
57 Read = 1,
58 }
59
60 pub struct I2c {
61 base_address: u16,
62 }
63
64 enum XferResult {
65 Ok,
66 BlockData(Vec<u8>),
67 }
68
69 #[derive(Debug)]
70 enum Error {
71 Busy,
72 Timeout,
73 IO,
74 Data,
75 }
76
77 impl I2c {
78 pub fn new(base_address: u16) -> Self {
79 I2c { base_address }
80 }
81
82 pub fn write_block_data(&self, addr: u8, command: u8, data: &[u8]) {
83 let l = data.len();
84 assert!(
85 l <= I2C_BLOCK_MAX,
86 "Data length must not exceed {}",
87 I2C_BLOCK_MAX
88 );
89 let mut data_block = [0u8; I2C_BLOCK_MAX + 2];
90 data_block[0] = l as u8;
91 data_block[1..l + 1].copy_from_slice(&data);
92
93 unsafe {
94 match self.i2c_smbus_xfer(
95 addr,
96 AccessType::Write,
97 command,
98 TransactionType::I2cSmbusBlockData,
99 Some(&data_block),
100 ) {
101 Err(error) => println!("Error when writing block (I2c): {error:?}"),
102 Ok(_) => (),
103 }
104 }
105 }
106
107 pub fn i2c_smbus_write_quick(&self, addr: u8, value: u8) {
108 unsafe {
109 self.i2c_smbus_xfer(
110 addr,
111 AccessType::Write,
112 value,
113 TransactionType::I2cSmbusQuick,
114 None,
115 )
116 .unwrap();
117 }
118 }
119
120 unsafe fn i2c_smbus_xfer(
121 &self,
122 addr: u8,
123 access_type: AccessType,
124 command: u8,
125 transaction_type: TransactionType, // Called 'size' in 'i2c_smbus\i2c_smbus_piix4.cpp'.
126 data: Option<&[u8]>,
127 ) -> Result<XferResult, Error> {
128 let piix4_transaction_type = match transaction_type {
129 TransactionType::I2cSmbusQuick => {
130 self.write_io_port_byte(
131 SMBusAddressOffsets::Smbhstadd,
132 addr << 1 | access_type as u8,
133 );
134 Piix4TransactionType::Piix4Quick
135 }
136 TransactionType::I2cSmbusByte => todo!(),
137 TransactionType::I2cSmbusByteData => todo!(), // Here 'data' should be a byte, maybe using a enum?.
138 TransactionType::I2cSmbusWordData => todo!(), // Here 'data' should be a u16, maybe using a enum?.
139 TransactionType::I2cSmbusBlockData => {
140 self.write_io_port_byte(
141 SMBusAddressOffsets::Smbhstadd,
142 addr << 1 | access_type as u8,
143 );
144 self.write_io_port_byte(SMBusAddressOffsets::Smbhstcmd, command);
145 if let AccessType::Write = access_type {
146 let len = data.unwrap()[0];
147 if len == 0 || len > I2C_BLOCK_MAX as u8 {
148 panic!("Invalid len value: {}", len);
149 }
150
151 self.write_io_port_byte(SMBusAddressOffsets::Smbhstdat0, len);
152 self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt); // TODO: do something of the result!?
153 for i in 1..=len {
154 self.write_io_port_byte(
155 SMBusAddressOffsets::Smbblkdat,
156 data.unwrap()[i as usize],
157 );
158 }
159 }
160 Piix4TransactionType::Piix4BlockData
161 }
162 _ => panic!("Not supported: {:?}", transaction_type),
163 };
164
165 self.write_io_port_byte(
166 SMBusAddressOffsets::Smbhstcnt,
167 piix4_transaction_type as u8 & 0x1C,
168 );
169
170 self.piix4_transaction()?;
171
172 // if let (AccessType::Write, Piix4TransactionType::Piix4Quick) = (access_type, piix4_transaction_type) {
173 // return Ok(())
174 // }
175
176 match piix4_transaction_type {
177 Piix4TransactionType::Piix4Quick => Ok(XferResult::Ok),
178 Piix4TransactionType::Piix4Byte => todo!(),
179 Piix4TransactionType::Piix4ByteData => todo!(),
180 Piix4TransactionType::Piix4WordData => todo!(),
181 Piix4TransactionType::Piix4BlockData => {
182 let l = self.read_io_port_byte(SMBusAddressOffsets::Smbhstdat0) as usize;
183 if l == 0 || l > I2C_BLOCK_MAX {
184 return Err(Error::Data);
185 }
186 self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt);
187 let mut data = vec![0; l + 1];
188 for i in 1..=l {
189 data[i] = self.read_io_port_byte(SMBusAddressOffsets::Smbblkdat);
190 }
191 return Ok(XferResult::BlockData(data));
192 }
193 }
194 }
195
196 unsafe fn piix4_transaction(&self) -> Result<(), Error> {
197 let timer = timer::Sleep::new();
198
199 // Make sure the SMBus is ready to start transmitting.
200 let mut res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs);
201 if res != 0x00 {
202 self.write_io_port_byte(SMBusAddressOffsets::Smbhststs, res);
203 res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs);
204 if res != 0x00 {
205 return Err(Error::Busy);
206 }
207 }
208
209 // Start the transaction by setting bit 6.
210 res = self.read_io_port_byte(SMBusAddressOffsets::Smbhstcnt);
211 self.write_io_port_byte(SMBusAddressOffsets::Smbhstcnt, res | 0x40);
212
213 // let duration: i64 = -2_500; // 250 us.
214 let mut n = 0;
215 loop {
216 timer.wait(Duration::from_micros(250));
217
218 res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs);
219 // println!("Res: {}", res);
220 if res > 0x01 {
221 break;
222 }
223
224 if n >= 100 {
225 return Err(Error::Timeout);
226 }
227 n += 1;
228 }
229 // println!("-----");
230
231 if res & 0x10 != 0x00 || res & 0x08 != 0x0 || res & 0x04 != 0x0 {
232 return Err(Error::IO);
233 }
234
235 res = self.read_io_port_byte(SMBusAddressOffsets::Smbhststs);
236 if res != 0x00 {
237 self.write_io_port_byte(SMBusAddressOffsets::Smbhststs, res);
238 }
239
240 return Ok(());
241 }
242
243 unsafe fn write_io_port_byte(&self, op: SMBusAddressOffsets, value: u8) {
244 wrapper_winring0::WriteIoPortByte(self.base_address + op as u16, value);
245 }
246
247 unsafe fn read_io_port_byte(&self, op: SMBusAddressOffsets) -> u8 {
248 wrapper_winring0::ReadIoPortByte(self.base_address + op as u16)
249 }
250 }
251
252 /*
253 type ADL_MAIN_MALLOC_CALLBACK = unsafe fn(c_int) -> *mut c_void;
254 type ADL_CONTEXT_HANDLE = *mut c_void;
255
256 type ADL2_MAIN_CONTROL_CREATE = unsafe extern "C" fn(ADL_MAIN_MALLOC_CALLBACK, c_int, *mut ADL_CONTEXT_HANDLE) -> c_int;
257 type ADL2_MAIN_CONTROL_DESTROY = unsafe extern "C" fn(ADL_CONTEXT_HANDLE) -> c_int;
258 type ADL2_ADAPTER_NUMBEROFADAPTERS_GET = unsafe extern "C" fn(ADL_CONTEXT_HANDLE, *mut c_int) -> c_int;
259
260 pub fn test() {
261 unsafe {
262 let hDLL = LoadLibraryW(w!("atiadlxx.dll")).unwrap();
263 println!("{:?}", hDLL);
264
265 let ADL2_Main_Control_Create: ADL2_MAIN_CONTROL_CREATE = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Create")).unwrap());
266 let ADL2_Main_Control_Destroy: ADL2_MAIN_CONTROL_DESTROY = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Destroy")).unwrap());
267 let ADL2_Adapter_NumberOfAdapters_Get: ADL2_ADAPTER_NUMBEROFADAPTERS_GET = transmute(&GetProcAddress(hDLL, s!("ADL2_Adapter_NumberOfAdapters_Get")).unwrap());
268
269
270 let m: *mut c_void = libc::malloc(4);
271
272
273 }
274 }
275 */