]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c
MdeModulePkg/PciSioSerial: Fix bad EOL
[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
4ab04a72 4Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
a59e2ede
RN
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 865 SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);\r
4ab04a72
RN
866\r
867 if (SerialDeviceCount != 0) {\r
868 if (RemainingDevicePath == NULL) {\r
869 //\r
870 // If the SerialIo instance is already created, NULL as RemainingDevicePath is treated\r
871 // as to create the same SerialIo instance.\r
872 //\r
873 return EFI_SUCCESS;\r
874 } else {\r
875 //\r
876 // Update the attributes/control of the SerialIo instance specified by RemainingDevicePath.\r
877 //\r
878 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
879 for (Index = 0; Index < SerialDeviceCount; Index++) {\r
880 ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL));\r
881 if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||\r
882 (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)\r
883 ) {\r
884 SerialIo = &SerialDevices[Index]->SerialIo;\r
885 Status = EFI_INVALID_PARAMETER;\r
886 //\r
887 // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.\r
888 // DriverBindingStart() shouldn't create a handle with different UART device path.\r
889 //\r
890 if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,\r
891 (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {\r
892 Status = SerialIo->SetAttributes (\r
893 SerialIo,\r
894 Uart->BaudRate,\r
895 SerialIo->Mode->ReceiveFifoDepth,\r
896 SerialIo->Mode->Timeout,\r
897 (EFI_PARITY_TYPE) Uart->Parity,\r
898 Uart->DataBits,\r
899 (EFI_STOP_BITS_TYPE) Uart->StopBits\r
900 );\r
901 }\r
902 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);\r
903 if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) {\r
904 Status = SerialIo->GetControl (SerialIo, &Control);\r
905 if (!EFI_ERROR (Status)) {\r
906 if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {\r
907 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
908 } else {\r
909 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
910 }\r
911 //\r
912 // Clear the bits that are not allowed to pass to SetControl\r
913 //\r
914 Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |\r
915 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |\r
916 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);\r
917 Status = SerialIo->SetControl (SerialIo, Control);\r
a59e2ede 918 }\r
a59e2ede 919 }\r
4ab04a72 920 break;\r
a59e2ede 921 }\r
a59e2ede 922 }\r
4ab04a72
RN
923 if (Index != SerialDeviceCount) {\r
924 //\r
925 // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.\r
926 // Otherwise continue to create the instance specified by RemainingDevicePath.\r
927 //\r
928 if (SerialDevices != NULL) {\r
929 FreePool (SerialDevices);\r
930 }\r
931 return Status;\r
a59e2ede 932 }\r
a59e2ede 933 }\r
77557b76 934 }\r
a59e2ede
RN
935\r
936 if (RemainingDevicePath != NULL) {\r
937 Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);\r
938 } else {\r
939 Uart = NULL;\r
940 }\r
941\r
942 PciDeviceInfo = NULL;\r
943 if (IoProtocolGuid == &gEfiSioProtocolGuid) {\r
944 Status = EFI_NOT_FOUND;\r
945 if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
946 Node = ParentDevicePath;\r
947 do {\r
948 Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
949 Node = NextDevicePathNode (Node);\r
950 } while (!IsDevicePathEnd (Node));\r
951 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);\r
952 DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));\r
953 }\r
954 } else {\r
955 Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);\r
956 if (!EFI_ERROR (Status)) {\r
957 //\r
958 // PcdPciSerialParameters takes the higher priority.\r
959 //\r
960 PciSerialCount = 0;\r
961 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
962 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
963 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)\r
964 ) {\r
965 PciSerialCount++;\r
966 }\r
967 }\r
968\r
969 if (SerialDeviceCount == 0) {\r
970 //\r
971 // Enable the IO & MEM decoding when creating the first child.\r
972 // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).\r
973 //\r
974 PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));\r
12f5ff97 975 ASSERT (PciDeviceInfo != NULL);\r
a59e2ede
RN
976 PciDeviceInfo->ChildCount = 0;\r
977 PciDeviceInfo->PciIo = ParentIo.PciIo;\r
978 Status = ParentIo.PciIo->Attributes (\r
979 ParentIo.PciIo,\r
980 EfiPciIoAttributeOperationGet,\r
981 0,\r
982 &PciDeviceInfo->PciAttributes\r
983 );\r
984\r
985 if (!EFI_ERROR (Status)) {\r
986 Status = ParentIo.PciIo->Attributes (\r
987 ParentIo.PciIo,\r
988 EfiPciIoAttributeOperationSupported,\r
989 0,\r
990 &Supports\r
991 );\r
992 if (!EFI_ERROR (Status)) {\r
d14198b3 993 Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);\r
a59e2ede
RN
994 Status = ParentIo.PciIo->Attributes (\r
995 ParentIo.PciIo,\r
996 EfiPciIoAttributeOperationEnable,\r
997 Supports,\r
998 NULL\r
999 );\r
1000 }\r
1001 }\r
1002 } else {\r
1003 //\r
1004 // Re-use the PciDeviceInfo stored in existing children.\r
1005 //\r
12f5ff97 1006 ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL));\r
a59e2ede
RN
1007 PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;\r
1008 ASSERT (PciDeviceInfo != NULL);\r
1009 }\r
1010\r
1011 Status = EFI_NOT_FOUND;\r
1012 if (PciSerialCount <= 1) {\r
1013 //\r
1014 // PCI serial device contains only one UART\r
1015 //\r
1016 if (RemainingDevicePath == NULL || !ContainsControllerNode) {\r
1017 //\r
1018 // This PCI serial device is matched by class code in Supported()\r
1019 //\r
1020 if (PciSerialCount == 0) {\r
1021 DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;\r
1022 DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;\r
1023 DefaultPciSerialParameter.BarIndex = 0;\r
1024 DefaultPciSerialParameter.Offset = 0;\r
1025 DefaultPciSerialParameter.RegisterStride = 0;\r
1026 DefaultPciSerialParameter.ClockRate = 0;\r
1027 PciSerialParameter = &DefaultPciSerialParameter;\r
1028 } else if (PciSerialCount == 1) {\r
1029 PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);\r
1030 }\r
1031\r
1032 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);\r
1033 DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));\r
1034 if (!EFI_ERROR (Status)) {\r
1035 PciDeviceInfo->ChildCount++;\r
1036 }\r
1037 }\r
1038 } else {\r
1039 //\r
1040 // PCI serial device contains multiple UARTs\r
1041 //\r
1042 if (RemainingDevicePath == NULL || ContainsControllerNode) {\r
1043 PciSerialCount = 0;\r
1044 for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {\r
1045 if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&\r
1046 (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&\r
1047 ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))\r
1048 ) {\r
1049 //\r
1050 // Create controller node when PCI serial device contains multiple UARTs\r
1051 //\r
1052 Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);\r
1053 PciSerialCount++;\r
1054 DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));\r
1055 if (!EFI_ERROR (Status)) {\r
1056 PciDeviceInfo->ChildCount++;\r
1057 }\r
1058 }\r
1059 }\r
1060 }\r
1061 }\r
1062 }\r
1063 }\r
1064\r
1065 if (SerialDevices != NULL) {\r
1066 FreePool (SerialDevices);\r
1067 }\r
1068\r
1069 //\r
1070 // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully\r
1071 //\r
1072 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {\r
1073 Status = EFI_SUCCESS;\r
1074 }\r
1075\r
1076 if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {\r
1077 if (PciDeviceInfo != NULL) {\r
1078 Status = ParentIo.PciIo->Attributes (\r
1079 ParentIo.PciIo,\r
1080 EfiPciIoAttributeOperationSet,\r
1081 PciDeviceInfo->PciAttributes,\r
1082 NULL\r
1083 );\r
1084 ASSERT_EFI_ERROR (Status);\r
1085 FreePool (PciDeviceInfo);\r
1086 }\r
1087 gBS->CloseProtocol (\r
1088 Controller,\r
1089 &gEfiDevicePathProtocolGuid,\r
1090 This->DriverBindingHandle,\r
1091 Controller\r
1092 );\r
1093 gBS->CloseProtocol (\r
1094 Controller,\r
1095 IoProtocolGuid,\r
1096 This->DriverBindingHandle,\r
1097 Controller\r
1098 );\r
1099 }\r
1100\r
1101 return Status;\r
1102}\r
1103\r
1104/**\r
1105 Disconnect this driver with the controller, uninstall related protocol instance\r
1106\r
1107 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1108 @param Controller The handle of the controller to test.\r
1109 @param NumberOfChildren Number of child device.\r
1110 @param ChildHandleBuffer A pointer to the remaining portion of a device path.\r
1111\r
1112 @retval EFI_SUCCESS Operation successfully\r
1113 @retval EFI_DEVICE_ERROR Cannot stop the driver successfully\r
1114\r
1115**/\r
1116EFI_STATUS\r
1117EFIAPI\r
1118SerialControllerDriverStop (\r
1119 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1120 IN EFI_HANDLE Controller,\r
1121 IN UINTN NumberOfChildren,\r
1122 IN EFI_HANDLE *ChildHandleBuffer\r
1123 )\r
1124\r
1125{\r
1126 EFI_STATUS Status;\r
1127 UINTN Index;\r
1128 BOOLEAN AllChildrenStopped;\r
1129 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
1130 SERIAL_DEV *SerialDevice;\r
1131 VOID *IoProtocol;\r
1132 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1133 PCI_DEVICE_INFO *PciDeviceInfo;\r
1134\r
1135 PciDeviceInfo = NULL;\r
1136\r
1137 Status = gBS->HandleProtocol (\r
1138 Controller,\r
1139 &gEfiDevicePathProtocolGuid,\r
1140 (VOID **) &DevicePath\r
1141 );\r
1142\r
1143 //\r
1144 // Report the status code disable the serial\r
1145 //\r
1146 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1147 EFI_PROGRESS_CODE,\r
1148 EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,\r
1149 DevicePath\r
1150 );\r
1151\r
1152 if (NumberOfChildren == 0) {\r
1153 //\r
1154 // Close the bus driver\r
1155 //\r
1156 Status = gBS->OpenProtocol (\r
1157 Controller,\r
1158 &gEfiPciIoProtocolGuid,\r
1159 &IoProtocol,\r
1160 This->DriverBindingHandle,\r
1161 Controller,\r
1162 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
1163 );\r
1164 gBS->CloseProtocol (\r
1165 Controller,\r
1166 !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
1167 This->DriverBindingHandle,\r
1168 Controller\r
1169 );\r
1170\r
1171 gBS->CloseProtocol (\r
1172 Controller,\r
1173 &gEfiDevicePathProtocolGuid,\r
1174 This->DriverBindingHandle,\r
1175 Controller\r
1176 );\r
1177 return EFI_SUCCESS;\r
1178 }\r
1179\r
1180 AllChildrenStopped = TRUE;\r
1181\r
1182 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1183\r
1184 Status = gBS->OpenProtocol (\r
1185 ChildHandleBuffer[Index],\r
1186 &gEfiSerialIoProtocolGuid,\r
1187 (VOID **) &SerialIo,\r
1188 This->DriverBindingHandle,\r
1189 Controller,\r
1190 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1191 );\r
1192 if (!EFI_ERROR (Status)) {\r
1193\r
1194 SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);\r
1195 ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));\r
1196 PciDeviceInfo = SerialDevice->PciDeviceInfo;\r
1197\r
1198 Status = gBS->CloseProtocol (\r
1199 Controller,\r
1200 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
1201 This->DriverBindingHandle,\r
1202 ChildHandleBuffer[Index]\r
1203 );\r
1204\r
1205 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1206 ChildHandleBuffer[Index],\r
1207 &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,\r
1208 &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,\r
1209 NULL\r
1210 );\r
1211 if (EFI_ERROR (Status)) {\r
1212 gBS->OpenProtocol (\r
1213 Controller,\r
1214 PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,\r
1215 &IoProtocol,\r
1216 This->DriverBindingHandle,\r
1217 ChildHandleBuffer[Index],\r
1218 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1219 );\r
1220 } else {\r
1221 FreePool (SerialDevice->DevicePath);\r
1222 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);\r
1223 FreePool (SerialDevice);\r
1224\r
1225 if (PciDeviceInfo != NULL) {\r
1226 ASSERT (PciDeviceInfo->ChildCount != 0);\r
1227 PciDeviceInfo->ChildCount--;\r
1228 }\r
1229 }\r
1230 }\r
1231\r
1232 if (EFI_ERROR (Status)) {\r
1233 AllChildrenStopped = FALSE;\r
1234 }\r
1235 }\r
1236\r
1237 if (!AllChildrenStopped) {\r
1238 return EFI_DEVICE_ERROR;\r
1239 } else {\r
1240 //\r
1241 // If all children are destroyed, restore the PCI attributes.\r
1242 //\r
1243 if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {\r
1244 ASSERT (PciDeviceInfo->PciIo != NULL);\r
1245 Status = PciDeviceInfo->PciIo->Attributes (\r
1246 PciDeviceInfo->PciIo,\r
1247 EfiPciIoAttributeOperationSet,\r
1248 PciDeviceInfo->PciAttributes,\r
1249 NULL\r
1250 );\r
1251 ASSERT_EFI_ERROR (Status);\r
1252 FreePool (PciDeviceInfo);\r
1253 }\r
1254 return EFI_SUCCESS;\r
1255 }\r
1256}\r