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