]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/WinNtSerialIoDxe/WinNtSerialIo.c
bd7424738778688abc7b51154a3737d866a763ae
[mirror_edk2.git] / Nt32Pkg / WinNtSerialIoDxe / WinNtSerialIo.c
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
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
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
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
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
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
346 Error:
347 return Status;
348 }
349
350 EFI_STATUS
351 EFIAPI
352 WinNtSerialIoDriverBindingStart (
353 IN EFI_DRIVER_BINDING_PROTOCOL *This,
354 IN EFI_HANDLE Handle,
355 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
356 )
357 /*++
358
359 Routine Description:
360
361 Arguments:
362
363 Returns:
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
689 Error:
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
716 EFI_STATUS
717 EFIAPI
718 WinNtSerialIoDriverBindingStop (
719 IN EFI_DRIVER_BINDING_PROTOCOL *This,
720 IN EFI_HANDLE Handle,
721 IN UINTN NumberOfChildren,
722 IN EFI_HANDLE *ChildHandleBuffer
723 )
724 /*++
725
726 Routine Description:
727
728 TODO: Add function description
729
730 Arguments:
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
737 Returns:
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
843 EFI_STATUS
844 EFIAPI
845 WinNtSerialIoReset (
846 IN EFI_SERIAL_IO_PROTOCOL *This
847 )
848 /*++
849
850 Routine Description:
851
852 TODO: Add function description
853
854 Arguments:
855
856 This - TODO: add argument description
857
858 Returns:
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
889 EFI_STATUS
890 EFIAPI
891 WinNtSerialIoSetAttributes (
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
902 Routine Description:
903
904 This function is used to set the attributes.
905
906 Arguments:
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
916 Returns:
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
1142 EFI_STATUS
1143 EFIAPI
1144 WinNtSerialIoSetControl (
1145 IN EFI_SERIAL_IO_PROTOCOL *This,
1146 IN UINT32 Control
1147 )
1148 /*++
1149
1150 Routine Description:
1151
1152 TODO: Add function description
1153
1154 Arguments:
1155
1156 This - TODO: add argument description
1157 Control - TODO: add argument description
1158
1159 Returns:
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
1262 EFI_STATUS
1263 EFIAPI
1264 WinNtSerialIoGetControl (
1265 IN EFI_SERIAL_IO_PROTOCOL *This,
1266 OUT UINT32 *Control
1267 )
1268 /*++
1269
1270 Routine Description:
1271
1272 TODO: Add function description
1273
1274 Arguments:
1275
1276 This - TODO: add argument description
1277 Control - TODO: add argument description
1278
1279 Returns:
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
1376 EFI_STATUS
1377 EFIAPI
1378 WinNtSerialIoWrite (
1379 IN EFI_SERIAL_IO_PROTOCOL *This,
1380 IN OUT UINTN *BufferSize,
1381 IN VOID *Buffer
1382 )
1383 /*++
1384
1385 Routine Description:
1386
1387 TODO: Add function description
1388
1389 Arguments:
1390
1391 This - TODO: add argument description
1392 BufferSize - TODO: add argument description
1393 Buffer - TODO: add argument description
1394
1395 Returns:
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
1479 EFI_STATUS
1480 EFIAPI
1481 WinNtSerialIoRead (
1482 IN EFI_SERIAL_IO_PROTOCOL *This,
1483 IN OUT UINTN *BufferSize,
1484 OUT VOID *Buffer
1485 )
1486 /*++
1487
1488 Routine Description:
1489
1490 TODO: Add function description
1491
1492 Arguments:
1493
1494 This - TODO: add argument description
1495 BufferSize - TODO: add argument description
1496 Buffer - TODO: add argument description
1497
1498 Returns:
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
1570 BOOLEAN
1571 IsaSerialFifoFull (
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
1595 BOOLEAN
1596 IsaSerialFifoEmpty (
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
1620 EFI_STATUS
1621 IsaSerialFifoAdd (
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
1661 EFI_STATUS
1662 IsaSerialFifoRemove (
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 }