Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1101 lines
38 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
  9. //
  10. // I2CSCRPT.C
  11. // I2CScript class implementation.
  12. // Main Include Module.
  13. //
  14. //==========================================================================;
  15. extern "C"
  16. {
  17. #define INITGUID
  18. #include "strmini.h"
  19. #include "ksmedia.h"
  20. #include "wdm.h"
  21. #include "wdmdebug.h"
  22. }
  23. #include "i2script.h"
  24. #include "wdmdrv.h"
  25. /*^^*
  26. * operator new
  27. * Purpose : CI2CScript class overloaded operator new.
  28. * Provides placement for a CI2CScript class object from the PADAPTER_DEVICE_EXTENSION
  29. * allocated by the StreamClassDriver for the MiniDriver.
  30. *
  31. * Inputs : UINT size_t : size of the object to be placed
  32. * PVOID pAllocation : casted pointer to the CI2CScript allocated data
  33. *
  34. * Outputs : PVOID : pointer of the CI2CScript class object
  35. * Author : IKLEBANOV
  36. *^^*/
  37. PVOID CI2CScript::operator new( size_t stSize, PVOID pAllocation)
  38. {
  39. if( stSize != sizeof( CI2CScript))
  40. {
  41. OutputDebugError(( "CI2CScript: operator new() fails\n"));
  42. return( NULL);
  43. }
  44. else
  45. return( pAllocation);
  46. }
  47. /*^^*
  48. * CI2CScript()
  49. * Purpose : CI2CScript class constructor.
  50. * Performs checking of the I2C provider presence. Sets the script in the initial state.
  51. *
  52. * Inputs : PUINT puiError : pointer to return a completion error code
  53. * PHW_STREAM_REQUEST_BLOCK pSrb : pointer to HW_INITIALIZE SRB
  54. *
  55. * Outputs : none
  56. * Author : IKLEBANOV
  57. *^^*/
  58. CI2CScript::CI2CScript( PPORT_CONFIGURATION_INFORMATION pConfigInfo,
  59. PUINT puiErrorCode)
  60. {
  61. m_dwI2CAccessKey = 0;
  62. m_i2cProviderInterface.i2cOpen = NULL;
  63. m_i2cProviderInterface.i2cAccess = NULL;
  64. m_pdoDriver = NULL;
  65. if( !InitializeAttachI2CProvider( &m_i2cProviderInterface, pConfigInfo->PhysicalDeviceObject))
  66. * puiErrorCode = WDMMINI_ERROR_NOI2CPROVIDER;
  67. else
  68. {
  69. // there was no error to get I2CInterface from the MiniVDD
  70. m_pdoDriver = pConfigInfo->RealPhysicalDeviceObject;
  71. m_ulI2CAccessClockRate = I2C_FIXED_CLOCK_RATE;
  72. * puiErrorCode = WDMMINI_NOERROR;
  73. }
  74. OutputDebugTrace(( "CI2CScript:CI2CScript() exit Error = %x\n", * puiErrorCode));
  75. }
  76. /*^^*
  77. * LockI2CProvider()
  78. * Purpose : locks the I2CProvider for exclusive use
  79. *
  80. * Inputs : none
  81. *
  82. * Outputs : BOOL : retunrs TRUE, if the I2CProvider is locked
  83. * Author : IKLEBANOV
  84. *^^*/
  85. BOOL CI2CScript::LockI2CProvider( void)
  86. {
  87. BOOL bResult;
  88. I2CControl i2cAccessBlock;
  89. bResult = FALSE;
  90. ENSURE
  91. {
  92. if(( m_i2cProviderInterface.i2cOpen == NULL) ||
  93. ( m_i2cProviderInterface.i2cAccess == NULL) ||
  94. ( m_pdoDriver == NULL))
  95. FAIL;
  96. i2cAccessBlock.Status = I2C_STATUS_NOERROR;
  97. if( m_i2cProviderInterface.i2cOpen( m_pdoDriver, TRUE, &i2cAccessBlock) != STATUS_SUCCESS)
  98. {
  99. OutputDebugError(( "CI2CScript: LockI2CProvider() bResult = %x\n", bResult));
  100. FAIL;
  101. }
  102. if( i2cAccessBlock.Status != I2C_STATUS_NOERROR)
  103. {
  104. OutputDebugError(( "CI2CScript: LockI2CProvider() Status = %x\n", i2cAccessBlock.Status));
  105. FAIL;
  106. }
  107. // the I2C Provider has granted access - save dwCookie for further use
  108. m_dwI2CAccessKey = i2cAccessBlock.dwCookie;
  109. bResult = TRUE;
  110. } END_ENSURE;
  111. return( bResult);
  112. }
  113. /*^^*
  114. * LockI2CProvider()
  115. * Purpose : locks the I2CProvider for exclusive use. Provides attempts to lock the
  116. * provider unless either the time-out condition or the attempt succeeded.
  117. *
  118. * Inputs : none
  119. *
  120. * Outputs : BOOL : retunrs TRUE, if the I2CProvider is locked
  121. * Author : IKLEBANOV
  122. *^^*/
  123. BOOL CI2CScript::LockI2CProviderEx( void)
  124. {
  125. LARGE_INTEGER liTime, liOperationStartTime;
  126. liOperationStartTime.QuadPart = 0;
  127. while( !LockI2CProvider())
  128. {
  129. KeQuerySystemTime( &liTime);
  130. if( !liOperationStartTime.QuadPart)
  131. liOperationStartTime.QuadPart = liTime.QuadPart;
  132. else
  133. if( liTime.QuadPart - liOperationStartTime.QuadPart >
  134. I2CSCRIPT_TIMELIMIT_OPENPROVIDER)
  135. {
  136. // the time is expired - abort the initialization
  137. return( FALSE);
  138. }
  139. liTime.QuadPart = I2CSCRIPT_DELAY_OPENPROVIDER;
  140. KeDelayExecutionThread( KernelMode, FALSE, &liTime);
  141. }
  142. return( TRUE);
  143. }
  144. /*^^*
  145. * GetI2CProviderLockStatus()
  146. * Purpose : retrieves I2CProvider lock status
  147. *
  148. * Inputs : none
  149. *
  150. * Outputs : BOOL : retunrs TRUE, if the I2CProvider has been locked
  151. * Author : IKLEBANOV
  152. *^^*/
  153. BOOL CI2CScript::GetI2CProviderLockStatus( void)
  154. {
  155. return( m_dwI2CAccessKey);
  156. }
  157. /*^^*
  158. * ReleaseI2CProvider()
  159. * Purpose : releases the I2CProvider for other clients' use
  160. *
  161. * Inputs : none
  162. *
  163. * Outputs : BOOL : retunrs TRUE, if the I2CProvider is released
  164. * Author : IKLEBANOV
  165. *^^*/
  166. BOOL CI2CScript::ReleaseI2CProvider( void)
  167. {
  168. BOOL bResult;
  169. I2CControl i2cAccessBlock;
  170. bResult = FALSE;
  171. ENSURE
  172. {
  173. if(( m_i2cProviderInterface.i2cOpen == NULL) ||
  174. ( m_i2cProviderInterface.i2cAccess == NULL) ||
  175. ( m_pdoDriver == NULL))
  176. // the I2CProvider was not found
  177. FAIL;
  178. i2cAccessBlock.Status = I2C_STATUS_NOERROR;
  179. i2cAccessBlock.dwCookie = m_dwI2CAccessKey;
  180. i2cAccessBlock.ClockRate = m_ulI2CAccessClockRate;
  181. if( m_i2cProviderInterface.i2cOpen( m_pdoDriver, FALSE, &i2cAccessBlock) != STATUS_SUCCESS)
  182. {
  183. OutputDebugError(( "CI2CScript: ReleaseI2CProvider() bResult = %x\n", bResult));
  184. FAIL;
  185. }
  186. if( i2cAccessBlock.Status != I2C_STATUS_NOERROR)
  187. {
  188. OutputDebugError(( "CI2CScript: ReleaseI2CProvider() bResult = %x\n", bResult));
  189. FAIL;
  190. }
  191. m_dwI2CAccessKey = 0;
  192. bResult = TRUE;
  193. } END_ENSURE;
  194. return( bResult);
  195. }
  196. /*^^*
  197. * PerformI2CPacketOperation()
  198. * Purpose : synchronosly executes I2C access packet. It assumed to be executed at Low priority.
  199. * The function does not return until the I2C session is done. The execution
  200. * is not dependent on the I2C Provider lock status
  201. *
  202. * Inputs : PI2CPacket pI2CPacket : pointer to I2C access packet
  203. *
  204. * Outputs : BOOL : returns TRUE, if I2C operation was carried out successfuly
  205. * The error status is returned via uchI2CResult field of the PI2CPacket
  206. * Author : IKLEBANOV
  207. *^^*/
  208. BOOL CI2CScript::PerformI2CPacketOperation( IN OUT PI2CPacket pI2CPacket)
  209. {
  210. BOOL bResult;
  211. if( GetI2CProviderLockStatus())
  212. // the Provider was locked before and we're not going to change it
  213. bResult = ExecuteI2CPacket( pI2CPacket);
  214. else
  215. {
  216. // the Provider was not locked and it's our responsibility to lock it first,
  217. // execute I2C operation and release it after the use
  218. if( LockI2CProviderEx())
  219. {
  220. bResult = ExecuteI2CPacket( pI2CPacket);
  221. ReleaseI2CProvider();
  222. }
  223. else
  224. bResult = FALSE;
  225. }
  226. return( bResult);
  227. }
  228. /*^^*
  229. * ExecuteI2CPacket()
  230. * Purpose : synchronosly executes I2C access packet. It assumed to be executed at Low priority.
  231. * The function does not return until the I2C session is done. This kind of access
  232. * is used during initialization ( boot up) time only. This function should be
  233. * called only after the I2CProvider was locked for exclusive service
  234. *
  235. * Inputs : PI2CPacket pI2CPacket : pointer to I2C access packet
  236. *
  237. * Outputs : BOOL : returns TRUE, if I2C operation was carried out successfuly
  238. * The error status is returned via uchI2CResult field of the PI2CPacket
  239. * Author : IKLEBANOV
  240. *^^*/
  241. BOOL CI2CScript::ExecuteI2CPacket( IN OUT PI2CPacket pI2CPacket)
  242. {
  243. UINT nError, cbCount;
  244. UCHAR uchValue;
  245. UCHAR uchI2CResult = I2C_STATUS_ERROR;
  246. ENSURE
  247. {
  248. I2CControl i2cAccessBlock;
  249. if(( nError = CheckI2CScriptPacket( pI2CPacket)) != I2CSCRIPT_NOERROR)
  250. FAIL;
  251. // we'll use I2CProvider interface, assuming there is a syncronous provider
  252. // for asynchronous provider some work has to be added. 16 bits emulation is
  253. // not supported at this time either. This implementation does not support
  254. // Read-Modify-Write request either
  255. ENSURE
  256. {
  257. UINT nIndex;
  258. i2cAccessBlock.dwCookie = m_dwI2CAccessKey;
  259. i2cAccessBlock.ClockRate = m_ulI2CAccessClockRate;
  260. // We assume the last byte in the buffer belongs to the Write operation
  261. // after Read-Modify, is specified.
  262. cbCount = ( pI2CPacket->usFlags & I2COPERATION_READWRITE) ?
  263. ( pI2CPacket->cbWriteCount - 1) : ( pI2CPacket->cbWriteCount);
  264. if( cbCount)
  265. {
  266. // implement a write request
  267. // apply START condition with the I2C chip address first
  268. i2cAccessBlock.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK;
  269. i2cAccessBlock.Command = I2C_COMMAND_WRITE;
  270. i2cAccessBlock.Data = pI2CPacket->uchChipAddress & 0xFE;
  271. if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR)
  272. FAIL;
  273. i2cAccessBlock.Flags = I2C_FLAGS_ACK;
  274. for( nIndex = 0; nIndex < cbCount; nIndex ++)
  275. {
  276. // write the data from the buffer
  277. i2cAccessBlock.Data = pI2CPacket->puchWriteBuffer[nIndex];
  278. if(( nIndex == cbCount - 1) &&
  279. !( pI2CPacket->usFlags & I2COPERATION_RANDOMACCESS))
  280. // the last byte to write - apply STOP condition, if no
  281. // I2COPERATION_RANDOMACCESS flag is specified
  282. i2cAccessBlock.Flags |= I2C_FLAGS_STOP;
  283. if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR)
  284. break;
  285. }
  286. if( nIndex != cbCount)
  287. FAIL;
  288. /* // STOP condition is applied withe the last byte to be written
  289. // apply stop condition as the end of write operation
  290. i2cAccessBlock.Flags = I2C_FLAGS_STOP;
  291. i2cAccessBlock.Command = I2C_COMMAND_NULL;
  292. m_i2cProviderInterface.i2cAccess( m_pdoDriver, &i2cAccessBlock);
  293. */
  294. }
  295. if( pI2CPacket->cbReadCount)
  296. {
  297. // implement a read request
  298. // apply START condition with the I2C chip address first
  299. i2cAccessBlock.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK;
  300. i2cAccessBlock.Command = I2C_COMMAND_WRITE;
  301. i2cAccessBlock.Data = pI2CPacket->uchChipAddress | 0x01;
  302. if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR)
  303. FAIL;
  304. i2cAccessBlock.Flags = I2C_FLAGS_ACK;
  305. i2cAccessBlock.Command = I2C_COMMAND_READ;
  306. for( nIndex = 0; nIndex < pI2CPacket->cbReadCount; nIndex ++)
  307. {
  308. // read the data to the buffer
  309. if( nIndex == ( UINT)( pI2CPacket->cbReadCount - 1))
  310. {
  311. // don't apply ACK at the last read - read operation termination
  312. i2cAccessBlock.Flags &= ~I2C_FLAGS_ACK;
  313. // also apply STOP condition for the last byte
  314. i2cAccessBlock.Flags |= I2C_FLAGS_STOP;
  315. }
  316. if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR)
  317. break;
  318. pI2CPacket->puchReadBuffer[nIndex] = i2cAccessBlock.Data;
  319. }
  320. if( nIndex != pI2CPacket->cbReadCount)
  321. FAIL;
  322. /* // STOP condition is applied with the last byte to be read
  323. // apply stop condition as the end of read operation
  324. i2cAccessBlock.Flags = I2C_FLAGS_STOP;
  325. i2cAccessBlock.Command = I2C_COMMAND_NULL;
  326. m_i2cProviderInterface.i2cAccess( m_pdoDriver, &i2cAccessBlock);
  327. */
  328. if( pI2CPacket->usFlags & I2COPERATION_READWRITE)
  329. {
  330. // write operation should be taken care again, the last byte in the pbyWriteBuffer
  331. // should be constructed from the value read back and the binary operations OR and AND
  332. // with the values specified in the packet
  333. uchValue = pI2CPacket->puchReadBuffer[pI2CPacket->cbReadCount - 1];
  334. uchValue &= pI2CPacket->uchANDValue;
  335. pI2CPacket->puchWriteBuffer[pI2CPacket->cbWriteCount - 1] = uchValue | pI2CPacket->uchORValue;
  336. if( pI2CPacket->cbWriteCount)
  337. {
  338. // implement a write request
  339. // apply START condition with the I2C chip address first
  340. i2cAccessBlock.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK;
  341. i2cAccessBlock.Command = I2C_COMMAND_WRITE;
  342. i2cAccessBlock.Data = pI2CPacket->uchChipAddress & 0xFE;
  343. if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR)
  344. FAIL;
  345. i2cAccessBlock.Flags = I2C_FLAGS_ACK;
  346. for( nIndex = 0; nIndex < pI2CPacket->cbWriteCount; nIndex ++)
  347. {
  348. // write the data from the buffer
  349. i2cAccessBlock.Data = pI2CPacket->puchWriteBuffer[nIndex];
  350. if( nIndex == ( UINT)( pI2CPacket->cbWriteCount - 1))
  351. // the last byte to write - apply STOP condition
  352. i2cAccessBlock.Flags |= I2C_FLAGS_STOP;
  353. if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR)
  354. break;
  355. }
  356. if( nIndex != pI2CPacket->cbWriteCount)
  357. FAIL;
  358. /* // STOP condition is applied withe the last byte to be written
  359. // apply stop condition as the end of write operation
  360. i2cAccessBlock.Flags = I2C_FLAGS_STOP;
  361. i2cAccessBlock.Command = I2C_COMMAND_NULL;
  362. m_i2cProviderInterface.i2cAccess( m_pdoDriver, &i2cAccessBlock);
  363. */
  364. }
  365. }
  366. }
  367. uchI2CResult = I2C_STATUS_NOERROR;
  368. } END_ENSURE;
  369. if( uchI2CResult == I2C_STATUS_ERROR)
  370. {
  371. // there was an error during accessing I2C - issue Reset command
  372. i2cAccessBlock.Command = I2C_COMMAND_RESET;
  373. AccessI2CProvider( m_pdoDriver, &i2cAccessBlock);
  374. }
  375. pI2CPacket->uchI2CResult = uchI2CResult;
  376. return( TRUE);
  377. } END_ENSURE;
  378. OutputDebugTrace(( "CI2CScript:ExecuteI2CPacket() nError = %x", nError));
  379. return( FALSE);
  380. }
  381. /*^^*
  382. * CheckI2CScriptPacket()
  383. * Purpose : checks integrity of the I2C control package
  384. *
  385. * Inputs : PI2CPacket pI2CPacket : pointer to I2C access packet
  386. *
  387. * Outputs : BOOL : returns TRUE, if I2C control package is a valid one
  388. *
  389. * Author : IKLEBANOV
  390. *^^*/
  391. UINT CI2CScript::CheckI2CScriptPacket( IN PI2CPacket pI2CPacket)
  392. {
  393. UINT nPacketError;
  394. ENSURE
  395. {
  396. if(( m_i2cProviderInterface.i2cOpen == NULL) ||
  397. ( m_i2cProviderInterface.i2cAccess == NULL) ||
  398. ( m_pdoDriver == NULL))
  399. {
  400. // the I2CProvider was not found
  401. nPacketError = I2CSCRIPT_ERROR_NOPROVIDER;
  402. FAIL;
  403. }
  404. if(( !pI2CPacket->cbWriteCount) && ( !pI2CPacket->cbReadCount))
  405. {
  406. // nothing to do
  407. nPacketError = I2CSCRIPT_ERROR_NODATA;
  408. FAIL;
  409. }
  410. if((( pI2CPacket->cbWriteCount) && ( pI2CPacket->puchWriteBuffer == NULL))
  411. || (( pI2CPacket->cbReadCount) && ( pI2CPacket->puchReadBuffer == NULL)))
  412. {
  413. // NULL pointer, when the data is specified
  414. nPacketError = I2CSCRIPT_ERROR_NOBUFFER;
  415. FAIL;
  416. }
  417. if(( pI2CPacket->usFlags & I2COPERATION_READWRITE) && ( !pI2CPacket->cbWriteCount))
  418. {
  419. // if Read-Modify-Write is specified, the Write data should be present
  420. nPacketError = I2CSCRIPT_ERROR_READWRITE;
  421. FAIL;
  422. }
  423. nPacketError = I2CSCRIPT_NOERROR;
  424. } END_ENSURE;
  425. return( nPacketError);
  426. }
  427. /*^^*
  428. * ClearScript()
  429. * Purpose : clears I2CScript to the NULL state - no I2C operations are on hold.
  430. *
  431. * Inputs : none
  432. *
  433. * Outputs : none
  434. * Author : IKLEBANOV
  435. *^^*/
  436. void CI2CScript::ClearScript( void)
  437. {
  438. m_nExecutionIndex = 0;
  439. m_nScriptLength = 0;
  440. m_pfnReturnWhenDone = NULL;
  441. m_bExecutionInProcess = FALSE;
  442. }
  443. /*^^*
  444. * AppendToScript()
  445. * Purpose : appends a I2CPacket to the bottom of the I2CScript.
  446. * The 16 bits emulation is not implemented at this time.
  447. *
  448. * Inputs : PI2CPacket pI2CPacket - pointer to the I2C packet to append
  449. *
  450. * Outputs : BOOL : returns TRUE, if the packet was successfully appended.
  451. * FALSE might happend if the I2CPacket is a bad one, or overflow occurs
  452. * Author : IKLEBANOV
  453. *^^*/
  454. BOOL CI2CScript::AppendToScript( PI2CPacket pI2CPacket)
  455. {
  456. UINT nError, nScriptIndex;
  457. UINT nIndex, cbCount;
  458. ENSURE
  459. {
  460. PI2CScriptPrimitive pI2CPrimitive;
  461. if(( nError = CheckI2CScriptPacket( pI2CPacket)) != I2CSCRIPT_NOERROR)
  462. FAIL;
  463. nError = I2CSCRIPT_ERROR_OVERFLOW;
  464. // m_nExecutionIndex is used as a Script build index. We will work with a local copy of it
  465. // first to ensure we have no overflow
  466. nScriptIndex = m_nExecutionIndex;
  467. pI2CPrimitive = &m_i2cScript[nScriptIndex];
  468. // We assume the last byte in the buffer belongs to the Write operation
  469. // after Read-Modify, is specified.
  470. cbCount = ( pI2CPacket->usFlags & I2COPERATION_READWRITE) ? \
  471. ( pI2CPacket->cbWriteCount - 1) : ( pI2CPacket->cbWriteCount);
  472. if( cbCount)
  473. {
  474. // I2C Chip address should be taken care of first
  475. pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE;
  476. pI2CPrimitive->byData = pI2CPacket->uchChipAddress;
  477. pI2CPrimitive->byANDData = 0xFE;
  478. pI2CPrimitive->byORData = 0x00;
  479. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_START | I2C_FLAGS_ACK;
  480. pI2CPrimitive->byFlags = 0x0;
  481. // check the Script length
  482. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  483. FAIL;
  484. pI2CPrimitive ++;
  485. // I2C write buffer should be taken care of.
  486. for( nIndex = 0; nIndex < cbCount; nIndex ++)
  487. {
  488. pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE;
  489. pI2CPrimitive->byData = pI2CPacket->puchWriteBuffer[nIndex];
  490. pI2CPrimitive->byORData = 0x00;
  491. pI2CPrimitive->byANDData = 0xFF;
  492. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_ACK;
  493. pI2CPrimitive->byFlags = 0x0;
  494. if( nIndex == cbCount - 1)
  495. // this is the last byte to be written - apply STOP
  496. pI2CPrimitive->ulProviderFlags |= I2C_FLAGS_STOP;
  497. // check the Script length
  498. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  499. break;
  500. pI2CPrimitive ++;
  501. }
  502. // check the Script length
  503. if( nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  504. FAIL;
  505. /*
  506. // Stop condition is applied with the last byte to be written
  507. // We finished Write portion here, whether it's a Write only, Read-Modify-Write operation
  508. pI2CPrimitive->ulCommand = I2C_COMMAND_NULL;
  509. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP;
  510. pI2CPrimitive->byFlags = 0x0;
  511. // check the Script length
  512. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  513. FAIL;
  514. pI2CPrimitive ++;
  515. */
  516. }
  517. // We have to see, if there is a Read operation involved
  518. if( pI2CPacket->cbReadCount)
  519. {
  520. // I2C Chip address should be taken care of first
  521. pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE;
  522. pI2CPrimitive->byData = pI2CPacket->uchChipAddress;
  523. pI2CPrimitive->byANDData = 0xFE;
  524. pI2CPrimitive->byORData = 0x01;
  525. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_START | I2C_FLAGS_ACK;
  526. pI2CPrimitive->byFlags = 0x0;
  527. // check the Script length
  528. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  529. FAIL;
  530. pI2CPrimitive ++;
  531. // I2C read buffer should be taken care of. We assume the last byte in the buffer belongs to
  532. // the Write operation after Read-Modify, is specified.
  533. for( nIndex = 0; nIndex < pI2CPacket->cbReadCount; nIndex ++)
  534. {
  535. pI2CPrimitive->ulCommand = I2C_COMMAND_READ;
  536. if( nIndex == ( UINT)( pI2CPacket->cbReadCount - 1))
  537. {
  538. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP;
  539. pI2CPrimitive->byFlags = pI2CPacket->usFlags & I2COPERATION_READWRITE;
  540. }
  541. else
  542. {
  543. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_ACK;
  544. pI2CPrimitive->byFlags = 0x0;
  545. }
  546. // check the Script length
  547. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  548. break;
  549. pI2CPrimitive ++;
  550. }
  551. // check the Script length
  552. if( nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  553. FAIL;
  554. /* // Stop condition is applied with the last byte to be read
  555. // We finished Read portion here, whether it's a Read only, Read-Modify-Write operation
  556. pI2CPrimitive->ulCommand = I2C_COMMAND_NULL;
  557. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP;
  558. pI2CPrimitive->byFlags = 0x0;
  559. // check the Script length
  560. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  561. FAIL;
  562. pI2CPrimitive ++;
  563. */
  564. }
  565. // the last thing left to do, is to implement Write after Read-Modify, if specified
  566. if( pI2CPacket->usFlags & I2COPERATION_READWRITE)
  567. {
  568. // I2C Chip address should be taken care of first
  569. pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE;
  570. pI2CPrimitive->byData = pI2CPacket->uchChipAddress;
  571. pI2CPrimitive->byANDData = 0xFE;
  572. pI2CPrimitive->byORData = 0x00;
  573. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_START | I2C_FLAGS_ACK;
  574. pI2CPrimitive->byFlags = 0x0;
  575. // check the Script length
  576. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  577. FAIL;
  578. pI2CPrimitive ++;
  579. // I2C write buffer should be taken care of.
  580. for( nIndex = 0; nIndex < pI2CPacket->cbWriteCount; nIndex ++)
  581. {
  582. pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE;
  583. pI2CPrimitive->byData = pI2CPacket->puchWriteBuffer[nIndex];
  584. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_ACK;
  585. if( nIndex == ( UINT)( pI2CPacket->cbWriteCount - 1))
  586. {
  587. // it's time to write the byte modified after the Read operation
  588. pI2CPrimitive->byORData = pI2CPacket->uchORValue;
  589. pI2CPrimitive->byANDData = pI2CPacket->uchANDValue;
  590. pI2CPrimitive->byFlags = I2COPERATION_READWRITE;
  591. // apply STOP condition with the last byte to be read
  592. pI2CPrimitive->ulProviderFlags |= I2C_FLAGS_STOP;
  593. }
  594. else
  595. {
  596. pI2CPrimitive->byORData = 0x00;
  597. pI2CPrimitive->byANDData = 0xFF;
  598. pI2CPrimitive->byFlags = 0x0;
  599. }
  600. // check the Script length
  601. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  602. break;
  603. pI2CPrimitive ++;
  604. }
  605. // check the Script length
  606. if( nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  607. FAIL;
  608. /* // Stop condition is applied with the last byte to be written
  609. // We finished Write portion here, whether it's a Write only, Read-Modify-Write operation
  610. pI2CPrimitive->ulCommand = I2C_COMMAND_NULL;
  611. pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP;
  612. pI2CPrimitive->byFlags = 0x0;
  613. // check the Script length
  614. if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM)
  615. FAIL;
  616. pI2CPrimitive ++;
  617. */
  618. }
  619. // the Packet was added succesfully to the Script. Modify the Script propertirs
  620. m_nExecutionIndex = nScriptIndex;
  621. m_nScriptLength = nScriptIndex;
  622. return( TRUE);
  623. } END_ENSURE;
  624. OutputDebugTrace(( "CI2CScript:AppendToScript() nError = %x", nError));
  625. return( FALSE);
  626. }
  627. /*^^*
  628. * ExecuteScript()
  629. * Purpose : triggers the execution of previously built I2CScript. This function is also
  630. * responsible for allocating I2CProvider for its own exclusive use.
  631. *
  632. * Inputs : PHW_STREAM_REQUEST_BLOCK pSrb : pointer to the current SRB
  633. * PHWCompletionRoutine pfnScriptCompletion: function pointer will be called,
  634. * when the script execution is completed. Indicates the Script execution
  635. * is to be carried out asynchronously.
  636. *
  637. * Outputs : BOOL : returns TRUE, if the execution was successfully triggered.
  638. * FALSE might happend if the Script has not been built by the time of the call
  639. *
  640. * Note : if pfnScriptExecuted is NULL pointer, the Script will be executed synchronously
  641. *
  642. * Author : IKLEBANOV
  643. *^^*/
  644. BOOL CI2CScript::ExecuteScript( IN PHW_STREAM_REQUEST_BLOCK pSrb,
  645. IN PHWCompletionRoutine pfnScriptCompletion)
  646. {
  647. ENSURE
  648. {
  649. if( pfnScriptCompletion != NULL)
  650. // not supported at this point. The idea is to create a new system thread,
  651. // where the Script to be executed. When the Script will be copleted,
  652. // call-back is called and the thred terminates itself.
  653. FAIL;
  654. if( !m_nExecutionIndex)
  655. FAIL;
  656. // there is not a NULL Script - proceed
  657. m_nScriptLength = m_nExecutionIndex;
  658. m_nExecutionIndex = m_nCompletionIndex = 0;
  659. if( !GetI2CProviderLockStatus())
  660. // The provider was not locked prior the Script execution
  661. if( !LockI2CProviderEx())
  662. FAIL;
  663. InterpreterScript();
  664. ReleaseI2CProvider();
  665. return( TRUE);
  666. } END_ENSURE;
  667. return( FALSE);
  668. }
  669. /*^^*
  670. * InterpreterScript()
  671. * Purpose : interpreters the I2CScript line by line. The Script is not cleaned up
  672. * after the completion to allow to client retrive the results of
  673. * the script execution. It's the client responsibility to clean it up
  674. * upon the results retrieving
  675. *
  676. * Inputs : none
  677. * Outputs : none
  678. *
  679. * Author : IKLEBANOV
  680. *^^*/
  681. void CI2CScript::InterpreterScript( void)
  682. {
  683. UINT nScriptIndex, nIndex;
  684. I2CControl i2cAccessBlock;
  685. m_bExecutionInProcess = TRUE;
  686. i2cAccessBlock.dwCookie = m_dwI2CAccessKey;
  687. i2cAccessBlock.ClockRate = m_ulI2CAccessClockRate;
  688. // We'll interpreter every line of the Script and call the I2C Provider to
  689. // execute it. It's assumed the I2CProvider is a syncronous one. If it's not the
  690. // case, the special care should be taken of based upon returned value I2C_STATUS_BUSY
  691. // in the Status.
  692. for( nScriptIndex = 0; nScriptIndex < m_nScriptLength; nScriptIndex ++)
  693. {
  694. i2cAccessBlock.Command = m_i2cScript[nScriptIndex].ulCommand;
  695. i2cAccessBlock.Flags = m_i2cScript[nScriptIndex].ulProviderFlags;
  696. if( i2cAccessBlock.Command == I2C_COMMAND_WRITE)
  697. {
  698. i2cAccessBlock.Data = m_i2cScript[nScriptIndex].byData;
  699. i2cAccessBlock.Data &= m_i2cScript[nScriptIndex].byANDData;
  700. i2cAccessBlock.Data |= m_i2cScript[nScriptIndex].byORData;
  701. }
  702. if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) == I2C_STATUS_ERROR)
  703. break;
  704. // check, wether it's a Read operation - save result
  705. if( i2cAccessBlock.Command == I2C_COMMAND_READ)
  706. {
  707. m_i2cScript[nScriptIndex].byData = i2cAccessBlock.Data;
  708. // check, if this data belongs to Read-Modify-Write operation
  709. if( m_i2cScript[nScriptIndex].byFlags & I2COPERATION_READWRITE)
  710. {
  711. // let's look for the next I2COPERATION_READWRITE flag - it is the pair
  712. for( nIndex = nScriptIndex; nIndex < m_nScriptLength; nIndex ++)
  713. if(( m_i2cScript[nIndex].ulCommand == I2C_COMMAND_WRITE) &&
  714. ( m_i2cScript[nIndex].byFlags & I2COPERATION_READWRITE))
  715. break;
  716. if( nIndex >= m_nScriptLength)
  717. // the Script got corrupted
  718. break;
  719. m_i2cScript[nIndex].byData = i2cAccessBlock.Data;
  720. }
  721. }
  722. }
  723. m_nCompletionIndex = nScriptIndex;
  724. m_bExecutionInProcess = FALSE;
  725. }
  726. /*^^*
  727. * AccessI2CProvider()
  728. * Purpose : provide synchronous type of access to I2CProvider
  729. *
  730. * Inputs : PDEVICE_OBJECT pdoDriver : pointer to the client's device object
  731. * PI2CControl pi2cAccessBlock : pointer to a composed I2C access block
  732. *
  733. * Outputs : UINT : status of the I2C operation I2C_STATUS_NOERROR or I2C_STATUS_ERROR
  734. *
  735. * Author : IKLEBANOV
  736. *^^*/
  737. UINT CI2CScript::AccessI2CProvider( PDEVICE_OBJECT pdoClient, PI2CControl pi2cAccessBlock)
  738. {
  739. UINT uiStatus;
  740. LARGE_INTEGER liTime;
  741. do
  742. {
  743. // this loop is infinitive. It has to be taken care of
  744. if( m_i2cProviderInterface.i2cAccess( pdoClient, pi2cAccessBlock) != STATUS_SUCCESS)
  745. {
  746. uiStatus = I2C_STATUS_ERROR;
  747. break;
  748. }
  749. if( pi2cAccessBlock->Status != I2C_STATUS_BUSY)
  750. {
  751. uiStatus = pi2cAccessBlock->Status;
  752. break;
  753. }
  754. liTime.QuadPart = I2CSCRIPT_DELAY_GETPROVIDERSTATUS;
  755. ::KeDelayExecutionThread( KernelMode, FALSE, &liTime);
  756. pi2cAccessBlock->Command = I2C_COMMAND_STATUS;
  757. } while( TRUE);
  758. return( uiStatus);
  759. }
  760. /*^^*
  761. * GetScriptResults()
  762. * Purpose : returns result of the executed Script
  763. * This function idealy is called twice:
  764. * first time with the puchReadBuffer = NULL to retrive the number of bytes read
  765. * second time - to fill in the pointer
  766. * Inputs : PUINT puiReadCount : pointer to the counter of the bytes were read
  767. * PUCH puchReadBuffer : pointer to the buffer to put the data
  768. *
  769. * Outputs : UINT : status of the I2C operation
  770. * If the status is I2C_STATUS_ERROR, puiReadCount will contain the step, where
  771. * I2CScript failed
  772. * Author : IKLEBANOV
  773. *^^*/
  774. UINT CI2CScript::GetScriptResults( PUINT puiReadCount, PUCHAR puchReadBuffer)
  775. {
  776. UINT nScriptIndex, nCount;
  777. ASSERT( puiReadCount != NULL);
  778. if( m_bExecutionInProcess)
  779. return( I2C_STATUS_BUSY);
  780. if( m_nScriptLength != m_nCompletionIndex)
  781. {
  782. // if the case of failure, step where I2CScript failed is return
  783. // instead of Read Counter. The returned status indicates the
  784. // failure
  785. * puiReadCount = m_nCompletionIndex;
  786. return( I2C_STATUS_ERROR);
  787. }
  788. else
  789. {
  790. nCount = 0;
  791. for( nScriptIndex = 0; nScriptIndex < m_nCompletionIndex; nScriptIndex ++)
  792. {
  793. if( m_i2cScript[nScriptIndex].ulCommand == I2C_COMMAND_READ)
  794. {
  795. if( puchReadBuffer != NULL)
  796. // fill in the supplied buffer
  797. puchReadBuffer[nCount] = m_i2cScript[nScriptIndex].byData;
  798. nCount ++;
  799. }
  800. }
  801. * puiReadCount = nCount;
  802. return( I2C_STATUS_NOERROR);
  803. }
  804. }
  805. /*^^*
  806. * InitializeAttachI2CProvider()
  807. * Purpose : gets the pointer to the parent I2C Provider interface using
  808. * several IRP_MJ_??? functions.
  809. * This function will be called at Low priority
  810. *
  811. * Inputs : I2CINTERFACE * pI2CInterface : pointer to the Interface to be filled in
  812. * PDEVICE_OBJECT pDeviceObject : MiniDriver device object, which is a child of I2C Master
  813. *
  814. * Outputs : BOOL - returns TRUE, if the interface was found
  815. * Author : IKLEBANOV
  816. *^^*/
  817. BOOL CI2CScript::InitializeAttachI2CProvider( I2CINTERFACE * pI2CInterface, PDEVICE_OBJECT pDeviceObject)
  818. {
  819. BOOL bResult;
  820. bResult = LocateAttachI2CProvider( pI2CInterface, pDeviceObject, IRP_MJ_PNP);
  821. if(( pI2CInterface->i2cOpen == NULL) || ( pI2CInterface->i2cAccess == NULL))
  822. {
  823. TRAP;
  824. OutputDebugError(( "CI2CScript(): interface has NULL pointers\n"));
  825. bResult = FALSE;
  826. }
  827. return( bResult);
  828. }
  829. /*^^*
  830. * LocateAttachI2CProvider()
  831. * Purpose : gets the pointer to the parent I2C Provider interface
  832. * This function will be called at Low priority
  833. *
  834. * Inputs : I2CINTERFACE * pI2CInterface : pointer to the Interface to be filled in
  835. * PDEVICE_OBJECT pDeviceObject : MiniDriver device object, which is a child of I2C Master
  836. * int nIrpMajorFunction : IRP major function to query the I2C Interface
  837. *
  838. * Outputs : BOOL - returns TRUE, if the interface was found
  839. * Author : IKLEBANOV
  840. *^^*/
  841. BOOL CI2CScript::LocateAttachI2CProvider( I2CINTERFACE * pI2CInterface, PDEVICE_OBJECT pDeviceObject, int nIrpMajorFunction)
  842. {
  843. PIRP pIrp;
  844. BOOL bResult = FALSE;
  845. ENSURE
  846. {
  847. PIO_STACK_LOCATION pNextStack;
  848. NTSTATUS ntStatus;
  849. KEVENT Event;
  850. pIrp = IoAllocateIrp( pDeviceObject->StackSize, FALSE);
  851. if( pIrp == NULL)
  852. {
  853. TRAP;
  854. OutputDebugError(( "CI2CScript(): can not allocate IRP\n"));
  855. FAIL;
  856. }
  857. pNextStack = IoGetNextIrpStackLocation( pIrp);
  858. if( pNextStack == NULL)
  859. {
  860. TRAP;
  861. OutputDebugError(( "CI2CScript(): can not allocate NextStack\n"));
  862. FAIL;
  863. }
  864. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  865. pNextStack->MajorFunction = (UCHAR)nIrpMajorFunction;
  866. pNextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  867. KeInitializeEvent( &Event, NotificationEvent, FALSE);
  868. IoSetCompletionRoutine( pIrp,
  869. I2CScriptIoSynchCompletionRoutine,
  870. &Event, TRUE, TRUE, TRUE);
  871. pNextStack->Parameters.QueryInterface.InterfaceType = ( struct _GUID *)&GUID_I2C_INTERFACE;
  872. pNextStack->Parameters.QueryInterface.Size = sizeof( I2CINTERFACE);
  873. pNextStack->Parameters.QueryInterface.Version = 1;
  874. pNextStack->Parameters.QueryInterface.Interface = ( PINTERFACE)pI2CInterface;
  875. pNextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  876. ntStatus = IoCallDriver( pDeviceObject, pIrp);
  877. if( ntStatus == STATUS_PENDING)
  878. KeWaitForSingleObject( &Event,
  879. Suspended, KernelMode, FALSE, NULL);
  880. if(( pI2CInterface->i2cOpen == NULL) || ( pI2CInterface->i2cAccess == NULL))
  881. FAIL;
  882. bResult = TRUE;
  883. } END_ENSURE;
  884. if( pIrp != NULL)
  885. IoFreeIrp( pIrp);
  886. return( bResult);
  887. }
  888. /*^^*
  889. * I2CScriptIoSynchCompletionRoutine()
  890. * Purpose : This routine is for use with synchronous IRP processing.
  891. * All it does is signal an event, so the driver knows it and can continue.
  892. *
  893. * Inputs : PDEVICE_OBJECT DriverObject : Pointer to driver object created by system
  894. * PIRP pIrp : Irp that just completed
  895. * PVOID Event : Event we'll signal to say Irp is done
  896. *
  897. * Outputs : none
  898. * Author : IKLEBANOV
  899. *^^*/
  900. extern "C"
  901. NTSTATUS I2CScriptIoSynchCompletionRoutine( IN PDEVICE_OBJECT pDeviceObject,
  902. IN PIRP pIrp,
  903. IN PVOID Event)
  904. {
  905. KeSetEvent(( PKEVENT)Event, 0, FALSE);
  906. return( STATUS_MORE_PROCESSING_REQUIRED);
  907. }