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.

1051 lines
29 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This module contains general PnP and Power code for the console fullscreen driver.
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "fsvga.h"
  13. VOID
  14. FsVgaDriverUnload(
  15. IN PDRIVER_OBJECT DriverObject
  16. )
  17. /*++
  18. Routine Description:
  19. This routine called when this driver is about to be unloaded. In
  20. previous versions of NT, this function would have gone through the list of
  21. DEV)CEOBJECTS belonging to this driver in order to delete each one. That
  22. function now happens (if it needs to) in response to IRP_MN_REMOVE_DEVICE
  23. PnP IRP's.
  24. ++*/
  25. {
  26. FsVgaPrint((2,"FSVGA-FsVgaDriverUnload:\n"));
  27. ExFreePool(Globals.RegistryPath.Buffer);
  28. }
  29. NTSTATUS
  30. FsVgaAddDevice(
  31. IN PDRIVER_OBJECT DriverObject,
  32. IN PDEVICE_OBJECT pdo
  33. )
  34. /*++
  35. Routine Description:
  36. This routine called when the Configuration Manager detects (or gets told about
  37. via the New Hardware Wizard) a new device for which this module is the driver.
  38. Its main purpose is to create a functional device object (FDO) and to layer the
  39. FDO into the stack of device objects.
  40. ++*/
  41. {
  42. NTSTATUS status = STATUS_SUCCESS;
  43. PDEVICE_OBJECT fdo;
  44. PDEVICE_EXTENSION pdx;
  45. UNICODE_STRING DeviceName;
  46. ULONG uniqueErrorValue;
  47. NTSTATUS errorCode = STATUS_SUCCESS;
  48. ULONG dumpCount = 0;
  49. ULONG dumpData[DUMP_COUNT];
  50. FsVgaPrint((2,"FSVGA-FsVgaAddDevice: enter\n"));
  51. //
  52. // Create a functional device object to represent the hardware we're managing.
  53. //
  54. RtlInitUnicodeString(&DeviceName, DD_FULLSCREEN_VIDEO_DEVICE_NAME);
  55. status = IoCreateDevice(DriverObject,
  56. sizeof(DEVICE_EXTENSION),
  57. &DeviceName,
  58. FILE_DEVICE_FULLSCREEN_VIDEO,
  59. 0,
  60. TRUE,
  61. &fdo);
  62. if (!NT_SUCCESS(status)) {
  63. FsVgaPrint((1,
  64. "FSVGA-FsVgaAddDevice: Couldn't create device object\n"));
  65. status = STATUS_UNSUCCESSFUL;
  66. errorCode = FSVGA_INSUFFICIENT_RESOURCES;
  67. uniqueErrorValue = FSVGA_ERROR_VALUE_BASE + 2;
  68. dumpData[0] = 0;
  69. dumpCount = 1;
  70. goto FsVgaAddDeviceExit;
  71. }
  72. pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  73. pdx->DeviceObject = fdo;
  74. pdx->usage = 1; // locked until RemoveDevice
  75. KeInitializeEvent(&pdx->evRemove, NotificationEvent, FALSE); // set when use count drops to zero
  76. //
  77. // Since we must pass PNP requests down to the next device object in the chain
  78. // (namely the physical device object created by the bus enumerator), we have
  79. // to remember what that device is. That's why we defined the LowerDeviceObject
  80. // member in our deviceextension.
  81. //
  82. pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
  83. //
  84. // Monolithic kernel-mode drivers usually create device objects during DriverEntry,
  85. // and the I/O manager automatically clears the INITIALIZING flag. Since we're
  86. // creating the object later (namely in response to PnP START_DEVICE request),
  87. // we need to clear the flag manually.
  88. //
  89. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  90. FsVgaAddDeviceExit:
  91. if (errorCode != STATUS_SUCCESS)
  92. {
  93. //
  94. // Log an error/warning message.
  95. //
  96. FsVgaLogError((fdo == NULL) ? (PVOID) DriverObject : (PVOID) fdo,
  97. errorCode,
  98. uniqueErrorValue,
  99. status,
  100. dumpData,
  101. dumpCount
  102. );
  103. }
  104. FsVgaPrint((2,"FSVGA-FsVgaAddDevice: exit\n"));
  105. return status;
  106. }
  107. NTSTATUS
  108. FsVgaDevicePnp(
  109. IN PDEVICE_OBJECT fdo,
  110. IN PIRP Irp
  111. )
  112. /*++
  113. Routine Description:
  114. This routine uses the IRP's minor function code to dispatch a handler
  115. function (like HandleStartDevice for IRP_MN_START_DEVICE) that actually
  116. handles the request. It calls DefaultPnpHandler for requests that we don't
  117. specifically need to handle.
  118. ++*/
  119. {
  120. NTSTATUS status;
  121. PIO_STACK_LOCATION stack;
  122. UCHAR MinorFunction;
  123. if (!LockDevice((PDEVICE_EXTENSION)fdo->DeviceExtension)) {
  124. return CompleteRequest(Irp, STATUS_DELETE_PENDING, 0);
  125. }
  126. stack = IoGetCurrentIrpStackLocation(Irp);
  127. ASSERT(stack->MajorFunction == IRP_MJ_PNP);
  128. switch (MinorFunction = stack->MinorFunction) {
  129. case IRP_MN_START_DEVICE:
  130. status = FsVgaPnpStartDevice(fdo, Irp);
  131. break;
  132. case IRP_MN_REMOVE_DEVICE:
  133. status = FsVgaPnpRemoveDevice(fdo, Irp);
  134. break;
  135. case IRP_MN_STOP_DEVICE:
  136. status = FsVgaPnpStopDevice(fdo, Irp);
  137. break;
  138. #ifdef RESOURCE_REQUIREMENTS
  139. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  140. status = FsVgaFilterResourceRequirements(fdo, Irp);
  141. break;
  142. #endif
  143. default:
  144. FsVgaPrint((2,"FSVGA-FsVgaDevicePnp: MinorFunction:%x\n",stack->MinorFunction));
  145. status = FsVgaDefaultPnpHandler(fdo, Irp);
  146. break;
  147. }
  148. if (MinorFunction != IRP_MN_REMOVE_DEVICE) {
  149. UnlockDevice((PDEVICE_EXTENSION)fdo->DeviceExtension);
  150. }
  151. return status;
  152. }
  153. NTSTATUS
  154. FsVgaDefaultPnpHandler(
  155. IN PDEVICE_OBJECT fdo,
  156. IN PIRP Irp
  157. )
  158. /*++
  159. Routine Description:
  160. This function sends the request down to the next lower layer and
  161. returns whatever status that generates.
  162. ++*/
  163. {
  164. PDEVICE_EXTENSION pdx;
  165. IoSkipCurrentIrpStackLocation(Irp);
  166. pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  167. return IoCallDriver(pdx->LowerDeviceObject, Irp);
  168. }
  169. NTSTATUS
  170. FsVgaPnpRemoveDevice(
  171. IN PDEVICE_OBJECT fdo,
  172. IN PIRP Irp
  173. )
  174. /*++
  175. Routine Description:
  176. This routine calls StopDevice to shut the device down, DefaultPnpHandler
  177. to pass the request down the stack, and RemoveDevice to cleanup the FDO.
  178. ++*/
  179. {
  180. NTSTATUS status;
  181. PDEVICE_EXTENSION pdx;
  182. FsVgaPrint((2,"FSVGA-FsVgaPnpRemoveDevice: enter\n"));
  183. //
  184. // Wait for any pending I/O operations to complete
  185. //
  186. pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  187. pdx->removing = TRUE;
  188. UnlockDevice(pdx); // once for LockDevice at start of dispatch
  189. UnlockDevice(pdx); // once for initialization during AddDevice
  190. KeWaitForSingleObject(&pdx->evRemove, Executive, KernelMode, FALSE, NULL);
  191. //
  192. // Do any processing required for *us* to remove the device. This
  193. // would include completing any outstanding requests, etc.
  194. //
  195. StopDevice(fdo);
  196. //
  197. // Let lower-level drivers handle this request. Ignore whatever
  198. // result eventuates.
  199. //
  200. status = FsVgaDefaultPnpHandler(fdo, Irp);
  201. //
  202. // Remove the device object
  203. //
  204. RemoveDevice(fdo);
  205. FsVgaPrint((2,"FSVGA-FsVgaPnpRemoveDevice: exit\n"));
  206. return status;
  207. }
  208. NTSTATUS
  209. FsVgaPnpStartDevice(
  210. IN PDEVICE_OBJECT fdo,
  211. IN PIRP Irp
  212. )
  213. /*++
  214. Routine Description:
  215. This routine calls ForwardAndWait to pass the IRP down the stack and
  216. StartDevice to configure the device and this driver. Then it completes the
  217. IRP.
  218. ++*/
  219. {
  220. NTSTATUS status;
  221. PIO_STACK_LOCATION stack;
  222. FsVgaPrint((2,"FSVGA-FsVgaPnpStartDevice: enter\n"));
  223. //
  224. // First let all lower-level drivers handle this request. In this particular
  225. // sample, the only lower-level driver should be the physical device created
  226. // by the bus driver, but there could theoretically be any number of intervening
  227. // bus filter devices. Those drivers may need to do some setup at this point
  228. // in time before they'll be ready to handle non-PnP IRP's.
  229. //
  230. status = ForwardAndWait(fdo, Irp);
  231. if (!NT_SUCCESS(status)) {
  232. return CompleteRequest(Irp, status, Irp->IoStatus.Information);
  233. }
  234. stack = IoGetCurrentIrpStackLocation(Irp);
  235. #if DBG
  236. {
  237. VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list);
  238. if (stack->Parameters.StartDevice.AllocatedResources != NULL) {
  239. KdPrint((" Resources:\n"));
  240. ShowResources(&stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList);
  241. }
  242. if (stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL) {
  243. KdPrint((" Translated Resources:\n"));
  244. ShowResources(&stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList);
  245. }
  246. }
  247. #endif // DBG
  248. if (stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL) {
  249. status = StartDevice(fdo,
  250. &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList);
  251. }
  252. else {
  253. PCM_PARTIAL_RESOURCE_LIST list;
  254. FsVgaPrint((1,
  255. "FSVGA-FsVgaPnpStartDevice: AllocatedResourcesTranslated is NULL\n" \
  256. "*\n* Create hardware depended IO port list.\n*\n"
  257. ));
  258. //
  259. // Create the current FsVga resource.
  260. //
  261. status = FsVgaCreateResource(&Globals.Configuration,&list);
  262. if (!NT_SUCCESS(status)) {
  263. return CompleteRequest(Irp, status, Irp->IoStatus.Information);
  264. }
  265. #if DBG
  266. {
  267. VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list);
  268. if (list != NULL) {
  269. KdPrint((" Resources:\n"));
  270. ShowResources(list);
  271. }
  272. }
  273. #endif // DBG
  274. status = StartDevice(fdo, list);
  275. }
  276. FsVgaPrint((2,"FSVGA-FsVgaPnpStartDevice: exit\n"));
  277. return CompleteRequest(Irp, status, 0);
  278. }
  279. NTSTATUS
  280. FsVgaPnpStopDevice(
  281. IN PDEVICE_OBJECT fdo,
  282. IN PIRP Irp
  283. )
  284. /*++
  285. Routine Description:
  286. We will sometimes, but not always, get a STOP_DEVICE before getting a
  287. REMOVE_DEVICE.
  288. ++*/
  289. {
  290. NTSTATUS status;
  291. FsVgaPrint((2,"FSVGA-FsVgaPnpStopDevice: enter\n"));
  292. status = FsVgaDefaultPnpHandler(fdo, Irp);
  293. StopDevice(fdo);
  294. FsVgaPrint((2,"FSVGA-FsVgaPnpStopDevice: exit\n"));
  295. return status;
  296. }
  297. #ifdef RESOURCE_REQUIREMENTS
  298. NTSTATUS
  299. FsVgaFilterResourceRequirements(
  300. IN PDEVICE_OBJECT fdo,
  301. IN PIRP Irp
  302. )
  303. /*++
  304. Routine Description:
  305. Completion routine for IRP_MN_QUERY_RESOURCE_REQUIREMENTS. This adds on the
  306. FsVga resource requirements.
  307. Arguments:
  308. fdo - Supplies the device object
  309. Irp - Supplies the IRP_MN_QUERY_RESOURCE_REQUIREMENTS Irp
  310. Return Value:
  311. NTSTATUS
  312. --*/
  313. {
  314. NTSTATUS status;
  315. PIO_RESOURCE_REQUIREMENTS_LIST OldRequirements = NULL;
  316. ULONG NewSize;
  317. PIO_RESOURCE_REQUIREMENTS_LIST NewRequirements = NULL;
  318. PIO_RESOURCE_LIST ApertureRequirements = NULL;
  319. PIO_STACK_LOCATION stack;
  320. ULONG uniqueErrorValue;
  321. NTSTATUS errorCode = STATUS_SUCCESS;
  322. ULONG dumpCount = 0;
  323. ULONG dumpData[DUMP_COUNT];
  324. FsVgaPrint((2,"FSVGA-FsVgaFilterResourceRequirements: enter\n"));
  325. stack = IoGetCurrentIrpStackLocation(Irp);
  326. OldRequirements = stack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  327. if (OldRequirements == NULL) {
  328. //
  329. // PNP helpfully passes us a NULL pointer instead of an empty resource list
  330. // when the bridge is disabled. In this case we will ignore this irp and not
  331. // add on our requirements since they are not going to be used anyway.
  332. //
  333. FsVgaPrint((3,"FSVGA-FsVgaFilterResourceRequirements: OldRequirements is NULL\n"));
  334. }
  335. //
  336. // Get the current FsVga aperture.
  337. //
  338. status = FsVgaQueryAperture(&ApertureRequirements); /* , &Globals.Resource); */
  339. if (!NT_SUCCESS(status)) {
  340. status = STATUS_UNSUCCESSFUL;
  341. errorCode = FSVGA_INSUFFICIENT_RESOURCES;
  342. uniqueErrorValue = FSVGA_ERROR_VALUE_BASE + 2;
  343. dumpData[0] = 0;
  344. dumpCount = 1;
  345. goto FsVgaFilterResourceRequirementsExit;
  346. }
  347. //
  348. // We will add IO_RESOURCE_DESCRIPTORs to each alternative.
  349. //
  350. // Following this is the requirements returned from FsVgaQueryAperture. These
  351. // get marked as alternatives.
  352. //
  353. if (OldRequirements) {
  354. NewSize = OldRequirements->ListSize +
  355. ApertureRequirements->Count * OldRequirements->AlternativeLists * sizeof(IO_RESOURCE_DESCRIPTOR);
  356. }
  357. else {
  358. NewSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  359. (ApertureRequirements->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR);
  360. }
  361. NewRequirements = ExAllocatePool(PagedPool, NewSize);
  362. if (NewRequirements == NULL) {
  363. status = STATUS_UNSUCCESSFUL;
  364. errorCode = FSVGA_INSUFFICIENT_RESOURCES;
  365. uniqueErrorValue = FSVGA_ERROR_VALUE_BASE + 2;
  366. dumpData[0] = 0;
  367. dumpCount = 1;
  368. goto FsVgaFilterResourceRequirementsExit;
  369. }
  370. RtlZeroMemory(NewRequirements, NewSize);
  371. NewRequirements->ListSize = NewSize;
  372. if (OldRequirements) {
  373. NewRequirements->InterfaceType = OldRequirements->InterfaceType;
  374. NewRequirements->BusNumber = OldRequirements->BusNumber;
  375. NewRequirements->SlotNumber = OldRequirements->SlotNumber;
  376. NewRequirements->AlternativeLists = OldRequirements->AlternativeLists;
  377. }
  378. else {
  379. NewRequirements->InterfaceType = Globals.Resource.InterfaceType;
  380. NewRequirements->BusNumber = Globals.Resource.BusNumber;
  381. NewRequirements->SlotNumber = 0;
  382. NewRequirements->AlternativeLists = 1;
  383. }
  384. //
  385. // Append our requirement to each alternative resource list.
  386. //
  387. if (OldRequirements) {
  388. PIO_RESOURCE_LIST OldResourceList;
  389. PIO_RESOURCE_LIST NewResourceList;
  390. ULONG Alternative;
  391. OldResourceList = &OldRequirements->List[0];
  392. NewResourceList = &NewRequirements->List[0];
  393. for (Alternative = 0; Alternative < OldRequirements->AlternativeLists; Alternative++) {
  394. PIO_RESOURCE_DESCRIPTOR Descriptor;
  395. ULONG i;
  396. //
  397. // Copy the old resource list into the new one.
  398. //
  399. NewResourceList->Version = OldResourceList->Version;
  400. NewResourceList->Revision = OldResourceList->Revision;
  401. NewResourceList->Count = OldResourceList->Count + ApertureRequirements->Count;
  402. RtlCopyMemory(&NewResourceList->Descriptors[0],
  403. &OldResourceList->Descriptors[0],
  404. OldResourceList->Count * sizeof(IO_RESOURCE_DESCRIPTOR));
  405. Descriptor = &NewResourceList->Descriptors[OldResourceList->Count];
  406. //
  407. // Append the alternatives
  408. //
  409. for (i = 0; i < ApertureRequirements->Count; i++) {
  410. //
  411. // Make sure this descriptor makes sense
  412. //
  413. ASSERT(ApertureRequirements->Descriptors[i].Flags == (CM_RESOURCE_PORT_IO));
  414. ASSERT(ApertureRequirements->Descriptors[i].Type == CmResourceTypePort);
  415. ASSERT(ApertureRequirements->Descriptors[i].ShareDisposition == CmResourceShareShared);
  416. *Descriptor = ApertureRequirements->Descriptors[i];
  417. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  418. ++Descriptor;
  419. }
  420. //
  421. // Advance to next resource list
  422. //
  423. NewResourceList = (PIO_RESOURCE_LIST)(NewResourceList->Descriptors + NewResourceList->Count);
  424. OldResourceList = (PIO_RESOURCE_LIST)(OldResourceList->Descriptors + OldResourceList->Count);
  425. }
  426. }
  427. else {
  428. PIO_RESOURCE_LIST NewResourceList;
  429. NewResourceList = &NewRequirements->List[0];
  430. NewResourceList->Version = 1;
  431. NewResourceList->Revision = 1;
  432. NewResourceList->Count = ApertureRequirements->Count;
  433. RtlCopyMemory(&NewResourceList->Descriptors[0],
  434. &ApertureRequirements->Descriptors[0],
  435. ApertureRequirements->Count * sizeof(IO_RESOURCE_DESCRIPTOR));
  436. }
  437. stack->Parameters.FilterResourceRequirements.IoResourceRequirementList = NewRequirements;
  438. Irp->IoStatus.Status = STATUS_SUCCESS;
  439. Irp->IoStatus.Information = (ULONG_PTR)NewRequirements;
  440. FsVgaFilterResourceRequirementsExit:
  441. if (errorCode != STATUS_SUCCESS)
  442. {
  443. //
  444. // Log an error/warning message.
  445. //
  446. FsVgaLogError(fdo,
  447. errorCode,
  448. uniqueErrorValue,
  449. status,
  450. dumpData,
  451. dumpCount
  452. );
  453. }
  454. if (NT_SUCCESS(status)) {
  455. status = FsVgaDefaultPnpHandler(fdo, Irp);
  456. }
  457. else {
  458. status = CompleteRequest(Irp, status, 0);
  459. }
  460. if (OldRequirements)
  461. ExFreePool(OldRequirements);
  462. if (ApertureRequirements)
  463. ExFreePool(ApertureRequirements);
  464. FsVgaPrint((2,"FSVGA-FsVgaFilterResourceRequirements: exit (status=%x)\n", status));
  465. return status;
  466. }
  467. #endif
  468. NTSTATUS
  469. FsVgaDevicePower(
  470. IN PDEVICE_OBJECT fdo,
  471. IN PIRP Irp
  472. )
  473. /*++
  474. Routine Description:
  475. This routine uses the IRP's minor function code to dispatch a handler
  476. function (such as HandleSetPower for IRP_MN_SET_POWER). It calls DefaultPowerHandler
  477. for any function we don't specifically need to handle.
  478. ++*/
  479. {
  480. NTSTATUS status;
  481. PIO_STACK_LOCATION stack;
  482. if (!LockDevice((PDEVICE_EXTENSION)fdo->DeviceExtension)) {
  483. return CompleteRequest(Irp, STATUS_DELETE_PENDING, 0);
  484. }
  485. stack = IoGetCurrentIrpStackLocation(Irp);
  486. ASSERT(stack->MajorFunction = IRP_MJ_POWER);
  487. switch (stack->MinorFunction) {
  488. default:
  489. status = FsVgaDefaultPowerHandler(fdo, Irp);
  490. break;
  491. }
  492. UnlockDevice((PDEVICE_EXTENSION)fdo->DeviceExtension);
  493. return status;
  494. }
  495. NTSTATUS
  496. FsVgaDefaultPowerHandler(
  497. IN PDEVICE_OBJECT fdo,
  498. IN PIRP Irp
  499. )
  500. /*++
  501. Routine Description:
  502. This function forwards a POWER IRP to the next driver using the
  503. special PoCallDriver function
  504. ++*/
  505. {
  506. PDEVICE_EXTENSION pdx;
  507. FsVgaPrint((2,"FSVGA-FsVgaDefaultPowerHandler: enter\n"));
  508. PoStartNextPowerIrp(Irp); // must be done while we own the IRP
  509. IoSkipCurrentIrpStackLocation(Irp);
  510. pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  511. FsVgaPrint((2,"FSVGA-FsVgaDefaultPowerHandler: exit\n"));
  512. return PoCallDriver(pdx->LowerDeviceObject, Irp);
  513. }
  514. NTSTATUS
  515. CompleteRequest(
  516. IN PIRP Irp,
  517. IN NTSTATUS status,
  518. IN ULONG info
  519. )
  520. /*++
  521. Routine Description:
  522. ++*/
  523. {
  524. Irp->IoStatus.Status = status;
  525. Irp->IoStatus.Information = info;
  526. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  527. return status;
  528. }
  529. NTSTATUS
  530. ForwardAndWait(
  531. IN PDEVICE_OBJECT fdo,
  532. IN PIRP Irp
  533. )
  534. /*++
  535. Routine Description:
  536. The processor must be at PASSIVE IRQL because this function initializes
  537. and waits for non-zero time on a kernel event object.
  538. The only purpose of this routine in this particular driver is to pass down
  539. IRP_MN_START_DEVICE requests and wait for the PDO to handle them.
  540. ++*/
  541. {
  542. KEVENT event;
  543. NTSTATUS status;
  544. PDEVICE_EXTENSION pdx;
  545. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  546. // Initialize a kernel event object to use in waiting for the lower-level
  547. // driver to finish processing the object. It's a little known fact that the
  548. // kernel stack *can* be paged, but only while someone is waiting in user mode
  549. // for an event to finish. Since neither we nor a completion routine can be in
  550. // the forbidden state, it's okay to put the event object on the stack.
  551. KeInitializeEvent(&event, NotificationEvent, FALSE);
  552. IoCopyCurrentIrpStackLocationToNext(Irp);
  553. IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)OnRequestComplete,
  554. (PVOID)&event, TRUE, TRUE, TRUE);
  555. pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  556. status = IoCallDriver(pdx->LowerDeviceObject, Irp);
  557. if (status == STATUS_PENDING) {
  558. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  559. status = Irp->IoStatus.Status;
  560. }
  561. return status;
  562. }
  563. NTSTATUS
  564. OnRequestComplete(
  565. IN PDEVICE_OBJECT fdo,
  566. IN PIRP Irp,
  567. IN PKEVENT pev
  568. )
  569. /*++
  570. Routine Description:
  571. This is the completion routine used for requests forwarded by ForwardAndWait. It
  572. sets the event object and thereby awakens ForwardAndWait.
  573. Note that it's *not* necessary for this particular completion routine to test
  574. the PendingReturned flag in the IRP and then call IoMarkIrpPending. You do that in many
  575. completion routines because the dispatch routine can't know soon enough that the
  576. lower layer has returned STATUS_PENDING. In our case, we're never going to pass a
  577. STATUS_PENDING back up the driver chain, so we don't need to worry about this.
  578. ++*/
  579. {
  580. KeSetEvent(pev, 0, FALSE);
  581. return STATUS_MORE_PROCESSING_REQUIRED;
  582. }
  583. VOID
  584. RemoveDevice(
  585. IN PDEVICE_OBJECT fdo
  586. )
  587. /*++
  588. Routine Description:
  589. Whereas AddDevice gets called by the I/O manager directly, this
  590. function is called in response to a PnP request with the minor function code
  591. of IRP_MN_REMOVE_DEVICE.
  592. ++*/
  593. {
  594. NTSTATUS status;
  595. PDEVICE_EXTENSION pdx;
  596. pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  597. if (pdx->LowerDeviceObject) {
  598. IoDetachDevice(pdx->LowerDeviceObject);
  599. }
  600. IoDeleteDevice(fdo);
  601. }
  602. BOOLEAN
  603. LockDevice(
  604. IN PDEVICE_EXTENSION pdx
  605. )
  606. /*++
  607. Routine Description:
  608. A FALSE return value indicates that we're in the process of deleting
  609. the device object, so all new requests should be failed
  610. ++*/
  611. {
  612. LONG usage;
  613. //
  614. // Increment use count on our device object
  615. //
  616. usage = InterlockedIncrement(&pdx->usage);
  617. //
  618. // AddDevice initialized the use count to 1, so it ought to be bigger than
  619. // one now. HandleRemoveDevice sets the "removing" flag and decrements the
  620. // use count, possibly to zero. So if we find a use count of "1" now, we
  621. // should also find the "removing" flag set.
  622. //
  623. ASSERT(usage > 1 || pdx->removing);
  624. //
  625. // If device is about to be removed, restore the use count and return FALSE.
  626. // If we're in a race with HandleRemoveDevice (maybe running on another CPU),
  627. // the sequence we've followed is guaranteed to avoid a mistaken deletion of
  628. // the device object. If we test "removing" after HandleRemoveDevice sets it,
  629. // we'll restore the use count and return FALSE. In the meantime, if
  630. // HandleRemoveDevice decremented the count to 0 before we did our increment,
  631. // its thread will have set the remove event. Otherwise, we'll decrement to 0
  632. // and set the event. Either way, HandleRemoveDevice will wake up to finish
  633. // removing the device, and we'll return FALSE to our caller.
  634. //
  635. // If, on the other hand, we test "removing" before HandleRemoveDevice sets it,
  636. // we'll have already incremented the use count past 1 and will return TRUE.
  637. // Our caller will eventually call UnlockDevice, which will decrement the use
  638. // count and might set the event HandleRemoveDevice is waiting on at that point.
  639. //
  640. if (pdx->removing) {
  641. if (InterlockedDecrement(&pdx->usage) == 0) {
  642. KeSetEvent(&pdx->evRemove, 0, FALSE);
  643. }
  644. return FALSE;
  645. }
  646. return TRUE;
  647. }
  648. VOID
  649. UnlockDevice(
  650. IN PDEVICE_EXTENSION pdx
  651. )
  652. /*++
  653. Routine Description:
  654. If the use count drops to zero, set the evRemove event because we're
  655. about to remove this device object.
  656. ++*/
  657. {
  658. LONG usage;
  659. usage = InterlockedDecrement(&pdx->usage);
  660. ASSERT(usage >= 0);
  661. if (usage == 0) {
  662. ASSERT(pdx->removing); // HandleRemoveDevice should already have set this
  663. KeSetEvent(&pdx->evRemove, 0, FALSE);
  664. }
  665. }
  666. NTSTATUS
  667. StartDevice(
  668. IN PDEVICE_OBJECT fdo,
  669. IN PCM_PARTIAL_RESOURCE_LIST list
  670. )
  671. /*++
  672. Routine Description:
  673. This function is called by the dispatch routine for IRP_MN_START_DEVICE
  674. in order to determine the configuration for the device and to prepare the driver
  675. and the device for subsequent operation.
  676. ++*/
  677. {
  678. NTSTATUS status;
  679. PDEVICE_EXTENSION pdx;
  680. PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
  681. ULONG i;
  682. FsVgaPrint((2,"FSVGA-StartDevice: enter\n"));
  683. pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  684. ASSERT(!pdx->started);
  685. RtlZeroMemory(&pdx->Resource.PortList, sizeof(pdx->Resource.PortList));
  686. // Identify the I/O resources we're supposed to use. In previous versions
  687. // of NT, this required nearly heroic efforts that were highly bus dependent.
  688. resource = list->PartialDescriptors;
  689. for (i = 0; i < list->Count; ++i, ++resource) {
  690. ULONG port;
  691. switch (resource->Type) {
  692. case CmResourceTypePort:
  693. switch (resource->u.Port.Start.QuadPart) {
  694. case VGA_BASE_IO_PORT + CRTC_ADDRESS_PORT_COLOR:
  695. port = CRTCAddressPortColor; break;
  696. case VGA_BASE_IO_PORT + CRTC_DATA_PORT_COLOR:
  697. port = CRTCDataPortColor; break;
  698. case VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT:
  699. port = GRAPHAddressPort; break;
  700. case VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT:
  701. port = SEQAddressPort; break;
  702. default:
  703. port = -1;
  704. FsVgaPrint((1,"FSVGA-StartDevice: CmResourceTypePort: Unknown port address %x\n", resource->u.Port.Start.LowPart));
  705. break;
  706. }
  707. if (port != -1) {
  708. if (resource->Flags & CM_RESOURCE_PORT_IO) {
  709. pdx->Resource.PortList[port].Port =
  710. (PUCHAR)resource->u.Port.Start.LowPart;
  711. pdx->Resource.PortList[port].MapRegistersRequired = FALSE;
  712. }
  713. else {
  714. pdx->Resource.PortList[port].Port =
  715. (PUCHAR)MmMapIoSpace(resource->u.Port.Start,
  716. resource->u.Port.Length,
  717. MmNonCached);
  718. pdx->Resource.PortList[port].Length = resource->u.Port.Length;
  719. pdx->Resource.PortList[port].MapRegistersRequired = TRUE;
  720. }
  721. }
  722. break;
  723. default:
  724. FsVgaPrint((1,"FSVGA-StartDevice: Unknown resource type %x\n", resource->Type));
  725. break;
  726. }
  727. }
  728. pdx->started = TRUE;
  729. FsVgaPrint((2,"FSVGA-StartDevice: exit\n"));
  730. return STATUS_SUCCESS;
  731. }
  732. VOID
  733. StopDevice(
  734. IN PDEVICE_OBJECT fdo
  735. )
  736. /*++
  737. Routine Description:
  738. This function is called by the dispatch routine for IRP_MN_STOP_DEVICE
  739. in order to undo everything that was done inside StartDevice.
  740. ++*/
  741. {
  742. ULONG i;
  743. PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  744. if (!pdx->started)
  745. return;
  746. pdx->started = FALSE;
  747. for (i=0; i < MaximumPortCount; i++) {
  748. if (pdx->Resource.PortList[i].MapRegistersRequired) {
  749. MmUnmapIoSpace(pdx->Resource.PortList[i].Port,
  750. pdx->Resource.PortList[i].Length);
  751. }
  752. }
  753. }
  754. #if DBG
  755. // @func List PnP resources assigned to our device
  756. // @parm List of resource descriptors to display
  757. // @comm Used only in the checked build of the driver
  758. #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
  759. VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list)
  760. { // ShowResources
  761. PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
  762. ULONG nres;
  763. ULONG i;
  764. if (list == NULL)
  765. return;
  766. resource = list->PartialDescriptors;
  767. if (resource == NULL)
  768. return;
  769. nres = list->Count;
  770. for (i = 0; i < nres; ++i, ++resource)
  771. { // for each resource
  772. ULONG type = resource->Type;
  773. static char* name[] = {
  774. "CmResourceTypeNull",
  775. "CmResourceTypePort",
  776. "CmResourceTypeInterrupt",
  777. "CmResourceTypeMemory",
  778. "CmResourceTypeDma",
  779. "CmResourceTypeDeviceSpecific",
  780. "CmResourceTypeBusNumber",
  781. "CmResourceTypeDevicePrivate",
  782. "CmResourceTypeAssignedResource",
  783. "CmResourceTypeSubAllocateFrom",
  784. };
  785. KdPrint((" type %s", type < arraysize(name) ? name[type] : "unknown"));
  786. switch (type)
  787. { // select on resource type
  788. case CmResourceTypePort:
  789. case CmResourceTypeMemory:
  790. KdPrint((" start %8X%8.8lX length %X\n",
  791. resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
  792. resource->u.Port.Length));
  793. break;
  794. case CmResourceTypeInterrupt:
  795. KdPrint((" level %X, vector %X, affinity %X\n",
  796. resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
  797. resource->u.Interrupt.Affinity));
  798. break;
  799. case CmResourceTypeDma:
  800. KdPrint((" channel %d, port %X\n",
  801. resource->u.Dma.Channel, resource->u.Dma.Port));
  802. } // select on resource type
  803. } // for each resource
  804. } // ShowResources
  805. #endif // DBG