WinNtSerialIo.c revision 6394182967f63d4a97a1c882861d9958657112bb
1/**@file
2
3Copyright (c) 2006 - 2007, Intel Corporation
4All rights reserved. This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution.  The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13
14  WinNtSerialIo.c
15
16Abstract:
17
18  Our DriverBinding member functions operate on the handles
19  created by the NT Bus driver.
20
21  Handle(1) - WinNtIo - DevicePath(1)
22
23  If a serial port is added to the system this driver creates a new handle.
24  The new handle is required, since the serial device must add an UART device
25  pathnode.
26
27  Handle(2) - SerialIo - DevicePath(1)\UART
28
29  The driver then adds a gEfiWinNtSerialPortGuid as a protocol to Handle(1).
30  The instance data for this protocol is the private data used to create
31  Handle(2).
32
33  Handle(1) - WinNtIo - DevicePath(1) - WinNtSerialPort
34
35  If the driver is unloaded Handle(2) is removed from the system and
36  gEfiWinNtSerialPortGuid is removed from Handle(1).
37
38  Note: Handle(1) is any handle created by the Win NT Bus driver that is passed
39  into the DriverBinding member functions of this driver. This driver requires
40  a Handle(1) to contain a WinNtIo protocol, a DevicePath protocol, and
41  the TypeGuid in the WinNtIo must be gEfiWinNtSerialPortGuid.
42
43  If Handle(1) contains a gEfiWinNtSerialPortGuid protocol then the driver is
44  loaded on the device.
45
46**/
47
48#include "WinNtSerialIo.h"
49
50EFI_DRIVER_BINDING_PROTOCOL gWinNtSerialIoDriverBinding = {
51  WinNtSerialIoDriverBindingSupported,
52  WinNtSerialIoDriverBindingStart,
53  WinNtSerialIoDriverBindingStop,
54  0xa,
55  NULL,
56  NULL
57};
58
59//
60// List of supported baud rate
61//
62UINT64 mBaudRateCurrentSupport[] = {50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200, 38400, 57600, 115200, SERIAL_PORT_MAX_BAUD_RATE + 1};
63
64/**
65  The user Entry Point for module WinNtSerialIo. The user code starts with this function.
66
67  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
68  @param[in] SystemTable    A pointer to the EFI System Table.
69
70  @retval EFI_SUCCESS       The entry point is executed successfully.
71  @retval other             Some error occurs when executing this entry point.
72
73**/
74EFI_STATUS
75EFIAPI
76InitializeWinNtSerialIo(
77  IN EFI_HANDLE           ImageHandle,
78  IN EFI_SYSTEM_TABLE     *SystemTable
79  )
80{
81  EFI_STATUS              Status;
82
83  //
84  // Install driver model protocol(s).
85  //
86  Status = EfiLibInstallDriverBindingComponentName2 (
87             ImageHandle,
88             SystemTable,
89             &gWinNtSerialIoDriverBinding,
90             ImageHandle,
91             &gWinNtSerialIoComponentName,
92             &gWinNtSerialIoComponentName2
93             );
94  ASSERT_EFI_ERROR (Status);
95
96
97  return Status;
98}
99
100EFI_STATUS
101EFIAPI
102WinNtSerialIoDriverBindingSupported (
103  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
104  IN  EFI_HANDLE                    Handle,
105  IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
106  )
107/*++
108
109Routine Description:
110
111Arguments:
112
113Returns:
114
115  None
116
117--*/
118// TODO:    This - add argument and description to function comment
119// TODO:    Handle - add argument and description to function comment
120// TODO:    RemainingDevicePath - add argument and description to function comment
121// TODO:    EFI_SUCCESS - add return value to function comment
122// TODO:    EFI_SUCCESS - add return value to function comment
123{
124  EFI_STATUS                Status;
125  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
126  EFI_WIN_NT_IO_PROTOCOL    *WinNtIo;
127  UART_DEVICE_PATH          *UartNode;
128
129  //
130  // Open the IO Abstraction(s) needed to perform the supported test
131  //
132  Status = gBS->OpenProtocol (
133                  Handle,
134                  &gEfiDevicePathProtocolGuid,
135                  (VOID **) &ParentDevicePath,
136                  This->DriverBindingHandle,
137                  Handle,
138                  EFI_OPEN_PROTOCOL_BY_DRIVER
139                  );
140  if (Status == EFI_ALREADY_STARTED) {
141    return EFI_SUCCESS;
142  }
143
144  if (EFI_ERROR (Status)) {
145    return Status;
146  }
147
148  gBS->CloseProtocol (
149        Handle,
150        &gEfiDevicePathProtocolGuid,
151        This->DriverBindingHandle,
152        Handle
153        );
154
155  Status = gBS->OpenProtocol (
156                  Handle,
157                  &gEfiWinNtIoProtocolGuid,
158                  (VOID **) &WinNtIo,
159                  This->DriverBindingHandle,
160                  Handle,
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  //
172  // Make sure that the WinNt Thunk Protocol is valid
173  //
174  if (WinNtIo->WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
175    Status = EFI_UNSUPPORTED;
176    goto Error;
177  }
178
179  //
180  // Check the GUID to see if this is a handle type the driver supports
181  //
182  if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtSerialPortGuid)) {
183    Status = EFI_UNSUPPORTED;
184    goto Error;
185  }
186
187  if (RemainingDevicePath != NULL) {
188    Status    = EFI_UNSUPPORTED;
189    UartNode  = (UART_DEVICE_PATH *) RemainingDevicePath;
190    if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
191        UartNode->Header.SubType != MSG_UART_DP ||
192        DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) {
193      goto Error;
194    }
195    if (UartNode->BaudRate < 0 || UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
196      goto Error;
197    }
198    if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
199      goto Error;
200    }
201    if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
202      goto Error;
203    }
204    if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
205      goto Error;
206    }
207    if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
208      goto Error;
209    }
210    if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
211      goto Error;
212    }
213    Status = EFI_SUCCESS;
214  }
215
216Error:
217  //
218  // Close the I/O Abstraction(s) used to perform the supported test
219  //
220  gBS->CloseProtocol (
221        Handle,
222        &gEfiWinNtIoProtocolGuid,
223        This->DriverBindingHandle,
224        Handle
225        );
226
227  return Status;
228}
229
230EFI_STATUS
231EFIAPI
232WinNtSerialIoDriverBindingStart (
233  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
234  IN  EFI_HANDLE                    Handle,
235  IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
236  )
237/*++
238
239Routine Description:
240
241Arguments:
242
243Returns:
244
245  None
246
247--*/
248// TODO:    This - add argument and description to function comment
249// TODO:    Handle - add argument and description to function comment
250// TODO:    RemainingDevicePath - add argument and description to function comment
251// TODO:    EFI_SUCCESS - add return value to function comment
252// TODO:    EFI_SUCCESS - add return value to function comment
253{
254  EFI_STATUS                          Status;
255  EFI_WIN_NT_IO_PROTOCOL              *WinNtIo;
256  WIN_NT_SERIAL_IO_PRIVATE_DATA       *Private;
257  HANDLE                              NtHandle;
258  UART_DEVICE_PATH                    Node;
259  EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
260  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
261  UINTN                               EntryCount;
262  UINTN                               Index;
263  EFI_SERIAL_IO_PROTOCOL              *SerialIo;
264
265  Private   = NULL;
266  NtHandle  = INVALID_HANDLE_VALUE;
267
268  //
269  // Grab the protocols we need
270  //
271  Status = gBS->OpenProtocol (
272                  Handle,
273                  &gEfiDevicePathProtocolGuid,
274                  (VOID **) &ParentDevicePath,
275                  This->DriverBindingHandle,
276                  Handle,
277                  EFI_OPEN_PROTOCOL_BY_DRIVER
278                  );
279  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
280    return Status;
281  }
282
283  //
284  // Grab the IO abstraction we need to get any work done
285  //
286  Status = gBS->OpenProtocol (
287                  Handle,
288                  &gEfiWinNtIoProtocolGuid,
289                  (VOID **) &WinNtIo,
290                  This->DriverBindingHandle,
291                  Handle,
292                  EFI_OPEN_PROTOCOL_BY_DRIVER
293                  );
294  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
295    gBS->CloseProtocol (
296          Handle,
297          &gEfiDevicePathProtocolGuid,
298          This->DriverBindingHandle,
299          Handle
300          );
301    return Status;
302  }
303
304  if (Status == EFI_ALREADY_STARTED) {
305
306    if (RemainingDevicePath == NULL) {
307      return EFI_SUCCESS;
308    }
309
310    //
311    // Make sure a child handle does not already exist.  This driver can only
312    // produce one child per serial port.
313    //
314    Status = gBS->OpenProtocolInformation (
315                    Handle,
316                    &gEfiWinNtIoProtocolGuid,
317                    &OpenInfoBuffer,
318                    &EntryCount
319                    );
320    if (EFI_ERROR (Status)) {
321      return Status;
322    }
323
324    Status = EFI_ALREADY_STARTED;
325    for (Index = 0; Index < EntryCount; Index++) {
326      if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
327        Status = gBS->OpenProtocol (
328                        OpenInfoBuffer[Index].ControllerHandle,
329                        &gEfiSerialIoProtocolGuid,
330                        (VOID **) &SerialIo,
331                        This->DriverBindingHandle,
332                        Handle,
333                        EFI_OPEN_PROTOCOL_GET_PROTOCOL
334                        );
335        if (!EFI_ERROR (Status)) {
336          CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
337          Status = SerialIo->SetAttributes (
338                              SerialIo,
339                              Node.BaudRate,
340                              SerialIo->Mode->ReceiveFifoDepth,
341                              SerialIo->Mode->Timeout,
342                              Node.Parity,
343                              Node.DataBits,
344                              Node.StopBits
345                              );
346        }
347        break;
348      }
349    }
350
351    FreePool (OpenInfoBuffer);
352    return Status;
353  }
354
355  //
356  // Check to see if we can access the hardware device. If it's Open in NT we
357  // will not get access.
358  //
359  NtHandle = WinNtIo->WinNtThunk->CreateFile (
360                                    WinNtIo->EnvString,
361                                    GENERIC_READ | GENERIC_WRITE,
362                                    0,
363                                    NULL,
364                                    OPEN_EXISTING,
365                                    0,
366                                    NULL
367                                    );
368  if (NtHandle == INVALID_HANDLE_VALUE) {
369    Status = EFI_DEVICE_ERROR;
370    goto Error;
371  }
372
373  //
374  // Construct Private data
375  //
376  Private = AllocatePool (sizeof (WIN_NT_SERIAL_IO_PRIVATE_DATA));
377  if (Private == NULL) {
378    goto Error;
379  }
380
381  //
382  // This signature must be valid before any member function is called
383  //
384  Private->Signature              = WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
385  Private->NtHandle               = NtHandle;
386  Private->ControllerHandle       = Handle;
387  Private->Handle                 = NULL;
388  Private->WinNtThunk             = WinNtIo->WinNtThunk;
389  Private->ParentDevicePath       = ParentDevicePath;
390  Private->ControllerNameTable    = NULL;
391
392  Private->SoftwareLoopbackEnable = FALSE;
393  Private->HardwareLoopbackEnable = FALSE;
394  Private->HardwareFlowControl    = FALSE;
395  Private->Fifo.First             = 0;
396  Private->Fifo.Last              = 0;
397  Private->Fifo.Surplus           = SERIAL_MAX_BUFFER_SIZE;
398
399  AddUnicodeString2 (
400    "eng",
401    gWinNtSerialIoComponentName.SupportedLanguages,
402    &Private->ControllerNameTable,
403    WinNtIo->EnvString,
404    TRUE
405    );
406  AddUnicodeString2 (
407    "en",
408    gWinNtSerialIoComponentName2.SupportedLanguages,
409    &Private->ControllerNameTable,
410    WinNtIo->EnvString,
411    FALSE
412    );
413
414
415  Private->SerialIo.Revision      = SERIAL_IO_INTERFACE_REVISION;
416  Private->SerialIo.Reset         = WinNtSerialIoReset;
417  Private->SerialIo.SetAttributes = WinNtSerialIoSetAttributes;
418  Private->SerialIo.SetControl    = WinNtSerialIoSetControl;
419  Private->SerialIo.GetControl    = WinNtSerialIoGetControl;
420  Private->SerialIo.Write         = WinNtSerialIoWrite;
421  Private->SerialIo.Read          = WinNtSerialIoRead;
422  Private->SerialIo.Mode          = &Private->SerialIoMode;
423
424  if (RemainingDevicePath != NULL) {
425    //
426    // Match the configuration of the RemainingDevicePath. IsHandleSupported()
427    // already checked to make sure the RemainingDevicePath contains settings
428    // that we can support.
429    //
430    CopyMem (&Private->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
431  } else {
432    //
433    // Build the device path by appending the UART node to the ParentDevicePath
434    // from the WinNtIo handle. The Uart setings are zero here, since
435    // SetAttribute() will update them to match the default setings.
436    //
437    ZeroMem (&Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
438    Private->UartDevicePath.Header.Type     = MESSAGING_DEVICE_PATH;
439    Private->UartDevicePath.Header.SubType  = MSG_UART_DP;
440    SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
441  }
442
443  //
444  // Build the device path by appending the UART node to the ParentDevicePath
445  // from the WinNtIo handle. The Uart setings are zero here, since
446  // SetAttribute() will update them to match the current setings.
447  //
448  Private->DevicePath = AppendDevicePathNode (
449                          ParentDevicePath,
450                          (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
451                          );
452  if (Private->DevicePath == NULL) {
453    Status = EFI_OUT_OF_RESOURCES;
454    goto Error;
455  }
456
457  //
458  // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
459  //
460  Private->SerialIoMode.ControlMask       = SERIAL_CONTROL_MASK;
461  Private->SerialIoMode.Timeout           = SERIAL_TIMEOUT_DEFAULT;
462  Private->SerialIoMode.BaudRate          = Private->UartDevicePath.BaudRate;
463  Private->SerialIoMode.ReceiveFifoDepth  = SERIAL_FIFO_DEFAULT;
464  Private->SerialIoMode.DataBits          = Private->UartDevicePath.DataBits;
465  Private->SerialIoMode.Parity            = Private->UartDevicePath.Parity;
466  Private->SerialIoMode.StopBits          = Private->UartDevicePath.StopBits;
467
468  //
469  // Issue a reset to initialize the COM port
470  //
471  Status = Private->SerialIo.Reset (&Private->SerialIo);
472  if (EFI_ERROR (Status)) {
473    goto Error;
474  }
475
476  //
477  // Create new child handle
478  //
479  Status = gBS->InstallMultipleProtocolInterfaces (
480                  &Private->Handle,
481                  &gEfiSerialIoProtocolGuid,
482                  &Private->SerialIo,
483                  &gEfiDevicePathProtocolGuid,
484                  Private->DevicePath,
485                  NULL
486                  );
487  if (EFI_ERROR (Status)) {
488    goto Error;
489  }
490
491  //
492  // Open For Child Device
493  //
494  Status = gBS->OpenProtocol (
495                  Handle,
496                  &gEfiWinNtIoProtocolGuid,
497                  (VOID **) &WinNtIo,
498                  This->DriverBindingHandle,
499                  Private->Handle,
500                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
501                  );
502  if (EFI_ERROR (Status)) {
503    goto Error;
504  }
505
506  return EFI_SUCCESS;
507
508Error:
509  //
510  // Use the Stop() function to free all resources allocated in Start()
511  //
512  if (Private != NULL) {
513    if (Private->Handle != NULL) {
514      This->Stop (This, Handle, 1, &Private->Handle);
515    } else {
516      if (NtHandle != INVALID_HANDLE_VALUE) {
517        Private->WinNtThunk->CloseHandle (NtHandle);
518      }
519
520      if (Private->DevicePath != NULL) {
521        FreePool (Private->DevicePath);
522      }
523
524      FreeUnicodeStringTable (Private->ControllerNameTable);
525
526      FreePool (Private);
527    }
528  }
529
530  This->Stop (This, Handle, 0, NULL);
531
532  return Status;
533}
534
535EFI_STATUS
536EFIAPI
537WinNtSerialIoDriverBindingStop (
538  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
539  IN  EFI_HANDLE                    Handle,
540  IN  UINTN                         NumberOfChildren,
541  IN  EFI_HANDLE                    *ChildHandleBuffer
542  )
543/*++
544
545Routine Description:
546
547  TODO: Add function description
548
549Arguments:
550
551  This              - TODO: add argument description
552  Handle            - TODO: add argument description
553  NumberOfChildren  - TODO: add argument description
554  ChildHandleBuffer - TODO: add argument description
555
556Returns:
557
558  EFI_DEVICE_ERROR - TODO: Add description for return value
559  EFI_SUCCESS - TODO: Add description for return value
560
561--*/
562{
563  EFI_STATUS                    Status;
564  UINTN                         Index;
565  BOOLEAN                       AllChildrenStopped;
566  EFI_SERIAL_IO_PROTOCOL        *SerialIo;
567  WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
568  EFI_WIN_NT_IO_PROTOCOL        *WinNtIo;
569
570  //
571  // Complete all outstanding transactions to Controller.
572  // Don't allow any new transaction to Controller to be started.
573  //
574
575  if (NumberOfChildren == 0) {
576    //
577    // Close the bus driver
578    //
579    Status = gBS->CloseProtocol (
580                    Handle,
581                    &gEfiWinNtIoProtocolGuid,
582                    This->DriverBindingHandle,
583                    Handle
584                    );
585    Status = gBS->CloseProtocol (
586                    Handle,
587                    &gEfiDevicePathProtocolGuid,
588                    This->DriverBindingHandle,
589                    Handle
590                    );
591    return Status;
592  }
593
594  AllChildrenStopped = TRUE;
595
596  for (Index = 0; Index < NumberOfChildren; Index++) {
597    Status = gBS->OpenProtocol (
598                    ChildHandleBuffer[Index],
599                    &gEfiSerialIoProtocolGuid,
600                    (VOID **) &SerialIo,
601                    This->DriverBindingHandle,
602                    Handle,
603                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
604                    );
605    if (!EFI_ERROR (Status)) {
606      Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo);
607
608      ASSERT (Private->Handle == ChildHandleBuffer[Index]);
609
610      Status = gBS->CloseProtocol (
611                      Handle,
612                      &gEfiWinNtIoProtocolGuid,
613                      This->DriverBindingHandle,
614                      ChildHandleBuffer[Index]
615                      );
616
617      Status = gBS->UninstallMultipleProtocolInterfaces (
618                      ChildHandleBuffer[Index],
619                      &gEfiSerialIoProtocolGuid,
620                      &Private->SerialIo,
621                      &gEfiDevicePathProtocolGuid,
622                      Private->DevicePath,
623                      NULL
624                      );
625
626      if (EFI_ERROR (Status)) {
627        gBS->OpenProtocol (
628              Handle,
629              &gEfiWinNtIoProtocolGuid,
630              (VOID **) &WinNtIo,
631              This->DriverBindingHandle,
632              ChildHandleBuffer[Index],
633              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
634              );
635      } else {
636        Private->WinNtThunk->CloseHandle (Private->NtHandle);
637
638        FreePool (Private->DevicePath);
639
640        FreeUnicodeStringTable (Private->ControllerNameTable);
641
642        FreePool (Private);
643      }
644    }
645
646    if (EFI_ERROR (Status)) {
647      AllChildrenStopped = FALSE;
648    }
649  }
650
651  if (!AllChildrenStopped) {
652    return EFI_DEVICE_ERROR;
653  }
654
655  return EFI_SUCCESS;
656}
657
658//
659// Serial IO Protocol member functions
660//
661
662EFI_STATUS
663EFIAPI
664WinNtSerialIoReset (
665  IN EFI_SERIAL_IO_PROTOCOL *This
666  )
667/*++
668
669Routine Description:
670
671  TODO: Add function description
672
673Arguments:
674
675  This  - TODO: add argument description
676
677Returns:
678
679  TODO: add return values
680
681--*/
682{
683  WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
684  EFI_TPL                       Tpl;
685
686  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
687
688  Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
689
690  Private->WinNtThunk->PurgeComm (
691                        Private->NtHandle,
692                        PURGE_TXCLEAR | PURGE_RXCLEAR
693                        );
694
695  gBS->RestoreTPL (Tpl);
696
697  return This->SetAttributes (
698                This,
699                This->Mode->BaudRate,
700                This->Mode->ReceiveFifoDepth,
701                This->Mode->Timeout,
702                This->Mode->Parity,
703                (UINT8) This->Mode->DataBits,
704                This->Mode->StopBits
705                );
706}
707
708EFI_STATUS
709EFIAPI
710WinNtSerialIoSetAttributes (
711  IN EFI_SERIAL_IO_PROTOCOL *This,
712  IN UINT64                 BaudRate,
713  IN UINT32                 ReceiveFifoDepth,
714  IN UINT32                 Timeout,
715  IN EFI_PARITY_TYPE        Parity,
716  IN UINT8                  DataBits,
717  IN EFI_STOP_BITS_TYPE     StopBits
718  )
719/*++
720
721Routine Description:
722
723  This function is used to set the attributes.
724
725Arguments:
726
727  This              - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue.
728  BaudRate          - The Baud rate of the serial device.
729  ReceiveFifoDepth  - The request depth of fifo on receive side.
730  Timeout           - the request timeout for a single charact.
731  Parity            - The type of parity used in serial device.
732  DataBits          - Number of deata bits used in serial device.
733  StopBits          - Number of stop bits used in serial device.
734
735Returns:
736  Status code
737
738  None
739
740--*/
741// TODO:    EFI_SUCCESS - add return value to function comment
742// TODO:    EFI_DEVICE_ERROR - add return value to function comment
743// TODO:    EFI_DEVICE_ERROR - add return value to function comment
744// TODO:    EFI_DEVICE_ERROR - add return value to function comment
745// TODO:    EFI_SUCCESS - add return value to function comment
746// TODO:    EFI_DEVICE_ERROR - add return value to function comment
747// TODO:    EFI_SUCCESS - add return value to function comment
748{
749  EFI_STATUS                    Status;
750  UINTN                         Index;
751  WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
752  COMMTIMEOUTS                  PortTimeOuts;
753  DWORD                         ConvertedTime;
754  BOOL                          Result;
755  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
756  EFI_TPL                       Tpl;
757
758  Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
759
760  //
761  //  Some of our arguments have defaults if a null value is passed in, and
762  //   we must set the default values if a null argument is passed in.
763  //
764  if (BaudRate == 0) {
765    BaudRate = FixedPcdGet64 (PcdUartDefaultBaudRate);
766  }
767
768  if (ReceiveFifoDepth == 0) {
769    ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
770  }
771
772  if (Timeout == 0) {
773    Timeout = SERIAL_TIMEOUT_DEFAULT;
774  }
775
776  if (Parity == DefaultParity) {
777    Parity = FixedPcdGet8 (PcdUartDefaultParity);
778  }
779
780  if (DataBits == 0) {
781    DataBits = FixedPcdGet8 (PcdUartDefaultDataBits);
782  }
783
784  if (StopBits == DefaultStopBits) {
785    StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits);
786  }
787
788  //
789  // Make sure all parameters are valid
790  //
791  if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
792    return EFI_INVALID_PARAMETER;
793  }
794
795  //
796  //The lower baud rate supported by the serial device will be selected without exceeding the unsupported BaudRate parameter
797  //
798
799  for (Index = 1; Index < (sizeof (mBaudRateCurrentSupport) / sizeof (mBaudRateCurrentSupport[0])); Index++) {
800    if (BaudRate < mBaudRateCurrentSupport[Index]) {
801      BaudRate = mBaudRateCurrentSupport[Index-1];
802      break;
803      }
804  }
805
806  if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {
807    return EFI_INVALID_PARAMETER;
808  }
809
810  if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
811    return EFI_INVALID_PARAMETER;
812  }
813
814  if ((Parity < NoParity) || (Parity > SpaceParity)) {
815    return EFI_INVALID_PARAMETER;
816  }
817
818  if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
819    return EFI_INVALID_PARAMETER;
820  }
821
822  //
823  // Now we only support DataBits=7,8.
824  //
825  if ((DataBits < 7) || (DataBits > 8)) {
826    return EFI_INVALID_PARAMETER;
827  }
828
829  //
830  // Now we only support DataBits=7,8.
831  // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits.
832  //
833  if (StopBits == OneFiveStopBits) {
834    return EFI_INVALID_PARAMETER;
835  }
836
837  //
838  // See if the new attributes already match the current attributes
839  //
840  if (Private->UartDevicePath.BaudRate       == BaudRate         &&
841      Private->UartDevicePath.DataBits       == DataBits         &&
842      Private->UartDevicePath.Parity         == Parity           &&
843      Private->UartDevicePath.StopBits       == StopBits         &&
844      Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth &&
845      Private->SerialIoMode.Timeout          == Timeout             ) {
846    return EFI_SUCCESS;
847  }
848
849  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
850
851  //
852  //  Get current values from NT
853  //
854  ZeroMem (&Private->NtDCB, sizeof (DCB));
855  Private->NtDCB.DCBlength = sizeof (DCB);
856
857  if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Private->NtDCB)) {
858    Private->NtError = Private->WinNtThunk->GetLastError ();
859    DEBUG ((EFI_D_ERROR, "SerialSetAttributes: GetCommState %d\n", Private->NtError));
860    gBS->RestoreTPL (Tpl);
861    return EFI_DEVICE_ERROR;
862  }
863
864  //
865  // Map EFI com setting to NT
866  //
867  Private->NtDCB.BaudRate         = ConvertBaud2Nt (BaudRate);
868  Private->NtDCB.ByteSize         = ConvertData2Nt (DataBits);
869  Private->NtDCB.Parity           = ConvertParity2Nt (Parity);
870  Private->NtDCB.StopBits         = ConvertStop2Nt (StopBits);
871
872  Private->NtDCB.fBinary          = TRUE;
873  Private->NtDCB.fParity          = Private->NtDCB.Parity == NOPARITY ? FALSE : TRUE;
874  Private->NtDCB.fOutxCtsFlow     = FALSE;
875  Private->NtDCB.fOutxDsrFlow     = FALSE;
876  Private->NtDCB.fDtrControl      = DTR_CONTROL_ENABLE;
877  Private->NtDCB.fDsrSensitivity  = FALSE;
878  Private->NtDCB.fOutX            = FALSE;
879  Private->NtDCB.fInX             = FALSE;
880  Private->NtDCB.fRtsControl      = RTS_CONTROL_ENABLE;
881  Private->NtDCB.fNull            = FALSE;
882
883  //
884  //  Set new values
885  //
886  Result = Private->WinNtThunk->SetCommState (Private->NtHandle, &Private->NtDCB);
887  if (!Result) {
888    Private->NtError = Private->WinNtThunk->GetLastError ();
889    DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommState %d\n", Private->NtError));
890    gBS->RestoreTPL (Tpl);
891    return EFI_DEVICE_ERROR;
892  }
893
894  //
895  //  Set com port read/write timeout values
896  //
897  ConvertedTime = ConvertTime2Nt (Timeout);
898  PortTimeOuts.ReadIntervalTimeout = MAXDWORD;
899  PortTimeOuts.ReadTotalTimeoutMultiplier = 0;
900  PortTimeOuts.ReadTotalTimeoutConstant = ConvertedTime;
901  PortTimeOuts.WriteTotalTimeoutMultiplier = ConvertedTime == 0 ? 1 : ConvertedTime;
902  PortTimeOuts.WriteTotalTimeoutConstant = 0;
903
904  if (!Private->WinNtThunk->SetCommTimeouts (Private->NtHandle, &PortTimeOuts)) {
905    Private->NtError = Private->WinNtThunk->GetLastError ();
906    DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommTimeouts %d\n", Private->NtError));
907    gBS->RestoreTPL (Tpl);
908    return EFI_DEVICE_ERROR;
909  }
910
911  //
912  //  Update mode
913  //
914  Private->SerialIoMode.BaudRate          = BaudRate;
915  Private->SerialIoMode.ReceiveFifoDepth  = ReceiveFifoDepth;
916  Private->SerialIoMode.Timeout           = Timeout;
917  Private->SerialIoMode.Parity            = Parity;
918  Private->SerialIoMode.DataBits          = DataBits;
919  Private->SerialIoMode.StopBits          = StopBits;
920
921  //
922  // See if Device Path Node has actually changed
923  //
924  if (Private->UartDevicePath.BaudRate     == BaudRate &&
925      Private->UartDevicePath.DataBits     == DataBits &&
926      Private->UartDevicePath.Parity       == Parity   &&
927      Private->UartDevicePath.StopBits     == StopBits    ) {
928    gBS->RestoreTPL(Tpl);
929    return EFI_SUCCESS;
930  }
931
932  //
933  // Update the device path
934  //
935  Private->UartDevicePath.BaudRate  = BaudRate;
936  Private->UartDevicePath.DataBits  = DataBits;
937  Private->UartDevicePath.Parity    = (UINT8) Parity;
938  Private->UartDevicePath.StopBits  = (UINT8) StopBits;
939
940  NewDevicePath = AppendDevicePathNode (
941                    Private->ParentDevicePath,
942                    (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
943                    );
944  if (NewDevicePath == NULL) {
945    gBS->RestoreTPL (Tpl);
946    return EFI_DEVICE_ERROR;
947  }
948
949  if (Private->Handle != NULL) {
950    Status = gBS->ReinstallProtocolInterface (
951                    Private->Handle,
952                    &gEfiDevicePathProtocolGuid,
953                    Private->DevicePath,
954                    NewDevicePath
955                    );
956    if (EFI_ERROR (Status)) {
957      gBS->RestoreTPL (Tpl);
958      return Status;
959    }
960  }
961
962  if (Private->DevicePath != NULL) {
963    FreePool (Private->DevicePath);
964  }
965
966  Private->DevicePath = NewDevicePath;
967
968  gBS->RestoreTPL (Tpl);
969
970  return EFI_SUCCESS;
971}
972
973EFI_STATUS
974EFIAPI
975WinNtSerialIoSetControl (
976  IN EFI_SERIAL_IO_PROTOCOL *This,
977  IN UINT32                 Control
978  )
979/*++
980
981Routine Description:
982
983  TODO: Add function description
984
985Arguments:
986
987  This    - TODO: add argument description
988  Control - TODO: add argument description
989
990Returns:
991
992  EFI_DEVICE_ERROR - TODO: Add description for return value
993  EFI_DEVICE_ERROR - TODO: Add description for return value
994  EFI_SUCCESS - TODO: Add description for return value
995
996--*/
997{
998  WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
999  BOOL                          Result;
1000  DCB                           Dcb;
1001  EFI_TPL                       Tpl;
1002
1003  //
1004  // first determine the parameter is invalid
1005  //
1006  if (Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
1007                   EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
1008                   EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) {
1009    return EFI_UNSUPPORTED;
1010  }
1011
1012  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
1013
1014  Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1015
1016  Result  = Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb);
1017
1018  if (!Result) {
1019    Private->NtError = Private->WinNtThunk->GetLastError ();
1020    DEBUG ((EFI_D_ERROR, "SerialSetControl: GetCommState %d\n", Private->NtError));
1021    gBS->RestoreTPL (Tpl);
1022    return EFI_DEVICE_ERROR;
1023  }
1024
1025  Dcb.fRtsControl                 = RTS_CONTROL_DISABLE;
1026  Dcb.fDtrControl                 = DTR_CONTROL_DISABLE;
1027  Private->HardwareFlowControl    = FALSE;
1028  Private->SoftwareLoopbackEnable = FALSE;
1029  Private->HardwareLoopbackEnable = FALSE;
1030
1031  if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
1032    Dcb.fRtsControl = RTS_CONTROL_ENABLE;
1033  }
1034
1035  if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
1036    Dcb.fDtrControl = DTR_CONTROL_ENABLE;
1037  }
1038
1039  if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
1040    Private->HardwareFlowControl = TRUE;
1041  }
1042
1043  if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
1044    Private->SoftwareLoopbackEnable = TRUE;
1045  }
1046
1047  if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
1048    Private->HardwareLoopbackEnable = TRUE;
1049  }
1050
1051  Result = Private->WinNtThunk->SetCommState (
1052                                  Private->NtHandle,
1053                                  &Dcb
1054                                  );
1055
1056  if (!Result) {
1057    Private->NtError = Private->WinNtThunk->GetLastError ();
1058    DEBUG ((EFI_D_ERROR, "SerialSetControl: SetCommState %d\n", Private->NtError));
1059    gBS->RestoreTPL (Tpl);
1060    return EFI_DEVICE_ERROR;
1061  }
1062
1063  gBS->RestoreTPL (Tpl);
1064
1065  return EFI_SUCCESS;
1066}
1067
1068EFI_STATUS
1069EFIAPI
1070WinNtSerialIoGetControl (
1071  IN  EFI_SERIAL_IO_PROTOCOL  *This,
1072  OUT UINT32                  *Control
1073  )
1074/*++
1075
1076Routine Description:
1077
1078  TODO: Add function description
1079
1080Arguments:
1081
1082  This    - TODO: add argument description
1083  Control - TODO: add argument description
1084
1085Returns:
1086
1087  EFI_DEVICE_ERROR - TODO: Add description for return value
1088  EFI_DEVICE_ERROR - TODO: Add description for return value
1089  EFI_DEVICE_ERROR - TODO: Add description for return value
1090  EFI_SUCCESS - TODO: Add description for return value
1091
1092--*/
1093{
1094  WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1095  DWORD                         ModemStatus;
1096  DWORD                         Errors;
1097  UINT32                        Bits;
1098  DCB                           Dcb;
1099  EFI_TPL                       Tpl;
1100
1101  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
1102
1103  Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1104
1105  //
1106  //  Get modem status
1107  //
1108  if (!Private->WinNtThunk->GetCommModemStatus (Private->NtHandle, &ModemStatus)) {
1109    Private->NtError = Private->WinNtThunk->GetLastError ();
1110    gBS->RestoreTPL (Tpl);
1111    return EFI_DEVICE_ERROR;
1112  }
1113
1114  Bits = 0;
1115  if (ModemStatus & MS_CTS_ON) {
1116    Bits |= EFI_SERIAL_CLEAR_TO_SEND;
1117  }
1118
1119  if (ModemStatus & MS_DSR_ON) {
1120    Bits |= EFI_SERIAL_DATA_SET_READY;
1121  }
1122
1123  if (ModemStatus & MS_RING_ON) {
1124    Bits |= EFI_SERIAL_RING_INDICATE;
1125  }
1126
1127  if (ModemStatus & MS_RLSD_ON) {
1128    Bits |= EFI_SERIAL_CARRIER_DETECT;
1129  }
1130
1131  //
1132  // Get ctrl status
1133  //
1134  if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb)) {
1135    Private->NtError = Private->WinNtThunk->GetLastError ();
1136    DEBUG ((EFI_D_ERROR, "SerialGetControl: GetCommState %d\n", Private->NtError));
1137    gBS->RestoreTPL (Tpl);
1138    return EFI_DEVICE_ERROR;
1139  }
1140
1141  if (Dcb.fDtrControl == DTR_CONTROL_ENABLE) {
1142    Bits |= EFI_SERIAL_DATA_TERMINAL_READY;
1143  }
1144
1145  if (Dcb.fRtsControl == RTS_CONTROL_ENABLE) {
1146    Bits |= EFI_SERIAL_REQUEST_TO_SEND;
1147  }
1148
1149  if (Private->HardwareFlowControl) {
1150    Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1151  }
1152
1153  if (Private->SoftwareLoopbackEnable) {
1154    Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1155  }
1156
1157  if (Private->HardwareLoopbackEnable) {
1158    Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1159  }
1160
1161  //
1162  //  Get input buffer status
1163  //
1164  if (!Private->WinNtThunk->ClearCommError (Private->NtHandle, &Errors, &Private->NtComStatus)) {
1165    Private->NtError = Private->WinNtThunk->GetLastError ();
1166    DEBUG ((EFI_D_ERROR, "SerialGetControl: ClearCommError %d\n", Private->NtError));
1167    gBS->RestoreTPL (Tpl);
1168    return EFI_DEVICE_ERROR;
1169  }
1170
1171  if (Private->NtComStatus.cbInQue == 0) {
1172    Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1173  }
1174
1175  *Control = Bits;
1176
1177  gBS->RestoreTPL (Tpl);
1178
1179  return EFI_SUCCESS;
1180}
1181
1182EFI_STATUS
1183EFIAPI
1184WinNtSerialIoWrite (
1185  IN EFI_SERIAL_IO_PROTOCOL   *This,
1186  IN OUT UINTN                *BufferSize,
1187  IN VOID                     *Buffer
1188  )
1189/*++
1190
1191Routine Description:
1192
1193  TODO: Add function description
1194
1195Arguments:
1196
1197  This        - TODO: add argument description
1198  BufferSize  - TODO: add argument description
1199  Buffer      - TODO: add argument description
1200
1201Returns:
1202
1203  EFI_DEVICE_ERROR - TODO: Add description for return value
1204  EFI_SUCCESS - TODO: Add description for return value
1205
1206--*/
1207{
1208  WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1209  UINT8                         *ByteBuffer;
1210  UINTN                         TotalBytesWritten;
1211  DWORD                         BytesToGo;
1212  DWORD                         BytesWritten;
1213  BOOL                          Result;
1214  UINT32                        Index;
1215  UINT32                        Control;
1216  EFI_TPL                       Tpl;
1217
1218  Tpl               = gBS->RaiseTPL (TPL_NOTIFY);
1219
1220  Private           = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1221
1222  ByteBuffer        = (UINT8 *) Buffer;
1223  TotalBytesWritten = 0;
1224
1225  if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1226    for (Index = 0; Index < *BufferSize; Index++) {
1227      if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) {
1228        TotalBytesWritten++;
1229      } else {
1230        break;
1231      }
1232    }
1233  } else {
1234    BytesToGo = (DWORD) (*BufferSize);
1235
1236    do {
1237      if (Private->HardwareFlowControl) {
1238        //
1239        // Send RTS
1240        //
1241        WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1242        Control |= EFI_SERIAL_REQUEST_TO_SEND;
1243        WinNtSerialIoSetControl (&Private->SerialIo, Control);
1244      }
1245
1246      //
1247      //  Do the write
1248      //
1249      Result = Private->WinNtThunk->WriteFile (
1250                                      Private->NtHandle,
1251                                      &ByteBuffer[TotalBytesWritten],
1252                                      BytesToGo,
1253                                      &BytesWritten,
1254                                      NULL
1255                                      );
1256
1257      if (Private->HardwareFlowControl) {
1258        //
1259        // Assert RTS
1260        //
1261        WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1262        Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND;
1263        WinNtSerialIoSetControl (&Private->SerialIo, Control);
1264      }
1265
1266      TotalBytesWritten += BytesWritten;
1267      BytesToGo -= BytesWritten;
1268      if (!Result) {
1269        Private->NtError = Private->WinNtThunk->GetLastError ();
1270        DEBUG ((EFI_D_ERROR, "SerialWrite: FileWrite %d\n", Private->NtError));
1271        *BufferSize = TotalBytesWritten;
1272        gBS->RestoreTPL (Tpl);
1273        return EFI_DEVICE_ERROR;
1274      }
1275    } while (BytesToGo > 0);
1276  }
1277
1278  *BufferSize = TotalBytesWritten;
1279
1280  gBS->RestoreTPL (Tpl);
1281
1282  return EFI_SUCCESS;
1283}
1284
1285EFI_STATUS
1286EFIAPI
1287WinNtSerialIoRead (
1288  IN  EFI_SERIAL_IO_PROTOCOL  *This,
1289  IN  OUT UINTN               *BufferSize,
1290  OUT VOID                    *Buffer
1291  )
1292/*++
1293
1294Routine Description:
1295
1296  TODO: Add function description
1297
1298Arguments:
1299
1300  This        - TODO: add argument description
1301  BufferSize  - TODO: add argument description
1302  Buffer      - TODO: add argument description
1303
1304Returns:
1305
1306  EFI_DEVICE_ERROR - TODO: Add description for return value
1307
1308--*/
1309{
1310  WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1311  BOOL                          Result;
1312  DWORD                         BytesRead;
1313  EFI_STATUS                    Status;
1314  UINT32                        Index;
1315  UINT8                         Data;
1316  UINT32                        Control;
1317  EFI_TPL                       Tpl;
1318
1319  Tpl     = gBS->RaiseTPL (TPL_NOTIFY);
1320
1321  Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1322
1323  //
1324  //  Do the read
1325  //
1326  if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1327    for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) {
1328      if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) {
1329        ((UINT8 *) Buffer)[Index] = Data;
1330        BytesRead++;
1331      } else {
1332        break;
1333      }
1334    }
1335  } else {
1336    if (Private->HardwareFlowControl) {
1337      WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1338      Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1339      WinNtSerialIoSetControl (&Private->SerialIo, Control);
1340    }
1341
1342    Result = Private->WinNtThunk->ReadFile (
1343                                    Private->NtHandle,
1344                                    Buffer,
1345                                    (DWORD) *BufferSize,
1346                                    &BytesRead,
1347                                    NULL
1348                                    );
1349
1350    if (Private->HardwareFlowControl) {
1351      WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1352      Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY;
1353      WinNtSerialIoSetControl (&Private->SerialIo, Control);
1354    }
1355
1356    if (!Result) {
1357      Private->NtError = Private->WinNtThunk->GetLastError ();
1358      gBS->RestoreTPL (Tpl);
1359      return EFI_DEVICE_ERROR;
1360    }
1361  }
1362
1363  if (BytesRead != *BufferSize) {
1364    Status = EFI_TIMEOUT;
1365  } else {
1366    Status = EFI_SUCCESS;
1367  }
1368
1369  *BufferSize = (UINTN) BytesRead;
1370
1371  gBS->RestoreTPL (Tpl);
1372
1373  return Status;
1374}
1375
1376BOOLEAN
1377IsaSerialFifoFull (
1378  IN SERIAL_DEV_FIFO *Fifo
1379  )
1380/*++
1381
1382  Routine Description:
1383  Detect whether specific FIFO is full or not
1384
1385  Arguments:
1386  Fifo  SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1387
1388  Returns:
1389  TRUE:  the FIFO is full
1390  FALSE: the FIFO is not full
1391
1392--*/
1393{
1394  if (Fifo->Surplus == 0) {
1395    return TRUE;
1396  }
1397
1398  return FALSE;
1399}
1400
1401BOOLEAN
1402IsaSerialFifoEmpty (
1403  IN SERIAL_DEV_FIFO *Fifo
1404  )
1405/*++
1406
1407  Routine Description:
1408  Detect whether specific FIFO is empty or not
1409
1410  Arguments:
1411    Fifo  SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1412
1413  Returns:
1414    TRUE:  the FIFO is empty
1415    FALSE: the FIFO is not empty
1416
1417--*/
1418{
1419  if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
1420    return TRUE;
1421  }
1422
1423  return FALSE;
1424}
1425
1426EFI_STATUS
1427IsaSerialFifoAdd (
1428  IN SERIAL_DEV_FIFO *Fifo,
1429  IN UINT8           Data
1430  )
1431/*++
1432
1433  Routine Description:
1434  Add data to specific FIFO
1435
1436  Arguments:
1437    Fifo  SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1438    Data  UINT8: the data added to FIFO
1439
1440  Returns:
1441    EFI_SUCCESS:  Add data to specific FIFO successfully
1442    EFI_OUT_RESOURCE: Failed to add data because FIFO is already full
1443
1444--*/
1445// TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
1446{
1447  //
1448  // if FIFO full can not add data
1449  //
1450  if (IsaSerialFifoFull (Fifo)) {
1451    return EFI_OUT_OF_RESOURCES;
1452  }
1453
1454  //
1455  // FIFO is not full can add data
1456  //
1457  Fifo->Data[Fifo->Last] = Data;
1458  Fifo->Surplus--;
1459  Fifo->Last++;
1460  if (Fifo->Last >= SERIAL_MAX_BUFFER_SIZE) {
1461    Fifo->Last = 0;
1462  }
1463
1464  return EFI_SUCCESS;
1465}
1466
1467EFI_STATUS
1468IsaSerialFifoRemove (
1469  IN  SERIAL_DEV_FIFO *Fifo,
1470  OUT UINT8           *Data
1471  )
1472/*++
1473
1474  Routine Description:
1475  Remove data from specific FIFO
1476
1477  Arguments:
1478    Fifo  SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1479    Data  UINT8*: the data removed from FIFO
1480
1481  Returns:
1482    EFI_SUCCESS:  Remove data from specific FIFO successfully
1483    EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty
1484
1485--*/
1486// TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
1487{
1488  //
1489  // if FIFO is empty, no data can remove
1490  //
1491  if (IsaSerialFifoEmpty (Fifo)) {
1492    return EFI_OUT_OF_RESOURCES;
1493  }
1494
1495  //
1496  // FIFO is not empty, can remove data
1497  //
1498  *Data = Fifo->Data[Fifo->First];
1499  Fifo->Surplus++;
1500  Fifo->First++;
1501  if (Fifo->First >= SERIAL_MAX_BUFFER_SIZE) {
1502    Fifo->First = 0;
1503  }
1504
1505  return EFI_SUCCESS;
1506}
1507