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