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