]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c
MdeModulePkg: Change OPTIONAL keyword usage style
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciSioSerialDxe / Serial.c
CommitLineData
a59e2ede
RN
1/** @file\r
2 Serial driver for PCI or SIO UARTS.\r
3\r
d1102dba 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
a59e2ede
RN
6\r
7**/\r
8\r
9#include "Serial.h"\r
10\r
11//\r
12// ISA Serial Driver Global Variables\r
13//\r
14\r
15EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {\r
16 SerialControllerDriverSupported,\r
17 SerialControllerDriverStart,\r
18 SerialControllerDriverStop,\r
19 0xa,\r
20 NULL,\r
21 NULL\r
22};\r
23\r
24CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = {\r
25 {\r
26 HARDWARE_DEVICE_PATH,\r
27 HW_CONTROLLER_DP,\r
83809dc0
MK
28 {\r
29 (UINT8) (sizeof (CONTROLLER_DEVICE_PATH)),\r
30 (UINT8) ((sizeof (CONTROLLER_DEVICE_PATH)) >> 8)\r
31 }\r
a59e2ede
RN
32 },\r
33 0\r
34};\r
35\r
36SERIAL_DEV gSerialDevTemplate = {\r
37 SERIAL_DEV_SIGNATURE,\r
38 NULL,\r
39 {\r
40 SERIAL_IO_INTERFACE_REVISION,\r
41 SerialReset,\r
42 SerialSetAttributes,\r
43 SerialSetControl,\r
44 SerialGetControl,\r
45 SerialWrite,\r
46 SerialRead,\r
47 NULL\r
48 }, // SerialIo\r
49 {\r
50 SERIAL_PORT_SUPPORT_CONTROL_MASK,\r
51 SERIAL_PORT_DEFAULT_TIMEOUT,\r
52 0,\r
53 16,\r
54 0,\r
55 0,\r
56 0\r
57 }, // SerialMode\r
58 NULL, // DevicePath\r
59 NULL, // ParentDevicePath\r
60 {\r
61 {\r
62 MESSAGING_DEVICE_PATH,\r
63 MSG_UART_DP,\r
64 {\r
65 (UINT8) (sizeof (UART_DEVICE_PATH)),\r
66 (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)\r
67 }\r
68 },\r
69 0, 0, 0, 0, 0\r
70 }, // UartDevicePath\r
71 0, // BaseAddress\r
72 FALSE, // MmioAccess\r
73 1, // RegisterStride\r
74 0, // ClockRate\r
75 16, // ReceiveFifoDepth\r
76 { 0, 0 }, // Receive;\r
77 16, // TransmitFifoDepth\r
78 { 0, 0 }, // Transmit;\r
79 FALSE, // SoftwareLoopbackEnable;\r
80 FALSE, // HardwareFlowControl;\r
81 NULL, // *ControllerNameTable;\r
82 FALSE, // ContainsControllerNode;\r
83 0, // Instance;\r
84 NULL // *PciDeviceInfo;\r
85};\r
86\r
87/**\r
88 Check the device path node whether it's the Flow Control node or not.\r
89\r
90 @param[in] FlowControl The device path node to be checked.\r
d1102dba 91\r
a59e2ede
RN
92 @retval TRUE It's the Flow Control node.\r
93 @retval FALSE It's not.\r
94\r
95**/\r
96BOOLEAN\r
97IsUartFlowControlDevicePathNode (\r
98 IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl\r
99 )\r
100{\r
101 return (BOOLEAN) (\r
102 (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&\r
103 (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&\r
104 (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))\r
105 );\r
106}\r
107\r
108/**\r
109 The user Entry Point for module PciSioSerial. The user code starts with this function.\r
110\r
d1102dba 111 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
a59e2ede 112 @param[in] SystemTable A pointer to the EFI System Table.\r
d1102dba 113\r
a59e2ede
RN
114 @retval EFI_SUCCESS The entry point is executed successfully.\r
115 @retval other Some error occurs when executing this entry point.\r
116\r
117**/\r
118EFI_STATUS\r
119EFIAPI\r
120InitializePciSioSerial (\r
121 IN EFI_HANDLE ImageHandle,\r
122 IN EFI_SYSTEM_TABLE *SystemTable\r
123 )\r
124{\r
125 EFI_STATUS Status;\r
126\r
127 //\r
128 // Install driver model protocol(s).\r
129 //\r
130 Status = EfiLibInstallDriverBindingComponentName2 (\r
131 ImageHandle,\r
132 SystemTable,\r
133 &gSerialControllerDriver,\r
134 ImageHandle,\r
135 &gPciSioSerialComponentName,\r
136 &gPciSioSerialComponentName2\r
137 );\r
138 ASSERT_EFI_ERROR (Status);\r
139\r
140 //\r
141 // Initialize UART default setting in gSerialDevTempate\r
142 //\r
143 gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
144 gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
145 gSerialDevTemplate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity);\r
146 gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
147 gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
148 gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
149 gSerialDevTemplate.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity);\r
150 gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
151 gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate);\r
152\r
153 return Status;\r
154}\r
155\r
156/**\r
157 Return whether the controller is a SIO serial controller.\r
158\r
159 @param Controller The controller handle.\r
160\r
161 @retval EFI_SUCCESS The controller is a SIO serial controller.\r
162 @retval others The controller is not a SIO serial controller.\r
163**/\r
164EFI_STATUS\r
165IsSioSerialController (\r
166 EFI_HANDLE Controller\r
167 )\r
168{\r
169 EFI_STATUS Status;\r
170 EFI_SIO_PROTOCOL *Sio;\r
171 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
172 ACPI_HID_DEVICE_PATH *Acpi;\r
173\r
174 //\r
175 // Open the IO Abstraction(s) needed to perform the supported test\r
176 //\r
177 Status = gBS->OpenProtocol (\r
178 Controller,\r
179 &gEfiSioProtocolGuid,\r
180 (VOID **) &Sio,\r
181 gSerialControllerDriver.DriverBindingHandle,\r
182 Controller,\r
183 EFI_OPEN_PROTOCOL_BY_DRIVER\r
184 );\r
185 if (Status == EFI_ALREADY_STARTED) {\r
186 return EFI_SUCCESS;\r
187 }\r
188\r
189 if (!EFI_ERROR (Status)) {\r
190 //\r
191 // Close the I/O Abstraction(s) used to perform the supported test\r
192 //\r
193 gBS->CloseProtocol (\r
194 Controller,\r
195 &gEfiSioProtocolGuid,\r
196 gSerialControllerDriver.DriverBindingHandle,\r
197 Controller\r
198 );\r
199\r
200 Status = gBS->OpenProtocol (\r
201 Controller,\r
202 &gEfiDevicePathProtocolGuid,\r
203 (VOID **) &DevicePath,\r
204 gSerialControllerDriver.DriverBindingHandle,\r
205 Controller,\r
206 EFI_OPEN_PROTOCOL_BY_DRIVER\r
207 );\r
208 ASSERT (Status != EFI_ALREADY_STARTED);\r
209\r
210 if (!EFI_ERROR (Status)) {\r
211 do {\r
212 Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;\r
213 DevicePath = NextDevicePathNode (DevicePath);\r
214 } while (!IsDevicePathEnd (DevicePath));\r
215\r
216 if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||\r
217 (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) ||\r
218 Acpi->HID != EISA_PNP_ID (0x501)\r
219 ) {\r
220 Status = EFI_UNSUPPORTED;\r
221 }\r
222 }\r
223\r
224 //\r
225 // Close protocol, don't use device path protocol in the Support() function\r
226 //\r
227 gBS->CloseProtocol (\r
228 Controller,\r
229 &gEfiDevicePathProtocolGuid,\r
230 gSerialControllerDriver.DriverBindingHandle,\r
231 Controller\r
232 );\r
233 }\r
234 return Status;\r
235}\r
236\r
237/**\r
238 Return whether the controller is a PCI serial controller.\r
239\r
240 @param Controller The controller handle.\r
241\r
242 @retval EFI_SUCCESS The controller is a PCI serial controller.\r
243 @retval others The controller is not a PCI serial controller.\r
244**/\r
245EFI_STATUS\r
246IsPciSerialController (\r
247 EFI_HANDLE Controller\r
248 )\r
249{\r
250 EFI_STATUS Status;\r
251 EFI_PCI_IO_PROTOCOL *PciIo;\r
252 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
253 PCI_TYPE00 Pci;\r
254 PCI_SERIAL_PARAMETER *PciSerialParameter;\r
255\r
256 //\r
257 // Open the IO Abstraction(s) needed to perform the supported test\r
258 //\r
259 Status = gBS->OpenProtocol (\r
260 Controller,\r
261 &gEfiPciIoProtocolGuid,\r
262 (VOID **) &PciIo,\r
263 gSerialControllerDriver.DriverBindingHandle,\r
264 Controller,\r
265 EFI_OPEN_PROTOCOL_BY_DRIVER\r
266 );\r
267 if (Status == EFI_ALREADY_STARTED) {\r
268 return EFI_SUCCESS;\r
269 }\r
270\r
271 if (!EFI_ERROR (Status)) {\r
272 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);\r
273 if (!EFI_ERROR (Status)) {\r
274 if (!IS_PCI_16550_SERIAL (&Pci)) {\r
275 for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters)\r
276 ; PciSerialParameter->VendorId != 0xFFFF\r
277 ; PciSerialParameter++\r
278 ) {\r
279 if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) &&\r
280 (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId)\r
281 ) {\r
282 break;\r
283 }\r
284 }\r
285 if (PciSerialParameter->VendorId == 0xFFFF) {\r
286 Status = EFI_UNSUPPORTED;\r
287 } else {\r
288 Status = EFI_SUCCESS;\r
289 }\r
290 }\r
291 }\r
292\r
293 //\r
294 // Close the I/O Abstraction(s) used to perform the supported test\r
295 //\r
296 gBS->CloseProtocol (\r
297 Controller,\r
298 &gEfiPciIoProtocolGuid,\r
299 gSerialControllerDriver.DriverBindingHandle,\r
300 Controller\r
301 );\r
302 }\r
303 if (EFI_ERROR (Status)) {\r
304 return Status;\r
305 }\r
306\r
307 //\r
308 // Open the EFI Device Path protocol needed to perform the supported test\r
309 //\r
310 Status = gBS->OpenProtocol (\r
311 Controller,\r
312 &gEfiDevicePathProtocolGuid,\r
313 (VOID **) &DevicePath,\r
314 gSerialControllerDriver.DriverBindingHandle,\r
315 Controller,\r
316 EFI_OPEN_PROTOCOL_BY_DRIVER\r
317 );\r
318 ASSERT (Status != EFI_ALREADY_STARTED);\r
319\r
320 //\r
321 // Close protocol, don't use device path protocol in the Support() function\r
322 //\r
323 gBS->CloseProtocol (\r
324 Controller,\r
325 &gEfiDevicePathProtocolGuid,\r
326 gSerialControllerDriver.DriverBindingHandle,\r
327 Controller\r
328 );\r
329\r
330 return Status;\r
331}\r
332\r
333/**\r
334 Check to see if this driver supports the given controller\r
335\r
336 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
337 @param Controller The handle of the controller to test.\r
338 @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
339\r
340 @return EFI_SUCCESS This driver can support the given controller\r
341\r
342**/\r
343EFI_STATUS\r
344EFIAPI\r
345SerialControllerDriverSupported (\r
346 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
347 IN EFI_HANDLE Controller,\r
348 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
349 )\r
350\r
351{\r
352 EFI_STATUS Status;\r
353 UART_DEVICE_PATH *Uart;\r
354 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
355\r
356 //\r
357 // Test RemainingDevicePath\r
358 //\r
359 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
360 Status = EFI_UNSUPPORTED;\r
361\r
362 Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL);\r
363 if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH ||\r
364 DevicePathSubType (Uart) != MSG_UART_DP ||\r
365 DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH)\r
366 ) {\r
367 return EFI_UNSUPPORTED;\r
368 }\r
369\r
370 //\r
371 // Do a rough check because Clock Rate is unknown until DriverBindingStart()\r
372 //\r
373 if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) {\r
374 return EFI_UNSUPPORTED;\r
375 }\r
376\r
377 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
378 if (IsUartFlowControlDevicePathNode (FlowControl)) {\r
379 //\r
380 // If the second node is Flow Control Node,\r
381 // return error when it request other than hardware flow control.\r
382 //\r
383 if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {\r
384 return EFI_UNSUPPORTED;\r
385 }\r
386 }\r
387 }\r
388\r
389 Status = IsSioSerialController (Controller);\r
390 if (EFI_ERROR (Status)) {\r
391 Status = IsPciSerialController (Controller);\r
392 }\r
d1102dba 393 return Status;\r
a59e2ede
RN
394}\r
395\r
396/**\r
397 Create the child serial device instance.\r
398\r
399 @param Controller The parent controller handle.\r
400 @param Uart Pointer to the UART device path node in RemainingDevicePath,\r
401 or NULL if RemainingDevicePath is NULL.\r
402 @param ParentDevicePath Pointer to the parent device path.\r
403 @param CreateControllerNode TRUE to create the controller node.\r
404 @param Instance Instance number of the serial device.\r
405 The value will be set to the controller node\r
406 if CreateControllerNode is TRUE.\r
407 @param ParentIo A union type pointer to either Sio or PciIo.\r
408 @param PciSerialParameter The PCI serial parameter to be used by current serial device.\r
409 NULL for SIO serial device.\r
410 @param PciDeviceInfo The PCI device info for the current serial device.\r
411 NULL for SIO serial device.\r
412\r
413 @retval EFI_SUCCESS The serial device was created successfully.\r
414 @retval others The serial device wasn't created.\r
415**/\r
416EFI_STATUS\r
417CreateSerialDevice (\r
418 IN EFI_HANDLE Controller,\r
419 IN UART_DEVICE_PATH *Uart,\r
420 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
421 IN BOOLEAN CreateControllerNode,\r
422 IN UINT32 Instance,\r
423 IN PARENT_IO_PROTOCOL_PTR ParentIo,\r
e3917e22 424 IN PCI_SERIAL_PARAMETER *PciSerialParameter OPTIONAL,\r
a59e2ede
RN
425 IN PCI_DEVICE_INFO *PciDeviceInfo OPTIONAL\r
426 )\r
427{\r
428 EFI_STATUS Status;\r
429 SERIAL_DEV *SerialDevice;\r
430 UINT8 BarIndex;\r
431 UINT64 Offset;\r
432 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
433 UINT32 FlowControlMap;\r
434 ACPI_RESOURCE_HEADER_PTR Resources;\r
435 EFI_ACPI_IO_PORT_DESCRIPTOR *Io;\r
436 EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;\r
437 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;\r
438 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
439\r
440 BarIndex = 0;\r
441 Offset = 0;\r
442 FlowControl = NULL;\r
443 FlowControlMap = 0;\r
444\r
445 //\r
446 // Initialize the serial device instance\r
447 //\r
448 SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate);\r
449 ASSERT (SerialDevice != NULL);\r
450\r
451 SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);\r
452 SerialDevice->ParentDevicePath = ParentDevicePath;\r
453 SerialDevice->PciDeviceInfo = PciDeviceInfo;\r
454 SerialDevice->Instance = Instance;\r
455\r
456 if (Uart != NULL) {\r
457 CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH));\r
458 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
459 if (IsUartFlowControlDevicePathNode (FlowControl)) {\r
460 FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);\r
461 } else {\r
462 FlowControl = NULL;\r
463 }\r
464 }\r
465\r
466 //\r
467 // For PCI serial device, use the information from PCD\r
468 //\r
469 if (PciSerialParameter != NULL) {\r
9b648323 470 BarIndex = (PciSerialParameter->BarIndex == MAX_UINT8) ? 0 : PciSerialParameter->BarIndex;\r
a59e2ede
RN
471 Offset = PciSerialParameter->Offset;\r
472 if (PciSerialParameter->RegisterStride != 0) {\r
473 SerialDevice->RegisterStride = PciSerialParameter->RegisterStride;\r
474 }\r
475 if (PciSerialParameter->ClockRate != 0) {\r
476 SerialDevice->ClockRate = PciSerialParameter->ClockRate;\r
477 }\r
478 if (PciSerialParameter->ReceiveFifoDepth != 0) {\r
479 SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth;\r
480 }\r
481 if (PciSerialParameter->TransmitFifoDepth != 0) {\r
482 SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth;\r
483 }\r
484 }\r
485\r
486 //\r
487 // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.\r
488 // DriverBindingStart() shouldn't create a handle with different UART device path.\r
489 //\r
490 if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits,\r
491 SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL\r
492 )) {\r
493 Status = EFI_INVALID_PARAMETER;\r
494 goto CreateError;\r
495 }\r
496\r
497 if (PciSerialParameter == NULL) {\r
498 Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources);\r
499 } else {\r
500 Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources);\r
501 }\r
502\r
503 if (!EFI_ERROR (Status)) {\r
504 //\r
505 // Get the base address information from ACPI resource descriptor.\r
506 // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio;\r
507 // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo.\r
508 //\r
509 while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) {\r
510 switch (Resources.SmallHeader->Byte) {\r
511 case ACPI_IO_PORT_DESCRIPTOR:\r
512 Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;\r
513 if (Io->Length != 0) {\r
514 SerialDevice->BaseAddress = Io->BaseAddressMin;\r
515 }\r
516 break;\r
517\r
518 case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:\r
519 FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;\r
520 if (FixedIo->Length != 0) {\r
521 SerialDevice->BaseAddress = FixedIo->BaseAddress;\r
522 }\r
523 break;\r
524\r
525 case ACPI_ADDRESS_SPACE_DESCRIPTOR:\r
526 AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader;\r
527 if (AddressSpace->AddrLen != 0) {\r
528 if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
529 SerialDevice->MmioAccess = TRUE;\r
530 }\r
531 SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset;\r
532 }\r
533 break;\r
534 }\r
535\r
536 if (Resources.SmallHeader->Bits.Type == 0) {\r
537 Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader\r
538 + Resources.SmallHeader->Bits.Length\r
539 + sizeof (*Resources.SmallHeader));\r
540 } else {\r
541 Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader\r
542 + Resources.LargeHeader->Length\r
543 + sizeof (*Resources.LargeHeader));\r
544 }\r
545 }\r
546 }\r
547\r
548 if (SerialDevice->BaseAddress == 0) {\r
549 Status = EFI_INVALID_PARAMETER;\r
550 goto CreateError;\r
551 }\r
552\r
553 SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);\r
554\r
555 //\r
556 // Report status code the serial present\r
557 //\r
558 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
559 EFI_PROGRESS_CODE,\r
560 EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,\r
561 SerialDevice->ParentDevicePath\r
562 );\r
563\r
564 if (!SerialPresent (SerialDevice)) {\r
565 Status = EFI_DEVICE_ERROR;\r
566 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
567 EFI_ERROR_CODE,\r
568 EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,\r
569 SerialDevice->ParentDevicePath\r
570 );\r
571 goto CreateError;\r
572 }\r
573\r
574 //\r
575 // 1. Append Controller device path node.\r
576 //\r
577 if (CreateControllerNode) {\r
578 mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance;\r
579 SerialDevice->DevicePath = AppendDevicePathNode (\r
580 SerialDevice->ParentDevicePath,\r
581 (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate\r
582 );\r
583 SerialDevice->ContainsControllerNode = TRUE;\r
584 }\r
585\r
586 //\r
587 // 2. Append UART device path node.\r
588 // The Uart setings are zero here.\r
589 // SetAttribute() will update them to match the default setings.\r
590 //\r
591 TempDevicePath = SerialDevice->DevicePath;\r
592 if (TempDevicePath != NULL) {\r
593 SerialDevice->DevicePath = AppendDevicePathNode (\r
594 TempDevicePath,\r
595 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
596 );\r
597 FreePool (TempDevicePath);\r
598 } else {\r
599 SerialDevice->DevicePath = AppendDevicePathNode (\r
600 SerialDevice->ParentDevicePath,\r
601 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath\r
602 );\r
603 }\r
604 //\r
605 // 3. Append the Flow Control device path node.\r
606 // Only produce the Flow Control node when remaining device path has it\r
607 //\r
608 if (FlowControl != NULL) {\r
609 TempDevicePath = SerialDevice->DevicePath;\r
610 if (TempDevicePath != NULL) {\r
611 SerialDevice->DevicePath = AppendDevicePathNode (\r
612 TempDevicePath,\r
613 (EFI_DEVICE_PATH_PROTOCOL *) FlowControl\r
614 );\r
615 FreePool (TempDevicePath);\r
616 }\r
617 }\r
618 ASSERT (SerialDevice->DevicePath != NULL);\r
619\r
620 //\r
621 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.\r
622 //\r
623 SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;\r
624 SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;\r
625 SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity;\r
626 SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;\r
627\r
628 //\r
629 // Issue a reset to initialize the COM port\r
630 //\r
631 Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);\r
632 if (EFI_ERROR (Status)) {\r
633 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
634 EFI_ERROR_CODE,\r
635 EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,\r
636 SerialDevice->DevicePath\r
637 );\r
638 goto CreateError;\r
639 }\r
640\r
641 AddName (SerialDevice, Instance);\r
642 //\r
643 // Install protocol interfaces for the serial device.\r
644 //\r
645 Status = gBS->InstallMultipleProtocolInterfaces (\r
646 &SerialDevice->Handle,\r
647 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
648 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
649 NULL\r
650 );\r
651 if (EFI_ERROR (Status)) {\r
652 goto CreateError;\r
653 }\r
654 //\r
655 // Open For Child Device\r
656 //\r
657 Status = gBS->OpenProtocol (\r
658 Controller,\r
659 PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
660 (VOID **) &ParentIo,\r
661 gSerialControllerDriver.DriverBindingHandle,\r
662 SerialDevice->Handle,\r
663 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
664 );\r
665\r
666 if (EFI_ERROR (Status)) {\r
667 gBS->UninstallMultipleProtocolInterfaces (\r
9388c6b1 668 SerialDevice->Handle,\r
a59e2ede
RN
669 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
670 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
671 NULL\r
672 );\r
673 }\r
674\r
675CreateError:\r
676 if (EFI_ERROR (Status)) {\r
677 if (SerialDevice->DevicePath != NULL) {\r
678 FreePool (SerialDevice->DevicePath);\r
679 }\r
680 if (SerialDevice->ControllerNameTable != NULL) {\r
681 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
682 }\r
683 FreePool (SerialDevice);\r
684 }\r
685 return Status;\r
686}\r
687\r
688/**\r
689 Returns an array of pointers containing all the child serial device pointers.\r
690\r
691 @param Controller The parent controller handle.\r
692 @param IoProtocolGuid The protocol GUID, either equals to gEfiSioProtocolGuid\r
693 or equals to gEfiPciIoProtocolGuid.\r
694 @param Count Count of the serial devices.\r
695\r
696 @return An array of pointers containing all the child serial device pointers.\r
697**/\r
698SERIAL_DEV **\r
699GetChildSerialDevices (\r
700 IN EFI_HANDLE Controller,\r
701 IN EFI_GUID *IoProtocolGuid,\r
702 OUT UINTN *Count\r
703 )\r
704{\r
705 EFI_STATUS Status;\r
706 UINTN Index;\r
707 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
708 UINTN EntryCount;\r
709 SERIAL_DEV **SerialDevices;\r
710 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
711 BOOLEAN OpenByDriver;\r
712\r
713 *Count = 0;\r
714 //\r
715 // If the SerialIo instance specified by RemainingDevicePath is already created,\r
716 // update the attributes/control.\r
717 //\r
718 Status = gBS->OpenProtocolInformation (\r
719 Controller,\r
720 IoProtocolGuid,\r
721 &OpenInfoBuffer,\r
722 &EntryCount\r
723 );\r
724 if (EFI_ERROR (Status)) {\r
725 return NULL;\r
726 }\r
727\r
728 SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *));\r
729 ASSERT (SerialDevices != NULL);\r
730\r
731 *Count = 0;\r
732 OpenByDriver = FALSE;\r
733 for (Index = 0; Index < EntryCount; Index++) {\r
734 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
735 Status = gBS->OpenProtocol (\r
736 OpenInfoBuffer[Index].ControllerHandle,\r
737 &gEfiSerialIoProtocolGuid,\r
738 (VOID **) &SerialIo,\r
739 gSerialControllerDriver.DriverBindingHandle,\r
740 Controller,\r
741 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
742 );\r
743 if (!EFI_ERROR (Status)) {\r
744 SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo);\r
745 }\r
746 }\r
747\r
748\r
749 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
750 ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle);\r
751 OpenByDriver = TRUE;\r
752 }\r
753 }\r
754 if (OpenInfoBuffer != NULL) {\r
755 FreePool (OpenInfoBuffer);\r
756 }\r
757\r
758 ASSERT ((*Count == 0) || (OpenByDriver));\r
759\r
760 return SerialDevices;\r
761}\r
762\r
763/**\r
764 Start to management the controller passed in\r
765\r
766 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
767 @param Controller The handle of the controller to test.\r
768 @param RemainingDevicePath A pointer to the remaining portion of a device path.\r
769\r
770 @return EFI_SUCCESS Driver is started successfully\r
771**/\r
772EFI_STATUS\r
773EFIAPI\r
774SerialControllerDriverStart (\r
775 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
776 IN EFI_HANDLE Controller,\r
777 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
778 )\r
779{\r
780 EFI_STATUS Status;\r
781 UINTN Index;\r
782 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
783 EFI_DEVICE_PATH_PROTOCOL *Node;\r
784 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
785 UINT32 ControllerNumber;\r
786 UART_DEVICE_PATH *Uart;\r
787 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;\r
788 UINT32 Control;\r
789 PARENT_IO_PROTOCOL_PTR ParentIo;\r
790 ACPI_HID_DEVICE_PATH *Acpi;\r
791 EFI_GUID *IoProtocolGuid;\r
792 PCI_SERIAL_PARAMETER *PciSerialParameter;\r
793 PCI_SERIAL_PARAMETER DefaultPciSerialParameter;\r
794 PCI_TYPE00 Pci;\r
795 UINT32 PciSerialCount;\r
796 SERIAL_DEV **SerialDevices;\r
797 UINTN SerialDeviceCount;\r
798 PCI_DEVICE_INFO *PciDeviceInfo;\r
799 UINT64 Supports;\r
800 BOOLEAN ContainsControllerNode;\r
801\r
802 //\r
803 // Get the Parent Device Path\r
804 //\r
805 Status = gBS->OpenProtocol (\r
806 Controller,\r
807 &gEfiDevicePathProtocolGuid,\r
808 (VOID **) &ParentDevicePath,\r
809 This->DriverBindingHandle,\r
810 Controller,\r
811 EFI_OPEN_PROTOCOL_BY_DRIVER\r
812 );\r
813 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
814 return Status;\r
815 }\r
816 //\r
817 // Report status code enable the serial\r
818 //\r
819 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
820 EFI_PROGRESS_CODE,\r
821 EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
822 ParentDevicePath\r
823 );\r
824\r
825 //\r
826 // Grab the IO abstraction we need to get any work done\r
827 //\r
828 IoProtocolGuid = &gEfiSioProtocolGuid;\r
829 Status = gBS->OpenProtocol (\r
830 Controller,\r
831 IoProtocolGuid,\r
832 (VOID **) &ParentIo,\r
833 This->DriverBindingHandle,\r
834 Controller,\r
835 EFI_OPEN_PROTOCOL_BY_DRIVER\r
836 );\r
837 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
838 IoProtocolGuid = &gEfiPciIoProtocolGuid;\r
839 Status = gBS->OpenProtocol (\r
840 Controller,\r
841 IoProtocolGuid,\r
842 (VOID **) &ParentIo,\r
843 This->DriverBindingHandle,\r
844 Controller,\r
845 EFI_OPEN_PROTOCOL_BY_DRIVER\r
846 );\r
847 }\r
848 ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);\r
849\r
850 //\r
851 // Do nothing for END device path node\r
852 //\r
853 if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
854 return EFI_SUCCESS;\r
855 }\r
856\r
83809dc0
MK
857 ControllerNumber = 0;\r
858 ContainsControllerNode = FALSE;\r
a59e2ede 859 SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);\r
4ab04a72
RN
860\r
861 if (SerialDeviceCount != 0) {\r
862 if (RemainingDevicePath == NULL) {\r
863 //\r
864 // If the SerialIo instance is already created, NULL as RemainingDevicePath is treated\r
865 // as to create the same SerialIo instance.\r
866 //\r
867 return EFI_SUCCESS;\r
868 } else {\r
869 //\r
870 // Update the attributes/control of the SerialIo instance specified by RemainingDevicePath.\r
871 //\r
872 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
873 for (Index = 0; Index < SerialDeviceCount; Index++) {\r
874 ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL));\r
875 if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||\r
876 (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)\r
877 ) {\r
878 SerialIo = &SerialDevices[Index]->SerialIo;\r
879 Status = EFI_INVALID_PARAMETER;\r
880 //\r
881 // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.\r
882 // DriverBindingStart() shouldn't create a handle with different UART device path.\r
883 //\r
884 if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,\r
885 (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {\r
886 Status = SerialIo->SetAttributes (\r
887 SerialIo,\r
888 Uart->BaudRate,\r
889 SerialIo->Mode->ReceiveFifoDepth,\r
890 SerialIo->Mode->Timeout,\r
891 (EFI_PARITY_TYPE) Uart->Parity,\r
892 Uart->DataBits,\r
893 (EFI_STOP_BITS_TYPE) Uart->StopBits\r
894 );\r
895 }\r
896 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
897 if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {\r
898 Status = SerialIo->GetControl (SerialIo, &Control);\r
899 if (!EFI_ERROR (Status)) {\r
900 if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {\r
901 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
902 } else {\r
903 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
904 }\r
905 //\r
906 // Clear the bits that are not allowed to pass to SetControl\r
907 //\r
908 Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
909 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |\r
910 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);\r
911 Status = SerialIo->SetControl (SerialIo, Control);\r
a59e2ede 912 }\r
a59e2ede 913 }\r
4ab04a72 914 break;\r
a59e2ede 915 }\r
a59e2ede 916 }\r
4ab04a72
RN
917 if (Index != SerialDeviceCount) {\r
918 //\r
919 // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.\r
920 // Otherwise continue to create the instance specified by RemainingDevicePath.\r
921 //\r
922 if (SerialDevices != NULL) {\r
923 FreePool (SerialDevices);\r
924 }\r
925 return Status;\r
a59e2ede 926 }\r
a59e2ede 927 }\r
77557b76 928 }\r
a59e2ede
RN
929\r
930 if (RemainingDevicePath != NULL) {\r
931 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
932 } else {\r
933 Uart = NULL;\r
934 }\r
935\r
936 PciDeviceInfo = NULL;\r
937 if (IoProtocolGuid == &gEfiSioProtocolGuid) {\r
938 Status = EFI_NOT_FOUND;\r
939 if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
940 Node = ParentDevicePath;\r
941 do {\r
942 Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
943 Node = NextDevicePathNode (Node);\r
944 } while (!IsDevicePathEnd (Node));\r
945 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);\r
87000d77 946 DEBUG ((DEBUG_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));\r
a59e2ede
RN
947 }\r
948 } else {\r
949 Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);\r
950 if (!EFI_ERROR (Status)) {\r
951 //\r
952 // PcdPciSerialParameters takes the higher priority.\r
953 //\r
954 PciSerialCount = 0;\r
955 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
956 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
957 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)\r
958 ) {\r
959 PciSerialCount++;\r
960 }\r
961 }\r
962\r
963 if (SerialDeviceCount == 0) {\r
964 //\r
965 // Enable the IO & MEM decoding when creating the first child.\r
966 // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).\r
967 //\r
968 PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));\r
12f5ff97 969 ASSERT (PciDeviceInfo != NULL);\r
a59e2ede
RN
970 PciDeviceInfo->ChildCount = 0;\r
971 PciDeviceInfo->PciIo = ParentIo.PciIo;\r
972 Status = ParentIo.PciIo->Attributes (\r
973 ParentIo.PciIo,\r
974 EfiPciIoAttributeOperationGet,\r
975 0,\r
976 &PciDeviceInfo->PciAttributes\r
977 );\r
978\r
979 if (!EFI_ERROR (Status)) {\r
980 Status = ParentIo.PciIo->Attributes (\r
981 ParentIo.PciIo,\r
982 EfiPciIoAttributeOperationSupported,\r
983 0,\r
984 &Supports\r
985 );\r
986 if (!EFI_ERROR (Status)) {\r
d14198b3 987 Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);\r
a59e2ede
RN
988 Status = ParentIo.PciIo->Attributes (\r
989 ParentIo.PciIo,\r
990 EfiPciIoAttributeOperationEnable,\r
991 Supports,\r
992 NULL\r
993 );\r
994 }\r
995 }\r
996 } else {\r
997 //\r
998 // Re-use the PciDeviceInfo stored in existing children.\r
999 //\r
12f5ff97 1000 ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL));\r
a59e2ede
RN
1001 PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;\r
1002 ASSERT (PciDeviceInfo != NULL);\r
1003 }\r
1004\r
1005 Status = EFI_NOT_FOUND;\r
1006 if (PciSerialCount <= 1) {\r
1007 //\r
1008 // PCI serial device contains only one UART\r
1009 //\r
1010 if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
1011 //\r
1012 // This PCI serial device is matched by class code in Supported()\r
1013 //\r
1014 if (PciSerialCount == 0) {\r
1015 DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;\r
1016 DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;\r
1017 DefaultPciSerialParameter.BarIndex = 0;\r
1018 DefaultPciSerialParameter.Offset = 0;\r
1019 DefaultPciSerialParameter.RegisterStride = 0;\r
1020 DefaultPciSerialParameter.ClockRate = 0;\r
1021 PciSerialParameter = &DefaultPciSerialParameter;\r
1022 } else if (PciSerialCount == 1) {\r
1023 PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);\r
1024 }\r
1025\r
1026 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);\r
87000d77 1027 DEBUG ((DEBUG_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));\r
a59e2ede
RN
1028 if (!EFI_ERROR (Status)) {\r
1029 PciDeviceInfo->ChildCount++;\r
1030 }\r
1031 }\r
1032 } else {\r
1033 //\r
1034 // PCI serial device contains multiple UARTs\r
1035 //\r
1036 if (RemainingDevicePath == NULL || ContainsControllerNode) {\r
1037 PciSerialCount = 0;\r
1038 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
1039 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
1040 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&\r
1041 ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))\r
1042 ) {\r
1043 //\r
1044 // Create controller node when PCI serial device contains multiple UARTs\r
1045 //\r
1046 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);\r
1047 PciSerialCount++;\r
87000d77 1048 DEBUG ((DEBUG_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));\r
a59e2ede
RN
1049 if (!EFI_ERROR (Status)) {\r
1050 PciDeviceInfo->ChildCount++;\r
1051 }\r
1052 }\r
1053 }\r
1054 }\r
1055 }\r
1056 }\r
1057 }\r
1058\r
1059 if (SerialDevices != NULL) {\r
1060 FreePool (SerialDevices);\r
1061 }\r
1062\r
1063 //\r
1064 // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully\r
1065 //\r
1066 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {\r
1067 Status = EFI_SUCCESS;\r
1068 }\r
1069\r
1070 if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {\r
1071 if (PciDeviceInfo != NULL) {\r
1072 Status = ParentIo.PciIo->Attributes (\r
1073 ParentIo.PciIo,\r
1074 EfiPciIoAttributeOperationSet,\r
1075 PciDeviceInfo->PciAttributes,\r
1076 NULL\r
1077 );\r
1078 ASSERT_EFI_ERROR (Status);\r
1079 FreePool (PciDeviceInfo);\r
1080 }\r
1081 gBS->CloseProtocol (\r
1082 Controller,\r
1083 &gEfiDevicePathProtocolGuid,\r
1084 This->DriverBindingHandle,\r
1085 Controller\r
1086 );\r
1087 gBS->CloseProtocol (\r
1088 Controller,\r
1089 IoProtocolGuid,\r
1090 This->DriverBindingHandle,\r
1091 Controller\r
1092 );\r
1093 }\r
1094\r
1095 return Status;\r
1096}\r
1097\r
1098/**\r
1099 Disconnect this driver with the controller, uninstall related protocol instance\r
1100\r
1101 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1102 @param Controller The handle of the controller to test.\r
1103 @param NumberOfChildren Number of child device.\r
1104 @param ChildHandleBuffer A pointer to the remaining portion of a device path.\r
1105\r
1106 @retval EFI_SUCCESS Operation successfully\r
1107 @retval EFI_DEVICE_ERROR Cannot stop the driver successfully\r
1108\r
1109**/\r
1110EFI_STATUS\r
1111EFIAPI\r
1112SerialControllerDriverStop (\r
1113 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1114 IN EFI_HANDLE Controller,\r
1115 IN UINTN NumberOfChildren,\r
1116 IN EFI_HANDLE *ChildHandleBuffer\r
1117 )\r
1118\r
1119{\r
1120 EFI_STATUS Status;\r
1121 UINTN Index;\r
1122 BOOLEAN AllChildrenStopped;\r
1123 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
1124 SERIAL_DEV *SerialDevice;\r
1125 VOID *IoProtocol;\r
1126 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1127 PCI_DEVICE_INFO *PciDeviceInfo;\r
1128\r
1129 PciDeviceInfo = NULL;\r
1130\r
1131 Status = gBS->HandleProtocol (\r
1132 Controller,\r
1133 &gEfiDevicePathProtocolGuid,\r
1134 (VOID **) &DevicePath\r
1135 );\r
1136\r
1137 //\r
1138 // Report the status code disable the serial\r
1139 //\r
1140 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1141 EFI_PROGRESS_CODE,\r
1142 EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
1143 DevicePath\r
1144 );\r
1145\r
1146 if (NumberOfChildren == 0) {\r
1147 //\r
1148 // Close the bus driver\r
1149 //\r
1150 Status = gBS->OpenProtocol (\r
1151 Controller,\r
1152 &gEfiPciIoProtocolGuid,\r
1153 &IoProtocol,\r
1154 This->DriverBindingHandle,\r
1155 Controller,\r
1156 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
1157 );\r
1158 gBS->CloseProtocol (\r
1159 Controller,\r
1160 !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
1161 This->DriverBindingHandle,\r
1162 Controller\r
1163 );\r
1164\r
1165 gBS->CloseProtocol (\r
1166 Controller,\r
1167 &gEfiDevicePathProtocolGuid,\r
1168 This->DriverBindingHandle,\r
1169 Controller\r
1170 );\r
1171 return EFI_SUCCESS;\r
1172 }\r
1173\r
1174 AllChildrenStopped = TRUE;\r
1175\r
1176 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1177\r
1178 Status = gBS->OpenProtocol (\r
1179 ChildHandleBuffer[Index],\r
1180 &gEfiSerialIoProtocolGuid,\r
1181 (VOID **) &SerialIo,\r
1182 This->DriverBindingHandle,\r
1183 Controller,\r
1184 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1185 );\r
1186 if (!EFI_ERROR (Status)) {\r
1187\r
1188 SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);\r
1189 ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));\r
1190 PciDeviceInfo = SerialDevice->PciDeviceInfo;\r
1191\r
1192 Status = gBS->CloseProtocol (\r
1193 Controller,\r
1194 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
1195 This->DriverBindingHandle,\r
1196 ChildHandleBuffer[Index]\r
1197 );\r
1198\r
1199 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1200 ChildHandleBuffer[Index],\r
1201 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
1202 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
1203 NULL\r
1204 );\r
1205 if (EFI_ERROR (Status)) {\r
1206 gBS->OpenProtocol (\r
1207 Controller,\r
1208 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
1209 &IoProtocol,\r
1210 This->DriverBindingHandle,\r
1211 ChildHandleBuffer[Index],\r
1212 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1213 );\r
1214 } else {\r
1215 FreePool (SerialDevice->DevicePath);\r
1216 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
1217 FreePool (SerialDevice);\r
1218\r
1219 if (PciDeviceInfo != NULL) {\r
1220 ASSERT (PciDeviceInfo->ChildCount != 0);\r
1221 PciDeviceInfo->ChildCount--;\r
1222 }\r
1223 }\r
1224 }\r
1225\r
1226 if (EFI_ERROR (Status)) {\r
1227 AllChildrenStopped = FALSE;\r
1228 }\r
1229 }\r
1230\r
1231 if (!AllChildrenStopped) {\r
1232 return EFI_DEVICE_ERROR;\r
1233 } else {\r
1234 //\r
1235 // If all children are destroyed, restore the PCI attributes.\r
1236 //\r
1237 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {\r
1238 ASSERT (PciDeviceInfo->PciIo != NULL);\r
1239 Status = PciDeviceInfo->PciIo->Attributes (\r
1240 PciDeviceInfo->PciIo,\r
1241 EfiPciIoAttributeOperationSet,\r
1242 PciDeviceInfo->PciAttributes,\r
1243 NULL\r
1244 );\r
1245 ASSERT_EFI_ERROR (Status);\r
1246 FreePool (PciDeviceInfo);\r
1247 }\r
1248 return EFI_SUCCESS;\r
1249 }\r
1250}\r