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