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