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.

676 lines
18 KiB

  1. /*
  2. *************************************************************************
  3. * File: HID.C
  4. *
  5. * Module: HID1394.SYS
  6. * HID (Human Input Device) minidriver for IEEE 1394 devices.
  7. *
  8. * Copyright (c) 1998 Microsoft Corporation
  9. *
  10. *
  11. * Author: ervinp
  12. *
  13. *************************************************************************
  14. */
  15. #include <wdm.h>
  16. #include <hidport.h>
  17. #include <1394.h>
  18. #include "hid1394.h"
  19. #include "debug.h"
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, HIDT_GetHidDescriptor)
  22. #pragma alloc_text(PAGE, HIDT_GetReportDescriptor)
  23. #pragma alloc_text(PAGE, HIDT_GetStringDescriptor)
  24. #pragma alloc_text(PAGE, HIDT_GetPhysicalDescriptor)
  25. #pragma alloc_text(PAGE, HIDT_GetFeature)
  26. #pragma alloc_text(PAGE, HIDT_SetFeature)
  27. #pragma alloc_text(PAGE, HIDT_GetDeviceAttributes)
  28. #endif
  29. resetWorkItemContext *resetWorkItemsList = NULL;
  30. KSPIN_LOCK resetWorkItemsListSpinLock;
  31. /*
  32. ************************************************************
  33. * EnqueueResetWorkItem
  34. ************************************************************
  35. *
  36. * This function must be called with resetWorkItemsListSpinLock held.
  37. */
  38. VOID EnqueueResetWorkItem(resetWorkItemContext *workItem)
  39. {
  40. workItem->next = resetWorkItemsList;
  41. resetWorkItemsList = workItem;
  42. }
  43. /*
  44. ************************************************************
  45. * DequeueResetWorkItemWithIrp
  46. ************************************************************
  47. *
  48. * Dequeue the workItem with the given IRP
  49. * AND mark it as cancelled in case the work item didn't fire yet.
  50. *
  51. *
  52. */
  53. BOOLEAN DequeueResetWorkItemWithIrp(PIRP Irp, BOOLEAN irpWasCancelled)
  54. {
  55. BOOLEAN didDequeue = FALSE;
  56. if (resetWorkItemsList){
  57. resetWorkItemContext *removedItem = NULL;
  58. if (resetWorkItemsList->irpToComplete == Irp){
  59. removedItem = resetWorkItemsList;
  60. resetWorkItemsList = resetWorkItemsList->next;
  61. }
  62. else {
  63. resetWorkItemContext *thisWorkItem = resetWorkItemsList;
  64. while (thisWorkItem->next && (thisWorkItem->next->irpToComplete != Irp)){
  65. thisWorkItem = thisWorkItem->next;
  66. }
  67. removedItem = thisWorkItem->next;
  68. if (removedItem){
  69. thisWorkItem->next = removedItem->next;
  70. }
  71. }
  72. if (removedItem){
  73. removedItem->next = BAD_POINTER;
  74. /*
  75. * Mark this workItem as cancelled so we won't touch
  76. * it's cancelled IRP when the workItem fires.
  77. */
  78. if (irpWasCancelled){
  79. removedItem->irpWasCancelled = TRUE;
  80. removedItem->irpToComplete = BAD_POINTER;
  81. }
  82. didDequeue = TRUE;
  83. }
  84. }
  85. return didDequeue;
  86. }
  87. /*
  88. ********************************************************************************
  89. * HIDT_GetHidDescriptor
  90. ********************************************************************************
  91. *
  92. * Routine Description:
  93. *
  94. * Free all the allocated resources, etc.
  95. *
  96. * Arguments:
  97. *
  98. * DeviceObject - pointer to a device object.
  99. *
  100. * Return Value:
  101. *
  102. * NT status code.
  103. *
  104. */
  105. NTSTATUS HIDT_GetHidDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  106. {
  107. NTSTATUS ntStatus;
  108. PDEVICE_EXTENSION DeviceExtension;
  109. PIO_STACK_LOCATION IrpStack;
  110. PAGED_CODE();
  111. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  112. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  113. // BUGBUG FINISH
  114. ntStatus = STATUS_UNSUCCESSFUL;
  115. ASSERT(NT_SUCCESS(ntStatus));
  116. return ntStatus;
  117. }
  118. /*
  119. ********************************************************************************
  120. * HIDT_GetDeviceAttributes
  121. ********************************************************************************
  122. *
  123. * Routine Description:
  124. *
  125. * Fill in the given struct _HID_DEVICE_ATTRIBUTES
  126. *
  127. * Arguments:
  128. *
  129. * DeviceObject - pointer to a device object.
  130. *
  131. * Return Value:
  132. *
  133. * NT status code.
  134. *
  135. */
  136. NTSTATUS HIDT_GetDeviceAttributes(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion)
  137. {
  138. NTSTATUS ntStatus;
  139. PDEVICE_EXTENSION deviceExtension;
  140. PIO_STACK_LOCATION irpStack;
  141. PHID_DEVICE_ATTRIBUTES deviceAttributes;
  142. PAGED_CODE();
  143. irpStack = IoGetCurrentIrpStackLocation(Irp);
  144. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  145. deviceAttributes = (PHID_DEVICE_ATTRIBUTES) Irp->UserBuffer;
  146. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
  147. sizeof (HID_DEVICE_ATTRIBUTES)){
  148. //
  149. // Report how many bytes were copied
  150. //
  151. Irp->IoStatus.Information = sizeof (HID_DEVICE_ATTRIBUTES);
  152. deviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES);
  153. // BUGBUG FINISH
  154. // deviceAttributes->VendorID = deviceExtension->DeviceDescriptor->idVendor;
  155. // deviceAttributes->ProductID = deviceExtension->DeviceDescriptor->idProduct;
  156. // deviceAttributes->VersionNumber = deviceExtension->DeviceDescriptor->bcdDevice;
  157. ntStatus = STATUS_SUCCESS;
  158. }
  159. else {
  160. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  161. }
  162. ASSERT(NT_SUCCESS(ntStatus));
  163. return ntStatus;
  164. }
  165. /*
  166. ********************************************************************************
  167. * HIDT_GetReportDescriptor
  168. ********************************************************************************
  169. *
  170. *
  171. */
  172. NTSTATUS HIDT_GetReportDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  173. {
  174. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  175. // BUGBUG FINISH
  176. return ntStatus;
  177. }
  178. /*
  179. ********************************************************************************
  180. * HIDT_IncrementPendingRequestCount
  181. ********************************************************************************
  182. *
  183. *
  184. */
  185. NTSTATUS HIDT_IncrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension)
  186. {
  187. LONG newRequestCount;
  188. NTSTATUS ntStatus = STATUS_SUCCESS;
  189. newRequestCount = InterlockedIncrement(&DeviceExtension->NumPendingRequests);
  190. //
  191. // Make sure that the device is capable of receiving new requests.
  192. //
  193. if (DeviceExtension->DeviceState != DEVICE_STATE_RUNNING) {
  194. //
  195. // Device cannot receive any more IOs, decrement back, fail the increment
  196. //
  197. HIDT_DecrementPendingRequestCount(DeviceExtension);
  198. ntStatus = STATUS_NO_SUCH_DEVICE;
  199. }
  200. return ntStatus;
  201. }
  202. /*
  203. ********************************************************************************
  204. * HIDT_DecrementPendingRequestCount
  205. ********************************************************************************
  206. *
  207. *
  208. */
  209. VOID HIDT_DecrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension)
  210. {
  211. LONG PendingCount;
  212. ASSERT(DeviceExtension->NumPendingRequests >= 0);
  213. PendingCount = InterlockedDecrement(&DeviceExtension->NumPendingRequests);
  214. if (PendingCount < 0){
  215. ASSERT(DeviceExtension->DeviceState != DEVICE_STATE_RUNNING);
  216. /*
  217. * The device state is stopping, and the last outstanding request
  218. * has just completed.
  219. *
  220. * Note: RemoveDevice does an extra decrement, so we complete
  221. * the REMOVE IRP on the transition to -1, whether this
  222. * happens in RemoveDevice itself or subsequently while
  223. * RemoveDevice is waiting for this event to fire.
  224. */
  225. KeSetEvent(&DeviceExtension->AllRequestsCompleteEvent, 0, FALSE);
  226. }
  227. }
  228. /*
  229. ********************************************************************************
  230. * HIDT_GetPortStatus
  231. ********************************************************************************
  232. *
  233. *
  234. */
  235. NTSTATUS HIDT_GetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN PULONG PortStatus)
  236. {
  237. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  238. // BUGBUG FINISH
  239. return ntStatus;
  240. }
  241. /*
  242. ********************************************************************************
  243. * HIDT_EnableParentPort
  244. ********************************************************************************
  245. *
  246. *
  247. */
  248. NTSTATUS HIDT_EnableParentPort(IN PDEVICE_OBJECT DeviceObject)
  249. {
  250. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  251. // BUGBUG FINISH
  252. return ntStatus;
  253. }
  254. /*
  255. ********************************************************************************
  256. * HIDT_ResetWorkItem
  257. ********************************************************************************
  258. *
  259. * Resets the interrupt pipe after a read error is encountered.
  260. *
  261. */
  262. NTSTATUS HIDT_ResetWorkItem(IN PVOID Context)
  263. {
  264. resetWorkItemContext *resetWorkItemObj;
  265. PDEVICE_EXTENSION DeviceExtension;
  266. NTSTATUS ntStatus;
  267. ULONG portStatus;
  268. BOOLEAN didDequeue;
  269. KIRQL oldIrql;
  270. /*
  271. * Get the information out of the resetWorkItemContext and free it.
  272. */
  273. resetWorkItemObj = (resetWorkItemContext *)Context;
  274. ASSERT(resetWorkItemObj);
  275. ASSERT(resetWorkItemObj->sig == RESET_WORK_ITEM_CONTEXT_SIG);
  276. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(resetWorkItemObj->deviceObject);
  277. if (DEVICE_STATE_RUNNING == DeviceExtension->DeviceState) {
  278. //
  279. // Check the port state, if it is disabled we will need
  280. // to re-enable it
  281. //
  282. ntStatus = HIDT_GetPortStatus(resetWorkItemObj->deviceObject, &portStatus);
  283. if (NT_SUCCESS(ntStatus)) {
  284. //
  285. // port is disabled, attempt reset
  286. //
  287. HIDT_AbortPendingRequests(resetWorkItemObj->deviceObject);
  288. HIDT_EnableParentPort(resetWorkItemObj->deviceObject);
  289. }
  290. //
  291. // now attempt to reset the stalled pipe, this will clear the stall
  292. // on the device as well.
  293. //
  294. if (NT_SUCCESS(ntStatus)) {
  295. // BUGBUG ntStatus = HIDT_ResetInterruptPipe(resetWorkItemObj->deviceObject);
  296. }
  297. }
  298. /*
  299. * Clear the ResetWorkItem ptr in the device extension
  300. * AFTER resetting the pipe so we don't end up with
  301. * two threads resetting the same pipe at the same time.
  302. */
  303. (VOID)InterlockedExchange ((PVOID) &DeviceExtension->ResetWorkItem, 0);
  304. /*
  305. * The IRP that returned the error which prompted us to do this reset
  306. * is still owned by this driver because we returned
  307. * STATUS_MORE_PROCESSING_REQUIRED in the completion routine.
  308. * Now that the hub is reset, complete this failed IRP.
  309. *
  310. * Note: we check the irpWasCancelled as well as checking
  311. * if the IRP is in the queue to deal with the pathological
  312. * case of the IRP being cancelled, re-allocated, and
  313. * re-queued.
  314. */
  315. KeAcquireSpinLock(&resetWorkItemsListSpinLock, &oldIrql);
  316. if (resetWorkItemObj->irpWasCancelled){
  317. didDequeue = FALSE;
  318. }
  319. else {
  320. IoSetCancelRoutine(resetWorkItemObj->irpToComplete, NULL);
  321. didDequeue = DequeueResetWorkItemWithIrp(resetWorkItemObj->irpToComplete, FALSE);
  322. }
  323. KeReleaseSpinLock(&resetWorkItemsListSpinLock, oldIrql);
  324. /*
  325. * If we found a waiting IRP, complete it _after_ releasing the spinlock.
  326. */
  327. if (didDequeue){
  328. IoCompleteRequest(resetWorkItemObj->irpToComplete, IO_NO_INCREMENT);
  329. }
  330. ExFreePool(resetWorkItemObj);
  331. HIDT_DecrementPendingRequestCount(DeviceExtension);
  332. return ntStatus;
  333. }
  334. /*
  335. ********************************************************************************
  336. * ResetCancelRoutine
  337. ********************************************************************************
  338. *
  339. *
  340. */
  341. VOID ResetCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  342. {
  343. BOOLEAN didDequeue;
  344. KIRQL oldIrql;
  345. KeAcquireSpinLock(&resetWorkItemsListSpinLock, &oldIrql);
  346. didDequeue = DequeueResetWorkItemWithIrp(Irp, TRUE);
  347. KeReleaseSpinLock(&resetWorkItemsListSpinLock, oldIrql);
  348. /*
  349. * We must release the CancelSpinLock whether or not
  350. * we are completing the IRP here.
  351. */
  352. IoReleaseCancelSpinLock(Irp->CancelIrql);
  353. /*
  354. * Complete this Irp only if we found it in our queue.
  355. */
  356. if (didDequeue){
  357. Irp->IoStatus.Status = STATUS_CANCELLED;
  358. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  359. }
  360. }
  361. /*
  362. ********************************************************************************
  363. * HIDT_GetPhysicalDescriptor
  364. ********************************************************************************
  365. *
  366. *
  367. */
  368. NTSTATUS HIDT_GetPhysicalDescriptor( IN PDEVICE_OBJECT DeviceObject,
  369. IN PIRP Irp,
  370. BOOLEAN *NeedsCompletion)
  371. {
  372. NTSTATUS status = STATUS_UNSUCCESSFUL;
  373. // BUGBUG FINISH ? REMOVE ?
  374. return status;
  375. }
  376. /*
  377. ********************************************************************************
  378. * HIDT_GetStringDescriptor
  379. ********************************************************************************
  380. *
  381. *
  382. */
  383. NTSTATUS HIDT_GetStringDescriptor( IN PDEVICE_OBJECT DeviceObject,
  384. IN PIRP Irp)
  385. {
  386. NTSTATUS ntStatus = STATUS_PENDING;
  387. PDEVICE_EXTENSION DeviceExtension;
  388. PIO_STACK_LOCATION IrpStack;
  389. PVOID buffer;
  390. ULONG bufferSize;
  391. BOOLEAN isIndexedString;
  392. PAGED_CODE();
  393. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  394. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  395. switch (IrpStack->Parameters.DeviceIoControl.IoControlCode){
  396. case IOCTL_HID_GET_INDEXED_STRING:
  397. /*
  398. * IOCTL_HID_GET_INDEXED_STRING uses buffering method
  399. * METHOD_OUT_DIRECT, which passes the buffer in the MDL.
  400. */
  401. buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
  402. isIndexedString = TRUE;
  403. break;
  404. case IOCTL_HID_GET_STRING:
  405. /*
  406. * IOCTL_HID_GET_STRING uses buffering method
  407. * METHOD_NEITHER, which passes the buffer in Irp->UserBuffer.
  408. */
  409. buffer = Irp->UserBuffer;
  410. isIndexedString = FALSE;
  411. break;
  412. default:
  413. ASSERT(0);
  414. buffer = NULL;
  415. break;
  416. }
  417. bufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  418. if (buffer && bufferSize){
  419. /*
  420. * BUGBUG - hack
  421. * String id and language id are in Type3InputBuffer field
  422. * of IRP stack location.
  423. *
  424. * Note: the string ID should be identical to the string's
  425. * field offset given in Chapter 9 of the USB spec.
  426. */
  427. ULONG languageId = ((ULONG)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) >> 16;
  428. ULONG stringIndex;
  429. if (isIndexedString){
  430. stringIndex = ((ULONG)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) & 0x0ffff;
  431. }
  432. else {
  433. ULONG stringId = ((ULONG)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) & 0x0ffff;
  434. switch (stringId){
  435. case HID_STRING_ID_IMANUFACTURER:
  436. // BUGBUG FINISH stringIndex = DeviceExtension->DeviceDescriptor->iManufacturer;
  437. break;
  438. case HID_STRING_ID_IPRODUCT:
  439. // BUGBUG FINISH stringIndex = DeviceExtension->DeviceDescriptor->iProduct;
  440. break;
  441. case HID_STRING_ID_ISERIALNUMBER:
  442. // BUGBUG FINISH stringIndex = DeviceExtension->DeviceDescriptor->iSerialNumber;
  443. break;
  444. default:
  445. stringIndex = -1;
  446. break;
  447. }
  448. }
  449. if (stringIndex == -1){
  450. ntStatus = STATUS_INVALID_PARAMETER;
  451. }
  452. else {
  453. // BUGBUG FINISH
  454. ntStatus = STATUS_UNSUCCESSFUL;
  455. }
  456. }
  457. else {
  458. ntStatus = STATUS_INVALID_USER_BUFFER;
  459. }
  460. return ntStatus;
  461. }
  462. /*
  463. ********************************************************************************
  464. * HIDT_GetFeatureCompletion
  465. ********************************************************************************
  466. *
  467. *
  468. */
  469. NTSTATUS HIDT_GetFeatureCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  470. {
  471. PDEVICE_EXTENSION deviceExtension;
  472. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  473. HIDT_DecrementPendingRequestCount(deviceExtension);
  474. if (NT_SUCCESS(Irp->IoStatus.Status)){
  475. /*
  476. * Record the number of bytes written.
  477. */
  478. // BUGBUG FINISH Irp->IoStatus.Information =
  479. }
  480. /*
  481. * If the lower driver returned PENDING, mark our stack location as
  482. * pending also. This prevents the IRP's thread from being freed if
  483. * the client's call returns pending.
  484. */
  485. if (Irp->PendingReturned){
  486. IoMarkIrpPending(Irp);
  487. }
  488. return STATUS_SUCCESS;
  489. }
  490. /*
  491. ********************************************************************************
  492. * HIDT_GetFeature
  493. ********************************************************************************
  494. *
  495. *
  496. */
  497. NTSTATUS HIDT_GetFeature(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion)
  498. {
  499. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  500. // BUGBUG FINISH
  501. return ntStatus;
  502. }
  503. /*
  504. ********************************************************************************
  505. * HIDT_SetFeatureCompletion
  506. ********************************************************************************
  507. *
  508. *
  509. */
  510. NTSTATUS HIDT_SetFeatureCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  511. {
  512. PDEVICE_EXTENSION deviceExtension;
  513. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  514. HIDT_DecrementPendingRequestCount(deviceExtension);
  515. if (NT_SUCCESS(Irp->IoStatus.Status)){
  516. /*
  517. * Record the number of bytes written.
  518. */
  519. // BUGBUG FINISH Irp->IoStatus.Information =
  520. }
  521. /*
  522. * If the lower driver returned PENDING, mark our stack location as
  523. * pending also. This prevents the IRP's thread from being freed if
  524. * the client's call returns pending.
  525. */
  526. if (Irp->PendingReturned){
  527. IoMarkIrpPending(Irp);
  528. }
  529. return STATUS_SUCCESS;
  530. }
  531. /*
  532. ********************************************************************************
  533. * HIDT_SetFeature
  534. ********************************************************************************
  535. *
  536. *
  537. */
  538. NTSTATUS HIDT_SetFeature(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion)
  539. {
  540. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  541. // BUGBUG FINISH
  542. return ntStatus;
  543. }