1 // Partial implementation for PCI IDE ISA Xcelerator.
2 // https://www.kernel.org/doc/html/latest/i2c/summary.html
4 use std
::time
::Duration
;
6 use crate::{timer
, wrapper_winring0
};
8 pub const I2C_BLOCK_MAX
: usize = 32;
11 #[derive(Clone, Copy, Debug)]
12 enum TransactionType
{
18 I2cSmbusBlockData
= 5,
19 I2cSmbusI2cBlockBroken
= 6,
20 I2cSmbusBlockProcCall
= 7, /* SMBus 2.0 */
21 I2cSmbusI2cBlockData
= 8,
25 #[derive(Clone, Copy, Debug)]
26 enum Piix4TransactionType
{
31 Piix4BlockData
= 0x14,
34 // PIIX4 SMBus address offsets
37 #[derive(Clone, Copy, Debug)]
38 enum SMBusAddressOffsets
{
54 #[derive(Clone, Copy)]
78 pub fn new(base_address
: u16) -> Self {
82 pub fn write_block_data(&self, addr
: u8, command
: u8, data
: &[u8]) {
86 "Data length must not exceed {}",
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
);
94 if let Err(error
) = self.i2c_smbus_xfer(
98 TransactionType
::I2cSmbusBlockData
,
101 println!("Error when writing block (I2c): {error:?}");
106 pub fn i2c_smbus_write_quick(&self, addr
: u8, value
: u8) {
108 let _
= self.i2c_smbus_xfer(
112 TransactionType
::I2cSmbusQuick
,
118 unsafe fn i2c_smbus_xfer(
121 access_type
: AccessType
,
123 transaction_type
: TransactionType
, // Called 'size' in 'i2c_smbus\i2c_smbus_piix4.cpp'.
125 ) -> Result
<XferResult
, Error
> {
126 let piix4_transaction_type
= match transaction_type
{
127 TransactionType
::I2cSmbusQuick
=> {
128 self.write_io_port_byte(
129 SMBusAddressOffsets
::Smbhstadd
,
130 (addr
<< 1) | access_type
as u8,
132 Piix4TransactionType
::Piix4Quick
134 TransactionType
::I2cSmbusByte
=> todo!(),
135 TransactionType
::I2cSmbusByteData
=> todo!(), // Here 'data' should be a byte, maybe using a enum?.
136 TransactionType
::I2cSmbusWordData
=> todo!(), // Here 'data' should be a u16, maybe using a enum?.
137 TransactionType
::I2cSmbusBlockData
=> {
138 self.write_io_port_byte(
139 SMBusAddressOffsets
::Smbhstadd
,
140 (addr
<< 1) | access_type
as u8,
142 self.write_io_port_byte(SMBusAddressOffsets
::Smbhstcmd
, command
);
143 if let AccessType
::Write
= access_type
{
144 let len
= data
.unwrap()[0];
145 if len
== 0 || len
> I2C_BLOCK_MAX
as u8 {
146 panic!("Invalid len value: {}", len
);
149 self.write_io_port_byte(SMBusAddressOffsets
::Smbhstdat0
, len
);
150 self.read_io_port_byte(SMBusAddressOffsets
::Smbhstcnt
); // TODO: do something of the result!?
152 self.write_io_port_byte(
153 SMBusAddressOffsets
::Smbblkdat
,
154 data
.unwrap()[i
as usize],
158 Piix4TransactionType
::Piix4BlockData
160 _
=> panic!("Not supported: {:?}", transaction_type
),
163 self.write_io_port_byte(
164 SMBusAddressOffsets
::Smbhstcnt
,
165 piix4_transaction_type
as u8 & 0x1C,
168 self.piix4_transaction()?
;
170 // if let (AccessType::Write, Piix4TransactionType::Piix4Quick) = (access_type, piix4_transaction_type) {
174 match piix4_transaction_type
{
175 Piix4TransactionType
::Piix4Quick
=> Ok(XferResult
::Ok
),
176 Piix4TransactionType
::Piix4Byte
=> todo!(),
177 Piix4TransactionType
::Piix4ByteData
=> todo!(),
178 Piix4TransactionType
::Piix4WordData
=> todo!(),
179 Piix4TransactionType
::Piix4BlockData
=> {
180 let l
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhstdat0
) as usize;
181 if l
== 0 || l
> I2C_BLOCK_MAX
{
182 return Err(Error
::Data
);
184 self.read_io_port_byte(SMBusAddressOffsets
::Smbhstcnt
);
185 let mut data
= vec
![0; l
+ 1];
187 data
[i
] = self.read_io_port_byte(SMBusAddressOffsets
::Smbblkdat
);
189 Ok(XferResult
::BlockData(data
))
194 unsafe fn piix4_transaction(&self) -> Result
<(), Error
> {
195 let timer
= timer
::Sleep
::new();
197 // Make sure the SMBus is ready to start transmitting.
198 let mut res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
200 self.write_io_port_byte(SMBusAddressOffsets
::Smbhststs
, res
);
201 res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
203 return Err(Error
::Busy
);
207 // Start the transaction by setting bit 6.
208 res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhstcnt
);
209 self.write_io_port_byte(SMBusAddressOffsets
::Smbhstcnt
, res
| 0x40);
211 // let duration: i64 = -2_500; // 250 us.
214 timer
.wait(Duration
::from_micros(250));
216 res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
217 // println!("Res: {}", res);
223 return Err(Error
::Timeout
);
227 // println!("-----");
229 if res
& 0x10 != 0x00 || res
& 0x08 != 0x0 || res
& 0x04 != 0x0 {
230 return Err(Error
::IO
);
233 res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
235 self.write_io_port_byte(SMBusAddressOffsets
::Smbhststs
, res
);
241 unsafe fn write_io_port_byte(&self, op
: SMBusAddressOffsets
, value
: u8) {
242 wrapper_winring0
::WriteIoPortByte(self.base_address
+ op
as u16, value
);
245 unsafe fn read_io_port_byte(&self, op
: SMBusAddressOffsets
) -> u8 {
246 wrapper_winring0
::ReadIoPortByte(self.base_address
+ op
as u16)
251 type ADL_MAIN_MALLOC_CALLBACK = unsafe fn(c_int) -> *mut c_void;
252 type ADL_CONTEXT_HANDLE = *mut c_void;
254 type ADL2_MAIN_CONTROL_CREATE = unsafe extern "C" fn(ADL_MAIN_MALLOC_CALLBACK, c_int, *mut ADL_CONTEXT_HANDLE) -> c_int;
255 type ADL2_MAIN_CONTROL_DESTROY = unsafe extern "C" fn(ADL_CONTEXT_HANDLE) -> c_int;
256 type ADL2_ADAPTER_NUMBEROFADAPTERS_GET = unsafe extern "C" fn(ADL_CONTEXT_HANDLE, *mut c_int) -> c_int;
260 let hDLL = LoadLibraryW(w!("atiadlxx.dll")).unwrap();
261 println!("{:?}", hDLL);
263 let ADL2_Main_Control_Create: ADL2_MAIN_CONTROL_CREATE = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Create")).unwrap());
264 let ADL2_Main_Control_Destroy: ADL2_MAIN_CONTROL_DESTROY = transmute(&GetProcAddress(hDLL, s!("ADL2_Main_Control_Destroy")).unwrap());
265 let ADL2_Adapter_NumberOfAdapters_Get: ADL2_ADAPTER_NUMBEROFADAPTERS_GET = transmute(&GetProcAddress(hDLL, s!("ADL2_Adapter_NumberOfAdapters_Get")).unwrap());
268 let m: *mut c_void = libc::malloc(4);