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