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.

628 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996,1997 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract: Human Input Device (HID) minidriver that creates an example
  6. device.
  7. --*/
  8. #include <WDM.H>
  9. #include <USBDI.H>
  10. #include <HIDPORT.H>
  11. #include <HIDMINI.H>
  12. NTSTATUS
  13. HidMiniPnP(
  14. IN PDEVICE_OBJECT DeviceObject,
  15. IN PIRP Irp
  16. )
  17. /*++
  18. Routine Description:
  19. Process the PnP IRPs sent to this device.
  20. Arguments:
  21. DeviceObject - pointer to a device object.
  22. Irp - pointer to an I/O Request Packet.
  23. Return Value:
  24. NT status code.
  25. --*/
  26. {
  27. NTSTATUS ntStatus;
  28. PIO_STACK_LOCATION IrpStack;
  29. PIO_STACK_LOCATION NextStack;
  30. PDEVICE_EXTENSION DeviceExtension;
  31. DBGPrint(("'HIDMINI.SYS: HidMiniPlugnPlay Enter\n"));
  32. DBGPrint(("'HIDMINI.SYS: DeviceObject = %x\n", DeviceObject));
  33. //
  34. // Get a pointer to the device extension
  35. //
  36. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  37. DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
  38. //
  39. // Get a pointer to the current location in the Irp
  40. //
  41. IrpStack = IoGetCurrentIrpStackLocation (Irp);
  42. DBGPrint(("'HIDMINI.SYS: IoGetCurrentIrpStackLocation (Irp) = %x\n", IrpStack));
  43. switch(IrpStack->MinorFunction)
  44. {
  45. case IRP_MN_START_DEVICE:
  46. DBGPrint(("'HIDMINI.SYS: IRP_MN_START_DEVICE\n"));
  47. ntStatus = HidMiniStartDevice(DeviceObject);
  48. break;
  49. case IRP_MN_STOP_DEVICE:
  50. DBGPrint(("'HIDMINI.SYS: IRP_MN_STOP_DEVICE\n"));
  51. ntStatus = HidMiniStopDevice(DeviceObject);
  52. break;
  53. case IRP_MN_REMOVE_DEVICE:
  54. DBGPrint(("'HIDMINI.SYS: IRP_MN_REMOVE_DEVICE\n"));
  55. ntStatus = HidMiniRemoveDevice(DeviceObject);
  56. break;
  57. case IRP_MN_QUERY_ID:
  58. DBGPrint(("'HIDMINI.SYS: IRP_MN_QUERY_ID\n"));
  59. (PWCHAR)Irp->IoStatus.Information = NULL;
  60. ntStatus = STATUS_SUCCESS;
  61. break;
  62. default:
  63. ntStatus = STATUS_SUCCESS;
  64. DBGPrint(("'HIDMINI.SYS: Unknown PNP IRP Parameter (%lx)\n", IrpStack->MinorFunction));
  65. }
  66. //
  67. // Set the status of the Irp
  68. //
  69. Irp->IoStatus.Status = ntStatus;
  70. if (NT_SUCCESS(ntStatus)) {
  71. //
  72. // Set next stack location
  73. //
  74. NextStack = IoGetNextIrpStackLocation(Irp);
  75. ASSERT(NextStack != NULL);
  76. //
  77. // Copy the Irp to the next stack location
  78. //
  79. RtlCopyMemory(NextStack, IrpStack, sizeof(IO_STACK_LOCATION));
  80. IoMarkIrpPending(Irp);
  81. //
  82. // Set our own completion routine or disable completion
  83. // routine of caller
  84. //
  85. switch(IrpStack->MinorFunction)
  86. {
  87. case IRP_MN_START_DEVICE:
  88. IoSetCompletionRoutine( Irp,
  89. HidMiniStartCompletion,
  90. DeviceExtension, // reference data
  91. TRUE, // call on success
  92. TRUE, // call on failure
  93. TRUE ); // call on cancel
  94. break;
  95. case IRP_MN_STOP_DEVICE:
  96. IoSetCompletionRoutine( Irp,
  97. HidMiniStopCompletion,
  98. DeviceExtension, // reference data
  99. TRUE, // call on success
  100. TRUE, // call on failure
  101. TRUE ); // call on cancel
  102. break;
  103. case IRP_MN_QUERY_ID:
  104. IoSetCompletionRoutine( Irp,
  105. HidMiniQueryIDCompletion,
  106. DeviceExtension, // reference data
  107. TRUE, // call on success
  108. TRUE, // call on failure
  109. TRUE ); // call on cancel
  110. break;
  111. default:
  112. NextStack->Control = 0;
  113. break;
  114. }
  115. //
  116. // Pass it down to the Next Device Object
  117. //
  118. DBGPrint(("'HIDMINI.SYS: Passing PnP Irp down to next object\n"));
  119. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  120. } else {
  121. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  122. //
  123. // NOTE: Real status returned in Irp->IoStatus.Status
  124. //
  125. ntStatus = STATUS_SUCCESS;
  126. }
  127. DBGPrint(("'HIDMINI.SYS: HidMiniPlugnPlay Exit = %x\n", ntStatus));
  128. return ntStatus;
  129. }
  130. NTSTATUS
  131. HidMiniStartDevice(
  132. IN PDEVICE_OBJECT DeviceObject
  133. )
  134. /*++
  135. Routine Description:
  136. Begins initialization a given instance of a HID device. Work done here occurs before
  137. the parent node gets to do anything.
  138. Arguments:
  139. DeviceObject - pointer to the device object for this instance.
  140. Return Value:
  141. NT status code
  142. --*/
  143. {
  144. PDEVICE_EXTENSION DeviceExtension;
  145. NTSTATUS ntStatus;
  146. PUSB_DEVICE_DESCRIPTOR DeviceDesc = NULL;
  147. DBGPrint(("'HIDMINI.SYS: HidMiniStartDevice Enter\n"));
  148. //
  149. // Get a pointer to the device extension
  150. //
  151. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  152. DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
  153. //
  154. // Start the device
  155. //
  156. DeviceExtension->DeviceState = DEVICE_STATE_STARTING;
  157. ntStatus = STATUS_SUCCESS;
  158. DBGPrint(("'HIDMINI.SYS: HidMiniStartDevice Exit = %x\n", ntStatus));
  159. return ntStatus;
  160. }
  161. NTSTATUS
  162. HidMiniStartCompletion(
  163. IN PDEVICE_OBJECT DeviceObject,
  164. IN PIRP Irp,
  165. IN PVOID Context
  166. )
  167. /*++
  168. Routine Description:
  169. Completes initialization a given instance of a HID device. Work done here occurs
  170. after the parent node has done its StartDevice.
  171. Arguments:
  172. DeviceObject - pointer to the device object for this instance.
  173. Return Value:
  174. NT status code
  175. --*/
  176. {
  177. PDEVICE_EXTENSION DeviceExtension;
  178. NTSTATUS ntStatus;
  179. PUSB_DEVICE_DESCRIPTOR DeviceDesc = NULL;
  180. DBGPrint(("'HIDMINI.SYS: HidMiniStartCompletion Enter\n"));
  181. //
  182. // Get a pointer to the device extension
  183. //
  184. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  185. DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
  186. ntStatus = Irp->IoStatus.Status;
  187. if(NT_SUCCESS(ntStatus)) {
  188. DeviceExtension->DeviceState = DEVICE_STATE_RUNNING;
  189. IsRunning = TRUE;
  190. DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) was started!\n", DeviceObject));
  191. ntStatus = HidMiniInitDevice(DeviceObject);
  192. if(NT_SUCCESS(ntStatus)) {
  193. DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) was configured!\n", DeviceObject));
  194. } else {
  195. DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) configuration failed!\n", DeviceObject));
  196. DeviceExtension->DeviceState = DEVICE_STATE_STOPPING;
  197. IsRunning = FALSE;
  198. }
  199. } else {
  200. //
  201. // The PnP call failed!
  202. //
  203. DeviceExtension->DeviceState = DEVICE_STATE_STOPPING;
  204. IsRunning = FALSE;
  205. DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) failed to start!\n", DeviceObject));
  206. }
  207. DBGPrint(("'HIDMINI.SYS: HidMiniStartCompletion Exit = %x\n", ntStatus));
  208. return ntStatus;
  209. }
  210. NTSTATUS
  211. HidMiniInitDevice(
  212. IN PDEVICE_OBJECT DeviceObject
  213. )
  214. /*++
  215. Routine Description:
  216. Get the device information and attempt to initialize a configuration
  217. for a device. If we cannot identify this as a valid HID device or
  218. configure the device, our start device function is failed.
  219. Arguments:
  220. DeviceObject - pointer to a device object.
  221. Return Value:
  222. NT status code.
  223. --*/
  224. {
  225. NTSTATUS ntStatus = STATUS_SUCCESS;
  226. PDEVICE_EXTENSION DeviceExtension;
  227. DBGPrint(("'HIDMINI.SYS: HidMiniInitDevice Entry\n"));
  228. //
  229. // Get a pointer to the device extension
  230. //
  231. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  232. //
  233. // Get config, hid, etc. descriptors
  234. //
  235. DeviceExtension->HidDescriptor = MyHidDescriptor;
  236. DeviceExtension->StringDescriptor = MyStringDescriptor;
  237. DeviceExtension->PhysicalDescriptor = MyPhysicalDescriptor;
  238. DeviceExtension->ReportDescriptor = MyReportDescriptor;
  239. InitializeListHead(&HidMini_ReadIrpHead);
  240. InitializeListHead(&HidMini_WriteIrpHead);
  241. DBGPrint(("'HIDMINI.SYS: HidMiniInitDevice Exit = 0x%x\n", ntStatus));
  242. return ntStatus;
  243. }
  244. NTSTATUS
  245. HidMiniStopDevice(
  246. IN PDEVICE_OBJECT DeviceObject
  247. )
  248. /*++
  249. Routine Description:
  250. Stops a given instance of a device. Work done here occurs before the parent
  251. does its stop device.
  252. Arguments:
  253. DeviceObject - pointer to the device object.
  254. Return Value:
  255. NT status code
  256. --*/
  257. {
  258. NTSTATUS ntStatus = STATUS_SUCCESS;
  259. PDEVICE_EXTENSION DeviceExtension;
  260. DBGPrint(("'HIDMINI.SYS: HidMiniStopDevice Enter\n"));
  261. //
  262. // Get a pointer to the device extension
  263. //
  264. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  265. DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
  266. DeviceExtension->DeviceState = DEVICE_STATE_STOPPING;
  267. IsRunning = FALSE;
  268. //
  269. // Stop the device
  270. //
  271. //
  272. // Perform a synchronous abort of all pending requests for this
  273. // device.
  274. //
  275. HidMiniAbortPendingRequests( DeviceObject );
  276. DBGPrint(("'HIDMINI.SYS: HidMiniStopDevice = %x\n", ntStatus));
  277. return ntStatus;
  278. }
  279. NTSTATUS
  280. HidMiniAbortPendingRequests(
  281. IN PDEVICE_OBJECT DeviceObject
  282. )
  283. {
  284. PNODE Node;
  285. //
  286. // Dispose of any Irps, free up all the NODEs waiting in the queues.
  287. //
  288. while ((Node = (PNODE)ExInterlockedRemoveHeadList(&HidMini_ReadIrpHead, &HidMini_IrpReadLock))) {
  289. Node->Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  290. IoCompleteRequest(Node->Irp, IO_NO_INCREMENT);
  291. ExFreePool(Node);
  292. }
  293. return STATUS_SUCCESS;
  294. }
  295. NTSTATUS
  296. HidMiniStopCompletion(
  297. IN PDEVICE_OBJECT DeviceObject,
  298. IN PIRP Irp,
  299. IN PVOID Context
  300. )
  301. /*++
  302. Routine Description:
  303. Stops a given instance of a device. Work done here occurs after the parent
  304. has done its stop device.
  305. Arguments:
  306. DeviceObject - pointer to the device object.
  307. Return Value:
  308. NT status code
  309. --*/
  310. {
  311. PDEVICE_EXTENSION DeviceExtension;
  312. NTSTATUS ntStatus;
  313. PUSB_DEVICE_DESCRIPTOR DeviceDesc = NULL;
  314. DBGPrint(("'HIDMINI.SYS: HidMiniStopCompletion Enter\n"));
  315. //
  316. // Get a pointer to the device extension
  317. //
  318. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  319. DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
  320. ntStatus = Irp->IoStatus.Status;
  321. if(!NT_SUCCESS(ntStatus)) {
  322. DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) was stopped!\n", DeviceObject));
  323. } else {
  324. //
  325. // The PnP call failed!
  326. //
  327. DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) failed to stop!\n", DeviceObject));
  328. }
  329. DeviceExtension->DeviceState = DEVICE_STATE_STOPPED;
  330. IsRunning = FALSE;
  331. DBGPrint(("'HIDMINI.SYS: HidMiniStopCompletion Exit = %x\n", ntStatus));
  332. return ntStatus;
  333. }
  334. NTSTATUS
  335. HidMiniQueryIDCompletion(
  336. IN PDEVICE_OBJECT DeviceObject,
  337. IN PIRP Irp,
  338. IN PVOID Context
  339. )
  340. /*++
  341. Routine Description:
  342. Fills in a dummy ID
  343. Arguments:
  344. DeviceObject - pointer to the device object.
  345. Return Value:
  346. NT status code
  347. --*/
  348. {
  349. NTSTATUS ntStatus;
  350. DBGPrint(("'HIDMINI.SYS: HidMiniQueryIDCompletion Enter\n"));
  351. //
  352. // If this wasn't filled in below us, fill it in with a dummy value
  353. //
  354. if ((PWCHAR)Irp->IoStatus.Information == NULL) {
  355. //
  356. // Here's the dummy value, allocate a buffer to copy it to.
  357. //
  358. static WCHAR MyBusID[] = L"HIDMINI_Device\0";
  359. PWCHAR Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, sizeof(MyBusID));
  360. if (Buffer) {
  361. //
  362. // Do the copy, store the buffer in the Irp
  363. //
  364. RtlCopyMemory(Buffer, MyBusID, sizeof(MyBusID));
  365. Irp->IoStatus.Information = (ULONG)Buffer;
  366. ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
  367. } else {
  368. //
  369. // No memory
  370. //
  371. ntStatus = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  372. }
  373. } else {
  374. //
  375. // Return with whatever we got below us.
  376. //
  377. ntStatus = Irp->IoStatus.Status;
  378. }
  379. DBGPrint(("'HIDMINI.SYS: HidMiniQueryIDCompletion Exit = %x\n", ntStatus));
  380. return ntStatus;
  381. }
  382. NTSTATUS
  383. HidMiniRemoveDevice(
  384. IN PDEVICE_OBJECT DeviceObject
  385. )
  386. /*++
  387. Routine Description:
  388. Removes a given instance of a device.
  389. Arguments:
  390. DeviceObject - pointer to the device object.
  391. Return Value:
  392. NT status code
  393. --*/
  394. {
  395. NTSTATUS ntStatus = STATUS_SUCCESS;
  396. PDEVICE_EXTENSION DeviceExtension;
  397. ULONG oldDeviceState;
  398. DBGPrint(("'HIDMINI.SYS: HidMiniRemoveDevice Enter\n"));
  399. //
  400. // Get a pointer to the device extension
  401. //
  402. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  403. DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
  404. oldDeviceState = DeviceExtension->DeviceState;
  405. DeviceExtension->DeviceState = DEVICE_STATE_REMOVING;
  406. IsRunning = FALSE;
  407. //
  408. // Cancel any outstanding IRPs if the device was running
  409. //
  410. if(oldDeviceState == DEVICE_STATE_RUNNING)
  411. {
  412. ntStatus = HidMiniAbortPendingRequests( DeviceObject );
  413. DBGPrint(("'HIDMINI.SYS: HidMiniAbortPendingRequests() = %x\n", ntStatus));
  414. } else {
  415. ASSERT( DeviceExtension->NumPendingRequests == 0 );
  416. }
  417. ntStatus = STATUS_SUCCESS;
  418. DBGPrint(("'HIDSAMHIDMINI.SYS: HidMiniRemoveDevice = %x\n", ntStatus));
  419. return ntStatus;
  420. }