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.

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