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