Serial.c revision ea2d90867ac938e89c4bae0d1c7308940af00784
1/**@file
2  Serial driver for standard UARTS on an ISA bus.
3
4  Copyright (c) 2006 - 2007, Intel Corporation<BR>
5  All rights reserved. This program and the accompanying materials
6  are licensed and made available under the terms and conditions of the BSD License
7  which accompanies this distribution.  The full text of the license may be found at
8  http://opensource.org/licenses/bsd-license.php
9
10  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "Serial.h"
16
17//
18// ISA Serial Driver Global Variables
19//
20EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
21  SerialControllerDriverSupported,
22  SerialControllerDriverStart,
23  SerialControllerDriverStop,
24  0xa,
25  NULL,
26  NULL
27};
28
29
30SERIAL_DEV  gSerialDevTempate = {
31  SERIAL_DEV_SIGNATURE,
32  NULL,
33  { // SerialIo
34    SERIAL_IO_INTERFACE_REVISION,
35    IsaSerialReset,
36    IsaSerialSetAttributes,
37    IsaSerialSetControl,
38    IsaSerialGetControl,
39    IsaSerialWrite,
40    IsaSerialRead,
41    NULL
42  },
43  { // SerialMode
44    SERIAL_PORT_DEFAULT_CONTROL_MASK,
45    SERIAL_PORT_DEFAULT_TIMEOUT,
46    FixedPcdGet64 (PcdUartDefaultBaudRate),     // BaudRate
47    SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
48    FixedPcdGet8 (PcdUartDefaultDataBits),      // DataBits
49    FixedPcdGet8 (PcdUartDefaultParity),        // Parity
50    FixedPcdGet8 (PcdUartDefaultStopBits)       // StopBits
51  },
52  NULL,
53  NULL,
54  { // UartDevicePath
55    {
56      MESSAGING_DEVICE_PATH,
57      MSG_UART_DP,
58      {
59        (UINT8) (sizeof (UART_DEVICE_PATH)),
60        (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
61      }
62    },
63    0,
64    FixedPcdGet64 (PcdUartDefaultBaudRate),
65    FixedPcdGet8 (PcdUartDefaultDataBits),
66    FixedPcdGet8 (PcdUartDefaultParity),
67    FixedPcdGet8 (PcdUartDefaultStopBits)
68  },
69  NULL,
70  0,    //BaseAddress
71  {
72    0,
73    0,
74    SERIAL_MAX_BUFFER_SIZE,
75    { 0 }
76  },
77  {
78    0,
79    0,
80    SERIAL_MAX_BUFFER_SIZE,
81    { 0 }
82  },
83  FALSE,
84  FALSE,
85  UART16550A,
86  NULL
87};
88
89/**
90  The user Entry Point for module IsaSerial. The user code starts with this function.
91
92  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
93  @param[in] SystemTable    A pointer to the EFI System Table.
94
95  @retval EFI_SUCCESS       The entry point is executed successfully.
96  @retval other             Some error occurs when executing this entry point.
97
98**/
99EFI_STATUS
100EFIAPI
101InitializeIsaSerial (
102  IN EFI_HANDLE           ImageHandle,
103  IN EFI_SYSTEM_TABLE     *SystemTable
104  )
105{
106  EFI_STATUS              Status;
107
108  //
109  // Install driver model protocol(s).
110  //
111  Status = 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  ADD_SERIAL_NAME (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) {
505      if (SerialDevice->DevicePath) {
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) {
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
673  @param  Fifo  - A pointer to the Data Structure SERIAL_DEV_FIFO
674
675  @return whether specific FIFO is empty or not
676
677**/
678BOOLEAN
679IsaSerialFifoEmpty (
680  IN SERIAL_DEV_FIFO *Fifo
681  )
682
683{
684  if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
685    return TRUE;
686  }
687
688  return FALSE;
689}
690
691/**
692  Add data to specific FIFO
693
694  @param Fifo                - A pointer to the Data Structure SERIAL_DEV_FIFO
695  @param Data                - the data added to FIFO
696
697  @retval EFI_SUCCESS         - Add data to specific FIFO successfully
698  @retval EFI_OUT_OF_RESOURCE - Failed to add data because FIFO is already full
699
700**/
701EFI_STATUS
702IsaSerialFifoAdd (
703  IN SERIAL_DEV_FIFO *Fifo,
704  IN UINT8           Data
705  )
706
707{
708  //
709  // if FIFO full can not add data
710  //
711  if (IsaSerialFifoFull (Fifo)) {
712    return EFI_OUT_OF_RESOURCES;
713  }
714  //
715  // FIFO is not full can add data
716  //
717  Fifo->Data[Fifo->Last] = Data;
718  Fifo->Surplus--;
719  Fifo->Last++;
720  if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {
721    Fifo->Last = 0;
722  }
723
724  return EFI_SUCCESS;
725}
726
727/**
728  Remove data from specific FIFO
729
730  @param Fifo                - A pointer to the Data Structure SERIAL_DEV_FIFO
731  @param Data                - the data removed from FIFO
732
733  @retval EFI_SUCCESS         - Remove data from specific FIFO successfully
734  @retval EFI_OUT_OF_RESOURCE - Failed to remove data because FIFO is empty
735
736**/
737EFI_STATUS
738IsaSerialFifoRemove (
739  IN  SERIAL_DEV_FIFO *Fifo,
740  OUT UINT8           *Data
741  )
742
743{
744  //
745  // if FIFO is empty, no data can remove
746  //
747  if (IsaSerialFifoEmpty (Fifo)) {
748    return EFI_OUT_OF_RESOURCES;
749  }
750  //
751  // FIFO is not empty, can remove data
752  //
753  *Data = Fifo->Data[Fifo->First];
754  Fifo->Surplus++;
755  Fifo->First++;
756  if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {
757    Fifo->First = 0;
758  }
759
760  return EFI_SUCCESS;
761}
762
763/**
764  Reads and writes all avaliable data.
765
766  @param SerialDevice         - The device to flush
767
768  @retval EFI_SUCCESS         - Data was read/written successfully.
769  @retval EFI_OUT_OF_RESOURCE - Failed because software receive FIFO is full.  Note, when
770                                this happens, pending writes are not done.
771
772**/
773EFI_STATUS
774IsaSerialReceiveTransmit (
775  IN SERIAL_DEV *SerialDevice
776  )
777
778{
779  SERIAL_PORT_LSR Lsr;
780  UINT8           Data;
781  BOOLEAN         ReceiveFifoFull;
782  SERIAL_PORT_MSR Msr;
783  SERIAL_PORT_MCR Mcr;
784  UINTN           TimeOut;
785
786  Data = 0;
787
788  //
789  // Begin the read or write
790  //
791  if (SerialDevice->SoftwareLoopbackEnable) {
792    do {
793      ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
794      if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
795        IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
796        if (ReceiveFifoFull) {
797          return EFI_OUT_OF_RESOURCES;
798        }
799
800        IsaSerialFifoAdd (&SerialDevice->Receive, Data);
801      }
802    } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));
803  } else {
804    ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
805    do {
806      Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
807
808      //
809      // Flush incomming data to prevent a an overrun during a long write
810      //
811      if (Lsr.Bits.DR && !ReceiveFifoFull) {
812        ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
813        if (!ReceiveFifoFull) {
814          if (Lsr.Bits.FIFOE || Lsr.Bits.OE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {
815            REPORT_STATUS_CODE_WITH_DEVICE_PATH (
816              EFI_ERROR_CODE,
817              EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
818              SerialDevice->DevicePath
819              );
820            if (Lsr.Bits.FIFOE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {
821              Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
822              continue;
823            }
824          }
825          //
826          // Make sure the receive data will not be missed, Assert DTR
827          //
828          if (SerialDevice->HardwareFlowControl) {
829            Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
830            Mcr.Bits.DTRC &= 0;
831            WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
832          }
833
834          Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
835
836          //
837          // Deassert DTR
838          //
839          if (SerialDevice->HardwareFlowControl) {
840            Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
841            Mcr.Bits.DTRC |= 1;
842            WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
843          }
844
845          IsaSerialFifoAdd (&SerialDevice->Receive, Data);
846
847          continue;
848        } else {
849          REPORT_STATUS_CODE_WITH_DEVICE_PATH (
850            EFI_PROGRESS_CODE,
851            EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
852            SerialDevice->DevicePath
853            );
854        }
855      }
856      //
857      // Do the write
858      //
859      if (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
860        //
861        // Make sure the transmit data will not be missed
862        //
863        if (SerialDevice->HardwareFlowControl) {
864          //
865          // Send RTS
866          //
867          Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
868          Mcr.Bits.RTS |= 1;
869          WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
870          //
871          // Wait for CTS
872          //
873          TimeOut   = 0;
874          Msr.Data  = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
875          while (!Msr.Bits.CTS) {
876            gBS->Stall (TIMEOUT_STALL_INTERVAL);
877            TimeOut++;
878            if (TimeOut > 5) {
879              break;
880            }
881
882            Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
883          }
884
885          if (Msr.Bits.CTS) {
886            IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
887            WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
888          }
889        }
890        //
891        // write the data out
892        //
893        if (!SerialDevice->HardwareFlowControl) {
894          IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
895          WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
896        }
897        //
898        // Make sure the transmit data will not be missed
899        //
900        if (SerialDevice->HardwareFlowControl) {
901          //
902          // Assert RTS
903          //
904          Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
905          Mcr.Bits.RTS &= 0;
906          WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
907        }
908      }
909    } while (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit));
910  }
911
912  return EFI_SUCCESS;
913}
914
915//
916// Interface Functions
917//
918/**
919  Reset serial device
920
921  @param This             - Pointer to EFI_SERIAL_IO_PROTOCOL
922
923  @retval EFI_SUCCESS      - Reset successfully
924  @retval EFI_DEVICE_ERROR - Failed to reset
925
926**/
927EFI_STATUS
928EFIAPI
929IsaSerialReset (
930  IN EFI_SERIAL_IO_PROTOCOL  *This
931  )
932{
933  EFI_STATUS      Status;
934  SERIAL_DEV      *SerialDevice;
935  SERIAL_PORT_LCR Lcr;
936  SERIAL_PORT_IER Ier;
937  SERIAL_PORT_MCR Mcr;
938  SERIAL_PORT_FCR Fcr;
939  EFI_TPL         Tpl;
940
941  SerialDevice = SERIAL_DEV_FROM_THIS (This);
942
943  //
944  // Report the status code reset the serial
945  //
946  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
947    EFI_PROGRESS_CODE,
948    EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
949    SerialDevice->DevicePath
950    );
951
952  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
953
954  //
955  // Make sure DLAB is 0.
956  //
957  Lcr.Data      = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
958  Lcr.Bits.DLAB = 0;
959  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
960
961  //
962  // Turn off all interrupts
963  //
964  Ier.Data        = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress);
965  Ier.Bits.RAVIE  = 0;
966  Ier.Bits.THEIE  = 0;
967  Ier.Bits.RIE    = 0;
968  Ier.Bits.MIE    = 0;
969  WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data);
970
971  //
972  // Disable the FIFO.
973  //
974  Fcr.Bits.TRFIFOE = 0;
975  WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
976
977  //
978  // Turn off loopback and disable device interrupt.
979  //
980  Mcr.Data      = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
981  Mcr.Bits.OUT1 = 0;
982  Mcr.Bits.OUT2 = 0;
983  Mcr.Bits.LME  = 0;
984  WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
985
986  //
987  // Clear the scratch pad register
988  //
989  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0);
990
991  //
992  // Go set the current attributes
993  //
994  Status = This->SetAttributes (
995                   This,
996                   This->Mode->BaudRate,
997                   This->Mode->ReceiveFifoDepth,
998                   This->Mode->Timeout,
999                   (EFI_PARITY_TYPE) This->Mode->Parity,
1000                   (UINT8) This->Mode->DataBits,
1001                   (EFI_STOP_BITS_TYPE) This->Mode->StopBits
1002                   );
1003
1004  if (EFI_ERROR (Status)) {
1005    gBS->RestoreTPL (Tpl);
1006    return EFI_DEVICE_ERROR;
1007  }
1008  //
1009  // Go set the current control bits
1010  //
1011  Status = This->SetControl (
1012                   This,
1013                   This->Mode->ControlMask
1014                   );
1015
1016  if (EFI_ERROR (Status)) {
1017    gBS->RestoreTPL (Tpl);
1018    return EFI_DEVICE_ERROR;
1019  }
1020  //
1021  // for 16550A enable FIFO, 16550 disable FIFO
1022  //
1023  Fcr.Bits.TRFIFOE  = 1;
1024  Fcr.Bits.RESETRF  = 1;
1025  Fcr.Bits.RESETTF  = 1;
1026  WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
1027
1028  //
1029  // Reset the software FIFO
1030  //
1031  SerialDevice->Receive.First     = 0;
1032  SerialDevice->Receive.Last      = 0;
1033  SerialDevice->Receive.Surplus   = SERIAL_MAX_BUFFER_SIZE;
1034  SerialDevice->Transmit.First    = 0;
1035  SerialDevice->Transmit.Last     = 0;
1036  SerialDevice->Transmit.Surplus  = SERIAL_MAX_BUFFER_SIZE;
1037
1038  gBS->RestoreTPL (Tpl);
1039
1040  //
1041  // Device reset is complete
1042  //
1043  return EFI_SUCCESS;
1044}
1045
1046/**
1047  Set new attributes to a serial device
1048
1049  @param This                   - Pointer to EFI_SERIAL_IO_PROTOCOL
1050  @param  BaudRate               - The baudrate of the serial device
1051  @param  ReceiveFifoDepth       - The depth of receive FIFO buffer
1052  @param  Timeout                - The request timeout for a single char
1053  @param  Parity                 - The type of parity used in serial device
1054  @param  DataBits               - Number of databits used in serial device
1055  @param  StopBits               - Number of stopbits used in serial device
1056
1057  @retval  EFI_SUCCESS            - The new attributes were set
1058  @retval  EFI_INVALID_PARAMETERS - One or more attributes have an unsupported value
1059  @retval  EFI_UNSUPPORTED        - Data Bits can not set to 5 or 6
1060  @retval  EFI_DEVICE_ERROR       - The serial device is not functioning correctly (no return)
1061
1062**/
1063EFI_STATUS
1064EFIAPI
1065IsaSerialSetAttributes (
1066  IN EFI_SERIAL_IO_PROTOCOL  *This,
1067  IN UINT64                  BaudRate,
1068  IN UINT32                  ReceiveFifoDepth,
1069  IN UINT32                  Timeout,
1070  IN EFI_PARITY_TYPE         Parity,
1071  IN UINT8                   DataBits,
1072  IN EFI_STOP_BITS_TYPE      StopBits
1073  )
1074{
1075  EFI_STATUS                Status;
1076  SERIAL_DEV                *SerialDevice;
1077  UINT32                    Divisor;
1078  UINT32                    Remained;
1079  SERIAL_PORT_LCR           Lcr;
1080  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
1081  EFI_TPL                   Tpl;
1082
1083  SerialDevice = SERIAL_DEV_FROM_THIS (This);
1084
1085  //
1086  // Check for default settings and fill in actual values.
1087  //
1088  if (BaudRate == 0) {
1089    BaudRate = FixedPcdGet64 (PcdUartDefaultBaudRate);
1090  }
1091
1092  if (ReceiveFifoDepth == 0) {
1093    ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
1094  }
1095
1096  if (Timeout == 0) {
1097    Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
1098  }
1099
1100  if (Parity == DefaultParity) {
1101    Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity);
1102  }
1103
1104  if (DataBits == 0) {
1105    DataBits = FixedPcdGet8 (PcdUartDefaultDataBits);
1106  }
1107
1108  if (StopBits == DefaultStopBits) {
1109    StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits);
1110  }
1111  //
1112  // 5 and 6 data bits can not be verified on a 16550A UART
1113  // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings.
1114  //
1115  if ((DataBits == 5) || (DataBits == 6)) {
1116    return EFI_INVALID_PARAMETER;
1117  }
1118  //
1119  // Make sure all parameters are valid
1120  //
1121  if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
1122    return EFI_INVALID_PARAMETER;
1123  }
1124  //
1125  // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200,
1126  // 38400,57600,115200
1127  //
1128  if (BaudRate < 75) {
1129    BaudRate = 50;
1130  } else if (BaudRate < 110) {
1131    BaudRate = 75;
1132  } else if (BaudRate < 134) {
1133    BaudRate = 110;
1134  } else if (BaudRate < 150) {
1135    BaudRate = 134;
1136  } else if (BaudRate < 300) {
1137    BaudRate = 150;
1138  } else if (BaudRate < 600) {
1139    BaudRate = 300;
1140  } else if (BaudRate < 1200) {
1141    BaudRate = 600;
1142  } else if (BaudRate < 1800) {
1143    BaudRate = 1200;
1144  } else if (BaudRate < 2000) {
1145    BaudRate = 1800;
1146  } else if (BaudRate < 2400) {
1147    BaudRate = 2000;
1148  } else if (BaudRate < 3600) {
1149    BaudRate = 2400;
1150  } else if (BaudRate < 4800) {
1151    BaudRate = 3600;
1152  } else if (BaudRate < 7200) {
1153    BaudRate = 4800;
1154  } else if (BaudRate < 9600) {
1155    BaudRate = 7200;
1156  } else if (BaudRate < 19200) {
1157    BaudRate = 9600;
1158  } else if (BaudRate < 38400) {
1159    BaudRate = 19200;
1160  } else if (BaudRate < 57600) {
1161    BaudRate = 38400;
1162  } else if (BaudRate < 115200) {
1163    BaudRate = 57600;
1164  } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) {
1165    BaudRate = 115200;
1166  }
1167
1168  if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {
1169    return EFI_INVALID_PARAMETER;
1170  }
1171
1172  if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
1173    return EFI_INVALID_PARAMETER;
1174  }
1175
1176  if ((Parity < NoParity) || (Parity > SpaceParity)) {
1177    return EFI_INVALID_PARAMETER;
1178  }
1179
1180  if ((DataBits < 5) || (DataBits > 8)) {
1181    return EFI_INVALID_PARAMETER;
1182  }
1183
1184  if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
1185    return EFI_INVALID_PARAMETER;
1186  }
1187  //
1188  // for DataBits = 5, StopBits can not set TwoStopBits
1189  //
1190  // if ((DataBits == 5) && (StopBits == TwoStopBits)) {
1191  //  return EFI_INVALID_PARAMETER;
1192  // }
1193  //
1194  // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits
1195  //
1196  if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {
1197    return EFI_INVALID_PARAMETER;
1198  }
1199
1200  //
1201  // Compute divisor use to program the baud rate using a round determination
1202  //
1203  Divisor = (UINT32) DivU64x32Remainder (
1204                       SERIAL_PORT_INPUT_CLOCK,
1205                       ((UINT32) BaudRate * 16),
1206                       &Remained
1207                       );
1208  if (Remained) {
1209    Divisor += 1;
1210  }
1211
1212  if ((Divisor == 0) || (Divisor & 0xffff0000)) {
1213    return EFI_INVALID_PARAMETER;
1214  }
1215
1216  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1217
1218  //
1219  // Compute the actual baud rate that the serial port will be programmed for.
1220  //
1221  BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16;
1222
1223  //
1224  // Put serial port on Divisor Latch Mode
1225  //
1226  Lcr.Data      = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1227  Lcr.Bits.DLAB = 1;
1228  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
1229
1230  //
1231  // Write the divisor to the serial port
1232  //
1233  WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));
1234  WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));
1235
1236  //
1237  // Put serial port back in normal mode and set remaining attributes.
1238  //
1239  Lcr.Bits.DLAB = 0;
1240
1241  switch (Parity) {
1242  case NoParity:
1243    Lcr.Bits.PAREN    = 0;
1244    Lcr.Bits.EVENPAR  = 0;
1245    Lcr.Bits.STICPAR  = 0;
1246    break;
1247
1248  case EvenParity:
1249    Lcr.Bits.PAREN    = 1;
1250    Lcr.Bits.EVENPAR  = 1;
1251    Lcr.Bits.STICPAR  = 0;
1252    break;
1253
1254  case OddParity:
1255    Lcr.Bits.PAREN    = 1;
1256    Lcr.Bits.EVENPAR  = 0;
1257    Lcr.Bits.STICPAR  = 0;
1258    break;
1259
1260  case SpaceParity:
1261    Lcr.Bits.PAREN    = 1;
1262    Lcr.Bits.EVENPAR  = 1;
1263    Lcr.Bits.STICPAR  = 1;
1264    break;
1265
1266  case MarkParity:
1267    Lcr.Bits.PAREN    = 1;
1268    Lcr.Bits.EVENPAR  = 0;
1269    Lcr.Bits.STICPAR  = 1;
1270    break;
1271
1272  default:
1273    break;
1274  }
1275
1276  switch (StopBits) {
1277  case OneStopBit:
1278    Lcr.Bits.STOPB = 0;
1279    break;
1280
1281  case OneFiveStopBits:
1282  case TwoStopBits:
1283    Lcr.Bits.STOPB = 1;
1284    break;
1285
1286  default:
1287    break;
1288  }
1289  //
1290  // DataBits
1291  //
1292  Lcr.Bits.SERIALDB = (UINT8) ((DataBits - 5) & 0x03);
1293  WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
1294
1295  //
1296  // Set the Serial I/O mode
1297  //
1298  This->Mode->BaudRate          = BaudRate;
1299  This->Mode->ReceiveFifoDepth  = ReceiveFifoDepth;
1300  This->Mode->Timeout           = Timeout;
1301  This->Mode->Parity            = Parity;
1302  This->Mode->DataBits          = DataBits;
1303  This->Mode->StopBits          = StopBits;
1304
1305  //
1306  // See if Device Path Node has actually changed
1307  //
1308  if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
1309      SerialDevice->UartDevicePath.DataBits == DataBits &&
1310      SerialDevice->UartDevicePath.Parity == Parity &&
1311      SerialDevice->UartDevicePath.StopBits == StopBits
1312      ) {
1313    gBS->RestoreTPL (Tpl);
1314    return EFI_SUCCESS;
1315  }
1316  //
1317  // Update the device path
1318  //
1319  SerialDevice->UartDevicePath.BaudRate = BaudRate;
1320  SerialDevice->UartDevicePath.DataBits = DataBits;
1321  SerialDevice->UartDevicePath.Parity   = (UINT8) Parity;
1322  SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
1323
1324  NewDevicePath = AppendDevicePathNode (
1325                    SerialDevice->ParentDevicePath,
1326                    (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
1327                    );
1328  if (NewDevicePath == NULL) {
1329    gBS->RestoreTPL (Tpl);
1330    return EFI_DEVICE_ERROR;
1331  }
1332
1333  if (SerialDevice->Handle != NULL) {
1334    Status = gBS->ReinstallProtocolInterface (
1335                    SerialDevice->Handle,
1336                    &gEfiDevicePathProtocolGuid,
1337                    SerialDevice->DevicePath,
1338                    NewDevicePath
1339                    );
1340    if (EFI_ERROR (Status)) {
1341      gBS->RestoreTPL (Tpl);
1342      return Status;
1343    }
1344  }
1345
1346  if (SerialDevice->DevicePath) {
1347    gBS->FreePool (SerialDevice->DevicePath);
1348  }
1349
1350  SerialDevice->DevicePath = NewDevicePath;
1351
1352  gBS->RestoreTPL (Tpl);
1353
1354  return EFI_SUCCESS;
1355}
1356
1357/**
1358  Set Control Bits
1359
1360  @param This            - Pointer to EFI_SERIAL_IO_PROTOCOL
1361  @param Control         - Control bits that can be settable
1362
1363  @retval EFI_SUCCESS     - New Control bits were set successfully
1364  @retval EFI_UNSUPPORTED - The Control bits wanted to set are not supported
1365
1366**/
1367EFI_STATUS
1368EFIAPI
1369IsaSerialSetControl (
1370  IN EFI_SERIAL_IO_PROTOCOL  *This,
1371  IN UINT32                  Control
1372  )
1373{
1374  SERIAL_DEV      *SerialDevice;
1375  SERIAL_PORT_MCR Mcr;
1376  EFI_TPL         Tpl;
1377
1378  //
1379  // The control bits that can be set are :
1380  //     EFI_SERIAL_DATA_TERMINAL_READY: 0x0001  // WO
1381  //     EFI_SERIAL_REQUEST_TO_SEND: 0x0002  // WO
1382  //     EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000  // RW
1383  //     EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000  // RW
1384  //
1385  SerialDevice = SERIAL_DEV_FROM_THIS (This);
1386
1387  //
1388  // first determine the parameter is invalid
1389  //
1390  if (Control & 0xffff8ffc) {
1391    return EFI_UNSUPPORTED;
1392  }
1393
1394  Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1395
1396  Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1397  Mcr.Bits.DTRC = 0;
1398  Mcr.Bits.RTS = 0;
1399  Mcr.Bits.LME = 0;
1400  SerialDevice->SoftwareLoopbackEnable = FALSE;
1401  SerialDevice->HardwareFlowControl = FALSE;
1402
1403  if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
1404    Mcr.Bits.DTRC = 1;
1405  }
1406
1407  if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
1408    Mcr.Bits.RTS = 1;
1409  }
1410
1411  if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
1412    Mcr.Bits.LME = 1;
1413  }
1414
1415  if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
1416    SerialDevice->HardwareFlowControl = TRUE;
1417  }
1418
1419  WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
1420
1421  if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
1422    SerialDevice->SoftwareLoopbackEnable = TRUE;
1423  }
1424
1425  gBS->RestoreTPL (Tpl);
1426
1427  return EFI_SUCCESS;
1428}
1429
1430/**
1431  Get ControlBits
1432
1433  @param This        - Pointer to EFI_SERIAL_IO_PROTOCOL
1434  @param Control     - Control signals of the serial device
1435
1436  @retval EFI_SUCCESS - Get Control signals successfully
1437
1438**/
1439EFI_STATUS
1440EFIAPI
1441IsaSerialGetControl (
1442  IN EFI_SERIAL_IO_PROTOCOL  *This,
1443  OUT UINT32                 *Control
1444  )
1445{
1446  SERIAL_DEV      *SerialDevice;
1447  SERIAL_PORT_MSR Msr;
1448  SERIAL_PORT_MCR Mcr;
1449  EFI_TPL         Tpl;
1450
1451  Tpl           = gBS->RaiseTPL (TPL_NOTIFY);
1452
1453  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1454
1455  *Control      = 0;
1456
1457  //
1458  // Read the Modem Status Register
1459  //
1460  Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1461
1462  if (Msr.Bits.CTS) {
1463    *Control |= EFI_SERIAL_CLEAR_TO_SEND;
1464  }
1465
1466  if (Msr.Bits.DSR) {
1467    *Control |= EFI_SERIAL_DATA_SET_READY;
1468  }
1469
1470  if (Msr.Bits.RI) {
1471    *Control |= EFI_SERIAL_RING_INDICATE;
1472  }
1473
1474  if (Msr.Bits.DCD) {
1475    *Control |= EFI_SERIAL_CARRIER_DETECT;
1476  }
1477  //
1478  // Read the Modem Control Register
1479  //
1480  Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1481
1482  if (Mcr.Bits.DTRC) {
1483    *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1484  }
1485
1486  if (Mcr.Bits.RTS) {
1487    *Control |= EFI_SERIAL_REQUEST_TO_SEND;
1488  }
1489
1490  if (Mcr.Bits.LME) {
1491    *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1492  }
1493
1494  if (SerialDevice->HardwareFlowControl) {
1495    *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1496  }
1497  //
1498  // See if the Transmit FIFO is empty
1499  //
1500  IsaSerialReceiveTransmit (SerialDevice);
1501
1502  if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
1503    *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
1504  }
1505  //
1506  // See if the Receive FIFO is empty.
1507  //
1508  IsaSerialReceiveTransmit (SerialDevice);
1509
1510  if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {
1511    *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1512  }
1513
1514  if (SerialDevice->SoftwareLoopbackEnable) {
1515    *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1516  }
1517
1518  gBS->RestoreTPL (Tpl);
1519
1520  return EFI_SUCCESS;
1521}
1522
1523/**
1524  Write the specified number of bytes to serial device
1525
1526  @param This             - Pointer to EFI_SERIAL_IO_PROTOCOL
1527  @param  BufferSize       - On input the size of Buffer, on output the amount of
1528                       data actually written
1529  @param  Buffer           - The buffer of data to write
1530
1531  @retval EFI_SUCCESS      - The data were written successfully
1532  @retval EFI_DEVICE_ERROR - The device reported an error
1533  @retval EFI_TIMEOUT      - The write operation was stopped due to timeout
1534
1535**/
1536EFI_STATUS
1537EFIAPI
1538IsaSerialWrite (
1539  IN EFI_SERIAL_IO_PROTOCOL  *This,
1540  IN OUT UINTN               *BufferSize,
1541  IN VOID                    *Buffer
1542  )
1543{
1544  SERIAL_DEV  *SerialDevice;
1545  UINT8       *CharBuffer;
1546  UINT32      Index;
1547  UINTN       Elapsed;
1548  UINTN       ActualWrite;
1549  EFI_TPL     Tpl;
1550
1551  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1552  Elapsed       = 0;
1553  ActualWrite   = 0;
1554
1555  if (*BufferSize == 0) {
1556    return EFI_SUCCESS;
1557  }
1558
1559  if (!Buffer) {
1560    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1561      EFI_ERROR_CODE,
1562      EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1563      SerialDevice->DevicePath
1564      );
1565
1566    return EFI_DEVICE_ERROR;
1567  }
1568
1569  Tpl         = gBS->RaiseTPL (TPL_NOTIFY);
1570
1571  CharBuffer  = (UINT8 *) Buffer;
1572
1573  for (Index = 0; Index < *BufferSize; Index++) {
1574    IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
1575
1576    while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
1577      //
1578      //  Unsuccessful write so check if timeout has expired, if not,
1579      //  stall for a bit, increment time elapsed, and try again
1580      //
1581      if (Elapsed >= This->Mode->Timeout) {
1582        *BufferSize = ActualWrite;
1583        gBS->RestoreTPL (Tpl);
1584        return EFI_TIMEOUT;
1585      }
1586
1587      gBS->Stall (TIMEOUT_STALL_INTERVAL);
1588
1589      Elapsed += TIMEOUT_STALL_INTERVAL;
1590    }
1591
1592    ActualWrite++;
1593    //
1594    //  Successful write so reset timeout
1595    //
1596    Elapsed = 0;
1597  }
1598
1599  gBS->RestoreTPL (Tpl);
1600
1601  return EFI_SUCCESS;
1602}
1603
1604/**
1605  Read the specified number of bytes from serial device
1606
1607  @param This             - Pointer to EFI_SERIAL_IO_PROTOCOL
1608  @param BufferSize       - On input the size of Buffer, on output the amount of
1609                       data returned in buffer
1610  @param Buffer           -  The buffer to return the data into
1611
1612  @retval EFI_SUCCESS      - The data were read successfully
1613  @retval EFI_DEVICE_ERROR - The device reported an error
1614  @retval EFI_TIMEOUT      - The read operation was stopped due to timeout
1615
1616**/
1617EFI_STATUS
1618EFIAPI
1619IsaSerialRead (
1620  IN EFI_SERIAL_IO_PROTOCOL  *This,
1621  IN OUT UINTN               *BufferSize,
1622  OUT VOID                   *Buffer
1623  )
1624{
1625  SERIAL_DEV  *SerialDevice;
1626  UINT32      Index;
1627  UINT8       *CharBuffer;
1628  UINTN       Elapsed;
1629  EFI_STATUS  Status;
1630  EFI_TPL     Tpl;
1631
1632  SerialDevice  = SERIAL_DEV_FROM_THIS (This);
1633  Elapsed       = 0;
1634
1635  if (*BufferSize == 0) {
1636    return EFI_SUCCESS;
1637  }
1638
1639  if (!Buffer) {
1640    return EFI_DEVICE_ERROR;
1641  }
1642
1643  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
1644
1645  Status  = IsaSerialReceiveTransmit (SerialDevice);
1646
1647  if (EFI_ERROR (Status)) {
1648    *BufferSize = 0;
1649
1650    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1651      EFI_ERROR_CODE,
1652      EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1653      SerialDevice->DevicePath
1654      );
1655
1656    gBS->RestoreTPL (Tpl);
1657
1658    return EFI_DEVICE_ERROR;
1659  }
1660
1661  CharBuffer = (UINT8 *) Buffer;
1662  for (Index = 0; Index < *BufferSize; Index++) {
1663    while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
1664      //
1665      //  Unsuccessful read so check if timeout has expired, if not,
1666      //  stall for a bit, increment time elapsed, and try again
1667      //  Need this time out to get conspliter to work.
1668      //
1669      if (Elapsed >= This->Mode->Timeout) {
1670        *BufferSize = Index;
1671        gBS->RestoreTPL (Tpl);
1672        return EFI_TIMEOUT;
1673      }
1674
1675      gBS->Stall (TIMEOUT_STALL_INTERVAL);
1676      Elapsed += TIMEOUT_STALL_INTERVAL;
1677
1678      Status = IsaSerialReceiveTransmit (SerialDevice);
1679      if (Status == EFI_DEVICE_ERROR) {
1680        *BufferSize = Index;
1681        gBS->RestoreTPL (Tpl);
1682        return EFI_DEVICE_ERROR;
1683      }
1684    }
1685    //
1686    //  Successful read so reset timeout
1687    //
1688    Elapsed = 0;
1689  }
1690
1691  IsaSerialReceiveTransmit (SerialDevice);
1692
1693  gBS->RestoreTPL (Tpl);
1694
1695  return EFI_SUCCESS;
1696}
1697
1698/**
1699  Use scratchpad register to test if this serial port is present
1700
1701  @param SerialDevice - Pointer to serial device structure
1702
1703  @return if this serial port is present
1704**/
1705BOOLEAN
1706IsaSerialPortPresent (
1707  IN SERIAL_DEV *SerialDevice
1708  )
1709
1710{
1711  UINT8   Temp;
1712  BOOLEAN Status;
1713
1714  Status = TRUE;
1715
1716  //
1717  // Save SCR reg
1718  //
1719  Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1720  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);
1721
1722  if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) {
1723    Status = FALSE;
1724  }
1725
1726  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);
1727
1728  if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) {
1729    Status = FALSE;
1730  }
1731  //
1732  // Restore SCR
1733  //
1734  WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);
1735  return Status;
1736}
1737
1738/**
1739  Use IsaIo protocol to read serial port
1740
1741  @param IsaIo       - Pointer to EFI_ISA_IO_PROTOCOL instance
1742  @param BaseAddress - Serial port register group base address
1743  @param Offset      - Offset in register group
1744
1745  @return Data read from serial port
1746
1747**/
1748UINT8
1749IsaSerialReadPort (
1750  IN EFI_ISA_IO_PROTOCOL                   *IsaIo,
1751  IN UINT16                                BaseAddress,
1752  IN UINT32                                Offset
1753  )
1754{
1755  UINT8 Data;
1756
1757  //
1758  // Use IsaIo to access IO
1759  //
1760  IsaIo->Io.Read (
1761             IsaIo,
1762             EfiIsaIoWidthUint8,
1763             BaseAddress + Offset,
1764             1,
1765             &Data
1766             );
1767  return Data;
1768}
1769
1770/**
1771  Use IsaIo protocol to write serial port
1772
1773  @param  IsaIo       - Pointer to EFI_ISA_IO_PROTOCOL instance
1774  @param  BaseAddress - Serial port register group base address
1775  @param  Offset      - Offset in register group
1776  @param  Data        - data which is to be written to some serial port register
1777
1778**/
1779VOID
1780IsaSerialWritePort (
1781  IN EFI_ISA_IO_PROTOCOL                 *IsaIo,
1782  IN UINT16                              BaseAddress,
1783  IN UINT32                              Offset,
1784  IN UINT8                               Data
1785  )
1786{
1787  //
1788  // Use IsaIo to access IO
1789  //
1790  IsaIo->Io.Write (
1791             IsaIo,
1792             EfiIsaIoWidthUint8,
1793             BaseAddress + Offset,
1794             1,
1795             &Data
1796             );
1797}
1798
1799