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