Source code of Windows XP (NT5)
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.

679 lines
11 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Copyright (c) 1993 Logitech Inc.
  4. Module Name:
  5. uart.c
  6. Abstract:
  7. Environment:
  8. Kernel mode only.
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "ntddk.h"
  13. #include "uart.h"
  14. #include "sermouse.h"
  15. #include "debug.h"
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(INIT,UARTSetFifo)
  18. #pragma alloc_text(INIT,UARTGetInterruptCtrl)
  19. #pragma alloc_text(INIT,UARTSetInterruptCtrl)
  20. #pragma alloc_text(INIT,UARTGetLineCtrl)
  21. #pragma alloc_text(INIT,UARTSetLineCtrl)
  22. #pragma alloc_text(INIT,UARTGetModemCtrl)
  23. #pragma alloc_text(INIT,UARTSetModemCtrl)
  24. #pragma alloc_text(INIT,UARTSetDlab)
  25. #pragma alloc_text(INIT,UARTGetBaudRate)
  26. #pragma alloc_text(INIT,UARTSetBaudRate)
  27. #pragma alloc_text(INIT,UARTGetState)
  28. #pragma alloc_text(INIT,UARTSetState)
  29. #pragma alloc_text(INIT,UARTReadChar)
  30. #pragma alloc_text(INIT,UARTIsTransmitEmpty)
  31. #pragma alloc_text(INIT,UARTWriteChar)
  32. #pragma alloc_text(INIT,UARTWriteString)
  33. #endif // ALLOC_PRAGMA
  34. //
  35. // Constants
  36. //
  37. VOID
  38. UARTSetFifo(
  39. PUCHAR Port,
  40. UCHAR Value
  41. )
  42. /*++
  43. Routine Description:
  44. Set the FIFO register.
  45. Arguments:
  46. Port - Pointer to the serial port.
  47. Value - The FIFO control mask.
  48. Return Value:
  49. None.
  50. --*/
  51. {
  52. WRITE_PORT_UCHAR(Port + ACE_IIDR, Value);
  53. }
  54. UCHAR
  55. UARTGetInterruptCtrl(
  56. PUCHAR Port
  57. )
  58. /*++
  59. Routine Description:
  60. Get the serial port interrupt control register.
  61. Arguments:
  62. Port - Pointer to the serial port.
  63. Return Value:
  64. Serial port interrupt control register value.
  65. --*/
  66. {
  67. return READ_PORT_UCHAR(Port + ACE_IER);
  68. }
  69. UCHAR
  70. UARTSetInterruptCtrl(
  71. PUCHAR Port,
  72. UCHAR Value
  73. )
  74. /*++
  75. Routine Description:
  76. Set the interrupt control register.
  77. Arguments:
  78. Port - Pointer to the serial port.
  79. Value - The interrupt control mask.
  80. Return Value:
  81. Previous interrupt control value.
  82. --*/
  83. {
  84. UCHAR oldValue = UARTGetInterruptCtrl(Port);
  85. WRITE_PORT_UCHAR(Port + ACE_IER, Value);
  86. return oldValue;
  87. }
  88. UCHAR
  89. UARTGetLineCtrl(
  90. PUCHAR Port
  91. )
  92. /*++
  93. Routine Description:
  94. Get the serial port line control register.
  95. Arguments:
  96. Port - Pointer to the serial port.
  97. Return Value:
  98. Serial port line control value.
  99. --*/
  100. {
  101. return READ_PORT_UCHAR(Port + ACE_LCR);
  102. }
  103. UCHAR
  104. UARTSetLineCtrl(
  105. PUCHAR Port,
  106. UCHAR Value
  107. )
  108. /*++
  109. Routine Description:
  110. Set the serial port line control register.
  111. Arguments:
  112. Port - Pointer to the serial port.
  113. Value - New line control value.
  114. Return Value:
  115. Previous serial line control register value.
  116. --*/
  117. {
  118. UCHAR oldValue = UARTGetLineCtrl(Port);
  119. WRITE_PORT_UCHAR(Port + ACE_LCR, Value);
  120. return oldValue;
  121. }
  122. UCHAR
  123. UARTGetModemCtrl(
  124. PUCHAR Port
  125. )
  126. /*++
  127. Routine Description:
  128. Get the serial port modem control register.
  129. Arguments:
  130. Port - Pointer to the serial port.
  131. Return Value:
  132. Serial port modem control register value.
  133. --*/
  134. {
  135. return READ_PORT_UCHAR(Port + ACE_MCR);
  136. }
  137. UCHAR
  138. UARTSetModemCtrl(
  139. PUCHAR Port,
  140. UCHAR Value
  141. )
  142. /*++
  143. Routine Description:
  144. Set the serial port modem control register.
  145. Arguments:
  146. Port - Pointer to the serial port.
  147. Return Value:
  148. Previous modem control register value.
  149. --*/
  150. {
  151. UCHAR oldValue = UARTGetModemCtrl(Port);
  152. WRITE_PORT_UCHAR(Port + ACE_MCR, Value);
  153. return oldValue;
  154. }
  155. BOOLEAN
  156. UARTSetDlab(
  157. PUCHAR Port,
  158. BOOLEAN Set
  159. )
  160. /*++
  161. Routine Description:
  162. Set/reset the baud rate access bit.
  163. Arguments:
  164. Port - Pointer to the serial port.
  165. Set - Set or Reset (TRUE/FALSE) the baud rate access bit.
  166. Return Value:
  167. The previous baud rate access bit setting.
  168. --*/
  169. {
  170. UCHAR lineControl = UARTGetLineCtrl(Port);
  171. UCHAR newLineControl = Set ? lineControl | ACE_DLAB :
  172. lineControl & ~ACE_DLAB;
  173. WRITE_PORT_UCHAR(Port + ACE_LCR, newLineControl);
  174. return lineControl & ACE_DLAB;
  175. }
  176. ULONG
  177. UARTGetBaudRate(
  178. PUCHAR Port,
  179. ULONG BaudClock
  180. )
  181. /*++
  182. Routine Description:
  183. Get the serial port baud rate setting.
  184. Arguments:
  185. Port - Pointer to the serial port.
  186. BaudClock - The external frequency driving the serial chip.
  187. Return Value:
  188. Serial port baud rate.
  189. --*/
  190. {
  191. USHORT baudRateDivisor;
  192. ULONG baudRateFactor = BaudClock/BAUD_GENERATOR_DIVISOR;
  193. //
  194. // Set the baud rate access bit.
  195. //
  196. UARTSetDlab(Port, TRUE);
  197. //
  198. // Read the baud rate factor.
  199. //
  200. baudRateDivisor = READ_PORT_UCHAR(Port + ACE_DLL);
  201. baudRateDivisor |= READ_PORT_UCHAR(Port + ACE_DLM) << 8;
  202. //
  203. // Reset the baud rate bit for normal data access.
  204. //
  205. UARTSetDlab(Port, FALSE);
  206. //
  207. // Make sure the divisor is not zero.
  208. //
  209. if (baudRateDivisor == 0) {
  210. baudRateDivisor = 1;
  211. }
  212. return baudRateFactor / baudRateDivisor;
  213. }
  214. VOID
  215. UARTSetBaudRate(
  216. PUCHAR Port,
  217. ULONG BaudRate,
  218. ULONG BaudClock
  219. )
  220. /*++
  221. Routine Description:
  222. Set the serial port baud rate.
  223. Arguments:
  224. Port - Pointer to the serial port.
  225. BaudRate - New serial port baud rate.
  226. BaudClock - The external frequency driving the serial chip.
  227. Return Value:
  228. None.
  229. --*/
  230. {
  231. ULONG baudRateFactor = BaudClock/BAUD_GENERATOR_DIVISOR;
  232. USHORT baudRateDivisor;
  233. SerMouPrint((2, "SERMOUSE-SetBaudRate: Enter\n"));
  234. baudRateDivisor = (USHORT) (baudRateFactor / BaudRate);
  235. UARTSetDlab(Port, TRUE);
  236. WRITE_PORT_UCHAR(Port + ACE_DLL, (UCHAR)baudRateDivisor);
  237. WRITE_PORT_UCHAR(Port + ACE_DLM, (UCHAR)(baudRateDivisor >> 8));
  238. UARTSetDlab(Port, FALSE);
  239. SerMouPrint((2, "SERMOUSE-New BaudRate: %u\n", BaudRate));
  240. SerMouPrint((2, "SERMOUSE-SetBaudRate: Exit\n"));
  241. return;
  242. }
  243. VOID
  244. UARTGetState(
  245. PUCHAR Port,
  246. PUART Uart,
  247. ULONG BaudClock
  248. )
  249. /*++
  250. Routine Description:
  251. Get the complete state of the serial port. May be used for save/restore.
  252. Arguments:
  253. Port - Pointer to the serial port.
  254. Uart - Pointer to a serial port structure.
  255. BaudClock - The external frequency driving the serial chip.
  256. Return Value:
  257. None.
  258. --*/
  259. {
  260. Uart->LineCtrl = UARTGetLineCtrl(Port);
  261. Uart->ModemCtrl = UARTGetModemCtrl(Port);
  262. Uart->InterruptCtrl = UARTGetInterruptCtrl(Port);
  263. Uart->BaudRate = UARTGetBaudRate(Port, BaudClock);
  264. return;
  265. }
  266. VOID
  267. UARTSetState(
  268. PUCHAR Port,
  269. PUART Uart,
  270. ULONG BaudClock
  271. )
  272. /*++
  273. Routine Description:
  274. Set the complete state of a serial port.
  275. Arguments:
  276. Port - Pointer to the serial port.
  277. Uart - Pointer to a serial port structure.
  278. BaudClock - The external frequency driving the serial chip.
  279. Return Value:
  280. None.
  281. --*/
  282. {
  283. UARTSetLineCtrl(Port, Uart->LineCtrl);
  284. UARTSetModemCtrl(Port, Uart->ModemCtrl);
  285. UARTSetInterruptCtrl(Port, Uart->InterruptCtrl);
  286. UARTSetBaudRate(Port, Uart->BaudRate, BaudClock);
  287. return;
  288. }
  289. BOOLEAN
  290. UARTIsReceiveBufferFull(
  291. PUCHAR Port
  292. )
  293. /*++
  294. Routine Description:
  295. Check whether the serial port input buffer is full.
  296. Arguments:
  297. Port - Pointer to the serial port.
  298. Return Value:
  299. TRUE if a character is present in the input buffer, otherwise FALSE.
  300. --*/
  301. {
  302. return READ_PORT_UCHAR(Port + ACE_LSR) & ACE_DR;
  303. }
  304. BOOLEAN
  305. UARTReadCharNoWait(
  306. PUCHAR Port,
  307. PUCHAR Value
  308. )
  309. /*++
  310. Routine Description:
  311. Read a character from the serial port and return immediately.
  312. Arguments:
  313. Port - Pointer to the serial port.
  314. Value - The character read from the serial port input buffer.
  315. Return Value:
  316. TRUE if character has been read, FALSE otherwise.
  317. --*/
  318. {
  319. BOOLEAN charReady = FALSE;
  320. if ( UARTIsReceiveBufferFull(Port) ) {
  321. *Value = READ_PORT_UCHAR(Port + ACE_RBR);
  322. charReady = TRUE;
  323. }
  324. return charReady;
  325. }
  326. BOOLEAN
  327. UARTReadChar(
  328. PUCHAR Port,
  329. PUCHAR Value,
  330. ULONG Timeout
  331. )
  332. /*++
  333. Routine Description:
  334. Read a character from the serial port. Waits until a character has
  335. been read or the timeout value is reached.
  336. Arguments:
  337. Port - Pointer to the serial port.
  338. Value - The character read from the serial port input buffer.
  339. Timeout - The timeout value in milliseconds for the read.
  340. Return Value:
  341. TRUE if a character has been read, FALSE if a timeout occured.
  342. --*/
  343. {
  344. ULONG i, j;
  345. BOOLEAN returnValue = FALSE;
  346. //
  347. // Exit when a character is found or the timeout value is reached.
  348. //
  349. for (i = 0; i < Timeout; i++) {
  350. for (j = 0; j < MS_TO_MICROSECONDS; j++) {
  351. if ((returnValue = UARTReadCharNoWait(Port, Value)) == TRUE) {
  352. //
  353. // Got a character.
  354. //
  355. break;
  356. } else {
  357. //
  358. // Stall 1 microsecond and then try to read again.
  359. //
  360. KeStallExecutionProcessor(1);
  361. }
  362. }
  363. if (returnValue) {
  364. break;
  365. }
  366. }
  367. return(returnValue);
  368. }
  369. BOOLEAN
  370. UARTFlushReadBuffer(
  371. PUCHAR Port
  372. )
  373. /*++
  374. Routine Description:
  375. Flush the serial port input buffer.
  376. Arguments:
  377. Port - Pointer to the serial port.
  378. Return Value:
  379. TRUE.
  380. --*/
  381. {
  382. UCHAR value;
  383. SerMouPrint((4, "SERMOUSE-UARTFlushReadBuffer: Enter\n"));
  384. while (UARTReadCharNoWait(Port, &value)) {
  385. /* Nothing */
  386. }
  387. SerMouPrint((4, "SERMOUSE-UARTFlushReadBuffer: Exit\n"));
  388. return TRUE;
  389. }
  390. BOOLEAN
  391. UARTIsTransmitEmpty(
  392. PUCHAR Port
  393. )
  394. /*++
  395. Routine Description:
  396. Check whether the serial port transmit buffer is empty.
  397. Note: We also check whether the shift register is empty. This is
  398. not critical in our case, but allows some more delay between characters
  399. sent to a device. (Safe, safe...)
  400. Arguments:
  401. Port - Pointer to the serial port.
  402. Return Value:
  403. TRUE if the serial port transmit buffer is empty.
  404. --*/
  405. {
  406. return ((READ_PORT_UCHAR((PUCHAR) (Port + ACE_LSR)) &
  407. (ACE_TSRE | ACE_THRE)) == (ACE_THRE | ACE_TSRE));
  408. }
  409. BOOLEAN
  410. UARTWriteChar(
  411. PUCHAR Port,
  412. UCHAR Value
  413. )
  414. /*++
  415. Routine Description:
  416. Write a character to a serial port. Make sure the transmit buffer
  417. is empty before we write there.
  418. Arguments:
  419. Port - Pointer to the serial port.
  420. Value - Value to write to the serial port.
  421. Return Value:
  422. TRUE.
  423. --*/
  424. {
  425. while (!UARTIsTransmitEmpty(Port)) {
  426. /* Nothing */
  427. }
  428. WRITE_PORT_UCHAR(Port + ACE_THR, Value);
  429. return TRUE;
  430. }
  431. BOOLEAN
  432. UARTWriteString(
  433. PUCHAR Port,
  434. PSZ Buffer
  435. )
  436. /*++
  437. Routine Description:
  438. Write a zero-terminated string to the serial port.
  439. Arguments:
  440. Port - Pointer to the serial port.
  441. Buffer - Pointer to a zero terminated string to write to
  442. the serial port.
  443. Return Value:
  444. TRUE.
  445. --*/
  446. {
  447. PSZ current = Buffer;
  448. while (*current) {
  449. UARTWriteChar(Port, *current++);
  450. }
  451. return TRUE;
  452. }