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