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