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.

945 lines
24 KiB

  1. /*++
  2. Copyright (c) 1996,1997 Microsoft Corporation
  3. Module Name:
  4. hid.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. //
  13. // Our descriptors. Normally you'd have to get these from the hardware, if it
  14. // was truly a HID device, or you'll have to build your own for non HID devices.
  15. //
  16. //
  17. // The report descriptor completely lays out what read and write packets will look like
  18. // and indicates what the semantics are for each field.
  19. //
  20. HID_REPORT_DESCRIPTOR MyReportDescriptor[] = {
  21. 0x05, 0x01, // Usage Page (Generic Desktop),
  22. 0x09, 0x06, // Usage (Keyboard),
  23. 0xA1, 0x01, // Collection (Application),
  24. 0x05, 0x07, // Usage Page (Key Codes);
  25. 0x19, 0xE0, // Usage Minimum (224),
  26. 0x29, 0xE7, // Usage Maximum (231),
  27. 0x15, 0x00, // Logical Minimum (0),
  28. 0x25, 0x01, // Logical Maximum (1),
  29. 0x75, 0x01, // Report Size (1),
  30. 0x95, 0x08, // Report Count (8),
  31. 0x81, 0x02, // Input (Data, Variable, Absolute),;Modifier byte
  32. 0x95, 0x01, // Report Count (1),
  33. 0x75, 0x08, // Report Size (8),
  34. 0x81, 0x01, // Input (Constant), ;Reserved byte
  35. 0x95, 0x05, // Report Count (5),
  36. 0x75, 0x01, // Report Size (1),
  37. 0x05, 0x08, // Usage Page (Page# for LEDs),
  38. 0x19, 0x01, // Usage Minimum (1),
  39. 0x29, 0x05, // Usage Maximum (5),
  40. 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
  41. 0x95, 0x01, // Report Count (1),
  42. 0x75, 0x03, // Report Size (3),
  43. 0x91, 0x01, // Output (Constant), ;LED report padding
  44. 0x95, 0x06, // Report Count (6),
  45. 0x75, 0x08, // Report Size (8),
  46. 0x15, 0x00, // Logical Minimum (0),
  47. 0x25, 0x65, // Logical Maximum(101),
  48. 0x05, 0x07, // Usage Page (Key Codes),
  49. 0x19, 0x00, // Usage Minimum (0),
  50. 0x29, 0x65, // Usage Maximum (101),
  51. 0x81, 0x00, // Input (Data, Array), ;Key arrays (6 bytes)
  52. 0xC0 // End Collection
  53. };
  54. //
  55. // The HID descriptor has some basic device info and tells how long the report
  56. // descriptor is.
  57. //
  58. USB_HID_DESCRIPTOR MyHidDescriptor = {
  59. 0x09, // length of HID descriptor
  60. 0x21, // descriptor type == HID
  61. 0x0100, // hid spec release
  62. 0x00, // country code == Not Specified
  63. 0x01, // number of HID class descriptors
  64. 0x22, // report descriptor type
  65. sizeof(MyReportDescriptor) // total length of report descriptor
  66. };
  67. //
  68. // This buffer has all of the strings that we define.
  69. //
  70. UCHAR AStringDescriptor[] = {
  71. 4, // length of this string
  72. 3, // type == STRING
  73. 0x09, 0x00, // language code == ENGLISH
  74. 44, 3,
  75. 'M',0, 'i',0, 'c',0, 'r',0, 'o',0, 's',0, 'o',0, 'f',0,
  76. 't',0, ' ',0, 'C',0, 'o',0, 'r',0, 'p',0, 'o',0, 'r',0,
  77. 'a',0, 't',0, 'i',0, 'o',0, 'n',0,
  78. 46, 3,
  79. 'S',0, 'y',0, 's',0, 't',0, 'e',0, 'm',0, ' ',0, 'C',0,
  80. 'o',0, 'n',0, 't',0, 'r',0, 'o',0, 'l',0, ' ',0, 'B',0,
  81. 'u',0, 't',0, 't',0, 'o',0, 'n',0, 's',0,
  82. 32, 3,
  83. 'L',0, 'e',0, 'g',0, 'a',0, 'c',0, 'y',0, ' ',0, 'K',0,
  84. 'e',0, 'y',0, 'b',0, 'o',0, 'a',0, 'r',0, 'd',0,
  85. };
  86. //
  87. // String descriptors are
  88. PUSB_STRING_DESCRIPTOR MyStringDescriptor = (PUSB_STRING_DESCRIPTOR) AStringDescriptor;
  89. //
  90. // No designator descriptors.
  91. //
  92. PUSB_PHYSICAL_DESCRIPTOR MyPhysicalDescriptor = NULL;
  93. //
  94. // IO lists
  95. //
  96. KSPIN_LOCK HidMini_IrpReadLock;
  97. KSPIN_LOCK HidMini_IrpWriteLock;
  98. LIST_ENTRY HidMini_ReadIrpHead;
  99. LIST_ENTRY HidMini_WriteIrpHead;
  100. BOOLEAN IsRunning = FALSE;
  101. LONG ReadsCompleting = 0;
  102. NTSTATUS HidMiniGetHIDDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  103. /*++
  104. Routine Description:
  105. Finds the HID descriptor and copies it into the buffer provided by the Irp.
  106. Arguments:
  107. DeviceObject - pointer to a device object.
  108. Irp - Pointer to Interrupt Request Packet.
  109. Return Value:
  110. NT status code.
  111. --*/
  112. {
  113. NTSTATUS ntStatus = STATUS_SUCCESS;
  114. PDEVICE_EXTENSION DeviceExtension;
  115. PIO_STACK_LOCATION IrpStack;
  116. ULONG bytesToCopy;
  117. DBGPrint(("'HIDMINI.SYS: HidMiniGetHIDDescriptor Entry\n"));
  118. //
  119. // Get a pointer to the current location in the Irp
  120. //
  121. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  122. //
  123. // Get a pointer to the device extension
  124. //
  125. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  126. //
  127. // Copy device descriptor to HIDCLASS buffer
  128. //
  129. DBGPrint(("'HIDMINI.SYS: HIDCLASS Buffer = 0x%x, Buffer length = 0x%x\n", Irp->UserBuffer, IrpStack->Parameters.DeviceIoControl.OutputBufferLength));
  130. //
  131. // Copy MIN (OutputBufferLength, DeviceExtension->HidDescriptor->bLength)
  132. //
  133. bytesToCopy = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  134. if (bytesToCopy > DeviceExtension->HidDescriptor.bLength) {
  135. bytesToCopy = DeviceExtension->HidDescriptor.bLength;
  136. }
  137. DBGPrint(("'HIDMINI.SYS: Copying %d bytes to HIDCLASS buffer\n", bytesToCopy));
  138. RtlCopyMemory((PUCHAR) Irp->UserBuffer, (PUCHAR) &DeviceExtension->HidDescriptor, bytesToCopy);
  139. //
  140. // Report how many bytes were copied
  141. //
  142. Irp->IoStatus.Information = bytesToCopy;
  143. DBGPrint(("'HIDMINI.SYS: HidMiniGetHIDDescriptor Exit = 0x%x\n", ntStatus));
  144. return ntStatus;
  145. }
  146. NTSTATUS HidMiniGetReportDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  147. /*++
  148. Routine Description:
  149. Finds the Report descriptor and copies it into the buffer provided by the Irp.
  150. Arguments:
  151. DeviceObject - pointer to a device object.
  152. Irp - Pointer to Interrupt Request Packet.
  153. Return Value:
  154. NT status code.
  155. --*/
  156. {
  157. NTSTATUS ntStatus = STATUS_SUCCESS;
  158. PDEVICE_EXTENSION DeviceExtension;
  159. PIO_STACK_LOCATION IrpStack;
  160. ULONG bytesToCopy;
  161. DBGPrint(("'HIDMINI.SYS: HidMiniGetReportDescriptor Entry\n"));
  162. //
  163. // Get a pointer to the current location in the Irp
  164. //
  165. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  166. //
  167. // Get a pointer to the device extension
  168. //
  169. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  170. //
  171. // Copy device descriptor to HIDCLASS buffer
  172. //
  173. DBGPrint(("'HIDMINI.SYS: HIDCLASS Buffer = 0x%x, Buffer length = 0x%x\n", Irp->UserBuffer, IrpStack->Parameters.DeviceIoControl.OutputBufferLength));
  174. //
  175. // Copy MIN (OutputBufferLength, DeviceExtension->HidDescriptor->bLength)
  176. //
  177. bytesToCopy = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  178. if (bytesToCopy > DeviceExtension->HidDescriptor.wReportLength) {
  179. bytesToCopy = DeviceExtension->HidDescriptor.wReportLength;
  180. }
  181. DBGPrint(("'HIDMINI.SYS: Copying %d bytes to HIDCLASS buffer\n", bytesToCopy));
  182. RtlCopyMemory((PUCHAR) Irp->UserBuffer, (PUCHAR) DeviceExtension->ReportDescriptor, bytesToCopy);
  183. //
  184. // Report how many bytes were copied
  185. //
  186. Irp->IoStatus.Information = bytesToCopy;
  187. DBGPrint(("'HIDMINI.SYS: HidMiniGetReportDescriptor Exit = 0x%x\n", ntStatus));
  188. return ntStatus;
  189. }
  190. NTSTATUS HidMiniGetDeviceAttributes(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  191. /*++
  192. Routine Description:
  193. Fill in the given struct _HID_DEVICE_ATTRIBUTES
  194. Arguments:
  195. DeviceObject - pointer to a device object.
  196. Return Value:
  197. NT status code.
  198. --*/
  199. {
  200. NTSTATUS ntStatus = STATUS_SUCCESS;
  201. PDEVICE_EXTENSION deviceExtension;
  202. PIO_STACK_LOCATION irpStack;
  203. PHID_DEVICE_ATTRIBUTES deviceAttributes;
  204. DBGPrint(("'HIDMINI.SYS: HidMiniGetDeviceAttributes Entry\n"));
  205. //
  206. // Get a pointer to the current location in the Irp
  207. //
  208. irpStack = IoGetCurrentIrpStackLocation(Irp);
  209. //
  210. // Get a pointer to the device extension
  211. //
  212. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  213. deviceAttributes = (PHID_DEVICE_ATTRIBUTES) Irp->UserBuffer;
  214. ASSERT (sizeof (HID_DEVICE_ATTRIBUTES) ==
  215. irpStack->Parameters.DeviceIoControl.OutputBufferLength);
  216. //
  217. // Report how many bytes were copied
  218. //
  219. Irp->IoStatus.Information = sizeof (HID_DEVICE_ATTRIBUTES);
  220. deviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES);
  221. deviceAttributes->VendorID = HIDMINI_VID;
  222. deviceAttributes->ProductID = HIDMINI_PID;
  223. deviceAttributes->VersionNumber = HIDMINI_VERSION;
  224. DBGPrint(("'HIDMINI.SYS: HidMiniGetAttributes Exit = 0x%x\n", ntStatus));
  225. return ntStatus;
  226. }
  227. VOID HidMiniIncrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension)
  228. /*++
  229. Routine Description:
  230. Increments the number of outstanding requests on the DeviceObject with this extension.
  231. Arguments:
  232. DeviceExtension - the mini driver extension area of the device that is being made busy.
  233. Return Value:
  234. VOID.
  235. --*/
  236. {
  237. DeviceExtension->NumPendingRequests++;
  238. DBGPrint(("'HIDMINI.SYS: Bumping requests on device extension 0x%08x up to %d\n",
  239. DeviceExtension,
  240. DeviceExtension->NumPendingRequests));
  241. }
  242. VOID HidMiniDecrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension)
  243. /*++
  244. Routine Description:
  245. Decrements the number of outstanding requests on the DeviceObject with this extension.
  246. If we get to zero outstanding IOs, set the device's all requests complete event.
  247. Arguments:
  248. DeviceExtension - the mini driver extension area of the device that is being made busy.
  249. Return Value:
  250. VOID.
  251. --*/
  252. {
  253. ASSERT( DeviceExtension->NumPendingRequests > 0 );
  254. DeviceExtension->NumPendingRequests--;
  255. DBGPrint(("'HIDMINI.SYS: Bumping requests on device extension 0x%08x down to %d\n",
  256. DeviceExtension,
  257. DeviceExtension->NumPendingRequests));
  258. if( DeviceExtension->NumPendingRequests == 0 &&
  259. DeviceExtension->DeviceState != DEVICE_STATE_RUNNING ){
  260. //
  261. // The device state is stopping, and the last outstanding request
  262. // has just completed.
  263. //
  264. DBGPrint(("'HIDMINI.SYS: last request completed, signalling event\n"));
  265. KeSetEvent( &DeviceExtension->AllRequestsCompleteEvent,
  266. 0, FALSE );
  267. }
  268. }
  269. NTSTATUS HidMiniReadReport(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  270. /*++
  271. Routine Description:
  272. Process a read HID packet request.
  273. Arguments:
  274. DeviceObject - pointer to a device object.
  275. Irp - Pointer to Interrupt Request Packet.
  276. Return Value:
  277. NT status code.
  278. --*/
  279. {
  280. NTSTATUS ntStatus;
  281. PDEVICE_EXTENSION DeviceExtension;
  282. PIO_STACK_LOCATION IrpStack;
  283. PVOID ReportBuffer;
  284. ULONG ReportTotalSize;
  285. PNODE Node;
  286. DBGPrint(("'HIDMINI.SYS: HidMiniReadReport Enter\n"));
  287. DBGPrint(("'HIDMINI.SYS: DeviceObject = 0x%x\n", DeviceObject));
  288. //
  289. // Get a pointer to the device extension.
  290. //
  291. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  292. DBGPrint(("'HIDMINI.SYS: DeviceExtension = 0x%x\n", DeviceExtension));
  293. //
  294. // Get Stack location
  295. //
  296. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  297. //
  298. // Get the buffer and its size, make sure they're valid.
  299. //
  300. ReportBuffer = Irp->UserBuffer;
  301. ReportTotalSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  302. DBGPrint(("'HIDMINI.SYS: ReportBuffer = 0x%x, ReportTotalSize = 0x%x\n", ReportBuffer, ReportTotalSize));
  303. if (IsRunning) {
  304. if (ReportTotalSize && ReportBuffer){
  305. Node = (PNODE)ExAllocatePool(NonPagedPool, sizeof(NODE));
  306. if (Node) {
  307. //
  308. // Increase the count of outstanding IOs, mark the Irp pending.
  309. //
  310. HidMiniIncrementPendingRequestCount(DeviceExtension);
  311. IoMarkIrpPending(Irp);
  312. //
  313. // Hook the Irp onto the pending IO list
  314. //
  315. Node->Irp = Irp;
  316. ExInterlockedInsertTailList(&HidMini_ReadIrpHead, &Node->List, &HidMini_IrpReadLock);
  317. ntStatus = STATUS_PENDING;
  318. } else {
  319. ntStatus = STATUS_NO_MEMORY;
  320. }
  321. } else {
  322. //
  323. // No buffer, or buffer of zero size
  324. //
  325. ntStatus = STATUS_INVALID_PARAMETER;
  326. }
  327. } else {
  328. //
  329. // We're shutting down
  330. //
  331. ntStatus = STATUS_NO_SUCH_DEVICE;
  332. }
  333. DBGPrint(("'HIDMINI.SYS: HidMiniReadReport Exit = 0x%x\n", ntStatus));
  334. return ntStatus;
  335. }
  336. NTSTATUS HidMiniReadCompletion(PVOID Context)
  337. /*++
  338. Routine Description:
  339. HID read packet completion routine.
  340. Arguments:
  341. Return Value:
  342. STATUS_SUCCESS, STATUS_UNSUCCESSFUL.
  343. --*/
  344. {
  345. PIO_STACK_LOCATION IrpStack;
  346. ULONG bytesRead;
  347. PDEVICE_EXTENSION deviceExtension;
  348. PNODE IrpNode;
  349. PIRP Irp;
  350. PDEVICE_OBJECT DeviceObject;
  351. //
  352. // ReadBuffer is a list of keyboard reports that can be transmitted as a
  353. // result for a read request.
  354. //
  355. static int ReadIndex = 0;
  356. static int Rest = 0;
  357. static UCHAR *ReadBuffer[] = {
  358. "\x02\x00\x0D\0\0\0\0\0", // J
  359. "\x00\x00\x04\0\0\0\0\0", // a
  360. "\x00\x00\x06\0\0\0\0\0", // c
  361. "\x00\x00\x0E\0\0\0\0\0", // k
  362. "\x00\x00\x07\0\0\0\0\0", // d
  363. "\x00\x00\x04\0\0\0\0\0", // a
  364. "\x00\x00\x1A\0\0\0\0\0", // w
  365. "\x00\x00\x16\0\0\0\0\0", // s
  366. "\x00\x00\x2C\0\0\0\0\0", // <space>
  367. "\x00\x00\x0F\0\0\0\0\0", // l
  368. "\x00\x00\x12\0\0\0\0\0", // o
  369. "\x00\x00\x19\0\0\0\0\0", // v
  370. "\x00\x00\x08\0\0\0\0\0", // e
  371. "\x00\x00\x2C\0\0\0\0\0", // <space>
  372. "\x00\x00\x10\0\0\0\0\0", // m
  373. "\x00\x00\x1C\0\0\0\0\0", // y
  374. "\x00\x00\x2C\0\0\0\0\0", // <space>
  375. "\x00\x00\x05\0\0\0\0\0", // b
  376. "\x00\x00\x0C\0\0\0\0\0", // i
  377. "\x00\x00\x0A\0\0\0\0\0", // g
  378. "\x00\x00\x2C\0\0\0\0\0", // <space>
  379. "\x00\x00\x16\0\0\0\0\0", // s
  380. "\x00\x00\x13\0\0\0\0\0", // p
  381. "\x00\x00\x0B\0\0\0\0\0", // h
  382. "\x00\x00\x1C\0\0\0\0\0", // y
  383. "\x00\x00\x11\0\0\0\0\0", // n
  384. "\x00\x00\x1B\0\0\0\0\0", // x
  385. "\x00\x00\x2C\0\0\0\0\0", // <space>
  386. "\x00\x00\x12\0\0\0\0\0", // o
  387. "\x00\x00\x09\0\0\0\0\0", // f
  388. "\x00\x00\x2C\0\0\0\0\0", // <space>
  389. "\x00\x00\x14\0\0\0\0\0", // q
  390. "\x00\x00\x18\0\0\0\0\0", // u
  391. "\x00\x00\x04\0\0\0\0\0", // a
  392. "\x00\x00\x15\0\0\0\0\0", // r
  393. "\x00\x00\x17\0\0\0\0\0", // t
  394. "\x00\x00\x1D\0\0\0\0\0", // z
  395. "\x00\x00\x37\0\0\0\0\0", // .
  396. "\x00\x00\x2C\0\0\0\0\0", // <space>
  397. "\x00\x00\x2C\0\0\0\0\0", // <space>
  398. NULL,
  399. };
  400. DBGPrint(("'HIDMINI.SYS: HidMiniReadCompletion Enter\n"));
  401. //
  402. // Free workitem that started us, check to see if we're already completing reads
  403. //
  404. ExFreePool((PWORK_QUEUE_ITEM)Context);
  405. ASSERT(ReadsCompleting > 0);
  406. if (InterlockedDecrement(&ReadsCompleting)) {
  407. return STATUS_SUCCESS;
  408. }
  409. //
  410. // Loop around completing Irps. When we run out, break
  411. // out of the loop.
  412. //
  413. while (IsRunning) {
  414. //
  415. // Make sure we don't overrun our list of replies. If we get to the end of it,
  416. // we'll exit this loop early and let the IRPs queue up again.
  417. //
  418. if (!ReadBuffer[ReadIndex]) {
  419. ReadIndex = 0;
  420. }
  421. //
  422. // Any Irps to complete?
  423. //
  424. IrpNode = (PNODE)ExInterlockedRemoveHeadList(&HidMini_ReadIrpHead, &HidMini_IrpReadLock);
  425. if (IrpNode) {
  426. //
  427. // Find all the pieces
  428. //
  429. Irp = IrpNode->Irp;
  430. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  431. DeviceObject = IrpStack->DeviceObject;
  432. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION( DeviceObject );
  433. HidMiniDecrementPendingRequestCount( deviceExtension );
  434. //
  435. // Get the bytes read and store in the status block
  436. //
  437. bytesRead = 8;
  438. if (bytesRead > IrpStack->Parameters.DeviceIoControl.OutputBufferLength) {
  439. bytesRead = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  440. }
  441. if (Rest) {
  442. RtlCopyMemory((PUCHAR) Irp->UserBuffer, "\x00\x00\0\0\0\0\0\0", bytesRead);
  443. } else {
  444. RtlCopyMemory((PUCHAR) Irp->UserBuffer, (PUCHAR)ReadBuffer[ReadIndex++], bytesRead);
  445. }
  446. Rest ^= 1;
  447. Irp->IoStatus.Information = bytesRead;
  448. Irp->IoStatus.Status = STATUS_SUCCESS;
  449. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  450. DBGPrint(("'HIDMINI.SYS: Read report DeviceObject (%x) completed, %d bytes!\n",
  451. DeviceObject, bytesRead ));
  452. //
  453. // Free up the Node
  454. //
  455. ExFreePool(IrpNode);
  456. if (!Rest) {
  457. break;
  458. }
  459. } else {
  460. //
  461. // No Irps
  462. //
  463. break;
  464. }
  465. }
  466. return STATUS_SUCCESS;
  467. }
  468. NTSTATUS HidMiniWriteReport(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  469. /*++
  470. Routine Description:
  471. Process a write HID packet request. This is also how we start up the read
  472. completion process.
  473. Arguments:
  474. DeviceObject - pointer to a device object.
  475. Irp - Pointer to Interrupt Request Packet.
  476. Return Value:
  477. NT status code.
  478. --*/
  479. {
  480. NTSTATUS ntStatus;
  481. PDEVICE_EXTENSION DeviceExtension;
  482. PNODE Node;
  483. PWORK_QUEUE_ITEM StartCompletingReads;
  484. DBGPrint(("'HIDMINI.SYS: HidMiniWriteReport Enter\n"));
  485. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  486. if (IsRunning) {
  487. Node = (PNODE)ExAllocatePool(NonPagedPool, sizeof(NODE));
  488. StartCompletingReads = (PWORK_QUEUE_ITEM)
  489. ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
  490. if (Node && StartCompletingReads) {
  491. //
  492. // Queue up a work item to start completing reads.
  493. //
  494. ASSERT(ReadsCompleting >= 0);
  495. InterlockedIncrement(&ReadsCompleting);
  496. ExInitializeWorkItem(StartCompletingReads,
  497. HidMiniReadCompletion,
  498. (PVOID)StartCompletingReads);
  499. ExQueueWorkItem(StartCompletingReads, DelayedWorkQueue);
  500. //
  501. // Increase the count of outstanding IOs, mark the Irp pending.
  502. //
  503. HidMiniIncrementPendingRequestCount(DeviceExtension);
  504. IoMarkIrpPending(Irp);
  505. //
  506. // Hook the Irp onto the pending IO list
  507. //
  508. Node->Irp = Irp;
  509. ExInterlockedInsertTailList(&HidMini_WriteIrpHead, &Node->List, &HidMini_IrpWriteLock);
  510. ntStatus = STATUS_PENDING;
  511. //
  512. // Give the write completion code a kick
  513. //
  514. HidMiniWriteCompletion();
  515. } else {
  516. ntStatus = STATUS_NO_MEMORY;
  517. }
  518. } else {
  519. //
  520. // We're shutting down
  521. //
  522. ntStatus = STATUS_NO_SUCH_DEVICE;
  523. }
  524. DBGPrint(("'HIDMINI.SYS: HidMiniWriteReport Exit = 0x%x\n", ntStatus));
  525. return ntStatus;
  526. }
  527. NTSTATUS HidMiniWriteCompletion(VOID)
  528. /*++
  529. Routine Description:
  530. Complete processing a write HID packet request.
  531. Arguments:
  532. Return Value:
  533. NT status code.
  534. --*/
  535. {
  536. PIO_STACK_LOCATION IrpStack;
  537. PDEVICE_EXTENSION deviceExtension;
  538. PNODE IrpNode;
  539. PIRP Irp;
  540. PDEVICE_OBJECT DeviceObject;
  541. //
  542. // Loop around completing Irps. When we run out, break
  543. // out of the loop.
  544. //
  545. while (IsRunning) {
  546. //
  547. // Any Irps to complete?
  548. //
  549. IrpNode = (PNODE)ExInterlockedRemoveHeadList(&HidMini_WriteIrpHead, &HidMini_IrpWriteLock);
  550. if (IrpNode) {
  551. //
  552. // Find all the pieces
  553. //
  554. Irp = IrpNode->Irp;
  555. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  556. DeviceObject = IrpStack->DeviceObject;
  557. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION( DeviceObject );
  558. //
  559. // Do something here...
  560. //
  561. //
  562. // Finish off the IRP
  563. //
  564. HidMiniDecrementPendingRequestCount( deviceExtension );
  565. Irp->IoStatus.Status = STATUS_SUCCESS;
  566. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  567. DBGPrint(("'HIDMINI.SYS: Write report DeviceObject (%x) completed\n", DeviceObject));
  568. //
  569. // Free up the Node
  570. //
  571. ExFreePool(IrpNode);
  572. } else {
  573. //
  574. // No Irps
  575. //
  576. break;
  577. }
  578. }
  579. return STATUS_SUCCESS;
  580. }
  581. NTSTATUS HidMiniGetStringDescriptor( IN PDEVICE_OBJECT DeviceObject,
  582. IN PIRP Irp)
  583. /*++
  584. Routine Description:
  585. Get the device string descriptor, if any.
  586. Arguments:
  587. DeviceObject - pointer to a device object.
  588. Irp - Pointer to Interrupt Request Packet.
  589. Return Value:
  590. NT status code.
  591. --*/
  592. {
  593. NTSTATUS ntStatus = STATUS_SUCCESS;
  594. PDEVICE_EXTENSION DeviceExtension;
  595. PIO_STACK_LOCATION IrpStack;
  596. ULONG bytesToCopy;
  597. DBGPrint(("'HIDMINI.SYS: HidMiniGetStringDescriptor Enter\n"));
  598. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  599. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  600. //
  601. // Get the buffer size to write into
  602. //
  603. bytesToCopy = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  604. //
  605. // Make sure we have a buffer and it has some space
  606. //
  607. if (Irp->UserBuffer && bytesToCopy){
  608. //
  609. // Adjust the size to the amount we have to write
  610. //
  611. if (bytesToCopy > sizeof(AStringDescriptor)) {
  612. bytesToCopy = sizeof(AStringDescriptor);
  613. }
  614. DBGPrint(("'HIDMINI.SYS: Copying %d bytes to STRING buffer\n", bytesToCopy));
  615. RtlCopyMemory((PUCHAR) Irp->UserBuffer, (PUCHAR) DeviceExtension->StringDescriptor, bytesToCopy);
  616. //
  617. // Report how many bytes were copied
  618. //
  619. Irp->IoStatus.Information = bytesToCopy;
  620. } else {
  621. ntStatus = STATUS_INVALID_USER_BUFFER;
  622. }
  623. Irp->IoStatus.Status = ntStatus;
  624. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  625. DBGPrint(("'HIDMINI.SYS: HidMiniGetStringDescriptor Exit = 0x%x\n", ntStatus));
  626. return ntStatus;
  627. }
  628. NTSTATUS HidMiniOpenCollection(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  629. /*++
  630. Routine Description:
  631. Called when a HIDCLASS client opens this collection
  632. Arguments:
  633. DeviceObject - Pointer to class device object.
  634. IrpStack - Pointer to Interrupt Request Packet.
  635. Return Value:
  636. STATUS_SUCCESS, STATUS_PENDING.
  637. --*/
  638. {
  639. NTSTATUS ntStatus = STATUS_SUCCESS;
  640. DBGPrint(("'HIDMINI.SYS: HidMiniOpenCollection Enter\n"));
  641. Irp->IoStatus.Status = ntStatus;
  642. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  643. DBGPrint(("'HIDMINI.SYS: HidMiniOpenCollection Exit = 0x%x\n", ntStatus));
  644. return ntStatus;
  645. }
  646. NTSTATUS HidMiniCloseCollection(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  647. /*++
  648. Routine Description:
  649. Called when a HIDCLASS client closes this collection
  650. Arguments:
  651. DeviceObject - Pointer to class device object.
  652. IrpStack - Pointer to Interrupt Request Packet.
  653. Return Value:
  654. STATUS_SUCCESS, STATUS_PENDING.
  655. --*/
  656. {
  657. NTSTATUS ntStatus = STATUS_SUCCESS;
  658. DBGPrint(("'HIDMINI.SYS: HidMiniCloseCollection Enter\n"));
  659. Irp->IoStatus.Status = ntStatus;
  660. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  661. DBGPrint(("'HIDMINI.SYS: HidMiniCloseCollection Exit = 0x%x\n", ntStatus));
  662. return ntStatus;
  663. }