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