gpio.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. gpio.c
  9. Abstract:
  10. This module implements support for the core GPIO library driver.
  11. Author:
  12. Evan Green 4-Aug-2015
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/driver.h>
  20. #include "gpiop.h"
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. VOID
  31. GpioDriverUnload (
  32. PVOID Driver
  33. );
  34. KSTATUS
  35. GpioOpenPin (
  36. PGPIO_ACCESS_INTERFACE Interface,
  37. ULONG Pin,
  38. PGPIO_PIN_HANDLE PinHandle
  39. );
  40. VOID
  41. GpioClosePin (
  42. PGPIO_ACCESS_INTERFACE Interface,
  43. GPIO_PIN_HANDLE PinHandle
  44. );
  45. KSTATUS
  46. GpioPinSetConfiguration (
  47. GPIO_PIN_HANDLE PinHandle,
  48. PGPIO_PIN_CONFIGURATION Configuration
  49. );
  50. KSTATUS
  51. GpioPinSetDirection (
  52. GPIO_PIN_HANDLE PinHandle,
  53. ULONG Flags
  54. );
  55. VOID
  56. GpioPinSetValue (
  57. GPIO_PIN_HANDLE PinHandle,
  58. ULONG Value
  59. );
  60. ULONG
  61. GpioPinGetValue (
  62. GPIO_PIN_HANDLE PinHandle
  63. );
  64. KSTATUS
  65. GpioPrepareForInterrupts (
  66. PVOID Context
  67. );
  68. KSTATUS
  69. GpioSetInterruptLineState (
  70. PVOID Context,
  71. PINTERRUPT_LINE Line,
  72. PINTERRUPT_LINE_STATE State,
  73. PVOID ResourceData,
  74. UINTN ResourceDataSize
  75. );
  76. VOID
  77. GpioInterruptMaskLine (
  78. PVOID Context,
  79. PINTERRUPT_LINE Line,
  80. BOOL Enable
  81. );
  82. INTERRUPT_CAUSE
  83. GpioInterruptBegin (
  84. PVOID Context,
  85. PINTERRUPT_LINE FiringLine,
  86. PULONG MagicCandy
  87. );
  88. VOID
  89. GpioEndOfInterrupt (
  90. PVOID Context,
  91. ULONG MagicCandy
  92. );
  93. KSTATUS
  94. GpioRequestInterrupt (
  95. PVOID Context,
  96. PINTERRUPT_LINE Line,
  97. ULONG Vector,
  98. PINTERRUPT_HARDWARE_TARGET Target
  99. );
  100. //
  101. // -------------------------------------------------------------------- Globals
  102. //
  103. UUID GpioInterfaceUuid = UUID_GPIO_ACCESS;
  104. GPIO_ACCESS_INTERFACE GpioInterfaceTemplate = {
  105. NULL,
  106. GpioOpenPin,
  107. GpioClosePin,
  108. GpioPinSetConfiguration,
  109. GpioPinSetDirection,
  110. GpioPinSetValue,
  111. GpioPinGetValue
  112. };
  113. //
  114. // ------------------------------------------------------------------ Functions
  115. //
  116. KSTATUS
  117. DriverEntry (
  118. PDRIVER Driver
  119. )
  120. /*++
  121. Routine Description:
  122. This routine implements the initial entry point of the GPIO core
  123. library, called when the library is first loaded.
  124. Arguments:
  125. Driver - Supplies a pointer to the driver object.
  126. Return Value:
  127. Status code.
  128. --*/
  129. {
  130. DRIVER_FUNCTION_TABLE FunctionTable;
  131. KSTATUS Status;
  132. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  133. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  134. FunctionTable.Unload = GpioDriverUnload;
  135. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  136. return Status;
  137. }
  138. GPIO_API
  139. KSTATUS
  140. GpioCreateController (
  141. PGPIO_CONTROLLER_INFORMATION Registration,
  142. PGPIO_CONTROLLER *Controller
  143. )
  144. /*++
  145. Routine Description:
  146. This routine creates a new GPIO controller.
  147. Arguments:
  148. Registration - Supplies a pointer to the host registration information.
  149. Controller - Supplies a pointer where a pointer to the new controller will
  150. be returned on success.
  151. Return Value:
  152. Status code.
  153. --*/
  154. {
  155. UINTN AllocationSize;
  156. PGPIO_CONTROLLER NewController;
  157. KSTATUS Status;
  158. if ((Registration->Version < GPIO_CONTROLLER_INFORMATION_VERSION) ||
  159. (Registration->Version > GPIO_CONTROLLER_INFORMATION_MAX_VERSION) ||
  160. (Registration->LineCount == 0) ||
  161. (Registration->LineCount > GPIO_MAX_LINES) ||
  162. (Registration->Device == NULL)) {
  163. return STATUS_INVALID_PARAMETER;
  164. }
  165. if ((Registration->Features & GPIO_FEATURE_LOW_RUN_LEVEL) != 0) {
  166. if ((Registration->FunctionTable.PrepareForInterrupts == NULL) ||
  167. (Registration->FunctionTable.MaskInterruptLine == NULL) ||
  168. (Registration->FunctionTable.BeginInterrupt == NULL) ||
  169. (Registration->FunctionTable.EndOfInterrupt == NULL)) {
  170. return STATUS_INVALID_PARAMETER;
  171. }
  172. }
  173. AllocationSize = sizeof(GPIO_CONTROLLER) +
  174. (Registration->LineCount * sizeof(GPIO_PIN_CONFIGURATION));
  175. NewController = MmAllocateNonPagedPool(AllocationSize, GPIO_ALLOCATION_TAG);
  176. if (NewController == NULL) {
  177. Status = STATUS_INSUFFICIENT_RESOURCES;
  178. goto CreateControllerEnd;
  179. }
  180. RtlZeroMemory(NewController, AllocationSize);
  181. NewController->Magic = GPIO_CONTROLLER_MAGIC;
  182. NewController->InterruptLine = -1ULL;
  183. //
  184. // It's not yet known what runlevel the device will consume, so set it to
  185. // the highest possible value to synchronize with an interrupt that
  186. // comes in before the start controller routine has been fully processed.
  187. //
  188. NewController->RunLevel = RunLevelMaxDevice;
  189. KeInitializeSpinLock(&(NewController->SpinLock));
  190. //
  191. // If the controller does not have interrupts or can only be accessed at
  192. // low runlevel, then used a queued lock for synchronization.
  193. //
  194. if (((Registration->Features & GPIO_FEATURE_INTERRUPTS) == 0) ||
  195. ((Registration->Features & GPIO_FEATURE_LOW_RUN_LEVEL) != 0)) {
  196. NewController->QueuedLock = KeCreateQueuedLock();
  197. if (NewController->QueuedLock == NULL) {
  198. Status = STATUS_INSUFFICIENT_RESOURCES;
  199. goto CreateControllerEnd;
  200. }
  201. NewController->RunLevel = RunLevelLow;
  202. }
  203. NewController->Pins = (PGPIO_PIN_CONFIGURATION)(NewController + 1);
  204. RtlCopyMemory(&(NewController->Host),
  205. Registration,
  206. sizeof(GPIO_CONTROLLER_INFORMATION));
  207. RtlCopyMemory(&(NewController->Interface),
  208. &GpioInterfaceTemplate,
  209. sizeof(GPIO_ACCESS_INTERFACE));
  210. INITIALIZE_LIST_HEAD(&(NewController->Interface.Handles));
  211. Status = STATUS_SUCCESS;
  212. CreateControllerEnd:
  213. if (!KSUCCESS(Status)) {
  214. if (NewController != NULL) {
  215. if (NewController->QueuedLock != NULL) {
  216. KeDestroyQueuedLock(NewController->QueuedLock);
  217. }
  218. MmFreeNonPagedPool(NewController);
  219. NewController = NULL;
  220. }
  221. }
  222. *Controller = NewController;
  223. return Status;
  224. }
  225. GPIO_API
  226. VOID
  227. GpioDestroyController (
  228. PGPIO_CONTROLLER Controller
  229. )
  230. /*++
  231. Routine Description:
  232. This routine destroys a GPIO controller.
  233. Arguments:
  234. Controller - Supplies a pointer to the controller to tear down.
  235. Return Value:
  236. None.
  237. --*/
  238. {
  239. if (Controller->InterruptController != NULL) {
  240. HlDestroyInterruptController(Controller->InterruptController);
  241. Controller->InterruptController = NULL;
  242. }
  243. if (Controller->QueuedLock != NULL) {
  244. KeDestroyQueuedLock(Controller->QueuedLock);
  245. Controller->QueuedLock = NULL;
  246. }
  247. //
  248. // Ruin the magic (but in a way that's still identifiable to a human).
  249. //
  250. Controller->Magic += 1;
  251. Controller->Pins = NULL;
  252. MmFreeNonPagedPool(Controller);
  253. return;
  254. }
  255. GPIO_API
  256. KSTATUS
  257. GpioStartController (
  258. PGPIO_CONTROLLER Controller,
  259. ULONGLONG InterruptLine,
  260. ULONGLONG InterruptVector
  261. )
  262. /*++
  263. Routine Description:
  264. This routine starts a GPIO controller. This routine should be serialized
  265. externally, as it does not acquire the internal controller lock. Calling
  266. it from the start IRP is sufficient.
  267. Arguments:
  268. Controller - Supplies a pointer to the controller.
  269. InterruptLine - Supplies the Global System Interrupt number of the
  270. interrupt line that this controller is wired to. That is, the GSI of
  271. the line this controller tickles when it wants to generate an interrupt.
  272. Set to -1ULL if the controller has no interrupt resources.
  273. InterruptVector - Supplies the interrupt vector number of the interrupt
  274. line that this controller is wired to. Set to RunLevelLow if this GPIO
  275. controller does not support interrupts.
  276. Return Value:
  277. Status code.
  278. --*/
  279. {
  280. PGPIO_CONTROLLER_INFORMATION Host;
  281. INTERRUPT_CONTROLLER_INFORMATION Information;
  282. INTERRUPT_CONTROLLER_DESCRIPTION Registration;
  283. KSTATUS Status;
  284. ASSERT(Controller->Interface.Public.Context == NULL);
  285. Host = &(Controller->Host);
  286. Controller->Interface.Public.Context = &(Controller->Interface);
  287. Status = IoCreateInterface(&GpioInterfaceUuid,
  288. Host->Device,
  289. &(Controller->Interface),
  290. sizeof(GPIO_ACCESS_INTERFACE));
  291. if (!KSUCCESS(Status)) {
  292. Controller->Interface.Public.Context = NULL;
  293. goto StartControllerEnd;
  294. }
  295. //
  296. // Create a resource arbiter for these pins so that other devices can
  297. // allocate them as part of their official resource requirements.
  298. //
  299. if (Controller->ArbiterCreated == FALSE) {
  300. Status = IoCreateResourceArbiter(Host->Device, ResourceTypeGpio);
  301. if ((!KSUCCESS(Status)) && (Status != STATUS_ALREADY_INITIALIZED)) {
  302. goto StartControllerEnd;
  303. }
  304. Status = IoAddFreeSpaceToArbiter(Host->Device,
  305. ResourceTypeGpio,
  306. 0,
  307. Host->LineCount,
  308. 0,
  309. NULL,
  310. 0);
  311. if (!KSUCCESS(Status)) {
  312. goto StartControllerEnd;
  313. }
  314. Controller->ArbiterCreated = TRUE;
  315. }
  316. //
  317. // Create the interrupt controller. Wire the interrupt controller functions
  318. // directly to the host and avoid interfering.
  319. //
  320. Controller->InterruptLine = InterruptLine;
  321. Controller->InterruptVector = InterruptVector;
  322. if (((Host->Features & GPIO_FEATURE_INTERRUPTS) != 0) &&
  323. (Controller->InterruptController == NULL) &&
  324. (Controller->InterruptLine != -1ULL)) {
  325. RtlZeroMemory(&Registration, sizeof(INTERRUPT_CONTROLLER_DESCRIPTION));
  326. Registration.TableVersion = INTERRUPT_CONTROLLER_DESCRIPTION_VERSION;
  327. Registration.FunctionTable.InitializeIoUnit = GpioPrepareForInterrupts;
  328. Registration.FunctionTable.SetLineState = GpioSetInterruptLineState;
  329. Registration.FunctionTable.MaskLine = GpioInterruptMaskLine;
  330. Registration.FunctionTable.BeginInterrupt = GpioInterruptBegin;
  331. Registration.FunctionTable.EndOfInterrupt = GpioEndOfInterrupt;
  332. if (Host->FunctionTable.RequestInterrupt != NULL) {
  333. Registration.FunctionTable.RequestInterrupt = GpioRequestInterrupt;
  334. }
  335. if ((Host->Features & GPIO_FEATURE_LOW_RUN_LEVEL) != 0) {
  336. Registration.Flags |= INTERRUPT_FEATURE_LOW_RUN_LEVEL;
  337. } else {
  338. //
  339. // Reset the controller's runlevel to the maximum it could be.
  340. //
  341. Controller->RunLevel = RunLevelMaxDevice;
  342. }
  343. Registration.Context = Controller;
  344. //
  345. // Set the identifier to the device pointer by convention so ACPI can
  346. // find this interrupt controller to get the resulting GSI base. It
  347. // needs that information to convert a GPIO interrupt resource
  348. // descriptor into a generic interrupt resource requirement.
  349. //
  350. Registration.Identifier = (UINTN)(Host->Device);
  351. Status = HlCreateInterruptController(Controller->InterruptLine,
  352. Controller->InterruptVector,
  353. Host->LineCount,
  354. &Registration,
  355. &Information);
  356. if (!KSUCCESS(Status)) {
  357. RtlDebugPrint("GPIO: Failed to create interrupt controller: %d\n",
  358. Status);
  359. goto StartControllerEnd;
  360. }
  361. Controller->InterruptController = Information.Controller;
  362. Controller->GsiBase = Information.StartingGsi;
  363. }
  364. StartControllerEnd:
  365. return Status;
  366. }
  367. GPIO_API
  368. VOID
  369. GpioStopController (
  370. PGPIO_CONTROLLER Controller
  371. )
  372. /*++
  373. Routine Description:
  374. This routine stops a GPIO controller. This routine should be serialized
  375. externally, as it does not acquire the internal GPIO lock. Calling this
  376. routine from state change IRPs should be sufficient.
  377. Arguments:
  378. Controller - Supplies a pointer to the controller.
  379. Return Value:
  380. None.
  381. --*/
  382. {
  383. KSTATUS Status;
  384. ASSERT(Controller->Interface.Public.Context == &(Controller->Interface));
  385. Status = IoDestroyInterface(&GpioInterfaceUuid,
  386. Controller->Host.Device,
  387. &(Controller->Interface));
  388. ASSERT(KSUCCESS(Status));
  389. Controller->Interface.Public.Context = NULL;
  390. ASSERT(LIST_EMPTY(&(Controller->Interface.Handles)));
  391. return;
  392. }
  393. GPIO_API
  394. VOID
  395. GpioSetInterruptRunLevel (
  396. PGPIO_CONTROLLER Controller,
  397. RUNLEVEL RunLevel
  398. )
  399. /*++
  400. Routine Description:
  401. This routine sets the internal runlevel of the GPIO lock.
  402. Arguments:
  403. Controller - Supplies a pointer to the controller.
  404. RunLevel - Supplies the runlevel that interrupts come in on for this
  405. controller.
  406. Return Value:
  407. None.
  408. --*/
  409. {
  410. ASSERT(Controller->RunLevel >= RunLevel);
  411. Controller->RunLevel = RunLevel;
  412. return;
  413. }
  414. GPIO_API
  415. INTERRUPT_STATUS
  416. GpioInterruptService (
  417. PVOID Context
  418. )
  419. /*++
  420. Routine Description:
  421. This routine represents the GPIO controller interrupt service routine.
  422. It should be connected by GPIO controllers that can generate interrupts.
  423. Arguments:
  424. Context - Supplies the context given to the connect interrupt routine,
  425. which must in this case be the GPIO controller pointer.
  426. Return Value:
  427. Returns an interrupt status indicating if this ISR is claiming the
  428. interrupt, not claiming the interrupt, or needs the interrupt to be
  429. masked temporarily.
  430. --*/
  431. {
  432. PGPIO_CONTROLLER Controller;
  433. INTERRUPT_STATUS Result;
  434. Controller = Context;
  435. Result = HlSecondaryInterruptControllerService(
  436. Controller->InterruptController);
  437. return Result;
  438. }
  439. GPIO_API
  440. RUNLEVEL
  441. GpioLockController (
  442. PGPIO_CONTROLLER Controller
  443. )
  444. /*++
  445. Routine Description:
  446. This routine acquires the GPIO controller lock. This routine is called
  447. automatically by most interface routines.
  448. Arguments:
  449. Controller - Supplies a pointer to the GPIO controller to acquire the lock
  450. for.
  451. Return Value:
  452. Returns the original runlevel, as this routine may have raised the runlevel.
  453. --*/
  454. {
  455. RUNLEVEL OldRunLevel;
  456. if (Controller->QueuedLock != NULL) {
  457. ASSERT((Controller->RunLevel == RunLevelLow) &&
  458. (KeGetRunLevel() == RunLevelLow));
  459. OldRunLevel = RunLevelLow;
  460. KeAcquireQueuedLock(Controller->QueuedLock);
  461. } else {
  462. ASSERT(Controller->RunLevel >= RunLevelDispatch);
  463. OldRunLevel = KeRaiseRunLevel(Controller->RunLevel);
  464. KeAcquireSpinLock(&(Controller->SpinLock));
  465. }
  466. return OldRunLevel;
  467. }
  468. GPIO_API
  469. VOID
  470. GpioUnlockController (
  471. PGPIO_CONTROLLER Controller,
  472. RUNLEVEL OldRunLevel
  473. )
  474. /*++
  475. Routine Description:
  476. This routine releases the GPIO controller lock. This routine is called
  477. automatically by most interface routines.
  478. Arguments:
  479. Controller - Supplies a pointer to the GPIO controller to release the lock
  480. for.
  481. OldRunLevel - Supplies the original runlevel to return to, as returned by
  482. the acquire lock function.
  483. Return Value:
  484. None.
  485. --*/
  486. {
  487. if (Controller->QueuedLock != NULL) {
  488. ASSERT((Controller->RunLevel == RunLevelLow) &&
  489. (KeGetRunLevel() == RunLevelLow));
  490. KeReleaseQueuedLock(Controller->QueuedLock);
  491. } else {
  492. KeReleaseSpinLock(&(Controller->SpinLock));
  493. KeLowerRunLevel(OldRunLevel);
  494. }
  495. return;
  496. }
  497. //
  498. // --------------------------------------------------------- Internal Functions
  499. //
  500. VOID
  501. GpioDriverUnload (
  502. PVOID Driver
  503. )
  504. /*++
  505. Routine Description:
  506. This routine is called before a driver is about to be unloaded from memory.
  507. The driver should take this opportunity to free any resources it may have
  508. set up in the driver entry routine.
  509. Arguments:
  510. Driver - Supplies a pointer to the driver being torn down.
  511. Return Value:
  512. None.
  513. --*/
  514. {
  515. return;
  516. }
  517. KSTATUS
  518. GpioOpenPin (
  519. PGPIO_ACCESS_INTERFACE Interface,
  520. ULONG Pin,
  521. PGPIO_PIN_HANDLE PinHandle
  522. )
  523. /*++
  524. Routine Description:
  525. This routine opens a new connection to a GPIO pin.
  526. Arguments:
  527. Interface - Supplies a pointer to the interface handle.
  528. Pin - Supplies the zero-based pin number to open.
  529. PinHandle - Supplies a pointer where a GPIO pin handle will be returned on
  530. success.
  531. Return Value:
  532. Status code.
  533. --*/
  534. {
  535. PGPIO_CONTROLLER Controller;
  536. PGPIO_PIN_HANDLE_DATA Handle;
  537. RUNLEVEL OldRunLevel;
  538. PGPIO_INTERFACE PrivateInterface;
  539. KSTATUS Status;
  540. PrivateInterface = Interface->Context;
  541. Handle = MmAllocateNonPagedPool(sizeof(GPIO_PIN_HANDLE_DATA),
  542. GPIO_ALLOCATION_TAG);
  543. if (Handle == NULL) {
  544. return STATUS_INSUFFICIENT_RESOURCES;
  545. }
  546. Controller = PARENT_STRUCTURE(PrivateInterface, GPIO_CONTROLLER, Interface);
  547. OldRunLevel = GpioLockController(Controller);
  548. ASSERT(Controller->Magic == GPIO_CONTROLLER_MAGIC);
  549. if (Pin >= Controller->Host.LineCount) {
  550. Status = STATUS_INVALID_PARAMETER;
  551. goto OpenPinEnd;
  552. }
  553. if ((Controller->Pins[Pin].Flags & GPIO_PIN_ACQUIRED) != 0) {
  554. Status = STATUS_RESOURCE_IN_USE;
  555. goto OpenPinEnd;
  556. }
  557. RtlZeroMemory(Handle, sizeof(GPIO_PIN_HANDLE_DATA));
  558. Handle->Magic = GPIO_PIN_HANDLE_MAGIC;
  559. Handle->Interface = PrivateInterface;
  560. Handle->Controller = Controller;
  561. Handle->Pin = Pin;
  562. INSERT_BEFORE(&(Handle->ListEntry), &(PrivateInterface->Handles));
  563. Controller->Pins[Pin].Flags |= GPIO_PIN_ACQUIRED;
  564. Status = STATUS_SUCCESS;
  565. OpenPinEnd:
  566. GpioUnlockController(Controller, OldRunLevel);
  567. if (!KSUCCESS(Status)) {
  568. if (Handle != NULL) {
  569. MmFreeNonPagedPool(Handle);
  570. Handle = NULL;
  571. }
  572. }
  573. *PinHandle = (GPIO_PIN_HANDLE)Handle;
  574. return Status;
  575. }
  576. VOID
  577. GpioClosePin (
  578. PGPIO_ACCESS_INTERFACE Interface,
  579. GPIO_PIN_HANDLE PinHandle
  580. )
  581. /*++
  582. Routine Description:
  583. This routine closes a previously opened GPIO pin handle.
  584. Arguments:
  585. Interface - Supplies a pointer to the interface handle.
  586. PinHandle - Supplies the GPIO pin handle to close.
  587. Return Value:
  588. None.
  589. --*/
  590. {
  591. PGPIO_CONTROLLER Controller;
  592. PGPIO_PIN_HANDLE_DATA Handle;
  593. RUNLEVEL OldRunLevel;
  594. Handle = (PGPIO_PIN_HANDLE_DATA)PinHandle;
  595. ASSERT(Handle->Magic == GPIO_PIN_HANDLE_MAGIC);
  596. ASSERT(Handle->ListEntry.Next != NULL);
  597. Controller = Handle->Controller;
  598. OldRunLevel = GpioLockController(Controller);
  599. LIST_REMOVE(&(Handle->ListEntry));
  600. Handle->ListEntry.Next = NULL;
  601. Controller->Pins[Handle->Pin].Flags &= ~GPIO_PIN_ACQUIRED;
  602. Handle->Magic += 1;
  603. GpioUnlockController(Controller, OldRunLevel);
  604. MmFreeNonPagedPool(Handle);
  605. return;
  606. }
  607. KSTATUS
  608. GpioPinSetConfiguration (
  609. GPIO_PIN_HANDLE PinHandle,
  610. PGPIO_PIN_CONFIGURATION Configuration
  611. )
  612. /*++
  613. Routine Description:
  614. This routine sets the complete configuration for a GPIO pin.
  615. Arguments:
  616. PinHandle - Supplies the pin handle previously opened with the open pin
  617. interface function.
  618. Configuration - Supplies a pointer to the new configuration to set.
  619. Return Value:
  620. Status code.
  621. --*/
  622. {
  623. PGPIO_CONTROLLER Controller;
  624. PGPIO_PIN_HANDLE_DATA Handle;
  625. PGPIO_CONTROLLER_INFORMATION Host;
  626. RUNLEVEL OldRunLevel;
  627. KSTATUS Status;
  628. Handle = (PGPIO_PIN_HANDLE_DATA)PinHandle;
  629. ASSERT(Handle->Magic == GPIO_PIN_HANDLE_MAGIC);
  630. Controller = Handle->Controller;
  631. OldRunLevel = GpioLockController(Controller);
  632. Host = &(Controller->Host);
  633. Status = Host->FunctionTable.SetConfiguration(Host->Context,
  634. Handle->Pin,
  635. Configuration);
  636. if (KSUCCESS(Status)) {
  637. RtlCopyMemory(&(Controller->Pins[Handle->Pin]),
  638. Configuration,
  639. sizeof(GPIO_PIN_CONFIGURATION));
  640. Controller->Pins[Handle->Pin].Flags |=
  641. GPIO_PIN_ACQUIRED | GPIO_PIN_CONFIGURED;
  642. }
  643. GpioUnlockController(Controller, OldRunLevel);
  644. return Status;
  645. }
  646. KSTATUS
  647. GpioPinSetDirection (
  648. GPIO_PIN_HANDLE PinHandle,
  649. ULONG Flags
  650. )
  651. /*++
  652. Routine Description:
  653. This routine sets the complete configuration for an open GPIO pin.
  654. Arguments:
  655. PinHandle - Supplies the pin handle previously opened with the open pin
  656. interface function.
  657. Flags - Supplies the GPIO_* configuration flags to set. Only GPIO_OUTPUT
  658. and GPIO_OUTPUT_HIGH are observed, all other flags are ignored.
  659. Return Value:
  660. Status code.
  661. --*/
  662. {
  663. PGPIO_CONTROLLER Controller;
  664. PGPIO_PIN_HANDLE_DATA Handle;
  665. PGPIO_CONTROLLER_INFORMATION Host;
  666. RUNLEVEL OldRunLevel;
  667. KSTATUS Status;
  668. Handle = (PGPIO_PIN_HANDLE_DATA)PinHandle;
  669. ASSERT(Handle->Magic == GPIO_PIN_HANDLE_MAGIC);
  670. Controller = Handle->Controller;
  671. OldRunLevel = GpioLockController(Controller);
  672. Host = &(Controller->Host);
  673. Status = Host->FunctionTable.SetDirection(Host->Context,
  674. Handle->Pin,
  675. Flags);
  676. GpioUnlockController(Controller, OldRunLevel);
  677. return Status;
  678. }
  679. VOID
  680. GpioPinSetValue (
  681. GPIO_PIN_HANDLE PinHandle,
  682. ULONG Value
  683. )
  684. /*++
  685. Routine Description:
  686. This routine sets the output value on a GPIO pin.
  687. Arguments:
  688. PinHandle - Supplies the pin handle previously opened with the open pin
  689. interface function.
  690. Value - Supplies the value to set on the pin: zero for low, non-zero for
  691. high.
  692. Return Value:
  693. None.
  694. --*/
  695. {
  696. PGPIO_CONTROLLER Controller;
  697. PGPIO_PIN_HANDLE_DATA Handle;
  698. PGPIO_CONTROLLER_INFORMATION Host;
  699. RUNLEVEL OldRunLevel;
  700. Handle = (PGPIO_PIN_HANDLE_DATA)PinHandle;
  701. ASSERT(Handle->Magic == GPIO_PIN_HANDLE_MAGIC);
  702. Controller = Handle->Controller;
  703. OldRunLevel = GpioLockController(Controller);
  704. Host = &(Controller->Host);
  705. Host->FunctionTable.SetValue(Host->Context, Handle->Pin, Value);
  706. GpioUnlockController(Controller, OldRunLevel);
  707. return;
  708. }
  709. ULONG
  710. GpioPinGetValue (
  711. GPIO_PIN_HANDLE PinHandle
  712. )
  713. /*++
  714. Routine Description:
  715. This routine gets the input value on a GPIO pin.
  716. Arguments:
  717. PinHandle - Supplies the pin handle previously opened with the open pin
  718. interface function.
  719. Return Value:
  720. 0 if the value was low.
  721. 1 if the value was high.
  722. -1 on error.
  723. --*/
  724. {
  725. PGPIO_CONTROLLER Controller;
  726. PGPIO_PIN_HANDLE_DATA Handle;
  727. PGPIO_CONTROLLER_INFORMATION Host;
  728. RUNLEVEL OldRunLevel;
  729. ULONG Result;
  730. Handle = (PGPIO_PIN_HANDLE_DATA)PinHandle;
  731. ASSERT(Handle->Magic == GPIO_PIN_HANDLE_MAGIC);
  732. Controller = Handle->Controller;
  733. OldRunLevel = GpioLockController(Controller);
  734. Host = &(Controller->Host);
  735. Result = Host->FunctionTable.GetValue(Host->Context, Handle->Pin);
  736. GpioUnlockController(Controller, OldRunLevel);
  737. return Result;
  738. }
  739. KSTATUS
  740. GpioPrepareForInterrupts (
  741. PVOID Context
  742. )
  743. /*++
  744. Routine Description:
  745. This routine initializes an interrupt controller. It's responsible for
  746. masking all interrupt lines on the controller and setting the current
  747. priority to the lowest (allow all interrupts). Once completed successfully,
  748. it is expected that interrupts can be enabled at the processor core with
  749. no interrupts occurring.
  750. Arguments:
  751. Context - Supplies the pointer to the controller's context, provided by the
  752. hardware module upon initialization.
  753. Return Value:
  754. STATUS_SUCCESS on success.
  755. Other status codes on failure.
  756. --*/
  757. {
  758. PGPIO_CONTROLLER Controller;
  759. PGPIO_CONTROLLER_INFORMATION Host;
  760. RUNLEVEL OldRunLevel;
  761. KSTATUS Status;
  762. Controller = Context;
  763. Host = &(Controller->Host);
  764. OldRunLevel = GpioLockController(Controller);
  765. Status = Host->FunctionTable.PrepareForInterrupts(Host->Context);
  766. GpioUnlockController(Controller, OldRunLevel);
  767. return Status;
  768. }
  769. KSTATUS
  770. GpioSetInterruptLineState (
  771. PVOID Context,
  772. PINTERRUPT_LINE Line,
  773. PINTERRUPT_LINE_STATE State,
  774. PVOID ResourceData,
  775. UINTN ResourceDataSize
  776. )
  777. /*++
  778. Routine Description:
  779. This routine enables or disables and configures an interrupt line.
  780. Arguments:
  781. Context - Supplies the pointer to the controller's context, provided by the
  782. hardware module upon initialization.
  783. Line - Supplies a pointer to the line to set up. This will always be a
  784. controller specified line.
  785. State - Supplies a pointer to the new configuration of the line.
  786. ResourceData - Supplies an optional pointer to the device specific resource
  787. data for the interrupt line.
  788. ResourceDataSize - Supplies the size of the resource data, in bytes.
  789. Return Value:
  790. Status code.
  791. --*/
  792. {
  793. PGPIO_CONTROLLER Controller;
  794. PRESOURCE_GPIO_DATA GpioData;
  795. RESOURCE_GPIO_DATA GpioDataBuffer;
  796. PGPIO_CONTROLLER_INFORMATION Host;
  797. RUNLEVEL OldRunLevel;
  798. PGPIO_PIN_CONFIGURATION Pin;
  799. KSTATUS Status;
  800. //
  801. // Before acquiring the controller lock, touch any paged-pool objects. This
  802. // includes the resource data. The lock may be acquired at a non-low
  803. // runlevel.
  804. //
  805. GpioData = ResourceData;
  806. if (GpioData != NULL) {
  807. if ((ResourceDataSize < sizeof(RESOURCE_GPIO_DATA)) ||
  808. (GpioData->Version < RESOURCE_GPIO_DATA_VERSION)) {
  809. return STATUS_VERSION_MISMATCH;
  810. }
  811. RtlCopyMemory(&GpioDataBuffer, GpioData, sizeof(RESOURCE_GPIO_DATA));
  812. GpioData = &GpioDataBuffer;
  813. }
  814. Controller = Context;
  815. OldRunLevel = GpioLockController(Controller);
  816. Host = &(Controller->Host);
  817. Pin = &(Controller->Pins[Line->U.Local.Line]);
  818. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) == 0) {
  819. Pin->Flags = GPIO_PIN_CONFIGURED | GPIO_PIN_ACQUIRED;
  820. } else {
  821. Pin->Flags = GPIO_INTERRUPT | GPIO_PIN_CONFIGURED | GPIO_PIN_ACQUIRED;
  822. if (State->Mode == InterruptModeEdge) {
  823. Pin->Flags |= GPIO_INTERRUPT_EDGE_TRIGGERED;
  824. }
  825. if (State->Polarity == InterruptActiveHigh) {
  826. Pin->Flags |= GPIO_INTERRUPT_RISING_EDGE;
  827. } else if (State->Polarity == InterruptActiveLow) {
  828. Pin->Flags |= GPIO_INTERRUPT_FALLING_EDGE;
  829. } else if (State->Polarity == InterruptActiveBoth) {
  830. Pin->Flags |= GPIO_INTERRUPT_RISING_EDGE |
  831. GPIO_INTERRUPT_FALLING_EDGE;
  832. }
  833. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_DEBOUNCE) != 0) {
  834. Pin->Flags |= GPIO_ENABLE_DEBOUNCE;
  835. }
  836. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_WAKE) != 0) {
  837. Pin->Flags |= GPIO_INTERRUPT_WAKE;
  838. }
  839. if (GpioData != NULL) {
  840. if ((GpioData->Flags & RESOURCE_GPIO_PULL_NONE) ==
  841. RESOURCE_GPIO_PULL_NONE) {
  842. Pin->Flags |= GPIO_PULL_NONE;
  843. } else if ((GpioData->Flags & RESOURCE_GPIO_PULL_UP) != 0) {
  844. Pin->Flags |= GPIO_PULL_UP;
  845. } else if ((GpioData->Flags & RESOURCE_GPIO_PULL_DOWN) != 0) {
  846. Pin->Flags |= GPIO_PULL_DOWN;
  847. }
  848. Pin->OutputDriveStrength = GpioData->OutputDriveStrength;
  849. Pin->DebounceTimeout = GpioData->DebounceTimeout;
  850. }
  851. }
  852. Status = Host->FunctionTable.SetConfiguration(Host->Context,
  853. Line->U.Local.Line,
  854. Pin);
  855. if (!KSUCCESS(Status)) {
  856. Pin->Flags &= ~GPIO_PIN_CONFIGURED;
  857. }
  858. GpioUnlockController(Controller, OldRunLevel);
  859. return Status;
  860. }
  861. VOID
  862. GpioInterruptMaskLine (
  863. PVOID Context,
  864. PINTERRUPT_LINE Line,
  865. BOOL Enable
  866. )
  867. /*++
  868. Routine Description:
  869. This routine masks or unmasks an interrupt line, leaving the rest of the
  870. line state intact.
  871. Arguments:
  872. Context - Supplies the pointer to the controller's context, provided by the
  873. hardware module upon initialization.
  874. Line - Supplies a pointer to the line to maek or unmask. This will always
  875. be a controller specified line.
  876. Enable - Supplies a boolean indicating whether to mask the interrupt,
  877. preventing interrupts from coming through (FALSE), or enable the line
  878. and allow interrupts to come through (TRUE).
  879. Return Value:
  880. None.
  881. --*/
  882. {
  883. PGPIO_CONTROLLER Controller;
  884. PGPIO_CONTROLLER_INFORMATION Host;
  885. RUNLEVEL OldRunLevel;
  886. Controller = Context;
  887. OldRunLevel = GpioLockController(Controller);
  888. Host = &(Controller->Host);
  889. Host->FunctionTable.MaskInterruptLine(Host->Context, Line, Enable);
  890. GpioUnlockController(Controller, OldRunLevel);
  891. return;
  892. }
  893. INTERRUPT_CAUSE
  894. GpioInterruptBegin (
  895. PVOID Context,
  896. PINTERRUPT_LINE FiringLine,
  897. PULONG MagicCandy
  898. )
  899. /*++
  900. Routine Description:
  901. This routine is called when an interrupt fires. Its role is to determine
  902. if an interrupt has fired on the given controller, accept it, and determine
  903. which line fired if any. This routine will always be called with interrupts
  904. disabled at the processor core.
  905. Arguments:
  906. Context - Supplies the pointer to the controller's context, provided by the
  907. hardware module upon initialization.
  908. FiringLine - Supplies a pointer where the interrupt hardware module will
  909. fill in which line fired, if applicable.
  910. MagicCandy - Supplies a pointer where the interrupt hardware module can
  911. store 32 bits of private information regarding this interrupt. This
  912. information will be returned to it when the End Of Interrupt routine
  913. is called.
  914. Return Value:
  915. Returns an interrupt cause indicating whether or not an interrupt line,
  916. spurious interrupt, or no interrupt fired on this controller.
  917. --*/
  918. {
  919. PGPIO_CONTROLLER Controller;
  920. PGPIO_CONTROLLER_INFORMATION Host;
  921. RUNLEVEL OldRunLevel;
  922. INTERRUPT_CAUSE Result;
  923. Controller = Context;
  924. OldRunLevel = GpioLockController(Controller);
  925. Host = &(Controller->Host);
  926. Result = Host->FunctionTable.BeginInterrupt(Host->Context,
  927. FiringLine,
  928. MagicCandy);
  929. GpioUnlockController(Controller, OldRunLevel);
  930. return Result;
  931. }
  932. VOID
  933. GpioEndOfInterrupt (
  934. PVOID Context,
  935. ULONG MagicCandy
  936. )
  937. /*++
  938. Routine Description:
  939. This routine is called after an interrupt has fired and been serviced. Its
  940. role is to tell the interrupt controller that processing has completed.
  941. This routine will always be called with interrupts disabled at the
  942. processor core.
  943. Arguments:
  944. Context - Supplies the pointer to the controller's context, provided by the
  945. hardware module upon initialization.
  946. MagicCandy - Supplies the magic candy that that the interrupt hardware
  947. module stored when the interrupt began.
  948. Return Value:
  949. None.
  950. --*/
  951. {
  952. PGPIO_CONTROLLER Controller;
  953. PGPIO_CONTROLLER_INFORMATION Host;
  954. RUNLEVEL OldRunLevel;
  955. Controller = Context;
  956. Host = &(Controller->Host);
  957. OldRunLevel = GpioLockController(Controller);
  958. Host->FunctionTable.EndOfInterrupt(Host->Context, MagicCandy);
  959. GpioUnlockController(Controller, OldRunLevel);
  960. return;
  961. }
  962. KSTATUS
  963. GpioRequestInterrupt (
  964. PVOID Context,
  965. PINTERRUPT_LINE Line,
  966. ULONG Vector,
  967. PINTERRUPT_HARDWARE_TARGET Target
  968. )
  969. /*++
  970. Routine Description:
  971. This routine requests a hardware interrupt on the given line.
  972. Arguments:
  973. Context - Supplies the pointer to the controller's context, provided by the
  974. hardware module upon initialization.
  975. Line - Supplies a pointer to the interrupt line to spark.
  976. Vector - Supplies the vector to generate the interrupt on (for vectored
  977. architectures only).
  978. Target - Supplies a pointer to the set of processors to target.
  979. Return Value:
  980. STATUS_SUCCESS on success.
  981. Error code on failure.
  982. --*/
  983. {
  984. PGPIO_CONTROLLER Controller;
  985. PGPIO_CONTROLLER_INFORMATION Host;
  986. RUNLEVEL OldRunLevel;
  987. KSTATUS Status;
  988. Controller = Context;
  989. OldRunLevel = GpioLockController(Controller);
  990. Host = &(Controller->Host);
  991. Status = Host->FunctionTable.RequestInterrupt(Host->Context,
  992. Line,
  993. Vector,
  994. Target);
  995. GpioUnlockController(Controller, OldRunLevel);
  996. return Status;
  997. }