Serial.c revision 19bf20e11acd88a02922201f97e6d64edcd16390
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 == 0) || 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 == 1) || 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  //
1193  // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits
1194  //
1195  if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {
1196    return EFI_INVALID_PARAMETER;
1197  }
1198
1199  //
1200  // Compute divisor use to program the baud rate using a round determination
1201  //
1202  Divisor = (UINT32) DivU64x32Remainder (
1203                       SERIAL_PORT_INPUT_CLOCK,
1204                       ((UINT32) BaudRate * 16),
1205                       &Remained
1206                       );
1207  if (Remained != 0) {
1208    Divisor += 1;
1209  }
1210
1211  if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) {
1212    return EFI_INVALID_PARAMETER;
1213  }
1214
1215  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1216
1217  //
1218  // Compute the actual baud rate that the serial port will be programmed for.
1219  //
1220  BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16;
1221
1222  //
1223  // Put serial port on Divisor Latch Mode
1224  //
1225  Lcr.Data      = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1226  Lcr.Bits.DLab = 1;
1227  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
1228
1229  //
1230  // Write the divisor to the serial port
1231  //
1232  WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));
1233  WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));
1234
1235  //
1236  // Put serial port back in normal mode and set remaining attributes.
1237  //
1238  Lcr.Bits.DLab = 0;
1239
1240  switch (Parity) {
1241  case NoParity:
1242    Lcr.Bits.ParEn    = 0;
1243    Lcr.Bits.EvenPar  = 0;
1244    Lcr.Bits.SticPar  = 0;
1245    break;
1246
1247  case EvenParity:
1248    Lcr.Bits.ParEn    = 1;
1249    Lcr.Bits.EvenPar  = 1;
1250    Lcr.Bits.SticPar  = 0;
1251    break;
1252
1253  case OddParity:
1254    Lcr.Bits.ParEn    = 1;
1255    Lcr.Bits.EvenPar  = 0;
1256    Lcr.Bits.SticPar  = 0;
1257    break;
1258
1259  case SpaceParity:
1260    Lcr.Bits.ParEn    = 1;
1261    Lcr.Bits.EvenPar  = 1;
1262    Lcr.Bits.SticPar  = 1;
1263    break;
1264
1265  case MarkParity:
1266    Lcr.Bits.ParEn    = 1;
1267    Lcr.Bits.EvenPar  = 0;
1268    Lcr.Bits.SticPar  = 1;
1269    break;
1270
1271  default:
1272    break;
1273  }
1274
1275  switch (StopBits) {
1276  case OneStopBit:
1277    Lcr.Bits.StopB = 0;
1278    break;
1279
1280  case OneFiveStopBits:
1281  case TwoStopBits:
1282    Lcr.Bits.StopB = 1;
1283    break;
1284
1285  default:
1286    break;
1287  }
1288  //
1289  // DataBits
1290  //
1291  Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
1292  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
1293
1294  //
1295  // Set the Serial I/O mode
1296  //
1297  This->Mode->BaudRate          = BaudRate;
1298  This->Mode->ReceiveFifoDepth  = ReceiveFifoDepth;
1299  This->Mode->Timeout           = Timeout;
1300  This->Mode->Parity            = Parity;
1301  This->Mode->DataBits          = DataBits;
1302  This->Mode->StopBits          = StopBits;
1303
1304  //
1305  // See if Device Path Node has actually changed
1306  //
1307  if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
1308      SerialDevice->UartDevicePath.DataBits == DataBits &&
1309      SerialDevice->UartDevicePath.Parity == Parity &&
1310      SerialDevice->UartDevicePath.StopBits == StopBits
1311      ) {
1312    gBS->RestoreTPL (Tpl);
1313    return EFI_SUCCESS;
1314  }
1315  //
1316  // Update the device path
1317  //
1318  SerialDevice->UartDevicePath.BaudRate = BaudRate;
1319  SerialDevice->UartDevicePath.DataBits = DataBits;
1320  SerialDevice->UartDevicePath.Parity   = (UINT8) Parity;
1321  SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
1322
1323  NewDevicePath = AppendDevicePathNode (
1324                    SerialDevice->ParentDevicePath,
1325                    (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
1326                    );
1327  if (NewDevicePath == NULL) {
1328    gBS->RestoreTPL (Tpl);
1329    return EFI_DEVICE_ERROR;
1330  }
1331
1332  if (SerialDevice->Handle != NULL) {
1333    Status = gBS->ReinstallProtocolInterface (
1334                    SerialDevice->Handle,
1335                    &gEfiDevicePathProtocolGuid,
1336                    SerialDevice->DevicePath,
1337                    NewDevicePath
1338                    );
1339    if (EFI_ERROR (Status)) {
1340      gBS->RestoreTPL (Tpl);
1341      return Status;
1342    }
1343  }
1344
1345  if (SerialDevice->DevicePath != NULL) {
1346    gBS->FreePool (SerialDevice->DevicePath);
1347  }
1348
1349  SerialDevice->DevicePath = NewDevicePath;
1350
1351  gBS->RestoreTPL (Tpl);
1352
1353  return EFI_SUCCESS;
1354}
1355
1356/**
1357  Set Control Bits.
1358
1359  @param This              Pointer to EFI_SERIAL_IO_PROTOCOL
1360  @param Control           Control bits that can be settable
1361
1362  @retval EFI_SUCCESS       New Control bits were set successfully
1363  @retval EFI_UNSUPPORTED   The Control bits wanted to set are not supported
1364
1365**/
1366EFI_STATUS
1367EFIAPI
1368IsaSerialSetControl (
1369  IN EFI_SERIAL_IO_PROTOCOL  *This,
1370  IN UINT32                  Control
1371  )
1372{
1373  SERIAL_DEV      *SerialDevice;
1374  SERIAL_PORT_MCR Mcr;
1375  EFI_TPL         Tpl;
1376
1377  //
1378  // The control bits that can be set are :
1379  //     EFI_SERIAL_DATA_TERMINAL_READY: 0x0001  // WO
1380  //     EFI_SERIAL_REQUEST_TO_SEND: 0x0002  // WO
1381  //     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000  // RW
1382  //     EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000  // RW
1383  //
1384  SerialDevice = SERIAL_DEV_FROM_THIS (This);
1385
1386  //
1387  // first determine the parameter is invalid
1388  //
1389  if ((Control & 0xffff8ffc) != 0) {
1390    return EFI_UNSUPPORTED;
1391  }
1392
1393  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1394
1395  Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1396  Mcr.Bits.DtrC = 0;
1397  Mcr.Bits.Rts = 0;
1398  Mcr.Bits.Lme = 0;
1399  SerialDevice->SoftwareLoopbackEnable = FALSE;
1400  SerialDevice->HardwareFlowControl = FALSE;
1401
1402  if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
1403    Mcr.Bits.DtrC = 1;
1404  }
1405
1406  if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
1407    Mcr.Bits.Rts = 1;
1408  }
1409
1410  if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
1411    Mcr.Bits.Lme = 1;
1412  }
1413
1414  if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
1415    SerialDevice->HardwareFlowControl = TRUE;
1416  }
1417
1418  WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
1419
1420  if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
1421    SerialDevice->SoftwareLoopbackEnable = TRUE;
1422  }
1423
1424  gBS->RestoreTPL (Tpl);
1425
1426  return EFI_SUCCESS;
1427}
1428
1429/**
1430  Get ControlBits.
1431
1432  @param This          Pointer to EFI_SERIAL_IO_PROTOCOL
1433  @param Control       Control signals of the serial device
1434
1435  @retval EFI_SUCCESS   Get Control signals successfully
1436
1437**/
1438EFI_STATUS
1439EFIAPI
1440IsaSerialGetControl (
1441  IN EFI_SERIAL_IO_PROTOCOL  *This,
1442  OUT UINT32                 *Control
1443  )
1444{
1445  SERIAL_DEV      *SerialDevice;
1446  SERIAL_PORT_MSR Msr;
1447  SERIAL_PORT_MCR Mcr;
1448  EFI_TPL         Tpl;
1449
1450  Tpl           = gBS->RaiseTPL (TPL_NOTIFY);
1451
1452  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1453
1454  *Control      = 0;
1455
1456  //
1457  // Read the Modem Status Register
1458  //
1459  Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1460
1461  if (Msr.Bits.Cts == 1) {
1462    *Control |= EFI_SERIAL_CLEAR_TO_SEND;
1463  }
1464
1465  if (Msr.Bits.Dsr == 1) {
1466    *Control |= EFI_SERIAL_DATA_SET_READY;
1467  }
1468
1469  if (Msr.Bits.Ri == 1) {
1470    *Control |= EFI_SERIAL_RING_INDICATE;
1471  }
1472
1473  if (Msr.Bits.Dcd == 1) {
1474    *Control |= EFI_SERIAL_CARRIER_DETECT;
1475  }
1476  //
1477  // Read the Modem Control Register
1478  //
1479  Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1480
1481  if (Mcr.Bits.DtrC == 1) {
1482    *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1483  }
1484
1485  if (Mcr.Bits.Rts == 1) {
1486    *Control |= EFI_SERIAL_REQUEST_TO_SEND;
1487  }
1488
1489  if (Mcr.Bits.Lme == 1) {
1490    *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1491  }
1492
1493  if (SerialDevice->HardwareFlowControl) {
1494    *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1495  }
1496  //
1497  // See if the Transmit FIFO is empty
1498  //
1499  IsaSerialReceiveTransmit (SerialDevice);
1500
1501  if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
1502    *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
1503  }
1504  //
1505  // See if the Receive FIFO is empty.
1506  //
1507  IsaSerialReceiveTransmit (SerialDevice);
1508
1509  if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {
1510    *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1511  }
1512
1513  if (SerialDevice->SoftwareLoopbackEnable) {
1514    *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1515  }
1516
1517  gBS->RestoreTPL (Tpl);
1518
1519  return EFI_SUCCESS;
1520}
1521
1522/**
1523  Write the specified number of bytes to serial device.
1524
1525  @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
1526  @param  BufferSize         On input the size of Buffer, on output the amount of
1527                       data actually written
1528  @param  Buffer             The buffer of data to write
1529
1530  @retval EFI_SUCCESS        The data were written successfully
1531  @retval EFI_DEVICE_ERROR   The device reported an error
1532  @retval EFI_TIMEOUT        The write operation was stopped due to timeout
1533
1534**/
1535EFI_STATUS
1536EFIAPI
1537IsaSerialWrite (
1538  IN EFI_SERIAL_IO_PROTOCOL  *This,
1539  IN OUT UINTN               *BufferSize,
1540  IN VOID                    *Buffer
1541  )
1542{
1543  SERIAL_DEV  *SerialDevice;
1544  UINT8       *CharBuffer;
1545  UINT32      Index;
1546  UINTN       Elapsed;
1547  UINTN       ActualWrite;
1548  EFI_TPL     Tpl;
1549
1550  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1551  Elapsed       = 0;
1552  ActualWrite   = 0;
1553
1554  if (*BufferSize == 0) {
1555    return EFI_SUCCESS;
1556  }
1557
1558  if (Buffer == NULL) {
1559    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1560      EFI_ERROR_CODE,
1561      EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1562      SerialDevice->DevicePath
1563      );
1564
1565    return EFI_DEVICE_ERROR;
1566  }
1567
1568  Tpl         = gBS->RaiseTPL (TPL_NOTIFY);
1569
1570  CharBuffer  = (UINT8 *) Buffer;
1571
1572  for (Index = 0; Index < *BufferSize; Index++) {
1573    IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
1574
1575    while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
1576      //
1577      //  Unsuccessful write so check if timeout has expired, if not,
1578      //  stall for a bit, increment time elapsed, and try again
1579      //
1580      if (Elapsed >= This->Mode->Timeout) {
1581        *BufferSize = ActualWrite;
1582        gBS->RestoreTPL (Tpl);
1583        return EFI_TIMEOUT;
1584      }
1585
1586      gBS->Stall (TIMEOUT_STALL_INTERVAL);
1587
1588      Elapsed += TIMEOUT_STALL_INTERVAL;
1589    }
1590
1591    ActualWrite++;
1592    //
1593    //  Successful write so reset timeout
1594    //
1595    Elapsed = 0;
1596  }
1597
1598  gBS->RestoreTPL (Tpl);
1599
1600  return EFI_SUCCESS;
1601}
1602
1603/**
1604  Read the specified number of bytes from serial device.
1605
1606  @param This               Pointer to EFI_SERIAL_IO_PROTOCOL
1607  @param BufferSize         On input the size of Buffer, on output the amount of
1608                            data returned in buffer
1609  @param Buffer             The buffer to return the data into
1610
1611  @retval EFI_SUCCESS        The data were read successfully
1612  @retval EFI_DEVICE_ERROR   The device reported an error
1613  @retval EFI_TIMEOUT        The read operation was stopped due to timeout
1614
1615**/
1616EFI_STATUS
1617EFIAPI
1618IsaSerialRead (
1619  IN EFI_SERIAL_IO_PROTOCOL  *This,
1620  IN OUT UINTN               *BufferSize,
1621  OUT VOID                   *Buffer
1622  )
1623{
1624  SERIAL_DEV  *SerialDevice;
1625  UINT32      Index;
1626  UINT8       *CharBuffer;
1627  UINTN       Elapsed;
1628  EFI_STATUS  Status;
1629  EFI_TPL     Tpl;
1630
1631  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1632  Elapsed       = 0;
1633
1634  if (*BufferSize == 0) {
1635    return EFI_SUCCESS;
1636  }
1637
1638  if (Buffer == NULL) {
1639    return EFI_DEVICE_ERROR;
1640  }
1641
1642  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
1643
1644  Status  = IsaSerialReceiveTransmit (SerialDevice);
1645
1646  if (EFI_ERROR (Status)) {
1647    *BufferSize = 0;
1648
1649    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1650      EFI_ERROR_CODE,
1651      EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1652      SerialDevice->DevicePath
1653      );
1654
1655    gBS->RestoreTPL (Tpl);
1656
1657    return EFI_DEVICE_ERROR;
1658  }
1659
1660  CharBuffer = (UINT8 *) Buffer;
1661  for (Index = 0; Index < *BufferSize; Index++) {
1662    while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
1663      //
1664      //  Unsuccessful read so check if timeout has expired, if not,
1665      //  stall for a bit, increment time elapsed, and try again
1666      //  Need this time out to get conspliter to work.
1667      //
1668      if (Elapsed >= This->Mode->Timeout) {
1669        *BufferSize = Index;
1670        gBS->RestoreTPL (Tpl);
1671        return EFI_TIMEOUT;
1672      }
1673
1674      gBS->Stall (TIMEOUT_STALL_INTERVAL);
1675      Elapsed += TIMEOUT_STALL_INTERVAL;
1676
1677      Status = IsaSerialReceiveTransmit (SerialDevice);
1678      if (Status == EFI_DEVICE_ERROR) {
1679        *BufferSize = Index;
1680        gBS->RestoreTPL (Tpl);
1681        return EFI_DEVICE_ERROR;
1682      }
1683    }
1684    //
1685    //  Successful read so reset timeout
1686    //
1687    Elapsed = 0;
1688  }
1689
1690  IsaSerialReceiveTransmit (SerialDevice);
1691
1692  gBS->RestoreTPL (Tpl);
1693
1694  return EFI_SUCCESS;
1695}
1696
1697/**
1698  Use scratchpad register to test if this serial port is present.
1699
1700  @param SerialDevice   Pointer to serial device structure
1701
1702  @return if this serial port is present
1703**/
1704BOOLEAN
1705IsaSerialPortPresent (
1706  IN SERIAL_DEV *SerialDevice
1707  )
1708
1709{
1710  UINT8   Temp;
1711  BOOLEAN Status;
1712
1713  Status = TRUE;
1714
1715  //
1716  // Save SCR reg
1717  //
1718  Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1719  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);
1720
1721  if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) {
1722    Status = FALSE;
1723  }
1724
1725  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);
1726
1727  if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) {
1728    Status = FALSE;
1729  }
1730  //
1731  // Restore SCR
1732  //
1733  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);
1734  return Status;
1735}
1736
1737/**
1738  Use IsaIo protocol to read serial port.
1739
1740  @param IsaIo         Pointer to EFI_ISA_IO_PROTOCOL instance
1741  @param BaseAddress   Serial port register group base address
1742  @param Offset        Offset in register group
1743
1744  @return Data read from serial port
1745
1746**/
1747UINT8
1748IsaSerialReadPort (
1749  IN EFI_ISA_IO_PROTOCOL                   *IsaIo,
1750  IN UINT16                                BaseAddress,
1751  IN UINT32                                Offset
1752  )
1753{
1754  UINT8 Data;
1755
1756  //
1757  // Use IsaIo to access IO
1758  //
1759  IsaIo->Io.Read (
1760             IsaIo,
1761             EfiIsaIoWidthUint8,
1762             BaseAddress + Offset,
1763             1,
1764             &Data
1765             );
1766  return Data;
1767}
1768
1769/**
1770  Use IsaIo protocol to write serial port.
1771
1772  @param  IsaIo         Pointer to EFI_ISA_IO_PROTOCOL instance
1773  @param  BaseAddress   Serial port register group base address
1774  @param  Offset        Offset in register group
1775  @param  Data          data which is to be written to some serial port register
1776
1777**/
1778VOID
1779IsaSerialWritePort (
1780  IN EFI_ISA_IO_PROTOCOL                 *IsaIo,
1781  IN UINT16                              BaseAddress,
1782  IN UINT32                              Offset,
1783  IN UINT8                               Data
1784  )
1785{
1786  //
1787  // Use IsaIo to access IO
1788  //
1789  IsaIo->Io.Write (
1790             IsaIo,
1791             EfiIsaIoWidthUint8,
1792             BaseAddress + Offset,
1793             1,
1794             &Data
1795             );
1796}
1797
1798