2 UART Serial Port library functions
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/IoLib.h>
11 #include <Library/SerialPortLib.h>
13 //---------------------------------------------
14 // UART Register Offsets
15 //---------------------------------------------
16 #define BAUD_LOW_OFFSET 0x00
17 #define BAUD_HIGH_OFFSET 0x01
18 #define IER_OFFSET 0x01
19 #define LCR_SHADOW_OFFSET 0x01
20 #define FCR_SHADOW_OFFSET 0x02
21 #define IR_CONTROL_OFFSET 0x02
22 #define FCR_OFFSET 0x02
23 #define EIR_OFFSET 0x02
24 #define BSR_OFFSET 0x03
25 #define LCR_OFFSET 0x03
26 #define MCR_OFFSET 0x04
27 #define LSR_OFFSET 0x05
28 #define MSR_OFFSET 0x06
30 //---------------------------------------------
31 // UART Register Bit Defines
32 //---------------------------------------------
33 #define LSR_TXRDY 0x20
43 //---------------------------------------------
45 //---------------------------------------------
46 UINT16 gUartBase
= 0x3F8;
54 Initialize the serial device hardware.
56 If no initialization is required, then return RETURN_SUCCESS.
57 If the serial device was successfully initialized, then return RETURN_SUCCESS.
58 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
60 @retval RETURN_SUCCESS The serial device was initialized.
61 @retval RETURN_DEVICE_ERROR The serail device could not be initialized.
66 SerialPortInitialize (
77 Data
= (UINT8
) (gData
- (UINT8
) 5);
80 // Calculate divisor for baud generator
82 Divisor
= 115200 / gBps
;
85 // Set communications format
87 OutputData
= (UINT8
) ((DLAB
<< 7) | (gBreakSet
<< 6) | (gParity
<< 3) | (gStop
<< 2) | Data
);
88 IoWrite8 (gUartBase
+ LCR_OFFSET
, OutputData
);
91 // Configure baud rate
93 IoWrite8 (gUartBase
+ BAUD_HIGH_OFFSET
, (UINT8
) (Divisor
>> 8));
94 IoWrite8 (gUartBase
+ BAUD_LOW_OFFSET
, (UINT8
) (Divisor
& 0xff));
97 // Switch back to bank 0
99 OutputData
= (UINT8
) ( (gBreakSet
<< 6) | (gParity
<< 3) | (gStop
<< 2) | Data
);
100 IoWrite8 (gUartBase
+ LCR_OFFSET
, OutputData
);
102 return RETURN_SUCCESS
;
106 Write data from buffer to serial device.
108 Writes NumberOfBytes data bytes from Buffer to the serial device.
109 The number of bytes actually written to the serial device is returned.
110 If the return value is less than NumberOfBytes, then the write operation failed.
112 If Buffer is NULL, then ASSERT().
114 If NumberOfBytes is zero, then return 0.
116 @param Buffer Pointer to the data buffer to be written.
117 @param NumberOfBytes Number of bytes to written to the serial device.
119 @retval 0 NumberOfBytes is 0.
120 @retval >0 The number of bytes written to the serial device.
121 If this value is less than NumberOfBytes, then the write operation failed.
128 IN UINTN NumberOfBytes
134 if (Buffer
== NULL
) {
138 Result
= NumberOfBytes
;
140 while ((NumberOfBytes
--) != 0) {
142 // Wait for the serail port to be ready.
145 Data
= IoRead8 ((UINT16
) gUartBase
+ LSR_OFFSET
);
146 } while ((Data
& LSR_TXRDY
) == 0);
147 IoWrite8 ((UINT16
) gUartBase
, *Buffer
++);
155 Reads data from a serial device into a buffer.
157 @param Buffer Pointer to the data buffer to store the data read from the serial device.
158 @param NumberOfBytes Number of bytes to read from the serial device.
160 @retval 0 NumberOfBytes is 0.
161 @retval >0 The number of bytes read from the serial device.
162 If this value is less than NumberOfBytes, then the read operation failed.
169 IN UINTN NumberOfBytes
175 if (NULL
== Buffer
) {
179 Result
= NumberOfBytes
;
181 while ((NumberOfBytes
--) != 0) {
183 // Wait for the serail port to be ready.
186 Data
= IoRead8 ((UINT16
) gUartBase
+ LSR_OFFSET
);
187 } while ((Data
& LSR_RXDA
) == 0);
189 *Buffer
++ = IoRead8 ((UINT16
) gUartBase
);
196 Polls a serial device to see if there is any data waiting to be read.
198 Polls a serial device to see if there is any data waiting to be read.
199 If there is data waiting to be read from the serial device, then TRUE is returned.
200 If there is no data waiting to be read from the serial device, then FALSE is returned.
202 @retval TRUE Data is waiting to be read from the serial device.
203 @retval FALSE There is no data waiting to be read from the serial device.
215 // Read the serial port status.
217 Data
= IoRead8 ((UINT16
) gUartBase
+ LSR_OFFSET
);
219 return (BOOLEAN
) ((Data
& LSR_RXDA
) != 0);
223 Sets the control bits on a serial device.
225 @param Control Sets the bits of Control that are settable.
227 @retval RETURN_SUCCESS The new control bits were set on the serial device.
228 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
229 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
234 SerialPortSetControl (
241 // First determine the parameter is invalid.
243 if ((Control
& (~(EFI_SERIAL_REQUEST_TO_SEND
| EFI_SERIAL_DATA_TERMINAL_READY
))) != 0) {
244 return RETURN_UNSUPPORTED
;
248 // Read the Modem Control Register.
250 Mcr
= IoRead8 ((UINT16
) gUartBase
+ MCR_OFFSET
);
251 Mcr
&= (~(MCR_DTRC
| MCR_RTS
));
253 if ((Control
& EFI_SERIAL_DATA_TERMINAL_READY
) == EFI_SERIAL_DATA_TERMINAL_READY
) {
257 if ((Control
& EFI_SERIAL_REQUEST_TO_SEND
) == EFI_SERIAL_REQUEST_TO_SEND
) {
262 // Write the Modem Control Register.
264 IoWrite8 ((UINT16
) gUartBase
+ MCR_OFFSET
, Mcr
);
266 return RETURN_SUCCESS
;
270 Retrieve the status of the control bits on a serial device.
272 @param Control A pointer to return the current control signals from the serial device.
274 @retval RETURN_SUCCESS The control bits were read from the serial device.
275 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
276 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
281 SerialPortGetControl (
292 // Read the Modem Status Register.
294 Msr
= IoRead8 ((UINT16
) gUartBase
+ MSR_OFFSET
);
296 if ((Msr
& MSR_CTS
) == MSR_CTS
) {
297 *Control
|= EFI_SERIAL_CLEAR_TO_SEND
;
300 if ((Msr
& MSR_DSR
) == MSR_DSR
) {
301 *Control
|= EFI_SERIAL_DATA_SET_READY
;
304 if ((Msr
& MSR_RI
) == MSR_RI
) {
305 *Control
|= EFI_SERIAL_RING_INDICATE
;
308 if ((Msr
& MSR_DCD
) == MSR_DCD
) {
309 *Control
|= EFI_SERIAL_CARRIER_DETECT
;
313 // Read the Modem Control Register.
315 Mcr
= IoRead8 ((UINT16
) gUartBase
+ MCR_OFFSET
);
317 if ((Mcr
& MCR_DTRC
) == MCR_DTRC
) {
318 *Control
|= EFI_SERIAL_DATA_TERMINAL_READY
;
321 if ((Mcr
& MCR_RTS
) == MCR_RTS
) {
322 *Control
|= EFI_SERIAL_REQUEST_TO_SEND
;
326 // Read the Line Status Register.
328 Lsr
= IoRead8 ((UINT16
) gUartBase
+ LSR_OFFSET
);
330 if ((Lsr
& LSR_TXRDY
) == LSR_TXRDY
) {
331 *Control
|= EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
334 if ((Lsr
& LSR_RXDA
) == 0) {
335 *Control
|= EFI_SERIAL_INPUT_BUFFER_EMPTY
;
338 return RETURN_SUCCESS
;
342 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
343 data bits, and stop bits on a serial device.
345 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
346 device's default interface speed.
347 On output, the value actually set.
348 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
349 serial interface. A ReceiveFifoDepth value of 0 will use
350 the device's default FIFO depth.
351 On output, the value actually set.
352 @param Timeout The requested time out for a single character in microseconds.
353 This timeout applies to both the transmit and receive side of the
354 interface. A Timeout value of 0 will use the device's default time
356 On output, the value actually set.
357 @param Parity The type of parity to use on this serial device. A Parity value of
358 DefaultParity will use the device's default parity value.
359 On output, the value actually set.
360 @param DataBits The number of data bits to use on the serial device. A DataBits
361 value of 0 will use the device's default data bit setting.
362 On output, the value actually set.
363 @param StopBits The number of stop bits to use on this serial device. A StopBits
364 value of DefaultStopBits will use the device's default number of
366 On output, the value actually set.
368 @retval RETURN_SUCCESS The new attributes were set on the serial device.
369 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
370 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
371 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
376 SerialPortSetAttributes (
377 IN OUT UINT64
*BaudRate
,
378 IN OUT UINT32
*ReceiveFifoDepth
,
379 IN OUT UINT32
*Timeout
,
380 IN OUT EFI_PARITY_TYPE
*Parity
,
381 IN OUT UINT8
*DataBits
,
382 IN OUT EFI_STOP_BITS_TYPE
*StopBits
392 // Check for default settings and fill in actual values.
394 if (*BaudRate
== 0) {
398 if (*DataBits
== 0) {
402 if (*Parity
== DefaultParity
) {
406 if (*StopBits
== DefaultStopBits
) {
407 *StopBits
= OneStopBit
;
410 if ((*DataBits
< 5) || (*DataBits
> 8)) {
411 return RETURN_INVALID_PARAMETER
;
417 LcrData
= (UINT8
) (*DataBits
- (UINT8
) 5);
441 return RETURN_INVALID_PARAMETER
;
449 case OneFiveStopBits
:
455 return RETURN_INVALID_PARAMETER
;
459 // Calculate divisor for baud generator
461 Divisor
= 115200 / (UINTN
) *BaudRate
;
464 // Set communications format
466 OutputData
= (UINT8
) ((DLAB
<< 7) | (gBreakSet
<< 6) | (LcrParity
<< 3) | (LcrStop
<< 2) | LcrData
);
467 IoWrite8 (gUartBase
+ LCR_OFFSET
, OutputData
);
470 // Configure baud rate
472 IoWrite8 (gUartBase
+ BAUD_HIGH_OFFSET
, (UINT8
) (Divisor
>> 8));
473 IoWrite8 (gUartBase
+ BAUD_LOW_OFFSET
, (UINT8
) (Divisor
& 0xff));
476 // Switch back to bank 0
478 OutputData
= (UINT8
) ((gBreakSet
<< 6) | (LcrParity
<< 3) | (LcrStop
<< 2) | LcrData
);
479 IoWrite8 (gUartBase
+ LCR_OFFSET
, OutputData
);
481 return RETURN_SUCCESS
;