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