Home | History | Annotate | Download | only in DebugPortDxe
      1 /** @file
      2   Top level C file for debugport driver.  Contains initialization function.
      3   This driver layers on top of SerialIo.
      4   ALL CODE IN THE SERIALIO STACK MUST BE RE-ENTRANT AND CALLABLE FROM
      5   INTERRUPT CONTEXT
      6 
      7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this distribution.  The full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "DebugPort.h"
     19 
     20 //
     21 // Globals
     22 //
     23 EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding = {
     24   DebugPortSupported,
     25   DebugPortStart,
     26   DebugPortStop,
     27   DEBUGPORT_DRIVER_VERSION,
     28   NULL,
     29   NULL
     30 };
     31 
     32 DEBUGPORT_DEVICE mDebugPortDevice = {
     33   DEBUGPORT_DEVICE_SIGNATURE,
     34   (EFI_HANDLE) 0,
     35   (EFI_HANDLE) 0,
     36   (EFI_DEVICE_PATH_PROTOCOL *) NULL,
     37   {
     38     DebugPortReset,
     39     DebugPortWrite,
     40     DebugPortRead,
     41     DebugPortPoll
     42   },
     43   (EFI_HANDLE) 0,
     44   (EFI_SERIAL_IO_PROTOCOL *) NULL,
     45   DEBUGPORT_UART_DEFAULT_BAUDRATE,
     46   DEBUGPORT_UART_DEFAULT_FIFO_DEPTH,
     47   DEBUGPORT_UART_DEFAULT_TIMEOUT,
     48   (EFI_PARITY_TYPE) DEBUGPORT_UART_DEFAULT_PARITY,
     49   DEBUGPORT_UART_DEFAULT_DATA_BITS,
     50   (EFI_STOP_BITS_TYPE) DEBUGPORT_UART_DEFAULT_STOP_BITS
     51 };
     52 
     53 /**
     54   Local worker function to obtain device path information from DebugPort variable.
     55 
     56   Records requested settings in DebugPort device structure.
     57 
     58 **/
     59 EFI_DEVICE_PATH_PROTOCOL *
     60 GetDebugPortVariable (
     61   VOID
     62   )
     63 {
     64   UINTN                     DataSize;
     65   EFI_DEVICE_PATH_PROTOCOL  *DebugPortVariable;
     66   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
     67 
     68   GetVariable2 (EFI_DEBUGPORT_VARIABLE_NAME, &gEfiDebugPortVariableGuid, (VOID **) &DebugPortVariable, &DataSize);
     69   if (DebugPortVariable == NULL) {
     70     return NULL;
     71   }
     72 
     73   DevicePath = DebugPortVariable;
     74   while (!IsDevicePathEnd (DevicePath) && !IS_UART_DEVICEPATH (DevicePath)) {
     75     DevicePath = NextDevicePathNode (DevicePath);
     76   }
     77 
     78   if (IsDevicePathEnd (DevicePath)) {
     79     FreePool (DebugPortVariable);
     80     return NULL;
     81   } else {
     82     CopyMem (
     83       &mDebugPortDevice.BaudRate,
     84       &((UART_DEVICE_PATH *) DevicePath)->BaudRate,
     85       sizeof (((UART_DEVICE_PATH *) DevicePath)->BaudRate)
     86       );
     87     mDebugPortDevice.ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH;
     88     mDebugPortDevice.Timeout          = DEBUGPORT_UART_DEFAULT_TIMEOUT;
     89     CopyMem (
     90       &mDebugPortDevice.Parity,
     91       &((UART_DEVICE_PATH *) DevicePath)->Parity,
     92       sizeof (((UART_DEVICE_PATH *) DevicePath)->Parity)
     93       );
     94     CopyMem (
     95       &mDebugPortDevice.DataBits,
     96       &((UART_DEVICE_PATH *) DevicePath)->DataBits,
     97       sizeof (((UART_DEVICE_PATH *) DevicePath)->DataBits)
     98       );
     99     CopyMem (
    100       &mDebugPortDevice.StopBits,
    101       &((UART_DEVICE_PATH *) DevicePath)->StopBits,
    102       sizeof (((UART_DEVICE_PATH *) DevicePath)->StopBits)
    103       );
    104     return DebugPortVariable;
    105   }
    106 }
    107 
    108 /**
    109   Debug Port Driver entry point.
    110 
    111   Reads DebugPort variable to determine what device and settings to use as the
    112   debug port.  Binds exclusively to SerialIo. Reverts to defaults if no variable
    113   is found.
    114 
    115   @param[in] ImageHandle       The firmware allocated handle for the EFI image.
    116   @param[in] SystemTable       A pointer to the EFI System Table.
    117 
    118   @retval EFI_SUCCESS          The entry point is executed successfully.
    119   @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
    120   @retval other                Some error occurs when executing this entry point.
    121 
    122 **/
    123 EFI_STATUS
    124 EFIAPI
    125 InitializeDebugPortDriver (
    126   IN EFI_HANDLE             ImageHandle,
    127   IN EFI_SYSTEM_TABLE       *SystemTable
    128   )
    129 {
    130   EFI_STATUS    Status;
    131 
    132   //
    133   // Install driver model protocol(s).
    134   //
    135   Status = EfiLibInstallDriverBindingComponentName2 (
    136              ImageHandle,
    137              SystemTable,
    138              &gDebugPortDriverBinding,
    139              ImageHandle,
    140              &gDebugPortComponentName,
    141              &gDebugPortComponentName2
    142              );
    143   ASSERT_EFI_ERROR (Status);
    144 
    145   return Status;
    146 }
    147 
    148 /**
    149   Checks to see if there's not already a DebugPort interface somewhere.
    150 
    151   If there's a DEBUGPORT variable, the device path must match exactly.  If there's
    152   no DEBUGPORT variable, then device path is not checked and does not matter.
    153   Checks to see that there's a serial io interface on the controller handle
    154   that can be bound BY_DRIVER | EXCLUSIVE.
    155   If all these tests succeed, then we return EFI_SUCCESS, else, EFI_UNSUPPORTED
    156   or other error returned by OpenProtocol.
    157 
    158   @param  This                 Protocol instance pointer.
    159   @param  ControllerHandle     Handle of device to test.
    160   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    161                                device to start.
    162 
    163   @retval EFI_SUCCESS          This driver supports this device.
    164   @retval EFI_UNSUPPORTED      Debug Port device is not supported.
    165   @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
    166   @retval others               Some error occurs.
    167 
    168 **/
    169 EFI_STATUS
    170 EFIAPI
    171 DebugPortSupported (
    172   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    173   IN EFI_HANDLE                     ControllerHandle,
    174   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    175   )
    176 {
    177   EFI_STATUS                Status;
    178   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    179   EFI_DEVICE_PATH_PROTOCOL  *DebugPortVariable;
    180   EFI_SERIAL_IO_PROTOCOL    *SerialIo;
    181   EFI_DEBUGPORT_PROTOCOL    *DebugPortInterface;
    182   EFI_HANDLE                TempHandle;
    183 
    184   //
    185   // Check to see that there's not a debugport protocol already published,
    186   // since only one standard UART serial port could be supported by this driver.
    187   //
    188   if (gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **) &DebugPortInterface) != EFI_NOT_FOUND) {
    189     return EFI_UNSUPPORTED;
    190   }
    191   //
    192   // Read DebugPort variable to determine debug port selection and parameters
    193   //
    194   DebugPortVariable = GetDebugPortVariable ();
    195 
    196   if (DebugPortVariable != NULL) {
    197     //
    198     // There's a DEBUGPORT variable, so do LocateDevicePath and check to see if
    199     // the closest matching handle matches the controller handle, and if it does,
    200     // check to see that the remaining device path has the DebugPort GUIDed messaging
    201     // device path only.  Otherwise, it's a mismatch and EFI_UNSUPPORTED is returned.
    202     //
    203     DevicePath = DebugPortVariable;
    204     Status = gBS->LocateDevicePath (
    205                     &gEfiSerialIoProtocolGuid,
    206                     &DevicePath,
    207                     &TempHandle
    208                     );
    209 
    210     if (Status == EFI_SUCCESS && TempHandle != ControllerHandle) {
    211       Status = EFI_UNSUPPORTED;
    212     }
    213 
    214     if (Status == EFI_SUCCESS &&
    215         (DevicePath->Type != MESSAGING_DEVICE_PATH ||
    216          DevicePath->SubType != MSG_VENDOR_DP ||
    217          *((UINT16 *) DevicePath->Length) != sizeof (DEBUGPORT_DEVICE_PATH))) {
    218 
    219       Status = EFI_UNSUPPORTED;
    220     }
    221 
    222     if (Status == EFI_SUCCESS && !CompareGuid (&gEfiDebugPortDevicePathGuid, (GUID *) (DevicePath + 1))) {
    223       Status = EFI_UNSUPPORTED;
    224     }
    225 
    226     FreePool (DebugPortVariable);
    227     if (EFI_ERROR (Status)) {
    228       return Status;
    229     }
    230   }
    231 
    232   Status = gBS->OpenProtocol (
    233                   ControllerHandle,
    234                   &gEfiSerialIoProtocolGuid,
    235                   (VOID **) &SerialIo,
    236                   This->DriverBindingHandle,
    237                   ControllerHandle,
    238                   EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
    239                   );
    240   if (EFI_ERROR (Status)) {
    241     return Status;
    242   }
    243 
    244   Status = gBS->CloseProtocol (
    245                   ControllerHandle,
    246                   &gEfiSerialIoProtocolGuid,
    247                   This->DriverBindingHandle,
    248                   ControllerHandle
    249                   );
    250 
    251   return Status;
    252 }
    253 
    254 /**
    255   Binds exclusively to serial io on the controller handle, Produces DebugPort
    256   protocol and DevicePath on new handle.
    257 
    258   @param  This                 Protocol instance pointer.
    259   @param  ControllerHandle     Handle of device to bind driver to.
    260   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    261                                device to start.
    262 
    263   @retval EFI_SUCCESS          This driver is added to ControllerHandle.
    264   @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
    265   @retval others               Some error occurs.
    266 
    267 **/
    268 EFI_STATUS
    269 EFIAPI
    270 DebugPortStart (
    271   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    272   IN EFI_HANDLE                     ControllerHandle,
    273   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    274   )
    275 {
    276   EFI_STATUS                Status;
    277   DEBUGPORT_DEVICE_PATH     DebugPortDP;
    278   EFI_DEVICE_PATH_PROTOCOL  EndDP;
    279   EFI_DEVICE_PATH_PROTOCOL  *Dp1;
    280 
    281   Status = gBS->OpenProtocol (
    282                   ControllerHandle,
    283                   &gEfiSerialIoProtocolGuid,
    284                   (VOID **) &mDebugPortDevice.SerialIoBinding,
    285                   This->DriverBindingHandle,
    286                   ControllerHandle,
    287                   EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
    288                   );
    289   if (EFI_ERROR (Status)) {
    290     return Status;
    291   }
    292 
    293   mDebugPortDevice.SerialIoDeviceHandle = ControllerHandle;
    294 
    295   //
    296   // Initialize the Serial Io interface...
    297   //
    298   Status = mDebugPortDevice.SerialIoBinding->SetAttributes (
    299                                                 mDebugPortDevice.SerialIoBinding,
    300                                                 mDebugPortDevice.BaudRate,
    301                                                 mDebugPortDevice.ReceiveFifoDepth,
    302                                                 mDebugPortDevice.Timeout,
    303                                                 mDebugPortDevice.Parity,
    304                                                 mDebugPortDevice.DataBits,
    305                                                 mDebugPortDevice.StopBits
    306                                                 );
    307   if (EFI_ERROR (Status)) {
    308     mDebugPortDevice.BaudRate          = 0;
    309     mDebugPortDevice.Parity            = DefaultParity;
    310     mDebugPortDevice.DataBits          = 0;
    311     mDebugPortDevice.StopBits          = DefaultStopBits;
    312     mDebugPortDevice.ReceiveFifoDepth  = 0;
    313     Status = mDebugPortDevice.SerialIoBinding->SetAttributes (
    314                                                   mDebugPortDevice.SerialIoBinding,
    315                                                   mDebugPortDevice.BaudRate,
    316                                                   mDebugPortDevice.ReceiveFifoDepth,
    317                                                   mDebugPortDevice.Timeout,
    318                                                   mDebugPortDevice.Parity,
    319                                                   mDebugPortDevice.DataBits,
    320                                                   mDebugPortDevice.StopBits
    321                                                   );
    322     if (EFI_ERROR (Status)) {
    323       gBS->CloseProtocol (
    324             ControllerHandle,
    325             &gEfiSerialIoProtocolGuid,
    326             This->DriverBindingHandle,
    327             ControllerHandle
    328             );
    329       return Status;
    330     }
    331   }
    332 
    333   mDebugPortDevice.SerialIoBinding->Reset (mDebugPortDevice.SerialIoBinding);
    334 
    335   //
    336   // Create device path instance for DebugPort
    337   //
    338   DebugPortDP.Header.Type     = MESSAGING_DEVICE_PATH;
    339   DebugPortDP.Header.SubType  = MSG_VENDOR_DP;
    340   SetDevicePathNodeLength (&(DebugPortDP.Header), sizeof (DebugPortDP));
    341   CopyGuid (&DebugPortDP.Guid, &gEfiDebugPortDevicePathGuid);
    342 
    343   Dp1 = DevicePathFromHandle (ControllerHandle);
    344   if (Dp1 == NULL) {
    345     Dp1 = &EndDP;
    346     SetDevicePathEndNode (Dp1);
    347   }
    348 
    349   mDebugPortDevice.DebugPortDevicePath = AppendDevicePathNode (Dp1, (EFI_DEVICE_PATH_PROTOCOL *) &DebugPortDP);
    350   if (mDebugPortDevice.DebugPortDevicePath == NULL) {
    351     return EFI_OUT_OF_RESOURCES;
    352   }
    353   //
    354   // Publish DebugPort and Device Path protocols
    355   //
    356   Status = gBS->InstallMultipleProtocolInterfaces (
    357                   &mDebugPortDevice.DebugPortDeviceHandle,
    358                   &gEfiDevicePathProtocolGuid,
    359                   mDebugPortDevice.DebugPortDevicePath,
    360                   &gEfiDebugPortProtocolGuid,
    361                   &mDebugPortDevice.DebugPortInterface,
    362                   NULL
    363                   );
    364 
    365   if (EFI_ERROR (Status)) {
    366     gBS->CloseProtocol (
    367           ControllerHandle,
    368           &gEfiSerialIoProtocolGuid,
    369           This->DriverBindingHandle,
    370           ControllerHandle
    371           );
    372     return Status;
    373   }
    374   //
    375   // Connect debugport child to serial io
    376   //
    377   Status = gBS->OpenProtocol (
    378                   ControllerHandle,
    379                   &gEfiSerialIoProtocolGuid,
    380                   (VOID **) &mDebugPortDevice.SerialIoBinding,
    381                   This->DriverBindingHandle,
    382                   mDebugPortDevice.DebugPortDeviceHandle,
    383                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    384                   );
    385 
    386   if (EFI_ERROR (Status)) {
    387     gBS->CloseProtocol (
    388           ControllerHandle,
    389           &gEfiSerialIoProtocolGuid,
    390           This->DriverBindingHandle,
    391           ControllerHandle
    392           );
    393     return Status;
    394   }
    395 
    396   return EFI_SUCCESS;
    397 }
    398 
    399 /**
    400   Stop this driver on ControllerHandle by removing Serial IO protocol on
    401   the ControllerHandle.
    402 
    403   @param  This              Protocol instance pointer.
    404   @param  ControllerHandle  Handle of device to stop driver on
    405   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    406                             children is zero stop the entire bus driver.
    407   @param  ChildHandleBuffer List of Child Handles to Stop.
    408 
    409   @retval EFI_SUCCESS       This driver is removed ControllerHandle.
    410   @retval other             This driver was not removed from this device.
    411 
    412 **/
    413 EFI_STATUS
    414 EFIAPI
    415 DebugPortStop (
    416   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    417   IN  EFI_HANDLE                     ControllerHandle,
    418   IN  UINTN                          NumberOfChildren,
    419   IN  EFI_HANDLE                     *ChildHandleBuffer
    420   )
    421 {
    422   EFI_STATUS  Status;
    423 
    424   if (NumberOfChildren == 0) {
    425     //
    426     // Close the bus driver
    427     //
    428     gBS->CloseProtocol (
    429           ControllerHandle,
    430           &gEfiSerialIoProtocolGuid,
    431           This->DriverBindingHandle,
    432           ControllerHandle
    433           );
    434 
    435     mDebugPortDevice.SerialIoBinding = NULL;
    436 
    437     gBS->CloseProtocol (
    438           ControllerHandle,
    439           &gEfiDevicePathProtocolGuid,
    440           This->DriverBindingHandle,
    441           ControllerHandle
    442           );
    443 
    444     FreePool (mDebugPortDevice.DebugPortDevicePath);
    445 
    446     return EFI_SUCCESS;
    447   } else {
    448     //
    449     // Disconnect SerialIo child handle
    450     //
    451     Status = gBS->CloseProtocol (
    452                     mDebugPortDevice.SerialIoDeviceHandle,
    453                     &gEfiSerialIoProtocolGuid,
    454                     This->DriverBindingHandle,
    455                     mDebugPortDevice.DebugPortDeviceHandle
    456                     );
    457 
    458     if (EFI_ERROR (Status)) {
    459       return Status;
    460     }
    461     //
    462     // Unpublish our protocols (DevicePath, DebugPort)
    463     //
    464     Status = gBS->UninstallMultipleProtocolInterfaces (
    465                     mDebugPortDevice.DebugPortDeviceHandle,
    466                     &gEfiDevicePathProtocolGuid,
    467                     mDebugPortDevice.DebugPortDevicePath,
    468                     &gEfiDebugPortProtocolGuid,
    469                     &mDebugPortDevice.DebugPortInterface,
    470                     NULL
    471                     );
    472 
    473     if (EFI_ERROR (Status)) {
    474       gBS->OpenProtocol (
    475             ControllerHandle,
    476             &gEfiSerialIoProtocolGuid,
    477             (VOID **) &mDebugPortDevice.SerialIoBinding,
    478             This->DriverBindingHandle,
    479             mDebugPortDevice.DebugPortDeviceHandle,
    480             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    481             );
    482     } else {
    483       mDebugPortDevice.DebugPortDeviceHandle = NULL;
    484     }
    485   }
    486 
    487   return Status;
    488 }
    489 
    490 /**
    491   DebugPort protocol member function.  Calls SerialIo:GetControl to flush buffer.
    492   We cannot call SerialIo:SetAttributes because it uses pool services, which use
    493   locks, which affect TPL, so it's not interrupt context safe or re-entrant.
    494   SerialIo:Reset() calls SetAttributes, so it can't be used either.
    495 
    496   The port itself should be fine since it was set up during initialization.
    497 
    498   @param  This              Protocol instance pointer.
    499 
    500   @return EFI_SUCCESS       Always.
    501 
    502 **/
    503 EFI_STATUS
    504 EFIAPI
    505 DebugPortReset (
    506   IN EFI_DEBUGPORT_PROTOCOL   *This
    507   )
    508 {
    509   UINTN             BufferSize;
    510   UINTN             BitBucket;
    511 
    512   while (This->Poll (This) == EFI_SUCCESS) {
    513     BufferSize = 1;
    514     This->Read (This, 0, &BufferSize, &BitBucket);
    515   }
    516 
    517   return EFI_SUCCESS;
    518 }
    519 
    520 /**
    521   DebugPort protocol member function.  Calls SerialIo:Read() after setting
    522   if it's different than the last SerialIo access.
    523 
    524   @param  This                Pointer to DebugPort protocol.
    525   @param  Timeout             Timeout value.
    526   @param  BufferSize          On input, the size of Buffer.
    527                               On output, the amount of data actually written.
    528   @param  Buffer              Pointer to buffer to read.
    529 
    530   @retval EFI_SUCCESS
    531   @retval others
    532 
    533 **/
    534 EFI_STATUS
    535 EFIAPI
    536 DebugPortRead (
    537   IN EFI_DEBUGPORT_PROTOCOL   *This,
    538   IN UINT32                   Timeout,
    539   IN OUT UINTN                *BufferSize,
    540   IN VOID                     *Buffer
    541   )
    542 {
    543   DEBUGPORT_DEVICE  *DebugPortDevice;
    544   UINTN             LocalBufferSize;
    545   EFI_STATUS        Status;
    546   UINT8             *BufferPtr;
    547 
    548   DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
    549   BufferPtr       = Buffer;
    550   LocalBufferSize = *BufferSize;
    551 
    552   do {
    553     Status = DebugPortDevice->SerialIoBinding->Read (
    554                                                 DebugPortDevice->SerialIoBinding,
    555                                                 &LocalBufferSize,
    556                                                 BufferPtr
    557                                                 );
    558     if (Status == EFI_TIMEOUT) {
    559       if (Timeout > DEBUGPORT_UART_DEFAULT_TIMEOUT) {
    560         Timeout -= DEBUGPORT_UART_DEFAULT_TIMEOUT;
    561       } else {
    562         Timeout = 0;
    563       }
    564     } else if (EFI_ERROR (Status)) {
    565       break;
    566     }
    567 
    568     BufferPtr += LocalBufferSize;
    569     LocalBufferSize = *BufferSize - (BufferPtr - (UINT8 *) Buffer);
    570   } while (LocalBufferSize != 0 && Timeout > 0);
    571 
    572   *BufferSize = (UINTN) (BufferPtr - (UINT8 *) Buffer);
    573 
    574   return Status;
    575 }
    576 
    577 /**
    578   DebugPort protocol member function.  Calls SerialIo:Write() Writes 8 bytes at
    579   a time and does a GetControl between 8 byte writes to help insure reads are
    580   interspersed This is poor-man's flow control.
    581 
    582   @param  This                Pointer to DebugPort protocol.
    583   @param  Timeout             Timeout value.
    584   @param  BufferSize          On input, the size of Buffer.
    585                               On output, the amount of data actually written.
    586   @param  Buffer              Pointer to buffer to read.
    587 
    588   @retval EFI_SUCCESS         The data was written.
    589   @retval others              Fails when writting datas to debug port device.
    590 
    591 **/
    592 EFI_STATUS
    593 EFIAPI
    594 DebugPortWrite (
    595   IN EFI_DEBUGPORT_PROTOCOL   *This,
    596   IN UINT32                   Timeout,
    597   IN OUT UINTN                *BufferSize,
    598   OUT VOID                    *Buffer
    599   )
    600 {
    601   DEBUGPORT_DEVICE  *DebugPortDevice;
    602   UINTN             Position;
    603   UINTN             WriteSize;
    604   EFI_STATUS        Status;
    605   UINT32            SerialControl;
    606 
    607   Status          = EFI_SUCCESS;
    608   DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
    609 
    610   WriteSize       = 8;
    611   for (Position = 0; Position < *BufferSize && !EFI_ERROR (Status); Position += WriteSize) {
    612     DebugPortDevice->SerialIoBinding->GetControl (
    613                                         DebugPortDevice->SerialIoBinding,
    614                                         &SerialControl
    615                                         );
    616     if (*BufferSize - Position < 8) {
    617       WriteSize = *BufferSize - Position;
    618     }
    619 
    620     Status = DebugPortDevice->SerialIoBinding->Write (
    621                                                 DebugPortDevice->SerialIoBinding,
    622                                                 &WriteSize,
    623                                                 &((UINT8 *) Buffer)[Position]
    624                                                 );
    625   }
    626 
    627   *BufferSize = Position;
    628   return Status;
    629 }
    630 
    631 /**
    632   DebugPort protocol member function.  Calls SerialIo:Write() after setting
    633   if it's different than the last SerialIo access.
    634 
    635   @param  This                Pointer to DebugPort protocol.
    636 
    637   @retval EFI_SUCCESS         At least 1 character is ready to be read from
    638                               the DebugPort interface.
    639   @retval EFI_NOT_READY       There are no characters ready to read from the
    640                               DebugPort interface
    641   @retval EFI_DEVICE_ERROR    A hardware failure occured... (from SerialIo)
    642 
    643 **/
    644 EFI_STATUS
    645 EFIAPI
    646 DebugPortPoll (
    647   IN EFI_DEBUGPORT_PROTOCOL   *This
    648   )
    649 {
    650   EFI_STATUS        Status;
    651   UINT32            SerialControl;
    652   DEBUGPORT_DEVICE  *DebugPortDevice;
    653 
    654   DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
    655 
    656   Status = DebugPortDevice->SerialIoBinding->GetControl (
    657                                               DebugPortDevice->SerialIoBinding,
    658                                               &SerialControl
    659                                               );
    660 
    661   if (!EFI_ERROR (Status)) {
    662     if ((SerialControl & EFI_SERIAL_INPUT_BUFFER_EMPTY) != 0) {
    663       Status = EFI_NOT_READY;
    664     } else {
    665       Status = EFI_SUCCESS;
    666     }
    667   }
    668 
    669   return Status;
    670 }
    671 
    672 /**
    673   Unload function that is registered in the LoadImage protocol.  It un-installs
    674   protocols produced and deallocates pool used by the driver.  Called by the core
    675   when unloading the driver.
    676 
    677   @param  ImageHandle
    678 
    679   @retval EFI_SUCCESS     Unload Debug Port driver successfully.
    680   @retval EFI_ABORTED     Serial IO is still binding.
    681 
    682 **/
    683 EFI_STATUS
    684 EFIAPI
    685 ImageUnloadHandler (
    686   EFI_HANDLE ImageHandle
    687   )
    688 {
    689   EFI_STATUS  Status;
    690   VOID        *ComponentName;
    691   VOID        *ComponentName2;
    692 
    693   if (mDebugPortDevice.SerialIoBinding != NULL) {
    694     return EFI_ABORTED;
    695   }
    696 
    697   //
    698   // Driver is stopped already.
    699   //
    700   Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName);
    701   if (EFI_ERROR (Status)) {
    702     ComponentName = NULL;
    703   }
    704 
    705   Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2);
    706   if (EFI_ERROR (Status)) {
    707     ComponentName2 = NULL;
    708   }
    709 
    710   if (ComponentName == NULL) {
    711     if (ComponentName2 == NULL) {
    712       Status = gBS->UninstallMultipleProtocolInterfaces (
    713                       ImageHandle,
    714                       &gEfiDriverBindingProtocolGuid,  &gDebugPortDriverBinding,
    715                       NULL
    716                       );
    717     } else {
    718       Status = gBS->UninstallMultipleProtocolInterfaces (
    719                       ImageHandle,
    720                       &gEfiDriverBindingProtocolGuid,  &gDebugPortDriverBinding,
    721                       &gEfiComponentName2ProtocolGuid, ComponentName2,
    722                       NULL
    723                       );
    724     }
    725   } else {
    726     if (ComponentName2 == NULL) {
    727       Status = gBS->UninstallMultipleProtocolInterfaces (
    728                       ImageHandle,
    729                       &gEfiDriverBindingProtocolGuid,  &gDebugPortDriverBinding,
    730                       &gEfiComponentNameProtocolGuid,  ComponentName,
    731                       NULL
    732                       );
    733     } else {
    734       Status = gBS->UninstallMultipleProtocolInterfaces (
    735                       ImageHandle,
    736                       &gEfiDriverBindingProtocolGuid,  &gDebugPortDriverBinding,
    737                       &gEfiComponentNameProtocolGuid,  ComponentName,
    738                       &gEfiComponentName2ProtocolGuid, ComponentName2,
    739                       NULL
    740                       );
    741     }
    742   }
    743 
    744   return Status;
    745 }
    746