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.

515 lines
13 KiB

  1. /*++
  2. Copyright (c) 1990-2001 Microsoft Corporation
  3. Module Name:
  4. i2c2.c
  5. Abstract:
  6. This is the NT Video port I2C helper code for interface version 2.
  7. Author:
  8. Michael Maciesowicz (mmacie) 23-Apr-2001
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. --*/
  13. #include "videoprt.h"
  14. //
  15. // Define constants used by I2C.
  16. //
  17. #define I2C_START_RETRIES 10
  18. #define I2C_SCL_READ_RETRIES 10
  19. #define I2C_DELAY(pI2CControl) DELAY_MICROSECONDS((pI2CControl)->I2CDelay / 10)
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text (PAGE, I2CStart2)
  22. #pragma alloc_text (PAGE, I2CStop2)
  23. #pragma alloc_text (PAGE, I2CWrite2)
  24. #pragma alloc_text (PAGE, I2CRead2)
  25. #pragma alloc_text (PAGE, I2CWriteByte2)
  26. #pragma alloc_text (PAGE, I2CReadByte2)
  27. #pragma alloc_text (PAGE, I2CWaitForClockLineHigh2)
  28. #endif // ALLOC_PRAGMA
  29. //
  30. // Routines exported via VideoPortQueryServices().
  31. //
  32. BOOLEAN
  33. I2CStart2(
  34. IN PVOID pHwDeviceExtension,
  35. IN PVIDEO_I2C_CONTROL pI2CControl
  36. )
  37. /*++
  38. Routine Description:
  39. This routine starts I2C communication.
  40. Arguments:
  41. pHwDeviceExtension - Points to per-adapter device extension.
  42. pI2CControl - I2C hardware specific functions.
  43. Returns:
  44. TRUE - Start OK.
  45. FALSE - Start failed.
  46. --*/
  47. {
  48. ULONG ulRetry;
  49. PAGED_CODE();
  50. ASSERT(NULL != pHwDeviceExtension);
  51. ASSERT(NULL != pI2CControl);
  52. ASSERT(NULL != pI2CControl->WriteClockLine);
  53. ASSERT(NULL != pI2CControl->WriteDataLine);
  54. ASSERT(NULL != pI2CControl->ReadClockLine);
  55. ASSERT(NULL != pI2CControl->ReadDataLine);
  56. ASSERT(IS_HW_DEVICE_EXTENSION(pHwDeviceExtension) == TRUE);
  57. //
  58. // The I2C communications start signal is a SDA high->low while the SCL is high.
  59. //
  60. for (ulRetry = 0; ulRetry <= I2C_START_RETRIES; ulRetry++)
  61. {
  62. pI2CControl->WriteDataLine(pHwDeviceExtension, 1); // Set SDA high
  63. I2C_DELAY(pI2CControl);
  64. if (pI2CControl->ReadDataLine(pHwDeviceExtension) == FALSE) // SDA didn't take - ulRetry
  65. continue;
  66. pI2CControl->WriteClockLine(pHwDeviceExtension, 1); // Set SCL high
  67. I2C_DELAY(pI2CControl);
  68. if (I2CWaitForClockLineHigh2(pHwDeviceExtension, pI2CControl) == FALSE)
  69. {
  70. pVideoDebugPrint((Warn, "VIDEOPRT: I2CStart2: SCL didn't take\n"));
  71. break;
  72. }
  73. pI2CControl->WriteDataLine(pHwDeviceExtension, 0); // Set SDA low
  74. I2C_DELAY(pI2CControl);
  75. pI2CControl->WriteClockLine(pHwDeviceExtension, 0); // Set SCL low
  76. I2C_DELAY(pI2CControl);
  77. return TRUE;
  78. }
  79. pVideoDebugPrint((Warn, "VIDEOPRT: I2CStart2: Failed\n"));
  80. return FALSE;
  81. } // I2CStart2()
  82. BOOLEAN
  83. I2CStop2(
  84. IN PVOID pHwDeviceExtension,
  85. IN PVIDEO_I2C_CONTROL pI2CControl
  86. )
  87. /*++
  88. Routine Description:
  89. This routine stops I2C communication.
  90. Arguments:
  91. pHwDeviceExtension - Points to per-adapter device extension.
  92. pI2CControl - I2C hardware specific functions.
  93. Returns:
  94. TRUE - Stop OK.
  95. FALSE - Stop failed.
  96. --*/
  97. {
  98. PAGED_CODE();
  99. ASSERT(NULL != pHwDeviceExtension);
  100. ASSERT(NULL != pI2CControl);
  101. ASSERT(NULL != pI2CControl->WriteClockLine);
  102. ASSERT(NULL != pI2CControl->WriteDataLine);
  103. ASSERT(NULL != pI2CControl->ReadClockLine);
  104. ASSERT(NULL != pI2CControl->ReadDataLine);
  105. ASSERT(IS_HW_DEVICE_EXTENSION(pHwDeviceExtension) == TRUE);
  106. //
  107. // The I2C communications stop signal is a SDA low->high while the SCL is high.
  108. //
  109. pI2CControl->WriteDataLine(pHwDeviceExtension, 0); // Set SDA low
  110. I2C_DELAY(pI2CControl);
  111. pI2CControl->WriteClockLine(pHwDeviceExtension, 1); // Set SCL high
  112. I2C_DELAY(pI2CControl);
  113. if (I2CWaitForClockLineHigh2(pHwDeviceExtension, pI2CControl) == FALSE)
  114. {
  115. pVideoDebugPrint((Warn, "VIDEOPRT: I2CStop2: SCL didn't take\n"));
  116. return FALSE;
  117. }
  118. pI2CControl->WriteDataLine(pHwDeviceExtension, 1); // Set SDA high
  119. I2C_DELAY(pI2CControl);
  120. if (pI2CControl->ReadDataLine(pHwDeviceExtension) != 1)
  121. {
  122. pVideoDebugPrint((Warn, "VIDEOPRT: I2CStop2: SDA didn't take\n"));
  123. return FALSE;
  124. }
  125. return TRUE;
  126. } // I2CStop2()
  127. BOOLEAN
  128. I2CWrite2(
  129. IN PVOID pHwDeviceExtension,
  130. IN PVIDEO_I2C_CONTROL pI2CControl,
  131. IN PUCHAR pucBuffer,
  132. IN ULONG ulLength
  133. )
  134. /*++
  135. Routine Description:
  136. This routine writes data over the I2C channel.
  137. Arguments:
  138. pHwDeviceExtension - Points to per-adapter device extension.
  139. pI2CControl - I2C hardware specific functions.
  140. pucBuffer - Points to data to be written.
  141. ulLength - Number of bytes to write.
  142. Returns:
  143. TRUE - Write OK.
  144. FALSE - Write failed.
  145. --*/
  146. {
  147. ULONG ulCount;
  148. PAGED_CODE();
  149. ASSERT(NULL != pHwDeviceExtension);
  150. ASSERT(NULL != pI2CControl);
  151. ASSERT(NULL != pucBuffer);
  152. ASSERT(NULL != pI2CControl->WriteClockLine);
  153. ASSERT(NULL != pI2CControl->WriteDataLine);
  154. ASSERT(NULL != pI2CControl->ReadClockLine);
  155. ASSERT(NULL != pI2CControl->ReadDataLine);
  156. ASSERT(IS_HW_DEVICE_EXTENSION(pHwDeviceExtension) == TRUE);
  157. for (ulCount = 0; ulCount < ulLength; ulCount++)
  158. {
  159. if (I2CWriteByte2(pHwDeviceExtension, pI2CControl, pucBuffer[ulCount]) == FALSE)
  160. {
  161. return FALSE;
  162. }
  163. }
  164. return TRUE;
  165. } // I2CWrite2()
  166. BOOLEAN
  167. I2CRead2(
  168. IN PVOID pHwDeviceExtension,
  169. IN PVIDEO_I2C_CONTROL pI2CControl,
  170. OUT PUCHAR pucBuffer,
  171. IN ULONG ulLength,
  172. IN BOOLEAN bEndOfRead
  173. )
  174. /*++
  175. Routine Description:
  176. This routine reads data over the I2C channel.
  177. Arguments:
  178. pHwDeviceExtension - Points to per-adapter device extension.
  179. pI2CControl - I2C hardware specific functions.
  180. pucBuffer - Points to storage for data.
  181. ulLength - Number of bytes to read.
  182. bEndOfRead - Indicates end of read requests so we can send NAK.
  183. Returns:
  184. TRUE - Read OK.
  185. FALSE - Read failed.
  186. --*/
  187. {
  188. ULONG ulCount;
  189. PAGED_CODE();
  190. ASSERT(NULL != pHwDeviceExtension);
  191. ASSERT(NULL != pI2CControl);
  192. ASSERT(NULL != pucBuffer);
  193. ASSERT(NULL != pI2CControl->WriteClockLine);
  194. ASSERT(NULL != pI2CControl->WriteDataLine);
  195. ASSERT(NULL != pI2CControl->ReadClockLine);
  196. ASSERT(NULL != pI2CControl->ReadDataLine);
  197. ASSERT(IS_HW_DEVICE_EXTENSION(pHwDeviceExtension) == TRUE);
  198. //
  199. // On all but the last byte, we must send an ACK in order to ensure that the sending device will
  200. // send subsequent data bytes. On the last byte, we must send a NAK so that it will shut up.
  201. //
  202. for (ulCount = 0; ulCount < ulLength; ulCount++)
  203. {
  204. if ((ulLength - 1 == ulCount && bEndOfRead))
  205. {
  206. if (I2CReadByte2(pHwDeviceExtension, pI2CControl, pucBuffer + ulCount, TRUE) == FALSE) // Last byte
  207. {
  208. return FALSE;
  209. }
  210. }
  211. else
  212. {
  213. if (I2CReadByte2(pHwDeviceExtension, pI2CControl, pucBuffer + ulCount, FALSE) == FALSE)
  214. {
  215. return FALSE;
  216. }
  217. }
  218. }
  219. return TRUE;
  220. } // I2CRead2()
  221. //
  222. // Local routines.
  223. //
  224. BOOLEAN
  225. I2CWriteByte2(
  226. IN PVOID pHwDeviceExtension,
  227. IN PVIDEO_I2C_CONTROL pI2CControl,
  228. IN UCHAR ucByte
  229. )
  230. /*++
  231. Routine Description:
  232. This routine writes byte over the I2C channel.
  233. Arguments:
  234. pHwDeviceExtension - Points to per-adapter device extension.
  235. pI2CControl - I2C hardware specific functions.
  236. ucByte - Byte to write.
  237. Returns:
  238. TRUE - Write OK.
  239. FALSE - Write failed.
  240. --*/
  241. {
  242. LONG lShift;
  243. UCHAR ucAck;
  244. PAGED_CODE();
  245. ASSERT(NULL != pHwDeviceExtension);
  246. ASSERT(NULL != pI2CControl);
  247. //
  248. // Bits are transmitted serially starting with the MSB.
  249. //
  250. for (lShift = 7; lShift >= 0; lShift--)
  251. {
  252. //
  253. // Transmitt data bit.
  254. //
  255. pI2CControl->WriteDataLine(pHwDeviceExtension, (UCHAR)((ucByte >> lShift) & 0x01)); // Set SDA
  256. I2C_DELAY(pI2CControl);
  257. //
  258. // After each data bit we must send high->low SCL pulse.
  259. //
  260. pI2CControl->WriteClockLine(pHwDeviceExtension, 1); // Set SCL high
  261. I2C_DELAY(pI2CControl);
  262. if (I2CWaitForClockLineHigh2(pHwDeviceExtension, pI2CControl) == FALSE)
  263. {
  264. pVideoDebugPrint((Warn, "VIDEOPRT: I2CWriteByte2: SCL didn't take\n"));
  265. return FALSE;
  266. }
  267. pI2CControl->WriteClockLine(pHwDeviceExtension, 0); // Set SCL low
  268. I2C_DELAY(pI2CControl);
  269. }
  270. //
  271. // The monitor sends ACK by preventing the SDA from going high after the clock pulse we use
  272. // to send our last data bit. If the SDA goes high after this bit, it is a NAK from the monitor.
  273. //
  274. pI2CControl->WriteDataLine(pHwDeviceExtension, 1); // Set SDA high
  275. I2C_DELAY(pI2CControl);
  276. pI2CControl->WriteClockLine(pHwDeviceExtension, 1); // Set SCL high
  277. I2C_DELAY(pI2CControl);
  278. if (I2CWaitForClockLineHigh2(pHwDeviceExtension, pI2CControl) == FALSE)
  279. {
  280. pVideoDebugPrint((Warn, "VIDEOPRT: I2CWriteByte2: SCL didn't take - ACK failed\n"));
  281. return FALSE;
  282. }
  283. ucAck = pI2CControl->ReadDataLine(pHwDeviceExtension); // Read ACK bit
  284. pI2CControl->WriteClockLine(pHwDeviceExtension, 0); // Set SCL low
  285. I2C_DELAY(pI2CControl);
  286. if (1 == ucAck) // NAK from the monitor
  287. {
  288. pVideoDebugPrint((Warn, "VIDEOPRT: I2CWriteByte2: NAK received\n"));
  289. return FALSE;
  290. }
  291. return TRUE;
  292. } // I2CWriteByte2()
  293. BOOLEAN
  294. I2CReadByte2(
  295. IN PVOID pHwDeviceExtension,
  296. IN PVIDEO_I2C_CONTROL pI2CControl,
  297. OUT PUCHAR pucByte,
  298. IN BOOLEAN bEndOfRead
  299. )
  300. /*++
  301. Routine Description:
  302. This routine reads byte over the I2C channel.
  303. Arguments:
  304. pHwDeviceExtension - Points to per-adapter device extension.
  305. pI2CControl - I2C hardware specific functions.
  306. pucBuffer - Points to storage for data.
  307. bEndOfRead - TRUE if this is last byte to read.
  308. Returns:
  309. TRUE - Read OK.
  310. FALSE - Read failed.
  311. --*/
  312. {
  313. LONG lShift;
  314. PAGED_CODE();
  315. ASSERT(NULL != pHwDeviceExtension);
  316. ASSERT(NULL != pI2CControl);
  317. ASSERT(NULL != pucByte);
  318. *pucByte = 0;
  319. //
  320. // The data bits are read from MSB to LSB. A data bit is read while the SCL is high.
  321. //
  322. for (lShift = 7; lShift >= 0; lShift--)
  323. {
  324. pI2CControl->WriteClockLine(pHwDeviceExtension, 1); // Set SCL high
  325. I2C_DELAY(pI2CControl);
  326. if (I2CWaitForClockLineHigh2(pHwDeviceExtension, pI2CControl) == FALSE)
  327. {
  328. pVideoDebugPrint((Warn, "VIDEOPRT: I2CReadByte2: SCL didn't take\n"));
  329. return FALSE;
  330. }
  331. *pucByte |= pI2CControl->ReadDataLine(pHwDeviceExtension) << lShift; // Read SDA
  332. pI2CControl->WriteClockLine(pHwDeviceExtension, 0); // Set SCL low
  333. I2C_DELAY(pI2CControl);
  334. }
  335. //
  336. // Send the acknowledge bit. SDA low = ACK, SDA high = NAK.
  337. //
  338. if (bEndOfRead)
  339. {
  340. pI2CControl->WriteDataLine(pHwDeviceExtension, 1); // Set SDA high - NAK
  341. }
  342. else
  343. {
  344. pI2CControl->WriteDataLine(pHwDeviceExtension, 0); // Set SDA low - ACK
  345. }
  346. I2C_DELAY(pI2CControl);
  347. //
  348. // Send a SCL high->low pulse, then release the SDA by setting it high.
  349. //
  350. pI2CControl->WriteClockLine(pHwDeviceExtension, 1); // Set SCL high
  351. I2C_DELAY(pI2CControl);
  352. if (I2CWaitForClockLineHigh2(pHwDeviceExtension, pI2CControl) == FALSE)
  353. {
  354. pVideoDebugPrint((Warn, "VIDEOPRT: I2CReadByte2: SCL didn't take - ACK failed\n"));
  355. return FALSE;
  356. }
  357. pI2CControl->WriteClockLine(pHwDeviceExtension, 0); // Set SCL low
  358. I2C_DELAY(pI2CControl);
  359. pI2CControl->WriteDataLine(pHwDeviceExtension, 1); // Set SDA high
  360. I2C_DELAY(pI2CControl);
  361. return TRUE;
  362. } // I2CReadByte2()
  363. BOOLEAN
  364. I2CWaitForClockLineHigh2(
  365. IN PVOID pHwDeviceExtension,
  366. IN PVIDEO_I2C_CONTROL pI2CControl
  367. )
  368. /*++
  369. Routine Description:
  370. This routine waits till SCL goes high
  371. (SCL low period can be stretched by slow devices).
  372. Arguments:
  373. pHwDeviceExtension - Points to per-adapter device extension.
  374. pI2CControl - I2C hardware specific functions.
  375. Returns:
  376. TRUE - OK - SCL high.
  377. FALSE - SCL didn't take.
  378. --*/
  379. {
  380. ULONG ulCount;
  381. PAGED_CODE();
  382. ASSERT(NULL != pHwDeviceExtension);
  383. ASSERT(NULL != pI2CControl);
  384. for (ulCount = 0; ulCount < I2C_SCL_READ_RETRIES; ulCount++)
  385. {
  386. if (pI2CControl->ReadClockLine(pHwDeviceExtension) == TRUE)
  387. return TRUE;
  388. I2C_DELAY(pI2CControl);
  389. }
  390. return FALSE;
  391. } // I2CWaitForClockLineHigh2()