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