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