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