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