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