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