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.

845 lines
19 KiB

  1. /**************************************************************************
  2. AVStream Simulated Hardware Sample
  3. Copyright (c) 2001, Microsoft Corporation.
  4. File:
  5. device.cpp
  6. Abstract:
  7. This file contains the device level implementation of the AVStream
  8. hardware sample. Note that this is not the "fake" hardware. The
  9. "fake" hardware is in hwsim.cpp.
  10. History:
  11. created 3/9/2001
  12. **************************************************************************/
  13. #include "BDACap.h"
  14. /**************************************************************************
  15. PAGEABLE CODE
  16. **************************************************************************/
  17. #ifdef ALLOC_PRAGMA
  18. #pragma code_seg("PAGE")
  19. #endif // ALLOC_PRAGMA
  20. NTSTATUS
  21. CCaptureDevice::
  22. DispatchCreate (
  23. IN PKSDEVICE Device
  24. )
  25. /*++
  26. Routine Description:
  27. Create the capture device. This is the creation dispatch for the
  28. capture device.
  29. Arguments:
  30. Device -
  31. The AVStream device being created.
  32. Return Value:
  33. Success / Failure
  34. --*/
  35. {
  36. PAGED_CODE();
  37. NTSTATUS Status;
  38. CCaptureDevice *CapDevice = new (NonPagedPool, MS_SAMPLE_CAPTURE_POOL_TAG) CCaptureDevice (Device);
  39. if (!CapDevice) {
  40. //
  41. // Return failure if we couldn't create the pin.
  42. //
  43. Status = STATUS_INSUFFICIENT_RESOURCES;
  44. } else {
  45. //
  46. // Add the item to the object bag if we were successful.
  47. // Whenever the device goes away, the bag is cleaned up and
  48. // we will be freed.
  49. //
  50. // For backwards compatibility with DirectX 8.0, we must grab
  51. // the device mutex before doing this. For Windows XP, this is
  52. // not required, but it is still safe.
  53. //
  54. KsAcquireDevice (Device);
  55. Status = KsAddItemToObjectBag (
  56. Device -> Bag,
  57. reinterpret_cast <PVOID> (CapDevice),
  58. reinterpret_cast <PFNKSFREE> (CCaptureDevice::Cleanup)
  59. );
  60. KsReleaseDevice (Device);
  61. if (!NT_SUCCESS (Status)) {
  62. delete CapDevice;
  63. } else {
  64. Device -> Context = reinterpret_cast <PVOID> (CapDevice);
  65. }
  66. }
  67. return Status;
  68. }
  69. /*************************************************/
  70. NTSTATUS
  71. CCaptureDevice::
  72. PnpStart (
  73. IN PCM_RESOURCE_LIST TranslatedResourceList,
  74. IN PCM_RESOURCE_LIST UntranslatedResourceList
  75. )
  76. /*++
  77. Routine Description:
  78. Called at Pnp start. We start up our virtual hardware simulation.
  79. Arguments:
  80. TranslatedResourceList -
  81. The translated resource list from Pnp
  82. UntranslatedResourceList -
  83. The untranslated resource list from Pnp
  84. Return Value:
  85. Success / Failure
  86. --*/
  87. {
  88. PAGED_CODE();
  89. //
  90. // Normally, we'd do things here like parsing the resource lists and
  91. // connecting our interrupt. Since this is a simulation, there isn't
  92. // much to parse. The parsing and connection should be the same as
  93. // any WDM driver. The sections that will differ are illustrated below
  94. // in setting up a simulated DMA.
  95. //
  96. NTSTATUS Status = STATUS_SUCCESS;
  97. //
  98. // By PnP, it's possible to receive multiple starts without an intervening
  99. // stop (to reevaluate resources, for example). Thus, we only perform
  100. // creations of the simulation on the initial start and ignore any
  101. // subsequent start. Hardware drivers with resources should evaluate
  102. // resources and make changes on 2nd start.
  103. //
  104. if (!m_Device -> Started) {
  105. m_HardwareSimulation = new (NonPagedPool, MS_SAMPLE_CAPTURE_POOL_TAG) CHardwareSimulation (this);
  106. if (!m_HardwareSimulation) {
  107. //
  108. // If we couldn't create the hardware simulation, fail.
  109. //
  110. Status = STATUS_INSUFFICIENT_RESOURCES;
  111. return Status;
  112. } else {
  113. //
  114. // Add the item to the object bag if we were successful.
  115. //
  116. Status = KsAddItemToObjectBag (
  117. m_Device -> Bag,
  118. reinterpret_cast <PVOID> (m_HardwareSimulation),
  119. reinterpret_cast <PFNKSFREE> (CCaptureDevice::CleanupHW)
  120. );
  121. if (!NT_SUCCESS(Status)) {
  122. delete m_HardwareSimulation;
  123. return Status;
  124. }
  125. }
  126. INTERFACE_TYPE InterfaceBuffer;
  127. ULONG InterfaceLength;
  128. DEVICE_DESCRIPTION DeviceDescription;
  129. NTSTATUS IfStatus;
  130. if (NT_SUCCESS (Status)) {
  131. //
  132. // Set up DMA...
  133. //
  134. IfStatus = IoGetDeviceProperty (
  135. m_Device -> PhysicalDeviceObject,
  136. DevicePropertyLegacyBusType,
  137. sizeof (INTERFACE_TYPE),
  138. &InterfaceBuffer,
  139. &InterfaceLength
  140. );
  141. //
  142. // Initialize our fake device description. We claim to be a
  143. // bus-mastering 32-bit scatter/gather capable piece of hardware.
  144. //
  145. // Ordinarilly, we'd be using InterfaceBuffer or
  146. // InterfaceTypeUndefined if !NT_SUCCESS (IfStatus) as the
  147. // InterfaceType below; however, for the purposes of this sample,
  148. // we lie and say we're on the PCI Bus. Otherwise, we're using map
  149. // registers on x86 32 bit physical to 32 bit logical and this isn't
  150. // what I want to show in this sample.
  151. //
  152. DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  153. DeviceDescription.DmaChannel = ((ULONG) ~0);
  154. DeviceDescription.InterfaceType = PCIBus;
  155. DeviceDescription.DmaWidth = Width32Bits;
  156. DeviceDescription.DmaSpeed = Compatible;
  157. DeviceDescription.ScatterGather = TRUE;
  158. DeviceDescription.Master = TRUE;
  159. DeviceDescription.Dma32BitAddresses = TRUE;
  160. DeviceDescription.AutoInitialize = FALSE;
  161. DeviceDescription.MaximumLength = (ULONG) -1;
  162. //
  163. // Get a DMA adapter object from the system.
  164. //
  165. m_DmaAdapterObject = IoGetDmaAdapter (
  166. m_Device -> PhysicalDeviceObject,
  167. &DeviceDescription,
  168. &m_NumberOfMapRegisters
  169. );
  170. if (!m_DmaAdapterObject) {
  171. Status = STATUS_UNSUCCESSFUL;
  172. }
  173. }
  174. if (NT_SUCCESS (Status)) {
  175. //
  176. // Initialize our DMA adapter object with AVStream. This is
  177. // **ONLY** necessary **IF** you are doing DMA directly into
  178. // capture buffers as this sample does. For this,
  179. // KSPIN_FLAG_GENERATE_MAPPINGS must be specified on a queue.
  180. //
  181. //
  182. // The (1 << 20) below is the maximum size of a single s/g mapping
  183. // that this hardware can handle. Note that I have pulled this
  184. // number out of thin air for the "fake" hardware.
  185. //
  186. KsDeviceRegisterAdapterObject (
  187. m_Device,
  188. m_DmaAdapterObject,
  189. (1 << 20),
  190. sizeof (KSMAPPING)
  191. );
  192. }
  193. }
  194. return Status;
  195. }
  196. /*************************************************/
  197. void
  198. CCaptureDevice::
  199. PnpStop (
  200. )
  201. /*++
  202. Routine Description:
  203. This is the pnp stop dispatch for the capture device. It releases any
  204. adapter object previously allocated by IoGetDmaAdapter during Pnp Start.
  205. Arguments:
  206. None
  207. Return Value:
  208. None
  209. --*/
  210. {
  211. if (m_DmaAdapterObject) {
  212. //
  213. // Return the DMA adapter back to the system.
  214. //
  215. m_DmaAdapterObject -> DmaOperations ->
  216. PutDmaAdapter (m_DmaAdapterObject);
  217. m_DmaAdapterObject = NULL;
  218. }
  219. }
  220. /*************************************************/
  221. NTSTATUS
  222. CCaptureDevice::
  223. AcquireHardwareResources (
  224. IN ICaptureSink *CaptureSink,
  225. IN PBDA_TRANSPORT_INFO TransportInfo
  226. )
  227. /*++
  228. Routine Description:
  229. Acquire hardware resources for the capture hardware. If the
  230. resources are already acquired, this will return an error.
  231. The hardware configuration must be passed as a VideoInfoHeader.
  232. Arguments:
  233. CaptureSink -
  234. The capture sink attempting to acquire resources. When scatter /
  235. gather mappings are completed, the capture sink specified here is
  236. what is notified of the completions.
  237. VideoInfoHeader -
  238. Information about the capture stream. This **MUST** remain
  239. stable until the caller releases hardware resources. Note
  240. that this could also be guaranteed by bagging it in the device
  241. object bag as well.
  242. Return Value:
  243. Success / Failure
  244. --*/
  245. {
  246. PAGED_CODE();
  247. NTSTATUS Status = STATUS_SUCCESS;
  248. //
  249. // If we're the first pin to go into acquire (remember we can have
  250. // a filter in another graph going simultaneously), grab the resources.
  251. //
  252. if (InterlockedCompareExchange (
  253. &m_PinsWithResources,
  254. 1,
  255. 0) == 0) {
  256. m_TransportInfo = TransportInfo;
  257. //
  258. // If there's an old hardware simulation sitting around for some
  259. // reason, blow it away.
  260. //
  261. if (m_TsSynth) {
  262. delete m_TsSynth;
  263. m_TsSynth = NULL;
  264. }
  265. //
  266. // Create the necessary type of transport stream synthesizer.
  267. //
  268. if (m_TransportInfo)
  269. {
  270. m_TsSynth = new (NonPagedPool, MS_SAMPLE_CAPTURE_POOL_TAG)
  271. CTsSynthesizer (
  272. m_TransportInfo -> ulcbPhyiscalPacket,
  273. m_TransportInfo -> ulcbPhyiscalFrame / m_TransportInfo -> ulcbPhyiscalPacket
  274. );
  275. }
  276. else
  277. //
  278. // We don't synthesize anything but RGB 24 and UYVY.
  279. //
  280. Status = STATUS_INVALID_PARAMETER;
  281. if (NT_SUCCESS (Status) && !m_TsSynth) {
  282. Status = STATUS_INSUFFICIENT_RESOURCES;
  283. }
  284. //
  285. // If everything has succeeded thus far, set the capture sink.
  286. //
  287. if (NT_SUCCESS(Status))
  288. m_CaptureSink = CaptureSink;
  289. else {
  290. ReleaseHardwareResources();
  291. }
  292. } else {
  293. //
  294. // TODO: Better status code?
  295. //
  296. Status = STATUS_SHARING_VIOLATION;
  297. }
  298. return Status;
  299. }
  300. /*************************************************/
  301. void
  302. CCaptureDevice::
  303. ReleaseHardwareResources (
  304. )
  305. /*++
  306. Routine Description:
  307. Release hardware resources. This should only be called by
  308. an object which has acquired them.
  309. Arguments:
  310. None
  311. Return Value:
  312. None
  313. --*/
  314. {
  315. PAGED_CODE();
  316. //
  317. // Blow away the image synth.
  318. //
  319. if (m_TsSynth) {
  320. delete m_TsSynth;
  321. m_TsSynth = NULL;
  322. }
  323. m_TransportInfo = NULL;
  324. m_CaptureSink = NULL;
  325. //
  326. // Release our "lock" on hardware resources. This will allow another
  327. // pin (perhaps in another graph) to acquire them.
  328. //
  329. InterlockedExchange (
  330. &m_PinsWithResources,
  331. 0
  332. );
  333. }
  334. /*************************************************/
  335. NTSTATUS
  336. CCaptureDevice::
  337. Start (
  338. )
  339. /*++
  340. Routine Description:
  341. Start the capture device based on the video info header we were told
  342. about when resources were acquired.
  343. Arguments:
  344. None
  345. Return Value:
  346. Success / Failure
  347. --*/
  348. {
  349. PAGED_CODE();
  350. m_LastMappingsCompleted = 0;
  351. m_InterruptTime = 0;
  352. return
  353. m_HardwareSimulation -> Start (
  354. m_TsSynth,
  355. m_TransportInfo -> AvgTimePerFrame,
  356. m_TransportInfo -> ulcbPhyiscalPacket,
  357. m_TransportInfo -> ulcbPhyiscalFrame / m_TransportInfo -> ulcbPhyiscalPacket
  358. );
  359. }
  360. /*************************************************/
  361. NTSTATUS
  362. CCaptureDevice::
  363. Pause (
  364. IN BOOLEAN Pausing
  365. )
  366. /*++
  367. Routine Description:
  368. Pause or unpause the hardware simulation. This is an effective start
  369. or stop without resetting counters and formats. Note that this can
  370. only be called to transition from started -> paused -> started. Calling
  371. this without starting the hardware with Start() does nothing.
  372. Arguments:
  373. Pausing -
  374. An indicatation of whether we are pausing or unpausing
  375. TRUE -
  376. Pause the hardware simulation
  377. FALSE -
  378. Unpause the hardware simulation
  379. Return Value:
  380. Success / Failure
  381. --*/
  382. {
  383. PAGED_CODE();
  384. return
  385. m_HardwareSimulation -> Pause (
  386. Pausing
  387. );
  388. }
  389. /*************************************************/
  390. NTSTATUS
  391. CCaptureDevice::
  392. Stop (
  393. )
  394. /*++
  395. Routine Description:
  396. Stop the capture device.
  397. Arguments:
  398. None
  399. Return Value:
  400. Success / Failure
  401. --*/
  402. {
  403. PAGED_CODE();
  404. return
  405. m_HardwareSimulation -> Stop ();
  406. }
  407. /*************************************************/
  408. ULONG
  409. CCaptureDevice::
  410. ProgramScatterGatherMappings (
  411. IN PUCHAR *Buffer,
  412. IN PKSMAPPING Mappings,
  413. IN ULONG MappingsCount
  414. )
  415. /*++
  416. Routine Description:
  417. Program the scatter / gather mappings for the "fake" hardware.
  418. Arguments:
  419. Buffer -
  420. Points to a pointer to the virtual address of the topmost
  421. scatter / gather chunk. The pointer will be updated as the
  422. device "programs" mappings. Reason for this is that we get
  423. the physical addresses and sizes, but must calculate the virtual
  424. addresses... This is used as scratch space for that.
  425. Mappings -
  426. An array of mappings to program
  427. MappingsCount -
  428. The count of mappings in the array
  429. Return Value:
  430. The number of mappings successfully programmed
  431. --*/
  432. {
  433. PAGED_CODE();
  434. return
  435. m_HardwareSimulation -> ProgramScatterGatherMappings (
  436. Buffer,
  437. Mappings,
  438. MappingsCount,
  439. sizeof (KSMAPPING)
  440. );
  441. }
  442. /*************************************************************************
  443. LOCKED CODE
  444. **************************************************************************/
  445. #ifdef ALLOC_PRAGMA
  446. #pragma code_seg()
  447. #endif // ALLOC_PRAGMA
  448. ULONG
  449. CCaptureDevice::
  450. QueryInterruptTime (
  451. )
  452. /*++
  453. Routine Description:
  454. Return the number of frame intervals that have elapsed since the
  455. start of the device. This will be the frame number.
  456. Arguments:
  457. None
  458. Return Value:
  459. The interrupt time of the device (the number of frame intervals that
  460. have elapsed since the start of the device).
  461. --*/
  462. {
  463. return m_InterruptTime;
  464. }
  465. /*************************************************/
  466. void
  467. CCaptureDevice::
  468. Interrupt (
  469. )
  470. /*++
  471. Routine Description:
  472. This is the "faked" interrupt service routine for this device. It
  473. is called at dispatch level by the hardware simulation.
  474. Arguments:
  475. None
  476. Return Value:
  477. None
  478. --*/
  479. {
  480. m_InterruptTime++;
  481. //
  482. // Realistically, we'd do some hardware manipulation here and then queue
  483. // a DPC. Since this is fake hardware, we do what's necessary here. This
  484. // is pretty much what the DPC would look like short of the access
  485. // of hardware registers (ReadNumberOfMappingsCompleted) which would likely
  486. // be done in the ISR.
  487. //
  488. ULONG NumMappingsCompleted =
  489. m_HardwareSimulation -> ReadNumberOfMappingsCompleted ();
  490. //
  491. // Inform the capture sink that a given number of scatter / gather
  492. // mappings have completed.
  493. //
  494. m_CaptureSink -> CompleteMappings (
  495. NumMappingsCompleted - m_LastMappingsCompleted
  496. );
  497. m_LastMappingsCompleted = NumMappingsCompleted;
  498. }
  499. /**************************************************************************
  500. DESCRIPTOR AND DISPATCH LAYOUT
  501. **************************************************************************/
  502. //
  503. // CaptureFilterDescriptor:
  504. //
  505. // The filter descriptor for the capture device.
  506. DEFINE_KSFILTER_DESCRIPTOR_TABLE (FilterDescriptors) {
  507. &CaptureFilterDescriptor
  508. };
  509. //
  510. // CaptureDeviceDispatch:
  511. //
  512. // This is the dispatch table for the capture device. Plug and play
  513. // notifications as well as power management notifications are dispatched
  514. // through this table.
  515. //
  516. const
  517. KSDEVICE_DISPATCH
  518. CaptureDeviceDispatch = {
  519. CCaptureDevice::DispatchCreate, // PnP Add Device
  520. CCaptureDevice::DispatchPnpStart, // PnP Start
  521. NULL, // Post-Start
  522. NULL, // Pnp Query Stop
  523. NULL, // Pnp Cancel Stop
  524. CCaptureDevice::DispatchPnpStop, // Pnp Stop
  525. NULL, // Pnp Query Remove
  526. NULL, // Pnp Cancel Remove
  527. NULL, // Pnp Remove
  528. NULL, // Pnp Query Capabilities
  529. NULL, // Pnp Surprise Remove
  530. NULL, // Query Power
  531. NULL // Set Power
  532. };
  533. //
  534. // CaptureDeviceDescriptor:
  535. //
  536. // This is the device descriptor for the capture device. It points to the
  537. // dispatch table and contains a list of filter descriptors that describe
  538. // filter-types that this device supports. Note that the filter-descriptors
  539. // can be created dynamically and the factories created via
  540. // KsCreateFilterFactory as well.
  541. //
  542. const
  543. KSDEVICE_DESCRIPTOR
  544. CaptureDeviceDescriptor = {
  545. &CaptureDeviceDispatch,
  546. SIZEOF_ARRAY (FilterDescriptors),
  547. FilterDescriptors,
  548. KSDEVICE_DESCRIPTOR_VERSION
  549. };
  550. /**************************************************************************
  551. INITIALIZATION CODE
  552. **************************************************************************/
  553. extern "C"
  554. NTSTATUS
  555. DriverEntry (
  556. IN PDRIVER_OBJECT DriverObject,
  557. IN PUNICODE_STRING RegistryPath
  558. )
  559. /*++
  560. Routine Description:
  561. Driver entry point. Pass off control to the AVStream initialization
  562. function (KsInitializeDriver) and return the status code from it.
  563. Arguments:
  564. DriverObject -
  565. The WDM driver object for our driver
  566. RegistryPath -
  567. The registry path for our registry info
  568. Return Value:
  569. As from KsInitializeDriver
  570. --*/
  571. {
  572. NTSTATUS Status = STATUS_SUCCESS;
  573. //
  574. // Simply pass the device descriptor and parameters off to AVStream
  575. // to initialize us. This will cause filter factories to be set up
  576. // at add & start. Everything is done based on the descriptors passed
  577. // here.
  578. //
  579. Status = KsInitializeDriver (
  580. DriverObject,
  581. RegistryPath,
  582. &CaptureDeviceDescriptor
  583. );
  584. return Status;
  585. }