Home | History | Annotate | Download | only in IsaSerialDxe
      1 /** @file
      2   Serial driver for standard UARTS on an ISA bus.
      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 // ISA Serial Driver Global Variables
     19 //
     20 EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
     21   SerialControllerDriverSupported,
     22   SerialControllerDriverStart,
     23   SerialControllerDriverStop,
     24   0xa,
     25   NULL,
     26   NULL
     27 };
     28 
     29 
     30 SERIAL_DEV  gSerialDevTempate = {
     31   SERIAL_DEV_SIGNATURE,
     32   NULL,
     33   { // SerialIo
     34     SERIAL_IO_INTERFACE_REVISION,
     35     IsaSerialReset,
     36     IsaSerialSetAttributes,
     37     IsaSerialSetControl,
     38     IsaSerialGetControl,
     39     IsaSerialWrite,
     40     IsaSerialRead,
     41     NULL
     42   },
     43   { // SerialMode
     44     SERIAL_PORT_SUPPORT_CONTROL_MASK,
     45     SERIAL_PORT_DEFAULT_TIMEOUT,
     46     0,
     47     SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
     48     0,
     49     0,
     50     0
     51   },
     52   NULL,
     53   NULL,
     54   { // UartDevicePath
     55     {
     56       MESSAGING_DEVICE_PATH,
     57       MSG_UART_DP,
     58       {
     59         (UINT8) (sizeof (UART_DEVICE_PATH)),
     60         (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
     61       }
     62     },
     63     0,
     64     0,
     65     0,
     66     0,
     67     0
     68   },
     69   NULL,
     70   0,    //BaseAddress
     71   {
     72     0,
     73     0,
     74     SERIAL_MAX_BUFFER_SIZE,
     75     { 0 }
     76   },
     77   {
     78     0,
     79     0,
     80     SERIAL_MAX_BUFFER_SIZE,
     81     { 0 }
     82   },
     83   FALSE,
     84   FALSE,
     85   Uart16550A,
     86   NULL
     87 };
     88 
     89 /**
     90   Check the device path node whether it's the Flow Control node or not.
     91 
     92   @param[in] FlowControl    The device path node to be checked.
     93 
     94   @retval TRUE              It's the Flow Control node.
     95   @retval FALSE             It's not.
     96 
     97 **/
     98 BOOLEAN
     99 IsUartFlowControlNode (
    100   IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
    101   )
    102 {
    103   return (BOOLEAN) (
    104            (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
    105            (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
    106            (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
    107            );
    108 }
    109 
    110 /**
    111   Check the device path node whether it contains Flow Control node or not.
    112 
    113   @param[in] DevicePath     The device path to be checked.
    114 
    115   @retval TRUE              It contains the Flow Control node.
    116   @retval FALSE             It doesn't.
    117 
    118 **/
    119 BOOLEAN
    120 ContainsFlowControl (
    121   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath
    122   )
    123 {
    124   while (!IsDevicePathEnd (DevicePath)) {
    125     if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) {
    126       return TRUE;
    127     }
    128     DevicePath = NextDevicePathNode (DevicePath);
    129   }
    130 
    131   return FALSE;
    132 }
    133 
    134 /**
    135   The user Entry Point for module IsaSerial. The user code starts with this function.
    136 
    137   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
    138   @param[in] SystemTable    A pointer to the EFI System Table.
    139 
    140   @retval EFI_SUCCESS       The entry point is executed successfully.
    141   @retval other             Some error occurs when executing this entry point.
    142 
    143 **/
    144 EFI_STATUS
    145 EFIAPI
    146 InitializeIsaSerial (
    147   IN EFI_HANDLE           ImageHandle,
    148   IN EFI_SYSTEM_TABLE     *SystemTable
    149   )
    150 {
    151   EFI_STATUS              Status;
    152 
    153   //
    154   // Install driver model protocol(s).
    155   //
    156   Status = EfiLibInstallDriverBindingComponentName2 (
    157              ImageHandle,
    158              SystemTable,
    159              &gSerialControllerDriver,
    160              ImageHandle,
    161              &gIsaSerialComponentName,
    162              &gIsaSerialComponentName2
    163              );
    164   ASSERT_EFI_ERROR (Status);
    165 
    166   //
    167   // Initialize UART default setting in gSerialDevTempate
    168   //
    169   gSerialDevTempate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
    170   gSerialDevTempate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);
    171   gSerialDevTempate.SerialMode.Parity   = PcdGet8 (PcdUartDefaultParity);
    172   gSerialDevTempate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);
    173   gSerialDevTempate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
    174   gSerialDevTempate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);
    175   gSerialDevTempate.UartDevicePath.Parity   = PcdGet8 (PcdUartDefaultParity);
    176   gSerialDevTempate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);
    177 
    178   return Status;
    179 }
    180 
    181 /**
    182   Check to see if this driver supports the given controller
    183 
    184   @param  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    185   @param  Controller           The handle of the controller to test.
    186   @param  RemainingDevicePath  A pointer to the remaining portion of a device path.
    187 
    188   @return EFI_SUCCESS          This driver can support the given controller
    189 
    190 **/
    191 EFI_STATUS
    192 EFIAPI
    193 SerialControllerDriverSupported (
    194   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    195   IN EFI_HANDLE                     Controller,
    196   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    197   )
    198 
    199 {
    200   EFI_STATUS                                Status;
    201   EFI_DEVICE_PATH_PROTOCOL                  *ParentDevicePath;
    202   EFI_ISA_IO_PROTOCOL                       *IsaIo;
    203   UART_DEVICE_PATH                          *UartNode;
    204   EFI_DEVICE_PATH_PROTOCOL                  *DevicePath;
    205   UART_FLOW_CONTROL_DEVICE_PATH             *FlowControlNode;
    206   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY       *OpenInfoBuffer;
    207   UINTN                                     EntryCount;
    208   UINTN                                     Index;
    209   BOOLEAN                                   HasFlowControl;
    210 
    211   //
    212   // Check RemainingDevicePath validation
    213   //
    214   if (RemainingDevicePath != NULL) {
    215     //
    216     // Check if RemainingDevicePath is the End of Device Path Node,
    217     // if yes, go on checking other conditions
    218     //
    219     if (!IsDevicePathEnd (RemainingDevicePath)) {
    220       //
    221       // If RemainingDevicePath isn't the End of Device Path Node,
    222       // check its validation
    223       //
    224       Status = EFI_UNSUPPORTED;
    225 
    226       UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
    227       if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
    228           UartNode->Header.SubType != MSG_UART_DP ||
    229           sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) UartNode)
    230                                         ) {
    231         goto Error;
    232       }
    233 
    234       if (UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
    235         goto Error;
    236       }
    237 
    238       if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
    239         goto Error;
    240       }
    241 
    242       if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
    243         goto Error;
    244       }
    245 
    246       if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
    247         goto Error;
    248       }
    249 
    250       if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
    251         goto Error;
    252       }
    253 
    254       if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
    255         goto Error;
    256       }
    257 
    258       FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);
    259       if (IsUartFlowControlNode (FlowControlNode)) {
    260         //
    261         // If the second node is Flow Control Node,
    262         //   return error when it request other than hardware flow control.
    263         //
    264         if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
    265           goto Error;
    266         }
    267       }
    268     }
    269   }
    270 
    271   //
    272   // Open the IO Abstraction(s) needed to perform the supported test
    273   //
    274   Status = gBS->OpenProtocol (
    275                   Controller,
    276                   &gEfiIsaIoProtocolGuid,
    277                   (VOID **) &IsaIo,
    278                   This->DriverBindingHandle,
    279                   Controller,
    280                   EFI_OPEN_PROTOCOL_BY_DRIVER
    281                   );
    282   if (Status == EFI_ALREADY_STARTED) {
    283     if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
    284       //
    285       // If RemainingDevicePath is NULL or is the End of Device Path Node
    286       //
    287       return EFI_SUCCESS;
    288     }
    289     //
    290     // When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node,
    291     //   return unsupported, and vice versa.
    292     //
    293     Status = gBS->OpenProtocolInformation (
    294                     Controller,
    295                     &gEfiIsaIoProtocolGuid,
    296                     &OpenInfoBuffer,
    297                     &EntryCount
    298                     );
    299     if (EFI_ERROR (Status)) {
    300       return Status;
    301     }
    302 
    303     for (Index = 0; Index < EntryCount; Index++) {
    304       if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
    305         Status = gBS->OpenProtocol (
    306                         OpenInfoBuffer[Index].ControllerHandle,
    307                         &gEfiDevicePathProtocolGuid,
    308                         (VOID **) &DevicePath,
    309                         This->DriverBindingHandle,
    310                         Controller,
    311                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
    312                         );
    313         if (!EFI_ERROR (Status)) {
    314           HasFlowControl = ContainsFlowControl (RemainingDevicePath);
    315           if (HasFlowControl ^ ContainsFlowControl (DevicePath)) {
    316             Status = EFI_UNSUPPORTED;
    317           }
    318         }
    319         break;
    320       }
    321     }
    322     FreePool (OpenInfoBuffer);
    323     return Status;
    324   }
    325 
    326   if (EFI_ERROR (Status)) {
    327     return Status;
    328   }
    329 
    330   //
    331   // Close the I/O Abstraction(s) used to perform the supported test
    332   //
    333   gBS->CloseProtocol (
    334          Controller,
    335          &gEfiIsaIoProtocolGuid,
    336          This->DriverBindingHandle,
    337          Controller
    338          );
    339 
    340   //
    341   // Open the EFI Device Path protocol needed to perform the supported test
    342   //
    343   Status = gBS->OpenProtocol (
    344                   Controller,
    345                   &gEfiDevicePathProtocolGuid,
    346                   (VOID **) &ParentDevicePath,
    347                   This->DriverBindingHandle,
    348                   Controller,
    349                   EFI_OPEN_PROTOCOL_BY_DRIVER
    350                   );
    351   if (Status == EFI_ALREADY_STARTED) {
    352     return EFI_SUCCESS;
    353   }
    354 
    355   if (EFI_ERROR (Status)) {
    356     return Status;
    357   }
    358   //
    359   // Use the ISA I/O Protocol to see if Controller is standard ISA UART that
    360   // can be managed by this driver.
    361   //
    362   Status = EFI_SUCCESS;
    363   if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) {
    364     Status = EFI_UNSUPPORTED;
    365     goto Error;
    366   }
    367 
    368 Error:
    369   //
    370   // Close protocol, don't use device path protocol in the Support() function
    371   //
    372   gBS->CloseProtocol (
    373          Controller,
    374          &gEfiDevicePathProtocolGuid,
    375          This->DriverBindingHandle,
    376          Controller
    377          );
    378 
    379   return Status;
    380 }
    381 
    382 /**
    383   Start to management the controller passed in
    384 
    385   @param  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    386   @param  Controller           The handle of the controller to test.
    387   @param  RemainingDevicePath  A pointer to the remaining portion of a device path.
    388 
    389   @return EFI_SUCCESS   Driver is started successfully
    390 
    391 **/
    392 EFI_STATUS
    393 EFIAPI
    394 SerialControllerDriverStart (
    395   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    396   IN EFI_HANDLE                     Controller,
    397   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    398   )
    399 
    400 {
    401   EFI_STATUS                          Status;
    402   EFI_ISA_IO_PROTOCOL                 *IsaIo;
    403   SERIAL_DEV                          *SerialDevice;
    404   UINTN                               Index;
    405   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
    406   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
    407   UINTN                               EntryCount;
    408   EFI_SERIAL_IO_PROTOCOL              *SerialIo;
    409   UART_DEVICE_PATH                    *Uart;
    410   UINT32                              FlowControlMap;
    411   UART_FLOW_CONTROL_DEVICE_PATH       *FlowControl;
    412   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
    413   UINT32                              Control;
    414 
    415   SerialDevice = NULL;
    416   //
    417   // Get the Parent Device Path
    418   //
    419   Status = gBS->OpenProtocol (
    420                   Controller,
    421                   &gEfiDevicePathProtocolGuid,
    422                   (VOID **) &ParentDevicePath,
    423                   This->DriverBindingHandle,
    424                   Controller,
    425                   EFI_OPEN_PROTOCOL_BY_DRIVER
    426                   );
    427   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    428     return Status;
    429   }
    430   //
    431   // Report status code enable the serial
    432   //
    433   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    434     EFI_PROGRESS_CODE,
    435     EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
    436     ParentDevicePath
    437     );
    438 
    439   //
    440   // Grab the IO abstraction we need to get any work done
    441   //
    442   Status = gBS->OpenProtocol (
    443                   Controller,
    444                   &gEfiIsaIoProtocolGuid,
    445                   (VOID **) &IsaIo,
    446                   This->DriverBindingHandle,
    447                   Controller,
    448                   EFI_OPEN_PROTOCOL_BY_DRIVER
    449                   );
    450   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    451     goto Error;
    452   }
    453 
    454   if (Status == EFI_ALREADY_STARTED) {
    455 
    456     if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
    457       //
    458       // If RemainingDevicePath is NULL or is the End of Device Path Node
    459       //
    460       return EFI_SUCCESS;
    461     }
    462 
    463     //
    464     // Make sure a child handle does not already exist.  This driver can only
    465     // produce one child per serial port.
    466     //
    467     Status = gBS->OpenProtocolInformation (
    468                     Controller,
    469                     &gEfiIsaIoProtocolGuid,
    470                     &OpenInfoBuffer,
    471                     &EntryCount
    472                     );
    473     if (EFI_ERROR (Status)) {
    474       return Status;
    475     }
    476 
    477     Status = EFI_ALREADY_STARTED;
    478     for (Index = 0; Index < EntryCount; Index++) {
    479       if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
    480         Status = gBS->OpenProtocol (
    481                         OpenInfoBuffer[Index].ControllerHandle,
    482                         &gEfiSerialIoProtocolGuid,
    483                         (VOID **) &SerialIo,
    484                         This->DriverBindingHandle,
    485                         Controller,
    486                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
    487                         );
    488         if (!EFI_ERROR (Status)) {
    489           Uart   = (UART_DEVICE_PATH *) RemainingDevicePath;
    490           Status = SerialIo->SetAttributes (
    491                                SerialIo,
    492                                Uart->BaudRate,
    493                                SerialIo->Mode->ReceiveFifoDepth,
    494                                SerialIo->Mode->Timeout,
    495                                (EFI_PARITY_TYPE) Uart->Parity,
    496                                Uart->DataBits,
    497                                (EFI_STOP_BITS_TYPE) Uart->StopBits
    498                                );
    499 
    500           FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
    501           if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {
    502             Status = SerialIo->GetControl (SerialIo, &Control);
    503             if (!EFI_ERROR (Status)) {
    504               if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
    505                 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
    506               } else {
    507                 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
    508               }
    509               //
    510               // Clear the bits that are not allowed to pass to SetControl
    511               //
    512               Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
    513                           EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
    514                           EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
    515               Status = SerialIo->SetControl (SerialIo, Control);
    516             }
    517           }
    518         }
    519         break;
    520       }
    521     }
    522 
    523     FreePool (OpenInfoBuffer);
    524     return Status;
    525   }
    526 
    527   if (RemainingDevicePath != NULL) {
    528     if (IsDevicePathEnd (RemainingDevicePath)) {
    529       //
    530       // If RemainingDevicePath is the End of Device Path Node,
    531       // skip enumerate any device and return EFI_SUCESSS
    532       //
    533       return EFI_SUCCESS;
    534     }
    535   }
    536 
    537   //
    538   // Initialize the serial device instance
    539   //
    540   SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTempate);
    541   if (SerialDevice == NULL) {
    542     Status = EFI_OUT_OF_RESOURCES;
    543     goto Error;
    544   }
    545 
    546   SerialDevice->SerialIo.Mode       = &(SerialDevice->SerialMode);
    547   SerialDevice->IsaIo               = IsaIo;
    548   SerialDevice->ParentDevicePath    = ParentDevicePath;
    549   FlowControl                       = NULL;
    550   FlowControlMap                    = 0;
    551 
    552   //
    553   // Check if RemainingDevicePath is NULL,
    554   // if yes, use the values from the gSerialDevTempate as no remaining device path was
    555   // passed in.
    556   //
    557   if (RemainingDevicePath != NULL) {
    558     //
    559     // If RemainingDevicePath isn't NULL,
    560     // match the configuration of the RemainingDevicePath. IsHandleSupported()
    561     // already checked to make sure the RemainingDevicePath contains settings
    562     // that we can support.
    563     //
    564     CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
    565     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
    566     if (IsUartFlowControlNode (FlowControl)) {
    567       FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
    568     } else {
    569       FlowControl    = NULL;
    570     }
    571   }
    572 
    573   AddName (SerialDevice, IsaIo);
    574 
    575   for (Index = 0; SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
    576     if (SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
    577       SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange;
    578     }
    579   }
    580 
    581   SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
    582 
    583   //
    584   // Report status code the serial present
    585   //
    586   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    587     EFI_PROGRESS_CODE,
    588     EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,
    589     ParentDevicePath
    590     );
    591 
    592   if (!IsaSerialPortPresent (SerialDevice)) {
    593     Status = EFI_DEVICE_ERROR;
    594     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    595       EFI_ERROR_CODE,
    596       EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
    597       ParentDevicePath
    598       );
    599     goto Error;
    600   }
    601 
    602   //
    603   // Build the device path by appending the UART node to the ParentDevicePath.
    604   // The Uart setings are zero here, since  SetAttribute() will update them to match
    605   // the default setings.
    606   //
    607   SerialDevice->DevicePath = AppendDevicePathNode (
    608                                ParentDevicePath,
    609                                (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
    610                                );
    611   //
    612   // Only produce the Flow Control node when remaining device path has it
    613   //
    614   if (FlowControl != NULL) {
    615     TempDevicePath = SerialDevice->DevicePath;
    616     if (TempDevicePath != NULL) {
    617       SerialDevice->DevicePath = AppendDevicePathNode (
    618                                    TempDevicePath,
    619                                    (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
    620                                    );
    621       FreePool (TempDevicePath);
    622     }
    623   }
    624   if (SerialDevice->DevicePath == NULL) {
    625     Status = EFI_OUT_OF_RESOURCES;
    626     goto Error;
    627   }
    628 
    629   //
    630   // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
    631   //
    632   SerialDevice->SerialMode.BaudRate         = SerialDevice->UartDevicePath.BaudRate;
    633   SerialDevice->SerialMode.DataBits         = SerialDevice->UartDevicePath.DataBits;
    634   SerialDevice->SerialMode.Parity           = SerialDevice->UartDevicePath.Parity;
    635   SerialDevice->SerialMode.StopBits         = SerialDevice->UartDevicePath.StopBits;
    636 
    637   //
    638   // Issue a reset to initialize the COM port
    639   //
    640   Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
    641   if (EFI_ERROR (Status)) {
    642     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    643       EFI_ERROR_CODE,
    644       EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
    645       ParentDevicePath
    646       );
    647     goto Error;
    648   }
    649   //
    650   // Install protocol interfaces for the serial device.
    651   //
    652   Status = gBS->InstallMultipleProtocolInterfaces (
    653                   &SerialDevice->Handle,
    654                   &gEfiDevicePathProtocolGuid,
    655                   SerialDevice->DevicePath,
    656                   &gEfiSerialIoProtocolGuid,
    657                   &SerialDevice->SerialIo,
    658                   NULL
    659                   );
    660   if (EFI_ERROR (Status)) {
    661     goto Error;
    662   }
    663   //
    664   // Open For Child Device
    665   //
    666   Status = gBS->OpenProtocol (
    667                   Controller,
    668                   &gEfiIsaIoProtocolGuid,
    669                   (VOID **) &IsaIo,
    670                   This->DriverBindingHandle,
    671                   SerialDevice->Handle,
    672                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    673                   );
    674 
    675 Error:
    676   if (EFI_ERROR (Status)) {
    677     gBS->CloseProtocol (
    678            Controller,
    679            &gEfiDevicePathProtocolGuid,
    680            This->DriverBindingHandle,
    681            Controller
    682            );
    683     gBS->CloseProtocol (
    684            Controller,
    685            &gEfiIsaIoProtocolGuid,
    686            This->DriverBindingHandle,
    687            Controller
    688            );
    689     if (SerialDevice != NULL) {
    690       if (SerialDevice->DevicePath != NULL) {
    691         gBS->FreePool (SerialDevice->DevicePath);
    692       }
    693 
    694       FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
    695       gBS->FreePool (SerialDevice);
    696     }
    697   }
    698 
    699   return Status;
    700 }
    701 
    702 /**
    703   Disconnect this driver with the controller, uninstall related protocol instance
    704 
    705   @param  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    706   @param  Controller            The handle of the controller to test.
    707   @param  NumberOfChildren      Number of child device.
    708   @param  ChildHandleBuffer     A pointer to the remaining portion of a device path.
    709 
    710   @retval EFI_SUCCESS           Operation successfully
    711   @retval EFI_DEVICE_ERROR      Cannot stop the driver successfully
    712 
    713 **/
    714 EFI_STATUS
    715 EFIAPI
    716 SerialControllerDriverStop (
    717   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    718   IN  EFI_HANDLE                     Controller,
    719   IN  UINTN                          NumberOfChildren,
    720   IN  EFI_HANDLE                     *ChildHandleBuffer
    721   )
    722 
    723 {
    724   EFI_STATUS                          Status;
    725   UINTN                               Index;
    726   BOOLEAN                             AllChildrenStopped;
    727   EFI_SERIAL_IO_PROTOCOL              *SerialIo;
    728   SERIAL_DEV                          *SerialDevice;
    729   EFI_ISA_IO_PROTOCOL                 *IsaIo;
    730   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
    731 
    732   Status = gBS->HandleProtocol (
    733                   Controller,
    734                   &gEfiDevicePathProtocolGuid,
    735                   (VOID **) &DevicePath
    736                   );
    737 
    738   //
    739   // Report the status code disable the serial
    740   //
    741   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    742     EFI_PROGRESS_CODE,
    743     EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
    744     DevicePath
    745     );
    746 
    747   //
    748   // Complete all outstanding transactions to Controller.
    749   // Don't allow any new transaction to Controller to be started.
    750   //
    751   if (NumberOfChildren == 0) {
    752     //
    753     // Close the bus driver
    754     //
    755     Status = gBS->CloseProtocol (
    756                     Controller,
    757                     &gEfiIsaIoProtocolGuid,
    758                     This->DriverBindingHandle,
    759                     Controller
    760                     );
    761 
    762     Status = gBS->CloseProtocol (
    763                     Controller,
    764                     &gEfiDevicePathProtocolGuid,
    765                     This->DriverBindingHandle,
    766                     Controller
    767                     );
    768     return Status;
    769   }
    770 
    771   AllChildrenStopped = TRUE;
    772 
    773   for (Index = 0; Index < NumberOfChildren; Index++) {
    774 
    775     Status = gBS->OpenProtocol (
    776                     ChildHandleBuffer[Index],
    777                     &gEfiSerialIoProtocolGuid,
    778                     (VOID **) &SerialIo,
    779                     This->DriverBindingHandle,
    780                     Controller,
    781                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    782                     );
    783     if (!EFI_ERROR (Status)) {
    784 
    785       SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
    786 
    787       Status = gBS->CloseProtocol (
    788                       Controller,
    789                       &gEfiIsaIoProtocolGuid,
    790                       This->DriverBindingHandle,
    791                       ChildHandleBuffer[Index]
    792                       );
    793 
    794       Status = gBS->UninstallMultipleProtocolInterfaces (
    795                       ChildHandleBuffer[Index],
    796                       &gEfiDevicePathProtocolGuid,
    797                       SerialDevice->DevicePath,
    798                       &gEfiSerialIoProtocolGuid,
    799                       &SerialDevice->SerialIo,
    800                       NULL
    801                       );
    802       if (EFI_ERROR (Status)) {
    803         gBS->OpenProtocol (
    804                Controller,
    805                &gEfiIsaIoProtocolGuid,
    806                (VOID **) &IsaIo,
    807                This->DriverBindingHandle,
    808                ChildHandleBuffer[Index],
    809                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    810                );
    811       } else {
    812         if (SerialDevice->DevicePath != NULL) {
    813           gBS->FreePool (SerialDevice->DevicePath);
    814         }
    815 
    816         FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
    817         gBS->FreePool (SerialDevice);
    818       }
    819     }
    820 
    821     if (EFI_ERROR (Status)) {
    822       AllChildrenStopped = FALSE;
    823     }
    824   }
    825 
    826   if (!AllChildrenStopped) {
    827     return EFI_DEVICE_ERROR;
    828   }
    829 
    830   return EFI_SUCCESS;
    831 }
    832 
    833 /**
    834   Detect whether specific FIFO is full or not.
    835 
    836   @param Fifo    A pointer to the Data Structure SERIAL_DEV_FIFO
    837 
    838   @return whether specific FIFO is full or not
    839 
    840 **/
    841 BOOLEAN
    842 IsaSerialFifoFull (
    843   IN SERIAL_DEV_FIFO *Fifo
    844   )
    845 
    846 {
    847   if (Fifo->Surplus == 0) {
    848     return TRUE;
    849   }
    850 
    851   return FALSE;
    852 }
    853 
    854 /**
    855   Detect whether specific FIFO is empty or not.
    856 
    857   @param  Fifo    A pointer to the Data Structure SERIAL_DEV_FIFO
    858 
    859   @return whether specific FIFO is empty or not
    860 
    861 **/
    862 BOOLEAN
    863 IsaSerialFifoEmpty (
    864   IN SERIAL_DEV_FIFO *Fifo
    865   )
    866 
    867 {
    868   if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
    869     return TRUE;
    870   }
    871 
    872   return FALSE;
    873 }
    874 
    875 /**
    876   Add data to specific FIFO.
    877 
    878   @param Fifo                  A pointer to the Data Structure SERIAL_DEV_FIFO
    879   @param Data                  the data added to FIFO
    880 
    881   @retval EFI_SUCCESS           Add data to specific FIFO successfully
    882   @retval EFI_OUT_OF_RESOURCE   Failed to add data because FIFO is already full
    883 
    884 **/
    885 EFI_STATUS
    886 IsaSerialFifoAdd (
    887   IN SERIAL_DEV_FIFO *Fifo,
    888   IN UINT8           Data
    889   )
    890 
    891 {
    892   //
    893   // if FIFO full can not add data
    894   //
    895   if (IsaSerialFifoFull (Fifo)) {
    896     return EFI_OUT_OF_RESOURCES;
    897   }
    898   //
    899   // FIFO is not full can add data
    900   //
    901   Fifo->Data[Fifo->Last] = Data;
    902   Fifo->Surplus--;
    903   Fifo->Last++;
    904   if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {
    905     Fifo->Last = 0;
    906   }
    907 
    908   return EFI_SUCCESS;
    909 }
    910 
    911 /**
    912   Remove data from specific FIFO.
    913 
    914   @param Fifo                  A pointer to the Data Structure SERIAL_DEV_FIFO
    915   @param Data                  the data removed from FIFO
    916 
    917   @retval EFI_SUCCESS           Remove data from specific FIFO successfully
    918   @retval EFI_OUT_OF_RESOURCE   Failed to remove data because FIFO is empty
    919 
    920 **/
    921 EFI_STATUS
    922 IsaSerialFifoRemove (
    923   IN  SERIAL_DEV_FIFO *Fifo,
    924   OUT UINT8           *Data
    925   )
    926 
    927 {
    928   //
    929   // if FIFO is empty, no data can remove
    930   //
    931   if (IsaSerialFifoEmpty (Fifo)) {
    932     return EFI_OUT_OF_RESOURCES;
    933   }
    934   //
    935   // FIFO is not empty, can remove data
    936   //
    937   *Data = Fifo->Data[Fifo->First];
    938   Fifo->Surplus++;
    939   Fifo->First++;
    940   if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {
    941     Fifo->First = 0;
    942   }
    943 
    944   return EFI_SUCCESS;
    945 }
    946 
    947 /**
    948   Reads and writes all avaliable data.
    949 
    950   @param SerialDevice           The device to flush
    951 
    952   @retval EFI_SUCCESS           Data was read/written successfully.
    953   @retval EFI_OUT_OF_RESOURCE   Failed because software receive FIFO is full.  Note, when
    954                                 this happens, pending writes are not done.
    955 
    956 **/
    957 EFI_STATUS
    958 IsaSerialReceiveTransmit (
    959   IN SERIAL_DEV *SerialDevice
    960   )
    961 
    962 {
    963   SERIAL_PORT_LSR Lsr;
    964   UINT8           Data;
    965   BOOLEAN         ReceiveFifoFull;
    966   SERIAL_PORT_MSR Msr;
    967   SERIAL_PORT_MCR Mcr;
    968   UINTN           TimeOut;
    969 
    970   Data = 0;
    971 
    972   //
    973   // Begin the read or write
    974   //
    975   if (SerialDevice->SoftwareLoopbackEnable) {
    976     do {
    977       ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
    978       if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
    979         IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
    980         if (ReceiveFifoFull) {
    981           return EFI_OUT_OF_RESOURCES;
    982         }
    983 
    984         IsaSerialFifoAdd (&SerialDevice->Receive, Data);
    985       }
    986     } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));
    987   } else {
    988     ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
    989     //
    990     // For full handshake flow control, tell the peer to send data
    991     // if receive buffer is available.
    992     //
    993     if (SerialDevice->HardwareFlowControl &&
    994         !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)&&
    995         !ReceiveFifoFull
    996         ) {
    997       Mcr.Data     = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
    998       Mcr.Bits.Rts = 1;
    999       WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
   1000     }
   1001     do {
   1002       Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1003 
   1004       //
   1005       // Flush incomming data to prevent a an overrun during a long write
   1006       //
   1007       if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
   1008         ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
   1009         if (!ReceiveFifoFull) {
   1010           if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
   1011             REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1012               EFI_ERROR_CODE,
   1013               EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
   1014               SerialDevice->DevicePath
   1015               );
   1016             if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
   1017               Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1018               continue;
   1019             }
   1020           }
   1021 
   1022           Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1023 
   1024           IsaSerialFifoAdd (&SerialDevice->Receive, Data);
   1025 
   1026           //
   1027           // For full handshake flow control, if receive buffer full
   1028           // tell the peer to stop sending data.
   1029           //
   1030           if (SerialDevice->HardwareFlowControl &&
   1031               !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)   &&
   1032               IsaSerialFifoFull (&SerialDevice->Receive)
   1033               ) {
   1034             Mcr.Data     = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1035             Mcr.Bits.Rts = 0;
   1036             WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
   1037           }
   1038 
   1039 
   1040           continue;
   1041         } else {
   1042           REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1043             EFI_PROGRESS_CODE,
   1044             EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
   1045             SerialDevice->DevicePath
   1046             );
   1047         }
   1048       }
   1049       //
   1050       // Do the write
   1051       //
   1052       if (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
   1053         //
   1054         // Make sure the transmit data will not be missed
   1055         //
   1056         if (SerialDevice->HardwareFlowControl) {
   1057           //
   1058           // For half handshake flow control assert RTS before sending.
   1059           //
   1060           if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {
   1061             Mcr.Data     = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1062             Mcr.Bits.Rts= 0;
   1063             WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
   1064           }
   1065           //
   1066           // Wait for CTS
   1067           //
   1068           TimeOut   = 0;
   1069           Msr.Data  = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1070           while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {
   1071             gBS->Stall (TIMEOUT_STALL_INTERVAL);
   1072             TimeOut++;
   1073             if (TimeOut > 5) {
   1074               break;
   1075             }
   1076 
   1077             Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1078           }
   1079 
   1080           if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {
   1081             IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
   1082             WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
   1083           }
   1084 
   1085           //
   1086           // For half handshake flow control, tell DCE we are done.
   1087           //
   1088           if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {
   1089             Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1090             Mcr.Bits.Rts = 1;
   1091             WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
   1092           }
   1093         } else {
   1094           IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
   1095           WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
   1096         }
   1097       }
   1098     } while (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit));
   1099   }
   1100 
   1101   return EFI_SUCCESS;
   1102 }
   1103 
   1104 //
   1105 // Interface Functions
   1106 //
   1107 /**
   1108   Reset serial device.
   1109 
   1110   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
   1111 
   1112   @retval EFI_SUCCESS        Reset successfully
   1113   @retval EFI_DEVICE_ERROR   Failed to reset
   1114 
   1115 **/
   1116 EFI_STATUS
   1117 EFIAPI
   1118 IsaSerialReset (
   1119   IN EFI_SERIAL_IO_PROTOCOL  *This
   1120   )
   1121 {
   1122   EFI_STATUS      Status;
   1123   SERIAL_DEV      *SerialDevice;
   1124   SERIAL_PORT_LCR Lcr;
   1125   SERIAL_PORT_IER Ier;
   1126   SERIAL_PORT_MCR Mcr;
   1127   SERIAL_PORT_FCR Fcr;
   1128   EFI_TPL         Tpl;
   1129   UINT32          Control;
   1130 
   1131   SerialDevice = SERIAL_DEV_FROM_THIS (This);
   1132 
   1133   //
   1134   // Report the status code reset the serial
   1135   //
   1136   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1137     EFI_PROGRESS_CODE,
   1138     EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
   1139     SerialDevice->DevicePath
   1140     );
   1141 
   1142   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
   1143 
   1144   //
   1145   // Make sure DLAB is 0.
   1146   //
   1147   Lcr.Data      = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1148   Lcr.Bits.DLab = 0;
   1149   WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
   1150 
   1151   //
   1152   // Turn off all interrupts
   1153   //
   1154   Ier.Data        = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1155   Ier.Bits.Ravie  = 0;
   1156   Ier.Bits.Theie  = 0;
   1157   Ier.Bits.Rie    = 0;
   1158   Ier.Bits.Mie    = 0;
   1159   WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data);
   1160 
   1161   //
   1162   // Disable the FIFO.
   1163   //
   1164   Fcr.Bits.TrFIFOE = 0;
   1165   WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
   1166 
   1167   //
   1168   // Turn off loopback and disable device interrupt.
   1169   //
   1170   Mcr.Data      = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1171   Mcr.Bits.Out1 = 0;
   1172   Mcr.Bits.Out2 = 0;
   1173   Mcr.Bits.Lme  = 0;
   1174   WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
   1175 
   1176   //
   1177   // Clear the scratch pad register
   1178   //
   1179   WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0);
   1180 
   1181   //
   1182   // Go set the current attributes
   1183   //
   1184   Status = This->SetAttributes (
   1185                    This,
   1186                    This->Mode->BaudRate,
   1187                    This->Mode->ReceiveFifoDepth,
   1188                    This->Mode->Timeout,
   1189                    (EFI_PARITY_TYPE) This->Mode->Parity,
   1190                    (UINT8) This->Mode->DataBits,
   1191                    (EFI_STOP_BITS_TYPE) This->Mode->StopBits
   1192                    );
   1193 
   1194   if (EFI_ERROR (Status)) {
   1195     gBS->RestoreTPL (Tpl);
   1196     return EFI_DEVICE_ERROR;
   1197   }
   1198   //
   1199   // Go set the current control bits
   1200   //
   1201   Control = 0;
   1202   if (SerialDevice->HardwareFlowControl) {
   1203     Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
   1204   }
   1205   if (SerialDevice->SoftwareLoopbackEnable) {
   1206     Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
   1207   }
   1208   Status = This->SetControl (
   1209                    This,
   1210                    Control
   1211                    );
   1212 
   1213   if (EFI_ERROR (Status)) {
   1214     gBS->RestoreTPL (Tpl);
   1215     return EFI_DEVICE_ERROR;
   1216   }
   1217   //
   1218   // for 16550A enable FIFO, 16550 disable FIFO
   1219   //
   1220   Fcr.Bits.TrFIFOE  = 1;
   1221   Fcr.Bits.ResetRF  = 1;
   1222   Fcr.Bits.ResetTF  = 1;
   1223   WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
   1224 
   1225   //
   1226   // Reset the software FIFO
   1227   //
   1228   SerialDevice->Receive.First     = 0;
   1229   SerialDevice->Receive.Last      = 0;
   1230   SerialDevice->Receive.Surplus   = SERIAL_MAX_BUFFER_SIZE;
   1231   SerialDevice->Transmit.First    = 0;
   1232   SerialDevice->Transmit.Last     = 0;
   1233   SerialDevice->Transmit.Surplus  = SERIAL_MAX_BUFFER_SIZE;
   1234 
   1235   gBS->RestoreTPL (Tpl);
   1236 
   1237   //
   1238   // Device reset is complete
   1239   //
   1240   return EFI_SUCCESS;
   1241 }
   1242 
   1243 /**
   1244   Set new attributes to a serial device.
   1245 
   1246   @param This                     Pointer to EFI_SERIAL_IO_PROTOCOL
   1247   @param  BaudRate                 The baudrate of the serial device
   1248   @param  ReceiveFifoDepth         The depth of receive FIFO buffer
   1249   @param  Timeout                  The request timeout for a single char
   1250   @param  Parity                   The type of parity used in serial device
   1251   @param  DataBits                 Number of databits used in serial device
   1252   @param  StopBits                 Number of stopbits used in serial device
   1253 
   1254   @retval  EFI_SUCCESS              The new attributes were set
   1255   @retval  EFI_INVALID_PARAMETERS   One or more attributes have an unsupported value
   1256   @retval  EFI_UNSUPPORTED          Data Bits can not set to 5 or 6
   1257   @retval  EFI_DEVICE_ERROR         The serial device is not functioning correctly (no return)
   1258 
   1259 **/
   1260 EFI_STATUS
   1261 EFIAPI
   1262 IsaSerialSetAttributes (
   1263   IN EFI_SERIAL_IO_PROTOCOL  *This,
   1264   IN UINT64                  BaudRate,
   1265   IN UINT32                  ReceiveFifoDepth,
   1266   IN UINT32                  Timeout,
   1267   IN EFI_PARITY_TYPE         Parity,
   1268   IN UINT8                   DataBits,
   1269   IN EFI_STOP_BITS_TYPE      StopBits
   1270   )
   1271 {
   1272   EFI_STATUS                Status;
   1273   SERIAL_DEV                *SerialDevice;
   1274   UINT32                    Divisor;
   1275   UINT32                    Remained;
   1276   SERIAL_PORT_LCR           Lcr;
   1277   UART_DEVICE_PATH          *Uart;
   1278   EFI_TPL                   Tpl;
   1279 
   1280   SerialDevice = SERIAL_DEV_FROM_THIS (This);
   1281 
   1282   //
   1283   // Check for default settings and fill in actual values.
   1284   //
   1285   if (BaudRate == 0) {
   1286     BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
   1287   }
   1288 
   1289   if (ReceiveFifoDepth == 0) {
   1290     ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
   1291   }
   1292 
   1293   if (Timeout == 0) {
   1294     Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
   1295   }
   1296 
   1297   if (Parity == DefaultParity) {
   1298     Parity = (EFI_PARITY_TYPE)PcdGet8 (PcdUartDefaultParity);
   1299   }
   1300 
   1301   if (DataBits == 0) {
   1302     DataBits = PcdGet8 (PcdUartDefaultDataBits);
   1303   }
   1304 
   1305   if (StopBits == DefaultStopBits) {
   1306     StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
   1307   }
   1308   //
   1309   // 5 and 6 data bits can not be verified on a 16550A UART
   1310   // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings.
   1311   //
   1312   if ((DataBits == 5) || (DataBits == 6)) {
   1313     return EFI_INVALID_PARAMETER;
   1314   }
   1315   //
   1316   // Make sure all parameters are valid
   1317   //
   1318   if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
   1319     return EFI_INVALID_PARAMETER;
   1320   }
   1321   //
   1322   // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200,
   1323   // 38400,57600,115200
   1324   //
   1325   if (BaudRate < 75) {
   1326     BaudRate = 50;
   1327   } else if (BaudRate < 110) {
   1328     BaudRate = 75;
   1329   } else if (BaudRate < 134) {
   1330     BaudRate = 110;
   1331   } else if (BaudRate < 150) {
   1332     BaudRate = 134;
   1333   } else if (BaudRate < 300) {
   1334     BaudRate = 150;
   1335   } else if (BaudRate < 600) {
   1336     BaudRate = 300;
   1337   } else if (BaudRate < 1200) {
   1338     BaudRate = 600;
   1339   } else if (BaudRate < 1800) {
   1340     BaudRate = 1200;
   1341   } else if (BaudRate < 2000) {
   1342     BaudRate = 1800;
   1343   } else if (BaudRate < 2400) {
   1344     BaudRate = 2000;
   1345   } else if (BaudRate < 3600) {
   1346     BaudRate = 2400;
   1347   } else if (BaudRate < 4800) {
   1348     BaudRate = 3600;
   1349   } else if (BaudRate < 7200) {
   1350     BaudRate = 4800;
   1351   } else if (BaudRate < 9600) {
   1352     BaudRate = 7200;
   1353   } else if (BaudRate < 19200) {
   1354     BaudRate = 9600;
   1355   } else if (BaudRate < 38400) {
   1356     BaudRate = 19200;
   1357   } else if (BaudRate < 57600) {
   1358     BaudRate = 38400;
   1359   } else if (BaudRate < 115200) {
   1360     BaudRate = 57600;
   1361   } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) {
   1362     BaudRate = 115200;
   1363   }
   1364 
   1365   if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {
   1366     return EFI_INVALID_PARAMETER;
   1367   }
   1368 
   1369   if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
   1370     return EFI_INVALID_PARAMETER;
   1371   }
   1372 
   1373   if ((Parity < NoParity) || (Parity > SpaceParity)) {
   1374     return EFI_INVALID_PARAMETER;
   1375   }
   1376 
   1377   if ((DataBits < 5) || (DataBits > 8)) {
   1378     return EFI_INVALID_PARAMETER;
   1379   }
   1380 
   1381   if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
   1382     return EFI_INVALID_PARAMETER;
   1383   }
   1384 
   1385   //
   1386   // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits
   1387   //
   1388   if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {
   1389     return EFI_INVALID_PARAMETER;
   1390   }
   1391 
   1392   //
   1393   // Compute divisor use to program the baud rate using a round determination
   1394   //
   1395   Divisor = (UINT32) DivU64x32Remainder (
   1396                        PcdGet32 (PcdSerialClockRate),
   1397                        ((UINT32) BaudRate * 16),
   1398                        &Remained
   1399                        );
   1400   if (Remained != 0) {
   1401     Divisor += 1;
   1402   }
   1403 
   1404   if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) {
   1405     return EFI_INVALID_PARAMETER;
   1406   }
   1407 
   1408   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
   1409 
   1410   //
   1411   // Compute the actual baud rate that the serial port will be programmed for.
   1412   //
   1413   BaudRate = PcdGet32 (PcdSerialClockRate) / Divisor / 16;
   1414 
   1415   //
   1416   // Put serial port on Divisor Latch Mode
   1417   //
   1418   Lcr.Data      = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1419   Lcr.Bits.DLab = 1;
   1420   WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
   1421 
   1422   //
   1423   // Write the divisor to the serial port
   1424   //
   1425   WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));
   1426   WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));
   1427 
   1428   //
   1429   // Put serial port back in normal mode and set remaining attributes.
   1430   //
   1431   Lcr.Bits.DLab = 0;
   1432 
   1433   switch (Parity) {
   1434   case NoParity:
   1435     Lcr.Bits.ParEn    = 0;
   1436     Lcr.Bits.EvenPar  = 0;
   1437     Lcr.Bits.SticPar  = 0;
   1438     break;
   1439 
   1440   case EvenParity:
   1441     Lcr.Bits.ParEn    = 1;
   1442     Lcr.Bits.EvenPar  = 1;
   1443     Lcr.Bits.SticPar  = 0;
   1444     break;
   1445 
   1446   case OddParity:
   1447     Lcr.Bits.ParEn    = 1;
   1448     Lcr.Bits.EvenPar  = 0;
   1449     Lcr.Bits.SticPar  = 0;
   1450     break;
   1451 
   1452   case SpaceParity:
   1453     Lcr.Bits.ParEn    = 1;
   1454     Lcr.Bits.EvenPar  = 1;
   1455     Lcr.Bits.SticPar  = 1;
   1456     break;
   1457 
   1458   case MarkParity:
   1459     Lcr.Bits.ParEn    = 1;
   1460     Lcr.Bits.EvenPar  = 0;
   1461     Lcr.Bits.SticPar  = 1;
   1462     break;
   1463 
   1464   default:
   1465     break;
   1466   }
   1467 
   1468   switch (StopBits) {
   1469   case OneStopBit:
   1470     Lcr.Bits.StopB = 0;
   1471     break;
   1472 
   1473   case OneFiveStopBits:
   1474   case TwoStopBits:
   1475     Lcr.Bits.StopB = 1;
   1476     break;
   1477 
   1478   default:
   1479     break;
   1480   }
   1481   //
   1482   // DataBits
   1483   //
   1484   Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
   1485   WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
   1486 
   1487   //
   1488   // Set the Serial I/O mode
   1489   //
   1490   This->Mode->BaudRate          = BaudRate;
   1491   This->Mode->ReceiveFifoDepth  = ReceiveFifoDepth;
   1492   This->Mode->Timeout           = Timeout;
   1493   This->Mode->Parity            = Parity;
   1494   This->Mode->DataBits          = DataBits;
   1495   This->Mode->StopBits          = StopBits;
   1496 
   1497   //
   1498   // See if Device Path Node has actually changed
   1499   //
   1500   if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
   1501       SerialDevice->UartDevicePath.DataBits == DataBits &&
   1502       SerialDevice->UartDevicePath.Parity == Parity &&
   1503       SerialDevice->UartDevicePath.StopBits == StopBits
   1504       ) {
   1505     gBS->RestoreTPL (Tpl);
   1506     return EFI_SUCCESS;
   1507   }
   1508   //
   1509   // Update the device path
   1510   //
   1511   SerialDevice->UartDevicePath.BaudRate = BaudRate;
   1512   SerialDevice->UartDevicePath.DataBits = DataBits;
   1513   SerialDevice->UartDevicePath.Parity   = (UINT8) Parity;
   1514   SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
   1515 
   1516   Status = EFI_SUCCESS;
   1517   if (SerialDevice->Handle != NULL) {
   1518     Uart = (UART_DEVICE_PATH *) (
   1519              (UINTN) SerialDevice->DevicePath
   1520              + GetDevicePathSize (SerialDevice->ParentDevicePath)
   1521              - END_DEVICE_PATH_LENGTH
   1522              );
   1523     CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
   1524     Status = gBS->ReinstallProtocolInterface (
   1525                     SerialDevice->Handle,
   1526                     &gEfiDevicePathProtocolGuid,
   1527                     SerialDevice->DevicePath,
   1528                     SerialDevice->DevicePath
   1529                     );
   1530   }
   1531 
   1532   gBS->RestoreTPL (Tpl);
   1533 
   1534   return Status;
   1535 }
   1536 
   1537 /**
   1538   Set Control Bits.
   1539 
   1540   @param This              Pointer to EFI_SERIAL_IO_PROTOCOL
   1541   @param Control           Control bits that can be settable
   1542 
   1543   @retval EFI_SUCCESS       New Control bits were set successfully
   1544   @retval EFI_UNSUPPORTED   The Control bits wanted to set are not supported
   1545 
   1546 **/
   1547 EFI_STATUS
   1548 EFIAPI
   1549 IsaSerialSetControl (
   1550   IN EFI_SERIAL_IO_PROTOCOL  *This,
   1551   IN UINT32                  Control
   1552   )
   1553 {
   1554   SERIAL_DEV                    *SerialDevice;
   1555   SERIAL_PORT_MCR               Mcr;
   1556   EFI_TPL                       Tpl;
   1557   UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
   1558   EFI_STATUS                    Status;
   1559 
   1560   //
   1561   // The control bits that can be set are :
   1562   //     EFI_SERIAL_DATA_TERMINAL_READY: 0x0001  // WO
   1563   //     EFI_SERIAL_REQUEST_TO_SEND: 0x0002  // WO
   1564   //     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000  // RW
   1565   //     EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000  // RW
   1566   //     EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
   1567   //
   1568   SerialDevice = SERIAL_DEV_FROM_THIS (This);
   1569 
   1570   //
   1571   // first determine the parameter is invalid
   1572   //
   1573   if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
   1574                     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
   1575                     EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
   1576     return EFI_UNSUPPORTED;
   1577   }
   1578 
   1579   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
   1580 
   1581   Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1582   Mcr.Bits.DtrC = 0;
   1583   Mcr.Bits.Rts = 0;
   1584   Mcr.Bits.Lme = 0;
   1585   SerialDevice->SoftwareLoopbackEnable = FALSE;
   1586   SerialDevice->HardwareFlowControl = FALSE;
   1587 
   1588   if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
   1589     Mcr.Bits.DtrC = 1;
   1590   }
   1591 
   1592   if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
   1593     Mcr.Bits.Rts = 1;
   1594   }
   1595 
   1596   if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
   1597     Mcr.Bits.Lme = 1;
   1598   }
   1599 
   1600   if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
   1601     SerialDevice->HardwareFlowControl = TRUE;
   1602   }
   1603 
   1604   WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
   1605 
   1606   if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
   1607     SerialDevice->SoftwareLoopbackEnable = TRUE;
   1608   }
   1609 
   1610   Status = EFI_SUCCESS;
   1611   if (SerialDevice->Handle != NULL) {
   1612     FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
   1613                     (UINTN) SerialDevice->DevicePath
   1614                     + GetDevicePathSize (SerialDevice->ParentDevicePath)
   1615                     - END_DEVICE_PATH_LENGTH
   1616                     + sizeof (UART_DEVICE_PATH)
   1617                     );
   1618     if (IsUartFlowControlNode (FlowControl) &&
   1619         ((ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) ^ SerialDevice->HardwareFlowControl)) {
   1620       //
   1621       // Flow Control setting is changed, need to reinstall device path protocol
   1622       //
   1623       WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);
   1624       Status = gBS->ReinstallProtocolInterface (
   1625                       SerialDevice->Handle,
   1626                       &gEfiDevicePathProtocolGuid,
   1627                       SerialDevice->DevicePath,
   1628                       SerialDevice->DevicePath
   1629                       );
   1630     }
   1631   }
   1632 
   1633   gBS->RestoreTPL (Tpl);
   1634 
   1635   return Status;
   1636 }
   1637 
   1638 /**
   1639   Get ControlBits.
   1640 
   1641   @param This          Pointer to EFI_SERIAL_IO_PROTOCOL
   1642   @param Control       Control signals of the serial device
   1643 
   1644   @retval EFI_SUCCESS   Get Control signals successfully
   1645 
   1646 **/
   1647 EFI_STATUS
   1648 EFIAPI
   1649 IsaSerialGetControl (
   1650   IN EFI_SERIAL_IO_PROTOCOL  *This,
   1651   OUT UINT32                 *Control
   1652   )
   1653 {
   1654   SERIAL_DEV      *SerialDevice;
   1655   SERIAL_PORT_MSR Msr;
   1656   SERIAL_PORT_MCR Mcr;
   1657   EFI_TPL         Tpl;
   1658 
   1659   Tpl           = gBS->RaiseTPL (TPL_NOTIFY);
   1660 
   1661   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
   1662 
   1663   *Control      = 0;
   1664 
   1665   //
   1666   // Read the Modem Status Register
   1667   //
   1668   Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1669 
   1670   if (Msr.Bits.Cts == 1) {
   1671     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
   1672   }
   1673 
   1674   if (Msr.Bits.Dsr == 1) {
   1675     *Control |= EFI_SERIAL_DATA_SET_READY;
   1676   }
   1677 
   1678   if (Msr.Bits.Ri == 1) {
   1679     *Control |= EFI_SERIAL_RING_INDICATE;
   1680   }
   1681 
   1682   if (Msr.Bits.Dcd == 1) {
   1683     *Control |= EFI_SERIAL_CARRIER_DETECT;
   1684   }
   1685   //
   1686   // Read the Modem Control Register
   1687   //
   1688   Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1689 
   1690   if (Mcr.Bits.DtrC == 1) {
   1691     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
   1692   }
   1693 
   1694   if (Mcr.Bits.Rts == 1) {
   1695     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
   1696   }
   1697 
   1698   if (Mcr.Bits.Lme == 1) {
   1699     *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
   1700   }
   1701 
   1702   if (SerialDevice->HardwareFlowControl) {
   1703     *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
   1704   }
   1705   //
   1706   // See if the Transmit FIFO is empty
   1707   //
   1708   IsaSerialReceiveTransmit (SerialDevice);
   1709 
   1710   if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
   1711     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
   1712   }
   1713   //
   1714   // See if the Receive FIFO is empty.
   1715   //
   1716   IsaSerialReceiveTransmit (SerialDevice);
   1717 
   1718   if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {
   1719     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
   1720   }
   1721 
   1722   if (SerialDevice->SoftwareLoopbackEnable) {
   1723     *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
   1724   }
   1725 
   1726   gBS->RestoreTPL (Tpl);
   1727 
   1728   return EFI_SUCCESS;
   1729 }
   1730 
   1731 /**
   1732   Write the specified number of bytes to serial device.
   1733 
   1734   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
   1735   @param  BufferSize         On input the size of Buffer, on output the amount of
   1736                        data actually written
   1737   @param  Buffer             The buffer of data to write
   1738 
   1739   @retval EFI_SUCCESS        The data were written successfully
   1740   @retval EFI_DEVICE_ERROR   The device reported an error
   1741   @retval EFI_TIMEOUT        The write operation was stopped due to timeout
   1742 
   1743 **/
   1744 EFI_STATUS
   1745 EFIAPI
   1746 IsaSerialWrite (
   1747   IN EFI_SERIAL_IO_PROTOCOL  *This,
   1748   IN OUT UINTN               *BufferSize,
   1749   IN VOID                    *Buffer
   1750   )
   1751 {
   1752   SERIAL_DEV  *SerialDevice;
   1753   UINT8       *CharBuffer;
   1754   UINT32      Index;
   1755   UINTN       Elapsed;
   1756   UINTN       ActualWrite;
   1757   EFI_TPL     Tpl;
   1758   UINTN       Timeout;
   1759   UINTN       BitsPerCharacter;
   1760 
   1761   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
   1762   Elapsed       = 0;
   1763   ActualWrite   = 0;
   1764 
   1765   if (*BufferSize == 0) {
   1766     return EFI_SUCCESS;
   1767   }
   1768 
   1769   if (Buffer == NULL) {
   1770     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1771       EFI_ERROR_CODE,
   1772       EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
   1773       SerialDevice->DevicePath
   1774       );
   1775 
   1776     return EFI_DEVICE_ERROR;
   1777   }
   1778 
   1779   Tpl         = gBS->RaiseTPL (TPL_NOTIFY);
   1780 
   1781   CharBuffer  = (UINT8 *) Buffer;
   1782 
   1783   //
   1784   // Compute the number of bits in a single character.  This is a start bit,
   1785   // followed by the number of data bits, followed by the number of stop bits.
   1786   // The number of stop bits is specified by an enumeration that includes
   1787   // support for 1.5 stop bits.  Treat 1.5 stop bits as 2 stop bits.
   1788   //
   1789   BitsPerCharacter =
   1790     1 +
   1791     This->Mode->DataBits +
   1792     ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits);
   1793 
   1794   //
   1795   // Compute the timeout in microseconds to wait for a single byte to be
   1796   // transmitted.  The Mode structure contans a Timeout field that is the
   1797   // maximum time to transmit or receive a character.  However, many UARTs
   1798   // have a FIFO for transmits, so the time required to add one new character
   1799   // to the transmit FIFO may be the time required to flush a full FIFO.  If
   1800   // the Timeout in the Mode structure is smaller than the time required to
   1801   // flush a full FIFO at the current baud rate, then use a timeout value that
   1802   // is required to flush a full transmit FIFO.
   1803   //
   1804   Timeout = MAX (
   1805               This->Mode->Timeout,
   1806               (UINTN)DivU64x64Remainder (
   1807                 BitsPerCharacter * (SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH + 1) * 1000000,
   1808                 This->Mode->BaudRate,
   1809                 NULL
   1810                 )
   1811               );
   1812 
   1813   for (Index = 0; Index < *BufferSize; Index++) {
   1814     IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
   1815 
   1816     while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
   1817       //
   1818       //  Unsuccessful write so check if timeout has expired, if not,
   1819       //  stall for a bit, increment time elapsed, and try again
   1820       //
   1821       if (Elapsed >= Timeout) {
   1822         *BufferSize = ActualWrite;
   1823         gBS->RestoreTPL (Tpl);
   1824         return EFI_TIMEOUT;
   1825       }
   1826 
   1827       gBS->Stall (TIMEOUT_STALL_INTERVAL);
   1828 
   1829       Elapsed += TIMEOUT_STALL_INTERVAL;
   1830     }
   1831 
   1832     ActualWrite++;
   1833     //
   1834     //  Successful write so reset timeout
   1835     //
   1836     Elapsed = 0;
   1837   }
   1838 
   1839   gBS->RestoreTPL (Tpl);
   1840 
   1841   return EFI_SUCCESS;
   1842 }
   1843 
   1844 /**
   1845   Read the specified number of bytes from serial device.
   1846 
   1847   @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
   1848   @param BufferSize         On input the size of Buffer, on output the amount of
   1849                             data returned in buffer
   1850   @param Buffer             The buffer to return the data into
   1851 
   1852   @retval EFI_SUCCESS        The data were read successfully
   1853   @retval EFI_DEVICE_ERROR   The device reported an error
   1854   @retval EFI_TIMEOUT        The read operation was stopped due to timeout
   1855 
   1856 **/
   1857 EFI_STATUS
   1858 EFIAPI
   1859 IsaSerialRead (
   1860   IN EFI_SERIAL_IO_PROTOCOL  *This,
   1861   IN OUT UINTN               *BufferSize,
   1862   OUT VOID                   *Buffer
   1863   )
   1864 {
   1865   SERIAL_DEV  *SerialDevice;
   1866   UINT32      Index;
   1867   UINT8       *CharBuffer;
   1868   UINTN       Elapsed;
   1869   EFI_STATUS  Status;
   1870   EFI_TPL     Tpl;
   1871 
   1872   SerialDevice  = SERIAL_DEV_FROM_THIS (This);
   1873   Elapsed       = 0;
   1874 
   1875   if (*BufferSize == 0) {
   1876     return EFI_SUCCESS;
   1877   }
   1878 
   1879   if (Buffer == NULL) {
   1880     return EFI_DEVICE_ERROR;
   1881   }
   1882 
   1883   Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
   1884 
   1885   Status  = IsaSerialReceiveTransmit (SerialDevice);
   1886 
   1887   if (EFI_ERROR (Status)) {
   1888     *BufferSize = 0;
   1889 
   1890     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1891       EFI_ERROR_CODE,
   1892       EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
   1893       SerialDevice->DevicePath
   1894       );
   1895 
   1896     gBS->RestoreTPL (Tpl);
   1897 
   1898     return EFI_DEVICE_ERROR;
   1899   }
   1900 
   1901   CharBuffer = (UINT8 *) Buffer;
   1902   for (Index = 0; Index < *BufferSize; Index++) {
   1903     while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
   1904       //
   1905       //  Unsuccessful read so check if timeout has expired, if not,
   1906       //  stall for a bit, increment time elapsed, and try again
   1907       //  Need this time out to get conspliter to work.
   1908       //
   1909       if (Elapsed >= This->Mode->Timeout) {
   1910         *BufferSize = Index;
   1911         gBS->RestoreTPL (Tpl);
   1912         return EFI_TIMEOUT;
   1913       }
   1914 
   1915       gBS->Stall (TIMEOUT_STALL_INTERVAL);
   1916       Elapsed += TIMEOUT_STALL_INTERVAL;
   1917 
   1918       Status = IsaSerialReceiveTransmit (SerialDevice);
   1919       if (Status == EFI_DEVICE_ERROR) {
   1920         *BufferSize = Index;
   1921         gBS->RestoreTPL (Tpl);
   1922         return EFI_DEVICE_ERROR;
   1923       }
   1924     }
   1925     //
   1926     //  Successful read so reset timeout
   1927     //
   1928     Elapsed = 0;
   1929   }
   1930 
   1931   IsaSerialReceiveTransmit (SerialDevice);
   1932 
   1933   gBS->RestoreTPL (Tpl);
   1934 
   1935   return EFI_SUCCESS;
   1936 }
   1937 
   1938 /**
   1939   Use scratchpad register to test if this serial port is present.
   1940 
   1941   @param SerialDevice   Pointer to serial device structure
   1942 
   1943   @return if this serial port is present
   1944 **/
   1945 BOOLEAN
   1946 IsaSerialPortPresent (
   1947   IN SERIAL_DEV *SerialDevice
   1948   )
   1949 
   1950 {
   1951   UINT8   Temp;
   1952   BOOLEAN Status;
   1953 
   1954   Status = TRUE;
   1955 
   1956   //
   1957   // Save SCR reg
   1958   //
   1959   Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
   1960   WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);
   1961 
   1962   if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) {
   1963     Status = FALSE;
   1964   }
   1965 
   1966   WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);
   1967 
   1968   if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) {
   1969     Status = FALSE;
   1970   }
   1971   //
   1972   // Restore SCR
   1973   //
   1974   WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);
   1975   return Status;
   1976 }
   1977 
   1978 /**
   1979   Use IsaIo protocol to read serial port.
   1980 
   1981   @param IsaIo         Pointer to EFI_ISA_IO_PROTOCOL instance
   1982   @param BaseAddress   Serial port register group base address
   1983   @param Offset        Offset in register group
   1984 
   1985   @return Data read from serial port
   1986 
   1987 **/
   1988 UINT8
   1989 IsaSerialReadPort (
   1990   IN EFI_ISA_IO_PROTOCOL                   *IsaIo,
   1991   IN UINT16                                BaseAddress,
   1992   IN UINT32                                Offset
   1993   )
   1994 {
   1995   UINT8 Data;
   1996 
   1997   //
   1998   // Use IsaIo to access IO
   1999   //
   2000   IsaIo->Io.Read (
   2001              IsaIo,
   2002              EfiIsaIoWidthUint8,
   2003              BaseAddress + Offset,
   2004              1,
   2005              &Data
   2006              );
   2007   return Data;
   2008 }
   2009 
   2010 /**
   2011   Use IsaIo protocol to write serial port.
   2012 
   2013   @param  IsaIo         Pointer to EFI_ISA_IO_PROTOCOL instance
   2014   @param  BaseAddress   Serial port register group base address
   2015   @param  Offset        Offset in register group
   2016   @param  Data          data which is to be written to some serial port register
   2017 
   2018 **/
   2019 VOID
   2020 IsaSerialWritePort (
   2021   IN EFI_ISA_IO_PROTOCOL                 *IsaIo,
   2022   IN UINT16                              BaseAddress,
   2023   IN UINT32                              Offset,
   2024   IN UINT8                               Data
   2025   )
   2026 {
   2027   //
   2028   // Use IsaIo to access IO
   2029   //
   2030   IsaIo->Io.Write (
   2031              IsaIo,
   2032              EfiIsaIoWidthUint8,
   2033              BaseAddress + Offset,
   2034              1,
   2035              &Data
   2036              );
   2037 }
   2038 
   2039