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