2 SerialIo implementation for PCI or SIO UARTs.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Skip the optional Controller device path node and return the
19 pointer to the next device path node.
21 @param DevicePath Pointer to the device path.
22 @param ContainsControllerNode Returns TRUE if the Controller device path exists.
23 @param ControllerNumber Returns the Controller Number if Controller device path exists.
25 @return Pointer to the next device path node.
28 SkipControllerDevicePathNode (
29 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
30 BOOLEAN
*ContainsControllerNode
,
31 UINT32
*ControllerNumber
34 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) &&
35 (DevicePathSubType (DevicePath
) == HW_CONTROLLER_DP
)
37 if (ContainsControllerNode
!= NULL
) {
38 *ContainsControllerNode
= TRUE
;
40 if (ControllerNumber
!= NULL
) {
41 *ControllerNumber
= ((CONTROLLER_DEVICE_PATH
*) DevicePath
)->ControllerNumber
;
43 DevicePath
= NextDevicePathNode (DevicePath
);
45 if (ContainsControllerNode
!= NULL
) {
46 *ContainsControllerNode
= FALSE
;
49 return (UART_DEVICE_PATH
*) DevicePath
;
53 Checks whether the UART parameters are valid and computes the Divisor.
55 @param ClockRate The clock rate of the serial device used to verify
56 the BaudRate. Do not verify the BaudRate if it's 0.
57 @param BaudRate The requested baudrate of the serial device.
58 @param DataBits Number of databits used in serial device.
59 @param Parity The type of parity used in serial device.
60 @param StopBits Number of stopbits used in serial device.
61 @param Divisor Return the divisor if ClockRate is not 0.
62 @param ActualBaudRate Return the actual supported baudrate without
63 exceeding BaudRate. NULL means baudrate degradation
65 If the requested BaudRate is not supported, the routine
66 returns TRUE and the Actual Baud Rate when ActualBaudRate
67 is not NULL, returns FALSE when ActualBaudRate is NULL.
69 @retval TRUE The UART parameters are valid.
70 @retval FALSE The UART parameters are not valid.
73 VerifyUartParameters (
77 IN EFI_PARITY_TYPE Parity
,
78 IN EFI_STOP_BITS_TYPE StopBits
,
80 OUT UINT64
*ActualBaudRate
84 UINT32 ComputedBaudRate
;
85 UINT64 ComputedDivisor
;
88 if ((DataBits
< 5) || (DataBits
> 8) ||
89 (Parity
< NoParity
) || (Parity
> SpaceParity
) ||
90 (StopBits
< OneStopBit
) || (StopBits
> TwoStopBits
) ||
91 ((DataBits
== 5) && (StopBits
== TwoStopBits
)) ||
92 ((DataBits
>= 6) && (DataBits
<= 8) && (StopBits
== OneFiveStopBits
))
98 // Do not verify the baud rate if clock rate is unknown (0).
100 if (ClockRate
== 0) {
105 // Compute divisor use to program the baud rate using a round determination
106 // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate)
107 // = ClockRate / (BaudRate << 4)
109 ComputedDivisor
= DivU64x64Remainder (ClockRate
, LShiftU64 (BaudRate
, 4), &Remainder
);
111 // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate)
112 // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3)
114 if (Remainder
>= LShiftU64 (BaudRate
, 3)) {
118 // If the computed divisor is larger than the maximum value that can be programmed
119 // into the UART, then the requested baud rate can not be supported.
121 if (ComputedDivisor
> MAX_UINT16
) {
126 // If the computed divisor is 0, then use a computed divisor of 1, which will select
127 // the maximum supported baud rate.
129 if (ComputedDivisor
== 0) {
134 // Actual baud rate that the serial port will be programmed for
135 // should be with in 4% of requested one.
137 ComputedBaudRate
= ClockRate
/ ((UINT16
) ComputedDivisor
<< 4);
138 if (ComputedBaudRate
== 0) {
142 Percent
= DivU64x32 (MultU64x32 (BaudRate
, 100), ComputedBaudRate
);
143 DEBUG ((EFI_D_INFO
, "ClockRate = %d\n", ClockRate
));
144 DEBUG ((EFI_D_INFO
, "Divisor = %ld\n", ComputedDivisor
));
145 DEBUG ((EFI_D_INFO
, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate
, ComputedBaudRate
, Percent
));
148 // If the requested BaudRate is not supported:
149 // Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL;
150 // Returns FALSE when ActualBaudRate is NULL.
152 if ((Percent
>= 96) && (Percent
<= 104)) {
153 if (ActualBaudRate
!= NULL
) {
154 *ActualBaudRate
= BaudRate
;
156 if (Divisor
!= NULL
) {
157 *Divisor
= ComputedDivisor
;
161 if (ComputedBaudRate
< BaudRate
) {
162 if (ActualBaudRate
!= NULL
) {
163 *ActualBaudRate
= ComputedBaudRate
;
165 if (Divisor
!= NULL
) {
166 *Divisor
= ComputedDivisor
;
172 // ActualBaudRate is higher than requested baud rate and more than 4%
173 // higher than the requested value. Increment Divisor if it is less
174 // than MAX_UINT16 and computed baud rate with new divisor.
176 if (ComputedDivisor
== MAX_UINT16
) {
180 ComputedBaudRate
= ClockRate
/ ((UINT16
) ComputedDivisor
<< 4);
181 if (ComputedBaudRate
== 0) {
185 DEBUG ((EFI_D_INFO
, "ClockRate = %d\n", ClockRate
));
186 DEBUG ((EFI_D_INFO
, "Divisor = %ld\n", ComputedDivisor
));
187 DEBUG ((EFI_D_INFO
, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate
, ComputedBaudRate
, Percent
));
189 if (ActualBaudRate
!= NULL
) {
190 *ActualBaudRate
= ComputedBaudRate
;
192 if (Divisor
!= NULL
) {
193 *Divisor
= ComputedDivisor
;
199 Detect whether specific FIFO is full or not.
201 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
203 @return whether specific FIFO is full or not
207 IN SERIAL_DEV_FIFO
*Fifo
210 return (BOOLEAN
) (((Fifo
->Tail
+ 1) % SERIAL_MAX_FIFO_SIZE
) == Fifo
->Head
);
214 Detect whether specific FIFO is empty or not.
216 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
218 @return whether specific FIFO is empty or not
222 IN SERIAL_DEV_FIFO
*Fifo
226 return (BOOLEAN
) (Fifo
->Head
== Fifo
->Tail
);
230 Add data to specific FIFO.
232 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
233 @param Data the data added to FIFO
235 @retval EFI_SUCCESS Add data to specific FIFO successfully
236 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full
240 IN OUT SERIAL_DEV_FIFO
*Fifo
,
245 // if FIFO full can not add data
247 if (SerialFifoFull (Fifo
)) {
248 return EFI_OUT_OF_RESOURCES
;
251 // FIFO is not full can add data
253 Fifo
->Data
[Fifo
->Tail
] = Data
;
254 Fifo
->Tail
= (Fifo
->Tail
+ 1) % SERIAL_MAX_FIFO_SIZE
;
259 Remove data from specific FIFO.
261 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
262 @param Data the data removed from FIFO
264 @retval EFI_SUCCESS Remove data from specific FIFO successfully
265 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty
270 IN OUT SERIAL_DEV_FIFO
*Fifo
,
275 // if FIFO is empty, no data can remove
277 if (SerialFifoEmpty (Fifo
)) {
278 return EFI_OUT_OF_RESOURCES
;
281 // FIFO is not empty, can remove data
283 *Data
= Fifo
->Data
[Fifo
->Head
];
284 Fifo
->Head
= (Fifo
->Head
+ 1) % SERIAL_MAX_FIFO_SIZE
;
289 Reads and writes all available data.
291 @param SerialDevice The device to transmit.
293 @retval EFI_SUCCESS Data was read/written successfully.
294 @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when
295 this happens, pending writes are not done.
299 SerialReceiveTransmit (
300 IN SERIAL_DEV
*SerialDevice
306 BOOLEAN ReceiveFifoFull
;
314 // Begin the read or write
316 if (SerialDevice
->SoftwareLoopbackEnable
) {
318 ReceiveFifoFull
= SerialFifoFull (&SerialDevice
->Receive
);
319 if (!SerialFifoEmpty (&SerialDevice
->Transmit
)) {
320 SerialFifoRemove (&SerialDevice
->Transmit
, &Data
);
321 if (ReceiveFifoFull
) {
322 return EFI_OUT_OF_RESOURCES
;
325 SerialFifoAdd (&SerialDevice
->Receive
, Data
);
327 } while (!SerialFifoEmpty (&SerialDevice
->Transmit
));
329 ReceiveFifoFull
= SerialFifoFull (&SerialDevice
->Receive
);
331 // For full handshake flow control, tell the peer to send data
332 // if receive buffer is available.
334 if (SerialDevice
->HardwareFlowControl
&&
335 !FeaturePcdGet(PcdSerialUseHalfHandshake
)&&
338 Mcr
.Data
= READ_MCR (SerialDevice
);
340 WRITE_MCR (SerialDevice
, Mcr
.Data
);
343 Lsr
.Data
= READ_LSR (SerialDevice
);
346 // Flush incomming data to prevent a an overrun during a long write
348 if ((Lsr
.Bits
.Dr
== 1) && !ReceiveFifoFull
) {
349 ReceiveFifoFull
= SerialFifoFull (&SerialDevice
->Receive
);
350 if (!ReceiveFifoFull
) {
351 if (Lsr
.Bits
.FIFOe
== 1 || Lsr
.Bits
.Oe
== 1 || Lsr
.Bits
.Pe
== 1 || Lsr
.Bits
.Fe
== 1 || Lsr
.Bits
.Bi
== 1) {
352 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
354 EFI_P_EC_INPUT_ERROR
| EFI_PERIPHERAL_SERIAL_PORT
,
355 SerialDevice
->DevicePath
357 if (Lsr
.Bits
.FIFOe
== 1 || Lsr
.Bits
.Pe
== 1|| Lsr
.Bits
.Fe
== 1 || Lsr
.Bits
.Bi
== 1) {
358 Data
= READ_RBR (SerialDevice
);
363 Data
= READ_RBR (SerialDevice
);
365 SerialFifoAdd (&SerialDevice
->Receive
, Data
);
368 // For full handshake flow control, if receive buffer full
369 // tell the peer to stop sending data.
371 if (SerialDevice
->HardwareFlowControl
&&
372 !FeaturePcdGet(PcdSerialUseHalfHandshake
) &&
373 SerialFifoFull (&SerialDevice
->Receive
)
375 Mcr
.Data
= READ_MCR (SerialDevice
);
377 WRITE_MCR (SerialDevice
, Mcr
.Data
);
383 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
385 EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER
| EFI_PERIPHERAL_SERIAL_PORT
,
386 SerialDevice
->DevicePath
393 if (Lsr
.Bits
.Thre
== 1 && !SerialFifoEmpty (&SerialDevice
->Transmit
)) {
395 // Make sure the transmit data will not be missed
397 if (SerialDevice
->HardwareFlowControl
) {
399 // For half handshake flow control assert RTS before sending.
401 if (FeaturePcdGet(PcdSerialUseHalfHandshake
)) {
402 Mcr
.Data
= READ_MCR (SerialDevice
);
404 WRITE_MCR (SerialDevice
, Mcr
.Data
);
410 Msr
.Data
= READ_MSR (SerialDevice
);
411 while ((Msr
.Bits
.Dcd
== 1) && ((Msr
.Bits
.Cts
== 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake
))) {
412 gBS
->Stall (TIMEOUT_STALL_INTERVAL
);
418 Msr
.Data
= READ_MSR (SerialDevice
);
421 if ((Msr
.Bits
.Dcd
== 0) || ((Msr
.Bits
.Cts
== 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake
))) {
422 SerialFifoRemove (&SerialDevice
->Transmit
, &Data
);
423 WRITE_THR (SerialDevice
, Data
);
427 // For half handshake flow control, tell DCE we are done.
429 if (FeaturePcdGet(PcdSerialUseHalfHandshake
)) {
430 Mcr
.Data
= READ_MCR (SerialDevice
);
432 WRITE_MCR (SerialDevice
, Mcr
.Data
);
435 SerialFifoRemove (&SerialDevice
->Transmit
, &Data
);
436 WRITE_THR (SerialDevice
, Data
);
439 } while (Lsr
.Bits
.Thre
== 1 && !SerialFifoEmpty (&SerialDevice
->Transmit
));
446 // Interface Functions
451 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
453 @retval EFI_SUCCESS Reset successfully
454 @retval EFI_DEVICE_ERROR Failed to reset
460 IN EFI_SERIAL_IO_PROTOCOL
*This
464 SERIAL_DEV
*SerialDevice
;
472 SerialDevice
= SERIAL_DEV_FROM_THIS (This
);
475 // Report the status code reset the serial
477 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
479 EFI_P_PC_RESET
| EFI_PERIPHERAL_SERIAL_PORT
,
480 SerialDevice
->DevicePath
483 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
486 // Make sure DLAB is 0.
488 Lcr
.Data
= READ_LCR (SerialDevice
);
490 WRITE_LCR (SerialDevice
, Lcr
.Data
);
493 // Turn off all interrupts
495 Ier
.Data
= READ_IER (SerialDevice
);
500 WRITE_IER (SerialDevice
, Ier
.Data
);
506 Fcr
.Bits
.TrFIFOE
= 0;
507 WRITE_FCR (SerialDevice
, Fcr
.Data
);
510 // Turn off loopback and disable device interrupt.
512 Mcr
.Data
= READ_MCR (SerialDevice
);
516 WRITE_MCR (SerialDevice
, Mcr
.Data
);
519 // Clear the scratch pad register
521 WRITE_SCR (SerialDevice
, 0);
526 Fcr
.Bits
.TrFIFOE
= 1;
527 if (SerialDevice
->ReceiveFifoDepth
> 16) {
528 Fcr
.Bits
.TrFIFO64
= 1;
530 Fcr
.Bits
.ResetRF
= 1;
531 Fcr
.Bits
.ResetTF
= 1;
532 WRITE_FCR (SerialDevice
, Fcr
.Data
);
535 // Go set the current attributes
537 Status
= This
->SetAttributes (
539 This
->Mode
->BaudRate
,
540 This
->Mode
->ReceiveFifoDepth
,
542 (EFI_PARITY_TYPE
) This
->Mode
->Parity
,
543 (UINT8
) This
->Mode
->DataBits
,
544 (EFI_STOP_BITS_TYPE
) This
->Mode
->StopBits
547 if (EFI_ERROR (Status
)) {
548 gBS
->RestoreTPL (Tpl
);
549 return EFI_DEVICE_ERROR
;
552 // Go set the current control bits
555 if (SerialDevice
->HardwareFlowControl
) {
556 Control
|= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
;
558 if (SerialDevice
->SoftwareLoopbackEnable
) {
559 Control
|= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
;
561 Status
= This
->SetControl (
566 if (EFI_ERROR (Status
)) {
567 gBS
->RestoreTPL (Tpl
);
568 return EFI_DEVICE_ERROR
;
572 // Reset the software FIFO
574 SerialDevice
->Receive
.Head
= SerialDevice
->Receive
.Tail
= 0;
575 SerialDevice
->Transmit
.Head
= SerialDevice
->Transmit
.Tail
= 0;
576 gBS
->RestoreTPL (Tpl
);
579 // Device reset is complete
585 Set new attributes to a serial device.
587 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
588 @param BaudRate The baudrate of the serial device
589 @param ReceiveFifoDepth The depth of receive FIFO buffer
590 @param Timeout The request timeout for a single char
591 @param Parity The type of parity used in serial device
592 @param DataBits Number of databits used in serial device
593 @param StopBits Number of stopbits used in serial device
595 @retval EFI_SUCCESS The new attributes were set
596 @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value
597 @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6
598 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)
603 SerialSetAttributes (
604 IN EFI_SERIAL_IO_PROTOCOL
*This
,
606 IN UINT32 ReceiveFifoDepth
,
608 IN EFI_PARITY_TYPE Parity
,
610 IN EFI_STOP_BITS_TYPE StopBits
614 SERIAL_DEV
*SerialDevice
;
617 UART_DEVICE_PATH
*Uart
;
620 SerialDevice
= SERIAL_DEV_FROM_THIS (This
);
623 // Check for default settings and fill in actual values.
626 BaudRate
= PcdGet64 (PcdUartDefaultBaudRate
);
629 if (ReceiveFifoDepth
== 0) {
630 ReceiveFifoDepth
= SerialDevice
->ReceiveFifoDepth
;
634 Timeout
= SERIAL_PORT_DEFAULT_TIMEOUT
;
637 if (Parity
== DefaultParity
) {
638 Parity
= (EFI_PARITY_TYPE
) PcdGet8 (PcdUartDefaultParity
);
642 DataBits
= PcdGet8 (PcdUartDefaultDataBits
);
645 if (StopBits
== DefaultStopBits
) {
646 StopBits
= (EFI_STOP_BITS_TYPE
) PcdGet8 (PcdUartDefaultStopBits
);
649 if (!VerifyUartParameters (SerialDevice
->ClockRate
, BaudRate
, DataBits
, Parity
, StopBits
, &Divisor
, &BaudRate
)) {
650 return EFI_INVALID_PARAMETER
;
653 if ((ReceiveFifoDepth
== 0) || (ReceiveFifoDepth
> SerialDevice
->ReceiveFifoDepth
)) {
654 return EFI_INVALID_PARAMETER
;
657 if ((Timeout
< SERIAL_PORT_MIN_TIMEOUT
) || (Timeout
> SERIAL_PORT_MAX_TIMEOUT
)) {
658 return EFI_INVALID_PARAMETER
;
661 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
664 // Put serial port on Divisor Latch Mode
666 Lcr
.Data
= READ_LCR (SerialDevice
);
668 WRITE_LCR (SerialDevice
, Lcr
.Data
);
671 // Write the divisor to the serial port
673 WRITE_DLL (SerialDevice
, (UINT8
) Divisor
);
674 WRITE_DLM (SerialDevice
, (UINT8
) ((UINT16
) Divisor
>> 8));
677 // Put serial port back in normal mode and set remaining attributes.
684 Lcr
.Bits
.EvenPar
= 0;
685 Lcr
.Bits
.SticPar
= 0;
690 Lcr
.Bits
.EvenPar
= 1;
691 Lcr
.Bits
.SticPar
= 0;
696 Lcr
.Bits
.EvenPar
= 0;
697 Lcr
.Bits
.SticPar
= 0;
702 Lcr
.Bits
.EvenPar
= 1;
703 Lcr
.Bits
.SticPar
= 1;
708 Lcr
.Bits
.EvenPar
= 0;
709 Lcr
.Bits
.SticPar
= 1;
721 case OneFiveStopBits
:
732 Lcr
.Bits
.SerialDB
= (UINT8
) ((DataBits
- 5) & 0x03);
733 WRITE_LCR (SerialDevice
, Lcr
.Data
);
736 // Set the Serial I/O mode
738 This
->Mode
->BaudRate
= BaudRate
;
739 This
->Mode
->ReceiveFifoDepth
= ReceiveFifoDepth
;
740 This
->Mode
->Timeout
= Timeout
;
741 This
->Mode
->Parity
= Parity
;
742 This
->Mode
->DataBits
= DataBits
;
743 This
->Mode
->StopBits
= StopBits
;
746 // See if Device Path Node has actually changed
748 if (SerialDevice
->UartDevicePath
.BaudRate
== BaudRate
&&
749 SerialDevice
->UartDevicePath
.DataBits
== DataBits
&&
750 SerialDevice
->UartDevicePath
.Parity
== Parity
&&
751 SerialDevice
->UartDevicePath
.StopBits
== StopBits
753 gBS
->RestoreTPL (Tpl
);
757 // Update the device path
759 SerialDevice
->UartDevicePath
.BaudRate
= BaudRate
;
760 SerialDevice
->UartDevicePath
.DataBits
= DataBits
;
761 SerialDevice
->UartDevicePath
.Parity
= (UINT8
) Parity
;
762 SerialDevice
->UartDevicePath
.StopBits
= (UINT8
) StopBits
;
764 Status
= EFI_SUCCESS
;
765 if (SerialDevice
->Handle
!= NULL
) {
768 // Skip the optional Controller device path node
770 Uart
= SkipControllerDevicePathNode (
771 (EFI_DEVICE_PATH_PROTOCOL
*) (
772 (UINT8
*) SerialDevice
->DevicePath
+ GetDevicePathSize (SerialDevice
->ParentDevicePath
) - END_DEVICE_PATH_LENGTH
777 CopyMem (Uart
, &SerialDevice
->UartDevicePath
, sizeof (UART_DEVICE_PATH
));
778 Status
= gBS
->ReinstallProtocolInterface (
779 SerialDevice
->Handle
,
780 &gEfiDevicePathProtocolGuid
,
781 SerialDevice
->DevicePath
,
782 SerialDevice
->DevicePath
786 gBS
->RestoreTPL (Tpl
);
794 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
795 @param Control Control bits that can be settable
797 @retval EFI_SUCCESS New Control bits were set successfully
798 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported
804 IN EFI_SERIAL_IO_PROTOCOL
*This
,
808 SERIAL_DEV
*SerialDevice
;
811 UART_FLOW_CONTROL_DEVICE_PATH
*FlowControl
;
815 // The control bits that can be set are :
816 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO
817 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO
818 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW
819 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW
820 // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
822 SerialDevice
= SERIAL_DEV_FROM_THIS (This
);
825 // first determine the parameter is invalid
827 if ((Control
& (~(EFI_SERIAL_REQUEST_TO_SEND
| EFI_SERIAL_DATA_TERMINAL_READY
|
828 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
| EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
|
829 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
))) != 0) {
830 return EFI_UNSUPPORTED
;
833 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
835 Mcr
.Data
= READ_MCR (SerialDevice
);
839 SerialDevice
->SoftwareLoopbackEnable
= FALSE
;
840 SerialDevice
->HardwareFlowControl
= FALSE
;
842 if ((Control
& EFI_SERIAL_DATA_TERMINAL_READY
) == EFI_SERIAL_DATA_TERMINAL_READY
) {
846 if ((Control
& EFI_SERIAL_REQUEST_TO_SEND
) == EFI_SERIAL_REQUEST_TO_SEND
) {
850 if ((Control
& EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
) {
854 if ((Control
& EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
) {
855 SerialDevice
->HardwareFlowControl
= TRUE
;
858 WRITE_MCR (SerialDevice
, Mcr
.Data
);
860 if ((Control
& EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
) {
861 SerialDevice
->SoftwareLoopbackEnable
= TRUE
;
864 Status
= EFI_SUCCESS
;
865 if (SerialDevice
->Handle
!= NULL
) {
866 FlowControl
= (UART_FLOW_CONTROL_DEVICE_PATH
*) (
867 (UINTN
) SerialDevice
->DevicePath
868 + GetDevicePathSize (SerialDevice
->ParentDevicePath
)
869 - END_DEVICE_PATH_LENGTH
870 + sizeof (UART_DEVICE_PATH
)
872 if (IsUartFlowControlDevicePathNode (FlowControl
) &&
873 ((BOOLEAN
) (ReadUnaligned32 (&FlowControl
->FlowControlMap
) == UART_FLOW_CONTROL_HARDWARE
) != SerialDevice
->HardwareFlowControl
)) {
875 // Flow Control setting is changed, need to reinstall device path protocol
877 WriteUnaligned32 (&FlowControl
->FlowControlMap
, SerialDevice
->HardwareFlowControl
? UART_FLOW_CONTROL_HARDWARE
: 0);
878 Status
= gBS
->ReinstallProtocolInterface (
879 SerialDevice
->Handle
,
880 &gEfiDevicePathProtocolGuid
,
881 SerialDevice
->DevicePath
,
882 SerialDevice
->DevicePath
887 gBS
->RestoreTPL (Tpl
);
895 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
896 @param Control Control signals of the serial device
898 @retval EFI_SUCCESS Get Control signals successfully
904 IN EFI_SERIAL_IO_PROTOCOL
*This
,
908 SERIAL_DEV
*SerialDevice
;
913 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
915 SerialDevice
= SERIAL_DEV_FROM_THIS (This
);
920 // Read the Modem Status Register
922 Msr
.Data
= READ_MSR (SerialDevice
);
924 if (Msr
.Bits
.Cts
== 1) {
925 *Control
|= EFI_SERIAL_CLEAR_TO_SEND
;
928 if (Msr
.Bits
.Dsr
== 1) {
929 *Control
|= EFI_SERIAL_DATA_SET_READY
;
932 if (Msr
.Bits
.Ri
== 1) {
933 *Control
|= EFI_SERIAL_RING_INDICATE
;
936 if (Msr
.Bits
.Dcd
== 1) {
937 *Control
|= EFI_SERIAL_CARRIER_DETECT
;
940 // Read the Modem Control Register
942 Mcr
.Data
= READ_MCR (SerialDevice
);
944 if (Mcr
.Bits
.DtrC
== 1) {
945 *Control
|= EFI_SERIAL_DATA_TERMINAL_READY
;
948 if (Mcr
.Bits
.Rts
== 1) {
949 *Control
|= EFI_SERIAL_REQUEST_TO_SEND
;
952 if (Mcr
.Bits
.Lme
== 1) {
953 *Control
|= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
;
956 if (SerialDevice
->HardwareFlowControl
) {
957 *Control
|= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
;
960 // Update FIFO status
962 SerialReceiveTransmit (SerialDevice
);
965 // See if the Transmit FIFO is empty
967 if (SerialFifoEmpty (&SerialDevice
->Transmit
)) {
968 *Control
|= EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
972 // See if the Receive FIFO is empty.
974 if (SerialFifoEmpty (&SerialDevice
->Receive
)) {
975 *Control
|= EFI_SERIAL_INPUT_BUFFER_EMPTY
;
978 if (SerialDevice
->SoftwareLoopbackEnable
) {
979 *Control
|= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
;
982 gBS
->RestoreTPL (Tpl
);
988 Write the specified number of bytes to serial device.
990 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
991 @param BufferSize On input the size of Buffer, on output the amount of
992 data actually written
993 @param Buffer The buffer of data to write
995 @retval EFI_SUCCESS The data were written successfully
996 @retval EFI_DEVICE_ERROR The device reported an error
997 @retval EFI_TIMEOUT The write operation was stopped due to timeout
1003 IN EFI_SERIAL_IO_PROTOCOL
*This
,
1004 IN OUT UINTN
*BufferSize
,
1008 SERIAL_DEV
*SerialDevice
;
1015 UINTN BitsPerCharacter
;
1017 SerialDevice
= SERIAL_DEV_FROM_THIS (This
);
1021 if (*BufferSize
== 0) {
1025 if (Buffer
== NULL
) {
1026 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1028 EFI_P_EC_OUTPUT_ERROR
| EFI_PERIPHERAL_SERIAL_PORT
,
1029 SerialDevice
->DevicePath
1032 return EFI_DEVICE_ERROR
;
1035 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1037 CharBuffer
= (UINT8
*) Buffer
;
1040 // Compute the number of bits in a single character. This is a start bit,
1041 // followed by the number of data bits, followed by the number of stop bits.
1042 // The number of stop bits is specified by an enumeration that includes
1043 // support for 1.5 stop bits. Treat 1.5 stop bits as 2 stop bits.
1047 This
->Mode
->DataBits
+
1048 ((This
->Mode
->StopBits
== TwoStopBits
) ? 2 : This
->Mode
->StopBits
);
1051 // Compute the timeout in microseconds to wait for a single byte to be
1052 // transmitted. The Mode structure contans a Timeout field that is the
1053 // maximum time to transmit or receive a character. However, many UARTs
1054 // have a FIFO for transmits, so the time required to add one new character
1055 // to the transmit FIFO may be the time required to flush a full FIFO. If
1056 // the Timeout in the Mode structure is smaller than the time required to
1057 // flush a full FIFO at the current baud rate, then use a timeout value that
1058 // is required to flush a full transmit FIFO.
1061 This
->Mode
->Timeout
,
1062 (UINTN
)DivU64x64Remainder (
1063 BitsPerCharacter
* (SerialDevice
->TransmitFifoDepth
+ 1) * 1000000,
1064 This
->Mode
->BaudRate
,
1069 for (Index
= 0; Index
< *BufferSize
; Index
++) {
1070 SerialFifoAdd (&SerialDevice
->Transmit
, CharBuffer
[Index
]);
1072 while (SerialReceiveTransmit (SerialDevice
) != EFI_SUCCESS
|| !SerialFifoEmpty (&SerialDevice
->Transmit
)) {
1074 // Unsuccessful write so check if timeout has expired, if not,
1075 // stall for a bit, increment time elapsed, and try again
1077 if (Elapsed
>= Timeout
) {
1078 *BufferSize
= ActualWrite
;
1079 gBS
->RestoreTPL (Tpl
);
1083 gBS
->Stall (TIMEOUT_STALL_INTERVAL
);
1085 Elapsed
+= TIMEOUT_STALL_INTERVAL
;
1090 // Successful write so reset timeout
1095 gBS
->RestoreTPL (Tpl
);
1101 Read the specified number of bytes from serial device.
1103 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1104 @param BufferSize On input the size of Buffer, on output the amount of
1105 data returned in buffer
1106 @param Buffer The buffer to return the data into
1108 @retval EFI_SUCCESS The data were read successfully
1109 @retval EFI_DEVICE_ERROR The device reported an error
1110 @retval EFI_TIMEOUT The read operation was stopped due to timeout
1116 IN EFI_SERIAL_IO_PROTOCOL
*This
,
1117 IN OUT UINTN
*BufferSize
,
1121 SERIAL_DEV
*SerialDevice
;
1128 SerialDevice
= SERIAL_DEV_FROM_THIS (This
);
1131 if (*BufferSize
== 0) {
1135 if (Buffer
== NULL
) {
1136 return EFI_DEVICE_ERROR
;
1139 Tpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1141 Status
= SerialReceiveTransmit (SerialDevice
);
1143 if (EFI_ERROR (Status
)) {
1146 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1148 EFI_P_EC_INPUT_ERROR
| EFI_PERIPHERAL_SERIAL_PORT
,
1149 SerialDevice
->DevicePath
1152 gBS
->RestoreTPL (Tpl
);
1154 return EFI_DEVICE_ERROR
;
1157 CharBuffer
= (UINT8
*) Buffer
;
1158 for (Index
= 0; Index
< *BufferSize
; Index
++) {
1159 while (SerialFifoRemove (&SerialDevice
->Receive
, &(CharBuffer
[Index
])) != EFI_SUCCESS
) {
1161 // Unsuccessful read so check if timeout has expired, if not,
1162 // stall for a bit, increment time elapsed, and try again
1163 // Need this time out to get conspliter to work.
1165 if (Elapsed
>= This
->Mode
->Timeout
) {
1166 *BufferSize
= Index
;
1167 gBS
->RestoreTPL (Tpl
);
1171 gBS
->Stall (TIMEOUT_STALL_INTERVAL
);
1172 Elapsed
+= TIMEOUT_STALL_INTERVAL
;
1174 Status
= SerialReceiveTransmit (SerialDevice
);
1175 if (Status
== EFI_DEVICE_ERROR
) {
1176 *BufferSize
= Index
;
1177 gBS
->RestoreTPL (Tpl
);
1178 return EFI_DEVICE_ERROR
;
1182 // Successful read so reset timeout
1187 SerialReceiveTransmit (SerialDevice
);
1189 gBS
->RestoreTPL (Tpl
);
1195 Use scratchpad register to test if this serial port is present.
1197 @param SerialDevice Pointer to serial device structure
1199 @return if this serial port is present
1203 IN SERIAL_DEV
*SerialDevice
1215 Temp
= READ_SCR (SerialDevice
);
1216 WRITE_SCR (SerialDevice
, 0xAA);
1218 if (READ_SCR (SerialDevice
) != 0xAA) {
1222 WRITE_SCR (SerialDevice
, 0x55);
1224 if (READ_SCR (SerialDevice
) != 0x55) {
1230 WRITE_SCR (SerialDevice
, Temp
);
1237 @param SerialDev Pointer to serial device
1238 @param Offset Offset in register group
1240 @return Data read from serial port
1244 SerialReadRegister (
1245 IN SERIAL_DEV
*SerialDev
,
1252 if (SerialDev
->PciDeviceInfo
== NULL
) {
1253 return IoRead8 ((UINTN
) SerialDev
->BaseAddress
+ Offset
* SerialDev
->RegisterStride
);
1255 if (SerialDev
->MmioAccess
) {
1256 Status
= SerialDev
->PciDeviceInfo
->PciIo
->Mem
.Read (SerialDev
->PciDeviceInfo
->PciIo
, EfiPciIoWidthUint8
, EFI_PCI_IO_PASS_THROUGH_BAR
,
1257 SerialDev
->BaseAddress
+ Offset
* SerialDev
->RegisterStride
, 1, &Data
);
1259 Status
= SerialDev
->PciDeviceInfo
->PciIo
->Io
.Read (SerialDev
->PciDeviceInfo
->PciIo
, EfiPciIoWidthUint8
, EFI_PCI_IO_PASS_THROUGH_BAR
,
1260 SerialDev
->BaseAddress
+ Offset
* SerialDev
->RegisterStride
, 1, &Data
);
1262 ASSERT_EFI_ERROR (Status
);
1270 @param SerialDev Pointer to serial device
1271 @param Offset Offset in register group
1272 @param Data data which is to be written to some serial port register
1275 SerialWriteRegister (
1276 IN SERIAL_DEV
*SerialDev
,
1283 if (SerialDev
->PciDeviceInfo
== NULL
) {
1284 IoWrite8 ((UINTN
) SerialDev
->BaseAddress
+ Offset
* SerialDev
->RegisterStride
, Data
);
1286 if (SerialDev
->MmioAccess
) {
1287 Status
= SerialDev
->PciDeviceInfo
->PciIo
->Mem
.Write (SerialDev
->PciDeviceInfo
->PciIo
, EfiPciIoWidthUint8
, EFI_PCI_IO_PASS_THROUGH_BAR
,
1288 SerialDev
->BaseAddress
+ Offset
* SerialDev
->RegisterStride
, 1, &Data
);
1290 Status
= SerialDev
->PciDeviceInfo
->PciIo
->Io
.Write (SerialDev
->PciDeviceInfo
->PciIo
, EfiPciIoWidthUint8
, EFI_PCI_IO_PASS_THROUGH_BAR
,
1291 SerialDev
->BaseAddress
+ Offset
* SerialDev
->RegisterStride
, 1, &Data
);
1293 ASSERT_EFI_ERROR (Status
);