]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/UnixSerialIoDxe/UnixSerialIo.c
e41e74964fda7ee8e4ed670f60a8344e19d669d6
[mirror_edk2.git] / UnixPkg / UnixSerialIoDxe / UnixSerialIo.c
1 /*++
2
3 Copyright (c) 2006 - 2009, 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 UnixSerialIo.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) - UnixIo - 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 gEfiUnixSerialPortGuid 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) - UnixIo - DevicePath(1) - UnixSerialPort
34
35 If the driver is unloaded Handle(2) is removed from the system and
36 gEfiUnixSerialPortGuid 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 UnixIo protocol, a DevicePath protocol, and
41 the TypeGuid in the UnixIo must be gEfiUnixSerialPortGuid.
42
43 If Handle(1) contains a gEfiUnixSerialPortGuid protocol then the driver is
44 loaded on the device.
45
46 --*/
47
48 #include "UnixSerialIo.h"
49
50 EFI_DRIVER_BINDING_PROTOCOL gUnixSerialIoDriverBinding = {
51 UnixSerialIoDriverBindingSupported,
52 UnixSerialIoDriverBindingStart,
53 UnixSerialIoDriverBindingStop,
54 0xa,
55 NULL,
56 NULL
57 };
58
59 UINTN
60 ConvertBaud2Unix (
61 UINT64 BaudRate
62 )
63 {
64 switch (BaudRate) {
65 case 0:
66 return B0;
67 case 50:
68 return B50;
69 case 75:
70 return B75;
71 case 110:
72 return B110;
73 case 134:
74 return B134;
75 case 150:
76 return B150;
77 case 200:
78 return B200;
79 case 300:
80 return B300;
81 case 600:
82 return B600;
83 case 1200:
84 return B1200;
85 case 1800:
86 return B1800;
87 case 2400:
88 return B2400;
89 case 4800:
90 return B4800;
91 case 9600:
92 return B9600;
93 case 19200:
94 return B19200;
95 case 38400:
96 return B38400;
97 case 57600:
98 return B57600;
99 case 115200:
100 return B115200;
101 case 230400:
102 return B230400;
103 case 460800:
104 return B460800;
105 case 500000:
106 return B500000;
107 case 576000:
108 return B576000;
109 case 921600:
110 return B921600;
111 case 1000000:
112 return B1000000;
113 case 1152000:
114 return B1152000;
115 case 1500000:
116 return B1500000;
117 case 2000000:
118 return B2000000;
119 case 2500000:
120 return B2500000;
121 case 3000000:
122 return B3000000;
123 case 3500000:
124 return B3500000;
125 case 4000000:
126 return B4000000;
127 case __MAX_BAUD:
128 default:
129 DEBUG ((EFI_D_ERROR, "Invalid Baud Rate Parameter!\r\n"));
130 }
131 return -1;
132 }
133
134 UINTN
135 ConvertByteSize2Unix (
136 UINT8 DataBit
137 )
138 {
139 switch (DataBit) {
140 case 5:
141 return CS5;
142 case 6:
143 return CS6;
144 case 7:
145 return CS7;
146 case 8:
147 return CS8;
148 default:
149 DEBUG ((EFI_D_ERROR, "Invalid Data Size Parameter!\r\n"));
150 }
151 return -1;
152 }
153
154 VOID
155 ConvertParity2Unix (
156 struct termios *Options,
157 EFI_PARITY_TYPE Parity
158 )
159 {
160 switch (Parity) {
161 case NoParity:
162 Options->c_cflag &= ~PARENB;
163 break;
164 case EvenParity:
165 Options->c_cflag |= PARENB;
166 break;
167 case OddParity:
168 Options->c_cflag |= PARENB;
169 Options->c_cflag |= PARODD;
170 break;
171 case MarkParity:
172 Options->c_cflag = PARENB | CMSPAR | PARODD;
173 break;
174 case SpaceParity:
175 Options->c_cflag |= PARENB | CMSPAR;
176 Options->c_cflag &= ~PARODD;
177 break;
178 default:
179 DEBUG ((EFI_D_ERROR, "Invalid Parity Parameter!\r\n"));
180 }
181 }
182
183 VOID
184 ConvertStopBit2Unix (
185 struct termios *Options,
186 EFI_STOP_BITS_TYPE StopBits
187 )
188 {
189 switch (StopBits) {
190 case TwoStopBits:
191 Options->c_cflag |= CSTOPB;
192 break;
193 case OneStopBit:
194 case OneFiveStopBits:
195 case DefaultStopBits:
196 Options->c_cflag &= ~CSTOPB;
197 }
198 }
199
200 EFI_STATUS
201 EFIAPI
202 UnixSerialIoDriverBindingSupported (
203 IN EFI_DRIVER_BINDING_PROTOCOL *This,
204 IN EFI_HANDLE Handle,
205 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
206 )
207 /*++
208
209 Routine Description:
210 The implementation of EFI_DRIVER_BINDING_PROTOCOL.EFI_DRIVER_BINDING_SUPPORTED.
211
212 Arguments:
213
214 Returns:
215
216 None
217
218 --*/
219 {
220 EFI_STATUS Status;
221 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
222 EFI_UNIX_IO_PROTOCOL *UnixIo;
223 UART_DEVICE_PATH *UartNode;
224
225 //
226 // Check RemainingDevicePath validation
227 //
228 if (RemainingDevicePath != NULL) {
229 //
230 // Check if RemainingDevicePath is the End of Device Path Node,
231 // if yes, go on checking other conditions
232 //
233 if (!IsDevicePathEnd (RemainingDevicePath)) {
234 //
235 // If RemainingDevicePath isn't the End of Device Path Node,
236 // check its validation
237 //
238 Status = EFI_UNSUPPORTED;
239 UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
240 if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
241 UartNode->Header.SubType != MSG_UART_DP ||
242 DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) {
243 goto Error;
244 }
245 if (UartNode->BaudRate < 0 || UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
246 goto Error;
247 }
248 if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
249 goto Error;
250 }
251 if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
252 goto Error;
253 }
254 if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
255 goto Error;
256 }
257 if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
258 goto Error;
259 }
260 if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
261 goto Error;
262 }
263 }
264 }
265
266 //
267 // Open the IO Abstraction(s) needed to perform the supported test
268 //
269 Status = gBS->OpenProtocol (
270 Handle,
271 &gEfiUnixIoProtocolGuid,
272 (VOID**)&UnixIo,
273 This->DriverBindingHandle,
274 Handle,
275 EFI_OPEN_PROTOCOL_BY_DRIVER
276 );
277 if (Status == EFI_ALREADY_STARTED) {
278 return EFI_SUCCESS;
279 }
280
281 if (EFI_ERROR (Status)) {
282 return Status;
283 }
284
285 //
286 // Close the I/O Abstraction(s) used to perform the supported test
287 //
288 gBS->CloseProtocol (
289 Handle,
290 &gEfiUnixIoProtocolGuid,
291 This->DriverBindingHandle,
292 Handle
293 );
294
295 //
296 // Open the EFI Device Path protocol needed to perform the supported test
297 //
298 Status = gBS->OpenProtocol (
299 Handle,
300 &gEfiDevicePathProtocolGuid,
301 (VOID**)&ParentDevicePath,
302 This->DriverBindingHandle,
303 Handle,
304 EFI_OPEN_PROTOCOL_BY_DRIVER
305 );
306 if (Status == EFI_ALREADY_STARTED) {
307 return EFI_SUCCESS;
308 }
309
310 if (EFI_ERROR (Status)) {
311 return Status;
312 }
313
314 //
315 // Close protocol, don't use device path protocol in the Support() function
316 //
317 gBS->CloseProtocol (
318 Handle,
319 &gEfiDevicePathProtocolGuid,
320 This->DriverBindingHandle,
321 Handle
322 );
323
324 //
325 // Make sure that the Unix Thunk Protocol is valid
326 //
327 if (UnixIo->UnixThunk->Signature != EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) {
328 Status = EFI_UNSUPPORTED;
329 goto Error;
330 }
331
332 //
333 // Check the GUID to see if this is a handle type the driver supports
334 //
335 if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixSerialPortGuid)) {
336 Status = EFI_UNSUPPORTED;
337 goto Error;
338 }
339
340 return EFI_SUCCESS;
341
342 Error:
343 return Status;
344 }
345
346 EFI_STATUS
347 EFIAPI
348 UnixSerialIoDriverBindingStart (
349 IN EFI_DRIVER_BINDING_PROTOCOL *This,
350 IN EFI_HANDLE Handle,
351 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
352 )
353 /*++
354
355 Routine Description:
356
357 Arguments:
358
359 Returns:
360
361 None
362
363 --*/
364 {
365 EFI_STATUS Status;
366 EFI_UNIX_IO_PROTOCOL *UnixIo;
367 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
368 UINTN UnixHandle;
369 UART_DEVICE_PATH Node;
370 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
371 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
372 UINTN EntryCount;
373 UINTN Index;
374 EFI_SERIAL_IO_PROTOCOL *SerialIo;
375 CHAR8 AsciiDevName[1024];
376 UART_DEVICE_PATH *UartNode;
377
378 DEBUG ((EFI_D_INFO, "SerialIo drive binding start!\r\n"));
379 Private = NULL;
380 UnixHandle = -1;
381
382 //
383 // Grab the protocols we need
384 //
385 Status = gBS->OpenProtocol (
386 Handle,
387 &gEfiDevicePathProtocolGuid,
388 (VOID**)&ParentDevicePath,
389 This->DriverBindingHandle,
390 Handle,
391 EFI_OPEN_PROTOCOL_BY_DRIVER
392 );
393 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
394 return Status;
395 }
396
397 //
398 // Grab the IO abstraction we need to get any work done
399 //
400 Status = gBS->OpenProtocol (
401 Handle,
402 &gEfiUnixIoProtocolGuid,
403 (VOID**)&UnixIo,
404 This->DriverBindingHandle,
405 Handle,
406 EFI_OPEN_PROTOCOL_BY_DRIVER
407 );
408 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
409 gBS->CloseProtocol (
410 Handle,
411 &gEfiDevicePathProtocolGuid,
412 This->DriverBindingHandle,
413 Handle
414 );
415 return Status;
416 }
417
418 if (Status == EFI_ALREADY_STARTED) {
419
420 if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
421 //
422 // If RemainingDevicePath is NULL or is the End of Device Path Node
423 //
424 return EFI_SUCCESS;
425 }
426
427 //
428 // Make sure a child handle does not already exist. This driver can only
429 // produce one child per serial port.
430 //
431 Status = gBS->OpenProtocolInformation (
432 Handle,
433 &gEfiUnixIoProtocolGuid,
434 &OpenInfoBuffer,
435 &EntryCount
436 );
437 if (EFI_ERROR (Status)) {
438 return Status;
439 }
440
441 Status = EFI_ALREADY_STARTED;
442 for (Index = 0; Index < EntryCount; Index++) {
443 if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
444 Status = gBS->OpenProtocol (
445 OpenInfoBuffer[Index].ControllerHandle,
446 &gEfiSerialIoProtocolGuid,
447 (VOID**)&SerialIo,
448 This->DriverBindingHandle,
449 Handle,
450 EFI_OPEN_PROTOCOL_GET_PROTOCOL
451 );
452 if (!EFI_ERROR (Status)) {
453 UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
454 Status = SerialIo->SetAttributes (
455 SerialIo,
456 UartNode->BaudRate,
457 SerialIo->Mode->ReceiveFifoDepth,
458 SerialIo->Mode->Timeout,
459 UartNode->Parity,
460 UartNode->DataBits,
461 UartNode->StopBits
462 );
463 }
464 break;
465 }
466 }
467
468 FreePool (OpenInfoBuffer);
469 return Status;
470 }
471
472 if (RemainingDevicePath == NULL) {
473 //
474 // Build the device path by appending the UART node to the ParentDevicePath
475 // from the UnixIo handle. The Uart setings are zero here, since
476 // SetAttribute() will update them to match the default setings.
477 //
478 ZeroMem (&Node, sizeof (UART_DEVICE_PATH));
479 Node.Header.Type = MESSAGING_DEVICE_PATH;
480 Node.Header.SubType = MSG_UART_DP;
481 SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &Node, sizeof (UART_DEVICE_PATH));
482
483 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
484 //
485 // If RemainingDevicePath isn't the End of Device Path Node,
486 // only scan the specified device by RemainingDevicePath
487 //
488 //
489 // Match the configuration of the RemainingDevicePath. IsHandleSupported()
490 // already checked to make sure the RemainingDevicePath contains settings
491 // that we can support.
492 //
493 CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
494
495 } else {
496 //
497 // If RemainingDevicePath is the End of Device Path Node,
498 // skip enumerate any device and return EFI_SUCESSS
499 //
500 return EFI_SUCCESS;
501 }
502
503 //
504 // Check to see if we can access the hardware device. If it's Open in Unix we
505 // will not get access.
506 //
507 UnicodeStrToAsciiStr(UnixIo->EnvString, AsciiDevName);
508 UnixHandle = UnixIo->UnixThunk->Open (AsciiDevName, O_RDWR | O_NOCTTY, 0);
509
510 if (UnixHandle == -1) {
511 DEBUG ((EFI_D_INFO, "Failed to open serial device, %s!\r\n", UnixIo->EnvString ));
512 UnixIo->UnixThunk->Perror (AsciiDevName);
513 Status = EFI_DEVICE_ERROR;
514 goto Error;
515 }
516 DEBUG ((EFI_D_INFO, "Success to open serial device %s, Hanle = 0x%x \r\n", UnixIo->EnvString, UnixHandle));
517
518 //
519 // Construct Private data
520 //
521 Private = AllocatePool (sizeof (UNIX_SERIAL_IO_PRIVATE_DATA));
522 if (Private == NULL) {
523 goto Error;
524 }
525
526 //
527 // This signature must be valid before any member function is called
528 //
529 Private->Signature = UNIX_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
530 Private->UnixHandle = UnixHandle;
531 Private->ControllerHandle = Handle;
532 Private->Handle = NULL;
533 Private->UnixThunk = UnixIo->UnixThunk;
534 Private->ParentDevicePath = ParentDevicePath;
535 Private->ControllerNameTable = NULL;
536
537 Private->SoftwareLoopbackEnable = FALSE;
538 Private->HardwareLoopbackEnable = FALSE;
539 Private->HardwareFlowControl = FALSE;
540 Private->Fifo.First = 0;
541 Private->Fifo.Last = 0;
542 Private->Fifo.Surplus = SERIAL_MAX_BUFFER_SIZE;
543
544 CopyMem (&Private->UartDevicePath, &Node, sizeof (UART_DEVICE_PATH));
545
546 AddUnicodeString (
547 "eng",
548 gUnixSerialIoComponentName.SupportedLanguages,
549 &Private->ControllerNameTable,
550 UnixIo->EnvString
551 );
552
553 Private->SerialIo.Revision = SERIAL_IO_INTERFACE_REVISION;
554 Private->SerialIo.Reset = UnixSerialIoReset;
555 Private->SerialIo.SetAttributes = UnixSerialIoSetAttributes;
556 Private->SerialIo.SetControl = UnixSerialIoSetControl;
557 Private->SerialIo.GetControl = UnixSerialIoGetControl;
558 Private->SerialIo.Write = UnixSerialIoWrite;
559 Private->SerialIo.Read = UnixSerialIoRead;
560 Private->SerialIo.Mode = &Private->SerialIoMode;
561
562
563
564 //
565 // Build the device path by appending the UART node to the ParentDevicePath
566 // from the UnixIo handle. The Uart setings are zero here, since
567 // SetAttribute() will update them to match the current setings.
568 //
569 Private->DevicePath = AppendDevicePathNode (
570 ParentDevicePath,
571 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
572 );
573 if (Private->DevicePath == NULL) {
574 Status = EFI_OUT_OF_RESOURCES;
575 goto Error;
576 }
577
578 //
579 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
580 //
581 Private->SerialIoMode.ControlMask = SERIAL_CONTROL_MASK;
582 Private->SerialIoMode.Timeout = SERIAL_TIMEOUT_DEFAULT;
583 Private->SerialIoMode.BaudRate = Private->UartDevicePath.BaudRate;
584 Private->SerialIoMode.ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
585 Private->SerialIoMode.DataBits = Private->UartDevicePath.DataBits;
586 Private->SerialIoMode.Parity = Private->UartDevicePath.Parity;
587 Private->SerialIoMode.StopBits = Private->UartDevicePath.StopBits;
588
589 //
590 // Issue a reset to initialize the COM port
591 //
592 Status = Private->SerialIo.Reset (&Private->SerialIo);
593 if (EFI_ERROR (Status)) {
594 goto Error;
595 }
596
597 //
598 // Create new child handle
599 //
600 Status = gBS->InstallMultipleProtocolInterfaces (
601 &Private->Handle,
602 &gEfiSerialIoProtocolGuid,
603 &Private->SerialIo,
604 &gEfiDevicePathProtocolGuid,
605 Private->DevicePath,
606 NULL
607 );
608 if (EFI_ERROR (Status)) {
609 goto Error;
610 }
611
612 //
613 // Open For Child Device
614 //
615 Status = gBS->OpenProtocol (
616 Handle,
617 &gEfiUnixIoProtocolGuid,
618 (VOID**)&UnixIo,
619 This->DriverBindingHandle,
620 Private->Handle,
621 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
622 );
623 if (EFI_ERROR (Status)) {
624 goto Error;
625 }
626
627 return EFI_SUCCESS;
628
629 Error:
630 //
631 // Use the Stop() function to free all resources allocated in Start()
632 //
633 if (Private != NULL) {
634 if (Private->Handle != NULL) {
635 This->Stop (This, Handle, 1, &Private->Handle);
636 } else {
637 if (UnixHandle != -1) {
638 Private->UnixThunk->Close (UnixHandle);
639 }
640
641 if (Private->DevicePath != NULL) {
642 FreePool (Private->DevicePath);
643 }
644
645 FreeUnicodeStringTable (Private->ControllerNameTable);
646
647 FreePool (Private);
648 }
649 }
650
651 This->Stop (This, Handle, 0, NULL);
652
653 return Status;
654 }
655
656 EFI_STATUS
657 EFIAPI
658 UnixSerialIoDriverBindingStop (
659 IN EFI_DRIVER_BINDING_PROTOCOL *This,
660 IN EFI_HANDLE Handle,
661 IN UINTN NumberOfChildren,
662 IN EFI_HANDLE *ChildHandleBuffer
663 )
664 /*++
665
666 Routine Description:
667
668 TODO: Add function description
669
670 Arguments:
671
672 This - TODO: add argument description
673 Handle - TODO: add argument description
674 NumberOfChildren - TODO: add argument description
675 ChildHandleBuffer - TODO: add argument description
676
677 Returns:
678
679 EFI_DEVICE_ERROR - TODO: Add description for return value
680 EFI_SUCCESS - TODO: Add description for return value
681
682 --*/
683 {
684 EFI_STATUS Status;
685 UINTN Index;
686 BOOLEAN AllChildrenStopped;
687 EFI_SERIAL_IO_PROTOCOL *SerialIo;
688 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
689 EFI_UNIX_IO_PROTOCOL *UnixIo;
690
691 //
692 // Complete all outstanding transactions to Controller.
693 // Don't allow any new transaction to Controller to be started.
694 //
695
696 if (NumberOfChildren == 0) {
697 //
698 // Close the bus driver
699 //
700 Status = gBS->CloseProtocol (
701 Handle,
702 &gEfiUnixIoProtocolGuid,
703 This->DriverBindingHandle,
704 Handle
705 );
706 Status = gBS->CloseProtocol (
707 Handle,
708 &gEfiDevicePathProtocolGuid,
709 This->DriverBindingHandle,
710 Handle
711 );
712 return Status;
713 }
714
715 AllChildrenStopped = TRUE;
716
717 for (Index = 0; Index < NumberOfChildren; Index++) {
718 Status = gBS->OpenProtocol (
719 ChildHandleBuffer[Index],
720 &gEfiSerialIoProtocolGuid,
721 (VOID**)&SerialIo,
722 This->DriverBindingHandle,
723 Handle,
724 EFI_OPEN_PROTOCOL_GET_PROTOCOL
725 );
726 if (!EFI_ERROR (Status)) {
727 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo);
728
729 ASSERT (Private->Handle == ChildHandleBuffer[Index]);
730
731 Status = gBS->CloseProtocol (
732 Handle,
733 &gEfiUnixIoProtocolGuid,
734 This->DriverBindingHandle,
735 ChildHandleBuffer[Index]
736 );
737
738 Status = gBS->UninstallMultipleProtocolInterfaces (
739 ChildHandleBuffer[Index],
740 &gEfiSerialIoProtocolGuid,
741 &Private->SerialIo,
742 &gEfiDevicePathProtocolGuid,
743 Private->DevicePath,
744 NULL
745 );
746
747 if (EFI_ERROR (Status)) {
748 gBS->OpenProtocol (
749 Handle,
750 &gEfiUnixIoProtocolGuid,
751 (VOID **) &UnixIo,
752 This->DriverBindingHandle,
753 ChildHandleBuffer[Index],
754 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
755 );
756 } else {
757 Private->UnixThunk->Close (Private->UnixHandle);
758
759 FreePool (Private->DevicePath);
760
761 FreeUnicodeStringTable (Private->ControllerNameTable);
762
763 FreePool (Private);
764 }
765 }
766
767 if (EFI_ERROR (Status)) {
768 AllChildrenStopped = FALSE;
769 }
770 }
771
772 if (!AllChildrenStopped) {
773 return EFI_DEVICE_ERROR;
774 }
775
776 return EFI_SUCCESS;
777 }
778
779 //
780 // Serial IO Protocol member functions
781 //
782
783 EFI_STATUS
784 EFIAPI
785 UnixSerialIoReset (
786 IN EFI_SERIAL_IO_PROTOCOL *This
787 )
788 /*++
789
790 Routine Description:
791
792 TODO: Add function description
793
794 Arguments:
795
796 This - TODO: add argument description
797
798 Returns:
799
800 TODO: add return values
801
802 --*/
803 {
804 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
805 EFI_TPL Tpl;
806 UINTN UnixStatus;
807
808 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
809
810 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
811
812 UnixStatus = Private->UnixThunk->Tcflush (
813 Private->UnixHandle,
814 TCIOFLUSH
815 );
816 switch (UnixStatus) {
817 case EBADF:
818 DEBUG ((EFI_D_ERROR, "Invalid handle of serial device!\r\n"));
819 return EFI_DEVICE_ERROR;
820 case EINVAL:
821 DEBUG ((EFI_D_ERROR, "Invalid queue selector!\r\n"));
822 return EFI_DEVICE_ERROR;
823 case ENOTTY:
824 DEBUG ((EFI_D_ERROR, "The file associated with serial's handle is not a terminal!\r\n"));
825 return EFI_DEVICE_ERROR;
826 default:
827 DEBUG ((EFI_D_ERROR, "The serial IO device is reset successfully!\r\n"));
828 }
829
830 gBS->RestoreTPL (Tpl);
831
832 return This->SetAttributes (
833 This,
834 This->Mode->BaudRate,
835 This->Mode->ReceiveFifoDepth,
836 This->Mode->Timeout,
837 This->Mode->Parity,
838 (UINT8) This->Mode->DataBits,
839 This->Mode->StopBits
840 );
841 }
842
843 EFI_STATUS
844 EFIAPI
845 UnixSerialIoSetAttributes (
846 IN EFI_SERIAL_IO_PROTOCOL *This,
847 IN UINT64 BaudRate,
848 IN UINT32 ReceiveFifoDepth,
849 IN UINT32 Timeout,
850 IN EFI_PARITY_TYPE Parity,
851 IN UINT8 DataBits,
852 IN EFI_STOP_BITS_TYPE StopBits
853 )
854 /*++
855
856 Routine Description:
857
858 This function is used to set the attributes.
859
860 Arguments:
861
862 This - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue.
863 BaudRate - The Baud rate of the serial device.
864 ReceiveFifoDepth - The request depth of fifo on receive side.
865 Timeout - the request timeout for a single charact.
866 Parity - The type of parity used in serial device.
867 DataBits - Number of deata bits used in serial device.
868 StopBits - Number of stop bits used in serial device.
869
870 Returns:
871 Status code
872
873 None
874
875 --*/
876 {
877 EFI_STATUS Status;
878 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
879 EFI_TPL Tpl;
880 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
881
882 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
883 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
884
885 //
886 // Some of our arguments have defaults if a null value is passed in, and
887 // we must set the default values if a null argument is passed in.
888 //
889 if (BaudRate == 0) {
890 BaudRate = SERIAL_BAUD_DEFAULT;
891 }
892
893 if (ReceiveFifoDepth == 0) {
894 ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
895 }
896
897 if (Timeout == 0) {
898 Timeout = SERIAL_TIMEOUT_DEFAULT;
899 }
900
901 if (Parity == DefaultParity) {
902 Parity = NoParity;
903 }
904
905 if (DataBits == 0) {
906 DataBits = SERIAL_DATABITS_DEFAULT;
907 }
908
909 if (StopBits == DefaultStopBits) {
910 StopBits = OneStopBit;
911 }
912
913 //
914 // See if the new attributes already match the current attributes
915 //
916 if (Private->UartDevicePath.BaudRate == BaudRate &&
917 Private->UartDevicePath.DataBits == DataBits &&
918 Private->UartDevicePath.Parity == Parity &&
919 Private->UartDevicePath.StopBits == StopBits &&
920 Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth &&
921 Private->SerialIoMode.Timeout == Timeout ) {
922 gBS->RestoreTPL(Tpl);
923 return EFI_SUCCESS;
924 }
925
926 //
927 // Try to get options from serial device.
928 //
929 if (Private->UnixThunk->Tcgetattr (Private->UnixHandle, &Private->UnixTermios) == -1) {
930 Private->UnixThunk->Perror ("IoSetAttributes");
931 gBS->RestoreTPL (Tpl);
932 return EFI_DEVICE_ERROR;
933 }
934
935 //
936 // Setting Baud Rate
937 //
938 Private->UnixThunk->Cfsetispeed (&Private->UnixTermios, ConvertBaud2Unix(BaudRate));
939 Private->UnixThunk->Cfsetospeed (&Private->UnixTermios, ConvertBaud2Unix(BaudRate));
940 //
941 // Setting DataBits
942 //
943 Private->UnixTermios.c_cflag &= ~CSIZE;
944 Private->UnixTermios.c_cflag |= ConvertByteSize2Unix (DataBits);
945 //
946 // Setting Parity
947 //
948 ConvertParity2Unix (&Private->UnixTermios, Parity);
949 //
950 // Setting StopBits
951 //
952 ConvertStopBit2Unix (&Private->UnixTermios, StopBits);
953 //
954 // Raw input
955 //
956 Private->UnixTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
957 //
958 // Raw output
959 //
960 Private->UnixTermios.c_oflag &= ~OPOST;
961 //
962 // Support hardware flow control
963 //
964 Private->UnixTermios.c_cflag &= ~CRTSCTS;;
965 //
966 // Time out
967 //
968 Private->UnixTermios.c_cc[VMIN] = 0;
969 Private->UnixTermios.c_cc[VTIME] = (Timeout/1000000) * 10;
970
971 //
972 // Set the options
973 //
974 if (-1 == Private->UnixThunk->Tcsetattr (
975 Private->UnixHandle,
976 TCSANOW,
977 &Private->UnixTermios
978 )) {
979 DEBUG ((EFI_D_INFO, "Fail to set options for serial device!\r\n"));
980 return EFI_DEVICE_ERROR;
981 }
982
983 //
984 // Update mode
985 //
986 Private->SerialIoMode.BaudRate = BaudRate;
987 Private->SerialIoMode.ReceiveFifoDepth = ReceiveFifoDepth;
988 Private->SerialIoMode.Timeout = Timeout;
989 Private->SerialIoMode.Parity = Parity;
990 Private->SerialIoMode.DataBits = DataBits;
991 Private->SerialIoMode.StopBits = StopBits;
992 //
993 // See if Device Path Node has actually changed
994 //
995 if (Private->UartDevicePath.BaudRate == BaudRate &&
996 Private->UartDevicePath.DataBits == DataBits &&
997 Private->UartDevicePath.Parity == Parity &&
998 Private->UartDevicePath.StopBits == StopBits ) {
999 gBS->RestoreTPL(Tpl);
1000 return EFI_SUCCESS;
1001 }
1002
1003 //
1004 // Update the device path
1005 //
1006 Private->UartDevicePath.BaudRate = BaudRate;
1007 Private->UartDevicePath.DataBits = DataBits;
1008 Private->UartDevicePath.Parity = (UINT8) Parity;
1009 Private->UartDevicePath.StopBits = (UINT8) StopBits;
1010
1011 NewDevicePath = AppendDevicePathNode (
1012 Private->ParentDevicePath,
1013 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
1014 );
1015 if (NewDevicePath == NULL) {
1016 gBS->RestoreTPL (Tpl);
1017 return EFI_DEVICE_ERROR;
1018 }
1019
1020 if (Private->Handle != NULL) {
1021 Status = gBS->ReinstallProtocolInterface (
1022 Private->Handle,
1023 &gEfiDevicePathProtocolGuid,
1024 Private->DevicePath,
1025 NewDevicePath
1026 );
1027 if (EFI_ERROR (Status)) {
1028 gBS->RestoreTPL (Tpl);
1029 return Status;
1030 }
1031 }
1032
1033 if (Private->DevicePath != NULL) {
1034 FreePool (Private->DevicePath);
1035 }
1036
1037 Private->DevicePath = NewDevicePath;
1038
1039 gBS->RestoreTPL (Tpl);
1040
1041 return EFI_SUCCESS;
1042 }
1043
1044 EFI_STATUS
1045 EFIAPI
1046 UnixSerialIoSetControl (
1047 IN EFI_SERIAL_IO_PROTOCOL *This,
1048 IN UINT32 Control
1049 )
1050 /*++
1051
1052 Routine Description:
1053
1054 TODO: Add function description
1055
1056 Arguments:
1057
1058 This - TODO: add argument description
1059 Control - TODO: add argument description
1060
1061 Returns:
1062
1063 EFI_DEVICE_ERROR - TODO: Add description for return value
1064 EFI_DEVICE_ERROR - TODO: Add description for return value
1065 EFI_SUCCESS - TODO: Add description for return value
1066
1067 --*/
1068 {
1069 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1070 UINTN Result;
1071 UINTN Status;
1072 struct termios Options;
1073 EFI_TPL Tpl;
1074
1075 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1076
1077 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1078
1079 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMGET, &Status);
1080
1081 if (Result == -1) {
1082 Private->UnixThunk->Perror ("SerialSetControl");
1083 gBS->RestoreTPL (Tpl);
1084 return EFI_DEVICE_ERROR;
1085 }
1086
1087 Private->HardwareFlowControl = FALSE;
1088 Private->SoftwareLoopbackEnable = FALSE;
1089 Private->HardwareLoopbackEnable = FALSE;
1090
1091 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
1092 Options.c_cflag |= TIOCM_RTS;
1093 }
1094
1095 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
1096 Options.c_cflag |= TIOCM_DTR;
1097 }
1098
1099 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
1100 Private->HardwareFlowControl = TRUE;
1101 }
1102
1103 if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
1104 Private->SoftwareLoopbackEnable = TRUE;
1105 }
1106
1107 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
1108 Private->HardwareLoopbackEnable = TRUE;
1109 }
1110
1111 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMSET, &Status);
1112
1113 if (Result == -1) {
1114 Private->UnixThunk->Perror ("SerialSetControl");
1115 gBS->RestoreTPL (Tpl);
1116 return EFI_DEVICE_ERROR;
1117 }
1118
1119 gBS->RestoreTPL (Tpl);
1120
1121 return EFI_SUCCESS;
1122 }
1123
1124 EFI_STATUS
1125 EFIAPI
1126 UnixSerialIoGetControl (
1127 IN EFI_SERIAL_IO_PROTOCOL *This,
1128 OUT UINT32 *Control
1129 )
1130 /*++
1131
1132 Routine Description:
1133
1134 TODO: Add function description
1135
1136 Arguments:
1137
1138 This - TODO: add argument description
1139 Control - TODO: add argument description
1140
1141 Returns:
1142
1143 EFI_DEVICE_ERROR - TODO: Add description for return value
1144 EFI_DEVICE_ERROR - TODO: Add description for return value
1145 EFI_DEVICE_ERROR - TODO: Add description for return value
1146 EFI_SUCCESS - TODO: Add description for return value
1147
1148 --*/
1149 {
1150 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1151 UINTN Result;
1152 UINTN Status;
1153 UINT32 Bits;
1154 EFI_TPL Tpl;
1155 UINTN Bytes;
1156
1157 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1158
1159 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1160 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMGET, &Status);
1161 if (Result == -1) {
1162 Private->UnixThunk->Perror ("SerialGetControl");
1163 gBS->RestoreTPL (Tpl);
1164 return EFI_DEVICE_ERROR;
1165 }
1166
1167 Bits = 0;
1168 if ((Status & TIOCM_CTS) == TIOCM_CTS) {
1169 Bits |= EFI_SERIAL_CLEAR_TO_SEND;
1170 }
1171
1172 if ((Status & TIOCM_DSR) == TIOCM_DSR) {
1173 Bits |= EFI_SERIAL_DATA_SET_READY;
1174 }
1175
1176 if ((Status & TIOCM_DTR) == TIOCM_DTR) {
1177 Bits |= EFI_SERIAL_DATA_TERMINAL_READY;
1178 }
1179
1180 if ((Status & TIOCM_RTS) == TIOCM_RTS) {
1181 Bits |= EFI_SERIAL_REQUEST_TO_SEND;
1182 }
1183
1184 if ((Status & TIOCM_RNG) == TIOCM_RNG) {
1185 Bits |= EFI_SERIAL_RING_INDICATE;
1186 }
1187
1188 if ((Status & TIOCM_CAR) == TIOCM_CAR) {
1189 Bits |= EFI_SERIAL_CARRIER_DETECT;
1190 }
1191
1192 if (Private->HardwareFlowControl) {
1193 Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1194 }
1195
1196 if (Private->SoftwareLoopbackEnable) {
1197 Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1198 }
1199
1200 if (Private->HardwareLoopbackEnable) {
1201 Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1202 }
1203
1204 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, FIONREAD, &Bytes);
1205 if (Result == -1) {
1206 Private->UnixThunk->Perror ("SerialGetControl");
1207 gBS->RestoreTPL (Tpl);
1208 return EFI_DEVICE_ERROR;
1209 }
1210
1211 if (Bytes == 0) {
1212 Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1213 }
1214
1215 *Control = Bits;
1216
1217 gBS->RestoreTPL (Tpl);
1218
1219 return EFI_SUCCESS;
1220 }
1221
1222 EFI_STATUS
1223 EFIAPI
1224 UnixSerialIoWrite (
1225 IN EFI_SERIAL_IO_PROTOCOL *This,
1226 IN OUT UINTN *BufferSize,
1227 IN 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 EFI_SUCCESS - TODO: Add description for return value
1245
1246 --*/
1247 {
1248 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1249 EFI_STATUS Status;
1250 UINT8 *ByteBuffer;
1251 UINT32 TotalBytesWritten;
1252 UINT32 BytesToGo;
1253 UINT32 BytesWritten;
1254 UINT32 Index;
1255 UINT32 Control;
1256 EFI_TPL Tpl;
1257
1258 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1259
1260 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1261
1262 ByteBuffer = (UINT8 *) Buffer;
1263 Status = EFI_SUCCESS;
1264 TotalBytesWritten = 0;
1265
1266 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1267 for (Index = 0; Index < *BufferSize; Index++) {
1268 if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) {
1269 TotalBytesWritten++;
1270 } else {
1271 break;
1272 }
1273 }
1274 } else {
1275 BytesToGo = (*BufferSize);
1276
1277 do {
1278 if (Private->HardwareFlowControl) {
1279 //
1280 // Send RTS
1281 //
1282 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1283 Control |= EFI_SERIAL_REQUEST_TO_SEND;
1284 UnixSerialIoSetControl (&Private->SerialIo, Control);
1285 }
1286
1287 //
1288 // Do the write
1289 //
1290 BytesWritten = Private->UnixThunk->Write (
1291 Private->UnixHandle,
1292 &ByteBuffer[TotalBytesWritten],
1293 BytesToGo
1294 );
1295 if (BytesWritten == -1) {
1296 Status = EFI_DEVICE_ERROR;
1297 break;
1298 }
1299
1300 if (Private->HardwareFlowControl) {
1301 //
1302 // Assert RTS
1303 //
1304 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1305 Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND;
1306 UnixSerialIoSetControl (&Private->SerialIo, Control);
1307 }
1308
1309 TotalBytesWritten += BytesWritten;
1310 BytesToGo -= BytesWritten;
1311 } while (BytesToGo > 0);
1312 }
1313
1314 *BufferSize = TotalBytesWritten;
1315
1316 gBS->RestoreTPL (Tpl);
1317
1318 return Status;
1319 }
1320
1321 EFI_STATUS
1322 EFIAPI
1323 UnixSerialIoRead (
1324 IN EFI_SERIAL_IO_PROTOCOL *This,
1325 IN OUT UINTN *BufferSize,
1326 OUT VOID *Buffer
1327 )
1328 /*++
1329
1330 Routine Description:
1331
1332 TODO: Add function description
1333
1334 Arguments:
1335
1336 This - TODO: add argument description
1337 BufferSize - TODO: add argument description
1338 Buffer - TODO: add argument description
1339
1340 Returns:
1341
1342 EFI_DEVICE_ERROR - TODO: Add description for return value
1343
1344 --*/
1345 {
1346 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1347 UINT32 BytesRead;
1348 EFI_STATUS Status;
1349 UINT32 Index;
1350 UINT8 Data;
1351 UINT32 Control;
1352 EFI_TPL Tpl;
1353
1354 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1355
1356 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1357
1358 //
1359 // Do the read
1360 //
1361 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1362 for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) {
1363 if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) {
1364 ((UINT8 *) Buffer)[Index] = Data;
1365 BytesRead++;
1366 } else {
1367 break;
1368 }
1369 }
1370 } else {
1371 if (Private->HardwareFlowControl) {
1372 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1373 Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1374 UnixSerialIoSetControl (&Private->SerialIo, Control);
1375 }
1376
1377 BytesRead = Private->UnixThunk->Read (Private->UnixHandle, Buffer, *BufferSize);
1378 if (Private->HardwareFlowControl) {
1379 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1380 Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY;
1381 UnixSerialIoSetControl (&Private->SerialIo, Control);
1382 }
1383
1384 }
1385
1386 if (BytesRead != *BufferSize) {
1387 Status = EFI_TIMEOUT;
1388 } else {
1389 Status = EFI_SUCCESS;
1390 }
1391
1392 *BufferSize = (UINTN) BytesRead;
1393
1394 gBS->RestoreTPL (Tpl);
1395
1396 return Status;
1397 }
1398
1399 BOOLEAN
1400 IsaSerialFifoFull (
1401 IN SERIAL_DEV_FIFO *Fifo
1402 )
1403 /*++
1404
1405 Routine Description:
1406 Detect whether specific FIFO is full or not
1407
1408 Arguments:
1409 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1410
1411 Returns:
1412 TRUE: the FIFO is full
1413 FALSE: the FIFO is not full
1414
1415 --*/
1416 {
1417 if (Fifo->Surplus == 0) {
1418 return TRUE;
1419 }
1420
1421 return FALSE;
1422 }
1423
1424 BOOLEAN
1425 IsaSerialFifoEmpty (
1426 IN SERIAL_DEV_FIFO *Fifo
1427 )
1428 /*++
1429
1430 Routine Description:
1431 Detect whether specific FIFO is empty or not
1432
1433 Arguments:
1434 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1435
1436 Returns:
1437 TRUE: the FIFO is empty
1438 FALSE: the FIFO is not empty
1439
1440 --*/
1441 {
1442 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
1443 return TRUE;
1444 }
1445
1446 return FALSE;
1447 }
1448
1449 EFI_STATUS
1450 IsaSerialFifoAdd (
1451 IN SERIAL_DEV_FIFO *Fifo,
1452 IN UINT8 Data
1453 )
1454 /*++
1455
1456 Routine Description:
1457 Add data to specific FIFO
1458
1459 Arguments:
1460 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1461 Data UINT8: the data added to FIFO
1462
1463 Returns:
1464 EFI_SUCCESS: Add data to specific FIFO successfully
1465 EFI_OUT_RESOURCE: Failed to add data because FIFO is already full
1466
1467 --*/
1468 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1469 {
1470 //
1471 // if FIFO full can not add data
1472 //
1473 if (IsaSerialFifoFull (Fifo)) {
1474 return EFI_OUT_OF_RESOURCES;
1475 }
1476
1477 //
1478 // FIFO is not full can add data
1479 //
1480 Fifo->Data[Fifo->Last] = Data;
1481 Fifo->Surplus--;
1482 Fifo->Last++;
1483 if (Fifo->Last >= SERIAL_MAX_BUFFER_SIZE) {
1484 Fifo->Last = 0;
1485 }
1486
1487 return EFI_SUCCESS;
1488 }
1489
1490 EFI_STATUS
1491 IsaSerialFifoRemove (
1492 IN SERIAL_DEV_FIFO *Fifo,
1493 OUT UINT8 *Data
1494 )
1495 /*++
1496
1497 Routine Description:
1498 Remove data from specific FIFO
1499
1500 Arguments:
1501 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1502 Data UINT8*: the data removed from FIFO
1503
1504 Returns:
1505 EFI_SUCCESS: Remove data from specific FIFO successfully
1506 EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty
1507
1508 --*/
1509 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1510 {
1511 //
1512 // if FIFO is empty, no data can remove
1513 //
1514 if (IsaSerialFifoEmpty (Fifo)) {
1515 return EFI_OUT_OF_RESOURCES;
1516 }
1517
1518 //
1519 // FIFO is not empty, can remove data
1520 //
1521 *Data = Fifo->Data[Fifo->First];
1522 Fifo->Surplus++;
1523 Fifo->First++;
1524 if (Fifo->First >= SERIAL_MAX_BUFFER_SIZE) {
1525 Fifo->First = 0;
1526 }
1527
1528 return EFI_SUCCESS;
1529 }