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