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