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.

2127 lines
56 KiB

  1. #if defined(i386)
  2. /*++
  3. Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
  4. Copyright (c) 1992 Logitech Inc.
  5. Module Name:
  6. busmdep.c
  7. Abstract:
  8. The initialization and hardware-dependent portions of a Bus mouse port
  9. driver. Modifications to support new mice similar to the bus mouse should
  10. be localized to this file.
  11. Environment:
  12. Kernel mode only.
  13. Notes:
  14. NOTES: (Future/outstanding issues)
  15. - Powerfail not implemented.
  16. - Consolidate duplicate code, where possible and appropriate.
  17. Revision History:
  18. --*/
  19. #include "stdarg.h"
  20. #include "stdio.h"
  21. #include "string.h"
  22. #include "ntddk.h"
  23. #include "busmouse.h"
  24. #include "busmlog.h"
  25. #ifdef PNP_IDENTIFY
  26. #include "devdesc.h"
  27. #endif
  28. //
  29. // Use the alloc_text pragma to specify the driver initialization routines
  30. // (they can be paged out).
  31. //
  32. #ifdef ALLOC_PRAGMA
  33. #pragma alloc_text(INIT,DriverEntry)
  34. #pragma alloc_text(INIT,BusConfiguration)
  35. #pragma alloc_text(INIT,BusPeripheralCallout)
  36. #pragma alloc_text(INIT,BusServiceParameters)
  37. #pragma alloc_text(INIT,BusInitializeHardware)
  38. #pragma alloc_text(INIT,BusBuildResourceList)
  39. #endif
  40. NTSTATUS
  41. DriverEntry(
  42. IN PDRIVER_OBJECT DriverObject,
  43. IN PUNICODE_STRING RegistryPath
  44. )
  45. /*++
  46. Routine Description:
  47. This routine initializes the Bus mouse port driver.
  48. Arguments:
  49. DriverObject - Pointer to driver object created by system.
  50. RegistryPath - Pointer to the Unicode name of the registry path
  51. for this driver.
  52. Return Value:
  53. The function value is the final status from the initialization operation.
  54. --*/
  55. {
  56. PDEVICE_OBJECT portDeviceObject = NULL;
  57. PDEVICE_EXTENSION deviceExtension = NULL;
  58. DEVICE_EXTENSION tmpDeviceExtension;
  59. NTSTATUS status = STATUS_SUCCESS;
  60. KIRQL coordinatorIrql = 0;
  61. ULONG interruptVector;
  62. KIRQL interruptLevel;
  63. KAFFINITY affinity;
  64. PIO_ERROR_LOG_PACKET errorLogEntry;
  65. ULONG uniqueErrorValue;
  66. ULONG dumpCount = 0;
  67. NTSTATUS errorCode = STATUS_SUCCESS;
  68. PCM_RESOURCE_LIST resources = NULL;
  69. ULONG resourceListSize = 0;
  70. BOOLEAN conflictDetected;
  71. ULONG addressSpace;
  72. PHYSICAL_ADDRESS cardAddress;
  73. ULONG i;
  74. UNICODE_STRING fullDeviceName;
  75. UNICODE_STRING baseDeviceName;
  76. UNICODE_STRING deviceNameSuffix;
  77. UNICODE_STRING registryPath;
  78. #define NAME_MAX 256
  79. WCHAR nameBuffer[NAME_MAX];
  80. #define DUMP_COUNT 4
  81. ULONG dumpData[DUMP_COUNT];
  82. BusPrint((1,"\n\nBusInitialize: enter\n"));
  83. //
  84. // Zero-initialize various structures.
  85. //
  86. RtlZeroMemory(&tmpDeviceExtension, sizeof(tmpDeviceExtension));
  87. for (i = 0; i < DUMP_COUNT; i++)
  88. dumpData[i] = 0;
  89. fullDeviceName.MaximumLength = 0;
  90. deviceNameSuffix.MaximumLength = 0;
  91. registryPath.MaximumLength = 0;
  92. RtlZeroMemory(nameBuffer, sizeof(nameBuffer));
  93. baseDeviceName.Buffer = nameBuffer;
  94. baseDeviceName.Length = 0;
  95. baseDeviceName.MaximumLength = sizeof(nameBuffer);
  96. //
  97. // Need to ensure that the registry path is null-terminated.
  98. // Allocate pool to hold a null-terminated copy of the path.
  99. //
  100. registryPath.Buffer = ExAllocatePool(
  101. PagedPool,
  102. RegistryPath->Length + sizeof(UNICODE_NULL)
  103. );
  104. if (!registryPath.Buffer) {
  105. BusPrint((
  106. 1,
  107. "BUSMOUSE-BusInitialize: Couldn't allocate pool for registry path\n"
  108. ));
  109. status = STATUS_UNSUCCESSFUL;
  110. errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES;
  111. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 2;
  112. dumpData[0] = (ULONG) RegistryPath->Length + sizeof(UNICODE_NULL);
  113. dumpCount = 1;
  114. goto BusInitializeExit;
  115. } else {
  116. registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
  117. registryPath.MaximumLength = registryPath.Length;
  118. RtlZeroMemory(
  119. registryPath.Buffer,
  120. registryPath.Length
  121. );
  122. RtlMoveMemory(
  123. registryPath.Buffer,
  124. RegistryPath->Buffer,
  125. RegistryPath->Length
  126. );
  127. }
  128. //
  129. // Get the configuration information for this driver.
  130. //
  131. BusConfiguration(&tmpDeviceExtension, &registryPath, &baseDeviceName);
  132. if (tmpDeviceExtension.HardwarePresent == FALSE) {
  133. //
  134. // There is no Bus mouse attached. Return an unsuccessful status.
  135. //
  136. BusPrint((1,"BusInitialize: No mouse attached.\n"));
  137. status = STATUS_NO_SUCH_DEVICE;
  138. errorCode = BUSMOUSE_NO_SUCH_DEVICE;
  139. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 4;
  140. dumpCount = 0;
  141. goto BusInitializeExit;
  142. }
  143. //
  144. // Set up space for the port's device object suffix. Note that
  145. // we overallocate space for the suffix string because it is much
  146. // easier than figuring out exactly how much space is required.
  147. // The storage gets freed at the end of driver initialization, so
  148. // who cares...
  149. //
  150. RtlInitUnicodeString(
  151. &deviceNameSuffix,
  152. NULL
  153. );
  154. deviceNameSuffix.MaximumLength = POINTER_PORTS_MAXIMUM * sizeof(WCHAR)
  155. + sizeof(UNICODE_NULL);
  156. deviceNameSuffix.Buffer = ExAllocatePool(
  157. PagedPool,
  158. deviceNameSuffix.MaximumLength
  159. );
  160. if (!deviceNameSuffix.Buffer) {
  161. BusPrint((
  162. 1,
  163. "BusInitialize: Couldn't allocate string for device object suffix\n"
  164. ));
  165. status = STATUS_UNSUCCESSFUL;
  166. errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES;
  167. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 6;
  168. dumpData[0] = (ULONG) deviceNameSuffix.MaximumLength;
  169. dumpCount = 1;
  170. goto BusInitializeExit;
  171. }
  172. RtlZeroMemory(
  173. deviceNameSuffix.Buffer,
  174. deviceNameSuffix.MaximumLength
  175. );
  176. //
  177. // Set up space for the port's full device object name.
  178. //
  179. RtlInitUnicodeString(
  180. &fullDeviceName,
  181. NULL
  182. );
  183. fullDeviceName.MaximumLength = sizeof(L"\\Device\\") +
  184. baseDeviceName.Length +
  185. deviceNameSuffix.MaximumLength;
  186. fullDeviceName.Buffer = ExAllocatePool(
  187. PagedPool,
  188. fullDeviceName.MaximumLength
  189. );
  190. if (!fullDeviceName.Buffer) {
  191. BusPrint((
  192. 1,
  193. "BusInitialize: Couldn't allocate string for device object name\n"
  194. ));
  195. status = STATUS_UNSUCCESSFUL;
  196. errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES;
  197. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 8;
  198. dumpData[0] = (ULONG) fullDeviceName.MaximumLength;
  199. dumpCount = 1;
  200. goto BusInitializeExit;
  201. }
  202. RtlZeroMemory(
  203. fullDeviceName.Buffer,
  204. fullDeviceName.MaximumLength
  205. );
  206. RtlAppendUnicodeToString(
  207. &fullDeviceName,
  208. L"\\Device\\"
  209. );
  210. RtlAppendUnicodeToString(
  211. &fullDeviceName,
  212. baseDeviceName.Buffer
  213. );
  214. for (i = 0; i < POINTER_PORTS_MAXIMUM; i++) {
  215. //
  216. // Append the suffix to the device object name string. E.g., turn
  217. // \Device\PointerPort into \Device\PointerPort0. Then we attempt
  218. // to create the device object. If the device object already
  219. // exists (because it was already created by another port driver),
  220. // increment the suffix and try again.
  221. //
  222. status = RtlIntegerToUnicodeString(
  223. i,
  224. 10,
  225. &deviceNameSuffix
  226. );
  227. if (!NT_SUCCESS(status)) {
  228. break;
  229. }
  230. RtlAppendUnicodeStringToString(
  231. &fullDeviceName,
  232. &deviceNameSuffix
  233. );
  234. BusPrint((
  235. 1,
  236. "BusInitialize: Creating device object named %ws\n",
  237. fullDeviceName.Buffer
  238. ));
  239. //
  240. // Create device object for the Bus mouse port device.
  241. //
  242. status = IoCreateDevice(
  243. DriverObject,
  244. sizeof(DEVICE_EXTENSION),
  245. &fullDeviceName,
  246. FILE_DEVICE_BUS_PORT,
  247. 0,
  248. FALSE,
  249. &portDeviceObject
  250. );
  251. if (NT_SUCCESS(status)) {
  252. //
  253. // We've successfully created a device object.
  254. //
  255. break;
  256. } else {
  257. //
  258. // We'll increment the suffix and try again. Note that we reset
  259. // the length of the string here to get back to the beginning
  260. // of the suffix portion of the name. Do not bother to
  261. // zero the suffix, though, because the string for the
  262. // incremented suffix will be at least as long as the previous
  263. // one.
  264. //
  265. fullDeviceName.Length -= deviceNameSuffix.Length;
  266. }
  267. }
  268. if (!NT_SUCCESS(status)) {
  269. BusPrint((
  270. 1,
  271. "BusInitialize: Could not create port device object = %ws\n",
  272. fullDeviceName.Buffer
  273. ));
  274. errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES;
  275. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 10;
  276. dumpData[0] = (ULONG) i;
  277. dumpCount = 1;
  278. goto BusInitializeExit;
  279. }
  280. //
  281. // Do buffered I/O. I.e., the I/O system will copy to/from user data
  282. // from/to a system buffer.
  283. //
  284. portDeviceObject->Flags |= DO_BUFFERED_IO;
  285. //
  286. // Set up the device extension.
  287. //
  288. deviceExtension =
  289. (PDEVICE_EXTENSION) portDeviceObject->DeviceExtension;
  290. *deviceExtension = tmpDeviceExtension;
  291. deviceExtension->DeviceObject = portDeviceObject;
  292. //
  293. // Set up the device resource list prior to reporting resource usage.
  294. //
  295. BusBuildResourceList(deviceExtension, &resources, &resourceListSize);
  296. //
  297. // Report resource usage for the registry.
  298. //
  299. IoReportResourceUsage(
  300. &baseDeviceName,
  301. DriverObject,
  302. NULL,
  303. 0,
  304. portDeviceObject,
  305. resources,
  306. resourceListSize,
  307. FALSE,
  308. &conflictDetected
  309. );
  310. if (conflictDetected) {
  311. //
  312. // Some other device already owns the ports or interrupts.
  313. // Fatal error.
  314. //
  315. BusPrint((
  316. 1,
  317. "BusInitialize: Resource usage conflict\n"
  318. ));
  319. //
  320. // Log an error.
  321. //
  322. errorCode = BUSMOUSE_RESOURCE_CONFLICT;
  323. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 15;
  324. dumpData[0] = (ULONG)
  325. resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Level;
  326. dumpData[1] = (ULONG)
  327. resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Vector;
  328. dumpData[2] = (ULONG)
  329. resources->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Level;
  330. dumpData[3] = (ULONG)
  331. resources->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Vector;
  332. dumpCount = 4;
  333. goto BusInitializeExit;
  334. }
  335. //
  336. // Map the Bus controller registers.
  337. //
  338. addressSpace = (deviceExtension->Configuration.PortList[0].Flags
  339. & CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_IO? 1:0;
  340. if (!HalTranslateBusAddress(
  341. deviceExtension->Configuration.InterfaceType,
  342. deviceExtension->Configuration.BusNumber,
  343. deviceExtension->Configuration.PortList[0].u.Port.Start,
  344. &addressSpace,
  345. &cardAddress
  346. )) {
  347. addressSpace = 1;
  348. cardAddress.QuadPart = 0;
  349. }
  350. if (!addressSpace) {
  351. deviceExtension->Configuration.UnmapRegistersRequired = TRUE;
  352. deviceExtension->Configuration.DeviceRegisters[0] =
  353. MmMapIoSpace(
  354. cardAddress,
  355. deviceExtension->Configuration.PortList[0].u.Port.Length,
  356. FALSE
  357. );
  358. } else {
  359. deviceExtension->Configuration.UnmapRegistersRequired = FALSE;
  360. deviceExtension->Configuration.DeviceRegisters[0] =
  361. (PVOID)cardAddress.LowPart;
  362. }
  363. if (!deviceExtension->Configuration.DeviceRegisters[0]) {
  364. BusPrint((
  365. 1,
  366. "BusInitialize: Couldn't map the device registers.\n"
  367. ));
  368. deviceExtension->Configuration.UnmapRegistersRequired = FALSE;
  369. status = STATUS_NONE_MAPPED;
  370. //
  371. // Log an error.
  372. //
  373. errorCode = BUSMOUSE_REGISTERS_NOT_MAPPED;
  374. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 20;
  375. dumpData[0] = cardAddress.LowPart;
  376. dumpCount = 1;
  377. goto BusInitializeExit;
  378. }
  379. //
  380. // Initialize the Bus hardware to default values for the mouse. Note
  381. // that interrupts remain disabled until the class driver
  382. // requests a MOUSE_CONNECT internal device control.
  383. //
  384. status = BusInitializeHardware(portDeviceObject);
  385. if (!NT_SUCCESS(status)) {
  386. BusPrint((
  387. 1,
  388. "BusInitialize: Could not initialize hardware\n"
  389. ));
  390. goto BusInitializeExit;
  391. }
  392. //
  393. // Allocate the ring buffer for the mouse input data.
  394. //
  395. deviceExtension->InputData =
  396. ExAllocatePool(
  397. NonPagedPool,
  398. deviceExtension->Configuration.MouseAttributes.InputDataQueueLength
  399. );
  400. if (!deviceExtension->InputData) {
  401. //
  402. // Could not allocate memory for the mouse data queue.
  403. //
  404. BusPrint((
  405. 1,
  406. "BusInitialize: Could not allocate mouse input data queue\n"
  407. ));
  408. status = STATUS_INSUFFICIENT_RESOURCES;
  409. //
  410. // Log an error.
  411. //
  412. errorCode = BUSMOUSE_NO_BUFFER_ALLOCATED;
  413. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 30;
  414. dumpData[0] =
  415. deviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
  416. dumpCount = 1;
  417. goto BusInitializeExit;
  418. }
  419. deviceExtension->DataEnd =
  420. (PMOUSE_INPUT_DATA) ((PCHAR) (deviceExtension->InputData)
  421. + deviceExtension->Configuration.MouseAttributes.InputDataQueueLength);
  422. //
  423. // Zero the mouse input data ring buffer.
  424. //
  425. RtlZeroMemory(
  426. deviceExtension->InputData,
  427. deviceExtension->Configuration.MouseAttributes.InputDataQueueLength
  428. );
  429. //
  430. // Initialize the connection data.
  431. //
  432. deviceExtension->ConnectData.ClassDeviceObject = NULL;
  433. deviceExtension->ConnectData.ClassService = NULL;
  434. //
  435. // Initialize the input data queue.
  436. //
  437. BusInitializeDataQueue((PVOID) deviceExtension);
  438. //
  439. // Initialize the port ISR DPC. The ISR DPC is responsible for
  440. // calling the connected class driver's callback routine to process
  441. // the input data queue.
  442. //
  443. deviceExtension->DpcInterlockVariable = -1;
  444. KeInitializeSpinLock(&deviceExtension->SpinLock);
  445. KeInitializeDpc(
  446. &deviceExtension->IsrDpc,
  447. (PKDEFERRED_ROUTINE) DBusIsrDpc,
  448. portDeviceObject
  449. );
  450. KeInitializeDpc(
  451. &deviceExtension->IsrDpcRetry,
  452. (PKDEFERRED_ROUTINE) DBusIsrDpc,
  453. portDeviceObject
  454. );
  455. //
  456. // Initialize the mouse data consumption timer.
  457. //
  458. KeInitializeTimer(&deviceExtension->DataConsumptionTimer);
  459. //
  460. // Initialize the port DPC queue to log overrun and internal
  461. // driver errors.
  462. //
  463. KeInitializeDpc(
  464. &deviceExtension->ErrorLogDpc,
  465. (PKDEFERRED_ROUTINE) BusErrorLogDpc,
  466. portDeviceObject
  467. );
  468. //
  469. // From the Hal, get the interrupt vector and level.
  470. //
  471. interruptVector = HalGetInterruptVector(
  472. deviceExtension->Configuration.InterfaceType,
  473. deviceExtension->Configuration.BusNumber,
  474. deviceExtension->Configuration.MouseInterrupt.u.Interrupt.Level,
  475. deviceExtension->Configuration.MouseInterrupt.u.Interrupt.Vector,
  476. &interruptLevel,
  477. &affinity
  478. );
  479. //
  480. // Initialize and connect the interrupt object for the mouse.
  481. //
  482. status = IoConnectInterrupt(
  483. &(deviceExtension->InterruptObject),
  484. (PKSERVICE_ROUTINE) DBusInterruptService,
  485. (PVOID) portDeviceObject,
  486. (PKSPIN_LOCK)NULL,
  487. interruptVector,
  488. interruptLevel,
  489. interruptLevel,
  490. deviceExtension->Configuration.MouseInterrupt.Flags
  491. == CM_RESOURCE_INTERRUPT_LATCHED ? Latched:LevelSensitive,
  492. deviceExtension->Configuration.MouseInterrupt.ShareDisposition,
  493. affinity,
  494. deviceExtension->Configuration.FloatingSave
  495. );
  496. if (!NT_SUCCESS(status)) {
  497. //
  498. // Failed to install. Free up resources before exiting.
  499. //
  500. BusPrint((
  501. 1,
  502. "BusInitialize: Could not connect mouse interrupt\n"
  503. ));
  504. //
  505. // Log an error.
  506. //
  507. errorCode = BUSMOUSE_NO_INTERRUPT_CONNECTED;
  508. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 40;
  509. dumpData[0] = interruptLevel;
  510. dumpCount = 1;
  511. goto BusInitializeExit;
  512. }
  513. //
  514. // Once initialization is finished, load the device map information
  515. // into the registry so that setup can determine which pointer port
  516. // is active.
  517. //
  518. status = RtlWriteRegistryValue(
  519. RTL_REGISTRY_DEVICEMAP,
  520. baseDeviceName.Buffer,
  521. fullDeviceName.Buffer,
  522. REG_SZ,
  523. registryPath.Buffer,
  524. registryPath.Length
  525. );
  526. if (!NT_SUCCESS(status)) {
  527. BusPrint((
  528. 1,
  529. "BusInitialize: Could not store name in DeviceMap\n"
  530. ));
  531. errorCode = BUSMOUSE_NO_DEVICEMAP_CREATED;
  532. uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 50;
  533. dumpCount = 0;
  534. goto BusInitializeExit;
  535. } else {
  536. BusPrint((
  537. 1,
  538. "BusInitialize: Stored name in DeviceMap\n"
  539. ));
  540. }
  541. #ifdef PNP_IDENTIFY
  542. LinkDeviceToDescription(
  543. RegistryPath,
  544. &fullDeviceName,
  545. deviceExtension->Configuration.InterfaceType,
  546. deviceExtension->Configuration.BusNumber,
  547. deviceExtension->Configuration.ControllerType,
  548. deviceExtension->Configuration.ControllerNumber,
  549. deviceExtension->Configuration.PeripheralType,
  550. deviceExtension->Configuration.PeripheralNumber
  551. );
  552. #endif
  553. ASSERT(status == STATUS_SUCCESS);
  554. //
  555. // Set up the device driver entry points.
  556. //
  557. DriverObject->DriverStartIo = DBusStartIo;
  558. DriverObject->MajorFunction[IRP_MJ_CREATE] = DBusOpenClose;
  559. DriverObject->MajorFunction[IRP_MJ_CLOSE] = DBusOpenClose;
  560. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]= DBusFlush;
  561. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  562. DBusInternalDeviceControl;
  563. //
  564. // NOTE: Don't allow this driver to unload. Otherwise, we would set
  565. // DriverObject->DriverUnload = DBusUnload.
  566. //
  567. BusInitializeExit:
  568. //
  569. // Log an error, if necessary.
  570. //
  571. if (errorCode != STATUS_SUCCESS) {
  572. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  573. IoAllocateErrorLogEntry(
  574. (portDeviceObject == NULL) ?
  575. (PVOID) DriverObject : (PVOID) portDeviceObject,
  576. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + (dumpCount * sizeof(ULONG)))
  577. );
  578. if (errorLogEntry != NULL) {
  579. errorLogEntry->ErrorCode = errorCode;
  580. errorLogEntry->DumpDataSize = (USHORT) (dumpCount * sizeof(ULONG));
  581. errorLogEntry->SequenceNumber = 0;
  582. errorLogEntry->MajorFunctionCode = 0;
  583. errorLogEntry->IoControlCode = 0;
  584. errorLogEntry->RetryCount = 0;
  585. errorLogEntry->UniqueErrorValue = uniqueErrorValue;
  586. errorLogEntry->FinalStatus = status;
  587. for (i = 0; i < dumpCount; i++)
  588. errorLogEntry->DumpData[i] = dumpData[i];
  589. IoWriteErrorLogEntry(errorLogEntry);
  590. }
  591. }
  592. if (!NT_SUCCESS(status)) {
  593. //
  594. // The initialization failed. Cleanup resources before exiting.
  595. //
  596. // Note: No need/way to undo the KeInitializeDpc or
  597. // KeInitializeTimer calls.
  598. //
  599. if (resources) {
  600. //
  601. // Call IoReportResourceUsage to remove the resources from
  602. // the map.
  603. //
  604. resources->Count = 0;
  605. IoReportResourceUsage(
  606. &baseDeviceName,
  607. DriverObject,
  608. NULL,
  609. 0,
  610. portDeviceObject,
  611. resources,
  612. resourceListSize,
  613. FALSE,
  614. &conflictDetected
  615. );
  616. }
  617. if (deviceExtension) {
  618. if (deviceExtension->InterruptObject != NULL)
  619. IoDisconnectInterrupt(deviceExtension->InterruptObject);
  620. if (deviceExtension->Configuration.UnmapRegistersRequired) {
  621. MmUnmapIoSpace(
  622. deviceExtension->Configuration.DeviceRegisters[0],
  623. deviceExtension->Configuration.PortList[0].u.Port.Length
  624. );
  625. }
  626. if (deviceExtension->InputData)
  627. ExFreePool(deviceExtension->InputData);
  628. }
  629. if (portDeviceObject)
  630. IoDeleteDevice(portDeviceObject);
  631. }
  632. //
  633. // Free the resource list.
  634. //
  635. // N.B. If we ever decide to hang on to the resource list instead,
  636. // we need to allocate it from non-paged pool (it is now paged pool).
  637. //
  638. if (resources)
  639. ExFreePool(resources);
  640. //
  641. // Free the unicode strings.
  642. //
  643. if (deviceNameSuffix.MaximumLength != 0)
  644. ExFreePool(deviceNameSuffix.Buffer);
  645. if (fullDeviceName.MaximumLength != 0)
  646. ExFreePool(fullDeviceName.Buffer);
  647. if (registryPath.MaximumLength != 0)
  648. ExFreePool(registryPath.Buffer);
  649. BusPrint((1,"BusInitialize: exit\n"));
  650. return(status);
  651. }
  652. BOOLEAN
  653. DBusInterruptService(
  654. IN PKINTERRUPT Interrupt,
  655. IN PVOID Context
  656. )
  657. /*++
  658. Routine Description:
  659. This is the interrupt service routine for the mouse device.
  660. Arguments:
  661. Interrupt - A pointer to the interrupt object for this interrupt.
  662. Context - A pointer to the device object.
  663. Return Value:
  664. Returns TRUE if the interrupt was expected (and therefore processed);
  665. otherwise, FALSE is returned.
  666. --*/
  667. {
  668. PDEVICE_EXTENSION deviceExtension;
  669. PDEVICE_OBJECT deviceObject;
  670. UCHAR previousButtons;
  671. PUCHAR port;
  672. UCHAR scratch;
  673. UCHAR status;
  674. UNREFERENCED_PARAMETER(Interrupt);
  675. BusPrint((3, "BusInterruptService: enter\n"));
  676. //
  677. // Get the device extension.
  678. //
  679. deviceObject = (PDEVICE_OBJECT) Context;
  680. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  681. //
  682. // Quit if the interrupt is not expected.
  683. // There is a problem right now when we connect the interrupt. It looks
  684. // like an interrupt is still registered even if we disabled
  685. // the device in the BusInitializeHardware routine.
  686. //
  687. if (deviceExtension->MouseEnableCount == 0) {
  688. BusPrint((
  689. 1,
  690. "BusInterruptService: Received interrupt with hardware disabled\n"));
  691. return TRUE;
  692. }
  693. //
  694. // Get the Bus mouse port address.
  695. //
  696. port = deviceExtension->Configuration.DeviceRegisters[0];
  697. //
  698. // Note: It would be nice to verify that the interrupt really
  699. // belongs to this driver, but it is currently not known how to
  700. // make that determination.
  701. //
  702. //
  703. // Set the Bus hold bit.
  704. //
  705. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE,
  706. BUS_CONTROL_COUNTER_CAPTURE);
  707. //
  708. // Read the position and buttons.
  709. //
  710. // The format is:
  711. //
  712. // BBBXMMMM
  713. // |||||--------- Movement selected by the control register
  714. // ||||---------- Not used (state of interrupt enable bit)
  715. // |||----------- 1 if button 3 is down (right button)
  716. // ||------------ 1 if button 2 is down (middle button)
  717. // |------------- 1 if button 1 is down (left button)
  718. //
  719. // NOTE: Optimize as follows.
  720. //
  721. // The bus mouse could be used as a clock because it interrupts the
  722. // system even if the device didn't move. Change the code to perform
  723. // no shifting/data handling in the initial part of the ISR. Process
  724. // the data only after the test for a null event.
  725. //
  726. //
  727. // X displacement
  728. //
  729. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE,
  730. BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_X_LOW);
  731. deviceExtension->CurrentInput.LastX =
  732. (LONG)(SCHAR) READ_PORT_UCHAR((port + BUS_DATA_PORT_READ))& 0x0F;
  733. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE,
  734. BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_X_HIGH);
  735. deviceExtension->CurrentInput.LastX |=
  736. (LONG)(SCHAR) ((READ_PORT_UCHAR((port + BUS_DATA_PORT_READ)) & 0x0F)
  737. << 4);
  738. BusPrint((3, "BusInterruptService: X displacement 0x%x\n",
  739. (int)deviceExtension->CurrentInput.LastX));
  740. //
  741. // Y displacment
  742. //
  743. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE,
  744. BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_Y_LOW);
  745. deviceExtension->CurrentInput.LastY =
  746. (LONG)(SCHAR) READ_PORT_UCHAR((port + BUS_DATA_PORT_READ)) & 0x0F;
  747. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE,
  748. BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_Y_HIGH);
  749. scratch = READ_PORT_UCHAR((port + BUS_DATA_PORT_READ));
  750. deviceExtension->CurrentInput.LastY |=
  751. (LONG)(SCHAR) ((scratch & 0x0F) << 4);
  752. BusPrint((3, "BusInterruptService: Y displacement 0x%x\n",
  753. (int)deviceExtension->CurrentInput.LastY));
  754. //
  755. // Invert the button state (down = 1).
  756. //
  757. scratch = ~scratch;
  758. //
  759. // Update CurrentInput with button transition data.
  760. // I.e., set a button up/down bit in the Buttons field if
  761. // the state of a given button has changed since we
  762. // received the last packet.
  763. //
  764. previousButtons = deviceExtension->PreviousButtons;
  765. deviceExtension->CurrentInput.Buttons = 0;
  766. if ((!(previousButtons & BUS_DATA_BUTTON_1))
  767. && (scratch & BUS_DATA_BUTTON_1)) {
  768. deviceExtension->CurrentInput.Buttons |= MOUSE_LEFT_BUTTON_DOWN;
  769. } else
  770. if ((previousButtons & BUS_DATA_BUTTON_1)
  771. && !(scratch & BUS_DATA_BUTTON_1)) {
  772. deviceExtension->CurrentInput.Buttons |= MOUSE_LEFT_BUTTON_UP;
  773. }
  774. if ((!(previousButtons & BUS_DATA_BUTTON_2))
  775. && (scratch & BUS_DATA_BUTTON_2)) {
  776. deviceExtension->CurrentInput.Buttons |= MOUSE_MIDDLE_BUTTON_DOWN;
  777. } else
  778. if ((previousButtons & BUS_DATA_BUTTON_2)
  779. && !(scratch & BUS_DATA_BUTTON_2)) {
  780. deviceExtension->CurrentInput.Buttons |= MOUSE_MIDDLE_BUTTON_UP;
  781. }
  782. if ((!(previousButtons & BUS_DATA_BUTTON_3))
  783. && (scratch & BUS_DATA_BUTTON_3)) {
  784. deviceExtension->CurrentInput.Buttons |= MOUSE_RIGHT_BUTTON_DOWN;
  785. } else
  786. if ((previousButtons & BUS_DATA_BUTTON_3)
  787. && !(scratch & BUS_DATA_BUTTON_3)) {
  788. deviceExtension->CurrentInput.Buttons |= MOUSE_RIGHT_BUTTON_UP;
  789. }
  790. BusPrint((3, "BusInterruptService: Button state 0x%x\n",
  791. deviceExtension->CurrentInput.Buttons));
  792. if (deviceExtension->CurrentInput.Buttons ||
  793. deviceExtension->CurrentInput.LastX ||
  794. deviceExtension->CurrentInput.LastY) {
  795. deviceExtension->CurrentInput.UnitId = deviceExtension->UnitId;
  796. //
  797. // Keep track of the state of the mouse buttons for the next
  798. // interrupt.
  799. //
  800. deviceExtension->PreviousButtons =
  801. scratch & (BUS_DATA_BUTTON_1|BUS_DATA_BUTTON_2|BUS_DATA_BUTTON_3);
  802. //
  803. // Clear the Bus hold bit.
  804. //
  805. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, 0x00);
  806. //
  807. // Write the input data to the queue and request the ISR DPC to
  808. // finish processing the interrupt at DISPATCH_LEVEL.
  809. //
  810. if (!BusWriteDataToQueue(
  811. deviceExtension,
  812. &deviceExtension->CurrentInput
  813. )) {
  814. //
  815. // The mouse input data queue is full. Just drop the
  816. // latest input on the floor.
  817. //
  818. // Queue a DPC to log an overrun error.
  819. //
  820. BusPrint((
  821. 1,
  822. "DBusInterruptService: queue overflow\n"
  823. ));
  824. if (deviceExtension->OkayToLogOverflow) {
  825. KeInsertQueueDpc(
  826. &deviceExtension->ErrorLogDpc,
  827. (PIRP) NULL,
  828. (PVOID) (ULONG) BUSMOUSE_MOU_BUFFER_OVERFLOW
  829. );
  830. deviceExtension->OkayToLogOverflow = FALSE;
  831. }
  832. } else if (deviceExtension->DpcInterlockVariable >= 0) {
  833. //
  834. // The ISR DPC is already executing. Tell the ISR DPC it has
  835. // more work to do by incrementing the DpcInterlockVariable.
  836. //
  837. deviceExtension->DpcInterlockVariable += 1;
  838. } else {
  839. //
  840. // Queue the ISR DPC.
  841. //
  842. KeInsertQueueDpc(
  843. &deviceExtension->IsrDpc,
  844. deviceObject->CurrentIrp,
  845. NULL
  846. );
  847. }
  848. } else {
  849. BusPrint((
  850. 3,
  851. "DBusInterruptService: interrupt without button/motion change\n"
  852. ));
  853. //
  854. // Clear the Bus hold bit.
  855. //
  856. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, 0x00);
  857. }
  858. BusPrint((3, "DBusInterruptService: exit\n"));
  859. return(TRUE);
  860. }
  861. VOID
  862. BusUnload(
  863. IN PDRIVER_OBJECT DriverObject
  864. )
  865. {
  866. UNREFERENCED_PARAMETER(DriverObject);
  867. BusPrint((2, "BusUnload: enter\n"));
  868. BusPrint((2, "BusUnload: exit\n"));
  869. }
  870. VOID
  871. BusBuildResourceList(
  872. IN PDEVICE_EXTENSION DeviceExtension,
  873. OUT PCM_RESOURCE_LIST *ResourceList,
  874. OUT PULONG ResourceListSize
  875. )
  876. /*++
  877. Routine Description:
  878. Creates a resource list that is used to query or report resource usage.
  879. Arguments:
  880. DeviceExtension - Pointer to the port's device extension.
  881. ResourceList - Pointer to a pointer to the resource list to be allocated
  882. and filled.
  883. ResourceListSize - Pointer to the returned size of the resource
  884. list (in bytes).
  885. Return Value:
  886. None. If the call succeeded, *ResourceList points to the built
  887. resource list and *ResourceListSize is set to the size (in bytes)
  888. of the resource list; otherwise, *ResourceList is NULL.
  889. Note:
  890. Memory is allocated here for *ResourceList. It must be
  891. freed up by the caller, by calling ExFreePool();
  892. --*/
  893. {
  894. ULONG count = 0;
  895. PIO_ERROR_LOG_PACKET errorLogEntry;
  896. ULONG i = 0;
  897. ULONG j = 0;
  898. BusPrint((2, "BusBuildResourceList: Enter\n"));
  899. count += DeviceExtension->Configuration.PortListCount;
  900. if (DeviceExtension->Configuration.MouseInterrupt.Type
  901. == CmResourceTypeInterrupt)
  902. count += 1;
  903. *ResourceListSize = sizeof(CM_RESOURCE_LIST) +
  904. ((count - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  905. *ResourceList = (PCM_RESOURCE_LIST) ExAllocatePool(
  906. PagedPool,
  907. *ResourceListSize
  908. );
  909. //
  910. // Return NULL if the structure could not be allocated.
  911. // Otherwise, fill in the resource list.
  912. //
  913. if (!*ResourceList) {
  914. //
  915. // Could not allocate memory for the resource list.
  916. //
  917. BusPrint((
  918. 1,
  919. "BusBuildResourceList: Could not allocate resource list\n"
  920. ));
  921. //
  922. // Log an error.
  923. //
  924. errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
  925. DeviceExtension->DeviceObject,
  926. sizeof(IO_ERROR_LOG_PACKET)
  927. + sizeof(ULONG)
  928. );
  929. if (errorLogEntry != NULL) {
  930. errorLogEntry->ErrorCode = BUSMOUSE_INSUFFICIENT_RESOURCES;
  931. errorLogEntry->DumpDataSize = sizeof(ULONG);
  932. errorLogEntry->SequenceNumber = 0;
  933. errorLogEntry->MajorFunctionCode = 0;
  934. errorLogEntry->IoControlCode = 0;
  935. errorLogEntry->RetryCount = 0;
  936. errorLogEntry->UniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 110;
  937. errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  938. errorLogEntry->DumpData[0] = *ResourceListSize;
  939. *ResourceListSize = 0;
  940. IoWriteErrorLogEntry(errorLogEntry);
  941. }
  942. return;
  943. }
  944. RtlZeroMemory(
  945. *ResourceList,
  946. *ResourceListSize
  947. );
  948. //
  949. // Concoct one full resource descriptor.
  950. //
  951. (*ResourceList)->Count = 1;
  952. (*ResourceList)->List[0].InterfaceType =
  953. DeviceExtension->Configuration.InterfaceType;
  954. (*ResourceList)->List[0].BusNumber =
  955. DeviceExtension->Configuration.BusNumber;
  956. //
  957. // Build the partial resource descriptors for interrupt and port
  958. // resources from the saved values.
  959. //
  960. (*ResourceList)->List[0].PartialResourceList.Count = count;
  961. if (DeviceExtension->Configuration.MouseInterrupt.Type
  962. == CmResourceTypeInterrupt)
  963. (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
  964. DeviceExtension->Configuration.MouseInterrupt;
  965. for (j = 0; j < DeviceExtension->Configuration.PortListCount; j++) {
  966. (*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
  967. DeviceExtension->Configuration.PortList[j];
  968. }
  969. BusPrint((2, "BusBuildResourceList: Exit\n"));
  970. }
  971. VOID
  972. BusConfiguration(
  973. IN PDEVICE_EXTENSION DeviceExtension,
  974. IN PUNICODE_STRING RegistryPath,
  975. IN PUNICODE_STRING DeviceName
  976. )
  977. /*++
  978. Routine Description:
  979. This routine retrieves the configuration information for the mouse.
  980. Arguments:
  981. DeviceExtension - Pointer to the (temporary) device extension.
  982. RegistryPath - Pointer to the null-terminated Unicode name of the
  983. registry path for this driver.
  984. DeviceName - Pointer to the Unicode string that will receive
  985. the port device name.
  986. Return Value:
  987. None. As a side-effect, may set DeviceExtension->HardwarePresent.
  988. --*/
  989. {
  990. NTSTATUS status = STATUS_SUCCESS;
  991. PBUS_CONFIGURATION_INFORMATION configuration;
  992. INTERFACE_TYPE interfaceType;
  993. CONFIGURATION_TYPE controllerType = PointerController;
  994. CONFIGURATION_TYPE peripheralType = PointerPeripheral;
  995. ULONG i;
  996. BusPrint((2, "BusConfiguration: Enter\n"));
  997. // Loop through the different interface types (Eisa, Isa, ...)
  998. for (i = 0; i < MaximumInterfaceType; i++) {
  999. //
  1000. // Get the registry information for this device.
  1001. //
  1002. interfaceType = i;
  1003. status = IoQueryDeviceDescription(&interfaceType,
  1004. NULL,
  1005. &controllerType,
  1006. NULL,
  1007. &peripheralType,
  1008. NULL,
  1009. BusPeripheralCallout,
  1010. (PVOID) DeviceExtension);
  1011. if (DeviceExtension->HardwarePresent) {
  1012. //
  1013. // Get the service parameters (e.g., user-configurable
  1014. // data input queue size, etc.).
  1015. //
  1016. BusServiceParameters(DeviceExtension, RegistryPath, DeviceName);
  1017. configuration = &DeviceExtension->Configuration;
  1018. //
  1019. // Initialize mouse-specific configuration parameters.
  1020. //
  1021. configuration->MouseAttributes.MouseIdentifier =
  1022. MOUSE_BUS_HARDWARE;
  1023. break;
  1024. } else {
  1025. BusPrint((
  1026. 1,
  1027. "BusConfiguration: IoQueryDeviceDescription for bus type %d failed\n",
  1028. interfaceType
  1029. ));
  1030. }
  1031. }
  1032. BusPrint((2, "BusConfiguration: Exit\n"));
  1033. }
  1034. VOID
  1035. BusDisableInterrupts(
  1036. IN PVOID Context
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine is called from StartIo synchronously. It touches the
  1041. hardware to disable interrupts.
  1042. Arguments:
  1043. Context - Pointer to the device extension.
  1044. Return Value:
  1045. None.
  1046. --*/
  1047. {
  1048. PUCHAR port;
  1049. PLONG enableCount;
  1050. //
  1051. // Decrement the reference count for device enables.
  1052. //
  1053. enableCount = &((PDEVICE_EXTENSION) Context)->MouseEnableCount;
  1054. *enableCount = *enableCount - 1;
  1055. if (*enableCount == 0) {
  1056. //
  1057. // Get the port register address.
  1058. //
  1059. port = ((PDEVICE_EXTENSION) Context)->Configuration.DeviceRegisters[0];
  1060. //
  1061. // Disable the interrupts
  1062. //
  1063. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE,
  1064. BUS_CONTROL_INTERRUPT_DISABLE);
  1065. }
  1066. }
  1067. VOID
  1068. BusEnableInterrupts(
  1069. IN PVOID Context
  1070. )
  1071. /*++
  1072. Routine Description:
  1073. This routine is called from StartIo synchronously. It touches the
  1074. hardware to enable interrupts.
  1075. Arguments:
  1076. Context - Pointer to the device extension.
  1077. Return Value:
  1078. None.
  1079. --*/
  1080. {
  1081. PUCHAR port;
  1082. PLONG enableCount;
  1083. enableCount = &((PDEVICE_EXTENSION) Context)->MouseEnableCount;
  1084. if (*enableCount == 0) {
  1085. //
  1086. // Get the port register address.
  1087. //
  1088. port = ((PDEVICE_EXTENSION) Context)->Configuration.DeviceRegisters[0];
  1089. //
  1090. // Enable the interrupts
  1091. //
  1092. WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, 0);
  1093. }
  1094. //
  1095. // Increment the reference count for device enables.
  1096. //
  1097. *enableCount = *enableCount + 1;
  1098. }
  1099. NTSTATUS
  1100. BusInitializeHardware(
  1101. IN PDEVICE_OBJECT DeviceObject
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. This routine initializes the Bus mouse. Note that this routine is
  1106. only called at initialization time, so synchronization is not required.
  1107. Arguments:
  1108. DeviceObject - Pointer to the device object.
  1109. Return Value:
  1110. None.
  1111. --*/
  1112. {
  1113. PDEVICE_EXTENSION deviceExtension;
  1114. PUCHAR mousePort;
  1115. BusPrint((2, "BusInitializeHardware: enter\n"));
  1116. //
  1117. // Grab useful configuration parameters from the device extension.
  1118. //
  1119. deviceExtension = DeviceObject->DeviceExtension;
  1120. mousePort = deviceExtension->Configuration.DeviceRegisters[0];
  1121. BusPrint((2, "BusInitializeHardware: Port base value is: 0x%x\n", (int)mousePort));
  1122. //
  1123. // Turn the bus interrupts off (in case).
  1124. //
  1125. WRITE_PORT_UCHAR((PUCHAR) mousePort + BUS_CONTROL_PORT_WRITE,
  1126. BUS_CONTROL_INTERRUPT_DISABLE);
  1127. //
  1128. // Configure the controller.
  1129. //
  1130. // WRITE_PORT_UCHAR((PUCHAR) mousePort + BUS_CONFIGURATION_PORT_READ_WRITE,
  1131. // BUS_CONFIGURATION_VALUE);
  1132. //
  1133. // Initialize the state of the mouse buttons.
  1134. //
  1135. deviceExtension->PreviousButtons = 0;
  1136. BusPrint((2, "BusInitializeHardware: exit\n"));
  1137. return(STATUS_SUCCESS);
  1138. }
  1139. NTSTATUS
  1140. BusPeripheralCallout(
  1141. IN PVOID Context,
  1142. IN PUNICODE_STRING PathName,
  1143. IN INTERFACE_TYPE BusType,
  1144. IN ULONG BusNumber,
  1145. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  1146. IN CONFIGURATION_TYPE ControllerType,
  1147. IN ULONG ControllerNumber,
  1148. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  1149. IN CONFIGURATION_TYPE PeripheralType,
  1150. IN ULONG PeripheralNumber,
  1151. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. This is the callout routine sent as a parameter to
  1156. IoQueryDeviceDescription. It grabs the pointer controller and
  1157. peripheral configuration information.
  1158. Arguments:
  1159. Context - Context parameter that was passed in by the routine
  1160. that called IoQueryDeviceDescription.
  1161. PathName - The full pathname for the registry key.
  1162. BusType - Bus interface type (Isa, Eisa, Mca, etc.).
  1163. BusNumber - The bus sub-key (0, 1, etc.).
  1164. BusInformation - Pointer to the array of pointers to the full value
  1165. information for the bus.
  1166. ControllerType - The controller type (should be PointerController).
  1167. ControllerNumber - The controller sub-key (0, 1, etc.).
  1168. ControllerInformation - Pointer to the array of pointers to the full
  1169. value information for the controller key.
  1170. PeripheralType - The peripheral type (should be PointerPeripheral).
  1171. PeripheralNumber - The peripheral sub-key.
  1172. PeripheralInformation - Pointer to the array of pointers to the full
  1173. value information for the peripheral key.
  1174. Return Value:
  1175. None. If successful, will have the following side-effects:
  1176. - Sets DeviceObject->DeviceExtension->HardwarePresent.
  1177. - Sets configuration fields in
  1178. DeviceObject->DeviceExtension->Configuration.
  1179. --*/
  1180. {
  1181. PDEVICE_EXTENSION deviceExtension;
  1182. PBUS_CONFIGURATION_INFORMATION configuration;
  1183. UNICODE_STRING unicodeIdentifier;
  1184. PUCHAR controllerData;
  1185. NTSTATUS status = STATUS_SUCCESS;
  1186. ULONG i;
  1187. ULONG listCount = 0;
  1188. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
  1189. ANSI_STRING ansiString;
  1190. BOOLEAN defaultInterruptShare;
  1191. KINTERRUPT_MODE defaultInterruptMode;
  1192. BusPrint((
  1193. 1,
  1194. "BusPeripheralCallout: Enter\n"
  1195. ));
  1196. BusPrint((
  1197. 1,
  1198. "BusPeripheralCallout: Path @ 0x%x, Bus Type 0x%x, Bus Number 0x%x\n",
  1199. PathName, BusType, BusNumber
  1200. ));
  1201. BusPrint((
  1202. 1,
  1203. " Controller Type 0x%x, Controller Number 0x%x, Controller info @ 0x%x\n",
  1204. ControllerType, ControllerNumber, ControllerInformation
  1205. ));
  1206. BusPrint((
  1207. 1,
  1208. " Peripheral Type 0x%x, Peripheral Number 0x%x, Peripheral info @ 0x%x\n",
  1209. PeripheralType, PeripheralNumber, PeripheralInformation
  1210. ));
  1211. //
  1212. // Get the length of the peripheral identifier information.
  1213. //
  1214. unicodeIdentifier.Length = (USHORT)
  1215. (*(PeripheralInformation + IoQueryDeviceIdentifier))->DataLength;
  1216. //
  1217. // If we already have the configuration information for the
  1218. // mouse peripheral, or if the peripheral identifier is missing,
  1219. // just return.
  1220. //
  1221. deviceExtension = (PDEVICE_EXTENSION) Context;
  1222. if ((deviceExtension->HardwarePresent) || (unicodeIdentifier.Length == 0)){
  1223. return (status);
  1224. }
  1225. //
  1226. // Get the identifier information for the peripheral.
  1227. //
  1228. unicodeIdentifier.MaximumLength = unicodeIdentifier.Length;
  1229. unicodeIdentifier.Buffer = (PWSTR) (((PUCHAR)(*(PeripheralInformation +
  1230. IoQueryDeviceIdentifier))) +
  1231. (*(PeripheralInformation +
  1232. IoQueryDeviceIdentifier))->DataOffset);
  1233. BusPrint((
  1234. 1,
  1235. "BusPeripheralCallout: Mouse type %ws\n",
  1236. unicodeIdentifier.Buffer
  1237. ));
  1238. //
  1239. // Verify that this is a Bus mouse.
  1240. //
  1241. status = RtlUnicodeStringToAnsiString(
  1242. &ansiString,
  1243. &unicodeIdentifier,
  1244. TRUE
  1245. );
  1246. if (!NT_SUCCESS(status)) {
  1247. BusPrint((
  1248. 1,
  1249. "BusPeripheralCallout: Could not convert identifier to Ansi\n"
  1250. ));
  1251. return(status);
  1252. }
  1253. if (strstr(ansiString.Buffer, "BUS")) {
  1254. //
  1255. // There is a Bus mouse (at least a card) present.
  1256. //
  1257. deviceExtension->HardwarePresent = TRUE;
  1258. }
  1259. RtlFreeAnsiString(&ansiString);
  1260. if (!deviceExtension->HardwarePresent) {
  1261. return(status);
  1262. }
  1263. //
  1264. // Get the bus information.
  1265. //
  1266. configuration = &deviceExtension->Configuration;
  1267. configuration->InterfaceType = BusType;
  1268. configuration->BusNumber = BusNumber;
  1269. #ifdef PNP_IDENTIFY
  1270. configuration->ControllerType = ControllerType;
  1271. configuration->ControllerNumber = ControllerNumber;
  1272. configuration->PeripheralType = PeripheralType;
  1273. configuration->PeripheralNumber = PeripheralNumber;
  1274. #endif
  1275. configuration->FloatingSave = BUS_FLOATING_SAVE;
  1276. if (BusType == MicroChannel) {
  1277. defaultInterruptShare = TRUE;
  1278. defaultInterruptMode = LevelSensitive;
  1279. } else {
  1280. defaultInterruptShare = BUS_INTERRUPT_SHARE;
  1281. defaultInterruptMode = BUS_INTERRUPT_MODE;
  1282. }
  1283. //
  1284. // Look through the resource list for interrupt and port
  1285. // configuration information.
  1286. //
  1287. if ((*(ControllerInformation + IoQueryDeviceConfigurationData))->DataLength != 0){
  1288. controllerData = ((PUCHAR)(*(ControllerInformation +
  1289. IoQueryDeviceConfigurationData))) +
  1290. (*(ControllerInformation +
  1291. IoQueryDeviceConfigurationData))->DataOffset;
  1292. controllerData += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  1293. PartialResourceList);
  1294. listCount = ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->Count;
  1295. resourceDescriptor =
  1296. ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->PartialDescriptors;
  1297. for (i = 0; i < listCount; i++, resourceDescriptor++) {
  1298. switch(resourceDescriptor->Type) {
  1299. case CmResourceTypePort:
  1300. //
  1301. // Copy the port information. Note that we only expect to
  1302. // find one port range for the Bus mouse.
  1303. //
  1304. ASSERT(configuration->PortListCount == 0);
  1305. configuration->PortList[configuration->PortListCount] =
  1306. *resourceDescriptor;
  1307. configuration->PortList[configuration->PortListCount].ShareDisposition =
  1308. BUS_REGISTER_SHARE? CmResourceShareShared:
  1309. CmResourceShareDeviceExclusive;
  1310. configuration->PortListCount += 1;
  1311. break;
  1312. case CmResourceTypeInterrupt:
  1313. //
  1314. // Copy the interrupt information.
  1315. //
  1316. configuration->MouseInterrupt = *resourceDescriptor;
  1317. configuration->MouseInterrupt.ShareDisposition =
  1318. defaultInterruptShare? CmResourceShareShared :
  1319. CmResourceShareDeviceExclusive;
  1320. break;
  1321. default:
  1322. break;
  1323. }
  1324. }
  1325. }
  1326. //
  1327. // If no interrupt configuration information was found, use the
  1328. // driver defaults.
  1329. //
  1330. if (!(configuration->MouseInterrupt.Type & CmResourceTypeInterrupt)) {
  1331. BusPrint((
  1332. 1,
  1333. "BusPeripheralCallout: Using default mouse interrupt config\n"
  1334. ));
  1335. configuration->MouseInterrupt.Type = CmResourceTypeInterrupt;
  1336. configuration->MouseInterrupt.ShareDisposition =
  1337. defaultInterruptShare? CmResourceShareShared :
  1338. CmResourceShareDeviceExclusive;
  1339. configuration->MouseInterrupt.Flags =
  1340. (defaultInterruptMode == Latched)? CM_RESOURCE_INTERRUPT_LATCHED :
  1341. CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1342. configuration->MouseInterrupt.u.Interrupt.Level = MOUSE_IRQL;
  1343. configuration->MouseInterrupt.u.Interrupt.Vector = MOUSE_VECTOR;
  1344. }
  1345. BusPrint((
  1346. 1,
  1347. "BusPeripheralCallout: Mouse interrupt config --\n"
  1348. ));
  1349. BusPrint((
  1350. 1,
  1351. "%s, %s, Irq = %d\n",
  1352. configuration->MouseInterrupt.ShareDisposition == CmResourceShareShared?
  1353. "Sharable" : "NonSharable",
  1354. configuration->MouseInterrupt.Flags == CM_RESOURCE_INTERRUPT_LATCHED?
  1355. "Latched" : "Level Sensitive",
  1356. configuration->MouseInterrupt.u.Interrupt.Vector
  1357. ));
  1358. //
  1359. // If no port configuration information was found, use the
  1360. // driver defaults.
  1361. //
  1362. if (configuration->PortListCount == 0) {
  1363. //
  1364. // No port configuration information was found, so use
  1365. // the driver defaults.
  1366. //
  1367. BusPrint((
  1368. 1,
  1369. "BusPeripheralCallout: Using default port config\n"
  1370. ));
  1371. configuration->PortList[0].Type = CmResourceTypePort;
  1372. configuration->PortList[0].Flags = BUS_PORT_TYPE;
  1373. configuration->PortList[0].ShareDisposition =
  1374. BUS_REGISTER_SHARE? CmResourceShareShared:
  1375. CmResourceShareDeviceExclusive;
  1376. configuration->PortList[0].u.Port.Start.LowPart =
  1377. BUS_PHYSICAL_BASE;
  1378. configuration->PortList[0].u.Port.Start.HighPart = 0;
  1379. configuration->PortList[0].u.Port.Length = BUS_REGISTER_LENGTH;
  1380. configuration->PortListCount = 1;
  1381. }
  1382. for (i = 0; i < configuration->PortListCount; i++) {
  1383. BusPrint((
  1384. 1,
  1385. "%s, Ports 0x%x - 0x%x\n",
  1386. configuration->PortList[i].ShareDisposition
  1387. == CmResourceShareShared? "Sharable" : "NonSharable",
  1388. configuration->PortList[i].u.Port.Start.LowPart,
  1389. configuration->PortList[i].u.Port.Start.LowPart +
  1390. configuration->PortList[i].u.Port.Length - 1
  1391. ));
  1392. }
  1393. BusPrint((
  1394. 1,
  1395. "BusPeripheralCallout: Exit\n"
  1396. ));
  1397. return(status);
  1398. }
  1399. VOID
  1400. BusServiceParameters(
  1401. IN PDEVICE_EXTENSION DeviceExtension,
  1402. IN PUNICODE_STRING RegistryPath,
  1403. IN PUNICODE_STRING DeviceName
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. This routine retrieves this driver's service parameters information
  1408. from the registry.
  1409. Arguments:
  1410. DeviceExtension - Pointer to the device extension.
  1411. RegistryPath - Pointer to the null-terminated Unicode name of the
  1412. registry path for this driver.
  1413. DeviceName - Pointer to the Unicode string that will receive
  1414. the port device name.
  1415. Return Value:
  1416. None. As a side-effect, sets fields in DeviceExtension->Configuration.
  1417. --*/
  1418. {
  1419. PBUS_CONFIGURATION_INFORMATION configuration;
  1420. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  1421. UNICODE_STRING parametersPath;
  1422. OBJECT_ATTRIBUTES parametersAttributes;
  1423. ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
  1424. ULONG numberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
  1425. USHORT defaultNumberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
  1426. ULONG sampleRate = MOUSE_SAMPLE_RATE_50HZ;
  1427. UNICODE_STRING defaultUnicodeName;
  1428. NTSTATUS status = STATUS_SUCCESS;
  1429. PWSTR path = NULL;
  1430. USHORT queriesPlusOne = 4;
  1431. BusPrint((
  1432. 1,
  1433. "BusServiceParameters: Enter\n"
  1434. ));
  1435. configuration = &DeviceExtension->Configuration;
  1436. parametersPath.Buffer = NULL;
  1437. //
  1438. // Registry path is already null-terminated, so just use it.
  1439. //
  1440. path = RegistryPath->Buffer;
  1441. if (NT_SUCCESS(status)) {
  1442. //
  1443. // Allocate the Rtl query table.
  1444. //
  1445. parameters = ExAllocatePool(
  1446. PagedPool,
  1447. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
  1448. );
  1449. if (!parameters) {
  1450. BusPrint((
  1451. 1,
  1452. "BusServiceParameters: Couldn't allocate table for Rtl query to parameters for %ws\n",
  1453. path
  1454. ));
  1455. status = STATUS_UNSUCCESSFUL;
  1456. } else {
  1457. RtlZeroMemory(
  1458. parameters,
  1459. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
  1460. );
  1461. //
  1462. // Form a path to this driver's Parameters subkey.
  1463. //
  1464. RtlInitUnicodeString(
  1465. &parametersPath,
  1466. NULL
  1467. );
  1468. parametersPath.MaximumLength = RegistryPath->Length +
  1469. sizeof(L"\\Parameters");
  1470. parametersPath.Buffer = ExAllocatePool(
  1471. PagedPool,
  1472. parametersPath.MaximumLength
  1473. );
  1474. if (!parametersPath.Buffer) {
  1475. BusPrint((
  1476. 1,
  1477. "BusServiceParameters: Couldn't allocate string for path to parameters for %ws\n",
  1478. path
  1479. ));
  1480. status = STATUS_UNSUCCESSFUL;
  1481. }
  1482. }
  1483. }
  1484. if (NT_SUCCESS(status)) {
  1485. //
  1486. // Form the parameters path.
  1487. //
  1488. RtlZeroMemory(
  1489. parametersPath.Buffer,
  1490. parametersPath.MaximumLength
  1491. );
  1492. RtlAppendUnicodeToString(
  1493. &parametersPath,
  1494. path
  1495. );
  1496. RtlAppendUnicodeToString(
  1497. &parametersPath,
  1498. L"\\Parameters"
  1499. );
  1500. BusPrint((
  1501. 1,
  1502. "BusServiceParameters: parameters path is %ws\n",
  1503. parametersPath.Buffer
  1504. ));
  1505. //
  1506. // Form the default pointer port device name, in case it is not
  1507. // specified in the registry.
  1508. //
  1509. RtlInitUnicodeString(
  1510. &defaultUnicodeName,
  1511. DD_POINTER_PORT_BASE_NAME_U
  1512. );
  1513. //
  1514. // Gather all of the "user specified" information from
  1515. // the registry.
  1516. //
  1517. parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1518. parameters[0].Name = L"MouseDataQueueSize";
  1519. parameters[0].EntryContext =
  1520. &configuration->MouseAttributes.InputDataQueueLength;
  1521. parameters[0].DefaultType = REG_DWORD;
  1522. parameters[0].DefaultData = &defaultDataQueueSize;
  1523. parameters[0].DefaultLength = sizeof(ULONG);
  1524. parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1525. parameters[1].Name = L"NumberOfButtons";
  1526. parameters[1].EntryContext = &numberOfButtons;
  1527. parameters[1].DefaultType = REG_DWORD;
  1528. parameters[1].DefaultData = &defaultNumberOfButtons;
  1529. parameters[1].DefaultLength = sizeof(USHORT);
  1530. parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1531. parameters[2].Name = L"PointerDeviceBaseName";
  1532. parameters[2].EntryContext = DeviceName;
  1533. parameters[2].DefaultType = REG_SZ;
  1534. parameters[2].DefaultData = defaultUnicodeName.Buffer;
  1535. parameters[2].DefaultLength = 0;
  1536. status = RtlQueryRegistryValues(
  1537. RTL_REGISTRY_ABSOLUTE,
  1538. parametersPath.Buffer,
  1539. parameters,
  1540. NULL,
  1541. NULL
  1542. );
  1543. if (!NT_SUCCESS(status)) {
  1544. BusPrint((
  1545. 1,
  1546. "BusServiceParameters: RtlQueryRegistryValues failed with 0x%x\n",
  1547. status
  1548. ));
  1549. }
  1550. }
  1551. if (!NT_SUCCESS(status)) {
  1552. //
  1553. // Go ahead and assign driver defaults.
  1554. //
  1555. configuration->MouseAttributes.InputDataQueueLength =
  1556. defaultDataQueueSize;
  1557. RtlCopyUnicodeString(DeviceName, &defaultUnicodeName);
  1558. }
  1559. BusPrint((
  1560. 1,
  1561. "BusServiceParameters: Pointer port base name = %ws\n",
  1562. DeviceName->Buffer
  1563. ));
  1564. if (configuration->MouseAttributes.InputDataQueueLength == 0) {
  1565. BusPrint((
  1566. 1,
  1567. "BusServiceParameters: overriding MouseInputDataQueueLength = 0x%x\n",
  1568. configuration->MouseAttributes.InputDataQueueLength
  1569. ));
  1570. configuration->MouseAttributes.InputDataQueueLength =
  1571. defaultDataQueueSize;
  1572. }
  1573. configuration->MouseAttributes.InputDataQueueLength *=
  1574. sizeof(MOUSE_INPUT_DATA);
  1575. BusPrint((
  1576. 1,
  1577. "BusServiceParameters: MouseInputDataQueueLength = 0x%x\n",
  1578. configuration->MouseAttributes.InputDataQueueLength
  1579. ));
  1580. configuration->MouseAttributes.NumberOfButtons = (USHORT) numberOfButtons;
  1581. BusPrint((
  1582. 1,
  1583. "BusServiceParameters: NumberOfButtons = %d\n",
  1584. configuration->MouseAttributes.NumberOfButtons
  1585. ));
  1586. configuration->MouseAttributes.SampleRate = (USHORT) sampleRate;
  1587. BusPrint((
  1588. 1,
  1589. "BusServiceParameters: SampleRate = %d\n",
  1590. configuration->MouseAttributes.SampleRate
  1591. ));
  1592. //
  1593. // Free the allocated memory before returning.
  1594. //
  1595. if (parametersPath.Buffer)
  1596. ExFreePool(parametersPath.Buffer);
  1597. if (parameters)
  1598. ExFreePool(parameters);
  1599. BusPrint((
  1600. 1,
  1601. "BusServiceParameters: Exit\n"
  1602. ));
  1603. }
  1604. #endif