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