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.

577 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract: Human Input Device (HID) minidriver for Universal Serial Bus (USB) devices
  6. The HID USB Minidriver (HUM, Hum) provides an abstraction layer for the
  7. HID Class so that future HID devices whic are not USB devices can be supported.
  8. Author:
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, HumPnP)
  16. #pragma alloc_text(PAGE, HumStartDevice)
  17. #pragma alloc_text(PAGE, HumStopDevice)
  18. #pragma alloc_text(PAGE, HumRemoveDevice)
  19. #pragma alloc_text(PAGE, HumAbortPendingRequests)
  20. #endif
  21. /*
  22. ************************************************************
  23. * HumPnP
  24. ************************************************************
  25. *
  26. * Process PnP IRPs sent to this device.
  27. *
  28. */
  29. NTSTATUS HumPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  30. {
  31. NTSTATUS ntStatus = STATUS_SUCCESS;
  32. PIO_STACK_LOCATION irpSp;
  33. PDEVICE_EXTENSION DeviceExtension;
  34. KEVENT event;
  35. PAGED_CODE();
  36. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  37. irpSp = IoGetCurrentIrpStackLocation (Irp);
  38. switch(irpSp->MinorFunction){
  39. case IRP_MN_START_DEVICE:
  40. ntStatus = HumStartDevice(DeviceObject);
  41. break;
  42. case IRP_MN_STOP_DEVICE:
  43. if (DeviceExtension->DeviceState == DEVICE_STATE_RUNNING) {
  44. ntStatus = HumStopDevice(DeviceObject);
  45. } else {
  46. ntStatus = STATUS_SUCCESS;
  47. }
  48. break;
  49. case IRP_MN_REMOVE_DEVICE:
  50. return HumRemoveDevice(DeviceObject, Irp);
  51. break;
  52. }
  53. if (NT_SUCCESS(ntStatus)){
  54. /*
  55. * Our processing has succeeded.
  56. * So pass this IRP down to the next driver.
  57. */
  58. KeInitializeEvent(&event, NotificationEvent, FALSE);
  59. IoCopyCurrentIrpStackLocationToNext(Irp);
  60. IoSetCompletionRoutine(Irp,
  61. HumPnpCompletion,
  62. &event, // context
  63. TRUE,
  64. TRUE,
  65. TRUE );
  66. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  67. if (ntStatus == STATUS_PENDING) {
  68. // wait for it...
  69. KeWaitForSingleObject(&event,
  70. Executive,
  71. KernelMode,
  72. FALSE,
  73. NULL);
  74. }
  75. ntStatus = Irp->IoStatus.Status;
  76. switch(irpSp->MinorFunction) {
  77. case IRP_MN_START_DEVICE:
  78. if (NT_SUCCESS(ntStatus)) {
  79. DeviceExtension->DeviceState = DEVICE_STATE_RUNNING;
  80. ntStatus = HumInitDevice(DeviceObject);
  81. if (!NT_SUCCESS(ntStatus)) {
  82. DBGWARN(("HumInitDevice failed; failing IRP_MN_START_DEVICE."));
  83. DeviceExtension->DeviceState = DEVICE_STATE_START_FAILED;
  84. Irp->IoStatus.Status = ntStatus;
  85. }
  86. }
  87. else {
  88. DBGWARN(("Pdo failed start irp with status %x", ntStatus));
  89. DeviceExtension->DeviceState = DEVICE_STATE_START_FAILED;
  90. }
  91. break;
  92. case IRP_MN_STOP_DEVICE:
  93. DeviceExtension->DeviceState = DEVICE_STATE_STOPPED;
  94. /*
  95. * Release resources
  96. */
  97. if (DeviceExtension->Interface) {
  98. ExFreePool(DeviceExtension->Interface);
  99. DeviceExtension->Interface = NULL;
  100. }
  101. if (DeviceExtension->DeviceDescriptor) {
  102. ExFreePool(DeviceExtension->DeviceDescriptor);
  103. DeviceExtension->DeviceDescriptor = NULL;
  104. }
  105. break;
  106. case IRP_MN_QUERY_CAPABILITIES:
  107. /*
  108. * The lower driver set the capabilities flags for this device.
  109. * Since all USB devices are hot-unpluggable,
  110. * add the SurpriseRemovalOK bit.
  111. */
  112. if (NT_SUCCESS(ntStatus)){
  113. irpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
  114. }
  115. break;
  116. }
  117. } else {
  118. DBGWARN(("A PnP irp is going to be failed. Status = %x.", ntStatus));
  119. }
  120. Irp->IoStatus.Status = ntStatus;
  121. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  122. return ntStatus;
  123. }
  124. NTSTATUS HumPowerCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  125. {
  126. NTSTATUS status;
  127. ASSERT(DeviceObject);
  128. status = Irp->IoStatus.Status;
  129. if (Irp->PendingReturned) {
  130. IoMarkIrpPending(Irp);
  131. }
  132. if (NT_SUCCESS(status)){
  133. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  134. switch (irpSp->MinorFunction){
  135. case IRP_MN_SET_POWER:
  136. switch (irpSp->Parameters.Power.Type){
  137. case DevicePowerState:
  138. switch (irpSp->Parameters.Power.State.DeviceState) {
  139. case PowerDeviceD0:
  140. /*
  141. * We just resumed from SUSPEND.
  142. * Send down a SET_IDLE to prevent keyboards
  143. * from chattering after the resume.
  144. */
  145. status = HumSetIdle(DeviceObject);
  146. /* if (!NT_SUCCESS(status)){
  147. DBGWARN(("HumPowerCompletion: SET_IDLE failed with %xh (only matters for keyboard).", status));
  148. }*/
  149. break;
  150. }
  151. break;
  152. }
  153. break;
  154. }
  155. }
  156. return STATUS_SUCCESS;
  157. }
  158. /*
  159. ************************************************************
  160. * HumPower
  161. ************************************************************
  162. *
  163. * Process Power IRPs sent to this device.
  164. *
  165. */
  166. NTSTATUS HumPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  167. {
  168. NTSTATUS status;
  169. IoCopyCurrentIrpStackLocationToNext(Irp);
  170. IoSetCompletionRoutine(Irp, HumPowerCompletion, NULL, TRUE, TRUE, TRUE);
  171. status = PoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  172. return status;
  173. }
  174. /*
  175. ************************************************************
  176. * HumStartDevice
  177. ************************************************************
  178. *
  179. * Initializes a given instance of the UTB device on the USB.
  180. *
  181. */
  182. NTSTATUS HumStartDevice(IN PDEVICE_OBJECT DeviceObject)
  183. {
  184. PDEVICE_EXTENSION DeviceExtension;
  185. ULONG oldDeviceState;
  186. PAGED_CODE();
  187. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  188. oldDeviceState = DeviceExtension->DeviceState;
  189. DeviceExtension->DeviceState = DEVICE_STATE_STARTING;
  190. /*
  191. * We may have been previously stopped, in which case the AllRequestsCompleteEvent
  192. * is still in the signalled state. It's very important that we reset it to
  193. * the non-signalled state so that we wait on it properly on the next stop/remove.
  194. */
  195. KeResetEvent(&DeviceExtension->AllRequestsCompleteEvent);
  196. ASSERT(oldDeviceState != DEVICE_STATE_REMOVING);
  197. if ((oldDeviceState == DEVICE_STATE_STOPPING) ||
  198. (oldDeviceState == DEVICE_STATE_STOPPED) ||
  199. (oldDeviceState == DEVICE_STATE_REMOVING)){
  200. /*
  201. * We did an extra decrement when the device was stopped.
  202. * Now that we're restarting, we need to bump it back to zero.
  203. */
  204. NTSTATUS incStat = HumIncrementPendingRequestCount(DeviceExtension);
  205. ASSERT(NT_SUCCESS(incStat));
  206. ASSERT(DeviceExtension->NumPendingRequests == 0);
  207. DBGWARN(("Got start-after-stop; re-incremented pendingRequestCount"));
  208. }
  209. DeviceExtension->Interface = NULL;
  210. return STATUS_SUCCESS;
  211. }
  212. /*
  213. ************************************************************
  214. * HumInitDevice
  215. ************************************************************
  216. *
  217. * Get the device information and attempt to initialize a configuration
  218. * for a device. If we cannot identify this as a valid HID device or
  219. * configure the device, our start device function is failed.
  220. *
  221. * Note: This function is called from the PnP completion routine,
  222. * so it cannot be pageable.
  223. */
  224. NTSTATUS HumInitDevice(IN PDEVICE_OBJECT DeviceObject)
  225. {
  226. NTSTATUS ntStatus;
  227. PDEVICE_EXTENSION DeviceExtension;
  228. PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc = NULL;
  229. ULONG DescriptorLength;
  230. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  231. /*
  232. * Get the Device descriptor and store it in the device extension
  233. */
  234. ntStatus = HumGetDeviceDescriptor(DeviceObject, DeviceExtension);
  235. if (NT_SUCCESS(ntStatus)){
  236. /*
  237. * Get config descriptor
  238. */
  239. ntStatus = HumGetConfigDescriptor(DeviceObject, &ConfigDesc, &DescriptorLength);
  240. if (NT_SUCCESS(ntStatus)) {
  241. ASSERT(ConfigDesc);
  242. #if DBG
  243. // NOTE: This debug function is currently confused
  244. // by power descriptors. Restore when fixed.
  245. // DumpConfigDescriptor(ConfigDesc, DescriptorLength);
  246. #endif
  247. ntStatus = HumGetHidInfo(DeviceObject, ConfigDesc, DescriptorLength);
  248. if (NT_SUCCESS(ntStatus)) {
  249. ntStatus = HumSelectConfiguration(DeviceObject, ConfigDesc);
  250. if (NT_SUCCESS(ntStatus)) {
  251. HumSetIdle(DeviceObject);
  252. }
  253. }
  254. ExFreePool(ConfigDesc);
  255. }
  256. }
  257. return ntStatus;
  258. }
  259. /*
  260. ************************************************************
  261. * HumStopDevice
  262. ************************************************************
  263. *
  264. * Stops a given instance of a device on the USB.
  265. *
  266. */
  267. NTSTATUS HumStopDevice(IN PDEVICE_OBJECT DeviceObject)
  268. {
  269. PURB Urb;
  270. ULONG Size;
  271. NTSTATUS ntStatus = STATUS_SUCCESS;
  272. PDEVICE_EXTENSION DeviceExtension;
  273. PAGED_CODE();
  274. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  275. DeviceExtension->DeviceState = DEVICE_STATE_STOPPING;
  276. /*
  277. * Abort all pending IO on the device.
  278. * We do an extra decrement here, which causes the
  279. * NumPendingRequests to eventually go to -1, which causes
  280. * AllRequestsCompleteEvent to get set.
  281. * NumPendingRequests will get reset to 0 when we re-start.
  282. */
  283. HumAbortPendingRequests(DeviceObject);
  284. HumDecrementPendingRequestCount(DeviceExtension);
  285. KeWaitForSingleObject( &DeviceExtension->AllRequestsCompleteEvent,
  286. Executive,
  287. KernelMode,
  288. FALSE,
  289. NULL );
  290. /*
  291. * Submit an open configuration Urb to the USB stack
  292. * (with a NULL pointer for the configuration handle).
  293. */
  294. Size = sizeof(struct _URB_SELECT_CONFIGURATION);
  295. Urb = ExAllocatePoolWithTag(NonPagedPool, Size, HIDUSB_TAG);
  296. if (Urb){
  297. UsbBuildSelectConfigurationRequest(Urb, (USHORT) Size, NULL);
  298. ntStatus = HumCallUSB(DeviceObject, Urb);
  299. ASSERT(NT_SUCCESS(ntStatus));
  300. ExFreePool(Urb);
  301. }
  302. else {
  303. ntStatus = STATUS_UNSUCCESSFUL;
  304. }
  305. if (!NT_SUCCESS(ntStatus)){
  306. /*
  307. * We will not pass this IRP down,
  308. * so our completion routine will not set the device's
  309. * state to DEVICE_STATE_STOPPED; so set it here.
  310. */
  311. ASSERT(NT_SUCCESS(ntStatus));
  312. DeviceExtension->DeviceState = DEVICE_STATE_STOPPED;
  313. }
  314. return ntStatus;
  315. }
  316. /*
  317. ************************************************************
  318. * HumAbortPendingRequests
  319. ************************************************************
  320. *
  321. *
  322. */
  323. NTSTATUS HumAbortPendingRequests(IN PDEVICE_OBJECT DeviceObject)
  324. {
  325. PDEVICE_EXTENSION deviceExtension;
  326. PURB urb;
  327. PVOID pipeHandle;
  328. ULONG urbSize;
  329. NTSTATUS status;
  330. PAGED_CODE();
  331. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION( DeviceObject );
  332. /*
  333. * Create and send down an abort pipe request.
  334. */
  335. urbSize = sizeof(struct _URB_PIPE_REQUEST);
  336. urb = ExAllocatePoolWithTag(NonPagedPool, urbSize, HIDUSB_TAG);
  337. if (urb){
  338. if (deviceExtension->Interface &&
  339. (deviceExtension->Interface->NumberOfPipes != 0)){
  340. pipeHandle = deviceExtension->Interface->Pipes[0].PipeHandle;
  341. if (pipeHandle) {
  342. urb->UrbHeader.Length = (USHORT)urbSize;
  343. urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
  344. urb->UrbPipeRequest.PipeHandle = pipeHandle;
  345. status = HumCallUSB(DeviceObject, urb);
  346. if (!NT_SUCCESS(status)){
  347. DBGWARN(("URB_FUNCTION_ABORT_PIPE returned %xh in HumAbortPendingRequests", status));
  348. }
  349. }
  350. else {
  351. ASSERT(pipeHandle);
  352. status = STATUS_NO_SUCH_DEVICE;
  353. }
  354. }
  355. else {
  356. DBGERR(("No such device in HumAbortPendingRequests"));
  357. status = STATUS_NO_SUCH_DEVICE;
  358. }
  359. ExFreePool(urb);
  360. }
  361. else {
  362. ASSERT(urb);
  363. status = STATUS_INSUFFICIENT_RESOURCES;
  364. }
  365. return status;
  366. }
  367. /*
  368. ************************************************************
  369. * HumPnpCompletion
  370. ************************************************************
  371. *
  372. */
  373. NTSTATUS HumPnpCompletion( IN PDEVICE_OBJECT DeviceObject,
  374. IN PIRP Irp,
  375. IN PVOID Context)
  376. {
  377. UNREFERENCED_PARAMETER (DeviceObject);
  378. if (Irp->PendingReturned) {
  379. IoMarkIrpPending( Irp );
  380. }
  381. KeSetEvent ((PKEVENT) Context, 1, FALSE);
  382. // No special priority
  383. // No Wait
  384. return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
  385. }
  386. /*
  387. ************************************************************
  388. * HumRemoveDevice
  389. ************************************************************
  390. *
  391. * Removes a given instance of a device on the USB.
  392. *
  393. */
  394. NTSTATUS HumRemoveDevice(IN PDEVICE_OBJECT DeviceObject, PIRP Irp)
  395. {
  396. NTSTATUS ntStatus = STATUS_SUCCESS;
  397. PDEVICE_EXTENSION DeviceExtension;
  398. ULONG oldDeviceState;
  399. PAGED_CODE();
  400. //
  401. // Get a pointer to the device extension
  402. //
  403. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  404. //
  405. // Set device state, this prevents new IOs from starting
  406. //
  407. oldDeviceState = DeviceExtension->DeviceState;
  408. DeviceExtension->DeviceState = DEVICE_STATE_REMOVING;
  409. /*
  410. * Note: RemoveDevice does an extra decrement, so we complete
  411. * the REMOVE IRP on the transition to -1, whether this
  412. * happens in RemoveDevice itself or subsequently while
  413. * RemoveDevice is waiting for this event to fire.
  414. */
  415. if ((oldDeviceState == DEVICE_STATE_STOPPING) ||
  416. (oldDeviceState == DEVICE_STATE_STOPPED)){
  417. /*
  418. * HumStopDevice did the extra decrement and aborted the
  419. * pending requests.
  420. */
  421. }
  422. else {
  423. HumDecrementPendingRequestCount(DeviceExtension);
  424. }
  425. //
  426. // Cancel any outstanding IRPs if the device was running
  427. //
  428. if (oldDeviceState == DEVICE_STATE_RUNNING){
  429. HumAbortPendingRequests(DeviceObject);
  430. }
  431. else if (oldDeviceState == DEVICE_STATE_STOPPING){
  432. ASSERT(!(PVOID)"PnP IRPs are not synchronized! -- got REMOVE_DEVICE before STOP_DEVICE completed!");
  433. }
  434. KeWaitForSingleObject( &DeviceExtension->AllRequestsCompleteEvent,
  435. Executive,
  436. KernelMode,
  437. FALSE,
  438. NULL );
  439. ASSERT(DeviceExtension->NumPendingRequests == -1);
  440. //
  441. // Fire and forget
  442. //
  443. Irp->IoStatus.Status = STATUS_SUCCESS;
  444. IoSkipCurrentIrpStackLocation(Irp);
  445. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  446. //
  447. // Release any resources
  448. //
  449. if (DeviceExtension->Interface) {
  450. ExFreePool(DeviceExtension->Interface);
  451. DeviceExtension->Interface = NULL;
  452. }
  453. if (DeviceExtension->DeviceDescriptor) {
  454. ExFreePool(DeviceExtension->DeviceDescriptor);
  455. DeviceExtension->DeviceDescriptor = NULL;
  456. }
  457. return ntStatus;
  458. }