Leaked source code of windows server 2003
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.

2510 lines
55 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. ops.c
  5. Abstract:
  6. video port stub routines for memory and io.
  7. Author:
  8. Andre Vachon (andreva) 22-Feb-1997
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. This module is a driver which implements OS dependant functions on the
  13. behalf of the video drivers
  14. Revision History:
  15. --*/
  16. #include "videoprt.h"
  17. #pragma alloc_text(PAGE,VideoPortGetAssociatedDeviceExtension)
  18. #pragma alloc_text(PAGE,VideoPortGetAssociatedDeviceID)
  19. #pragma alloc_text(PAGE,VideoPortAcquireDeviceLock)
  20. #pragma alloc_text(PAGE,VideoPortReleaseDeviceLock)
  21. #pragma alloc_text(PAGE,VideoPortGetRomImage)
  22. #pragma alloc_text(PAGE,VpGetBusInterface)
  23. #pragma alloc_text(PAGE,VideoPortGetVgaStatus)
  24. #pragma alloc_text(PAGE,pVideoPortGetVgaStatusPci)
  25. #pragma alloc_text(PAGE,VideoPortCheckForDeviceExistence)
  26. #pragma alloc_text(PAGE,VpGetDeviceCount)
  27. #pragma alloc_text(PAGE,VideoPortRegisterBugcheckCallback)
  28. #pragma alloc_text(PAGE,VpAllocateNonPagedPoolPageAligned)
  29. #pragma alloc_text(PAGE,VpAcquireLock)
  30. #pragma alloc_text(PAGE,VpReleaseLock)
  31. #pragma alloc_text(PAGE,pVpGeneralBugcheckHandler)
  32. //
  33. //ULONG
  34. //VideoPortCompareMemory (
  35. // PVOID Source1,
  36. // PVOID Source2,
  37. // ULONG Length
  38. // )
  39. //Forwarded to RtlCompareMemory(Source1,Source2,Length);
  40. //
  41. VP_STATUS
  42. VideoPortDisableInterrupt(
  43. IN PVOID HwDeviceExtension
  44. )
  45. /*++
  46. Routine Description:
  47. VideoPortDisableInterrupt allows a miniport driver to disable interrupts
  48. from its adapter. This means that the interrupts coming from the device
  49. will be ignored by the operating system and therefore not forwarded to
  50. the driver.
  51. A call to this function is valid only if the interrupt is defined, in
  52. other words, if the appropriate data was provided at initialization
  53. time to set up the interrupt. Interrupts will remain disabled until
  54. they are reenabled using the VideoPortEnableInterrupt function.
  55. Arguments:
  56. HwDeviceExtension - Points to the miniport driver's device extension.
  57. Return Value:
  58. NO_ERROR if the function completes successfully.
  59. ERROR_INVALID_FUNCTION if the interrupt cannot be disabled because it
  60. was not set up at initialization.
  61. --*/
  62. {
  63. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  64. //
  65. // Only perform this operation if the interurpt is actually connected.
  66. //
  67. if (fdoExtension->InterruptObject) {
  68. #if defined(_IA64_)
  69. //
  70. // The old code here would actually disable interrupts for
  71. // the device's vector on whatever processor this thread
  72. // happened to be running on. This would have a couple of
  73. // possible outcomes:
  74. //
  75. // 1) All devices on this vector would stop interrupting.
  76. // Remember that PCI and AGP require the possibility
  77. // of interrupt sharing. This might mean, for instance
  78. // that the SCSI controller would stop paging.
  79. //
  80. // 2) Some other processor would still handle interrupts
  81. // for this device, meaning that the call would be
  82. // meaningless.
  83. //
  84. // Additionally, there was no guarantee that
  85. // VidePortDisableInterrupt would be called on the same
  86. // processor as this function. So it could frequently
  87. // be the case that this vector would never be re-enabled
  88. // on this processor.
  89. //
  90. // Given all of this, I am just turning this function into
  91. // a no-op, since it can't be made to work in an architec-
  92. // turally coherent fashion. -- JakeO 11/1/2002
  93. //
  94. // Due to test limitation we disabling it just for IA64
  95. // -- OlegK 1/9/2003
  96. #else
  97. HalDisableSystemInterrupt(fdoExtension->InterruptVector,
  98. fdoExtension->InterruptIrql);
  99. #endif // defined(_IA64_)
  100. fdoExtension->InterruptsEnabled = FALSE;
  101. return NO_ERROR;
  102. } else {
  103. return ERROR_INVALID_FUNCTION;
  104. }
  105. } // VideoPortDisableInterrupt()
  106. VP_STATUS
  107. VideoPortEnableInterrupt(
  108. IN PVOID HwDeviceExtension
  109. )
  110. /*++
  111. Routine Description:
  112. VideoPortEnableInterrupt allows a miniport driver to enable interrupts
  113. from its adapter. A call to this function is valid only if the
  114. interrupt is defined, in other words, if the appropriate data was
  115. provided at initialization time to set up the interrupt.
  116. This function is used to re-enable interrupts if they have been disabled
  117. using VideoPortDisableInterrupt.
  118. Arguments:
  119. HwDeviceExtension - Points to the miniport driver's device extension.
  120. Return Value:
  121. NO_ERROR if the function completes successfully.
  122. ERROR_INVALID_FUNCTION if the interrupt cannot be disabled because it
  123. was not set up at initialization.
  124. --*/
  125. {
  126. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  127. //
  128. // Only perform this operation if the interurpt is actually connected.
  129. //
  130. if (fdoExtension->InterruptObject) {
  131. fdoExtension->InterruptsEnabled = TRUE;
  132. #if defined(_IA64_)
  133. //
  134. // The old code here would actually disable interrupts for
  135. // the device's vector on whatever processor this thread
  136. // happened to be running on. This would have a couple of
  137. // possible outcomes:
  138. //
  139. // 1) All devices on this vector would stop interrupting.
  140. // Remember that PCI and AGP require the possibility
  141. // of interrupt sharing. This might mean, for instance
  142. // that the SCSI controller would stop paging.
  143. //
  144. // 2) Some other processor would still handle interrupts
  145. // for this device, meaning that the call would be
  146. // meaningless.
  147. //
  148. // Additionally, there was no guarantee that
  149. // VidePortDisableInterrupt would be called on the same
  150. // processor as this function. So it could frequently
  151. // be the case that this vector would never be re-enabled
  152. // on this processor.
  153. //
  154. // Given all of this, I am just turning this function into
  155. // a no-op, since it can't be made to work in an architec-
  156. // turally coherent fashion. -- JakeO 11/1/2002
  157. //
  158. // Due to test limitation we disabling it just for IA64
  159. // -- OlegK 1/9/2003
  160. #else
  161. HalEnableSystemInterrupt(fdoExtension->InterruptVector,
  162. fdoExtension->InterruptIrql,
  163. fdoExtension->InterruptMode);
  164. #endif // defined(_IA64_)
  165. return NO_ERROR;
  166. } else {
  167. return ERROR_INVALID_FUNCTION;
  168. }
  169. } // VideoPortEnableInterrupt()
  170. PVOID
  171. VideoPortGetRomImage(
  172. IN PVOID HwDeviceExtension,
  173. IN PVOID Unused1,
  174. IN ULONG Unused2,
  175. IN ULONG Length
  176. )
  177. /*++
  178. Routine Description:
  179. This routine allows a miniport driver to get a copy of its devices
  180. ROM. This function returns the pointer to a buffer containing the
  181. devices ROM.
  182. Arguments;
  183. HwDeviceExtension - Points to the miniport driver's device extension.
  184. Unused1 - Reserved for future use. Must be NULL. (Buffer)
  185. Unused2 - Reserved for future use. Must be zero. (Offset)
  186. Length - Number of bytes to return.
  187. --*/
  188. {
  189. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  190. #if DBG
  191. if ((Unused1 != NULL) || (Unused2 != 0)) {
  192. pVideoDebugPrint((0,"VideoPortGetRomImage - Unused1 and Unused2 must be zero\n"));
  193. ASSERT(FALSE);
  194. return NULL;
  195. }
  196. #endif
  197. //
  198. // Each time this routine is called the previous contents of the ROM
  199. // image are dropped.
  200. //
  201. if (fdoExtension->RomImage) {
  202. ExFreePool(fdoExtension->RomImage);
  203. fdoExtension->RomImage = NULL;
  204. }
  205. //
  206. // The caller should try to grab a buffer of length zero to free
  207. // any ROM Image already returned.
  208. //
  209. if (Length == 0) {
  210. return NULL;
  211. }
  212. //
  213. // This entry point is only valid for PnP Drivers.
  214. //
  215. if (((fdoExtension->Flags & LEGACY_DRIVER) == 0) &&
  216. fdoExtension->ValidBusInterface) {
  217. NTSTATUS status;
  218. PUCHAR Buffer;
  219. ULONG len, len1;
  220. PUCHAR outputBuffer;
  221. //
  222. // Allocate memory for our buffer
  223. //
  224. Buffer = ExAllocatePoolWithTag(PagedPool,
  225. Length * sizeof(UCHAR),
  226. VP_TAG);
  227. if (!Buffer) {
  228. pVideoDebugPrint((1, "VideoPortGetRomImage - could not allocate buffer\n"));
  229. return NULL;
  230. }
  231. // Try ACPI _ROM method first
  232. outputBuffer = ExAllocatePoolWithTag(PagedPool,
  233. (0x1000 + sizeof(ACPI_EVAL_OUTPUT_BUFFER))*sizeof(UCHAR),
  234. VP_TAG);
  235. if (!outputBuffer) {
  236. ExFreePool(Buffer);
  237. pVideoDebugPrint((1, "VideoPortGetRomImage - could not allocate buffer\n"));
  238. return NULL;
  239. }
  240. for (len = 0; len < Length; len += len1)
  241. {
  242. // _ROM can transfer only 4K at one time
  243. len1 = ((Length-len) < 0x1000) ? (Length-len) : 0x1000;
  244. status = pVideoPortACPIIoctl(
  245. fdoExtension->AttachedDeviceObject,
  246. (ULONG) ('MOR_'),
  247. &len,
  248. &len1,
  249. len1+sizeof(ACPI_EVAL_OUTPUT_BUFFER),
  250. (PACPI_EVAL_OUTPUT_BUFFER) outputBuffer);
  251. if (!NT_SUCCESS(status))
  252. break;
  253. RtlCopyMemory(Buffer+len,
  254. ((PACPI_EVAL_OUTPUT_BUFFER)outputBuffer)->Argument[0].Data,
  255. len1 * sizeof(UCHAR));
  256. }
  257. ExFreePool(outputBuffer);
  258. if (NT_SUCCESS(status)) {
  259. fdoExtension->RomImage = Buffer;
  260. return Buffer;
  261. }
  262. // If ACPI _ROM method failed
  263. Length = fdoExtension->BusInterface.GetBusData(
  264. fdoExtension->BusInterface.Context,
  265. PCI_WHICHSPACE_ROM,
  266. Buffer,
  267. 0,
  268. Length);
  269. if (Length) {
  270. fdoExtension->RomImage = Buffer;
  271. return Buffer;
  272. } else {
  273. ExFreePool(Buffer);
  274. return NULL;
  275. }
  276. } else {
  277. pVideoDebugPrint((0, "VideoPortGetRomImage - not supported on legacy devices\n"));
  278. return NULL;
  279. }
  280. }
  281. ULONG
  282. VideoPortGetBusData(
  283. PVOID HwDeviceExtension,
  284. IN BUS_DATA_TYPE BusDataType,
  285. IN ULONG SlotNumber,
  286. IN PVOID Buffer,
  287. IN ULONG Offset,
  288. IN ULONG Length
  289. )
  290. {
  291. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  292. if ((fdoExtension->Flags & LEGACY_DRIVER) ||
  293. (BusDataType != PCIConfiguration)) {
  294. #if defined(NO_LEGACY_DRIVERS)
  295. pVideoDebugPrint((0, "VideoPortGetBusData: fdoExtension->Flags & LEGACY_DRIVER not supported for 64-bits.\n"));
  296. return 0;
  297. #else
  298. return HalGetBusDataByOffset(BusDataType,
  299. fdoExtension->SystemIoBusNumber,
  300. SlotNumber,
  301. Buffer,
  302. Offset,
  303. Length);
  304. #endif // NO_LEGACY_DRIVERS
  305. } else {
  306. if (fdoExtension->ValidBusInterface) {
  307. Length = fdoExtension->BusInterface.GetBusData(
  308. fdoExtension->BusInterface.Context,
  309. PCI_WHICHSPACE_CONFIG,
  310. Buffer,
  311. Offset,
  312. Length);
  313. return Length;
  314. } else {
  315. return 0;
  316. }
  317. }
  318. } // end VideoPortGetBusData()
  319. UCHAR
  320. VideoPortGetCurrentIrql(
  321. )
  322. /*++
  323. Routine Description:
  324. Stub to get Current Irql.
  325. --*/
  326. {
  327. return (KeGetCurrentIrql());
  328. } // VideoPortGetCurrentIrql()
  329. ULONG
  330. VideoPortSetBusData(
  331. PVOID HwDeviceExtension,
  332. IN BUS_DATA_TYPE BusDataType,
  333. IN ULONG SlotNumber,
  334. IN PVOID Buffer,
  335. IN ULONG Offset,
  336. IN ULONG Length
  337. )
  338. {
  339. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  340. if ((fdoExtension->Flags & LEGACY_DRIVER) ||
  341. (BusDataType != PCIConfiguration)) {
  342. #if defined(NO_LEGACY_DRIVERS)
  343. pVideoDebugPrint((0, "VideoPortSetBusData: fdoExtension->Flags & LEGACY_DRIVER not supported for 64-bits.\n"));
  344. return 0;
  345. #else
  346. return HalSetBusDataByOffset(BusDataType,
  347. fdoExtension->SystemIoBusNumber,
  348. SlotNumber,
  349. Buffer,
  350. Offset,
  351. Length);
  352. #endif // NO_LEGACY_DRIVERS
  353. } else {
  354. if (fdoExtension->ValidBusInterface) {
  355. Length = fdoExtension->BusInterface.SetBusData(
  356. fdoExtension->BusInterface.Context,
  357. PCI_WHICHSPACE_CONFIG,
  358. Buffer,
  359. Offset,
  360. Length);
  361. return Length;
  362. } else {
  363. return 0;
  364. }
  365. }
  366. } // end VideoPortSetBusData()
  367. //
  368. //VOID
  369. //VideoPortStallExecution(
  370. // IN ULONG Microseconds
  371. // )
  372. //
  373. //Forwarded to KeStallExecutionProcessor(Microseconds);
  374. //
  375. //
  376. //VOID
  377. //VideoPortMoveMemory(
  378. // IN PVOID Destination,
  379. // IN PVOID Source,
  380. // IN ULONG Length
  381. // )
  382. //
  383. //Forwarded to RtlMoveMemory(Destination,Source,Length);
  384. //
  385. //
  386. // ALL the functions to read ports and registers are forwarded on free
  387. // builds on x86 to the appropriate kernel function.
  388. // This saves time and memory
  389. //
  390. #if DBG || !defined(_X86_)
  391. UCHAR
  392. VideoPortReadPortUchar(
  393. IN PUCHAR Port
  394. )
  395. /*++
  396. Routine Description:
  397. VideoPortReadPortUchar reads a byte from the specified port address.
  398. It requires a logical port address obtained from VideoPortGetDeviceBase.
  399. Arguments:
  400. Port - Specifies the port address.
  401. Return Value:
  402. This function returns the byte read from the specified port address.
  403. --*/
  404. {
  405. UCHAR temp;
  406. temp = READ_PORT_UCHAR(Port);
  407. pVideoDebugPrint((3,"VideoPortReadPortUchar %x = %x\n", Port, temp));
  408. return(temp);
  409. } // VideoPortReadPortUchar()
  410. USHORT
  411. VideoPortReadPortUshort(
  412. IN PUSHORT Port
  413. )
  414. /*++
  415. Routine Description:
  416. VideoPortReadPortUshort reads a word from the specified port address.
  417. It requires a logical port address obtained from VideoPortGetDeviceBase.
  418. Arguments:
  419. Port - Specifies the port address.
  420. Return Value:
  421. This function returns the word read from the specified port address.
  422. --*/
  423. {
  424. USHORT temp;
  425. temp = READ_PORT_USHORT(Port);
  426. pVideoDebugPrint((3,"VideoPortReadPortUshort %x = %x\n", Port, temp));
  427. return(temp);
  428. } // VideoPortReadPortUshort()
  429. ULONG
  430. VideoPortReadPortUlong(
  431. IN PULONG Port
  432. )
  433. /*++
  434. Routine Description:
  435. VideoPortReadPortUlong reads a double word from the specified port
  436. address. It requires a logical port address obtained from
  437. VideoPortGetDeviceBase.
  438. Arguments:
  439. Port - Specifies the port address.
  440. Return Value:
  441. This function returns the double word read from the specified port address.
  442. --*/
  443. {
  444. ULONG temp;
  445. temp = READ_PORT_ULONG(Port);
  446. pVideoDebugPrint((3,"VideoPortReadPortUlong %x = %x\n", Port, temp));
  447. return(temp);
  448. } // VideoPortReadPortUlong()
  449. VOID
  450. VideoPortReadPortBufferUchar(
  451. IN PUCHAR Port,
  452. IN PUCHAR Buffer,
  453. IN ULONG Count
  454. )
  455. /*++
  456. Routine Description:
  457. VideoPortReadPortBufferUchar reads a number of bytes from a single port
  458. into a buffer. It requires a logical port address obtained from
  459. VideoPortGetDeviceBase.
  460. Arguments:
  461. Port - Specifies the port address.
  462. Buffer - Points to an array of UCHAR values into which the values are
  463. stored.
  464. Count - Specifes the number of bytes to be read into the buffer.
  465. Return Value:
  466. None.
  467. --*/
  468. {
  469. pVideoDebugPrint((3,"VideoPortReadPortBufferUchar %x\n", Port));
  470. READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
  471. } // VideoPortReadPortBufferUchar()
  472. VOID
  473. VideoPortReadPortBufferUshort(
  474. IN PUSHORT Port,
  475. IN PUSHORT Buffer,
  476. IN ULONG Count
  477. )
  478. /*++
  479. Routine Description:
  480. VideoPortReadPortBufferUshort reads a number of words from a single port
  481. into a buffer. It requires a logical port address obtained from
  482. VideoPortGetDeviceBase.
  483. Arguments:
  484. Port - Specifies the port address.
  485. Buffer - Points to an array of words into which the values are stored.
  486. Count - Specifies the number of words to be read into the buffer.
  487. Return Value:
  488. None.
  489. --*/
  490. {
  491. pVideoDebugPrint((3,"VideoPortReadPortBufferUshort %x\n", Port));
  492. READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
  493. } // VideoPortReadPortBufferUshort()
  494. VOID
  495. VideoPortReadPortBufferUlong(
  496. IN PULONG Port,
  497. IN PULONG Buffer,
  498. IN ULONG Count
  499. )
  500. /*++
  501. Routine Description:
  502. VideoPortReadPortBufferUlong reads a number of double words from a
  503. single port into a buffer. It requires a logical port address obtained
  504. from VideoPortGetDeviceBase.
  505. Arguments:
  506. Port - Specifies the port address.
  507. Buffer - Points to an array of double words into which the values are
  508. stored.
  509. Count - Specifies the number of double words to be read into the buffer.
  510. Return Value:
  511. None.
  512. --*/
  513. {
  514. pVideoDebugPrint((3,"VideoPortReadPortBufferUlong %x\n", Port));
  515. READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
  516. } // VideoPortReadPortBufferUlong()
  517. #endif
  518. //
  519. // ALL the functions to read ports and registers are forwarded on free
  520. // builds on x86 to the appropriate kernel function.
  521. // This saves time and memory
  522. //
  523. #if DBG || !defined(_X86_)
  524. UCHAR
  525. VideoPortReadRegisterUchar(
  526. IN PUCHAR Register
  527. )
  528. /*++
  529. Routine Description:
  530. VideoPortReadRegisterUchar reads a byte from the specified register
  531. address. It requires a logical port address obtained from
  532. VideoPortGetDeviceBase.
  533. Arguments:
  534. Register - Specifies the register address.
  535. Return Value:
  536. This function returns the byte read from the specified register address.
  537. --*/
  538. {
  539. UCHAR temp;
  540. temp = READ_REGISTER_UCHAR(Register);
  541. pVideoDebugPrint((3,"VideoPortReadRegisterUchar %x = %x\n", Register, temp));
  542. return(temp);
  543. } // VideoPortReadRegisterUchar()
  544. USHORT
  545. VideoPortReadRegisterUshort(
  546. IN PUSHORT Register
  547. )
  548. /*++
  549. Routine Description:
  550. VideoPortReadRegisterUshort reads a word from the specified register
  551. address. It requires a logical port address obtained from
  552. VideoPortGetDeviceBase.
  553. Arguments:
  554. Register - Specifies the register address.
  555. Return Value:
  556. This function returns the word read from the specified register address.
  557. --*/
  558. {
  559. USHORT temp;
  560. temp = READ_REGISTER_USHORT(Register);
  561. pVideoDebugPrint((3,"VideoPortReadRegisterUshort %x = %x\n", Register, temp));
  562. return(temp);
  563. } // VideoPortReadRegisterUshort()
  564. ULONG
  565. VideoPortReadRegisterUlong(
  566. IN PULONG Register
  567. )
  568. /*++
  569. Routine Description:
  570. VideoPortReadRegisterUlong reads a double word from the specified
  571. register address. It requires a logical port address obtained from
  572. VideoPortGetDeviceBase.
  573. Arguments:
  574. Register - Specifies the register address.
  575. Return Value:
  576. This function returns the double word read from the specified register
  577. address.
  578. --*/
  579. {
  580. ULONG temp;
  581. temp = READ_REGISTER_ULONG(Register);
  582. pVideoDebugPrint((3,"VideoPortReadRegisterUlong %x = %x\n", Register, temp));
  583. return(temp);
  584. } // VideoPortReadRegisterUlong()
  585. VOID
  586. VideoPortReadRegisterBufferUchar(
  587. IN PUCHAR Register,
  588. IN PUCHAR Buffer,
  589. IN ULONG Count
  590. )
  591. /*++
  592. Routine Description:
  593. Read a buffer of unsigned bytes from the specified register address.
  594. Arguments:
  595. Register - Supplies a pointer to the port address.
  596. Buffer - Supplies a pointer to the data buffer area.
  597. Count - The count of items to move.
  598. Return Value:
  599. None
  600. --*/
  601. {
  602. READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
  603. }
  604. VOID
  605. VideoPortReadRegisterBufferUshort(
  606. IN PUSHORT Register,
  607. IN PUSHORT Buffer,
  608. IN ULONG Count
  609. )
  610. /*++
  611. Routine Description:
  612. Read a buffer of unsigned shorts from the specified register address.
  613. Arguments:
  614. Register - Supplies a pointer to the port address.
  615. Buffer - Supplies a pointer to the data buffer area.
  616. Count - The count of items to move.
  617. Return Value:
  618. None
  619. --*/
  620. {
  621. READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
  622. }
  623. VOID
  624. VideoPortReadRegisterBufferUlong(
  625. IN PULONG Register,
  626. IN PULONG Buffer,
  627. IN ULONG Count
  628. )
  629. /*++
  630. Routine Description:
  631. Read a buffer of unsigned longs from the specified register address.
  632. Arguments:
  633. Register - Supplies a pointer to the port address.
  634. Buffer - Supplies a pointer to the data buffer area.
  635. Count - The count of items to move.
  636. Return Value:
  637. None
  638. --*/
  639. {
  640. READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
  641. }
  642. VOID
  643. VideoPortWritePortUchar(
  644. IN PUCHAR Port,
  645. IN UCHAR Value
  646. )
  647. /*++
  648. Routine Description:
  649. VideoPortWritePortUchar writes a byte to the specified port address. It
  650. requires a logical port address obtained from VideoPortGetDeviceBase.
  651. Arguments:
  652. Port - Specifies the port address.
  653. Value - Specifies a byte to be written to the port.
  654. Return Value:
  655. None.
  656. --*/
  657. {
  658. pVideoDebugPrint((3,"VideoPortWritePortUchar %x %x\n", Port, Value));
  659. WRITE_PORT_UCHAR(Port, Value);
  660. } // VideoPortWritePortUchar()
  661. VOID
  662. VideoPortWritePortUshort(
  663. IN PUSHORT Port,
  664. IN USHORT Value
  665. )
  666. /*++
  667. Routine Description:
  668. VideoPortWritePortUshort writes a word to the specified port address. It
  669. requires a logical port address obtained from VideoPortGetDeviceBase.
  670. Arguments:
  671. Port - Specifies the port address.
  672. Value - Specifies a word to be written to the port.
  673. Return Value:
  674. None.
  675. --*/
  676. {
  677. pVideoDebugPrint((3,"VideoPortWritePortUhort %x %x\n", Port, Value));
  678. WRITE_PORT_USHORT(Port, Value);
  679. } // VideoPortWritePortUshort()
  680. VOID
  681. VideoPortWritePortUlong(
  682. IN PULONG Port,
  683. IN ULONG Value
  684. )
  685. /*++
  686. Routine Description:
  687. VideoPortWritePortUlong writes a double word to the specified port address.
  688. It requires a logical port address obtained from VideoPortGetDeviceBase.
  689. Arguments:
  690. Port - Specifies the port address.
  691. Value - Specifies a double word to be written to the port.
  692. Return Value:
  693. None.
  694. --*/
  695. {
  696. pVideoDebugPrint((3,"VideoPortWritePortUlong %x %x\n", Port, Value));
  697. WRITE_PORT_ULONG(Port, Value);
  698. } // VideoPortWritePortUlong()
  699. VOID
  700. VideoPortWritePortBufferUchar(
  701. IN PUCHAR Port,
  702. IN PUCHAR Buffer,
  703. IN ULONG Count
  704. )
  705. /*++
  706. Routine Description:
  707. VideoPortWritePortBufferUchar writes a number of bytes to a
  708. specific port. It requires a logical port address obtained from
  709. VideoPortGetDeviceBase.
  710. Arguments:
  711. Port - Specifies the port address.
  712. Buffer - Points to an array of bytes to be written.
  713. Count - Specifies the number of bytes to be written to the buffer.
  714. Return Value:
  715. None.
  716. --*/
  717. {
  718. pVideoDebugPrint((3,"VideoPortWritePortBufferUchar %x \n", Port));
  719. WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
  720. } // VideoPortWritePortBufferUchar()
  721. VOID
  722. VideoPortWritePortBufferUshort(
  723. IN PUSHORT Port,
  724. IN PUSHORT Buffer,
  725. IN ULONG Count
  726. )
  727. /*++
  728. Routine Description:
  729. VideoPortWritePortBufferUshort writes a number of words to a
  730. specific port. It requires a logical port address obtained from
  731. VideoPortGetDeviceBase.
  732. Arguments:
  733. Port - Specifies the port address.
  734. Buffer - Points to an array of words to be written.
  735. Count - Specifies the number of words to be written to the buffer.
  736. Return Value:
  737. None.
  738. --*/
  739. {
  740. pVideoDebugPrint((3,"VideoPortWritePortBufferUshort %x \n", Port));
  741. WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
  742. } // VideoPortWritePortBufferUshort()
  743. VOID
  744. VideoPortWritePortBufferUlong(
  745. IN PULONG Port,
  746. IN PULONG Buffer,
  747. IN ULONG Count
  748. )
  749. /*++
  750. Routine Description:
  751. VideoPortWritePortBufferUlong writes a number of double words to a
  752. specific port. It requires a logical port address obtained from
  753. VideoPortGetDeviceBase.
  754. Arguments:
  755. Port - Specifies the port address.
  756. Buffer - Points to an array of double word to be written.
  757. Count - Specifies the number of double words to be written to the buffer.
  758. Return Value:
  759. None.
  760. --*/
  761. {
  762. pVideoDebugPrint((3,"VideoPortWriteBufferUlong %x \n", Port));
  763. WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
  764. } // VideoPortWritePortBufferUlong()
  765. VOID
  766. VideoPortWriteRegisterUchar(
  767. IN PUCHAR Register,
  768. IN UCHAR Value
  769. )
  770. /*++
  771. Routine Description:
  772. VideoPortWriteRegisterUchar writes a byte to the specified
  773. register address. It requires a logical port address obtained
  774. from VideoPortGetDeviceBase.
  775. Arguments:
  776. Register - Specifies the register address.
  777. Value - Specifies a byte to be written to the register.
  778. Return Value:
  779. None.
  780. --*/
  781. {
  782. pVideoDebugPrint((3,"VideoPortWritePortRegisterUchar %x \n", Register));
  783. WRITE_REGISTER_UCHAR(Register, Value);
  784. } // VideoPortWriteRegisterUchar()
  785. VOID
  786. VideoPortWriteRegisterUshort(
  787. IN PUSHORT Register,
  788. IN USHORT Value
  789. )
  790. /*++
  791. Routine Description:
  792. VideoPortWriteRegisterUshort writes a word to the specified
  793. register address. It requires a logical port address obtained
  794. from VideoPortGetDeviceBase.
  795. Arguments:
  796. Register - Specifies the register address.
  797. Value - Specifies a word to be written to the register.
  798. Return Value:
  799. None.
  800. --*/
  801. {
  802. pVideoDebugPrint((3,"VideoPortWritePortRegisterUshort %x \n", Register));
  803. WRITE_REGISTER_USHORT(Register, Value);
  804. } // VideoPortWriteRegisterUshort()
  805. VOID
  806. VideoPortWriteRegisterUlong(
  807. IN PULONG Register,
  808. IN ULONG Value
  809. )
  810. /*++
  811. Routine Description:
  812. VideoPortWriteRegisterUlong writes a double word to the
  813. specified register address. It requires a logical port
  814. address obtained from VideoPortGetDeviceBase.
  815. Arguments:
  816. Register - Specifies the register address.
  817. Value - Specifies a double word to be written to the register.
  818. Return Value:
  819. None.
  820. --*/
  821. {
  822. pVideoDebugPrint((3,"VideoPortWritePortRegisterUlong %x \n", Register));
  823. WRITE_REGISTER_ULONG(Register, Value);
  824. } // VideoPortWriteRegisterUlong()
  825. VOID
  826. VideoPortWriteRegisterBufferUchar(
  827. IN PUCHAR Register,
  828. IN PUCHAR Buffer,
  829. IN ULONG Count
  830. )
  831. /*++
  832. Routine Description:
  833. Write a buffer of unsigned bytes from the specified register address.
  834. Arguments:
  835. Register - Supplies a pointer to the port address.
  836. Buffer - Supplies a pointer to the data buffer area.
  837. Count - The count of items to move.
  838. Return Value:
  839. None
  840. --*/
  841. {
  842. WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
  843. }
  844. VOID
  845. VideoPortWriteRegisterBufferUshort(
  846. IN PUSHORT Register,
  847. IN PUSHORT Buffer,
  848. IN ULONG Count
  849. )
  850. /*++
  851. Routine Description:
  852. Write a buffer of unsigned shorts from the specified register address.
  853. Arguments:
  854. Register - Supplies a pointer to the port address.
  855. Buffer - Supplies a pointer to the data buffer area.
  856. Count - The count of items to move.
  857. Return Value:
  858. None
  859. --*/
  860. {
  861. WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
  862. }
  863. VOID
  864. VideoPortWriteRegisterBufferUlong(
  865. IN PULONG Register,
  866. IN PULONG Buffer,
  867. IN ULONG Count
  868. )
  869. /*++
  870. Routine Description:
  871. Write a buffer of unsigned longs from the specified register address.
  872. Arguments:
  873. Register - Supplies a pointer to the port address.
  874. Buffer - Supplies a pointer to the data buffer area.
  875. Count - The count of items to move.
  876. Return Value:
  877. None
  878. --*/
  879. {
  880. WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
  881. }
  882. #endif // DBG
  883. //
  884. //VOID
  885. //VideoPortZeroMemory(
  886. // IN PVOID Destination,
  887. // IN ULONG Length
  888. // )
  889. //
  890. //Forwarded to RtlZeroMemory(Destination,Length);
  891. //
  892. PVOID
  893. VideoPortGetAssociatedDeviceExtension(
  894. IN PVOID DeviceObject
  895. )
  896. /*++
  897. Routine Description:
  898. This routine will return the HwDeviceExtension for the parent of the
  899. given device object.
  900. Arguments:
  901. DeviceObject - The child device object (PDO).
  902. Notes:
  903. This function is useful if you want to get the parent device extension
  904. for a child device object. For example this is useful with I2C.
  905. --*/
  906. {
  907. PFDO_EXTENSION DeviceExtension;
  908. PCHILD_PDO_EXTENSION ChildDeviceExtension;
  909. PAGED_CODE();
  910. ASSERT(NULL != DeviceObject);
  911. ChildDeviceExtension = (PCHILD_PDO_EXTENSION)((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
  912. if (!IS_PDO(ChildDeviceExtension)) {
  913. ASSERT(FALSE);
  914. return NULL;
  915. }
  916. DeviceExtension = (PFDO_EXTENSION)ChildDeviceExtension->pFdoExtension;
  917. return (PVOID) DeviceExtension->HwDeviceExtension;
  918. }
  919. ULONG
  920. VideoPortGetAssociatedDeviceID(
  921. IN PVOID DeviceObject
  922. )
  923. /*++
  924. Routine Description:
  925. This routine will return the ChildId for the given device object.
  926. Arguments:
  927. DeviceObject - The child device object (PDO).
  928. Notes:
  929. This function is useful if you want to get the child ID
  930. for a child device object. For example this is useful with I2C.
  931. --*/
  932. {
  933. PCHILD_PDO_EXTENSION ChildDeviceExtension;
  934. PAGED_CODE();
  935. ASSERT(NULL != DeviceObject);
  936. ChildDeviceExtension = (PCHILD_PDO_EXTENSION)((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
  937. if (!IS_PDO(ChildDeviceExtension)) {
  938. ASSERT(FALSE);
  939. return VIDEO_INVALID_CHILD_ID;
  940. }
  941. return ChildDeviceExtension->ChildUId;
  942. }
  943. VOID
  944. VideoPortAcquireDeviceLock(
  945. IN PVOID HwDeviceExtension
  946. )
  947. /*++
  948. Routine Description:
  949. This routine acquires the per device lock maintained by the videoprt.
  950. Arguments:
  951. HwDeviceExtension - Pointer to the hardware device extension.
  952. --*/
  953. {
  954. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  955. ACQUIRE_DEVICE_LOCK(fdoExtension);
  956. }
  957. VOID
  958. VideoPortReleaseDeviceLock(
  959. IN PVOID HwDeviceExtension
  960. )
  961. /*++
  962. Routine Description:
  963. This routine releases the per device lock maintained by the videoprt.
  964. Arguments:
  965. HwDeviceExtension - Pointer to the hardware device extension.
  966. --*/
  967. {
  968. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  969. RELEASE_DEVICE_LOCK(fdoExtension);
  970. }
  971. PVOID
  972. VpGetProcAddress(
  973. IN PVOID HwDeviceExtension,
  974. IN PUCHAR FunctionName
  975. )
  976. /*++
  977. Routine Description:
  978. This routine allows a video miniport to get access to VideoPort
  979. functions without linking to them directly. This will allow an NT 5.0
  980. miniport to take advantage of NT 5.0 features while running on NT 5.0,
  981. but still retain the ability to load on NT 4.0.
  982. Arguments:
  983. HwDeviceExtension - Pointer to the hardware device extension.
  984. FunctionName - pointer to a zero terminated ascii string which contains
  985. the function name we are looking for.
  986. Returns:
  987. Pointer to the given function if it exists.
  988. NULL otherwise.
  989. --*/
  990. {
  991. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  992. PPROC_ADDRESS ProcAddress = VideoPortEntryPoints;
  993. //
  994. // Since the list of exported functions is small, and this routine
  995. // will not be called often we can get away with a linear search.
  996. //
  997. while (ProcAddress->FunctionName) {
  998. if (strcmp(ProcAddress->FunctionName, FunctionName) == 0) {
  999. return ProcAddress->FunctionAddress;
  1000. }
  1001. ProcAddress++;
  1002. }
  1003. return NULL;
  1004. }
  1005. NTSTATUS
  1006. VpGetBusInterface(
  1007. PFDO_EXTENSION FdoExtension
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. Send a QueryInterface Irp to our parent to retrieve
  1012. the BUS_INTERFACE_STANDARD.
  1013. Returns:
  1014. NT_STATUS code
  1015. --*/
  1016. {
  1017. KEVENT Event;
  1018. PIRP QueryIrp = NULL;
  1019. IO_STATUS_BLOCK IoStatusBlock;
  1020. PIO_STACK_LOCATION NextStack;
  1021. NTSTATUS Status;
  1022. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  1023. QueryIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
  1024. FdoExtension->AttachedDeviceObject,
  1025. NULL,
  1026. 0,
  1027. NULL,
  1028. &Event,
  1029. &IoStatusBlock);
  1030. if (QueryIrp == NULL) {
  1031. return STATUS_INSUFFICIENT_RESOURCES;
  1032. }
  1033. QueryIrp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
  1034. NextStack = IoGetNextIrpStackLocation(QueryIrp);
  1035. //
  1036. // Set up for a QueryInterface Irp.
  1037. //
  1038. NextStack->MajorFunction = IRP_MJ_PNP;
  1039. NextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1040. NextStack->Parameters.QueryInterface.InterfaceType = &GUID_BUS_INTERFACE_STANDARD;
  1041. NextStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
  1042. NextStack->Parameters.QueryInterface.Version = 1;
  1043. NextStack->Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->BusInterface;
  1044. NextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1045. FdoExtension->BusInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
  1046. FdoExtension->BusInterface.Version = 1;
  1047. Status = IoCallDriver(FdoExtension->AttachedDeviceObject, QueryIrp);
  1048. if (Status == STATUS_PENDING) {
  1049. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  1050. Status = IoStatusBlock.Status;
  1051. }
  1052. return Status;
  1053. }
  1054. BOOLEAN
  1055. VideoPortCheckForDeviceExistence(
  1056. IN PVOID HwDeviceExtension,
  1057. IN USHORT VendorId,
  1058. IN USHORT DeviceId,
  1059. IN UCHAR RevisionId,
  1060. IN USHORT SubVendorId,
  1061. IN USHORT SubSystemId,
  1062. IN ULONG Flags
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. Checks for the existance of a given PCI device in the system.
  1067. Returns:
  1068. TRUE if the device is present,
  1069. FALSE otherwise.
  1070. --*/
  1071. {
  1072. PFDO_EXTENSION FdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1073. BOOLEAN Result = FALSE;
  1074. if ((FdoExtension->Flags & LEGACY_DRIVER) == 0) {
  1075. KEVENT Event;
  1076. PIRP QueryIrp = NULL;
  1077. IO_STATUS_BLOCK IoStatusBlock;
  1078. PIO_STACK_LOCATION NextStack;
  1079. NTSTATUS Status;
  1080. PCI_DEVICE_PRESENT_INTERFACE Interface;
  1081. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  1082. QueryIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
  1083. FdoExtension->AttachedDeviceObject,
  1084. NULL,
  1085. 0,
  1086. NULL,
  1087. &Event,
  1088. &IoStatusBlock);
  1089. if (QueryIrp == NULL) {
  1090. return FALSE;
  1091. }
  1092. QueryIrp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
  1093. NextStack = IoGetNextIrpStackLocation(QueryIrp);
  1094. //
  1095. // Set up for a QueryInterface Irp.
  1096. //
  1097. NextStack->MajorFunction = IRP_MJ_PNP;
  1098. NextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1099. NextStack->Parameters.QueryInterface.InterfaceType = &GUID_PCI_DEVICE_PRESENT_INTERFACE;
  1100. NextStack->Parameters.QueryInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
  1101. NextStack->Parameters.QueryInterface.Version = 1;
  1102. NextStack->Parameters.QueryInterface.Interface = (PINTERFACE) &Interface;
  1103. NextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1104. FdoExtension->BusInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
  1105. FdoExtension->BusInterface.Version = 1;
  1106. Status = IoCallDriver(FdoExtension->AttachedDeviceObject, QueryIrp);
  1107. if (Status == STATUS_PENDING) {
  1108. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  1109. Status = IoStatusBlock.Status;
  1110. }
  1111. if (NT_SUCCESS(Status)) {
  1112. //
  1113. // We were able to acquire the interface. Check for our device.
  1114. //
  1115. Interface.InterfaceReference(Interface.Context);
  1116. Result = Interface.IsDevicePresent(VendorId,
  1117. DeviceId,
  1118. RevisionId,
  1119. SubVendorId,
  1120. SubSystemId,
  1121. Flags);
  1122. Interface.InterfaceDereference(Interface.Context);
  1123. }
  1124. }
  1125. return Result;
  1126. }
  1127. //
  1128. // Use these until I can make forwarders work.
  1129. //
  1130. LONG
  1131. FASTCALL
  1132. VideoPortInterlockedExchange(
  1133. IN OUT PLONG Target,
  1134. IN LONG Value
  1135. )
  1136. {
  1137. return InterlockedExchange(Target, Value);
  1138. }
  1139. LONG
  1140. FASTCALL
  1141. VideoPortInterlockedIncrement(
  1142. IN PLONG Addend
  1143. )
  1144. {
  1145. return InterlockedIncrement(Addend);
  1146. }
  1147. LONG
  1148. FASTCALL
  1149. VideoPortInterlockedDecrement(
  1150. IN PLONG Addend
  1151. )
  1152. {
  1153. return InterlockedDecrement(Addend);
  1154. }
  1155. VP_STATUS
  1156. VideoPortGetVgaStatus(
  1157. PVOID HwDeviceExtension,
  1158. OUT PULONG VgaStatus
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. VideoPortGetVgaStatus detect if the calling device is decoding
  1163. Vga IO address
  1164. Arguments:
  1165. HwDeviceExtension - Points to the miniport driver's device extension
  1166. VgaStatus - Points to the the result
  1167. Return Value:
  1168. NO_ERROR if the function completes successfully.
  1169. ERROR_INVALID_FUNCTION if it is a non-PCI device
  1170. --*/
  1171. {
  1172. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1173. //
  1174. // We can not handle legacy devices
  1175. //
  1176. if (fdoExtension->AdapterInterfaceType != PCIBus) {
  1177. *VgaStatus = 0;
  1178. return ERROR_INVALID_FUNCTION;
  1179. }
  1180. else {
  1181. *VgaStatus = pVideoPortGetVgaStatusPci( HwDeviceExtension );
  1182. return (NO_ERROR);
  1183. }
  1184. }
  1185. #define VGA_STATUS_REGISTER1 0x3DA
  1186. ULONG
  1187. pVideoPortGetVgaStatusPci(
  1188. PVOID HwDeviceExtension
  1189. )
  1190. {
  1191. USHORT Command;
  1192. PCI_COMMON_CONFIG ConfigSpace;
  1193. PHYSICAL_ADDRESS PhysicalAddress;
  1194. PUCHAR BaseReg;
  1195. ULONG VgaEnable;
  1196. //
  1197. // assume VGA is disabled
  1198. //
  1199. VgaEnable = 0;
  1200. //
  1201. // Get the PCI config for this device
  1202. //
  1203. VideoPortGetBusData( HwDeviceExtension,
  1204. PCIConfiguration,
  1205. 0,
  1206. &ConfigSpace,
  1207. 0,
  1208. PCI_COMMON_HDR_LENGTH);
  1209. if( !(ConfigSpace.Command & PCI_ENABLE_IO_SPACE) ) {
  1210. return VgaEnable;
  1211. }
  1212. if (((ConfigSpace.BaseClass == PCI_CLASS_PRE_20) &&
  1213. (ConfigSpace.SubClass == PCI_SUBCLASS_PRE_20_VGA)) ||
  1214. ((ConfigSpace.BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
  1215. (ConfigSpace.SubClass == PCI_SUBCLASS_VID_VGA_CTLR))) {
  1216. //
  1217. // Map the VGA registers we are going to use.
  1218. //
  1219. PhysicalAddress.HighPart = 0;
  1220. PhysicalAddress.LowPart = VGA_STATUS_REGISTER1;
  1221. BaseReg = VideoPortGetDeviceBase(HwDeviceExtension,
  1222. PhysicalAddress,
  1223. 1,
  1224. VIDEO_MEMORY_SPACE_IO);
  1225. if (BaseReg) {
  1226. //
  1227. // If we got here the PCI config space for our device indicates
  1228. // we are the VGA, and we were able to map the VGA resources.
  1229. //
  1230. VgaEnable = DEVICE_VGA_ENABLED;
  1231. VideoPortFreeDeviceBase(HwDeviceExtension, BaseReg);
  1232. }
  1233. }
  1234. return VgaEnable;
  1235. }
  1236. VOID
  1237. pVideoPortDpcDispatcher(
  1238. IN PKDPC Dpc,
  1239. IN PVOID HwDeviceExtension,
  1240. IN PMINIPORT_DPC_ROUTINE DpcRoutine,
  1241. IN PVOID Context
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. This routine handles DPCs and forwards them to the miniport callback
  1246. routine.
  1247. Arguments:
  1248. Dpc - The DPC which is executing.
  1249. HwDeviceExtension - The HwDeviceExtension for the device which scheduled
  1250. the DPC.
  1251. DpcRoutine - The callback in the miniport which needs to be called.
  1252. Context - The miniport supplied context.
  1253. Returns:
  1254. None.
  1255. --*/
  1256. {
  1257. DpcRoutine(HwDeviceExtension, Context);
  1258. }
  1259. BOOLEAN
  1260. VideoPortQueueDpc(
  1261. IN PVOID HwDeviceExtension,
  1262. IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
  1263. IN PVOID Context
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. Allows a miniport driver to queue a DPC.
  1268. Arguments:
  1269. HwDeviceExtension - The HwDeviceExtension for the miniport.
  1270. CallbackRoutine - The entry point within the miniport to call when the DPC
  1271. is scheduled.
  1272. Context - A miniport supplies context which will be passed to the
  1273. CallbackRoutine.
  1274. Returns:
  1275. TRUE if successful,
  1276. FALSE otherwise.
  1277. --*/
  1278. {
  1279. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1280. return KeInsertQueueDpc(&fdoExtension->Dpc, CallbackRoutine, Context);
  1281. }
  1282. ULONG
  1283. VpGetDeviceCount(
  1284. IN PVOID HwDeviceExtension
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. Returns the number of started devices.
  1289. Arguments:
  1290. HwDeviceExtension - The HwDeviceExtension for the miniport.
  1291. Returns:
  1292. The number of started devices.
  1293. --*/
  1294. {
  1295. return NumDevicesStarted;
  1296. }
  1297. VOID
  1298. pVpBugcheckCallback(
  1299. IN KBUGCHECK_CALLBACK_REASON Reason,
  1300. IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
  1301. IN OUT PVOID ReasonSpecificData,
  1302. IN ULONG ReasonSpecificDataLength
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. This callback is called when a bugcheck occurs. It allows the
  1307. videoprt an opportunity to store data which can later be used
  1308. to help diagnose the bugcheck.
  1309. Arguments:
  1310. Reason - the reason we are being called
  1311. Record - a pointer to the bugcheck reason record we set up
  1312. ReasonSpecificData - pointer to KBUGCHECK_SECONDARY_DUMP_DATA
  1313. ReasonSpecificDataLength - the size of the reason specific data
  1314. Returns:
  1315. None.
  1316. Notes:
  1317. This routine can be called at any time, and must not be pageable.
  1318. --*/
  1319. {
  1320. ULONG BugcheckCode;
  1321. PKBUGCHECK_SECONDARY_DUMP_DATA DumpData
  1322. = (PKBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData;
  1323. //
  1324. // Only handle secondary dumps
  1325. //
  1326. if (Reason != KbCallbackSecondaryDumpData) {
  1327. return;
  1328. }
  1329. //
  1330. // Grab the bugcheck code. We only handle EA currently.
  1331. //
  1332. BugcheckCode = *((PULONG)KiBugCheckData[0]);
  1333. if (BugcheckCode == 0xEA) {
  1334. pVpGeneralBugcheckHandler(DumpData);
  1335. }
  1336. }
  1337. VOID
  1338. pVpGeneralBugcheckHandler(
  1339. PKBUGCHECK_SECONDARY_DUMP_DATA DumpData
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. This routine calls all of the hooked bugcheck callbacks,
  1344. and appends the data into the supplied buffer.
  1345. Arguments:
  1346. DumpData - pointer to the location in which to store the dump data
  1347. Returns:
  1348. None
  1349. --*/
  1350. {
  1351. if (VpBugcheckDeviceObject != NULL) {
  1352. #if DBG
  1353. const char szDumpCanary[] = "kirgudu! barban bia!";
  1354. C_ASSERT((sizeof(szDumpCanary) + MAX_SECONDARY_DUMP_SIZE) <= PAGE_SIZE);
  1355. // XXX olegk - Must be removed for Longhorn
  1356. C_ASSERT(sizeof(szDumpCanary) <= BUGCHECK_DATA_SIZE_RESERVED);
  1357. char* pCanaryLocation = (char*)(VpBugcheckData) + MAX_SECONDARY_DUMP_SIZE -
  1358. sizeof(DUMP_BLOB_FILE_HEADER) - sizeof(DUMP_BLOB_HEADER); // remove it for Longhorn
  1359. #endif // DBG
  1360. //
  1361. // It is possible that the device object stored in VpBugcheckDeviceObject
  1362. // is actually an upper level filter. Therefore we can't assume it is
  1363. // actually our device object. Instead we'll have to get the lowest level
  1364. // device object, and scan our list of FDO's for the one that is attached.
  1365. //
  1366. PDEVICE_OBJECT pdo = VpBugcheckDeviceObject;
  1367. PFDO_EXTENSION FdoExtension = VpBugcheckDeviceObject->DeviceExtension;
  1368. //
  1369. // Fill in the GUID, output buffer, and output buffer length
  1370. //
  1371. DumpData->OutBuffer = VpBugcheckData;
  1372. DumpData->OutBufferLength = FdoExtension->BugcheckDataSize;
  1373. #if DBG
  1374. strcpy(pCanaryLocation, szDumpCanary);
  1375. #endif // DBG
  1376. memcpy(&DumpData->Guid, &VpBugcheckGUID, sizeof(VpBugcheckGUID));
  1377. //
  1378. // Call the "hooked" reason callback entry point
  1379. //
  1380. if (FdoExtension->BugcheckCallback) {
  1381. FdoExtension->BugcheckCallback(
  1382. FdoExtension->HwDeviceExtension,
  1383. 0xEA,
  1384. VpBugcheckData,
  1385. FdoExtension->BugcheckDataSize);
  1386. }
  1387. #if DBG
  1388. ASSERT(!strcmp(szDumpCanary, pCanaryLocation));
  1389. #endif // DBG
  1390. }
  1391. }
  1392. VOID
  1393. VpAcquireLock(
  1394. VOID
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. This routine will acquire the global video port lock. This lock
  1399. protects global data structures which are shared across drivers.
  1400. Arguments:
  1401. none.
  1402. Returns:
  1403. none.
  1404. --*/
  1405. {
  1406. KeWaitForSingleObject(
  1407. &VpGlobalLock,
  1408. Executive,
  1409. KernelMode,
  1410. FALSE,
  1411. (PTIME)NULL);
  1412. }
  1413. VOID
  1414. VpReleaseLock(
  1415. VOID
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. This routine will release the global video port lock. This lock
  1420. protects global data structures which are shared across drivers.
  1421. Arguments:
  1422. none.
  1423. Returns:
  1424. none.
  1425. --*/
  1426. {
  1427. KeReleaseMutex(&VpGlobalLock, FALSE);
  1428. }
  1429. PVOID
  1430. VpAllocateNonPagedPoolPageAligned(
  1431. ULONG Size
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. This routine will allocate non-paged pool on a page alignment.
  1436. Arguments:
  1437. Size - The number of bytes of memory to allocate.
  1438. Returns:
  1439. A pointer to the allocated buffer.
  1440. --*/
  1441. {
  1442. PVOID Buffer;
  1443. if (Size < PAGE_SIZE) {
  1444. Size = PAGE_SIZE;
  1445. }
  1446. Buffer = ExAllocatePoolWithTag(NonPagedPool, Size, VP_TAG);
  1447. //
  1448. // Make sure the buffer is page aligned. In current builds,
  1449. // allocating at least 1 page from non-paged pool, will always
  1450. // result in a page aligned allocation.
  1451. //
  1452. // However, since this could change someday, verify that this
  1453. // remains true.
  1454. //
  1455. if ((ULONG_PTR)Buffer & (PAGE_SIZE - 1)) {
  1456. ExFreePool(Buffer);
  1457. Buffer = NULL;
  1458. }
  1459. return Buffer;
  1460. }
  1461. VP_STATUS
  1462. VideoPortRegisterBugcheckCallback(
  1463. IN PVOID HwDeviceExtension,
  1464. IN ULONG BugcheckCode,
  1465. IN PVIDEO_BUGCHECK_CALLBACK Callback,
  1466. IN ULONG BugcheckDataSize
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. This routine allows a video miniport to register for a callback at
  1471. bugcheck time. The driver will then have an opportunity to store
  1472. data that can be used to help diagnose the bugcheck. The data is
  1473. appended to the dump file.
  1474. Arguments:
  1475. HwDeviceExtension - a pointer to the device extension
  1476. BugcheckCode - allows you to specify the bugcheck code you want to
  1477. be notified for.
  1478. Callback - a pointer to the miniport supplied callback function
  1479. which will be invoked when a bugcheck occurs. The callback function
  1480. must be non-paged, and must not access pageable code or data.
  1481. BugcheckDataSize - The amount of data the miniport will want to add
  1482. to the minidump.
  1483. Returns:
  1484. A status code indicating success or failure.
  1485. Notes:
  1486. Currently only bugcheck EA's can be hooked.
  1487. Currently we limit the data size to 4k.
  1488. To unhook the callback, the miniport can specify NULL for the callback
  1489. or 0 for the DataSize.
  1490. --*/
  1491. {
  1492. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1493. VP_STATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  1494. //
  1495. // For now let's only support hooking bugcheck EA.
  1496. //
  1497. if (BugcheckCode != 0xEA) {
  1498. pVideoDebugPrint((0, "Currently only bugcheck 0xEA can be hooked.\n"));
  1499. return STATUS_INVALID_PARAMETER;
  1500. }
  1501. //
  1502. // Force the data size to be a multiple of 16 bytes.
  1503. //
  1504. BugcheckDataSize = (BugcheckDataSize + 15) & ~15;
  1505. //
  1506. // The kernel support code only allows 4k per caller for minidumps.
  1507. //
  1508. if (BugcheckDataSize > MAX_SECONDARY_DUMP_SIZE) {
  1509. pVideoDebugPrint((0, "There is 4000 bytes limit on bugcheck data size.\n"));
  1510. return STATUS_INVALID_PARAMETER;
  1511. }
  1512. //
  1513. // Acquire global videoprt lock, because we will be modifiying
  1514. // global state.
  1515. //
  1516. VpAcquireLock();
  1517. //
  1518. // If the Callback is NULL, or the BugcheckDataSize is 0 then
  1519. // they are unregistering the callback.
  1520. //
  1521. if ((Callback == NULL) || (BugcheckDataSize == 0)) {
  1522. //
  1523. // Only unregister if they were registered!
  1524. //
  1525. if (fdoExtension->BugcheckCallback) {
  1526. fdoExtension->BugcheckCallback = NULL;
  1527. fdoExtension->BugcheckDataSize = 0;
  1528. }
  1529. Status = NO_ERROR;
  1530. } else {
  1531. if (VpBugcheckData == NULL) {
  1532. //
  1533. // Try to acquire a large enough buffer for the bugcheck data for
  1534. // this driver and all other drivers already registered
  1535. //
  1536. VpBugcheckData = VpAllocateNonPagedPoolPageAligned(PAGE_SIZE);
  1537. }
  1538. //
  1539. // If the allocation succeeded then register the bugcheck
  1540. // callback
  1541. //
  1542. if (VpBugcheckData) {
  1543. //
  1544. // Update the fdoExtension to indicate the callback is hooked.
  1545. //
  1546. fdoExtension->BugcheckCallback = Callback;
  1547. fdoExtension->BugcheckDataSize = BugcheckDataSize;
  1548. Status = NO_ERROR;
  1549. }
  1550. }
  1551. //
  1552. // Release the global videoprt lock
  1553. //
  1554. VpReleaseLock();
  1555. return Status;
  1556. }
  1557. static
  1558. VOID
  1559. FreeDumpFileDacl(
  1560. PACL pDacl
  1561. )
  1562. {
  1563. if (pDacl) ExFreePool(pDacl);
  1564. }
  1565. static
  1566. PACL
  1567. CreateDumpFileDacl(
  1568. VOID
  1569. )
  1570. {
  1571. ULONG ulDacLength = sizeof(ACL)
  1572. + 2 * sizeof(ACCESS_ALLOWED_ACE)
  1573. - 2 * sizeof(ULONG)
  1574. + RtlLengthSid(SeExports->SeLocalSystemSid)
  1575. + RtlLengthSid(SeExports->SeCreatorOwnerSid);
  1576. PACL pDacl = (PACL)ExAllocatePoolWithTag(PagedPool, ulDacLength, VP_TAG);
  1577. if (pDacl &&
  1578. NT_SUCCESS(RtlCreateAcl(pDacl, ulDacLength, ACL_REVISION)) &&
  1579. NT_SUCCESS(RtlAddAccessAllowedAce(pDacl,
  1580. ACL_REVISION,
  1581. GENERIC_ALL,
  1582. SeExports->SeLocalSystemSid)) &&
  1583. NT_SUCCESS(RtlAddAccessAllowedAce(pDacl,
  1584. ACL_REVISION,
  1585. DELETE,
  1586. SeExports->SeCreatorOwnerSid)))
  1587. {
  1588. return pDacl;
  1589. }
  1590. FreeDumpFileDacl(pDacl);
  1591. return NULL;
  1592. }
  1593. static
  1594. BOOLEAN
  1595. InitDumpFileSid(
  1596. PSID pSid,
  1597. PACL pDacl
  1598. )
  1599. {
  1600. return (pSid &&
  1601. pDacl &&
  1602. NT_SUCCESS(RtlCreateSecurityDescriptor(pSid, SECURITY_DESCRIPTOR_REVISION)) &&
  1603. NT_SUCCESS(RtlSetDaclSecurityDescriptor(pSid, TRUE, pDacl,FALSE)));
  1604. }
  1605. VOID
  1606. pVpWriteFile(
  1607. PWSTR pwszFileName,
  1608. PVOID pvBuffer,
  1609. ULONG ulSize
  1610. )
  1611. /*++
  1612. Routine Description:
  1613. This routine is called when we are trying to recover from a bugcheck
  1614. EA.
  1615. Arguments:
  1616. pwszFileName - name of dump file
  1617. pvBuffer - data to write
  1618. ulSize - size of the data to data
  1619. Returns:
  1620. none.
  1621. Notes:
  1622. This routine can be pagable because it will be called at passive level.
  1623. --*/
  1624. {
  1625. SECURITY_DESCRIPTOR Sid;
  1626. PACL pDacl = CreateDumpFileDacl();
  1627. if (InitDumpFileSid(&Sid, pDacl)) {
  1628. OBJECT_ATTRIBUTES ObjectAttributes;
  1629. UNICODE_STRING UnicodeString;
  1630. HANDLE FileHandle;
  1631. NTSTATUS Status;
  1632. IO_STATUS_BLOCK IoStatusBlock;
  1633. RtlInitUnicodeString(&UnicodeString,
  1634. pwszFileName);
  1635. InitializeObjectAttributes(&ObjectAttributes,
  1636. &UnicodeString,
  1637. OBJ_CASE_INSENSITIVE,
  1638. (HANDLE) NULL,
  1639. &Sid);
  1640. if (NT_SUCCESS(ZwCreateFile(&FileHandle,
  1641. FILE_GENERIC_WRITE,
  1642. &ObjectAttributes,
  1643. &IoStatusBlock,
  1644. NULL,
  1645. FILE_ATTRIBUTE_HIDDEN,
  1646. 0, // exclusive
  1647. FILE_SUPERSEDE,
  1648. FILE_SYNCHRONOUS_IO_NONALERT |
  1649. FILE_WRITE_THROUGH,
  1650. NULL,
  1651. 0)))
  1652. {
  1653. ZwWriteFile(FileHandle,
  1654. NULL,
  1655. NULL,
  1656. NULL,
  1657. &IoStatusBlock,
  1658. pvBuffer,
  1659. ulSize,
  1660. NULL,
  1661. NULL);
  1662. //
  1663. // Close the file.
  1664. //
  1665. ZwClose(FileHandle);
  1666. }
  1667. }
  1668. FreeDumpFileDacl(pDacl);
  1669. }
  1670. #if defined(_AMD64_)
  1671. VOID
  1672. VideoPortQuerySystemTime(
  1673. OUT PLARGE_INTEGER CurrentTime
  1674. )
  1675. /*++
  1676. Routine Description:
  1677. This function returns the current system time.
  1678. Arguments:
  1679. CurrentTime - Supplies a pointer to a variable that will receive the
  1680. current system time.
  1681. Return Value:
  1682. None.
  1683. --*/
  1684. {
  1685. KeQuerySystemTime(CurrentTime);
  1686. return;
  1687. }
  1688. #endif