intrupt.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. intrupt.c
  5. Abstract:
  6. This module implements driver-facing APIs for managing interrupts.
  7. Author:
  8. Evan Green 21-Dec-2012
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "iop.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. #define IO_CONNECT_INTERRUPT_PARAMETERS_MAX_VERSION 0x1000
  21. //
  22. // ------------------------------------------------------ Data Type Definitions
  23. //
  24. //
  25. // ----------------------------------------------- Internal Function Prototypes
  26. //
  27. //
  28. // -------------------------------------------------------------------- Globals
  29. //
  30. //
  31. // ------------------------------------------------------------------ Functions
  32. //
  33. KERNEL_API
  34. KSTATUS
  35. IoConnectInterrupt (
  36. PIO_CONNECT_INTERRUPT_PARAMETERS Parameters
  37. )
  38. /*++
  39. Routine Description:
  40. This routine connects a device's interrupt.
  41. Arguments:
  42. Parameters - Supplies a pointer to a versioned table containing the
  43. parameters of the connection.
  44. Return Value:
  45. STATUS_SUCCESS on success.
  46. STATUS_NOT_READY if the device has no resources or is not started.
  47. STATUS_RESOURCE_IN_USE if the device attempts to connect to an interrupt
  48. it does not own.
  49. Other errors on failure.
  50. --*/
  51. {
  52. PRESOURCE_ALLOCATION Allocation;
  53. PRESOURCE_ALLOCATION_LIST AllocationList;
  54. BOOL Connected;
  55. BOOL Enabled;
  56. PRESOURCE_ALLOCATION LineAllocation;
  57. ULONGLONG LineCharacteristics;
  58. INTERRUPT_LINE_STATE LineState;
  59. PKINTERRUPT NewInterrupt;
  60. KSTATUS Status;
  61. PRESOURCE_ALLOCATION VectorAllocation;
  62. Connected = FALSE;
  63. Enabled = FALSE;
  64. NewInterrupt = NULL;
  65. LineAllocation = NULL;
  66. VectorAllocation = NULL;
  67. if ((Parameters->Version < IO_CONNECT_INTERRUPT_PARAMETERS_VERSION) ||
  68. (Parameters->Version >= IO_CONNECT_INTERRUPT_PARAMETERS_MAX_VERSION)) {
  69. return STATUS_INVALID_PARAMETER;
  70. }
  71. if (Parameters->Device == NULL) {
  72. return STATUS_INVALID_PARAMETER;
  73. }
  74. //
  75. // Ensure that the device has resources.
  76. //
  77. AllocationList = Parameters->Device->ProcessorLocalResources;
  78. if (AllocationList == NULL) {
  79. Status = STATUS_NOT_READY;
  80. goto ConnectInterruptEnd;
  81. }
  82. //
  83. // Ensure that the device owns the line number it's trying to connect to.
  84. //
  85. Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
  86. while (Allocation != NULL) {
  87. if ((VectorAllocation == NULL) &&
  88. (Allocation->Type == ResourceTypeInterruptVector)) {
  89. if ((Allocation->Allocation <= Parameters->Vector) &&
  90. (Allocation->Allocation + Allocation->Length >
  91. Parameters->Vector)) {
  92. VectorAllocation = Allocation;
  93. }
  94. } else if ((Parameters->LineNumber != INVALID_INTERRUPT_LINE) &&
  95. (LineAllocation == NULL) &&
  96. (Allocation->Type == ResourceTypeInterruptLine)) {
  97. if ((Allocation->Allocation <= Parameters->LineNumber) &&
  98. (Allocation->Allocation + Allocation->Length >
  99. Parameters->LineNumber)) {
  100. LineAllocation = Allocation;
  101. }
  102. }
  103. //
  104. // If both are found stop looking.
  105. //
  106. if ((VectorAllocation != NULL) &&
  107. ((Parameters->LineNumber == INVALID_INTERRUPT_LINE) ||
  108. (LineAllocation != NULL))) {
  109. break;
  110. }
  111. Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
  112. }
  113. //
  114. // If the device is trying to pull a fast one and doesn't own the
  115. // resources its connecting to, fail.
  116. //
  117. if ((VectorAllocation == NULL) ||
  118. ((Parameters->LineNumber != INVALID_INTERRUPT_LINE) &&
  119. (LineAllocation == NULL))) {
  120. Status = STATUS_RESOURCE_IN_USE;
  121. goto ConnectInterruptEnd;
  122. }
  123. //
  124. // If the vector and line allocations are not connected then something is
  125. // wrong. The line might not be targeting the correct vector.
  126. //
  127. if ((Parameters->LineNumber != INVALID_INTERRUPT_LINE) &&
  128. (VectorAllocation->OwningAllocation != LineAllocation)) {
  129. Status = STATUS_INVALID_PARAMETER;
  130. goto ConnectInterruptEnd;
  131. }
  132. //
  133. // Attempt to create an interrupt.
  134. //
  135. NewInterrupt = HlCreateInterrupt(Parameters->Vector,
  136. Parameters->InterruptServiceRoutine,
  137. Parameters->DispatchServiceRoutine,
  138. Parameters->LowLevelServiceRoutine,
  139. Parameters->Context);
  140. if (NewInterrupt == NULL) {
  141. Status = STATUS_INSUFFICIENT_RESOURCES;
  142. goto ConnectInterruptEnd;
  143. }
  144. //
  145. // Attempt to wire up the ISR.
  146. //
  147. *(Parameters->Interrupt) = NewInterrupt;
  148. Status = HlConnectInterrupt(NewInterrupt);
  149. if (!KSUCCESS(Status)) {
  150. goto ConnectInterruptEnd;
  151. }
  152. Connected = TRUE;
  153. //
  154. // If a valid line number was supplied, then enable the interrupt line.
  155. //
  156. if (Parameters->LineNumber != INVALID_INTERRUPT_LINE) {
  157. LineState.Flags = 0;
  158. LineCharacteristics = LineAllocation->Characteristics;
  159. //
  160. // Set up the interrupt mode and polarity.
  161. //
  162. LineState.Polarity = InterruptActiveLevelUnknown;
  163. if ((LineCharacteristics & INTERRUPT_LINE_ACTIVE_HIGH) != 0) {
  164. if ((LineCharacteristics & INTERRUPT_LINE_ACTIVE_LOW) != 0) {
  165. LineState.Polarity = InterruptActiveBoth;
  166. } else {
  167. LineState.Polarity = InterruptActiveHigh;
  168. }
  169. } else if ((LineCharacteristics & INTERRUPT_LINE_ACTIVE_LOW) != 0) {
  170. LineState.Polarity = InterruptActiveLow;
  171. }
  172. LineState.Mode = InterruptModeLevel;
  173. if ((LineCharacteristics & INTERRUPT_LINE_EDGE_TRIGGERED) != 0) {
  174. LineState.Mode = InterruptModeEdge;
  175. }
  176. //
  177. // Set any other flags.
  178. //
  179. if ((LineCharacteristics & INTERRUPT_LINE_WAKE) != 0) {
  180. LineState.Flags |= INTERRUPT_LINE_STATE_FLAG_WAKE;
  181. }
  182. if ((LineCharacteristics & INTERRUPT_LINE_DEBOUNCE) != 0) {
  183. LineState.Flags |= INTERRUPT_LINE_STATE_FLAG_DEBOUNCE;
  184. }
  185. //
  186. // Now attempt to enable the interrupt line.
  187. //
  188. Status = HlEnableInterruptLine(Parameters->LineNumber,
  189. &LineState,
  190. NewInterrupt,
  191. LineAllocation->Data,
  192. LineAllocation->DataSize);
  193. if (!KSUCCESS(Status)) {
  194. goto ConnectInterruptEnd;
  195. }
  196. Enabled = TRUE;
  197. }
  198. Status = STATUS_SUCCESS;
  199. ConnectInterruptEnd:
  200. if (!KSUCCESS(Status)) {
  201. if (NewInterrupt != NULL) {
  202. if (Enabled != FALSE) {
  203. HlDisableInterruptLine(NewInterrupt);
  204. }
  205. if (Connected != FALSE) {
  206. HlDisconnectInterrupt(NewInterrupt);
  207. }
  208. HlDestroyInterrupt(NewInterrupt);
  209. }
  210. *(Parameters->Interrupt) = INVALID_HANDLE;
  211. }
  212. return Status;
  213. }
  214. KERNEL_API
  215. VOID
  216. IoDisconnectInterrupt (
  217. HANDLE InterruptHandle
  218. )
  219. /*++
  220. Routine Description:
  221. This routine disconnects a device's interrupt. The device must not
  222. generate interrupts when this routine is called, as the interrupt line
  223. may remain open to service other devices connected to the line.
  224. Arguments:
  225. InterruptHandle - Supplies the handle to the interrupt, returned when the
  226. interrupt was connected.
  227. Return Value:
  228. None.
  229. --*/
  230. {
  231. PKINTERRUPT Interrupt;
  232. Interrupt = (PKINTERRUPT)InterruptHandle;
  233. //
  234. // Disable the interrupt line, then disconnect the vector.
  235. //
  236. HlDisableInterruptLine(Interrupt);
  237. HlDisconnectInterrupt(Interrupt);
  238. //
  239. // Destroy the interrupt.
  240. //
  241. HlDestroyInterrupt(Interrupt);
  242. return;
  243. }
  244. KERNEL_API
  245. RUNLEVEL
  246. IoRaiseToInterruptRunLevel (
  247. HANDLE InterruptHandle
  248. )
  249. /*++
  250. Routine Description:
  251. This routine raises the current run level to that of the given connected
  252. interrupt. Callers should use KeLowerRunLevel to return from the run level
  253. raised to here.
  254. Arguments:
  255. InterruptHandle - Supplies the handle to the interrupt, returned when the
  256. interrupt was connected.
  257. Return Value:
  258. Returns the run level of the current processor immediately before it was
  259. raised by this function.
  260. --*/
  261. {
  262. PKINTERRUPT Interrupt;
  263. ASSERT((InterruptHandle != INVALID_HANDLE) && (InterruptHandle != NULL));
  264. Interrupt = (PKINTERRUPT)InterruptHandle;
  265. return KeRaiseRunLevel(Interrupt->RunLevel);
  266. }
  267. KERNEL_API
  268. RUNLEVEL
  269. IoGetInterruptRunLevel (
  270. PHANDLE Handles,
  271. UINTN HandleCount
  272. )
  273. /*++
  274. Routine Description:
  275. This routine determines the highest runlevel between all of the
  276. connected interrupt handles given.
  277. Arguments:
  278. Handles - Supplies an pointer to an array of connected interrupt handles.
  279. HandleCount - Supplies the number of elements in the array.
  280. Return Value:
  281. Returns the highest runlevel between all connected interrupts. This is
  282. the runlevel to synchronize to if trying to synchronize a device with
  283. multiple interrupts.
  284. --*/
  285. {
  286. UINTN Index;
  287. PKINTERRUPT Interrupt;
  288. RUNLEVEL Runlevel;
  289. Runlevel = RunLevelLow;
  290. for (Index = 0; Index < HandleCount; Index += 1) {
  291. Interrupt = Handles[Index];
  292. if (Interrupt->RunLevel > Runlevel) {
  293. Runlevel = Interrupt->RunLevel;
  294. }
  295. }
  296. return Runlevel;
  297. }
  298. //
  299. // --------------------------------------------------------- Internal Functions
  300. //