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 match self.i2c_smbus_xfer(
98 TransactionType
::I2cSmbusBlockData
,
101 Err(error
) => println!("Error when writing block (I2c): {error:?}"),
107 pub fn i2c_smbus_write_quick(&self, addr
: u8, value
: u8) {
113 TransactionType
::I2cSmbusQuick
,
120 unsafe fn i2c_smbus_xfer(
123 access_type
: AccessType
,
125 transaction_type
: TransactionType
, // Called 'size' in 'i2c_smbus\i2c_smbus_piix4.cpp'.
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,
134 Piix4TransactionType
::Piix4Quick
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,
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
);
151 self.write_io_port_byte(SMBusAddressOffsets
::Smbhstdat0
, len
);
152 self.read_io_port_byte(SMBusAddressOffsets
::Smbhstcnt
); // TODO: do something of the result!?
154 self.write_io_port_byte(
155 SMBusAddressOffsets
::Smbblkdat
,
156 data
.unwrap()[i
as usize],
160 Piix4TransactionType
::Piix4BlockData
162 _
=> panic!("Not supported: {:?}", transaction_type
),
165 self.write_io_port_byte(
166 SMBusAddressOffsets
::Smbhstcnt
,
167 piix4_transaction_type
as u8 & 0x1C,
170 self.piix4_transaction()?
;
172 // if let (AccessType::Write, Piix4TransactionType::Piix4Quick) = (access_type, piix4_transaction_type) {
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
);
186 self.read_io_port_byte(SMBusAddressOffsets
::Smbhstcnt
);
187 let mut data
= vec
![0; l
+ 1];
189 data
[i
] = self.read_io_port_byte(SMBusAddressOffsets
::Smbblkdat
);
191 return Ok(XferResult
::BlockData(data
));
196 unsafe fn piix4_transaction(&self) -> Result
<(), Error
> {
197 let timer
= timer
::Sleep
::new();
199 // Make sure the SMBus is ready to start transmitting.
200 let mut res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
202 self.write_io_port_byte(SMBusAddressOffsets
::Smbhststs
, res
);
203 res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
205 return Err(Error
::Busy
);
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);
213 // let duration: i64 = -2_500; // 250 us.
216 timer
.wait(Duration
::from_micros(250));
218 res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
219 // println!("Res: {}", res);
225 return Err(Error
::Timeout
);
229 // println!("-----");
231 if res
& 0x10 != 0x00 || res
& 0x08 != 0x0 || res
& 0x04 != 0x0 {
232 return Err(Error
::IO
);
235 res
= self.read_io_port_byte(SMBusAddressOffsets
::Smbhststs
);
237 self.write_io_port_byte(SMBusAddressOffsets
::Smbhststs
, res
);
243 unsafe fn write_io_port_byte(&self, op
: SMBusAddressOffsets
, value
: u8) {
244 wrapper_winring0
::WriteIoPortByte(self.base_address
+ op
as u16, value
);
247 unsafe fn read_io_port_byte(&self, op
: SMBusAddressOffsets
) -> u8 {
248 wrapper_winring0
::ReadIoPortByte(self.base_address
+ op
as u16)
253 type ADL_MAIN_MALLOC_CALLBACK = unsafe fn(c_int) -> *mut c_void;
254 type ADL_CONTEXT_HANDLE = *mut c_void;
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;
262 let hDLL = LoadLibraryW(w!("atiadlxx.dll")).unwrap();
263 println!("{:?}", hDLL);
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());
270 let m: *mut c_void = libc::malloc(4);