Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

484 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. button.c
  5. Abstract:
  6. Fixed button support
  7. Author:
  8. Stephane Plante (splante)
  9. Environment:
  10. NT Kernel Model Driver only
  11. Revision History:
  12. July 7, 1997 - Complete Rewrite
  13. --*/
  14. #include "pch.h"
  15. PDEVICE_OBJECT FixedButtonDeviceObject;
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, ACPIButtonStartDevice)
  18. #endif
  19. //
  20. // Spinlock to protect the thermal list
  21. //
  22. KSPIN_LOCK AcpiButtonLock;
  23. //
  24. // List entry to store the thermal requests on
  25. //
  26. LIST_ENTRY AcpiButtonList;
  27. VOID
  28. ACPIButtonCancelRequest(
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN PIRP Irp
  31. )
  32. /*++
  33. Routine Description:
  34. This routine cancels an outstanding button request
  35. Arguments:
  36. DeviceObject - the device which as a request being cancelled
  37. Irp - the cancelling irp
  38. Return Value:
  39. None
  40. --*/
  41. {
  42. KIRQL oldIrql;
  43. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  44. //
  45. // We no longer need the cancel lock
  46. //
  47. IoReleaseCancelSpinLock( Irp->CancelIrql );
  48. //
  49. // We do however need the button queue lock
  50. //
  51. KeAcquireSpinLock( &AcpiButtonLock, &oldIrql );
  52. //
  53. // Remove the irp from the list that it is on
  54. //
  55. RemoveEntryList( &(Irp->Tail.Overlay.ListEntry) );
  56. //
  57. // Complete the irp now
  58. //
  59. Irp->IoStatus.Status = STATUS_CANCELLED;
  60. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  61. }
  62. BOOLEAN
  63. ACPIButtonCompletePendingIrps(
  64. IN PDEVICE_OBJECT DeviceObject,
  65. IN ULONG ButtonEvent
  66. )
  67. /*++
  68. Routine Description:
  69. This routine completes any pending button irp sent to the specified
  70. device object with the knowledge of which button events have occured
  71. The respective's button's spinlock is held during this call
  72. Arguments:
  73. DeviceObject - the target button object
  74. ButtonEvent - the button event that occured
  75. Return Value:
  76. TRUE if we completed an irp, FALSE, otherwise
  77. --*/
  78. {
  79. BOOLEAN handledRequest = FALSE;
  80. KIRQL oldIrql;
  81. LIST_ENTRY doneList;
  82. PDEVICE_OBJECT targetObject;
  83. PIO_STACK_LOCATION irpSp;
  84. PIRP irp;
  85. PLIST_ENTRY listEntry;
  86. PULONG resultBuffer;
  87. //
  88. // Initialize the list that will hold the requests that we need to
  89. // complete
  90. //
  91. InitializeListHead( &doneList );
  92. //
  93. // Acquire the thermal lock so that we can pend these requests
  94. //
  95. KeAcquireSpinLock( &AcpiButtonLock, &oldIrql );
  96. //
  97. // Walk the list of pending irps to see which ones match this extension
  98. //
  99. listEntry = AcpiButtonList.Flink;
  100. while (listEntry != &AcpiButtonList) {
  101. //
  102. // Grab the irp from the list entry and update the next list entry
  103. // that we will look at
  104. //
  105. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  106. listEntry = listEntry->Flink;
  107. //
  108. // We need the current irp stack location
  109. //
  110. irpSp = IoGetCurrentIrpStackLocation( irp );
  111. //
  112. // what is the target object for this irp?
  113. //
  114. targetObject = irpSp->DeviceObject;
  115. //
  116. // Is this an irp that we care about? IE: does the does target mage
  117. // the ones specified in this function
  118. //
  119. if (targetObject != DeviceObject) {
  120. continue;
  121. }
  122. //
  123. // At this point, we need to set the cancel routine to NULL because
  124. // we are going to take care of this irp and we don't want it cancelled
  125. // underneath us
  126. //
  127. if (IoSetCancelRoutine(irp, NULL) == NULL) {
  128. //
  129. // Cancel routine is active. stop processing this irp and move on
  130. //
  131. continue;
  132. }
  133. //
  134. // set the data to return in the irp
  135. //
  136. resultBuffer = (PULONG) irp->AssociatedIrp.SystemBuffer;
  137. *resultBuffer = ButtonEvent;
  138. irp->IoStatus.Status = STATUS_SUCCESS;
  139. irp->IoStatus.Information = sizeof(ULONG);
  140. //
  141. // Remove the entry from the list
  142. //
  143. RemoveEntryList( &(irp->Tail.Overlay.ListEntry) );
  144. //
  145. // Insert the list onto the next queue, so that we know how to
  146. // complete it later on
  147. //
  148. InsertTailList( &doneList, &(irp->Tail.Overlay.ListEntry) );
  149. }
  150. //
  151. // At this point, droup our button lock
  152. //
  153. KeReleaseSpinLock( &AcpiButtonLock, oldIrql );
  154. //
  155. // Walk the list of irps to be completed
  156. //
  157. listEntry = doneList.Flink;
  158. while (listEntry != &doneList) {
  159. //
  160. // Grab the irp from the list entry, update the next list entry
  161. // that we will look at, and complete the request
  162. //
  163. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  164. listEntry = listEntry->Flink;
  165. RemoveEntryList( &(irp->Tail.Overlay.ListEntry) );
  166. //
  167. // Complete the request and remember that we handled a request
  168. //
  169. IoCompleteRequest( irp, IO_NO_INCREMENT );
  170. handledRequest = TRUE;
  171. }
  172. //
  173. // Return wether or not we handled a request
  174. //
  175. return handledRequest;
  176. }
  177. NTSTATUS
  178. ACPIButtonDeviceControl (
  179. IN PDEVICE_OBJECT DeviceObject,
  180. IN PIRP Irp
  181. )
  182. /*++
  183. Routine Description:
  184. Fixed button device IOCTL handler
  185. Arguments:
  186. DeviceObject - fixed feature button device object
  187. Irp - the ioctl request
  188. Return Value:
  189. Status
  190. --*/
  191. {
  192. KIRQL oldIrql;
  193. NTSTATUS status;
  194. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  195. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  196. PULONG resultBuffer;
  197. //
  198. // Do not allow user mode IRPs in this routine
  199. //
  200. if (Irp->RequestorMode != KernelMode) {
  201. return ACPIDispatchIrpInvalid( DeviceObject, Irp );
  202. }
  203. resultBuffer = (PULONG) Irp->AssociatedIrp.SystemBuffer;
  204. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  205. case IOCTL_GET_SYS_BUTTON_CAPS:
  206. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG)) {
  207. status = STATUS_INFO_LENGTH_MISMATCH;
  208. Irp->IoStatus.Information = 0;
  209. } else {
  210. *resultBuffer = deviceExtension->Button.Capabilities;
  211. status = STATUS_SUCCESS;
  212. Irp->IoStatus.Information = sizeof(ULONG);
  213. }
  214. Irp->IoStatus.Status = status;
  215. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  216. break;
  217. case IOCTL_GET_SYS_BUTTON_EVENT:
  218. //
  219. // Make sure our buffer is big enough
  220. //
  221. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG)) {
  222. Irp->IoStatus.Status = status = STATUS_INFO_LENGTH_MISMATCH;
  223. Irp->IoStatus.Information = 0;
  224. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  225. break;
  226. }
  227. //
  228. // Grab the button lock, queue the request to the proper place, and
  229. // make sure to set a cancel routine
  230. //
  231. KeAcquireSpinLock( &AcpiButtonLock, &oldIrql );
  232. IoSetCancelRoutine( Irp, ACPIButtonCancelRequest);
  233. if (Irp->Cancel && IoSetCancelRoutine( Irp, NULL) ) {
  234. //
  235. // If we got here, that measn that the irp has been cancelled and
  236. // that we beat the IO manager to the ButtonLock. So release the
  237. // irp and mark the irp as being cancelled
  238. //
  239. KeReleaseSpinLock( &AcpiButtonLock, oldIrql );
  240. Irp->IoStatus.Information = 0;
  241. Irp->IoStatus.Status = status = STATUS_CANCELLED;
  242. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  243. break;
  244. }
  245. //
  246. // If we got here, that means we are going to the queue the request and so
  247. // some work on it later
  248. //
  249. IoMarkIrpPending( Irp );
  250. //
  251. // Queue the irp into a queue
  252. //
  253. InsertTailList( &AcpiButtonList, &(Irp->Tail.Overlay.ListEntry) );
  254. //
  255. // Done with the lock at this point
  256. //
  257. KeReleaseSpinLock( &AcpiButtonLock, oldIrql );
  258. //
  259. // Fire off the work thread
  260. //
  261. status = ACPIButtonEvent( DeviceObject, 0, NULL );
  262. break ;
  263. default:
  264. status = STATUS_NOT_SUPPORTED;
  265. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  266. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  267. break;
  268. }
  269. return status;
  270. }
  271. NTSTATUS
  272. ACPIButtonEvent (
  273. IN PDEVICE_OBJECT DeviceObject,
  274. IN ULONG ButtonEvent,
  275. IN PIRP Irp
  276. )
  277. /*++
  278. Routine Description:
  279. This routine applies and event mask and irp to the button device.
  280. If there's a pending event and an irp to handle it, the irp will
  281. be completed
  282. Arguments:
  283. DeviceObject - fixed feature button device object
  284. ButtonEvent - events to apply to the device
  285. Irp - irp to capture the next events
  286. Return Value:
  287. Status
  288. --*/
  289. {
  290. BOOLEAN completedIrp;
  291. KIRQL oldIrql;
  292. NTSTATUS status;
  293. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  294. PULONG resultBuffer;
  295. UNREFERENCED_PARAMETER( Irp );
  296. if ((ButtonEvent & (SYS_BUTTON_SLEEP | SYS_BUTTON_POWER | SYS_BUTTON_WAKE)) &&
  297. !(deviceExtension->Button.Capabilities & SYS_BUTTON_LID)) {
  298. //
  299. // Notify that the user is present, except if we happen to be
  300. // messing with the lid. The kernel will set the user-present
  301. // bit there, and we don't want the screen to turn on when
  302. // the user closes the lid.
  303. //
  304. PoSetSystemState (ES_USER_PRESENT);
  305. }
  306. if (!DeviceObject) {
  307. return (STATUS_SUCCESS);
  308. }
  309. //
  310. // Set pending info
  311. //
  312. KeAcquireSpinLock (&(deviceExtension->Button.SpinLock), &oldIrql);
  313. deviceExtension->Button.Events |= ButtonEvent;
  314. //
  315. // Are there any outstanding events? If so, then try to complete all
  316. // the pending irps against that button with the list of events
  317. //
  318. if (deviceExtension->Button.Events) {
  319. completedIrp = ACPIButtonCompletePendingIrps(
  320. DeviceObject,
  321. deviceExtension->Button.Events
  322. );
  323. if (completedIrp) {
  324. deviceExtension->Button.Events = 0;
  325. }
  326. }
  327. KeReleaseSpinLock (&(deviceExtension->Button.SpinLock), oldIrql);
  328. //
  329. // Always return pending
  330. //
  331. return STATUS_PENDING;
  332. }
  333. NTSTATUS
  334. ACPIButtonStartDevice (
  335. IN PDEVICE_OBJECT DeviceObject,
  336. IN PIRP Irp
  337. )
  338. /*++
  339. Routine Description:
  340. Start device function for the fixed feature power and sleep device
  341. Arguments:
  342. DeviceObject - fixed feature button device object
  343. Irp - the start request
  344. Return Value:
  345. Status
  346. --*/
  347. {
  348. NTSTATUS Status;
  349. Status = ACPIInternalSetDeviceInterface (
  350. DeviceObject,
  351. (LPGUID) &GUID_DEVICE_SYS_BUTTON
  352. );
  353. Irp->IoStatus.Status = Status;
  354. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  355. return Status;
  356. }