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