Source code of Windows XP (NT5)
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.

391 lines
11 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. detect.c
  5. Abstract:
  6. Detection of surprise removal of the mouse.
  7. Environment:
  8. Kernel mode only.
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "stdarg.h"
  13. #include "stdio.h"
  14. #include "string.h"
  15. #include "ntddk.h"
  16. #include "mouser.h"
  17. #include "sermlog.h"
  18. #include "debug.h"
  19. VOID
  20. SerialMouseSerialMaskEventWorker(
  21. PDEVICE_OBJECT DeviceObject,
  22. PIO_WORKITEM Item
  23. );
  24. NTSTATUS
  25. SerialMouseSerialMaskEventComplete (
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp,
  28. IN PVOID Context
  29. );
  30. NTSTATUS
  31. SerialMouseSendWaitMaskIrp(
  32. IN PDEVICE_EXTENSION DeviceExtension
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(PAGE, SerialMouseSerialMaskEventWorker)
  36. #pragma alloc_text(PAGE, SerialMouseStartDetection)
  37. #pragma alloc_text(PAGE, SerialMouseStopDetection)
  38. #pragma alloc_text(PAGE, SerialMouseSendWaitMaskIrp)
  39. #endif
  40. NTSTATUS
  41. SerialMouseSendWaitMaskIrp(
  42. IN PDEVICE_EXTENSION DeviceExtension
  43. )
  44. {
  45. PIRP irp;
  46. PIO_STACK_LOCATION next;
  47. NTSTATUS status;
  48. PAGED_CODE();
  49. irp = DeviceExtension->DetectionIrp;
  50. DeviceExtension->SerialEventBits = 0x0;
  51. //
  52. // Will be released in the completion routine
  53. //
  54. status = IoAcquireRemoveLock (&DeviceExtension->RemoveLock, irp);
  55. if (!NT_SUCCESS(status)) {
  56. return status;
  57. }
  58. IoReuseIrp(irp, STATUS_SUCCESS);
  59. next = IoGetNextIrpStackLocation(irp);
  60. next->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  61. next->Parameters.DeviceIoControl.IoControlCode = IOCTL_SERIAL_WAIT_ON_MASK;
  62. next->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ULONG);
  63. irp->AssociatedIrp.SystemBuffer = &DeviceExtension->SerialEventBits;
  64. //
  65. // Hook a completion routine for when the device completes.
  66. //
  67. IoSetCompletionRoutine(irp,
  68. SerialMouseSerialMaskEventComplete,
  69. DeviceExtension,
  70. TRUE,
  71. TRUE,
  72. TRUE);
  73. return IoCallDriver(DeviceExtension->TopOfStack, irp);
  74. }
  75. VOID
  76. SerialMouseStartDetection(
  77. PDEVICE_EXTENSION DeviceExtension
  78. )
  79. /*++
  80. Routine Description
  81. This will cancel any previous set on the timer and queue the timer for
  82. DetectionTimeout # of seconds and repeatedly trigger the timer every
  83. DetectionTimeout # of seconds.
  84. Arguments:
  85. DeviceExtension - pointer to the device extension
  86. Return Value:
  87. None
  88. --*/
  89. {
  90. IO_STATUS_BLOCK iosb;
  91. KEVENT event;
  92. ULONG waitMask, bits = 0x0;
  93. NTSTATUS status;
  94. PDEVICE_OBJECT self;
  95. ULONG statusBits[] = {
  96. SERIAL_DSR_STATE,
  97. SERIAL_CTS_STATE,
  98. 0x0
  99. };
  100. ULONG eventBits[] = {
  101. SERIAL_EV_DSR,
  102. SERIAL_EV_CTS,
  103. };
  104. int i;
  105. PAGED_CODE();
  106. //
  107. // Check to see if removal detection was turned off in the registry
  108. //
  109. if (DeviceExtension->WaitEventMask == 0xffffffff) {
  110. DeviceExtension->DetectionSupported = FALSE;
  111. return;
  112. }
  113. KeInitializeEvent(&event, NotificationEvent, FALSE);
  114. if (!DeviceExtension->WaitEventMask) {
  115. status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_MODEMSTATUS,
  116. DeviceExtension->TopOfStack,
  117. &event,
  118. &iosb,
  119. NULL,
  120. 0,
  121. &bits,
  122. sizeof(ULONG)
  123. );
  124. Print(DeviceExtension, DBG_SS_NOISE,
  125. ("get modem status, NTSTATUS = 0x%x, bits = 0x%x\n",
  126. status, bits));
  127. if (!NT_SUCCESS(status) || !bits) {
  128. Print(DeviceExtension, DBG_SS_ERROR,
  129. ("modem status failed, status = 0x%x, bits are 0x%x\n",
  130. status, bits));
  131. DeviceExtension->ModemStatusBits = 0x0;
  132. DeviceExtension->DetectionSupported = FALSE;
  133. return;
  134. }
  135. DeviceExtension->ModemStatusBits = bits;
  136. for (i = 0, waitMask = 0x0; statusBits[i] != 0x0; i++) {
  137. if (bits & statusBits[i]) {
  138. waitMask |= eventBits[i];
  139. }
  140. }
  141. Print(DeviceExtension, DBG_SS_NOISE,
  142. ("event wait bits are 0x%x\n", waitMask));
  143. }
  144. else {
  145. waitMask = DeviceExtension->WaitEventMask;
  146. }
  147. status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_WAIT_MASK,
  148. DeviceExtension->TopOfStack,
  149. &event,
  150. &iosb,
  151. &waitMask,
  152. sizeof(ULONG),
  153. NULL,
  154. 0);
  155. if (!NT_SUCCESS(status)) {
  156. Print(DeviceExtension, DBG_SS_ERROR,
  157. ("set mask failed, status = 0x%x\n", status));
  158. DeviceExtension->DetectionSupported = FALSE;
  159. return;
  160. }
  161. self = DeviceExtension->Self;
  162. if (!DeviceExtension->DetectionIrp) {
  163. if (!(DeviceExtension->DetectionIrp =
  164. IoAllocateIrp(self->StackSize, FALSE))) {
  165. DeviceExtension->DetectionSupported = FALSE;
  166. return;
  167. }
  168. }
  169. status = SerialMouseSendWaitMaskIrp(DeviceExtension);
  170. Print(DeviceExtension, DBG_SS_NOISE, ("set wait event status = 0x%x\n", status));
  171. if (NT_SUCCESS(status)) {
  172. DeviceExtension->DetectionSupported = TRUE;
  173. }
  174. else {
  175. IoCancelIrp(DeviceExtension->DetectionIrp);
  176. DeviceExtension->DetectionSupported = FALSE;
  177. }
  178. }
  179. VOID
  180. SerialMouseStopDetection(
  181. PDEVICE_EXTENSION DeviceExtension
  182. )
  183. {
  184. PAGED_CODE();
  185. if (!DeviceExtension->DetectionSupported) {
  186. return;
  187. }
  188. if (!DeviceExtension->RemovalDetected) {
  189. IoCancelIrp(DeviceExtension->DetectionIrp);
  190. }
  191. }
  192. NTSTATUS
  193. SerialMouseSerialMaskEventComplete (
  194. IN PDEVICE_OBJECT DeviceObject,
  195. IN PIRP Irp,
  196. IN PVOID Context
  197. )
  198. {
  199. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) Context;
  200. PIO_WORKITEM item;
  201. NTSTATUS status;
  202. BOOLEAN killMouse = FALSE;
  203. //
  204. // DeviceObject is NULL b/c this driver was the one that allocated and sent
  205. // the irp, we must use deviceExtension->Self instead.
  206. //
  207. UNREFERENCED_PARAMETER(DeviceObject);
  208. if (!deviceExtension->Removed && !deviceExtension->SurpriseRemoved) {
  209. item = IoAllocateWorkItem(deviceExtension->Self);
  210. if (!item) {
  211. //
  212. // Well, we can't allocate the work item, so lets invalidate our device
  213. // state and hope everything gets torn down.
  214. //
  215. killMouse = TRUE;
  216. }
  217. else {
  218. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, item);
  219. if (NT_SUCCESS(status)) {
  220. IoQueueWorkItem (item,
  221. SerialMouseSerialMaskEventWorker,
  222. DelayedWorkQueue,
  223. item);
  224. }
  225. else {
  226. killMouse = TRUE;
  227. }
  228. }
  229. }
  230. if (killMouse) {
  231. deviceExtension->RemovalDetected = TRUE;
  232. IoInvalidateDeviceState(deviceExtension->PDO);
  233. }
  234. IoReleaseRemoveLock (&deviceExtension->RemoveLock,
  235. deviceExtension->DetectionIrp);
  236. return STATUS_MORE_PROCESSING_REQUIRED;
  237. }
  238. VOID
  239. SerialMouseSerialMaskEventWorker(
  240. PDEVICE_OBJECT DeviceObject,
  241. PIO_WORKITEM Item
  242. )
  243. {
  244. IO_STATUS_BLOCK iosb;
  245. PIRP irp;
  246. KEVENT event;
  247. NTSTATUS status;
  248. ULONG bits;
  249. BOOLEAN removeSelf = FALSE;
  250. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  251. PAGED_CODE();
  252. irp = deviceExtension->DetectionIrp;
  253. KeInitializeEvent(&event, NotificationEvent, FALSE);
  254. switch (irp->IoStatus.Status) {
  255. case STATUS_SUCCESS:
  256. Print(deviceExtension, DBG_SS_NOISE,
  257. ("SerialEventBits are 0x%x\n", deviceExtension->SerialEventBits));
  258. bits = 0x0;
  259. status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_MODEMSTATUS,
  260. deviceExtension->TopOfStack,
  261. &event,
  262. &iosb,
  263. NULL,
  264. 0,
  265. &bits,
  266. sizeof(ULONG)
  267. );
  268. Print(deviceExtension, DBG_SS_NOISE,
  269. ("get modem status, NTSTATUS = 0x%x, bits = 0x%x, MSB = 0x%x\n",
  270. status, bits, deviceExtension->ModemStatusBits));
  271. //
  272. // Make sure that the lines truly changed
  273. //
  274. if (deviceExtension->ModemStatusBits == bits) {
  275. //
  276. // Resend the detection irp
  277. //
  278. SerialMouseSendWaitMaskIrp(deviceExtension);
  279. }
  280. else {
  281. //
  282. // The lines have changed, it is a hot removal
  283. //
  284. Print(deviceExtension, DBG_SS_NOISE, ("device hot removed!\n"));
  285. SerialMouseIoSyncInternalIoctl(IOCTL_INTERNAL_SERENUM_REMOVE_SELF,
  286. deviceExtension->TopOfStack,
  287. &event,
  288. &iosb);
  289. deviceExtension->RemovalDetected = TRUE;
  290. }
  291. break;
  292. case STATUS_CANCELLED:
  293. //
  294. // We get here if the user manually removes the device (ie through the
  295. // device manager) and we send the clean up irp down the stack
  296. //
  297. Print(deviceExtension, DBG_SS_NOISE, ("wait cancelled!\n"));
  298. if (deviceExtension->PowerState != PowerDeviceD0 &&
  299. !deviceExtension->PoweringDown) {
  300. deviceExtension->RemovalDetected = TRUE;
  301. }
  302. break;
  303. default:
  304. Print(deviceExtension, DBG_SS_ERROR,
  305. ("unknown status in mask event (0x%x)\n",
  306. irp->IoStatus.Status));
  307. TRAP();
  308. }
  309. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Item);
  310. IoFreeWorkItem(Item);
  311. }