SioDriver.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /** @file
  2. EFI Driver following Driver Binding Protocol.
  3. Copyright (c) 2010 - 2019 Intel Corporation. All rights reserved. <BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "SioDriver.h"
  7. //
  8. // This driver is for ACPI(PNP0A03,0)/PCI(0x1f,0)
  9. //
  10. //
  11. // Sio Driver Global Variables
  12. //
  13. EFI_DRIVER_BINDING_PROTOCOL mSioDriver = {
  14. SioDriverSupported,
  15. SioDriverStart,
  16. SioDriverStop,
  17. 1,
  18. NULL,
  19. NULL
  20. };
  21. //
  22. // The list of the created SIO_DEV
  23. //
  24. LIST_ENTRY mSioDevPool = INITIALIZE_LIST_HEAD_VARIABLE (mSioDevPool);
  25. //
  26. // Template structure to create SIO_DEV
  27. //
  28. SIO_DEV mSioDevTemplate = {
  29. SIO_DEV_SIGNATURE, // Signature
  30. NULL, // PciHandle
  31. {
  32. 0x00000000, // HID
  33. 0x00000000 // UID
  34. },
  35. NULL, // Handle
  36. { // Sio Instance
  37. SioRegisterAccess,
  38. SioGetResources,
  39. SioSetResources,
  40. SioPossibleResources,
  41. SioModify
  42. },
  43. NULL, // DevicePath
  44. {
  45. NULL, // ForwardLink
  46. NULL, // BackLink
  47. }
  48. };
  49. //
  50. // Template ACPI_HID_DEVICE_PATH structure to create device path
  51. //
  52. ACPI_HID_DEVICE_PATH mAcpiNodeTemplate = {
  53. {
  54. ACPI_DEVICE_PATH, // Type
  55. ACPI_DP, // SubType
  56. {
  57. sizeof (ACPI_HID_DEVICE_PATH), // Length[0]
  58. 0 // Length[1]
  59. }
  60. },
  61. 0x00000000, // HID
  62. 0x00000000 // UID
  63. };
  64. /**
  65. The user Entry Point for module Lpc47m17x. The user code starts with this function.
  66. @param[in] ImageHandle The firmware allocated handle for the EFI image.
  67. @param[in] SystemTable A pointer to the EFI System Table.
  68. @retval EFI_SUCCESS The entry point is executed successfully.
  69. @retval other Some error occurs when executing this entry point.
  70. **/
  71. EFI_STATUS
  72. EFIAPI
  73. SioDriverEntryPoint (
  74. IN EFI_HANDLE ImageHandle,
  75. IN EFI_SYSTEM_TABLE *SystemTable
  76. )
  77. {
  78. if (EFI_ERROR (SioInit())) {
  79. return EFI_UNSUPPORTED;
  80. } else {
  81. //
  82. // Install protocols
  83. //
  84. return EfiLibInstallDriverBindingComponentName2 (
  85. ImageHandle,
  86. SystemTable,
  87. &mSioDriver,
  88. ImageHandle,
  89. &mSioComponentName,
  90. &mSioComponentName2
  91. );
  92. }
  93. }
  94. /**
  95. Test to see if this driver supports Controller Handle.
  96. @param[in] This Protocol instance pointer.
  97. @param[in] Controller Handle of device to test
  98. @param[in] RemainingDevicePath Optional parameter use to pick a specific child
  99. device to start.
  100. @retval EFI_SUCCESS This driver supports this device
  101. @retval EFI_ALREADY_STARTED This driver is already running on this device
  102. @retval other This driver does not support this device
  103. **/
  104. EFI_STATUS
  105. EFIAPI
  106. SioDriverSupported (
  107. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  108. IN EFI_HANDLE Controller,
  109. IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
  110. )
  111. {
  112. EFI_STATUS Status;
  113. EFI_PCI_IO_PROTOCOL *PciIo;
  114. EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
  115. ACPI_HID_DEVICE_PATH *AcpiNode;
  116. PCI_TYPE00 Pci;
  117. UINTN Index;
  118. EFI_SIO_ACPI_DEVICE_ID *Devices;
  119. UINTN Count;
  120. UINTN SegmentNumber;
  121. UINTN BusNumber;
  122. UINTN DeviceNumber;
  123. UINTN FunctionNumber;
  124. //
  125. // If RemainingDevicePath is not NULL, it should verify that the first device
  126. // path node in RemainingDevicePath is an ACPI Device path node which is a
  127. // legal Device Path Node for this bus driver's children.
  128. //
  129. if (RemainingDevicePath != NULL) {
  130. if (!IsDevicePathEnd (RemainingDevicePath)) {
  131. if ((RemainingDevicePath->Type != ACPI_DEVICE_PATH) ||
  132. (((RemainingDevicePath->SubType != ACPI_DP) || (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_HID_DEVICE_PATH))) &&
  133. ((RemainingDevicePath->SubType != ACPI_EXTENDED_DP) || (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_EXTENDED_HID_DEVICE_PATH))))
  134. ) {
  135. return EFI_UNSUPPORTED;
  136. }
  137. DeviceGetList (&Devices, &Count);
  138. if (Devices == NULL) {
  139. return EFI_OUT_OF_RESOURCES;
  140. }
  141. AcpiNode = (ACPI_HID_DEVICE_PATH *) RemainingDevicePath;
  142. for (Index = 0; Index < Count; Index++) {
  143. if ((AcpiNode->HID == Devices[Index].HID) &&
  144. (AcpiNode->UID == Devices[Index].UID)) {
  145. break;
  146. }
  147. }
  148. FreePool (Devices);
  149. if (Index == Count) {
  150. return EFI_UNSUPPORTED;
  151. }
  152. }
  153. }
  154. //
  155. // See if the parent device path can be opened BY_DRIVER
  156. //
  157. Status = gBS->OpenProtocol (
  158. Controller,
  159. &gEfiDevicePathProtocolGuid,
  160. (VOID **) &ParentDevicePath,
  161. This->DriverBindingHandle,
  162. Controller,
  163. EFI_OPEN_PROTOCOL_BY_DRIVER
  164. );
  165. if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
  166. return Status;
  167. }
  168. gBS->CloseProtocol (
  169. Controller,
  170. &gEfiDevicePathProtocolGuid,
  171. This->DriverBindingHandle,
  172. Controller
  173. );
  174. //
  175. // Get PciIo protocol instance
  176. //
  177. Status = gBS->OpenProtocol (
  178. Controller,
  179. &gEfiPciIoProtocolGuid,
  180. (VOID **) &PciIo,
  181. This->DriverBindingHandle,
  182. Controller,
  183. EFI_OPEN_PROTOCOL_BY_DRIVER
  184. );
  185. if (!EFI_ERROR (Status)) {
  186. Status = PciIo->Pci.Read (
  187. PciIo,
  188. EfiPciIoWidthUint32,
  189. 0,
  190. sizeof (Pci) / sizeof (UINT32),
  191. &Pci
  192. );
  193. ASSERT_EFI_ERROR (Status);
  194. Status = EFI_UNSUPPORTED;
  195. if ((Pci.Hdr.Command & (EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_MEMORY_SPACE))
  196. == (EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_MEMORY_SPACE)
  197. ) {
  198. if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
  199. //
  200. // See if this is a standard PCI to ISA Bridge from the Base Code and Class Code
  201. //
  202. if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA) {
  203. Status = EFI_SUCCESS;
  204. }
  205. //
  206. // See if this is an Intel PCI to ISA Bridge in Positive Decode Mode
  207. //
  208. if ((Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) &&
  209. (Pci.Hdr.VendorId == 0x8086)) {
  210. //
  211. // See if this is on Function #0 to avoid false positive on
  212. // PCI_CLASS_BRIDGE_OTHER that has the same value as
  213. // PCI_CLASS_BRIDGE_ISA_PDECODE
  214. //
  215. Status = PciIo->GetLocation (
  216. PciIo,
  217. &SegmentNumber,
  218. &BusNumber,
  219. &DeviceNumber,
  220. &FunctionNumber
  221. );
  222. if (!EFI_ERROR (Status) && (FunctionNumber == 0)) {
  223. Status = EFI_SUCCESS;
  224. } else {
  225. Status = EFI_UNSUPPORTED;
  226. }
  227. }
  228. }
  229. }
  230. gBS->CloseProtocol (
  231. Controller,
  232. &gEfiPciIoProtocolGuid,
  233. This->DriverBindingHandle,
  234. Controller
  235. );
  236. }
  237. if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
  238. return Status;
  239. }
  240. return EFI_SUCCESS;
  241. }
  242. /**
  243. Destroy the SIO controller handle.
  244. @param[in] ChildHandle The SIO controller handle.
  245. @retval EFI_SUCCESS The SIO controller handle is destroyed successfully.
  246. **/
  247. EFI_STATUS
  248. SioDestroyDevice (
  249. IN EFI_HANDLE ChildHandle
  250. )
  251. {
  252. EFI_STATUS Status;
  253. SIO_DEV *SioDev;
  254. EFI_SIO_PROTOCOL *Sio;
  255. EFI_PCI_IO_PROTOCOL *PciIo;
  256. Status = gBS->HandleProtocol (
  257. ChildHandle,
  258. &gEfiSioProtocolGuid,
  259. (VOID **) &Sio
  260. );
  261. ASSERT_EFI_ERROR (Status);
  262. SioDev = SIO_DEV_FROM_THIS (Sio);
  263. Status = gBS->CloseProtocol (
  264. SioDev->PciHandle,
  265. &gEfiPciIoProtocolGuid,
  266. mSioDriver.DriverBindingHandle,
  267. ChildHandle
  268. );
  269. ASSERT_EFI_ERROR (Status);
  270. Status = gBS->UninstallMultipleProtocolInterfaces (
  271. ChildHandle,
  272. &gEfiDevicePathProtocolGuid,
  273. SioDev->DevicePath,
  274. &gEfiSioProtocolGuid,
  275. &SioDev->Sio,
  276. NULL
  277. );
  278. if (EFI_ERROR (Status)) {
  279. gBS->OpenProtocol (
  280. SioDev->PciHandle,
  281. &gEfiPciIoProtocolGuid,
  282. (VOID **) &PciIo,
  283. mSioDriver.DriverBindingHandle,
  284. ChildHandle,
  285. EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
  286. );
  287. return Status;
  288. }
  289. RemoveEntryList (&SioDev->Link);
  290. FreePool (SioDev->DevicePath);
  291. FreePool (SioDev);
  292. return EFI_SUCCESS;
  293. }
  294. /**
  295. Create the SIO controller handle.
  296. @param[in] Controller The parent PCI controller handle.
  297. @param[in] Device Pointer to EFI_SIO_ACPI_DEVICE_ID.
  298. @param[in] ParentDevicePath The device path of the parent controller.
  299. @param[out] PciIo The PciIo instance of the parent controller.
  300. **/
  301. VOID
  302. SioCreateDevice (
  303. IN EFI_HANDLE Controller,
  304. IN EFI_SIO_ACPI_DEVICE_ID *Device,
  305. IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
  306. OUT EFI_PCI_IO_PROTOCOL *PciIo
  307. )
  308. {
  309. EFI_STATUS Status;
  310. SIO_DEV *SioDev;
  311. DeviceEnable (Device);
  312. SioDev = AllocateCopyPool (sizeof (SIO_DEV), &mSioDevTemplate);
  313. ASSERT (SioDev != NULL);
  314. if (SioDev == NULL) {
  315. return;
  316. }
  317. InsertHeadList (&mSioDevPool, &SioDev->Link);
  318. SioDev->PciHandle = Controller;
  319. CopyMem (&SioDev->Device, Device, sizeof (*Device));
  320. mAcpiNodeTemplate.HID = Device->HID;
  321. mAcpiNodeTemplate.UID = Device->UID;
  322. SioDev->DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &mAcpiNodeTemplate);
  323. ASSERT (SioDev->DevicePath != NULL);
  324. Status = gBS->InstallMultipleProtocolInterfaces (
  325. &SioDev->Handle,
  326. &gEfiSioProtocolGuid, &SioDev->Sio,
  327. &gEfiDevicePathProtocolGuid, SioDev->DevicePath,
  328. NULL
  329. );
  330. ASSERT_EFI_ERROR (Status);
  331. Status = gBS->OpenProtocol (
  332. Controller,
  333. &gEfiPciIoProtocolGuid,
  334. (VOID **) &PciIo,
  335. mSioDriver.DriverBindingHandle,
  336. SioDev->Handle,
  337. EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
  338. );
  339. ASSERT_EFI_ERROR (Status);
  340. }
  341. /**
  342. Start this driver on ControllerHandle.
  343. @param[in] This Protocol instance pointer.
  344. @param[in] Controller Handle of device to bind driver to
  345. @param[in] RemainingDevicePath Optional parameter use to pick a specific child
  346. device to start.
  347. @retval EFI_SUCCESS This driver is added to ControllerHandle
  348. @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
  349. @retval other This driver does not support this device
  350. **/
  351. EFI_STATUS
  352. EFIAPI
  353. SioDriverStart (
  354. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  355. IN EFI_HANDLE Controller,
  356. IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
  357. )
  358. {
  359. EFI_STATUS Status;
  360. EFI_PCI_IO_PROTOCOL *PciIo;
  361. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  362. EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
  363. EFI_SIO_ACPI_DEVICE_ID *Devices;
  364. SIO_DEV *SioDev;
  365. UINTN Count;
  366. UINTN Index;
  367. ACPI_HID_DEVICE_PATH *AcpiNode;
  368. BOOLEAN *HasCreated;
  369. BOOLEAN *RequestCreate;
  370. LIST_ENTRY *Node;
  371. HasCreated = NULL;
  372. RequestCreate = NULL;
  373. //
  374. // Get the ISA bridge's Device Path
  375. //
  376. Status = gBS->OpenProtocol (
  377. Controller,
  378. &gEfiDevicePathProtocolGuid,
  379. (VOID **) &ParentDevicePath,
  380. This->DriverBindingHandle,
  381. Controller,
  382. EFI_OPEN_PROTOCOL_BY_DRIVER
  383. );
  384. if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
  385. return Status;
  386. }
  387. //
  388. // Get Pci IO
  389. //
  390. Status = gBS->OpenProtocol (
  391. Controller,
  392. &gEfiPciIoProtocolGuid,
  393. (VOID **) &PciIo,
  394. This->DriverBindingHandle,
  395. Controller,
  396. EFI_OPEN_PROTOCOL_BY_DRIVER
  397. );
  398. if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
  399. gBS->CloseProtocol (
  400. Controller,
  401. &gEfiDevicePathProtocolGuid,
  402. This->DriverBindingHandle,
  403. Controller
  404. );
  405. return Status;
  406. }
  407. if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
  408. return EFI_SUCCESS;
  409. }
  410. DeviceGetList (&Devices, &Count);
  411. if (Devices == NULL) {
  412. Status = EFI_OUT_OF_RESOURCES;
  413. goto Exit_Start;
  414. }
  415. HasCreated = AllocatePool (sizeof (BOOLEAN) * Count);
  416. ASSERT (HasCreated != NULL);
  417. if (HasCreated == NULL) {
  418. Status = EFI_OUT_OF_RESOURCES;
  419. goto Exit_Start;
  420. }
  421. RequestCreate = AllocatePool (sizeof (BOOLEAN) * Count);
  422. ASSERT (RequestCreate != NULL);
  423. if (RequestCreate == NULL) {
  424. Status = EFI_OUT_OF_RESOURCES;
  425. goto Exit_Start;
  426. }
  427. //
  428. // Assume no children has been created.
  429. // Assume the SIO interface hasn't been initialized.
  430. //
  431. ZeroMem (HasCreated, sizeof (BOOLEAN) * Count);
  432. if (Status == EFI_ALREADY_STARTED) {
  433. for (Node = GetFirstNode (&mSioDevPool);
  434. !IsNull (&mSioDevPool, Node);
  435. Node = GetNextNode (&mSioDevPool, Node)
  436. ) {
  437. SioDev = CR (Node, SIO_DEV, Link, SIO_DEV_SIGNATURE);
  438. Status = gBS->HandleProtocol (
  439. SioDev->PciHandle,
  440. &gEfiDevicePathProtocolGuid,
  441. (VOID **) &DevicePath
  442. );
  443. ASSERT_EFI_ERROR (Status);
  444. //
  445. // See if they are under the same PCI to ISA Bridge
  446. //
  447. if (CompareMem (DevicePath, ParentDevicePath, GetDevicePathSize (DevicePath)) == 0) {
  448. for (Index = 0; Index < Count; Index++) {
  449. if (CompareMem (&SioDev->Device, &Devices[Index], sizeof (EFI_SIO_ACPI_DEVICE_ID)) == 0) {
  450. HasCreated[Index] = TRUE;
  451. break;
  452. }
  453. }
  454. }
  455. }
  456. }
  457. AcpiNode = (ACPI_HID_DEVICE_PATH *) RemainingDevicePath;
  458. for (Index = 0; Index < Count; Index++) {
  459. if ((AcpiNode == NULL) ||
  460. ((AcpiNode->HID == Devices[Index].HID) && (AcpiNode->UID == Devices[Index].UID))
  461. ) {
  462. RequestCreate[Index] = TRUE;
  463. } else {
  464. RequestCreate[Index] = FALSE;
  465. }
  466. }
  467. for (Index = 0; Index < Count; Index++) {
  468. if (RequestCreate[Index] && !HasCreated[Index]) {
  469. SioCreateDevice (Controller, &Devices[Index], ParentDevicePath, PciIo);
  470. }
  471. }
  472. Exit_Start:
  473. if (Devices != NULL) {
  474. FreePool (Devices);
  475. }
  476. if (HasCreated != NULL) {
  477. FreePool (HasCreated);
  478. }
  479. if (RequestCreate != NULL) {
  480. FreePool (RequestCreate);
  481. }
  482. return Status;
  483. }
  484. /**
  485. Stop this driver on ControllerHandle.
  486. @param[in] This Protocol instance pointer.
  487. @param[in] Controller Handle of device to stop driver on
  488. @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
  489. children is zero stop the entire bus driver.
  490. @param[in] ChildHandleBuffer List of Child Handles to Stop.
  491. @retval EFI_SUCCESS This driver is removed ControllerHandle
  492. @retval other This driver was not removed from this device
  493. **/
  494. EFI_STATUS
  495. EFIAPI
  496. SioDriverStop (
  497. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  498. IN EFI_HANDLE Controller,
  499. IN UINTN NumberOfChildren,
  500. IN EFI_HANDLE *ChildHandleBuffer
  501. )
  502. {
  503. EFI_STATUS Status;
  504. UINTN Index;
  505. BOOLEAN AllChildrenStopped;
  506. if (NumberOfChildren == 0) {
  507. gBS->CloseProtocol (
  508. Controller,
  509. &gEfiDevicePathProtocolGuid,
  510. This->DriverBindingHandle,
  511. Controller
  512. );
  513. gBS->CloseProtocol (
  514. Controller,
  515. &gEfiPciIoProtocolGuid,
  516. This->DriverBindingHandle,
  517. Controller
  518. );
  519. return EFI_SUCCESS;
  520. }
  521. AllChildrenStopped = TRUE;
  522. for (Index = 0; Index < NumberOfChildren; Index++) {
  523. Status = SioDestroyDevice (ChildHandleBuffer[Index]);
  524. if (EFI_ERROR (Status)) {
  525. AllChildrenStopped = FALSE;
  526. }
  527. }
  528. if (AllChildrenStopped) {
  529. return EFI_SUCCESS;
  530. } else {
  531. return EFI_DEVICE_ERROR;
  532. }
  533. }