77from ..constants .MEMMAP import *
88from ..exceptions import ECError
99
10-
1110try :
1211 import portio
1312except ImportError as e :
1716
1817class CrosEcLpc (CrosEcClass ):
1918 def __init__ (self , init : bool = True , address : Int32 = None ):
19+ """
20+ Detect and initialise the EC.
21+ @param init: Whether to initialise the EC on creation. Default is True.
22+ @param address: Specify a custom memmap address, will be detected if not specified.
23+ """
2024 self .address = address
2125 if init :
2226 self .ec_init ()
@@ -33,6 +37,11 @@ def detect() -> bool:
3337
3438 @staticmethod
3539 def find_address (* addresses ) -> int | None :
40+ """
41+ Find the EC memory map address.
42+ @param addresses: A list of addresses to check.
43+ @return: The address of the EC memory map, or None if not found.
44+ """
3645 for a in addresses :
3746 if res := portio .ioperm (a , EC_MEMMAP_SIZE , True ):
3847 if res == errno .EPERM :
@@ -48,7 +57,6 @@ def find_address(*addresses) -> int | None:
4857 portio .ioperm (a , EC_MEMMAP_SIZE , False )
4958 continue
5059
51-
5260 def ec_init (self ) -> None :
5361 """
5462 Initialise the EC. Checks for the EC, and configures the library to speak the same version.
@@ -70,7 +78,6 @@ def ec_init(self) -> None:
7078 else :
7179 raise OSError (f"ioperm returned { errno .errorcode [res ]} ({ res } )" )
7280
73-
7481 status = 0xFF
7582
7683 # Read status bits, at least one should be 0
@@ -98,8 +105,75 @@ def wait_for_ec(status_addr: Int32 = EC_LPC_ADDR_HOST_CMD) -> None:
98105 while portio .inb (status_addr ) & EC_LPC_STATUS_BUSY_MASK :
99106 pass
100107
101- def ec_command_v2 (self ):
102- raise NotImplementedError
108+ def ec_command_v2 (self , version : UInt8 , command : UInt32 , outsize : UInt16 , insize : UInt32 , data : bytes = None ,
109+ warn : bool = True ):
110+ """
111+ Send a command to the EC and return the response. Uses the v2 command protocol over LPC. UNTESTED!
112+ @param version: Command version number (often 0).
113+ @param command: Command to send (EC_CMD_...).
114+ @param outsize: Outgoing length in bytes.
115+ @param insize: Max number of bytes to accept from the EC.
116+ @param data: Outgoing data to EC.
117+ @param warn: Whether to warn if the response size is not as expected. Default is True.
118+ @return: Response from the EC.
119+ """
120+ warnings .warn ("Support for v2 commands haven't been tested! Open an issue on github if it does "
121+ "or doesn't work: https://github.com/Steve-Tech/CrOS_EC_Python/issues" , RuntimeWarning )
122+ csum = 0
123+ args = bytearray (struct .pack ("BBBB" , EC_HOST_ARGS_FLAG_FROM_HOST , version , outsize , csum ))
124+ # (flags: UInt8, command_version: UInt8, data_size: UInt8, checksum: UInt8)
125+
126+ # Copy data and start checksum
127+ for i in range (outsize ):
128+ portio .outb (data [i ], EC_LPC_ADDR_HOST_PARAM + i )
129+ csum += data [i ]
130+
131+ # Finish checksum
132+ for i in range (len (args )):
133+ csum += args [i ]
134+
135+ args [3 ] = csum & 0xff
136+
137+ # Copy header
138+ for i in range (len (args )):
139+ portio .outb (args [i ], EC_LPC_ADDR_HOST_ARGS + i )
140+
141+ # Start the command
142+ portio .outb (command , EC_LPC_ADDR_HOST_CMD )
143+
144+ self .wait_for_ec ()
145+
146+ # Check result
147+ i = portio .inb (EC_LPC_ADDR_HOST_DATA )
148+ if i :
149+ raise ECError (i )
150+
151+ # Read back args
152+ csum = 0
153+ data_out = bytearray (len (args ))
154+ for i in range (len (data_out )):
155+ data_out [i ] = portio .inb (EC_LPC_ADDR_HOST_ARGS + i )
156+ csum += data_out [i ]
157+
158+ response = struct .unpack ("BBBB" , data_out )
159+ # (flags: UInt8, command_version: UInt8, data_size: UInt8, checksum: UInt8)
160+
161+ if response [0 ] != EC_HOST_ARGS_FLAG_TO_HOST :
162+ raise IOError ("Invalid response!" )
163+
164+ if response [2 ] != insize and warn :
165+ warnings .warn (f"Expected { insize } bytes, got { response [2 ]} back from EC" , RuntimeWarning )
166+
167+ # Read back data
168+ data = bytearray ()
169+ for i in range (response [2 ]):
170+ data .append (portio .inb (EC_LPC_ADDR_HOST_PARAM + i ))
171+ csum += data [i ]
172+
173+ if response [3 ] != (csum & 0xff ):
174+ raise IOError ("Checksum error!" )
175+
176+ return bytes (data )
103177
104178 def ec_command_v3 (self , version : UInt8 , command : UInt32 , outsize : UInt16 , insize : UInt32 , data : bytes = None ,
105179 warn : bool = True ) -> bytes :
@@ -115,6 +189,8 @@ def ec_command_v3(self, version: UInt8, command: UInt32, outsize: UInt16, insize
115189 """
116190 csum = 0
117191 request = bytearray (struct .pack ("BBHBxH" , EC_HOST_REQUEST_VERSION , csum , command , version , outsize ))
192+ # (struct_version: UInt8, checksum: UInt8, command: UInt16,
193+ # command_version: UInt8, reserved: UInt8, data_len: UInt16)
118194
119195 # Fail if output size is too big
120196 if outsize + len (request ) > EC_LPC_HOST_PACKET_SIZE :
@@ -153,6 +229,7 @@ def ec_command_v3(self, version: UInt8, command: UInt32, outsize: UInt16, insize
153229 csum += data_out [i ]
154230
155231 response = struct .unpack ("BBHHH" , data_out )
232+ # (struct_version: UInt8, checksum: UInt8, result: UInt16, data_len: UInt16, reserved: UInt16)
156233
157234 if response [0 ] != EC_HOST_RESPONSE_VERSION :
158235 raise IOError ("Invalid response version!" )
@@ -179,7 +256,7 @@ def command(self, *args):
179256 """
180257 Stub function, will get overwritten in ec_get_cmd_version.
181258 """
182- raise NotImplementedError
259+ raise NotImplementedError ( "EC doesn't support commands!" )
183260
184261 def ec_get_cmd_version (self ) -> int :
185262 version = portio .inb (self .address + EC_MEMMAP_HOST_CMD_FLAGS )
0 commit comments