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