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.

1565 lines
44 KiB

  1. #include <ntddk.h>
  2. #include <windef.h>
  3. #include <mmsystem.h>
  4. #include <mmddk.h>
  5. #include <ntddjoy.h>
  6. #define ANAJOYST_VERSION 10
  7. // Device extension data
  8. typedef struct {
  9. // JOYSTICKID0 or JOYDSTICKID1
  10. DWORD DeviceNumber;
  11. // Number of axes supported and configured for this device.
  12. DWORD NumberOfAxes;
  13. // TRUE if there are two joysticks installed
  14. BOOL bTwoSticks;
  15. // The I/O address of the device, usually 0x201
  16. PUCHAR DeviceAddress;
  17. // A Spinlock is used to synchronize access to this device. This is
  18. // a pointer to the actual spinlock data area
  19. PKSPIN_LOCK SpinLock;
  20. // Actual SpinLock data area
  21. KSPIN_LOCK SpinLockData;
  22. } JOY_EXTENSION, *PJOY_EXTENSION;
  23. // Debugging macros
  24. #ifdef DEBUG
  25. #define ENABLE_DEBUG_TRACE
  26. #endif
  27. #ifdef ENABLE_DEBUG_TRACE
  28. #define DebugTrace(_x_) \
  29. DbgPrint("Joystick: "); \
  30. KdPrint(_x_); \
  31. DbgPrint("\n");
  32. #else
  33. #define DebugTrace(_x_)
  34. #endif
  35. // Global values (mostly timing related)
  36. JOY_STATISTICS JoyStatistics; // Debugging and performance testing
  37. // The high resolution system clock (from KeQueryPerformanceCounter) is updated at this frequency
  38. DWORD Frequency;
  39. // min number of KeQueryPerformanceCounter ticks between polls
  40. // Used to prevent too-frequent polling of joystick
  41. DWORD nMinTicksBetweenPolls;
  42. // Last good packet
  43. BOOL bLastGoodPacket; // TRUE if there is a last good packet
  44. JOY_DD_INPUT_DATA jjLastGoodPacket; // data in last good packet
  45. // time at which the joystick was last polled
  46. LARGE_INTEGER liLastPoll; // set whenever the joystick's polled
  47. // The maximum duration of a polling cycle (expressed in ticks).
  48. DWORD MaxTimeoutInTicks;
  49. // The maximum duration of a polling cycle for use in quiesce wait
  50. LONG nQuiesceLoop;
  51. // The minimum resolution of a polling cycle. This is used to detect
  52. // if we've been pre-empted or interrupted during a polling loop. If
  53. // we have been, we can retry the operation.
  54. DWORD ThresholdInTicks;
  55. // End of Global Values
  56. // Routine Prototypes
  57. NTSTATUS
  58. DriverEntry(
  59. IN PDRIVER_OBJECT pDriverObject,
  60. IN PUNICODE_STRING RegistryPathName
  61. );
  62. NTSTATUS
  63. AnajoystCreateDevice(
  64. PDRIVER_OBJECT pDriverObject,
  65. PWSTR DeviceNameBase,
  66. DWORD DeviceNumber,
  67. DWORD ExtensionSize,
  68. BOOLEAN Exclusive,
  69. DWORD DeviceType,
  70. PDEVICE_OBJECT *DeviceObject
  71. );
  72. NTSTATUS
  73. AnajoystDispatch(
  74. IN PDEVICE_OBJECT pDO,
  75. IN PIRP pIrp
  76. );
  77. NTSTATUS
  78. AnajoystReadRegistryParameterDWORD(
  79. PUNICODE_STRING RegistryPathName,
  80. PWSTR ParameterName,
  81. PDWORD ParameterValue
  82. );
  83. NTSTATUS
  84. AnajoystMapDevice(
  85. DWORD PortBase,
  86. DWORD NumberOfPorts,
  87. PJOY_EXTENSION pJoyExtension
  88. );
  89. VOID
  90. AnajoystUnload(
  91. PDRIVER_OBJECT pDriverObject
  92. );
  93. BOOL
  94. AnajoystQuiesce(
  95. PUCHAR JoyPort,
  96. UCHAR Mask
  97. );
  98. DWORD
  99. TimeInMicroSeconds(
  100. DWORD dwTime
  101. );
  102. DWORD
  103. TimeInTicks(
  104. DWORD dwTimeInMicroSeconds
  105. );
  106. int
  107. lstrnicmpW(
  108. LPWSTR pszA,
  109. LPWSTR pszB,
  110. size_t cch
  111. );
  112. void
  113. AnajoystGetConfig(
  114. LPJOYREGHWCONFIG pConfig,
  115. PJOY_EXTENSION pJoyExtension
  116. );
  117. NTSTATUS
  118. AnajoystAnalogPoll(
  119. PDEVICE_OBJECT pDO,
  120. PIRP pIrp
  121. );
  122. NTSTATUS
  123. AnajoystPoll(
  124. IN PDEVICE_OBJECT pDO,
  125. IN PIRP pIrp
  126. );
  127. NTSTATUS
  128. DriverEntry(
  129. IN PDRIVER_OBJECT pDriverObject,
  130. IN PUNICODE_STRING RegistryPathName
  131. )
  132. /*++
  133. Routine Description:
  134. This routine is called at system initialization time to initialize
  135. this driver.
  136. Arguments:
  137. DriverObject - Supplies the driver object.
  138. RegistryPath - Supplies the registry path for this driver.
  139. Return Value:
  140. STATUS_SUCCESS
  141. STATUS_DEVICE_CONFIGURATION_ERROR - Wrong number of axi in the registry
  142. or error status from NT itself
  143. --*/
  144. {
  145. NTSTATUS Status;
  146. PDEVICE_OBJECT pJoyDevice0;
  147. PDEVICE_OBJECT pJoyDevice1;
  148. DWORD NumberOfAxes;
  149. BOOL bTwoSticks;
  150. DWORD DeviceAddress;
  151. PJOY_EXTENSION pext0, pext1;
  152. //DbgBreakPoint();
  153. JoyStatistics.Version = ANAJOYST_VERSION;
  154. DebugTrace(("Anajoyst %d", JoyStatistics.Version));
  155. // Read registry parameters. These parameters are set up by the driver
  156. // installation program and can be modified by the control panel applets.
  157. // Number of axes
  158. Status = AnajoystReadRegistryParameterDWORD(
  159. RegistryPathName,
  160. JOY_DD_NAXES_U,
  161. &NumberOfAxes
  162. );
  163. DebugTrace(("Number of axes returned from registry: %d", NumberOfAxes));
  164. if (!NT_SUCCESS(Status))
  165. {
  166. AnajoystUnload(pDriverObject);
  167. return Status;
  168. }
  169. if (( NumberOfAxes < 2) || (NumberOfAxes > 4))
  170. {
  171. AnajoystUnload(pDriverObject);
  172. Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  173. return Status;
  174. }
  175. // Device address (usually 0x201)
  176. Status = AnajoystReadRegistryParameterDWORD(
  177. RegistryPathName,
  178. JOY_DD_DEVICE_ADDRESS_U,
  179. &DeviceAddress
  180. );
  181. if (NT_SUCCESS(Status))
  182. {
  183. DebugTrace(("Registry specified device address of 0x%x", DeviceAddress));
  184. }
  185. else
  186. {
  187. DebugTrace(("Using default device address of 0x%x", JOY_IO_PORT_ADDRESS));
  188. DeviceAddress = JOY_IO_PORT_ADDRESS;
  189. }
  190. // Number of joysticks
  191. Status = AnajoystReadRegistryParameterDWORD(
  192. RegistryPathName,
  193. JOY_DD_TWOSTICKS_U,
  194. &bTwoSticks
  195. );
  196. bTwoSticks = !!bTwoSticks;
  197. DebugTrace(("bTwoSticks: %ld", bTwoSticks));
  198. if (!NT_SUCCESS(Status))
  199. {
  200. AnajoystUnload(pDriverObject);
  201. return Status;
  202. }
  203. // if two joysticks are installed, only support two axes per joystick
  204. if (bTwoSticks)
  205. {
  206. NumberOfAxes = 2;
  207. }
  208. // Calculate time thresholds for analog device
  209. {
  210. //DWORD Remainder;
  211. LARGE_INTEGER LargeFrequency;
  212. //DWORD ulStart, ulTemp, ulEnd;
  213. //DWORD dwTicks, dwTimems;
  214. //int i;
  215. //BYTE byteJoy, byteTmp;
  216. // Get the system timer resolution expressed in Hertz.
  217. KeQueryPerformanceCounter(&LargeFrequency);
  218. Frequency = LargeFrequency.LowPart;
  219. DebugTrace(("Frequency: %u", Frequency));
  220. //ThresholdInTicks = RtlExtendedLargeIntegerDivide(
  221. // RtlExtendedIntegerMultiply(
  222. // LargeFrequency,
  223. // ANALOG_POLL_RESOLUTION
  224. // ),
  225. // 1000000L,
  226. // &Remainder).LowPart;
  227. //DebugTrace(("ThresholdInTicks: %u", ThresholdInTicks));
  228. ThresholdInTicks = (DWORD) (((__int64)Frequency * (__int64)ANALOG_POLL_RESOLUTION) / (__int64)1000000L);
  229. DebugTrace(("ThresholdInTicks: %u", ThresholdInTicks));
  230. //MaxTimeoutInTicks = RtlExtendedLargeIntegerDivide(
  231. // RtlExtendedIntegerMultiply(
  232. // LargeFrequency,
  233. // ANALOG_POLL_TIMEOUT
  234. // ),
  235. // 1000000L,
  236. // &Remainder).LowPart;
  237. //DebugTrace(("MaxTimeoutInTicks: %u", MaxTimeoutInTicks));
  238. MaxTimeoutInTicks = (DWORD) (((__int64)Frequency * (__int64)ANALOG_POLL_TIMEOUT) / (__int64)1000000L);
  239. DebugTrace(("MaxTimeoutInTicks: %u", MaxTimeoutInTicks));
  240. // need latency for KeQueryPerformanceCounter. While we're at it, let's
  241. // get min time for delay and stall execution
  242. //ulStart = KeQueryPerformanceCounter(NULL).LowPart;
  243. //for (i = 0; i < 1000; i++) {
  244. // ulTemp = KeQueryPerformanceCounter(NULL).LowPart;
  245. //}
  246. //dwTicks = ulTemp - ulStart;
  247. //dwTimems = TimeInMicroSeconds (dwTicks);
  248. }
  249. // Create the device
  250. Status = AnajoystCreateDevice(
  251. pDriverObject,
  252. JOY_DD_DEVICE_NAME_U, // device driver
  253. 0,
  254. sizeof(JOY_EXTENSION),
  255. FALSE, // exclusive access
  256. FILE_DEVICE_UNKNOWN,
  257. &pJoyDevice0);
  258. if (!NT_SUCCESS(Status))
  259. {
  260. DebugTrace(("SwndrCreateDevice returned %x", Status));
  261. AnajoystUnload(pDriverObject);
  262. return Status;
  263. }
  264. //((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->DeviceNumber = JOYSTICKID1;
  265. //((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->NumberOfAxes = NumberOfAxes;
  266. //((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->DeviceAddress = (PUCHAR) 0;
  267. pext0 = (PJOY_EXTENSION)pJoyDevice0->DeviceExtension;
  268. pext0->DeviceNumber = JOYSTICKID1;
  269. pext0->NumberOfAxes = NumberOfAxes;
  270. pext0->bTwoSticks = bTwoSticks;
  271. pext0->DeviceAddress = (PUCHAR) 0;
  272. // Initialize the spinlock used to synchronize access to this device
  273. // KeInitializeSpinLock(&((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->SpinLockData);
  274. // ((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->SpinLock =
  275. // &((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->SpinLockData;
  276. KeInitializeSpinLock(&pext0->SpinLockData);
  277. pext0->SpinLock = &pext0->SpinLockData;
  278. // Get the device address into the device extension
  279. Status = AnajoystMapDevice(
  280. DeviceAddress,
  281. 1,
  282. pext0);
  283. // (PJOY_EXTENSION)pJoyDevice0->DeviceExtension);
  284. // Calibrate nQuiesceLoop for spinning in read_port loops to timeout after 10ms
  285. {
  286. int i;
  287. PBYTE JoyPort;
  288. DWORD ulStart, ulEnd;
  289. BYTE byteJoy;
  290. int LoopTimeInMicroSeconds;
  291. JoyPort = ((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->DeviceAddress;
  292. ulStart = KeQueryPerformanceCounter(NULL).LowPart;
  293. for (i = 0; i < 1000; i++) {
  294. byteJoy = READ_PORT_UCHAR(JoyPort);
  295. if ((byteJoy & X_AXIS_BITMASK)) {
  296. ;
  297. }
  298. }
  299. ulEnd = KeQueryPerformanceCounter(NULL).LowPart;
  300. LoopTimeInMicroSeconds = TimeInMicroSeconds (ulEnd - ulStart);
  301. nQuiesceLoop = (DWORD) (((__int64)1000L * (__int64)ANALOG_POLL_TIMEOUT) / (__int64)LoopTimeInMicroSeconds);
  302. DebugTrace(("READ_PORT_UCHAR loop, 1000 interations: %u ticks", ulEnd - ulStart));
  303. DebugTrace(("nQuiesceLoop: %u", nQuiesceLoop));
  304. }
  305. // if 2 joysticks are installed, support a second device
  306. if (bTwoSticks)
  307. {
  308. Status = AnajoystCreateDevice(
  309. pDriverObject,
  310. JOY_DD_DEVICE_NAME_U,
  311. 1, // device number
  312. sizeof (JOY_EXTENSION),
  313. FALSE, // exclusive access
  314. FILE_DEVICE_UNKNOWN,
  315. &pJoyDevice1);
  316. if (!NT_SUCCESS(Status))
  317. {
  318. DebugTrace(("Create device for second device returned %x", Status));
  319. AnajoystUnload(pDriverObject);
  320. return Status;
  321. }
  322. // // Both devices share the same I/O address so just copy it from pJoyDevice0
  323. // ((PJOY_EXTENSION)pJoyDevice1->DeviceExtension)->DeviceAddress =
  324. // ((PJOY_EXTENSION)pJoyDevice0->DeviceExtension)->DeviceAddress;
  325. // ((PJOY_EXTENSION)pJoyDevice1->DeviceExtension)->DeviceNumber = JOYSTICKID2;
  326. // ((PJOY_EXTENSION)pJoyDevice1->DeviceExtension)->NumberOfAxes = NumberOfAxes;
  327. //
  328. // // Initialize the spinlock used to synchronize access to this device
  329. // KeInitializeSpinLock(&((PJOY_EXTENSION)pJoyDevice1->DeviceExtension)->SpinLockData);
  330. // ((PJOY_EXTENSION)pJoyDevice1->DeviceExtension)->SpinLock =
  331. // &((PJOY_EXTENSION)pJoyDevice1->DeviceExtension)->SpinLockData;
  332. pext1 = (PJOY_EXTENSION)pJoyDevice1->DeviceExtension;
  333. // Both devices share the same I/O address so just copy it from pJoyDevice0
  334. pext1->DeviceAddress = pext0->DeviceAddress;
  335. pext1->DeviceNumber = JOYSTICKID2;
  336. pext1->NumberOfAxes = NumberOfAxes;
  337. pext1->bTwoSticks = bTwoSticks; // (will be TRUE)
  338. // Initialize the spinlock used to synchronize access to this device
  339. KeInitializeSpinLock(&pext1->SpinLockData);
  340. pext1->SpinLock = &pext1->SpinLockData;
  341. }
  342. // Define entry points
  343. pDriverObject->DriverUnload = AnajoystUnload;
  344. pDriverObject->MajorFunction[IRP_MJ_CREATE] = AnajoystDispatch;
  345. pDriverObject->MajorFunction[IRP_MJ_CLOSE] = AnajoystDispatch;
  346. pDriverObject->MajorFunction[IRP_MJ_READ] = AnajoystDispatch;
  347. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AnajoystDispatch;
  348. // Zero statistics, set misc globals
  349. JoyStatistics.Polls = 0;
  350. JoyStatistics.Timeouts = 0;
  351. JoyStatistics.PolledTooSoon = 0;
  352. JoyStatistics.Redo = 0;
  353. // allow max of 100 polls/s (min time between polls 10ms), which reduces time spinning in the NT kernel
  354. nMinTicksBetweenPolls = TimeInTicks (10000);
  355. bLastGoodPacket = FALSE;
  356. liLastPoll = KeQueryPerformanceCounter (NULL);
  357. return STATUS_SUCCESS;
  358. }
  359. NTSTATUS
  360. AnajoystCreateDevice(
  361. PDRIVER_OBJECT pDriverObject,
  362. PWSTR DeviceNameBase,
  363. DWORD DeviceNumber,
  364. DWORD ExtensionSize,
  365. BOOLEAN Exclusive,
  366. DWORD DeviceType,
  367. PDEVICE_OBJECT *DeviceObject
  368. )
  369. /*++
  370. Routine Description:
  371. This routine is called at driver initialization time to create
  372. the device. The device is created to use Buffered IO.
  373. Arguments:
  374. pDriverObject - Supplies the driver object.
  375. DeviceNameBase - The base name of the device to which a number is appended
  376. DeviceNumber - A number which will be appended to the device name
  377. ExtensionSize - Size of the device extension area
  378. Exclusive - True if exclusive access should be enforced
  379. DeviceType - NT Device type this device is modeled after
  380. DeviceObject - pointer to the device object
  381. Return Value:
  382. STATUS_SUCCESS
  383. or error status from NT itself
  384. --*/
  385. {
  386. WCHAR DeviceName[100];
  387. WCHAR UnicodeDosDeviceName[200];
  388. UNICODE_STRING UnicodeDeviceName;
  389. NTSTATUS Status;
  390. int Length;
  391. (void) wcscpy(DeviceName, DeviceNameBase);
  392. Length = wcslen(DeviceName);
  393. DeviceName[Length + 1] = L'\0';
  394. DeviceName[Length] = (USHORT) (L'0' + DeviceNumber);
  395. (void) RtlInitUnicodeString(&UnicodeDeviceName, DeviceName);
  396. Status = IoCreateDevice(
  397. pDriverObject,
  398. ExtensionSize,
  399. &UnicodeDeviceName,
  400. DeviceType,
  401. 0,
  402. (BOOLEAN) Exclusive,
  403. DeviceObject
  404. );
  405. if (!NT_SUCCESS(Status))
  406. {
  407. return Status;
  408. }
  409. // very crude hack here, do the right thing sometime
  410. if (DeviceNumber == 0) {
  411. RtlInitUnicodeString((PUNICODE_STRING) &UnicodeDosDeviceName, L"\\DosDevices\\Joy1");
  412. }
  413. else {
  414. RtlInitUnicodeString((PUNICODE_STRING) &UnicodeDosDeviceName, L"\\DosDevices\\Joy2");
  415. }
  416. Status = IoCreateSymbolicLink(
  417. (PUNICODE_STRING) &UnicodeDosDeviceName,
  418. (PUNICODE_STRING) &UnicodeDeviceName
  419. );
  420. if (!NT_SUCCESS(Status))
  421. {
  422. return Status;
  423. }
  424. // Set the flag signifying that we will do buffered I/O. This causes NT
  425. // to allocate a buffer on a ReadFile operation which will then be copied
  426. // back to the calling application by the I/O subsystem
  427. (*DeviceObject)->Flags |= DO_BUFFERED_IO;
  428. return Status;
  429. }
  430. NTSTATUS
  431. AnajoystReadRegistryParameterDWORD(
  432. PUNICODE_STRING RegistryPathName,
  433. PWSTR ParameterName,
  434. PDWORD ParameterValue
  435. )
  436. /*++
  437. Routine Description:
  438. This routine reads registry values for the driver configuration
  439. Arguments:
  440. RegistryPathName - Registry path containing the desired parameters
  441. ParameterName - The name of the parameter
  442. ParameterValue - Variable to receive the parameter value
  443. Return Value:
  444. STATUS_SUCCESS --
  445. STATUS_NO_MORE_ENTRIES -- Couldn't find any entries
  446. STATUS_INSUFFICIENT_RESOURCES -- Couldn't allocate paged pool
  447. STATUS_DEVICE_CONFIGURATION_ERROR -- Returned value wasn't a DWORD
  448. or error status from NT itself
  449. -- */
  450. {
  451. OBJECT_ATTRIBUTES ObjectAttributes;
  452. NTSTATUS Status;
  453. HANDLE ServiceKey;
  454. HANDLE DeviceKey; // Key handle of service node
  455. UNICODE_STRING DeviceName; // Key to parameter node
  456. DWORD KeyIndex;
  457. DWORD KeyValueLength;
  458. PBYTE KeyData;
  459. BOOL ValueWasFound;
  460. PKEY_VALUE_FULL_INFORMATION KeyInfo;
  461. InitializeObjectAttributes( &ObjectAttributes,
  462. RegistryPathName,
  463. OBJ_CASE_INSENSITIVE,
  464. NULL,
  465. (PSECURITY_DESCRIPTOR) NULL);
  466. //
  467. // Open a key for our services node entry
  468. //
  469. Status = ZwOpenKey( &ServiceKey,
  470. KEY_READ | KEY_WRITE,
  471. &ObjectAttributes);
  472. if (!NT_SUCCESS(Status))
  473. {
  474. return Status;
  475. }
  476. //
  477. // Open the key to our device subkey
  478. //
  479. RtlInitUnicodeString(&DeviceName, L"Parameters");
  480. InitializeObjectAttributes( &ObjectAttributes,
  481. &DeviceName,
  482. OBJ_CASE_INSENSITIVE,
  483. ServiceKey,
  484. (PSECURITY_DESCRIPTOR) NULL);
  485. Status = ZwOpenKey (&DeviceKey,
  486. KEY_READ | KEY_WRITE,
  487. &ObjectAttributes);
  488. ZwClose(ServiceKey);
  489. if (!NT_SUCCESS(Status))
  490. {
  491. return Status;
  492. }
  493. //
  494. // Loop reading our key values
  495. //
  496. // TODO exit loop when value is found?
  497. ValueWasFound = FALSE;
  498. for (KeyIndex = 0; ; KeyIndex++)
  499. {
  500. KeyValueLength = 0;
  501. //
  502. // find out how much data we will get
  503. //
  504. Status = ZwEnumerateValueKey(
  505. DeviceKey,
  506. KeyIndex,
  507. KeyValueFullInformation,
  508. NULL,
  509. 0,
  510. &KeyValueLength);
  511. if (STATUS_NO_MORE_ENTRIES == Status)
  512. {
  513. break;
  514. }
  515. if (0 == KeyValueLength)
  516. {
  517. return Status;
  518. }
  519. //
  520. // Read the data
  521. //
  522. KeyData = ExAllocatePool (PagedPool, KeyValueLength);
  523. if (NULL == KeyData)
  524. {
  525. return STATUS_INSUFFICIENT_RESOURCES;
  526. }
  527. Status = ZwEnumerateValueKey(
  528. DeviceKey,
  529. KeyIndex,
  530. KeyValueFullInformation,
  531. KeyData,
  532. KeyValueLength,
  533. &KeyValueLength);
  534. if (!NT_SUCCESS(Status))
  535. {
  536. ExFreePool(KeyData);
  537. return Status;
  538. }
  539. KeyInfo = (PKEY_VALUE_FULL_INFORMATION) KeyData;
  540. if (0 == lstrnicmpW(KeyInfo->Name,
  541. ParameterName,
  542. KeyInfo->NameLength / sizeof(WCHAR)))
  543. {
  544. // check its a DWORD
  545. if (REG_DWORD != KeyInfo->Type)
  546. {
  547. ExFreePool(KeyData);
  548. return STATUS_DEVICE_CONFIGURATION_ERROR;
  549. }
  550. ValueWasFound = TRUE;
  551. *ParameterValue = *(PDWORD) (KeyData + KeyInfo->DataOffset);
  552. }
  553. ExFreePool(KeyData);
  554. }
  555. return (ValueWasFound) ? STATUS_SUCCESS : STATUS_DEVICE_CONFIGURATION_ERROR;
  556. }
  557. NTSTATUS
  558. AnajoystDispatch(
  559. IN PDEVICE_OBJECT pDO,
  560. IN PIRP pIrp
  561. )
  562. /*++
  563. Routine Description:
  564. Driver dispatch routine. Processes IRPs based on IRP MajorFunction
  565. Arguments:
  566. pDO -- pointer to the device object
  567. pIrp -- pointer to the IRP to process
  568. Return Value:
  569. Returns the value of the IRP IoStatus.Status
  570. --*/
  571. {
  572. PIO_STACK_LOCATION pIrpStack;
  573. KIRQL OldIrql;
  574. NTSTATUS Status;
  575. DWORD dwRetries = 0;
  576. //DbgBreakPoint();
  577. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  578. Status = STATUS_SUCCESS;
  579. pIrp->IoStatus.Status = Status;
  580. pIrp->IoStatus.Information = 0;
  581. switch (pIrpStack->MajorFunction)
  582. {
  583. case IRP_MJ_CREATE:
  584. //
  585. // perform synchronous I/O
  586. //
  587. //pIrpStack->FileObject->Flags |= FO_SYNCHRONOUS_IO;
  588. //NB This is bad code -- we are simply one thread wandering off through the computer -- we should be queuing up a DPC,
  589. //returning status_pending to the calling program, then finishing the job when the dpc goes. This is possible given
  590. //the analog game port technology.
  591. // don't slam it into digital mode
  592. //Status = AnajoystReset (((PJOY_EXTENSION)pDO->DeviceExtension)->DeviceAddress);
  593. //((PJOY_EXTENSION)pDO->DeviceExtension)->CurrentDeviceMode = NULL;
  594. // KeDelayExecutionThread( KernelMode, FALSE, &LI10ms); //unnecessary since AnajoystReset has a delay in it?
  595. pIrp->IoStatus.Status = Status;
  596. break;
  597. case IRP_MJ_CLOSE:
  598. break;
  599. case IRP_MJ_READ:
  600. //
  601. // Find out which device we are and read, but first make sure
  602. // there is enough room
  603. //
  604. DebugTrace(("IRP_MJ_READ"));
  605. //DbgBreakPoint();
  606. if (pIrpStack->Parameters.Read.Length < sizeof(JOY_DD_INPUT_DATA))
  607. {
  608. Status = STATUS_BUFFER_TOO_SMALL;
  609. pIrp->IoStatus.Status = Status;
  610. break;
  611. }
  612. //
  613. // Serialize and get the current device values
  614. //
  615. KeAcquireSpinLock(((PJOY_EXTENSION) pDO->DeviceExtension)->SpinLock,
  616. & OldIrql);
  617. Status = AnajoystPoll(pDO, pIrp);
  618. //
  619. // release the spinlock
  620. //
  621. KeReleaseSpinLock(((PJOY_EXTENSION)pDO->DeviceExtension)->SpinLock,
  622. OldIrql);
  623. pIrp->IoStatus.Status = Status;
  624. pIrp->IoStatus.Information = sizeof (JOY_DD_INPUT_DATA);
  625. break;
  626. case IRP_MJ_DEVICE_CONTROL:
  627. switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
  628. {
  629. case IOCTL_JOY_GET_STATISTICS:
  630. // report statistics
  631. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->Version = JoyStatistics.Version;
  632. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->Polls = JoyStatistics.Polls;
  633. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->Timeouts = JoyStatistics.Timeouts;
  634. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->PolledTooSoon = JoyStatistics.PolledTooSoon;
  635. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->Redo = JoyStatistics.Redo;
  636. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->nQuiesceLoop = nQuiesceLoop;
  637. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->Frequency = Frequency;
  638. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->NumberOfAxes = ((PJOY_EXTENSION)pDO->DeviceExtension)->NumberOfAxes;
  639. ((PJOY_STATISTICS)pIrp->AssociatedIrp.SystemBuffer)->bTwoSticks = ((PJOY_EXTENSION)pDO->DeviceExtension)->bTwoSticks;
  640. Status = STATUS_SUCCESS;
  641. pIrp->IoStatus.Status = Status;
  642. pIrp->IoStatus.Information = sizeof(JOY_STATISTICS);
  643. // reset statistics
  644. JoyStatistics.Polls = 0;
  645. JoyStatistics.Timeouts = 0;
  646. JoyStatistics.PolledTooSoon = 0;
  647. JoyStatistics.Redo = 0;
  648. break;
  649. case IOCTL_JOY_GET_JOYREGHWCONFIG:
  650. AnajoystGetConfig (
  651. (LPJOYREGHWCONFIG)(pIrp->AssociatedIrp.SystemBuffer),
  652. ((PJOY_EXTENSION)pDO->DeviceExtension)
  653. );
  654. pIrp->IoStatus.Information = sizeof(JOYREGHWCONFIG);
  655. break;
  656. default:
  657. DebugTrace(("Unknown IoControlCode"));
  658. break;
  659. } // end switch on IOCTL code
  660. break;
  661. default:
  662. DebugTrace(("Unknown IRP Major Function %d", pIrpStack->MajorFunction));
  663. } // end switch on IRP_MAJOR_XXXX
  664. // pIrp->IoStatus.Status must be set to Status by this point.
  665. // pIrp->IoStatus.Information must be set to the correct size by this point.
  666. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  667. return Status;
  668. }
  669. VOID
  670. AnajoystUnload(
  671. PDRIVER_OBJECT pDriverObject
  672. )
  673. /*++
  674. Routine Description:
  675. Driver unload routine. Deletes the device objects
  676. Arguments:
  677. pDriverObject -- pointer to the driver object whose devices we
  678. are about to delete.
  679. Return Value:
  680. Returns Nothing
  681. --*/
  682. {
  683. DWORD DeviceNumber;
  684. WCHAR UnicodeDosDeviceName[200];
  685. //
  686. // Delete all of our devices
  687. //
  688. while (pDriverObject->DeviceObject)
  689. {
  690. DeviceNumber =
  691. ((PJOY_EXTENSION)pDriverObject->DeviceObject->DeviceExtension)->
  692. DeviceNumber;
  693. //
  694. // withdraw claims on hardware by reporting no resource utilization
  695. //
  696. if (pDriverObject->DeviceObject)
  697. {
  698. if (DeviceNumber == 0)
  699. {
  700. // This isn't really necessary since we never reported the usage in the first place.
  701. // There's some unused code in the original driver that may have once reported usage,
  702. // but it was never called in the version I received. But this doesn't seem to hurt,
  703. // and "if it ain't broke, don't fix it," at least two weeks before RC1 target.
  704. DebugTrace(("ReportNull place"));
  705. //AnajoystReportNullResourceUsage(pDriverObject->DeviceObject);
  706. }
  707. }
  708. if (DeviceNumber == 0) {
  709. RtlInitUnicodeString((PUNICODE_STRING) &UnicodeDosDeviceName, L"\\DosDevices\\Joy1");
  710. }
  711. else {
  712. RtlInitUnicodeString((PUNICODE_STRING) &UnicodeDosDeviceName, L"\\DosDevices\\Joy2");
  713. }
  714. IoDeleteSymbolicLink((PUNICODE_STRING) &UnicodeDosDeviceName);
  715. DebugTrace(("Freeing device %d", DeviceNumber));
  716. IoDeleteDevice(pDriverObject->DeviceObject);
  717. }
  718. }
  719. NTSTATUS
  720. AnajoystPoll(
  721. IN PDEVICE_OBJECT pDO,
  722. IN PIRP pIrp
  723. )
  724. /*++
  725. Routine Description:
  726. Polls the device for position and button information. The polling method
  727. (analog, digital, enhanced) is selected by the CurrentDeviceMode variable
  728. in the device extension.
  729. Only enhanced digital allowed. If other modes are necessary, cut and paste
  730. (and test!) the code from file analog3p.c
  731. Arguments:
  732. pDO -- pointer to the device object
  733. pIrp -- pointer to the IRP to process
  734. if successful, data is put into the pIrp
  735. Return Value:
  736. STATUS_SUCCESS -- if the poll succeeded,
  737. STATUS_TIMEOUT -- if the poll failed
  738. --*/
  739. {
  740. NTSTATUS Status;
  741. PJOY_DD_INPUT_DATA pInput;
  742. pInput = (PJOY_DD_INPUT_DATA)pIrp->AssociatedIrp.SystemBuffer;
  743. Status = STATUS_TIMEOUT;
  744. pIrp->IoStatus.Status = Status;
  745. if (pInput != NULL)
  746. {
  747. pInput->Unplugged = TRUE; // until proven otherwise
  748. }
  749. if (KeQueryPerformanceCounter(NULL).QuadPart < liLastPoll.QuadPart + nMinTicksBetweenPolls) {
  750. // Don't poll too frequently, instead return last good packet
  751. JoyStatistics.PolledTooSoon++;
  752. if (bLastGoodPacket) {
  753. RtlCopyMemory (pInput, &jjLastGoodPacket, sizeof (JOY_DD_INPUT_DATA));
  754. Status = STATUS_SUCCESS;
  755. }
  756. else {
  757. // no last packet, too soon to poll, nothing we can do
  758. Status = STATUS_TIMEOUT;
  759. }
  760. }
  761. else {
  762. // do the analog poll
  763. liLastPoll = KeQueryPerformanceCounter (NULL);
  764. ++JoyStatistics.Polls;
  765. Status = AnajoystAnalogPoll(pDO, pIrp);
  766. if (Status != STATUS_SUCCESS) ++JoyStatistics.Timeouts;
  767. }
  768. pIrp->IoStatus.Status = Status;
  769. return Status;
  770. }
  771. BOOL
  772. AnajoystQuiesce(
  773. PUCHAR JoyPort,
  774. UCHAR Mask
  775. )
  776. /*++
  777. Routine Description:
  778. This routine attempts to insure that the joystick is not still active as a
  779. result of an earlier operation. This is accomplished by repeatedly reading
  780. the device and checking that no bits are set in the supplied mask. The idea
  781. is to check that none of the analog bits (resistive bits) are in use.
  782. Arguments:
  783. JoyPort - the address of the port (as returned from hal)
  784. Mask - the mask specifying which analog bits should be checked.
  785. Return Value:
  786. TRUE Quiesce operation succeeded
  787. FALSE No quiesce within a reasonable period. This generally means
  788. that the device is unplugged.
  789. NB This is not a reliable test for "joystick unplugged"
  790. This routine can return TRUE under some circumstances
  791. even when there is no joystick
  792. --*/
  793. {
  794. int i;
  795. UCHAR PortVal;
  796. // Wait for port to quiesce
  797. for (i = 0; i < nQuiesceLoop; i++) {
  798. PortVal = READ_PORT_UCHAR(JoyPort);
  799. if ((PortVal & Mask) == 0) return TRUE;
  800. }
  801. // If poll timed out we have an uplugged joystick or something's wrong
  802. DebugTrace(("AnajoystQuiesce failed!"));
  803. return FALSE;
  804. }
  805. NTSTATUS
  806. AnajoystMapDevice(
  807. DWORD PortBase,
  808. DWORD NumberOfPorts,
  809. PJOY_EXTENSION pJoyExtension
  810. )
  811. {
  812. DWORD MemType;
  813. PHYSICAL_ADDRESS PortAddress;
  814. PHYSICAL_ADDRESS MappedAddress;
  815. MemType = 1; // IO space
  816. PortAddress.LowPart = PortBase;
  817. PortAddress.HighPart = 0;
  818. HalTranslateBusAddress(
  819. Isa,
  820. 0,
  821. PortAddress,
  822. &MemType,
  823. &MappedAddress);
  824. if (MemType == 0) {
  825. //
  826. // Map memory type IO space into our address space
  827. //
  828. pJoyExtension->DeviceAddress = (PUCHAR) MmMapIoSpace(MappedAddress,
  829. NumberOfPorts,
  830. FALSE);
  831. }
  832. else
  833. {
  834. pJoyExtension->DeviceAddress = (PUCHAR) MappedAddress.LowPart;
  835. }
  836. return STATUS_SUCCESS;
  837. }
  838. DWORD
  839. TimeInMicroSeconds(
  840. DWORD dwTime
  841. )
  842. {
  843. DWORD Remainder;
  844. return RtlExtendedLargeIntegerDivide(
  845. RtlEnlargedUnsignedMultiply( dwTime, 1000000L),
  846. Frequency,
  847. &Remainder
  848. ).LowPart;
  849. }
  850. DWORD
  851. TimeInTicks(
  852. DWORD dwTimeInMicroSeconds
  853. )
  854. {
  855. return (DWORD) (((__int64)dwTimeInMicroSeconds * (__int64)Frequency) / (__int64) 1000000L);
  856. }
  857. int lstrnicmpW (LPWSTR pszA, LPWSTR pszB, size_t cch)
  858. {
  859. if (!pszA || !pszB)
  860. {
  861. return (!pszB) - (!pszA); // A,!B:1, !A,B:-1, !A,!B:0
  862. }
  863. // while (cch--)
  864. for ( ; cch > 0; cch--, pszA++, pszB++) // previous version did not increment string pointers [SteveZ]
  865. {
  866. if (!*pszA || !*pszB)
  867. {
  868. return (!*pszB) - (!*pszA); // A,!B:1, !A,B:-1, !A,!B:0
  869. }
  870. if (*pszA != *pszB)
  871. {
  872. return (int)(*pszA) - (int)(*pszB); // -1:A<B, 0:A==B, 1:A>B
  873. }
  874. }
  875. return 0; // no differences before told to stop comparing, so A==B
  876. }
  877. void
  878. AnajoystGetConfig (
  879. LPJOYREGHWCONFIG pConfig,
  880. PJOY_EXTENSION pJoyExtension
  881. )
  882. /*++
  883. Routine Description:
  884. This routine is called in response to the IOCTL_JOY_GET_JOYREGHWCONFIG
  885. query. It fills out a JOYREGHWCONFIG structure with relevant information
  886. about the given joystick.
  887. Arguments:
  888. pConfig - Specifies a JOYREGHWCONFIG structure, to be filled in
  889. pJoyExtension - Specifies the joystick to query
  890. Return Value:
  891. void
  892. --*/
  893. {
  894. pConfig->hwv.jrvHardware.jpMin.dwX = 20;
  895. pConfig->hwv.jrvHardware.jpMin.dwY = 20;
  896. pConfig->hwv.jrvHardware.jpMin.dwZ = 20;
  897. pConfig->hwv.jrvHardware.jpMin.dwR = 20;
  898. pConfig->hwv.jrvHardware.jpMin.dwU = 20;
  899. pConfig->hwv.jrvHardware.jpMin.dwV = 20;
  900. pConfig->hwv.jrvHardware.jpMax.dwX = 1600;
  901. pConfig->hwv.jrvHardware.jpMax.dwY = 1600;
  902. pConfig->hwv.jrvHardware.jpMax.dwZ = 1600;
  903. pConfig->hwv.jrvHardware.jpMax.dwR = 1600;
  904. pConfig->hwv.jrvHardware.jpMax.dwU = 1600;
  905. pConfig->hwv.jrvHardware.jpMax.dwV = 1600;
  906. pConfig->hwv.jrvHardware.jpCenter.dwX = 790;
  907. pConfig->hwv.jrvHardware.jpCenter.dwY = 790;
  908. pConfig->hwv.jrvHardware.jpCenter.dwZ = 790;
  909. pConfig->hwv.jrvHardware.jpCenter.dwR = 790;
  910. pConfig->hwv.jrvHardware.jpCenter.dwU = 790;
  911. pConfig->hwv.jrvHardware.jpCenter.dwV = 790;
  912. pConfig->hwv.dwCalFlags = 0;
  913. pConfig->dwReserved = 0;
  914. pConfig->dwUsageSettings = JOY_US_PRESENT;
  915. switch( ((PJOY_EXTENSION)pJoyExtension)->NumberOfAxes )
  916. {
  917. case 2:
  918. pConfig->hws.dwFlags = 0;
  919. pConfig->hws.dwNumButtons = 2;
  920. pConfig->dwType = JOY_HW_2A_2B_GENERIC;
  921. break;
  922. case 3:
  923. pConfig->hws.dwFlags = JOY_HWS_HASR;
  924. pConfig->hws.dwNumButtons = 4;
  925. pConfig->dwType = JOY_HW_CUSTOM;
  926. break;
  927. case 4:
  928. pConfig->hws.dwFlags = JOY_HWS_HASU | JOY_HWS_HASR;
  929. pConfig->hws.dwNumButtons = 4;
  930. pConfig->dwType = JOY_HW_CUSTOM;
  931. break;
  932. }
  933. }
  934. NTSTATUS
  935. AnajoystAnalogPoll(
  936. PDEVICE_OBJECT pDO,
  937. PIRP pIrp
  938. )
  939. /*++
  940. Do a good comment block here...
  941. THIS MAY HANG UP IF NO JOYSTICK ATTACHED. DON'T RELEASE THIS CODE WITH ANALOG
  942. JOYSTICK SUPPORT WITHOUT CAREFULLY CHECKING THE CODE.
  943. Routine Description:
  944. Polls the analog device for position and button information. The position
  945. information in analog devices is coveyed by the duration of a pulse width.
  946. Each axis occupies one bit position. The read operation is started by
  947. writing a value to the joystick io address. Immediately thereafter we
  948. begin examing the values returned and the elapsed time.
  949. This sort of device has a few limitations:
  950. First, button information is not latched by the device, so if a button press
  951. which occurrs in between polls will be lost. There is really no way to prevent
  952. this short of devoting the entire cpu to polling.
  953. Secondly, although we raise IRQL to DISPATCH_LEVEL, other interrupts will
  954. occur during the polling routines and this will have the effect of lengthening
  955. the pulse width (by delaying our polling loop) and thus there will be some
  956. fluctuation about the actual value. It might be possible to try another IRQL
  957. to see if this helps, but ultimately, nothing short of disabling interrupts
  958. altogether will insure success. This is too much of a price to pay. The
  959. solution is a better device.
  960. Third, when circumstances cause a poll to last too long, we abort it and
  961. retry the operation. We have to do this to place an upper bound on the
  962. time we poll, and an upper bound on the time we spend at an elevated IRQL.
  963. But in this case both the position information and
  964. the button press information is lost. Note that there is an upper bound
  965. on the poll duration, beyond which we conclude that the device is disconnected.
  966. Arguments:
  967. pDO -- pointer to the device object
  968. pIrp -- pointer to the requesing Irp
  969. Return Value:
  970. STATUS_SUCCESS -- if the poll succeeded,
  971. STATUS_TIMEOUT -- if the poll failed (timeout), or the checksum was incorrect
  972. --*/
  973. {
  974. UCHAR PortVal;
  975. PBYTE JoyPort;
  976. DWORD Id;
  977. DWORD NumberOfAxes;
  978. BOOL bTwoSticks;
  979. PJOY_DD_INPUT_DATA pInput;
  980. BOOL Redo;
  981. UCHAR Buttons;
  982. UCHAR xMask, yMask, zMask, rMask;
  983. DWORD xTime, yTime, zTime, rTime;
  984. int MaxRedos;
  985. DebugTrace(("AnajoystAnalogPoll"));
  986. pInput = (PJOY_DD_INPUT_DATA)pIrp->AssociatedIrp.SystemBuffer;
  987. // If we fail we assume it's because we're unplugged
  988. pInput->Unplugged = TRUE;
  989. // Find where our port and data area are, and related parameters
  990. JoyPort = ((PJOY_EXTENSION)pDO->DeviceExtension)->DeviceAddress;
  991. Id = ((PJOY_EXTENSION)pDO->DeviceExtension)->DeviceNumber;
  992. NumberOfAxes = ((PJOY_EXTENSION)pDO->DeviceExtension)->NumberOfAxes;
  993. bTwoSticks = ((PJOY_EXTENSION)pDO->DeviceExtension)->bTwoSticks;
  994. // Read port state
  995. PortVal = READ_PORT_UCHAR(JoyPort);
  996. Buttons = 0;
  997. // Get current button states and build bitmasks for the resistive inputs
  998. if (Id == JOYSTICKID1)
  999. {
  1000. switch (NumberOfAxes)
  1001. {
  1002. case 2:
  1003. xMask = JOYSTICK1_X_MASK;
  1004. yMask = JOYSTICK1_Y_MASK;
  1005. zMask = 0;
  1006. rMask = 0;
  1007. if (!(PortVal & JOYSTICK1_BUTTON1))
  1008. {
  1009. Buttons |= JOY_BUTTON1;
  1010. }
  1011. if (!(PortVal & JOYSTICK1_BUTTON2))
  1012. {
  1013. Buttons |= JOY_BUTTON2;
  1014. }
  1015. if (!bTwoSticks)
  1016. {
  1017. if (!(PortVal & JOYSTICK2_BUTTON1))
  1018. {
  1019. Buttons |= JOY_BUTTON3;
  1020. }
  1021. if (!(PortVal & JOYSTICK2_BUTTON2))
  1022. {
  1023. Buttons |= JOY_BUTTON4;
  1024. }
  1025. }
  1026. break;
  1027. case 3:
  1028. xMask = JOYSTICK1_X_MASK;
  1029. yMask = JOYSTICK1_Y_MASK;
  1030. zMask = 0;
  1031. rMask = JOYSTICK1_R_MASK; // this is 0x08, typically the third axis on 3axis joysticks
  1032. if (!(PortVal & JOYSTICK1_BUTTON1))
  1033. {
  1034. Buttons |= JOY_BUTTON1;
  1035. }
  1036. if (!(PortVal & JOYSTICK1_BUTTON2))
  1037. {
  1038. Buttons |= JOY_BUTTON2;
  1039. }
  1040. if (!(PortVal & JOYSTICK2_BUTTON1))
  1041. {
  1042. Buttons |= JOY_BUTTON3;
  1043. }
  1044. if (!(PortVal & JOYSTICK2_BUTTON2))
  1045. {
  1046. Buttons |= JOY_BUTTON4;
  1047. }
  1048. break;
  1049. case 4:
  1050. // Note that we read all axi because we don't know which
  1051. // axis will be used by the joystick, and we read all the
  1052. // buttons because no other joystick could use them
  1053. xMask = JOYSTICK1_X_MASK;
  1054. yMask = JOYSTICK1_Y_MASK;
  1055. zMask = JOYSTICK1_Z_MASK;
  1056. rMask = JOYSTICK1_R_MASK;
  1057. if (!(PortVal & JOYSTICK1_BUTTON1))
  1058. {
  1059. Buttons |= JOY_BUTTON1;
  1060. }
  1061. if (!(PortVal & JOYSTICK1_BUTTON2))
  1062. {
  1063. Buttons |= JOY_BUTTON2;
  1064. }
  1065. if (!(PortVal & JOYSTICK2_BUTTON1))
  1066. {
  1067. Buttons |= JOY_BUTTON3;
  1068. }
  1069. if (!(PortVal & JOYSTICK2_BUTTON2))
  1070. {
  1071. Buttons |= JOY_BUTTON4;
  1072. }
  1073. break;
  1074. default:
  1075. break;
  1076. // $TODO - report invalid number of axi
  1077. }
  1078. }
  1079. else if ((Id == JOYSTICKID2) && (bTwoSticks))
  1080. {
  1081. xMask = JOYSTICK2_X_MASK;
  1082. yMask = JOYSTICK2_Y_MASK;
  1083. zMask = 0;
  1084. rMask = 0;
  1085. if (!(PortVal & JOYSTICK2_BUTTON1))
  1086. {
  1087. Buttons |= JOY_BUTTON1;
  1088. }
  1089. if (!(PortVal & JOYSTICK2_BUTTON2))
  1090. {
  1091. Buttons |= JOY_BUTTON2;
  1092. }
  1093. }
  1094. else
  1095. {
  1096. // $TODO - report unsupported configuration
  1097. }
  1098. // Insure that the resistive inputs are currently reset before performing
  1099. // the next read. If we find one or more hot inputs, wait briefly for
  1100. // them to reset. If they don't, we assume that the joystick is unplugged
  1101. if (!AnajoystQuiesce(JoyPort, (UCHAR) (xMask | yMask | zMask | rMask)))
  1102. {
  1103. DebugTrace(("AnajoystQuiesce: failed to quiesce resistive inputs"));
  1104. return STATUS_TIMEOUT;
  1105. }
  1106. // Note that timing is EXTREMELY critical in the loop below.
  1107. // Avoid calling complicated arithmetic (eg TimeInMicroSeconds)
  1108. // or we will decrease our accuracy
  1109. // Other problems with accuracy, probably larger than the delays caused
  1110. // by arithmetic, are the latency in calls to KeQueryPerformanceCounter
  1111. // (typically about 5 us), and delays that can occur on the bus when DMA
  1112. // is taking place.
  1113. // Now poll the device. We wait until the status bit(s) set(s)
  1114. // and note the time. If the time since the last poll was
  1115. // too great we ignore the answer and try again.
  1116. // Loop until we get a decent reading or exceed the threshold
  1117. for (Redo = TRUE, MaxRedos = 20; Redo && --MaxRedos != 0;)
  1118. {
  1119. ULONG StartTime;
  1120. ULONG CurrentTime;
  1121. ULONG PreviousTime;
  1122. ULONG PreviousTimeButOne;
  1123. UCHAR ResistiveInputMask;
  1124. ResistiveInputMask = xMask | yMask | zMask | rMask;
  1125. // Lock on to start time
  1126. StartTime = KeQueryPerformanceCounter(NULL).LowPart;
  1127. WRITE_PORT_UCHAR(JoyPort, JOY_START_TIMERS);
  1128. CurrentTime = KeQueryPerformanceCounter(NULL).LowPart - StartTime;
  1129. PortVal = READ_PORT_UCHAR(JoyPort);
  1130. // Now wait until our end times for each coordinate
  1131. PreviousTimeButOne = 0;
  1132. PreviousTime = CurrentTime;
  1133. for (Redo = FALSE;
  1134. ResistiveInputMask;
  1135. PreviousTimeButOne = PreviousTime,
  1136. PreviousTime = CurrentTime,
  1137. PortVal = READ_PORT_UCHAR(JoyPort)
  1138. ) {
  1139. PortVal = ResistiveInputMask & ~PortVal;
  1140. CurrentTime = KeQueryPerformanceCounter(NULL).LowPart - StartTime;
  1141. if (CurrentTime > MaxTimeoutInTicks) {
  1142. DebugTrace(("Polling failed - ResistiveInputMask = %x, Time = %d",
  1143. (ULONG)ResistiveInputMask,
  1144. TimeInMicroSeconds(CurrentTime)));
  1145. return STATUS_TIMEOUT;
  1146. }
  1147. if (PortVal & xMask) {
  1148. ResistiveInputMask &= ~xMask;
  1149. xTime = PreviousTime;
  1150. }
  1151. if (PortVal & yMask) {
  1152. ResistiveInputMask &= ~yMask;
  1153. yTime = PreviousTime;
  1154. }
  1155. if (PortVal & zMask) {
  1156. ResistiveInputMask &= ~zMask;
  1157. zTime = PreviousTime;
  1158. }
  1159. if (PortVal & rMask){
  1160. ResistiveInputMask &= ~rMask;
  1161. rTime = PreviousTime;
  1162. }
  1163. if (PortVal && CurrentTime - PreviousTimeButOne > ThresholdInTicks) {
  1164. // Something (DMA or interrupts) delayed our read loop, start again.
  1165. DebugTrace(("Too long a gap between polls - %u us", TimeInMicroSeconds(CurrentTime - PreviousTimeButOne)));
  1166. JoyStatistics.Redo++;
  1167. Redo = TRUE;
  1168. break;
  1169. }
  1170. }
  1171. }
  1172. if (MaxRedos == 0)
  1173. {
  1174. DebugTrace(("Overran redos to get counters"));
  1175. pInput->Unplugged = TRUE;
  1176. return STATUS_TIMEOUT;
  1177. }
  1178. pInput->Unplugged = FALSE;
  1179. pInput->Buttons = Buttons;
  1180. pInput->XTime = TimeInMicroSeconds(xTime);
  1181. pInput->YTime = TimeInMicroSeconds(yTime);
  1182. pInput->ZTime = (zMask) ? TimeInMicroSeconds(zTime) : 0;
  1183. pInput->TTime = (rMask) ? TimeInMicroSeconds(rTime) : 0;
  1184. pInput->Axi = ((PJOY_EXTENSION)pDO->DeviceExtension)->NumberOfAxes;
  1185. // everything worked, save this info as last good packet
  1186. RtlCopyMemory (&jjLastGoodPacket, pInput, sizeof (JOY_DD_INPUT_DATA));
  1187. bLastGoodPacket = TRUE;
  1188. DebugTrace(("X = %x, Y = %x, Z = %x, R = %x, Buttons = %x",
  1189. pInput->XTime,
  1190. pInput->YTime,
  1191. pInput->ZTime,
  1192. pInput->TTime,
  1193. pInput->Buttons));
  1194. return STATUS_SUCCESS;
  1195. }