]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c
Fix ICC build failure.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaSerialDxe / Serial.c
... / ...
CommitLineData
1/** @file\r
2 Serial driver for standard UARTS on an ISA bus.\r
3\r
4Copyright (c) 2006 - 2010, Intel Corporation<BR>\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Serial.h"\r
16\r
17//\r
18// ISA Serial Driver Global Variables\r
19//\r
20EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {\r
21 SerialControllerDriverSupported,\r
22 SerialControllerDriverStart,\r
23 SerialControllerDriverStop,\r
24 0xa,\r
25 NULL,\r
26 NULL\r
27};\r
28\r
29\r
30SERIAL_DEV gSerialDevTempate = {\r
31 SERIAL_DEV_SIGNATURE,\r
32 NULL,\r
33 { // SerialIo\r
34 SERIAL_IO_INTERFACE_REVISION,\r
35 IsaSerialReset,\r
36 IsaSerialSetAttributes,\r
37 IsaSerialSetControl,\r
38 IsaSerialGetControl,\r
39 IsaSerialWrite,\r
40 IsaSerialRead,\r
41 NULL\r
42 },\r
43 { // SerialMode\r
44 SERIAL_PORT_SUPPORT_CONTROL_MASK,\r
45 SERIAL_PORT_DEFAULT_TIMEOUT,\r
46 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate\r
47 SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,\r
48 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits\r
49 FixedPcdGet8 (PcdUartDefaultParity), // Parity\r
50 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits\r
51 },\r
52 NULL,\r
53 NULL,\r
54 { // UartDevicePath\r
55 {\r
56 MESSAGING_DEVICE_PATH,\r
57 MSG_UART_DP,\r
58 {\r
59 (UINT8) (sizeof (UART_DEVICE_PATH)),\r
60 (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)\r
61 }\r
62 },\r
63 0,\r
64 FixedPcdGet64 (PcdUartDefaultBaudRate), \r
65 FixedPcdGet8 (PcdUartDefaultDataBits),\r
66 FixedPcdGet8 (PcdUartDefaultParity),\r
67 FixedPcdGet8 (PcdUartDefaultStopBits)\r
68 },\r
69 NULL,\r
70 0, //BaseAddress\r
71 {\r
72 0,\r
73 0,\r
74 SERIAL_MAX_BUFFER_SIZE,\r
75 { 0 }\r
76 },\r
77 {\r
78 0,\r
79 0,\r
80 SERIAL_MAX_BUFFER_SIZE,\r
81 { 0 }\r
82 },\r
83 FALSE,\r
84 FALSE,\r
85 Uart16550A,\r
86 NULL\r
87};\r
88\r
89/**\r
90 Check the device path node whether it's the Flow Control node or not.\r
91\r
92 @param[in] FlowControl The device path node to be checked.\r
93 \r
94 @retval TRUE It's the Flow Control node.\r
95 @retval FALSE It's not.\r
96\r
97**/\r
98BOOLEAN\r
99IsUartFlowControlNode (\r
100 IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl\r
101 )\r
102{\r
103 return (BOOLEAN) (\r
104 (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&\r
105 (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&\r
106 (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))\r
107 );\r
108}\r
109\r
110/**\r
111 Check the device path node whether it contains Flow Control node or not.\r
112\r
113 @param[in] DevicePath The device path to be checked.\r
114 \r
115 @retval TRUE It contains the Flow Control node.\r
116 @retval FALSE It doesn't.\r
117\r
118**/\r
119BOOLEAN\r
120ContainsFlowControl (\r
121 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
122 )\r
123{\r
124 while (!IsDevicePathEnd (DevicePath)) {\r
125 if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) {\r
126 return TRUE;\r
127 }\r
128 DevicePath = NextDevicePathNode (DevicePath);\r
129 }\r
130\r
131 return FALSE;\r
132}\r
133\r
134/**\r
135 The user Entry Point for module IsaSerial. The user code starts with this function.\r
136\r
137 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
138 @param[in] SystemTable A pointer to the EFI System Table.\r
139 \r
140 @retval EFI_SUCCESS The entry point is executed successfully.\r
141 @retval other Some error occurs when executing this entry point.\r
142\r
143**/\r
144EFI_STATUS\r
145EFIAPI\r
146InitializeIsaSerial (\r
147 IN EFI_HANDLE ImageHandle,\r
148 IN EFI_SYSTEM_TABLE *SystemTable\r
149 )\r
150{\r
151 EFI_STATUS Status;\r
152\r
153 //\r
154 // Install driver model protocol(s).\r
155 //\r
156 Status = EfiLibInstallDriverBindingComponentName2 (\r
157 ImageHandle,\r
158 SystemTable,\r
159 &gSerialControllerDriver,\r
160 ImageHandle,\r
161 &gIsaSerialComponentName,\r
162 &gIsaSerialComponentName2\r
163 );\r
164 ASSERT_EFI_ERROR (Status);\r
165\r
166\r
167 return Status;\r
168}\r
169\r
170/**\r
171 Check to see if this driver supports the given controller\r
172\r
173 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
174 @param Controller The handle of the controller to test.\r
175 @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
176\r
177 @return EFI_SUCCESS This driver can support the given controller\r
178\r
179**/\r
180EFI_STATUS\r
181EFIAPI\r
182SerialControllerDriverSupported (\r
183 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
184 IN EFI_HANDLE Controller,\r
185 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
186 )\r
187\r
188{\r
189 EFI_STATUS Status;\r
190 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
191 EFI_ISA_IO_PROTOCOL *IsaIo;\r
192 UART_DEVICE_PATH *UartNode;\r
193 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
194 UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;\r
195 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
196 UINTN EntryCount;\r
197 UINTN Index;\r
198 BOOLEAN HasFlowControl;\r
199\r
200 //\r
201 // Check RemainingDevicePath validation\r
202 //\r
203 if (RemainingDevicePath != NULL) {\r
204 //\r
205 // Check if RemainingDevicePath is the End of Device Path Node, \r
206 // if yes, go on checking other conditions\r
207 //\r
208 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
209 //\r
210 // If RemainingDevicePath isn't the End of Device Path Node,\r
211 // check its validation\r
212 //\r
213 Status = EFI_UNSUPPORTED;\r
214\r
215 UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;\r
216 if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||\r
217 UartNode->Header.SubType != MSG_UART_DP ||\r
218 sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) UartNode)\r
219 ) {\r
220 goto Error;\r
221 }\r
222 \r
223 if (UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {\r
224 goto Error;\r
225 }\r
226 \r
227 if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {\r
228 goto Error;\r
229 }\r
230 \r
231 if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {\r
232 goto Error;\r
233 }\r
234 \r
235 if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {\r
236 goto Error;\r
237 }\r
238 \r
239 if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {\r
240 goto Error;\r
241 }\r
242 \r
243 if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {\r
244 goto Error;\r
245 }\r
246\r
247 FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);\r
248 if (IsUartFlowControlNode (FlowControlNode)) {\r
249 //\r
250 // If the second node is Flow Control Node,\r
251 // return error when it request other than hardware flow control.\r
252 //\r
253 if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {\r
254 goto Error;\r
255 }\r
256 }\r
257 }\r
258 }\r
259\r
260 //\r
261 // Open the IO Abstraction(s) needed to perform the supported test\r
262 //\r
263 Status = gBS->OpenProtocol (\r
264 Controller,\r
265 &gEfiIsaIoProtocolGuid,\r
266 (VOID **) &IsaIo,\r
267 This->DriverBindingHandle,\r
268 Controller,\r
269 EFI_OPEN_PROTOCOL_BY_DRIVER\r
270 );\r
271 if (Status == EFI_ALREADY_STARTED) {\r
272 if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {\r
273 //\r
274 // If RemainingDevicePath is NULL or is the End of Device Path Node\r
275 //\r
276 return EFI_SUCCESS;\r
277 }\r
278 //\r
279 // When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node,\r
280 // return unsupported, and vice versa.\r
281 //\r
282 Status = gBS->OpenProtocolInformation (\r
283 Controller,\r
284 &gEfiIsaIoProtocolGuid,\r
285 &OpenInfoBuffer,\r
286 &EntryCount\r
287 );\r
288 if (EFI_ERROR (Status)) {\r
289 return Status;\r
290 }\r
291\r
292 for (Index = 0; Index < EntryCount; Index++) {\r
293 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
294 Status = gBS->OpenProtocol (\r
295 OpenInfoBuffer[Index].ControllerHandle,\r
296 &gEfiDevicePathProtocolGuid,\r
297 (VOID **) &DevicePath,\r
298 This->DriverBindingHandle,\r
299 Controller,\r
300 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
301 );\r
302 if (!EFI_ERROR (Status)) {\r
303 HasFlowControl = ContainsFlowControl (RemainingDevicePath);\r
304 if (HasFlowControl ^ ContainsFlowControl (DevicePath)) {\r
305 Status = EFI_UNSUPPORTED;\r
306 }\r
307 }\r
308 break;\r
309 }\r
310 }\r
311 FreePool (OpenInfoBuffer);\r
312 return Status;\r
313 }\r
314\r
315 if (EFI_ERROR (Status)) {\r
316 return Status;\r
317 }\r
318\r
319 //\r
320 // Close the I/O Abstraction(s) used to perform the supported test\r
321 //\r
322 gBS->CloseProtocol (\r
323 Controller,\r
324 &gEfiIsaIoProtocolGuid,\r
325 This->DriverBindingHandle,\r
326 Controller\r
327 );\r
328\r
329 //\r
330 // Open the EFI Device Path protocol needed to perform the supported test\r
331 //\r
332 Status = gBS->OpenProtocol (\r
333 Controller,\r
334 &gEfiDevicePathProtocolGuid,\r
335 (VOID **) &ParentDevicePath,\r
336 This->DriverBindingHandle,\r
337 Controller,\r
338 EFI_OPEN_PROTOCOL_BY_DRIVER\r
339 );\r
340 if (Status == EFI_ALREADY_STARTED) {\r
341 return EFI_SUCCESS;\r
342 }\r
343\r
344 if (EFI_ERROR (Status)) {\r
345 return Status;\r
346 }\r
347 //\r
348 // Use the ISA I/O Protocol to see if Controller is standard ISA UART that\r
349 // can be managed by this driver.\r
350 //\r
351 Status = EFI_SUCCESS;\r
352 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) {\r
353 Status = EFI_UNSUPPORTED;\r
354 goto Error;\r
355 }\r
356\r
357Error:\r
358 //\r
359 // Close protocol, don't use device path protocol in the Support() function\r
360 //\r
361 gBS->CloseProtocol (\r
362 Controller,\r
363 &gEfiDevicePathProtocolGuid,\r
364 This->DriverBindingHandle,\r
365 Controller\r
366 );\r
367\r
368 return Status;\r
369}\r
370\r
371/**\r
372 Start to management the controller passed in\r
373\r
374 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
375 @param Controller The handle of the controller to test.\r
376 @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
377\r
378 @return EFI_SUCCESS Driver is started successfully\r
379\r
380**/\r
381EFI_STATUS\r
382EFIAPI\r
383SerialControllerDriverStart (\r
384 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
385 IN EFI_HANDLE Controller,\r
386 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
387 )\r
388\r
389{\r
390 EFI_STATUS Status;\r
391 EFI_ISA_IO_PROTOCOL *IsaIo;\r
392 SERIAL_DEV *SerialDevice;\r
393 UINTN Index;\r
394 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
395 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
396 UINTN EntryCount;\r
397 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
398 UART_DEVICE_PATH *Uart;\r
399 UINT32 FlowControlMap;\r
400 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
401 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
402 UINT32 Control;\r
403\r
404 SerialDevice = NULL;\r
405 //\r
406 // Get the Parent Device Path\r
407 //\r
408 Status = gBS->OpenProtocol (\r
409 Controller,\r
410 &gEfiDevicePathProtocolGuid,\r
411 (VOID **) &ParentDevicePath,\r
412 This->DriverBindingHandle,\r
413 Controller,\r
414 EFI_OPEN_PROTOCOL_BY_DRIVER\r
415 );\r
416 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
417 return Status;\r
418 }\r
419 //\r
420 // Report status code enable the serial\r
421 //\r
422 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
423 EFI_PROGRESS_CODE,\r
424 EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
425 ParentDevicePath\r
426 );\r
427\r
428 //\r
429 // Grab the IO abstraction we need to get any work done\r
430 //\r
431 Status = gBS->OpenProtocol (\r
432 Controller,\r
433 &gEfiIsaIoProtocolGuid,\r
434 (VOID **) &IsaIo,\r
435 This->DriverBindingHandle,\r
436 Controller,\r
437 EFI_OPEN_PROTOCOL_BY_DRIVER\r
438 );\r
439 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
440 goto Error;\r
441 }\r
442\r
443 if (Status == EFI_ALREADY_STARTED) {\r
444\r
445 if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {\r
446 //\r
447 // If RemainingDevicePath is NULL or is the End of Device Path Node\r
448 //\r
449 return EFI_SUCCESS;\r
450 }\r
451\r
452 //\r
453 // Make sure a child handle does not already exist. This driver can only\r
454 // produce one child per serial port.\r
455 //\r
456 Status = gBS->OpenProtocolInformation (\r
457 Controller,\r
458 &gEfiIsaIoProtocolGuid,\r
459 &OpenInfoBuffer,\r
460 &EntryCount\r
461 );\r
462 if (EFI_ERROR (Status)) {\r
463 return Status;\r
464 }\r
465\r
466 Status = EFI_ALREADY_STARTED;\r
467 for (Index = 0; Index < EntryCount; Index++) {\r
468 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
469 Status = gBS->OpenProtocol (\r
470 OpenInfoBuffer[Index].ControllerHandle,\r
471 &gEfiSerialIoProtocolGuid,\r
472 (VOID **) &SerialIo,\r
473 This->DriverBindingHandle,\r
474 Controller,\r
475 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
476 );\r
477 if (!EFI_ERROR (Status)) {\r
478 Uart = (UART_DEVICE_PATH *) RemainingDevicePath;\r
479 Status = SerialIo->SetAttributes (\r
480 SerialIo,\r
481 Uart->BaudRate,\r
482 SerialIo->Mode->ReceiveFifoDepth,\r
483 SerialIo->Mode->Timeout,\r
484 (EFI_PARITY_TYPE) Uart->Parity,\r
485 Uart->DataBits,\r
486 (EFI_STOP_BITS_TYPE) Uart->StopBits\r
487 );\r
488\r
489 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
490 if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {\r
491 Status = SerialIo->GetControl (SerialIo, &Control);\r
492 if (!EFI_ERROR (Status)) {\r
493 if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {\r
494 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
495 } else {\r
496 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
497 }\r
498 //\r
499 // Clear the bits that are not allowed to pass to SetControl\r
500 //\r
501 Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
502 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \r
503 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);\r
504 Status = SerialIo->SetControl (SerialIo, Control);\r
505 }\r
506 }\r
507 }\r
508 break;\r
509 }\r
510 }\r
511\r
512 FreePool (OpenInfoBuffer);\r
513 return Status;\r
514 }\r
515\r
516 if (RemainingDevicePath != NULL) {\r
517 if (IsDevicePathEnd (RemainingDevicePath)) {\r
518 //\r
519 // If RemainingDevicePath is the End of Device Path Node,\r
520 // skip enumerate any device and return EFI_SUCESSS\r
521 // \r
522 return EFI_SUCCESS;\r
523 }\r
524 }\r
525\r
526 //\r
527 // Initialize the serial device instance\r
528 //\r
529 SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTempate);\r
530 if (SerialDevice == NULL) {\r
531 Status = EFI_OUT_OF_RESOURCES;\r
532 goto Error;\r
533 }\r
534\r
535 SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);\r
536 SerialDevice->IsaIo = IsaIo;\r
537 SerialDevice->ParentDevicePath = ParentDevicePath;\r
538 FlowControl = NULL;\r
539 FlowControlMap = 0;\r
540\r
541 //\r
542 // Check if RemainingDevicePath is NULL, \r
543 // if yes, use the values from the gSerialDevTempate as no remaining device path was\r
544 // passed in.\r
545 //\r
546 if (RemainingDevicePath != NULL) {\r
547 //\r
548 // If RemainingDevicePath isn't NULL, \r
549 // match the configuration of the RemainingDevicePath. IsHandleSupported()\r
550 // already checked to make sure the RemainingDevicePath contains settings\r
551 // that we can support.\r
552 //\r
553 CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));\r
554 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);\r
555 if (IsUartFlowControlNode (FlowControl)) {\r
556 FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);\r
557 } else {\r
558 FlowControl = NULL;\r
559 }\r
560 }\r
561\r
562 AddName (SerialDevice, IsaIo);\r
563\r
564 for (Index = 0; SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {\r
565 if (SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {\r
566 SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange;\r
567 }\r
568 }\r
569 \r
570 SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);\r
571\r
572 //\r
573 // Report status code the serial present\r
574 //\r
575 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
576 EFI_PROGRESS_CODE,\r
577 EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,\r
578 ParentDevicePath\r
579 );\r
580\r
581 if (!IsaSerialPortPresent (SerialDevice)) {\r
582 Status = EFI_DEVICE_ERROR;\r
583 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
584 EFI_ERROR_CODE,\r
585 EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,\r
586 ParentDevicePath\r
587 );\r
588 goto Error;\r
589 }\r
590\r
591 //\r
592 // Build the device path by appending the UART node to the ParentDevicePath.\r
593 // The Uart setings are zero here, since SetAttribute() will update them to match \r
594 // the default setings.\r
595 //\r
596 SerialDevice->DevicePath = AppendDevicePathNode (\r
597 ParentDevicePath,\r
598 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
599 );\r
600 //\r
601 // Only produce the Flow Control node when remaining device path has it\r
602 //\r
603 if (FlowControl != NULL) {\r
604 TempDevicePath = SerialDevice->DevicePath;\r
605 if (TempDevicePath != NULL) {\r
606 SerialDevice->DevicePath = AppendDevicePathNode (\r
607 TempDevicePath,\r
608 (EFI_DEVICE_PATH_PROTOCOL *) FlowControl\r
609 );\r
610 FreePool (TempDevicePath);\r
611 }\r
612 }\r
613 if (SerialDevice->DevicePath == NULL) {\r
614 Status = EFI_OUT_OF_RESOURCES;\r
615 goto Error;\r
616 }\r
617\r
618 //\r
619 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.\r
620 //\r
621 SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;\r
622 SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;\r
623 SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity;\r
624 SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;\r
625\r
626 //\r
627 // Issue a reset to initialize the COM port\r
628 //\r
629 Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);\r
630 if (EFI_ERROR (Status)) {\r
631 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
632 EFI_ERROR_CODE,\r
633 EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
634 ParentDevicePath\r
635 );\r
636 goto Error;\r
637 }\r
638 //\r
639 // Install protocol interfaces for the serial device.\r
640 //\r
641 Status = gBS->InstallMultipleProtocolInterfaces (\r
642 &SerialDevice->Handle,\r
643 &gEfiDevicePathProtocolGuid,\r
644 SerialDevice->DevicePath,\r
645 &gEfiSerialIoProtocolGuid,\r
646 &SerialDevice->SerialIo,\r
647 NULL\r
648 );\r
649 if (EFI_ERROR (Status)) {\r
650 goto Error;\r
651 }\r
652 //\r
653 // Open For Child Device\r
654 //\r
655 Status = gBS->OpenProtocol (\r
656 Controller,\r
657 &gEfiIsaIoProtocolGuid,\r
658 (VOID **) &IsaIo,\r
659 This->DriverBindingHandle,\r
660 SerialDevice->Handle,\r
661 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
662 );\r
663\r
664Error:\r
665 if (EFI_ERROR (Status)) {\r
666 gBS->CloseProtocol (\r
667 Controller,\r
668 &gEfiDevicePathProtocolGuid,\r
669 This->DriverBindingHandle,\r
670 Controller\r
671 );\r
672 gBS->CloseProtocol (\r
673 Controller,\r
674 &gEfiIsaIoProtocolGuid,\r
675 This->DriverBindingHandle,\r
676 Controller\r
677 );\r
678 if (SerialDevice != NULL) {\r
679 if (SerialDevice->DevicePath != NULL) {\r
680 gBS->FreePool (SerialDevice->DevicePath);\r
681 }\r
682\r
683 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
684 gBS->FreePool (SerialDevice);\r
685 }\r
686 }\r
687\r
688 return Status;\r
689}\r
690\r
691/**\r
692 Disconnect this driver with the controller, uninstall related protocol instance\r
693\r
694 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
695 @param Controller The handle of the controller to test.\r
696 @param NumberOfChildren Number of child device.\r
697 @param ChildHandleBuffer A pointer to the remaining portion of a device path.\r
698\r
699 @retval EFI_SUCCESS Operation successfully\r
700 @retval EFI_DEVICE_ERROR Cannot stop the driver successfully\r
701\r
702**/\r
703EFI_STATUS\r
704EFIAPI\r
705SerialControllerDriverStop (\r
706 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
707 IN EFI_HANDLE Controller,\r
708 IN UINTN NumberOfChildren,\r
709 IN EFI_HANDLE *ChildHandleBuffer\r
710 )\r
711\r
712{\r
713 EFI_STATUS Status;\r
714 UINTN Index;\r
715 BOOLEAN AllChildrenStopped;\r
716 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
717 SERIAL_DEV *SerialDevice;\r
718 EFI_ISA_IO_PROTOCOL *IsaIo;\r
719 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
720\r
721 Status = gBS->HandleProtocol (\r
722 Controller,\r
723 &gEfiDevicePathProtocolGuid,\r
724 (VOID **) &DevicePath\r
725 );\r
726\r
727 //\r
728 // Report the status code disable the serial\r
729 //\r
730 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
731 EFI_PROGRESS_CODE,\r
732 EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
733 DevicePath\r
734 );\r
735\r
736 //\r
737 // Complete all outstanding transactions to Controller.\r
738 // Don't allow any new transaction to Controller to be started.\r
739 //\r
740 if (NumberOfChildren == 0) {\r
741 //\r
742 // Close the bus driver\r
743 //\r
744 Status = gBS->CloseProtocol (\r
745 Controller,\r
746 &gEfiIsaIoProtocolGuid,\r
747 This->DriverBindingHandle,\r
748 Controller\r
749 );\r
750\r
751 Status = gBS->CloseProtocol (\r
752 Controller,\r
753 &gEfiDevicePathProtocolGuid,\r
754 This->DriverBindingHandle,\r
755 Controller\r
756 );\r
757 return Status;\r
758 }\r
759\r
760 AllChildrenStopped = TRUE;\r
761\r
762 for (Index = 0; Index < NumberOfChildren; Index++) {\r
763\r
764 Status = gBS->OpenProtocol (\r
765 ChildHandleBuffer[Index],\r
766 &gEfiSerialIoProtocolGuid,\r
767 (VOID **) &SerialIo,\r
768 This->DriverBindingHandle,\r
769 Controller,\r
770 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
771 );\r
772 if (!EFI_ERROR (Status)) {\r
773\r
774 SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);\r
775\r
776 Status = gBS->CloseProtocol (\r
777 Controller,\r
778 &gEfiIsaIoProtocolGuid,\r
779 This->DriverBindingHandle,\r
780 ChildHandleBuffer[Index]\r
781 );\r
782\r
783 Status = gBS->UninstallMultipleProtocolInterfaces (\r
784 ChildHandleBuffer[Index],\r
785 &gEfiDevicePathProtocolGuid,\r
786 SerialDevice->DevicePath,\r
787 &gEfiSerialIoProtocolGuid,\r
788 &SerialDevice->SerialIo,\r
789 NULL\r
790 );\r
791 if (EFI_ERROR (Status)) {\r
792 gBS->OpenProtocol (\r
793 Controller,\r
794 &gEfiIsaIoProtocolGuid,\r
795 (VOID **) &IsaIo,\r
796 This->DriverBindingHandle,\r
797 ChildHandleBuffer[Index],\r
798 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
799 );\r
800 } else {\r
801 if (SerialDevice->DevicePath != NULL) {\r
802 gBS->FreePool (SerialDevice->DevicePath);\r
803 }\r
804\r
805 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
806 gBS->FreePool (SerialDevice);\r
807 }\r
808 }\r
809\r
810 if (EFI_ERROR (Status)) {\r
811 AllChildrenStopped = FALSE;\r
812 }\r
813 }\r
814\r
815 if (!AllChildrenStopped) {\r
816 return EFI_DEVICE_ERROR;\r
817 }\r
818\r
819 return EFI_SUCCESS;\r
820}\r
821\r
822/**\r
823 Detect whether specific FIFO is full or not.\r
824\r
825 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
826\r
827 @return whether specific FIFO is full or not\r
828\r
829**/\r
830BOOLEAN\r
831IsaSerialFifoFull (\r
832 IN SERIAL_DEV_FIFO *Fifo\r
833 )\r
834\r
835{\r
836 if (Fifo->Surplus == 0) {\r
837 return TRUE;\r
838 }\r
839\r
840 return FALSE;\r
841}\r
842\r
843/**\r
844 Detect whether specific FIFO is empty or not.\r
845 \r
846 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
847\r
848 @return whether specific FIFO is empty or not\r
849\r
850**/\r
851BOOLEAN\r
852IsaSerialFifoEmpty (\r
853 IN SERIAL_DEV_FIFO *Fifo\r
854 )\r
855\r
856{\r
857 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {\r
858 return TRUE;\r
859 }\r
860\r
861 return FALSE;\r
862}\r
863\r
864/**\r
865 Add data to specific FIFO.\r
866\r
867 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
868 @param Data the data added to FIFO\r
869\r
870 @retval EFI_SUCCESS Add data to specific FIFO successfully\r
871 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full\r
872\r
873**/\r
874EFI_STATUS\r
875IsaSerialFifoAdd (\r
876 IN SERIAL_DEV_FIFO *Fifo,\r
877 IN UINT8 Data\r
878 )\r
879\r
880{\r
881 //\r
882 // if FIFO full can not add data\r
883 //\r
884 if (IsaSerialFifoFull (Fifo)) {\r
885 return EFI_OUT_OF_RESOURCES;\r
886 }\r
887 //\r
888 // FIFO is not full can add data\r
889 //\r
890 Fifo->Data[Fifo->Last] = Data;\r
891 Fifo->Surplus--;\r
892 Fifo->Last++;\r
893 if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {\r
894 Fifo->Last = 0;\r
895 }\r
896\r
897 return EFI_SUCCESS;\r
898}\r
899\r
900/**\r
901 Remove data from specific FIFO.\r
902\r
903 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO\r
904 @param Data the data removed from FIFO\r
905\r
906 @retval EFI_SUCCESS Remove data from specific FIFO successfully\r
907 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty\r
908\r
909**/\r
910EFI_STATUS\r
911IsaSerialFifoRemove (\r
912 IN SERIAL_DEV_FIFO *Fifo,\r
913 OUT UINT8 *Data\r
914 )\r
915\r
916{\r
917 //\r
918 // if FIFO is empty, no data can remove\r
919 //\r
920 if (IsaSerialFifoEmpty (Fifo)) {\r
921 return EFI_OUT_OF_RESOURCES;\r
922 }\r
923 //\r
924 // FIFO is not empty, can remove data\r
925 //\r
926 *Data = Fifo->Data[Fifo->First];\r
927 Fifo->Surplus++;\r
928 Fifo->First++;\r
929 if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {\r
930 Fifo->First = 0;\r
931 }\r
932\r
933 return EFI_SUCCESS;\r
934}\r
935\r
936/**\r
937 Reads and writes all avaliable data.\r
938\r
939 @param SerialDevice The device to flush\r
940\r
941 @retval EFI_SUCCESS Data was read/written successfully.\r
942 @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when\r
943 this happens, pending writes are not done.\r
944\r
945**/\r
946EFI_STATUS\r
947IsaSerialReceiveTransmit (\r
948 IN SERIAL_DEV *SerialDevice\r
949 )\r
950\r
951{\r
952 SERIAL_PORT_LSR Lsr;\r
953 UINT8 Data;\r
954 BOOLEAN ReceiveFifoFull;\r
955 SERIAL_PORT_MSR Msr;\r
956 SERIAL_PORT_MCR Mcr;\r
957 UINTN TimeOut;\r
958\r
959 Data = 0;\r
960\r
961 //\r
962 // Begin the read or write\r
963 //\r
964 if (SerialDevice->SoftwareLoopbackEnable) {\r
965 do {\r
966 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);\r
967 if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
968 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);\r
969 if (ReceiveFifoFull) {\r
970 return EFI_OUT_OF_RESOURCES;\r
971 }\r
972\r
973 IsaSerialFifoAdd (&SerialDevice->Receive, Data);\r
974 }\r
975 } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));\r
976 } else {\r
977 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);\r
978 //\r
979 // For full handshake flow control, tell the peer to send data\r
980 // if receive buffer is available.\r
981 //\r
982 if (SerialDevice->HardwareFlowControl &&\r
983 !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)&&\r
984 !ReceiveFifoFull\r
985 ) {\r
986 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
987 Mcr.Bits.Rts = 1;\r
988 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
989 }\r
990 do {\r
991 Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
992\r
993 //\r
994 // Flush incomming data to prevent a an overrun during a long write\r
995 //\r
996 if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {\r
997 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);\r
998 if (!ReceiveFifoFull) {\r
999 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {\r
1000 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1001 EFI_ERROR_CODE,\r
1002 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
1003 SerialDevice->DevicePath\r
1004 );\r
1005 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {\r
1006 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1007 continue;\r
1008 }\r
1009 }\r
1010\r
1011 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1012\r
1013 IsaSerialFifoAdd (&SerialDevice->Receive, Data);\r
1014 \r
1015 //\r
1016 // For full handshake flow control, if receive buffer full\r
1017 // tell the peer to stop sending data.\r
1018 //\r
1019 if (SerialDevice->HardwareFlowControl &&\r
1020 !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake) &&\r
1021 IsaSerialFifoFull (&SerialDevice->Receive)\r
1022 ) {\r
1023 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1024 Mcr.Bits.Rts = 0;\r
1025 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
1026 }\r
1027\r
1028\r
1029 continue;\r
1030 } else {\r
1031 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1032 EFI_PROGRESS_CODE,\r
1033 EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,\r
1034 SerialDevice->DevicePath\r
1035 );\r
1036 }\r
1037 }\r
1038 //\r
1039 // Do the write\r
1040 //\r
1041 if (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
1042 //\r
1043 // Make sure the transmit data will not be missed\r
1044 //\r
1045 if (SerialDevice->HardwareFlowControl) {\r
1046 //\r
1047 // For half handshake flow control assert RTS before sending.\r
1048 //\r
1049 if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {\r
1050 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1051 Mcr.Bits.Rts= 0;\r
1052 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
1053 }\r
1054 //\r
1055 // Wait for CTS\r
1056 //\r
1057 TimeOut = 0;\r
1058 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1059 while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {\r
1060 gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
1061 TimeOut++;\r
1062 if (TimeOut > 5) {\r
1063 break;\r
1064 }\r
1065\r
1066 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1067 }\r
1068\r
1069 if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {\r
1070 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);\r
1071 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);\r
1072 }\r
1073\r
1074 //\r
1075 // For half handshake flow control, tell DCE we are done.\r
1076 //\r
1077 if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {\r
1078 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1079 Mcr.Bits.Rts = 1;\r
1080 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
1081 }\r
1082 } else {\r
1083 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);\r
1084 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);\r
1085 }\r
1086 }\r
1087 } while (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit));\r
1088 }\r
1089\r
1090 return EFI_SUCCESS;\r
1091}\r
1092\r
1093//\r
1094// Interface Functions\r
1095//\r
1096/**\r
1097 Reset serial device.\r
1098\r
1099 @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
1100\r
1101 @retval EFI_SUCCESS Reset successfully\r
1102 @retval EFI_DEVICE_ERROR Failed to reset\r
1103\r
1104**/\r
1105EFI_STATUS\r
1106EFIAPI\r
1107IsaSerialReset (\r
1108 IN EFI_SERIAL_IO_PROTOCOL *This\r
1109 )\r
1110{\r
1111 EFI_STATUS Status;\r
1112 SERIAL_DEV *SerialDevice;\r
1113 SERIAL_PORT_LCR Lcr;\r
1114 SERIAL_PORT_IER Ier;\r
1115 SERIAL_PORT_MCR Mcr;\r
1116 SERIAL_PORT_FCR Fcr;\r
1117 EFI_TPL Tpl;\r
1118 UINT32 Control;\r
1119\r
1120 SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
1121\r
1122 //\r
1123 // Report the status code reset the serial\r
1124 //\r
1125 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1126 EFI_PROGRESS_CODE,\r
1127 EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,\r
1128 SerialDevice->DevicePath\r
1129 );\r
1130\r
1131 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1132\r
1133 //\r
1134 // Make sure DLAB is 0.\r
1135 //\r
1136 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1137 Lcr.Bits.DLab = 0;\r
1138 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);\r
1139\r
1140 //\r
1141 // Turn off all interrupts\r
1142 //\r
1143 Ier.Data = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1144 Ier.Bits.Ravie = 0;\r
1145 Ier.Bits.Theie = 0;\r
1146 Ier.Bits.Rie = 0;\r
1147 Ier.Bits.Mie = 0;\r
1148 WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data);\r
1149\r
1150 //\r
1151 // Disable the FIFO.\r
1152 //\r
1153 Fcr.Bits.TrFIFOE = 0;\r
1154 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);\r
1155\r
1156 //\r
1157 // Turn off loopback and disable device interrupt.\r
1158 //\r
1159 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1160 Mcr.Bits.Out1 = 0;\r
1161 Mcr.Bits.Out2 = 0;\r
1162 Mcr.Bits.Lme = 0;\r
1163 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
1164\r
1165 //\r
1166 // Clear the scratch pad register\r
1167 //\r
1168 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0);\r
1169\r
1170 //\r
1171 // Go set the current attributes\r
1172 //\r
1173 Status = This->SetAttributes (\r
1174 This,\r
1175 This->Mode->BaudRate,\r
1176 This->Mode->ReceiveFifoDepth,\r
1177 This->Mode->Timeout,\r
1178 (EFI_PARITY_TYPE) This->Mode->Parity,\r
1179 (UINT8) This->Mode->DataBits,\r
1180 (EFI_STOP_BITS_TYPE) This->Mode->StopBits\r
1181 );\r
1182\r
1183 if (EFI_ERROR (Status)) {\r
1184 gBS->RestoreTPL (Tpl);\r
1185 return EFI_DEVICE_ERROR;\r
1186 }\r
1187 //\r
1188 // Go set the current control bits\r
1189 //\r
1190 Control = 0;\r
1191 if (SerialDevice->HardwareFlowControl) {\r
1192 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
1193 }\r
1194 if (SerialDevice->SoftwareLoopbackEnable) {\r
1195 Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
1196 }\r
1197 Status = This->SetControl (\r
1198 This,\r
1199 Control\r
1200 );\r
1201\r
1202 if (EFI_ERROR (Status)) {\r
1203 gBS->RestoreTPL (Tpl);\r
1204 return EFI_DEVICE_ERROR;\r
1205 }\r
1206 //\r
1207 // for 16550A enable FIFO, 16550 disable FIFO\r
1208 //\r
1209 Fcr.Bits.TrFIFOE = 1;\r
1210 Fcr.Bits.ResetRF = 1;\r
1211 Fcr.Bits.ResetTF = 1;\r
1212 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);\r
1213\r
1214 //\r
1215 // Reset the software FIFO\r
1216 //\r
1217 SerialDevice->Receive.First = 0;\r
1218 SerialDevice->Receive.Last = 0;\r
1219 SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE;\r
1220 SerialDevice->Transmit.First = 0;\r
1221 SerialDevice->Transmit.Last = 0;\r
1222 SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE;\r
1223\r
1224 gBS->RestoreTPL (Tpl);\r
1225\r
1226 //\r
1227 // Device reset is complete\r
1228 //\r
1229 return EFI_SUCCESS;\r
1230}\r
1231\r
1232/**\r
1233 Set new attributes to a serial device.\r
1234\r
1235 @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
1236 @param BaudRate The baudrate of the serial device\r
1237 @param ReceiveFifoDepth The depth of receive FIFO buffer\r
1238 @param Timeout The request timeout for a single char\r
1239 @param Parity The type of parity used in serial device\r
1240 @param DataBits Number of databits used in serial device\r
1241 @param StopBits Number of stopbits used in serial device\r
1242\r
1243 @retval EFI_SUCCESS The new attributes were set\r
1244 @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value\r
1245 @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6\r
1246 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)\r
1247\r
1248**/\r
1249EFI_STATUS\r
1250EFIAPI\r
1251IsaSerialSetAttributes (\r
1252 IN EFI_SERIAL_IO_PROTOCOL *This,\r
1253 IN UINT64 BaudRate,\r
1254 IN UINT32 ReceiveFifoDepth,\r
1255 IN UINT32 Timeout,\r
1256 IN EFI_PARITY_TYPE Parity,\r
1257 IN UINT8 DataBits,\r
1258 IN EFI_STOP_BITS_TYPE StopBits\r
1259 )\r
1260{\r
1261 EFI_STATUS Status;\r
1262 SERIAL_DEV *SerialDevice;\r
1263 UINT32 Divisor;\r
1264 UINT32 Remained;\r
1265 SERIAL_PORT_LCR Lcr;\r
1266 UART_DEVICE_PATH *Uart;\r
1267 EFI_TPL Tpl;\r
1268\r
1269 SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
1270\r
1271 //\r
1272 // Check for default settings and fill in actual values.\r
1273 //\r
1274 if (BaudRate == 0) {\r
1275 BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
1276 }\r
1277\r
1278 if (ReceiveFifoDepth == 0) {\r
1279 ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;\r
1280 }\r
1281\r
1282 if (Timeout == 0) {\r
1283 Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;\r
1284 }\r
1285\r
1286 if (Parity == DefaultParity) {\r
1287 Parity = (EFI_PARITY_TYPE)PcdGet8 (PcdUartDefaultParity);\r
1288 }\r
1289\r
1290 if (DataBits == 0) {\r
1291 DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
1292 }\r
1293\r
1294 if (StopBits == DefaultStopBits) {\r
1295 StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);\r
1296 }\r
1297 //\r
1298 // 5 and 6 data bits can not be verified on a 16550A UART\r
1299 // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings.\r
1300 //\r
1301 if ((DataBits == 5) || (DataBits == 6)) {\r
1302 return EFI_INVALID_PARAMETER;\r
1303 }\r
1304 //\r
1305 // Make sure all parameters are valid\r
1306 //\r
1307 if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {\r
1308 return EFI_INVALID_PARAMETER;\r
1309 }\r
1310 //\r
1311 // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200,\r
1312 // 38400,57600,115200\r
1313 //\r
1314 if (BaudRate < 75) {\r
1315 BaudRate = 50;\r
1316 } else if (BaudRate < 110) {\r
1317 BaudRate = 75;\r
1318 } else if (BaudRate < 134) {\r
1319 BaudRate = 110;\r
1320 } else if (BaudRate < 150) {\r
1321 BaudRate = 134;\r
1322 } else if (BaudRate < 300) {\r
1323 BaudRate = 150;\r
1324 } else if (BaudRate < 600) {\r
1325 BaudRate = 300;\r
1326 } else if (BaudRate < 1200) {\r
1327 BaudRate = 600;\r
1328 } else if (BaudRate < 1800) {\r
1329 BaudRate = 1200;\r
1330 } else if (BaudRate < 2000) {\r
1331 BaudRate = 1800;\r
1332 } else if (BaudRate < 2400) {\r
1333 BaudRate = 2000;\r
1334 } else if (BaudRate < 3600) {\r
1335 BaudRate = 2400;\r
1336 } else if (BaudRate < 4800) {\r
1337 BaudRate = 3600;\r
1338 } else if (BaudRate < 7200) {\r
1339 BaudRate = 4800;\r
1340 } else if (BaudRate < 9600) {\r
1341 BaudRate = 7200;\r
1342 } else if (BaudRate < 19200) {\r
1343 BaudRate = 9600;\r
1344 } else if (BaudRate < 38400) {\r
1345 BaudRate = 19200;\r
1346 } else if (BaudRate < 57600) {\r
1347 BaudRate = 38400;\r
1348 } else if (BaudRate < 115200) {\r
1349 BaudRate = 57600;\r
1350 } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) {\r
1351 BaudRate = 115200;\r
1352 }\r
1353\r
1354 if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {\r
1355 return EFI_INVALID_PARAMETER;\r
1356 }\r
1357\r
1358 if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {\r
1359 return EFI_INVALID_PARAMETER;\r
1360 }\r
1361\r
1362 if ((Parity < NoParity) || (Parity > SpaceParity)) {\r
1363 return EFI_INVALID_PARAMETER;\r
1364 }\r
1365\r
1366 if ((DataBits < 5) || (DataBits > 8)) {\r
1367 return EFI_INVALID_PARAMETER;\r
1368 }\r
1369\r
1370 if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {\r
1371 return EFI_INVALID_PARAMETER;\r
1372 }\r
1373\r
1374 //\r
1375 // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits\r
1376 //\r
1377 if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {\r
1378 return EFI_INVALID_PARAMETER;\r
1379 }\r
1380\r
1381 //\r
1382 // Compute divisor use to program the baud rate using a round determination\r
1383 //\r
1384 Divisor = (UINT32) DivU64x32Remainder (\r
1385 SERIAL_PORT_INPUT_CLOCK,\r
1386 ((UINT32) BaudRate * 16),\r
1387 &Remained\r
1388 );\r
1389 if (Remained != 0) {\r
1390 Divisor += 1;\r
1391 }\r
1392\r
1393 if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) {\r
1394 return EFI_INVALID_PARAMETER;\r
1395 }\r
1396\r
1397 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1398\r
1399 //\r
1400 // Compute the actual baud rate that the serial port will be programmed for.\r
1401 //\r
1402 BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16;\r
1403\r
1404 //\r
1405 // Put serial port on Divisor Latch Mode\r
1406 //\r
1407 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1408 Lcr.Bits.DLab = 1;\r
1409 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);\r
1410\r
1411 //\r
1412 // Write the divisor to the serial port\r
1413 //\r
1414 WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));\r
1415 WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));\r
1416\r
1417 //\r
1418 // Put serial port back in normal mode and set remaining attributes.\r
1419 //\r
1420 Lcr.Bits.DLab = 0;\r
1421\r
1422 switch (Parity) {\r
1423 case NoParity:\r
1424 Lcr.Bits.ParEn = 0;\r
1425 Lcr.Bits.EvenPar = 0;\r
1426 Lcr.Bits.SticPar = 0;\r
1427 break;\r
1428\r
1429 case EvenParity:\r
1430 Lcr.Bits.ParEn = 1;\r
1431 Lcr.Bits.EvenPar = 1;\r
1432 Lcr.Bits.SticPar = 0;\r
1433 break;\r
1434\r
1435 case OddParity:\r
1436 Lcr.Bits.ParEn = 1;\r
1437 Lcr.Bits.EvenPar = 0;\r
1438 Lcr.Bits.SticPar = 0;\r
1439 break;\r
1440\r
1441 case SpaceParity:\r
1442 Lcr.Bits.ParEn = 1;\r
1443 Lcr.Bits.EvenPar = 1;\r
1444 Lcr.Bits.SticPar = 1;\r
1445 break;\r
1446\r
1447 case MarkParity:\r
1448 Lcr.Bits.ParEn = 1;\r
1449 Lcr.Bits.EvenPar = 0;\r
1450 Lcr.Bits.SticPar = 1;\r
1451 break;\r
1452\r
1453 default:\r
1454 break;\r
1455 }\r
1456\r
1457 switch (StopBits) {\r
1458 case OneStopBit:\r
1459 Lcr.Bits.StopB = 0;\r
1460 break;\r
1461\r
1462 case OneFiveStopBits:\r
1463 case TwoStopBits:\r
1464 Lcr.Bits.StopB = 1;\r
1465 break;\r
1466\r
1467 default:\r
1468 break;\r
1469 }\r
1470 //\r
1471 // DataBits\r
1472 //\r
1473 Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);\r
1474 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);\r
1475\r
1476 //\r
1477 // Set the Serial I/O mode\r
1478 //\r
1479 This->Mode->BaudRate = BaudRate;\r
1480 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;\r
1481 This->Mode->Timeout = Timeout;\r
1482 This->Mode->Parity = Parity;\r
1483 This->Mode->DataBits = DataBits;\r
1484 This->Mode->StopBits = StopBits;\r
1485\r
1486 //\r
1487 // See if Device Path Node has actually changed\r
1488 //\r
1489 if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&\r
1490 SerialDevice->UartDevicePath.DataBits == DataBits &&\r
1491 SerialDevice->UartDevicePath.Parity == Parity &&\r
1492 SerialDevice->UartDevicePath.StopBits == StopBits\r
1493 ) {\r
1494 gBS->RestoreTPL (Tpl);\r
1495 return EFI_SUCCESS;\r
1496 }\r
1497 //\r
1498 // Update the device path\r
1499 //\r
1500 SerialDevice->UartDevicePath.BaudRate = BaudRate;\r
1501 SerialDevice->UartDevicePath.DataBits = DataBits;\r
1502 SerialDevice->UartDevicePath.Parity = (UINT8) Parity;\r
1503 SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;\r
1504\r
1505 Status = EFI_SUCCESS;\r
1506 if (SerialDevice->Handle != NULL) {\r
1507 Uart = (UART_DEVICE_PATH *) (\r
1508 (UINTN) SerialDevice->DevicePath\r
1509 + GetDevicePathSize (SerialDevice->ParentDevicePath)\r
1510 - END_DEVICE_PATH_LENGTH\r
1511 );\r
1512 CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));\r
1513 Status = gBS->ReinstallProtocolInterface (\r
1514 SerialDevice->Handle,\r
1515 &gEfiDevicePathProtocolGuid,\r
1516 SerialDevice->DevicePath,\r
1517 SerialDevice->DevicePath\r
1518 );\r
1519 }\r
1520\r
1521 gBS->RestoreTPL (Tpl);\r
1522\r
1523 return Status;\r
1524}\r
1525\r
1526/**\r
1527 Set Control Bits.\r
1528\r
1529 @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
1530 @param Control Control bits that can be settable\r
1531\r
1532 @retval EFI_SUCCESS New Control bits were set successfully\r
1533 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported\r
1534\r
1535**/\r
1536EFI_STATUS\r
1537EFIAPI\r
1538IsaSerialSetControl (\r
1539 IN EFI_SERIAL_IO_PROTOCOL *This,\r
1540 IN UINT32 Control\r
1541 )\r
1542{\r
1543 SERIAL_DEV *SerialDevice;\r
1544 SERIAL_PORT_MCR Mcr;\r
1545 EFI_TPL Tpl;\r
1546 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
1547 EFI_STATUS Status;\r
1548\r
1549 //\r
1550 // The control bits that can be set are :\r
1551 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO\r
1552 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO\r
1553 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW\r
1554 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW\r
1555 // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW\r
1556 //\r
1557 SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
1558\r
1559 //\r
1560 // first determine the parameter is invalid\r
1561 //\r
1562 if (Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
1563 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \r
1564 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) {\r
1565 return EFI_UNSUPPORTED;\r
1566 }\r
1567\r
1568 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1569\r
1570 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1571 Mcr.Bits.DtrC = 0;\r
1572 Mcr.Bits.Rts = 0;\r
1573 Mcr.Bits.Lme = 0;\r
1574 SerialDevice->SoftwareLoopbackEnable = FALSE;\r
1575 SerialDevice->HardwareFlowControl = FALSE;\r
1576\r
1577 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {\r
1578 Mcr.Bits.DtrC = 1;\r
1579 }\r
1580\r
1581 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {\r
1582 Mcr.Bits.Rts = 1;\r
1583 }\r
1584\r
1585 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {\r
1586 Mcr.Bits.Lme = 1;\r
1587 }\r
1588\r
1589 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {\r
1590 SerialDevice->HardwareFlowControl = TRUE;\r
1591 }\r
1592\r
1593 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);\r
1594\r
1595 if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {\r
1596 SerialDevice->SoftwareLoopbackEnable = TRUE;\r
1597 }\r
1598\r
1599 Status = EFI_SUCCESS;\r
1600 if (SerialDevice->Handle != NULL) {\r
1601 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (\r
1602 (UINTN) SerialDevice->DevicePath\r
1603 + GetDevicePathSize (SerialDevice->ParentDevicePath)\r
1604 - END_DEVICE_PATH_LENGTH\r
1605 + sizeof (UART_DEVICE_PATH)\r
1606 );\r
1607 if (IsUartFlowControlNode (FlowControl) &&\r
1608 ((ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) ^ SerialDevice->HardwareFlowControl)) {\r
1609 //\r
1610 // Flow Control setting is changed, need to reinstall device path protocol\r
1611 //\r
1612 WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);\r
1613 Status = gBS->ReinstallProtocolInterface (\r
1614 SerialDevice->Handle,\r
1615 &gEfiDevicePathProtocolGuid,\r
1616 SerialDevice->DevicePath,\r
1617 SerialDevice->DevicePath\r
1618 );\r
1619 }\r
1620 }\r
1621\r
1622 gBS->RestoreTPL (Tpl);\r
1623\r
1624 return Status;\r
1625}\r
1626\r
1627/**\r
1628 Get ControlBits.\r
1629\r
1630 @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
1631 @param Control Control signals of the serial device\r
1632\r
1633 @retval EFI_SUCCESS Get Control signals successfully\r
1634\r
1635**/\r
1636EFI_STATUS\r
1637EFIAPI\r
1638IsaSerialGetControl (\r
1639 IN EFI_SERIAL_IO_PROTOCOL *This,\r
1640 OUT UINT32 *Control\r
1641 )\r
1642{\r
1643 SERIAL_DEV *SerialDevice;\r
1644 SERIAL_PORT_MSR Msr;\r
1645 SERIAL_PORT_MCR Mcr;\r
1646 EFI_TPL Tpl;\r
1647\r
1648 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1649\r
1650 SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
1651\r
1652 *Control = 0;\r
1653\r
1654 //\r
1655 // Read the Modem Status Register\r
1656 //\r
1657 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1658\r
1659 if (Msr.Bits.Cts == 1) {\r
1660 *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
1661 }\r
1662\r
1663 if (Msr.Bits.Dsr == 1) {\r
1664 *Control |= EFI_SERIAL_DATA_SET_READY;\r
1665 }\r
1666\r
1667 if (Msr.Bits.Ri == 1) {\r
1668 *Control |= EFI_SERIAL_RING_INDICATE;\r
1669 }\r
1670\r
1671 if (Msr.Bits.Dcd == 1) {\r
1672 *Control |= EFI_SERIAL_CARRIER_DETECT;\r
1673 }\r
1674 //\r
1675 // Read the Modem Control Register\r
1676 //\r
1677 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1678\r
1679 if (Mcr.Bits.DtrC == 1) {\r
1680 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
1681 }\r
1682\r
1683 if (Mcr.Bits.Rts == 1) {\r
1684 *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
1685 }\r
1686\r
1687 if (Mcr.Bits.Lme == 1) {\r
1688 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;\r
1689 }\r
1690\r
1691 if (SerialDevice->HardwareFlowControl) {\r
1692 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
1693 }\r
1694 //\r
1695 // See if the Transmit FIFO is empty\r
1696 //\r
1697 IsaSerialReceiveTransmit (SerialDevice);\r
1698\r
1699 if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
1700 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
1701 }\r
1702 //\r
1703 // See if the Receive FIFO is empty.\r
1704 //\r
1705 IsaSerialReceiveTransmit (SerialDevice);\r
1706\r
1707 if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {\r
1708 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
1709 }\r
1710\r
1711 if (SerialDevice->SoftwareLoopbackEnable) {\r
1712 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
1713 }\r
1714\r
1715 gBS->RestoreTPL (Tpl);\r
1716\r
1717 return EFI_SUCCESS;\r
1718}\r
1719\r
1720/**\r
1721 Write the specified number of bytes to serial device.\r
1722\r
1723 @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
1724 @param BufferSize On input the size of Buffer, on output the amount of\r
1725 data actually written\r
1726 @param Buffer The buffer of data to write\r
1727\r
1728 @retval EFI_SUCCESS The data were written successfully\r
1729 @retval EFI_DEVICE_ERROR The device reported an error\r
1730 @retval EFI_TIMEOUT The write operation was stopped due to timeout\r
1731\r
1732**/\r
1733EFI_STATUS\r
1734EFIAPI\r
1735IsaSerialWrite (\r
1736 IN EFI_SERIAL_IO_PROTOCOL *This,\r
1737 IN OUT UINTN *BufferSize,\r
1738 IN VOID *Buffer\r
1739 )\r
1740{\r
1741 SERIAL_DEV *SerialDevice;\r
1742 UINT8 *CharBuffer;\r
1743 UINT32 Index;\r
1744 UINTN Elapsed;\r
1745 UINTN ActualWrite;\r
1746 EFI_TPL Tpl;\r
1747\r
1748 SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
1749 Elapsed = 0;\r
1750 ActualWrite = 0;\r
1751\r
1752 if (*BufferSize == 0) {\r
1753 return EFI_SUCCESS;\r
1754 }\r
1755\r
1756 if (Buffer == NULL) {\r
1757 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1758 EFI_ERROR_CODE,\r
1759 EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
1760 SerialDevice->DevicePath\r
1761 );\r
1762\r
1763 return EFI_DEVICE_ERROR;\r
1764 }\r
1765\r
1766 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1767\r
1768 CharBuffer = (UINT8 *) Buffer;\r
1769\r
1770 for (Index = 0; Index < *BufferSize; Index++) {\r
1771 IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);\r
1772\r
1773 while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {\r
1774 //\r
1775 // Unsuccessful write so check if timeout has expired, if not,\r
1776 // stall for a bit, increment time elapsed, and try again\r
1777 //\r
1778 if (Elapsed >= This->Mode->Timeout) {\r
1779 *BufferSize = ActualWrite;\r
1780 gBS->RestoreTPL (Tpl);\r
1781 return EFI_TIMEOUT;\r
1782 }\r
1783\r
1784 gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
1785\r
1786 Elapsed += TIMEOUT_STALL_INTERVAL;\r
1787 }\r
1788\r
1789 ActualWrite++;\r
1790 //\r
1791 // Successful write so reset timeout\r
1792 //\r
1793 Elapsed = 0;\r
1794 }\r
1795\r
1796 gBS->RestoreTPL (Tpl);\r
1797\r
1798 return EFI_SUCCESS;\r
1799}\r
1800\r
1801/**\r
1802 Read the specified number of bytes from serial device.\r
1803\r
1804 @param This Pointer to EFI_SERIAL_IO_PROTOCOL\r
1805 @param BufferSize On input the size of Buffer, on output the amount of\r
1806 data returned in buffer\r
1807 @param Buffer The buffer to return the data into\r
1808\r
1809 @retval EFI_SUCCESS The data were read successfully\r
1810 @retval EFI_DEVICE_ERROR The device reported an error\r
1811 @retval EFI_TIMEOUT The read operation was stopped due to timeout\r
1812\r
1813**/\r
1814EFI_STATUS\r
1815EFIAPI\r
1816IsaSerialRead (\r
1817 IN EFI_SERIAL_IO_PROTOCOL *This,\r
1818 IN OUT UINTN *BufferSize,\r
1819 OUT VOID *Buffer\r
1820 )\r
1821{\r
1822 SERIAL_DEV *SerialDevice;\r
1823 UINT32 Index;\r
1824 UINT8 *CharBuffer;\r
1825 UINTN Elapsed;\r
1826 EFI_STATUS Status;\r
1827 EFI_TPL Tpl;\r
1828\r
1829 SerialDevice = SERIAL_DEV_FROM_THIS (This);\r
1830 Elapsed = 0;\r
1831\r
1832 if (*BufferSize == 0) {\r
1833 return EFI_SUCCESS;\r
1834 }\r
1835\r
1836 if (Buffer == NULL) {\r
1837 return EFI_DEVICE_ERROR;\r
1838 }\r
1839\r
1840 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1841\r
1842 Status = IsaSerialReceiveTransmit (SerialDevice);\r
1843\r
1844 if (EFI_ERROR (Status)) {\r
1845 *BufferSize = 0;\r
1846\r
1847 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1848 EFI_ERROR_CODE,\r
1849 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
1850 SerialDevice->DevicePath\r
1851 );\r
1852\r
1853 gBS->RestoreTPL (Tpl);\r
1854\r
1855 return EFI_DEVICE_ERROR;\r
1856 }\r
1857\r
1858 CharBuffer = (UINT8 *) Buffer;\r
1859 for (Index = 0; Index < *BufferSize; Index++) {\r
1860 while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {\r
1861 //\r
1862 // Unsuccessful read so check if timeout has expired, if not,\r
1863 // stall for a bit, increment time elapsed, and try again\r
1864 // Need this time out to get conspliter to work.\r
1865 //\r
1866 if (Elapsed >= This->Mode->Timeout) {\r
1867 *BufferSize = Index;\r
1868 gBS->RestoreTPL (Tpl);\r
1869 return EFI_TIMEOUT;\r
1870 }\r
1871\r
1872 gBS->Stall (TIMEOUT_STALL_INTERVAL);\r
1873 Elapsed += TIMEOUT_STALL_INTERVAL;\r
1874\r
1875 Status = IsaSerialReceiveTransmit (SerialDevice);\r
1876 if (Status == EFI_DEVICE_ERROR) {\r
1877 *BufferSize = Index;\r
1878 gBS->RestoreTPL (Tpl);\r
1879 return EFI_DEVICE_ERROR;\r
1880 }\r
1881 }\r
1882 //\r
1883 // Successful read so reset timeout\r
1884 //\r
1885 Elapsed = 0;\r
1886 }\r
1887\r
1888 IsaSerialReceiveTransmit (SerialDevice);\r
1889\r
1890 gBS->RestoreTPL (Tpl);\r
1891\r
1892 return EFI_SUCCESS;\r
1893}\r
1894\r
1895/**\r
1896 Use scratchpad register to test if this serial port is present.\r
1897\r
1898 @param SerialDevice Pointer to serial device structure\r
1899\r
1900 @return if this serial port is present\r
1901**/\r
1902BOOLEAN\r
1903IsaSerialPortPresent (\r
1904 IN SERIAL_DEV *SerialDevice\r
1905 )\r
1906\r
1907{\r
1908 UINT8 Temp;\r
1909 BOOLEAN Status;\r
1910\r
1911 Status = TRUE;\r
1912\r
1913 //\r
1914 // Save SCR reg\r
1915 //\r
1916 Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);\r
1917 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);\r
1918\r
1919 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) {\r
1920 Status = FALSE;\r
1921 }\r
1922\r
1923 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);\r
1924\r
1925 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) {\r
1926 Status = FALSE;\r
1927 }\r
1928 //\r
1929 // Restore SCR\r
1930 //\r
1931 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);\r
1932 return Status;\r
1933}\r
1934\r
1935/**\r
1936 Use IsaIo protocol to read serial port.\r
1937\r
1938 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance\r
1939 @param BaseAddress Serial port register group base address\r
1940 @param Offset Offset in register group\r
1941\r
1942 @return Data read from serial port\r
1943\r
1944**/\r
1945UINT8\r
1946IsaSerialReadPort (\r
1947 IN EFI_ISA_IO_PROTOCOL *IsaIo,\r
1948 IN UINT16 BaseAddress,\r
1949 IN UINT32 Offset\r
1950 )\r
1951{\r
1952 UINT8 Data;\r
1953\r
1954 //\r
1955 // Use IsaIo to access IO\r
1956 //\r
1957 IsaIo->Io.Read (\r
1958 IsaIo,\r
1959 EfiIsaIoWidthUint8,\r
1960 BaseAddress + Offset,\r
1961 1,\r
1962 &Data\r
1963 );\r
1964 return Data;\r
1965}\r
1966\r
1967/**\r
1968 Use IsaIo protocol to write serial port.\r
1969\r
1970 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance\r
1971 @param BaseAddress Serial port register group base address\r
1972 @param Offset Offset in register group\r
1973 @param Data data which is to be written to some serial port register\r
1974\r
1975**/\r
1976VOID\r
1977IsaSerialWritePort (\r
1978 IN EFI_ISA_IO_PROTOCOL *IsaIo,\r
1979 IN UINT16 BaseAddress,\r
1980 IN UINT32 Offset,\r
1981 IN UINT8 Data\r
1982 )\r
1983{\r
1984 //\r
1985 // Use IsaIo to access IO\r
1986 //\r
1987 IsaIo->Io.Write (\r
1988 IsaIo,\r
1989 EfiIsaIoWidthUint8,\r
1990 BaseAddress + Offset,\r
1991 1,\r
1992 &Data\r
1993 );\r
1994}\r
1995\r