1 /** @file
2   SerialIo implementation for PCI or SIO UARTs.
3 
4 Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "Serial.h"
10 
11 /**
12   Skip the optional Controller device path node and return the
13   pointer to the next device path node.
14 
15   @param DevicePath             Pointer to the device path.
16   @param ContainsControllerNode Returns TRUE if the Controller device path exists.
17   @param ControllerNumber       Returns the Controller Number if Controller device path exists.
18 
19   @return     Pointer to the next device path node.
20 **/
21 UART_DEVICE_PATH *
SkipControllerDevicePathNode(EFI_DEVICE_PATH_PROTOCOL * DevicePath,BOOLEAN * ContainsControllerNode,UINT32 * ControllerNumber)22 SkipControllerDevicePathNode (
23   EFI_DEVICE_PATH_PROTOCOL          *DevicePath,
24   BOOLEAN                           *ContainsControllerNode,
25   UINT32                            *ControllerNumber
26   )
27 {
28   if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) &&
29       (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP)
30       ) {
31     if (ContainsControllerNode != NULL) {
32       *ContainsControllerNode = TRUE;
33     }
34     if (ControllerNumber != NULL) {
35       *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber;
36     }
37     DevicePath = NextDevicePathNode (DevicePath);
38   } else {
39     if (ContainsControllerNode != NULL) {
40       *ContainsControllerNode = FALSE;
41     }
42   }
43   return (UART_DEVICE_PATH *) DevicePath;
44 }
45 
46 /**
47   Checks whether the UART parameters are valid and computes the Divisor.
48 
49   @param  ClockRate      The clock rate of the serial device used to verify
50                          the BaudRate. Do not verify the BaudRate if it's 0.
51   @param  BaudRate       The requested baudrate of the serial device.
52   @param  DataBits       Number of databits used in serial device.
53   @param  Parity         The type of parity used in serial device.
54   @param  StopBits       Number of stopbits used in serial device.
55   @param  Divisor        Return the divisor if ClockRate is not 0.
56   @param  ActualBaudRate Return the actual supported baudrate without
57                          exceeding BaudRate. NULL means baudrate degradation
58                          is not allowed.
59                          If the requested BaudRate is not supported, the routine
60                          returns TRUE and the Actual Baud Rate when ActualBaudRate
61                          is not NULL, returns FALSE when ActualBaudRate is NULL.
62 
63   @retval TRUE   The UART parameters are valid.
64   @retval FALSE  The UART parameters are not valid.
65 **/
66 BOOLEAN
VerifyUartParameters(IN UINT32 ClockRate,IN UINT64 BaudRate,IN UINT8 DataBits,IN EFI_PARITY_TYPE Parity,IN EFI_STOP_BITS_TYPE StopBits,OUT UINT64 * Divisor,OUT UINT64 * ActualBaudRate)67 VerifyUartParameters (
68   IN     UINT32                  ClockRate,
69   IN     UINT64                  BaudRate,
70   IN     UINT8                   DataBits,
71   IN     EFI_PARITY_TYPE         Parity,
72   IN     EFI_STOP_BITS_TYPE      StopBits,
73      OUT UINT64                  *Divisor,
74      OUT UINT64                  *ActualBaudRate
75   )
76 {
77   UINT64                     Remainder;
78   UINT32                     ComputedBaudRate;
79   UINT64                     ComputedDivisor;
80   UINT64                     Percent;
81 
82   if ((DataBits < 5) || (DataBits > 8) ||
83       (Parity < NoParity) || (Parity > SpaceParity) ||
84       (StopBits < OneStopBit) || (StopBits > TwoStopBits) ||
85       ((DataBits == 5) && (StopBits == TwoStopBits)) ||
86       ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits))
87       ) {
88     return FALSE;
89   }
90 
91   //
92   // Do not verify the baud rate if clock rate is unknown (0).
93   //
94   if (ClockRate == 0) {
95     return TRUE;
96   }
97 
98   //
99   // Compute divisor use to program the baud rate using a round determination
100   // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate)
101   //         = ClockRate / (BaudRate << 4)
102   //
103   ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), &Remainder);
104   //
105   // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate)
106   // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3)
107   //
108   if (Remainder >= LShiftU64 (BaudRate, 3)) {
109     ComputedDivisor++;
110   }
111   //
112   // If the computed divisor is larger than the maximum value that can be programmed
113   // into the UART, then the requested baud rate can not be supported.
114   //
115   if (ComputedDivisor > MAX_UINT16) {
116     return FALSE;
117   }
118 
119   //
120   // If the computed divisor is 0, then use a computed divisor of 1, which will select
121   // the maximum supported baud rate.
122   //
123   if (ComputedDivisor == 0) {
124     ComputedDivisor = 1;
125   }
126 
127   //
128   // Actual baud rate that the serial port will be programmed for
129   // should be with in 4% of requested one.
130   //
131   ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
132   if (ComputedBaudRate == 0) {
133     return FALSE;
134   }
135 
136   Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate);
137   DEBUG ((EFI_D_INFO, "ClockRate = %d\n",  ClockRate));
138   DEBUG ((EFI_D_INFO, "Divisor   = %ld\n", ComputedDivisor));
139   DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
140 
141   //
142   // If the requested BaudRate is not supported:
143   //  Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL;
144   //  Returns FALSE when ActualBaudRate is NULL.
145   //
146   if ((Percent >= 96) && (Percent <= 104)) {
147     if (ActualBaudRate != NULL) {
148       *ActualBaudRate = BaudRate;
149     }
150     if (Divisor != NULL) {
151       *Divisor = ComputedDivisor;
152     }
153     return TRUE;
154   }
155   if (ComputedBaudRate < BaudRate) {
156     if (ActualBaudRate != NULL) {
157       *ActualBaudRate = ComputedBaudRate;
158     }
159     if (Divisor != NULL) {
160       *Divisor = ComputedDivisor;
161     }
162     return TRUE;
163   }
164 
165   //
166   // ActualBaudRate is higher than requested baud rate and more than 4%
167   // higher than the requested value.  Increment Divisor if it is less
168   // than MAX_UINT16 and computed baud rate with new divisor.
169   //
170   if (ComputedDivisor == MAX_UINT16) {
171     return FALSE;
172   }
173   ComputedDivisor++;
174   ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
175   if (ComputedBaudRate == 0) {
176     return FALSE;
177   }
178 
179   DEBUG ((EFI_D_INFO, "ClockRate = %d\n",  ClockRate));
180   DEBUG ((EFI_D_INFO, "Divisor   = %ld\n", ComputedDivisor));
181   DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
182 
183   if (ActualBaudRate != NULL) {
184     *ActualBaudRate = ComputedBaudRate;
185   }
186   if (Divisor != NULL) {
187     *Divisor = ComputedDivisor;
188   }
189   return TRUE;
190 }
191 
192 /**
193   Detect whether specific FIFO is full or not.
194 
195   @param Fifo    A pointer to the Data Structure SERIAL_DEV_FIFO
196 
197   @return whether specific FIFO is full or not
198 **/
199 BOOLEAN
SerialFifoFull(IN SERIAL_DEV_FIFO * Fifo)200 SerialFifoFull (
201   IN SERIAL_DEV_FIFO *Fifo
202   )
203 {
204   return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head);
205 }
206 
207 /**
208   Detect whether specific FIFO is empty or not.
209 
210   @param  Fifo    A pointer to the Data Structure SERIAL_DEV_FIFO
211 
212   @return whether specific FIFO is empty or not
213 **/
214 BOOLEAN
SerialFifoEmpty(IN SERIAL_DEV_FIFO * Fifo)215 SerialFifoEmpty (
216   IN SERIAL_DEV_FIFO *Fifo
217   )
218 
219 {
220   return (BOOLEAN) (Fifo->Head == Fifo->Tail);
221 }
222 
223 /**
224   Add data to specific FIFO.
225 
226   @param Fifo                  A pointer to the Data Structure SERIAL_DEV_FIFO
227   @param Data                  the data added to FIFO
228 
229   @retval EFI_SUCCESS           Add data to specific FIFO successfully
230   @retval EFI_OUT_OF_RESOURCE   Failed to add data because FIFO is already full
231 **/
232 EFI_STATUS
SerialFifoAdd(IN OUT SERIAL_DEV_FIFO * Fifo,IN UINT8 Data)233 SerialFifoAdd (
234   IN OUT SERIAL_DEV_FIFO *Fifo,
235   IN     UINT8           Data
236   )
237 {
238   //
239   // if FIFO full can not add data
240   //
241   if (SerialFifoFull (Fifo)) {
242     return EFI_OUT_OF_RESOURCES;
243   }
244   //
245   // FIFO is not full can add data
246   //
247   Fifo->Data[Fifo->Tail] = Data;
248   Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE;
249   return EFI_SUCCESS;
250 }
251 
252 /**
253   Remove data from specific FIFO.
254 
255   @param Fifo                  A pointer to the Data Structure SERIAL_DEV_FIFO
256   @param Data                  the data removed from FIFO
257 
258   @retval EFI_SUCCESS           Remove data from specific FIFO successfully
259   @retval EFI_OUT_OF_RESOURCE   Failed to remove data because FIFO is empty
260 
261 **/
262 EFI_STATUS
SerialFifoRemove(IN OUT SERIAL_DEV_FIFO * Fifo,OUT UINT8 * Data)263 SerialFifoRemove (
264   IN OUT SERIAL_DEV_FIFO *Fifo,
265   OUT    UINT8           *Data
266   )
267 {
268   //
269   // if FIFO is empty, no data can remove
270   //
271   if (SerialFifoEmpty (Fifo)) {
272     return EFI_OUT_OF_RESOURCES;
273   }
274   //
275   // FIFO is not empty, can remove data
276   //
277   *Data = Fifo->Data[Fifo->Head];
278   Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE;
279   return EFI_SUCCESS;
280 }
281 
282 /**
283   Reads and writes all available data.
284 
285   @param SerialDevice           The device to transmit.
286 
287   @retval EFI_SUCCESS           Data was read/written successfully.
288   @retval EFI_OUT_OF_RESOURCE   Failed because software receive FIFO is full.  Note, when
289                                 this happens, pending writes are not done.
290 
291 **/
292 EFI_STATUS
SerialReceiveTransmit(IN SERIAL_DEV * SerialDevice)293 SerialReceiveTransmit (
294   IN SERIAL_DEV *SerialDevice
295   )
296 
297 {
298   SERIAL_PORT_LSR Lsr;
299   UINT8           Data;
300   BOOLEAN         ReceiveFifoFull;
301   SERIAL_PORT_MSR Msr;
302   SERIAL_PORT_MCR Mcr;
303   UINTN           TimeOut;
304 
305   Data = 0;
306 
307   //
308   // Begin the read or write
309   //
310   if (SerialDevice->SoftwareLoopbackEnable) {
311     do {
312       ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
313       if (!SerialFifoEmpty (&SerialDevice->Transmit)) {
314         SerialFifoRemove (&SerialDevice->Transmit, &Data);
315         if (ReceiveFifoFull) {
316           return EFI_OUT_OF_RESOURCES;
317         }
318 
319         SerialFifoAdd (&SerialDevice->Receive, Data);
320       }
321     } while (!SerialFifoEmpty (&SerialDevice->Transmit));
322   } else {
323     ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
324     //
325     // For full handshake flow control, tell the peer to send data
326     // if receive buffer is available.
327     //
328     if (SerialDevice->HardwareFlowControl &&
329         !FeaturePcdGet(PcdSerialUseHalfHandshake)&&
330         !ReceiveFifoFull
331         ) {
332       Mcr.Data     = READ_MCR (SerialDevice);
333       Mcr.Bits.Rts = 1;
334       WRITE_MCR (SerialDevice, Mcr.Data);
335     }
336     do {
337       Lsr.Data = READ_LSR (SerialDevice);
338 
339       //
340       // Flush incomming data to prevent a an overrun during a long write
341       //
342       if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
343         ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
344         if (!ReceiveFifoFull) {
345           if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
346             REPORT_STATUS_CODE_WITH_DEVICE_PATH (
347               EFI_ERROR_CODE,
348               EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
349               SerialDevice->DevicePath
350               );
351             if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
352               Data = READ_RBR (SerialDevice);
353               continue;
354             }
355           }
356 
357           Data = READ_RBR (SerialDevice);
358 
359           SerialFifoAdd (&SerialDevice->Receive, Data);
360 
361           //
362           // For full handshake flow control, if receive buffer full
363           // tell the peer to stop sending data.
364           //
365           if (SerialDevice->HardwareFlowControl &&
366               !FeaturePcdGet(PcdSerialUseHalfHandshake)   &&
367               SerialFifoFull (&SerialDevice->Receive)
368               ) {
369             Mcr.Data     = READ_MCR (SerialDevice);
370             Mcr.Bits.Rts = 0;
371             WRITE_MCR (SerialDevice, Mcr.Data);
372           }
373 
374 
375           continue;
376         } else {
377           REPORT_STATUS_CODE_WITH_DEVICE_PATH (
378             EFI_PROGRESS_CODE,
379             EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
380             SerialDevice->DevicePath
381             );
382         }
383       }
384       //
385       // Do the write
386       //
387       if (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)) {
388         //
389         // Make sure the transmit data will not be missed
390         //
391         if (SerialDevice->HardwareFlowControl) {
392           //
393           // For half handshake flow control assert RTS before sending.
394           //
395           if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
396             Mcr.Data     = READ_MCR (SerialDevice);
397             Mcr.Bits.Rts= 0;
398             WRITE_MCR (SerialDevice, Mcr.Data);
399           }
400           //
401           // Wait for CTS
402           //
403           TimeOut   = 0;
404           Msr.Data  = READ_MSR (SerialDevice);
405           while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
406             gBS->Stall (TIMEOUT_STALL_INTERVAL);
407             TimeOut++;
408             if (TimeOut > 5) {
409               break;
410             }
411 
412             Msr.Data = READ_MSR (SerialDevice);
413           }
414 
415           if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
416             SerialFifoRemove (&SerialDevice->Transmit, &Data);
417             WRITE_THR (SerialDevice, Data);
418           }
419 
420           //
421           // For half handshake flow control, tell DCE we are done.
422           //
423           if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
424             Mcr.Data = READ_MCR (SerialDevice);
425             Mcr.Bits.Rts = 1;
426             WRITE_MCR (SerialDevice, Mcr.Data);
427           }
428         } else {
429           SerialFifoRemove (&SerialDevice->Transmit, &Data);
430           WRITE_THR (SerialDevice, Data);
431         }
432       }
433     } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit));
434   }
435 
436   return EFI_SUCCESS;
437 }
438 
439 /**
440   Flush the serial hardware transmit FIFO, holding register, and shift register.
441 
442   @param SerialDevice  The device to flush.
443 
444   @retval  EFI_SUCCESS  The transmit FIFO is completely flushed.
445   @retval  EFI_TIMEOUT  A timeout occured waiting for the transmit FIFO to flush.
446 **/
447 EFI_STATUS
SerialFlushTransmitFifo(SERIAL_DEV * SerialDevice)448 SerialFlushTransmitFifo (
449   SERIAL_DEV  *SerialDevice
450   )
451 {
452   SERIAL_PORT_LSR  Lsr;
453   UINTN            Timeout;
454   UINTN            Elapsed;
455 
456   //
457   // If this is the first time the UART is being configured, then the current
458   // UART settings are not known, so compute a timeout to wait for the Tx FIFO
459   // assuming the worst case current settings.
460   //
461   // Timeout = (Max Bits per Char) * (Max Pending Chars) / (Slowest Baud Rate)
462   //   Max Bits per Char = Start bit + 8 data bits + parity + 2 stop bits = 12
463   //   Max Pending Chars = Largest Tx FIFO + hold + shift = 64 + 1 + 1 = 66
464   //   Slowest Reasonable Baud Rate = 300 baud
465   // Timeout = 12 * 66 / 300 = 2.64 seconds = 2,640,000 uS
466   //
467   Timeout = 2640000;
468 
469   //
470   // Use the largest of the computed timeout, the default timeout, and the
471   // currently set timeout.
472   //
473   Timeout = MAX (Timeout, SERIAL_PORT_DEFAULT_TIMEOUT);
474   Timeout = MAX (Timeout, SerialDevice->SerialMode.Timeout);
475 
476   //
477   // Wait for the shortest time possible for the serial port to be ready making
478   // sure the transmit FIFO, holding register, and shift register are all
479   // empty.  The actual wait time is expected to be very small because the
480   // number characters currently in the FIFO should be small when a
481   // configuration change is requested.
482   //
483   // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
484   // in the rest of this function that may send additional characters to this
485   // UART device invalidating the flush operation.
486   //
487   Elapsed = 0;
488   Lsr.Data = READ_LSR (SerialDevice);
489   while (Lsr.Bits.Temt == 0 || Lsr.Bits.Thre == 0) {
490     if (Elapsed >= Timeout) {
491       return EFI_TIMEOUT;
492     }
493     gBS->Stall (TIMEOUT_STALL_INTERVAL);
494     Elapsed += TIMEOUT_STALL_INTERVAL;
495     Lsr.Data = READ_LSR (SerialDevice);
496   }
497 
498   return EFI_SUCCESS;
499 }
500 
501 //
502 // Interface Functions
503 //
504 /**
505   Reset serial device.
506 
507   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
508 
509   @retval EFI_SUCCESS        Reset successfully
510   @retval EFI_DEVICE_ERROR   Failed to reset
511 
512 **/
513 EFI_STATUS
514 EFIAPI
SerialReset(IN EFI_SERIAL_IO_PROTOCOL * This)515 SerialReset (
516   IN EFI_SERIAL_IO_PROTOCOL  *This
517   )
518 {
519   EFI_STATUS      Status;
520   SERIAL_DEV      *SerialDevice;
521   SERIAL_PORT_LCR Lcr;
522   SERIAL_PORT_IER Ier;
523   SERIAL_PORT_MCR Mcr;
524   SERIAL_PORT_FCR Fcr;
525   EFI_TPL         Tpl;
526   UINT32          Control;
527 
528   SerialDevice = SERIAL_DEV_FROM_THIS (This);
529 
530   //
531   // Report the status code reset the serial
532   //
533   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
534     EFI_PROGRESS_CODE,
535     EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
536     SerialDevice->DevicePath
537     );
538 
539   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
540 
541   //
542   // Wait for all data to be transmitted before changing the UART configuration.
543   //
544   // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
545   // that may send additional characters to this UART device until the UART
546   // configuration change is complete.
547   //
548   SerialFlushTransmitFifo (SerialDevice);
549 
550   //
551   // Make sure DLAB is 0.
552   //
553   Lcr.Data      = READ_LCR (SerialDevice);
554   Lcr.Bits.DLab = 0;
555   WRITE_LCR (SerialDevice, Lcr.Data);
556 
557   //
558   // Turn off all interrupts
559   //
560   Ier.Data        = READ_IER (SerialDevice);
561   Ier.Bits.Ravie  = 0;
562   Ier.Bits.Theie  = 0;
563   Ier.Bits.Rie    = 0;
564   Ier.Bits.Mie    = 0;
565   WRITE_IER (SerialDevice, Ier.Data);
566 
567   //
568   // Reset the FIFO
569   //
570   Fcr.Data = 0;
571   Fcr.Bits.TrFIFOE = 0;
572   WRITE_FCR (SerialDevice, Fcr.Data);
573 
574   //
575   // Turn off loopback and disable device interrupt.
576   //
577   Mcr.Data      = READ_MCR (SerialDevice);
578   Mcr.Bits.Out1 = 0;
579   Mcr.Bits.Out2 = 0;
580   Mcr.Bits.Lme  = 0;
581   WRITE_MCR (SerialDevice, Mcr.Data);
582 
583   //
584   // Clear the scratch pad register
585   //
586   WRITE_SCR (SerialDevice, 0);
587 
588   //
589   // Enable FIFO
590   //
591   Fcr.Bits.TrFIFOE  = 1;
592   if (SerialDevice->ReceiveFifoDepth > 16) {
593     Fcr.Bits.TrFIFO64 = 1;
594   }
595   Fcr.Bits.ResetRF  = 1;
596   Fcr.Bits.ResetTF  = 1;
597   WRITE_FCR (SerialDevice, Fcr.Data);
598 
599   //
600   // Go set the current attributes
601   //
602   Status = This->SetAttributes (
603                    This,
604                    This->Mode->BaudRate,
605                    This->Mode->ReceiveFifoDepth,
606                    This->Mode->Timeout,
607                    (EFI_PARITY_TYPE) This->Mode->Parity,
608                    (UINT8) This->Mode->DataBits,
609                    (EFI_STOP_BITS_TYPE) This->Mode->StopBits
610                    );
611 
612   if (EFI_ERROR (Status)) {
613     gBS->RestoreTPL (Tpl);
614     return EFI_DEVICE_ERROR;
615   }
616   //
617   // Go set the current control bits
618   //
619   Control = 0;
620   if (SerialDevice->HardwareFlowControl) {
621     Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
622   }
623   if (SerialDevice->SoftwareLoopbackEnable) {
624     Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
625   }
626   Status = This->SetControl (
627                    This,
628                    Control
629                    );
630 
631   if (EFI_ERROR (Status)) {
632     gBS->RestoreTPL (Tpl);
633     return EFI_DEVICE_ERROR;
634   }
635 
636   //
637   // Reset the software FIFO
638   //
639   SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0;
640   SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0;
641   gBS->RestoreTPL (Tpl);
642 
643   //
644   // Device reset is complete
645   //
646   return EFI_SUCCESS;
647 }
648 
649 /**
650   Set new attributes to a serial device.
651 
652   @param This                     Pointer to EFI_SERIAL_IO_PROTOCOL
653   @param  BaudRate                 The baudrate of the serial device
654   @param  ReceiveFifoDepth         The depth of receive FIFO buffer
655   @param  Timeout                  The request timeout for a single char
656   @param  Parity                   The type of parity used in serial device
657   @param  DataBits                 Number of databits used in serial device
658   @param  StopBits                 Number of stopbits used in serial device
659 
660   @retval  EFI_SUCCESS              The new attributes were set
661   @retval  EFI_INVALID_PARAMETERS   One or more attributes have an unsupported value
662   @retval  EFI_UNSUPPORTED          Data Bits can not set to 5 or 6
663   @retval  EFI_DEVICE_ERROR         The serial device is not functioning correctly (no return)
664 
665 **/
666 EFI_STATUS
667 EFIAPI
SerialSetAttributes(IN EFI_SERIAL_IO_PROTOCOL * This,IN UINT64 BaudRate,IN UINT32 ReceiveFifoDepth,IN UINT32 Timeout,IN EFI_PARITY_TYPE Parity,IN UINT8 DataBits,IN EFI_STOP_BITS_TYPE StopBits)668 SerialSetAttributes (
669   IN EFI_SERIAL_IO_PROTOCOL  *This,
670   IN UINT64                  BaudRate,
671   IN UINT32                  ReceiveFifoDepth,
672   IN UINT32                  Timeout,
673   IN EFI_PARITY_TYPE         Parity,
674   IN UINT8                   DataBits,
675   IN EFI_STOP_BITS_TYPE      StopBits
676   )
677 {
678   EFI_STATUS                Status;
679   SERIAL_DEV                *SerialDevice;
680   UINT64                    Divisor;
681   SERIAL_PORT_LCR           Lcr;
682   UART_DEVICE_PATH          *Uart;
683   EFI_TPL                   Tpl;
684 
685   SerialDevice = SERIAL_DEV_FROM_THIS (This);
686 
687   //
688   // Check for default settings and fill in actual values.
689   //
690   if (BaudRate == 0) {
691     BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
692   }
693 
694   if (ReceiveFifoDepth == 0) {
695     ReceiveFifoDepth = SerialDevice->ReceiveFifoDepth;
696   }
697 
698   if (Timeout == 0) {
699     Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
700   }
701 
702   if (Parity == DefaultParity) {
703     Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity);
704   }
705 
706   if (DataBits == 0) {
707     DataBits = PcdGet8 (PcdUartDefaultDataBits);
708   }
709 
710   if (StopBits == DefaultStopBits) {
711     StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
712   }
713 
714   if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, Parity, StopBits, &Divisor, &BaudRate)) {
715     return EFI_INVALID_PARAMETER;
716   }
717 
718   if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > SerialDevice->ReceiveFifoDepth)) {
719     return EFI_INVALID_PARAMETER;
720   }
721 
722   if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
723     return EFI_INVALID_PARAMETER;
724   }
725 
726   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
727 
728   //
729   // Wait for all data to be transmitted before changing the UART configuration.
730   //
731   // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
732   // that may send additional characters to this UART device until the UART
733   // configuration change is complete.
734   //
735   SerialFlushTransmitFifo (SerialDevice);
736 
737   //
738   // Put serial port on Divisor Latch Mode
739   //
740   Lcr.Data      = READ_LCR (SerialDevice);
741   Lcr.Bits.DLab = 1;
742   WRITE_LCR (SerialDevice, Lcr.Data);
743 
744   //
745   // Write the divisor to the serial port
746   //
747   WRITE_DLL (SerialDevice, (UINT8) Divisor);
748   WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8));
749 
750   //
751   // Put serial port back in normal mode and set remaining attributes.
752   //
753   Lcr.Bits.DLab = 0;
754 
755   switch (Parity) {
756   case NoParity:
757     Lcr.Bits.ParEn    = 0;
758     Lcr.Bits.EvenPar  = 0;
759     Lcr.Bits.SticPar  = 0;
760     break;
761 
762   case EvenParity:
763     Lcr.Bits.ParEn    = 1;
764     Lcr.Bits.EvenPar  = 1;
765     Lcr.Bits.SticPar  = 0;
766     break;
767 
768   case OddParity:
769     Lcr.Bits.ParEn    = 1;
770     Lcr.Bits.EvenPar  = 0;
771     Lcr.Bits.SticPar  = 0;
772     break;
773 
774   case SpaceParity:
775     Lcr.Bits.ParEn    = 1;
776     Lcr.Bits.EvenPar  = 1;
777     Lcr.Bits.SticPar  = 1;
778     break;
779 
780   case MarkParity:
781     Lcr.Bits.ParEn    = 1;
782     Lcr.Bits.EvenPar  = 0;
783     Lcr.Bits.SticPar  = 1;
784     break;
785 
786   default:
787     break;
788   }
789 
790   switch (StopBits) {
791   case OneStopBit:
792     Lcr.Bits.StopB = 0;
793     break;
794 
795   case OneFiveStopBits:
796   case TwoStopBits:
797     Lcr.Bits.StopB = 1;
798     break;
799 
800   default:
801     break;
802   }
803   //
804   // DataBits
805   //
806   Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
807   WRITE_LCR (SerialDevice, Lcr.Data);
808 
809   //
810   // Set the Serial I/O mode
811   //
812   This->Mode->BaudRate          = BaudRate;
813   This->Mode->ReceiveFifoDepth  = ReceiveFifoDepth;
814   This->Mode->Timeout           = Timeout;
815   This->Mode->Parity            = Parity;
816   This->Mode->DataBits          = DataBits;
817   This->Mode->StopBits          = StopBits;
818 
819   //
820   // See if Device Path Node has actually changed
821   //
822   if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
823       SerialDevice->UartDevicePath.DataBits == DataBits &&
824       SerialDevice->UartDevicePath.Parity == Parity &&
825       SerialDevice->UartDevicePath.StopBits == StopBits
826       ) {
827     gBS->RestoreTPL (Tpl);
828     return EFI_SUCCESS;
829   }
830   //
831   // Update the device path
832   //
833   SerialDevice->UartDevicePath.BaudRate = BaudRate;
834   SerialDevice->UartDevicePath.DataBits = DataBits;
835   SerialDevice->UartDevicePath.Parity   = (UINT8) Parity;
836   SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
837 
838   Status = EFI_SUCCESS;
839   if (SerialDevice->Handle != NULL) {
840 
841     //
842     // Skip the optional Controller device path node
843     //
844     Uart = SkipControllerDevicePathNode (
845              (EFI_DEVICE_PATH_PROTOCOL *) (
846                (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH
847                ),
848              NULL,
849              NULL
850              );
851     CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
852     Status = gBS->ReinstallProtocolInterface (
853                     SerialDevice->Handle,
854                     &gEfiDevicePathProtocolGuid,
855                     SerialDevice->DevicePath,
856                     SerialDevice->DevicePath
857                     );
858   }
859 
860   gBS->RestoreTPL (Tpl);
861 
862   return Status;
863 }
864 
865 /**
866   Set Control Bits.
867 
868   @param This              Pointer to EFI_SERIAL_IO_PROTOCOL
869   @param Control           Control bits that can be settable
870 
871   @retval EFI_SUCCESS       New Control bits were set successfully
872   @retval EFI_UNSUPPORTED   The Control bits wanted to set are not supported
873 
874 **/
875 EFI_STATUS
876 EFIAPI
SerialSetControl(IN EFI_SERIAL_IO_PROTOCOL * This,IN UINT32 Control)877 SerialSetControl (
878   IN EFI_SERIAL_IO_PROTOCOL  *This,
879   IN UINT32                  Control
880   )
881 {
882   SERIAL_DEV                    *SerialDevice;
883   SERIAL_PORT_MCR               Mcr;
884   EFI_TPL                       Tpl;
885   UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
886   EFI_STATUS                    Status;
887 
888   //
889   // The control bits that can be set are :
890   //     EFI_SERIAL_DATA_TERMINAL_READY: 0x0001  // WO
891   //     EFI_SERIAL_REQUEST_TO_SEND: 0x0002  // WO
892   //     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000  // RW
893   //     EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000  // RW
894   //     EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
895   //
896   SerialDevice = SERIAL_DEV_FROM_THIS (This);
897 
898   //
899   // first determine the parameter is invalid
900   //
901   if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
902                     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
903                     EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
904     return EFI_UNSUPPORTED;
905   }
906 
907   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
908 
909   //
910   // Wait for all data to be transmitted before changing the UART configuration.
911   //
912   // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
913   // that may send additional characters to this UART device until the UART
914   // configuration change is complete.
915   //
916   SerialFlushTransmitFifo (SerialDevice);
917 
918   Mcr.Data = READ_MCR (SerialDevice);
919   Mcr.Bits.DtrC = 0;
920   Mcr.Bits.Rts = 0;
921   Mcr.Bits.Lme = 0;
922   SerialDevice->SoftwareLoopbackEnable = FALSE;
923   SerialDevice->HardwareFlowControl = FALSE;
924 
925   if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
926     Mcr.Bits.DtrC = 1;
927   }
928 
929   if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
930     Mcr.Bits.Rts = 1;
931   }
932 
933   if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
934     Mcr.Bits.Lme = 1;
935   }
936 
937   if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
938     SerialDevice->HardwareFlowControl = TRUE;
939   }
940 
941   WRITE_MCR (SerialDevice, Mcr.Data);
942 
943   if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
944     SerialDevice->SoftwareLoopbackEnable = TRUE;
945   }
946 
947   Status = EFI_SUCCESS;
948   if (SerialDevice->Handle != NULL) {
949     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
950                     (UINTN) SerialDevice->DevicePath
951                     + GetDevicePathSize (SerialDevice->ParentDevicePath)
952                     - END_DEVICE_PATH_LENGTH
953                     + sizeof (UART_DEVICE_PATH)
954                     );
955     if (IsUartFlowControlDevicePathNode (FlowControl) &&
956         ((BOOLEAN) (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) != SerialDevice->HardwareFlowControl)) {
957       //
958       // Flow Control setting is changed, need to reinstall device path protocol
959       //
960       WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);
961       Status = gBS->ReinstallProtocolInterface (
962                       SerialDevice->Handle,
963                       &gEfiDevicePathProtocolGuid,
964                       SerialDevice->DevicePath,
965                       SerialDevice->DevicePath
966                       );
967     }
968   }
969 
970   gBS->RestoreTPL (Tpl);
971 
972   return Status;
973 }
974 
975 /**
976   Get ControlBits.
977 
978   @param This          Pointer to EFI_SERIAL_IO_PROTOCOL
979   @param Control       Control signals of the serial device
980 
981   @retval EFI_SUCCESS   Get Control signals successfully
982 
983 **/
984 EFI_STATUS
985 EFIAPI
SerialGetControl(IN EFI_SERIAL_IO_PROTOCOL * This,OUT UINT32 * Control)986 SerialGetControl (
987   IN EFI_SERIAL_IO_PROTOCOL  *This,
988   OUT UINT32                 *Control
989   )
990 {
991   SERIAL_DEV      *SerialDevice;
992   SERIAL_PORT_MSR Msr;
993   SERIAL_PORT_MCR Mcr;
994   EFI_TPL         Tpl;
995 
996   Tpl           = gBS->RaiseTPL (TPL_NOTIFY);
997 
998   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
999 
1000   *Control      = 0;
1001 
1002   //
1003   // Read the Modem Status Register
1004   //
1005   Msr.Data = READ_MSR (SerialDevice);
1006 
1007   if (Msr.Bits.Cts == 1) {
1008     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
1009   }
1010 
1011   if (Msr.Bits.Dsr == 1) {
1012     *Control |= EFI_SERIAL_DATA_SET_READY;
1013   }
1014 
1015   if (Msr.Bits.Ri == 1) {
1016     *Control |= EFI_SERIAL_RING_INDICATE;
1017   }
1018 
1019   if (Msr.Bits.Dcd == 1) {
1020     *Control |= EFI_SERIAL_CARRIER_DETECT;
1021   }
1022   //
1023   // Read the Modem Control Register
1024   //
1025   Mcr.Data = READ_MCR (SerialDevice);
1026 
1027   if (Mcr.Bits.DtrC == 1) {
1028     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1029   }
1030 
1031   if (Mcr.Bits.Rts == 1) {
1032     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
1033   }
1034 
1035   if (Mcr.Bits.Lme == 1) {
1036     *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1037   }
1038 
1039   if (SerialDevice->HardwareFlowControl) {
1040     *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1041   }
1042   //
1043   // Update FIFO status
1044   //
1045   SerialReceiveTransmit (SerialDevice);
1046 
1047   //
1048   // See if the Transmit FIFO is empty
1049   //
1050   if (SerialFifoEmpty (&SerialDevice->Transmit)) {
1051     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
1052   }
1053 
1054   //
1055   // See if the Receive FIFO is empty.
1056   //
1057   if (SerialFifoEmpty (&SerialDevice->Receive)) {
1058     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1059   }
1060 
1061   if (SerialDevice->SoftwareLoopbackEnable) {
1062     *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1063   }
1064 
1065   gBS->RestoreTPL (Tpl);
1066 
1067   return EFI_SUCCESS;
1068 }
1069 
1070 /**
1071   Write the specified number of bytes to serial device.
1072 
1073   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
1074   @param  BufferSize         On input the size of Buffer, on output the amount of
1075                        data actually written
1076   @param  Buffer             The buffer of data to write
1077 
1078   @retval EFI_SUCCESS        The data were written successfully
1079   @retval EFI_DEVICE_ERROR   The device reported an error
1080   @retval EFI_TIMEOUT        The write operation was stopped due to timeout
1081 
1082 **/
1083 EFI_STATUS
1084 EFIAPI
SerialWrite(IN EFI_SERIAL_IO_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)1085 SerialWrite (
1086   IN EFI_SERIAL_IO_PROTOCOL  *This,
1087   IN OUT UINTN               *BufferSize,
1088   IN VOID                    *Buffer
1089   )
1090 {
1091   SERIAL_DEV  *SerialDevice;
1092   UINT8       *CharBuffer;
1093   UINT32      Index;
1094   UINTN       Elapsed;
1095   UINTN       ActualWrite;
1096   EFI_TPL     Tpl;
1097   UINTN       Timeout;
1098   UINTN       BitsPerCharacter;
1099 
1100   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1101   Elapsed       = 0;
1102   ActualWrite   = 0;
1103 
1104   if (*BufferSize == 0) {
1105     return EFI_SUCCESS;
1106   }
1107 
1108   if (Buffer == NULL) {
1109     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1110       EFI_ERROR_CODE,
1111       EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1112       SerialDevice->DevicePath
1113       );
1114 
1115     return EFI_DEVICE_ERROR;
1116   }
1117 
1118   Tpl         = gBS->RaiseTPL (TPL_NOTIFY);
1119 
1120   CharBuffer  = (UINT8 *) Buffer;
1121 
1122   //
1123   // Compute the number of bits in a single character.  This is a start bit,
1124   // followed by the number of data bits, followed by the number of stop bits.
1125   // The number of stop bits is specified by an enumeration that includes
1126   // support for 1.5 stop bits.  Treat 1.5 stop bits as 2 stop bits.
1127   //
1128   BitsPerCharacter =
1129     1 +
1130     This->Mode->DataBits +
1131     ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits);
1132 
1133   //
1134   // Compute the timeout in microseconds to wait for a single byte to be
1135   // transmitted.  The Mode structure contans a Timeout field that is the
1136   // maximum time to transmit or receive a character.  However, many UARTs
1137   // have a FIFO for transmits, so the time required to add one new character
1138   // to the transmit FIFO may be the time required to flush a full FIFO.  If
1139   // the Timeout in the Mode structure is smaller than the time required to
1140   // flush a full FIFO at the current baud rate, then use a timeout value that
1141   // is required to flush a full transmit FIFO.
1142   //
1143   Timeout = MAX (
1144               This->Mode->Timeout,
1145               (UINTN)DivU64x64Remainder (
1146                 BitsPerCharacter * (SerialDevice->TransmitFifoDepth + 1) * 1000000,
1147                 This->Mode->BaudRate,
1148                 NULL
1149                 )
1150               );
1151 
1152   for (Index = 0; Index < *BufferSize; Index++) {
1153     SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
1154 
1155     while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !SerialFifoEmpty (&SerialDevice->Transmit)) {
1156       //
1157       //  Unsuccessful write so check if timeout has expired, if not,
1158       //  stall for a bit, increment time elapsed, and try again
1159       //
1160       if (Elapsed >= Timeout) {
1161         *BufferSize = ActualWrite;
1162         gBS->RestoreTPL (Tpl);
1163         return EFI_TIMEOUT;
1164       }
1165 
1166       gBS->Stall (TIMEOUT_STALL_INTERVAL);
1167 
1168       Elapsed += TIMEOUT_STALL_INTERVAL;
1169     }
1170 
1171     ActualWrite++;
1172     //
1173     //  Successful write so reset timeout
1174     //
1175     Elapsed = 0;
1176   }
1177 
1178   gBS->RestoreTPL (Tpl);
1179 
1180   return EFI_SUCCESS;
1181 }
1182 
1183 /**
1184   Read the specified number of bytes from serial device.
1185 
1186   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
1187   @param BufferSize         On input the size of Buffer, on output the amount of
1188                             data returned in buffer
1189   @param Buffer             The buffer to return the data into
1190 
1191   @retval EFI_SUCCESS        The data were read successfully
1192   @retval EFI_DEVICE_ERROR   The device reported an error
1193   @retval EFI_TIMEOUT        The read operation was stopped due to timeout
1194 
1195 **/
1196 EFI_STATUS
1197 EFIAPI
SerialRead(IN EFI_SERIAL_IO_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)1198 SerialRead (
1199   IN EFI_SERIAL_IO_PROTOCOL  *This,
1200   IN OUT UINTN               *BufferSize,
1201   OUT VOID                   *Buffer
1202   )
1203 {
1204   SERIAL_DEV  *SerialDevice;
1205   UINT32      Index;
1206   UINT8       *CharBuffer;
1207   UINTN       Elapsed;
1208   EFI_STATUS  Status;
1209   EFI_TPL     Tpl;
1210 
1211   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1212   Elapsed       = 0;
1213 
1214   if (*BufferSize == 0) {
1215     return EFI_SUCCESS;
1216   }
1217 
1218   if (Buffer == NULL) {
1219     return EFI_DEVICE_ERROR;
1220   }
1221 
1222   Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
1223 
1224   Status  = SerialReceiveTransmit (SerialDevice);
1225 
1226   if (EFI_ERROR (Status)) {
1227     *BufferSize = 0;
1228 
1229     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1230       EFI_ERROR_CODE,
1231       EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1232       SerialDevice->DevicePath
1233       );
1234 
1235     gBS->RestoreTPL (Tpl);
1236 
1237     return EFI_DEVICE_ERROR;
1238   }
1239 
1240   CharBuffer = (UINT8 *) Buffer;
1241   for (Index = 0; Index < *BufferSize; Index++) {
1242     while (SerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
1243       //
1244       //  Unsuccessful read so check if timeout has expired, if not,
1245       //  stall for a bit, increment time elapsed, and try again
1246       //  Need this time out to get conspliter to work.
1247       //
1248       if (Elapsed >= This->Mode->Timeout) {
1249         *BufferSize = Index;
1250         gBS->RestoreTPL (Tpl);
1251         return EFI_TIMEOUT;
1252       }
1253 
1254       gBS->Stall (TIMEOUT_STALL_INTERVAL);
1255       Elapsed += TIMEOUT_STALL_INTERVAL;
1256 
1257       Status = SerialReceiveTransmit (SerialDevice);
1258       if (Status == EFI_DEVICE_ERROR) {
1259         *BufferSize = Index;
1260         gBS->RestoreTPL (Tpl);
1261         return EFI_DEVICE_ERROR;
1262       }
1263     }
1264     //
1265     //  Successful read so reset timeout
1266     //
1267     Elapsed = 0;
1268   }
1269 
1270   SerialReceiveTransmit (SerialDevice);
1271 
1272   gBS->RestoreTPL (Tpl);
1273 
1274   return EFI_SUCCESS;
1275 }
1276 
1277 /**
1278   Use scratchpad register to test if this serial port is present.
1279 
1280   @param SerialDevice   Pointer to serial device structure
1281 
1282   @return if this serial port is present
1283 **/
1284 BOOLEAN
SerialPresent(IN SERIAL_DEV * SerialDevice)1285 SerialPresent (
1286   IN SERIAL_DEV *SerialDevice
1287   )
1288 
1289 {
1290   UINT8   Temp;
1291   BOOLEAN Status;
1292 
1293   Status = TRUE;
1294 
1295   //
1296   // Save SCR reg
1297   //
1298   Temp = READ_SCR (SerialDevice);
1299   WRITE_SCR (SerialDevice, 0xAA);
1300 
1301   if (READ_SCR (SerialDevice) != 0xAA) {
1302     Status = FALSE;
1303   }
1304 
1305   WRITE_SCR (SerialDevice, 0x55);
1306 
1307   if (READ_SCR (SerialDevice) != 0x55) {
1308     Status = FALSE;
1309   }
1310   //
1311   // Restore SCR
1312   //
1313   WRITE_SCR (SerialDevice, Temp);
1314   return Status;
1315 }
1316 
1317 /**
1318   Read serial port.
1319 
1320   @param SerialDev     Pointer to serial device
1321   @param Offset        Offset in register group
1322 
1323   @return Data read from serial port
1324 
1325 **/
1326 UINT8
SerialReadRegister(IN SERIAL_DEV * SerialDev,IN UINT32 Offset)1327 SerialReadRegister (
1328   IN SERIAL_DEV                            *SerialDev,
1329   IN UINT32                                Offset
1330   )
1331 {
1332   UINT8                                    Data;
1333   EFI_STATUS                               Status;
1334 
1335   if (SerialDev->PciDeviceInfo == NULL) {
1336     return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride);
1337   } else {
1338     if (SerialDev->MmioAccess) {
1339       Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1340                                                           SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1341     } else {
1342       Status = SerialDev->PciDeviceInfo->PciIo->Io.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1343                                                          SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1344     }
1345     ASSERT_EFI_ERROR (Status);
1346     return Data;
1347   }
1348 }
1349 
1350 /**
1351   Write serial port.
1352 
1353   @param  SerialDev     Pointer to serial device
1354   @param  Offset        Offset in register group
1355   @param  Data          data which is to be written to some serial port register
1356 **/
1357 VOID
SerialWriteRegister(IN SERIAL_DEV * SerialDev,IN UINT32 Offset,IN UINT8 Data)1358 SerialWriteRegister (
1359   IN SERIAL_DEV                            *SerialDev,
1360   IN UINT32                                Offset,
1361   IN UINT8                                 Data
1362   )
1363 {
1364   EFI_STATUS                               Status;
1365 
1366   if (SerialDev->PciDeviceInfo == NULL) {
1367     IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, Data);
1368   } else {
1369     if (SerialDev->MmioAccess) {
1370       Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1371                                                            SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1372     } else {
1373       Status = SerialDev->PciDeviceInfo->PciIo->Io.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1374                                                           SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1375     }
1376     ASSERT_EFI_ERROR (Status);
1377   }
1378 }
1379