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