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