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