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.

1083 lines
31 KiB

  1. //--------------------------------------------------------------------------;
  2. //
  3. // File: dev.cpp
  4. //
  5. // Copyright (c) 1995-1997 Microsoft Corporation. All Rights Reserved.
  6. //
  7. // Abstract:
  8. // Contains program related to managing the direct sound drivers and
  9. // driver list.
  10. //
  11. // Contents:
  12. //
  13. // History:
  14. // 06/15/95 FrankYe
  15. //
  16. //--------------------------------------------------------------------------;
  17. #define WANTVXDWRAPS
  18. #include <windows.h>
  19. extern "C"
  20. {
  21. #include <vmm.h>
  22. #include <vxdldr.h>
  23. #include <vwin32.h>
  24. #include <vxdwraps.h>
  25. #include <configmg.h>
  26. }
  27. #define NODSOUNDWRAPS
  28. #include <mmsystem.h>
  29. #include <dsound.h>
  30. #include <dsdrvi.h>
  31. #include "dsvxd.h"
  32. #include "dsvxdi.h"
  33. #pragma warning(disable:4355) // 'this' : used in base member initializer list
  34. #pragma VxD_PAGEABLE_CODE_SEG
  35. #pragma VxD_PAGEABLE_DATA_SEG
  36. VMMLIST gvmmlistDrivers = 0;
  37. //==========================================================================;
  38. //
  39. // guid functions
  40. // guidAlloc: gets guid from guid pool and returns pointer to it
  41. // guidFree: returns guid to guid pool
  42. //
  43. //==========================================================================;
  44. //--------------------------------------------------------------------------;
  45. //
  46. //
  47. //--------------------------------------------------------------------------;
  48. // TODO need more static guids. this is enough for now
  49. GUID guidList[] = {
  50. { /* 3d0b92c0-abfc-11ce-a3b3-00aa004a9f0c */
  51. 0x3d0b92c0,
  52. 0xabfc,
  53. 0x11ce,
  54. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  55. },
  56. { /* 3d0b92c1-abfc-11ce-a3b3-00aa004a9f0c */
  57. 0x3d0b92c1,
  58. 0xabfc,
  59. 0x11ce,
  60. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  61. },
  62. { /* 3d0b92c2-abfc-11ce-a3b3-00aa004a9f0c */
  63. 0x3d0b92c2,
  64. 0xabfc,
  65. 0x11ce,
  66. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  67. },
  68. { /* 3d0b92c3-abfc-11ce-a3b3-00aa004a9f0c */
  69. 0x3d0b92c3,
  70. 0xabfc,
  71. 0x11ce,
  72. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  73. },
  74. { /* 3d0b92c4-abfc-11ce-a3b3-00aa004a9f0c */
  75. 0x3d0b92c4,
  76. 0xabfc,
  77. 0x11ce,
  78. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  79. },
  80. { /* 3d0b92c5-abfc-11ce-a3b3-00aa004a9f0c */
  81. 0x3d0b92c5,
  82. 0xabfc,
  83. 0x11ce,
  84. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  85. },
  86. { /* 3d0b92c6-abfc-11ce-a3b3-00aa004a9f0c */
  87. 0x3d0b92c6,
  88. 0xabfc,
  89. 0x11ce,
  90. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  91. },
  92. { /* 3d0b92c7-abfc-11ce-a3b3-00aa004a9f0c */
  93. 0x3d0b92c7,
  94. 0xabfc,
  95. 0x11ce,
  96. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  97. },
  98. { /* 3d0b92c8-abfc-11ce-a3b3-00aa004a9f0c */
  99. 0x3d0b92c8,
  100. 0xabfc,
  101. 0x11ce,
  102. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  103. },
  104. { /* 3d0b92c9-abfc-11ce-a3b3-00aa004a9f0c */
  105. 0x3d0b92c9,
  106. 0xabfc,
  107. 0x11ce,
  108. {0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
  109. }
  110. };
  111. #define NUMGUIDS (sizeof(guidList) / sizeof(guidList[0]))
  112. typedef struct tGUIDRECORD {
  113. LPCGUID pGuid;
  114. BOOL fAlloc;
  115. UINT uAge;
  116. } GUIDRECORD, *PGUIDRECORD;
  117. PGUIDRECORD gpaGuidRec;
  118. REFGUID GuidAlloc()
  119. {
  120. PGUIDRECORD pGuidRec;
  121. PGUIDRECORD pGuidRecOldest;
  122. UINT uAgeOldest;
  123. int i;
  124. pGuidRecOldest = NULL;
  125. uAgeOldest = 0;
  126. for (i=0; i<NUMGUIDS; i++) {
  127. pGuidRec = &gpaGuidRec[i];
  128. if (pGuidRec->fAlloc) continue;
  129. if (pGuidRec->uAge++ >= uAgeOldest) {
  130. pGuidRecOldest = pGuidRec;
  131. uAgeOldest = pGuidRec->uAge;
  132. }
  133. }
  134. if (NULL == pGuidRecOldest) {
  135. BREAK(("Ran out of guids"));
  136. return GUID_NULL;
  137. } else {
  138. pGuidRecOldest->fAlloc = TRUE;
  139. return *(pGuidRecOldest->pGuid);
  140. }
  141. }
  142. void GuidFree(REFGUID rGuid)
  143. {
  144. PGUIDRECORD pGuidRecMatch;
  145. int i;
  146. pGuidRecMatch = NULL;
  147. for (i=0; i<NUMGUIDS; i++) {
  148. if (IsEqualGUID(*gpaGuidRec[i].pGuid, rGuid)) {
  149. //
  150. // For debug, we go thru all guid records and assert if
  151. // we match on more than just one. For retail, we break
  152. // the loop as soon as we match one.
  153. //
  154. #ifdef DEBUG
  155. if (pGuidRecMatch != NULL) ASSERT(FALSE);
  156. pGuidRecMatch = &gpaGuidRec[i];
  157. #else
  158. pGuidRecMatch = &gpaGuidRec[i];
  159. break;
  160. #endif
  161. }
  162. }
  163. ASSERT(NULL != pGuidRecMatch);
  164. if (NULL == pGuidRecMatch) return; // defensive
  165. pGuidRecMatch->fAlloc = FALSE;
  166. pGuidRecMatch->uAge = 0;
  167. return;
  168. }
  169. //==========================================================================;
  170. //==========================================================================;
  171. //
  172. // CBuf_IDsDriverPropertySet class implementation
  173. //
  174. //==========================================================================;
  175. //==========================================================================;
  176. //--------------------------------------------------------------------------;
  177. //
  178. // Constructor
  179. //
  180. //--------------------------------------------------------------------------;
  181. CBuf_IDsDriverPropertySet::CBuf_IDsDriverPropertySet(CBuf *pBuf)
  182. {
  183. m_cRef = 0;
  184. m_pBuf = pBuf;
  185. return;
  186. }
  187. //--------------------------------------------------------------------------;
  188. //
  189. // QueryInterface - delegates to CBuf
  190. //
  191. //--------------------------------------------------------------------------;
  192. STDMETHODIMP CBuf_IDsDriverPropertySet::QueryInterface(REFIID riid, PVOID *ppv)
  193. {
  194. return m_pBuf->QueryInterface(riid, ppv);
  195. }
  196. //--------------------------------------------------------------------------;
  197. //
  198. // AddRef
  199. // Maintains interface ref count, and delegates to CBuf to maintain
  200. // total object ref count.
  201. //
  202. //--------------------------------------------------------------------------;
  203. STDMETHODIMP_(ULONG) CBuf_IDsDriverPropertySet::AddRef(void)
  204. {
  205. ASSERT(m_cRef >= 0);
  206. m_cRef++;
  207. m_pBuf->AddRef();
  208. return m_cRef;
  209. }
  210. //--------------------------------------------------------------------------;
  211. //
  212. // Release
  213. // Maintains interface ref count. When interface ref count goes to 0
  214. // then release the real driver's IDsDriverPropertySet interface. Also,
  215. // delegate to CBuf in order to maintain total object ref count
  216. //
  217. //--------------------------------------------------------------------------;
  218. STDMETHODIMP_(ULONG) CBuf_IDsDriverPropertySet::Release(void)
  219. {
  220. ASSERT(m_cRef > 0);
  221. if (--m_cRef > 0) {
  222. m_pBuf->Release();
  223. return m_cRef;
  224. }
  225. m_pBuf->m_pIDsDriverPropertySet_Real->Release();
  226. m_pBuf->m_pIDsDriverPropertySet_Real = NULL;
  227. m_pBuf->Release();
  228. return 0;
  229. }
  230. //--------------------------------------------------------------------------;
  231. //
  232. // Get, Set, QuerySupport
  233. // If CBuf hasn't been deregistered, call real driver's
  234. // IDsDriverPropertySet interface
  235. //
  236. //--------------------------------------------------------------------------;
  237. STDMETHODIMP CBuf_IDsDriverPropertySet::Get(PDSPROPERTY pDsProperty,
  238. PVOID pPropertyParams,
  239. ULONG cbPropertyParams,
  240. PVOID pPropertyData,
  241. ULONG cbPropertyData,
  242. PULONG pcbReturnedData)
  243. {
  244. if (m_pBuf->m_fDeregistered) return DSERR_NODRIVER;
  245. return m_pBuf->m_pIDsDriverPropertySet_Real->Get(pDsProperty, pPropertyParams,
  246. cbPropertyParams, pPropertyData, cbPropertyData, pcbReturnedData);
  247. }
  248. STDMETHODIMP CBuf_IDsDriverPropertySet::Set(PDSPROPERTY pDsProperty,
  249. PVOID pPropertyParams,
  250. ULONG cbPropertyParams,
  251. PVOID pPropertyData,
  252. ULONG cbPropertyData)
  253. {
  254. if (m_pBuf->m_fDeregistered) return DSERR_NODRIVER;
  255. return m_pBuf->m_pIDsDriverPropertySet_Real->Set(pDsProperty, pPropertyParams, cbPropertyParams, pPropertyData, cbPropertyData);
  256. }
  257. STDMETHODIMP CBuf_IDsDriverPropertySet::QuerySupport(REFGUID PropertySetId,
  258. ULONG PropertyId,
  259. PULONG pSupport)
  260. {
  261. if (m_pBuf->m_fDeregistered) return DSERR_NODRIVER;
  262. return m_pBuf->m_pIDsDriverPropertySet_Real->QuerySupport(PropertySetId, PropertyId, pSupport);
  263. }
  264. //==========================================================================;
  265. //==========================================================================;
  266. //
  267. // CBuf class implementation
  268. //
  269. //==========================================================================;
  270. //==========================================================================;
  271. //--------------------------------------------------------------------------;
  272. //
  273. // CBuf new and delete operators
  274. //
  275. // We allocate these objects as nodes on a VMMLIST. New takes a VMMLIST
  276. // as a parameter. We bump the size of the allocation enough to store the
  277. // VMMLIST handle at the end of the object. The Delete operator gets the
  278. // VMMLIST handle from the end of the storage that was allocated for the
  279. // object, and uses that hande to deallocate the list node. The objects
  280. // are also attached to and removed from the list as they are created and
  281. // deleted.
  282. //
  283. //--------------------------------------------------------------------------;
  284. //--------------------------------------------------------------------------;
  285. //
  286. //
  287. //
  288. //--------------------------------------------------------------------------;
  289. void* CBuf::operator new(size_t size, VMMLIST list)
  290. {
  291. PVOID pv;
  292. pv = List_Allocate(list);
  293. if (pv) {
  294. memset(pv, 0x00, size);
  295. *(VMMLIST*)((PBYTE)pv + size) = list;
  296. List_Attach_Tail(list, pv);
  297. }
  298. return pv;
  299. }
  300. //--------------------------------------------------------------------------;
  301. //
  302. //
  303. //
  304. //--------------------------------------------------------------------------;
  305. void CBuf::operator delete(void * pv, size_t size)
  306. {
  307. VMMLIST list;
  308. list = *(VMMLIST*)((PBYTE)pv + size);
  309. ASSERT(list);
  310. List_Remove(list, pv);
  311. List_Deallocate(list, pv);
  312. }
  313. //--------------------------------------------------------------------------;
  314. //
  315. // Constructor
  316. // Initializes its contained CBuf_IDsDriverPropertySet interface
  317. // implementation.
  318. //
  319. //--------------------------------------------------------------------------;
  320. CBuf::CBuf(void)
  321. : m_IDsDriverPropertySet(this)
  322. {
  323. return;
  324. }
  325. //--------------------------------------------------------------------------;
  326. //
  327. // CreateList
  328. // Static class method. It simpley creates a VMMLIST
  329. // to be used to create/delete CBuf objects.
  330. //
  331. //--------------------------------------------------------------------------;
  332. VMMLIST CBuf::CreateList(void)
  333. {
  334. return List_Create(LF_ALLOC_ERROR, sizeof(CBuf) + sizeof(VMMLIST));
  335. }
  336. //--------------------------------------------------------------------------;
  337. //
  338. // DeleteList
  339. // Static class method. Destroys a VMMLIST that was used to
  340. // create/destroy CBuf objects.
  341. //
  342. //--------------------------------------------------------------------------;
  343. void CBuf::DestroyList(VMMLIST list)
  344. {
  345. ASSERT(!List_Get_First(list));
  346. List_Destroy(list);
  347. }
  348. //--------------------------------------------------------------------------;
  349. //
  350. // CreateBuf
  351. // Static class method. Creates a CBuf object given the creating CDrv
  352. // object, the VMMLIST to be used to create the CBuf, and a pointer to the
  353. // IDsDriverBuffer interface on the real driver buffer to be contained by
  354. // the CBuf object.
  355. //
  356. //--------------------------------------------------------------------------;
  357. HRESULT CBuf::CreateBuf(CDrv *pDrv, VMMLIST list, IDsDriverBuffer *pIDsDriverBuffer_Real, IDsDriverBuffer **ppIDsDriverBuffer)
  358. {
  359. CBuf *pBuf;
  360. *ppIDsDriverBuffer = NULL;
  361. pBuf = new(list) CBuf;
  362. if (!pBuf) return E_OUTOFMEMORY;
  363. pBuf->m_pDrv = pDrv;
  364. pBuf->m_pIDsDriverBuffer_Real = pIDsDriverBuffer_Real;
  365. pBuf->AddRef();
  366. *ppIDsDriverBuffer = (IDsDriverBuffer*)pBuf;
  367. return S_OK;
  368. }
  369. //--------------------------------------------------------------------------;
  370. //
  371. // DeregisterBuffers
  372. // Static class method. Given a VMMLIST containing CBuf objects, this method
  373. // walks the list marking each of the CBuf objects as deregistered.
  374. //
  375. //--------------------------------------------------------------------------;
  376. void CBuf::DeregisterBuffers(VMMLIST list)
  377. {
  378. CBuf *pBuf;
  379. for ( pBuf = (CBuf*)List_Get_First(list);
  380. pBuf;
  381. pBuf = (CBuf*)List_Get_Next(list, pBuf) )
  382. {
  383. pBuf->m_fDeregistered = TRUE;
  384. }
  385. return;
  386. }
  387. //--------------------------------------------------------------------------;
  388. //
  389. // QueryInterface
  390. // When querying for IUnknown or IDsDriverBuffer, just return this
  391. // object. If querying for IDsDriverPropertySet, then we need to query
  392. // the real driver buffer for this interface, if we haven't already.
  393. //
  394. //--------------------------------------------------------------------------;
  395. STDMETHODIMP CBuf::QueryInterface(REFIID riid, LPVOID *ppv)
  396. {
  397. HRESULT hr;
  398. *ppv = NULL;
  399. if (IID_IUnknown == riid || IID_IDsDriverBuffer == riid) {
  400. *ppv = (IDsDriverBuffer*)this;
  401. } else if (IID_IDsDriverPropertySet == riid) {
  402. if (!m_pIDsDriverPropertySet_Real) {
  403. // don't have the interface from the driver so try to get it
  404. hr = m_pIDsDriverBuffer_Real->QueryInterface(riid, (PVOID*)&m_pIDsDriverPropertySet_Real);
  405. if (FAILED(hr) && m_pIDsDriverPropertySet_Real) {
  406. // TODO: RPF(Driver is stupic cuz it failed QI but set *ppv)
  407. m_pIDsDriverPropertySet_Real = NULL;
  408. }
  409. }
  410. if (m_pIDsDriverPropertySet_Real) {
  411. *ppv = &m_IDsDriverPropertySet;
  412. }
  413. }
  414. if (NULL == *ppv) return E_NOINTERFACE;
  415. ((LPUNKNOWN)*ppv)->AddRef();
  416. return S_OK;
  417. }
  418. //--------------------------------------------------------------------------;
  419. //
  420. // AddRef
  421. //
  422. //--------------------------------------------------------------------------;
  423. STDMETHODIMP_(ULONG) CBuf::AddRef(void)
  424. {
  425. m_cRef++;
  426. m_pDrv->AddRef();
  427. return m_cRef;
  428. }
  429. //--------------------------------------------------------------------------;
  430. //
  431. // Release
  432. // When the ref count goes to zero, then we release the real driver
  433. // buffer's IDsDriverBuffer interface. We always release the CDrv object
  434. // that created this CBuf, too, since we the CDrv lifetime brackets the
  435. // CBuf lifetime.
  436. //
  437. //--------------------------------------------------------------------------;
  438. STDMETHODIMP_(ULONG) CBuf::Release(void)
  439. {
  440. CDrv *pDrv;
  441. pDrv = m_pDrv;
  442. m_cRef--;
  443. if (0 == m_cRef) {
  444. DRVCALL(("IDsDriverBuffer(%008X)->Release()", m_pIDsDriverBuffer_Real));
  445. m_pIDsDriverBuffer_Real->Release();
  446. delete this;
  447. pDrv->Release();
  448. return 0;
  449. }
  450. pDrv->Release();
  451. return m_cRef;
  452. }
  453. //--------------------------------------------------------------------------;
  454. //
  455. // IDsDriverBuffer methods
  456. // Return error if the real driver has deregistered, otherwise
  457. // call the real driver's buffer's interface
  458. //
  459. //--------------------------------------------------------------------------;
  460. STDMETHODIMP CBuf::GetPosition(PDWORD pdwPlay, PDWORD pdwWrite)
  461. {
  462. if (m_fDeregistered) return DSERR_NODRIVER;
  463. DRVCALL(("IDsDriverBuffer(%08Xh)->GetPosition(%08Xh, %08Xh)", m_pIDsDriverBuffer_Real, pdwPlay, pdwWrite));
  464. return m_pIDsDriverBuffer_Real->GetPosition(pdwPlay, pdwWrite);
  465. }
  466. STDMETHODIMP CBuf::Lock(LPVOID *ppvAudio1,
  467. LPDWORD pdwLen1, LPVOID *ppvAudio2,
  468. LPDWORD pdwLen2, DWORD dwWritePosition,
  469. DWORD dwWriteLen, DWORD dwFlags)
  470. {
  471. if (m_fDeregistered) return DSERR_NODRIVER;
  472. DRVCALL(("IDsDriverBuffer(%08Xh)->Lock(%08Xh, %08Xh, %08Xh, %08Xh, %08Xh, %08Xh, %08Xh)",
  473. m_pIDsDriverBuffer_Real, ppvAudio1, pdwLen1, ppvAudio2,
  474. pdwLen2,dwWritePosition, dwWriteLen, dwFlags));
  475. return m_pIDsDriverBuffer_Real->Lock(ppvAudio1, pdwLen1, ppvAudio2, pdwLen2,
  476. dwWritePosition, dwWriteLen, dwFlags);
  477. }
  478. STDMETHODIMP CBuf::Play(DWORD dw1, DWORD dw2, DWORD dwFlags)
  479. {
  480. if (m_fDeregistered) return DSERR_NODRIVER;
  481. DRVCALL(("IDsDriverBuffer(%08Xh)->Play(%08Xh, %08Xh, %08Xh)", dw1, dw2, dwFlags));
  482. return m_pIDsDriverBuffer_Real->Play(dw1, dw2, dwFlags);
  483. }
  484. STDMETHODIMP CBuf::SetFormat(LPWAVEFORMATEX pwfx)
  485. {
  486. if (m_fDeregistered) return DSERR_NODRIVER;
  487. DRVCALL(("IDsDriverBuffer(%08Xh)->SetFormat(%08Xh)", m_pIDsDriverBuffer_Real, pwfx));
  488. return m_pIDsDriverBuffer_Real->SetFormat(pwfx);
  489. }
  490. STDMETHODIMP CBuf::SetFrequency(DWORD dwFrequency)
  491. {
  492. if (m_fDeregistered) return DSERR_NODRIVER;
  493. DRVCALL(("IDsDriverBuffer(%08Xh)->SetFrequency(%08Xh)", m_pIDsDriverBuffer_Real, dwFrequency));
  494. return m_pIDsDriverBuffer_Real->SetFrequency(dwFrequency);
  495. }
  496. STDMETHODIMP CBuf::SetPosition(DWORD dwPosition)
  497. {
  498. if (m_fDeregistered) return DSERR_NODRIVER;
  499. DRVCALL(("IDsDriverBuffer(%08Xh)->SetPosition(%08Xh)", m_pIDsDriverBuffer_Real, dwPosition));
  500. return m_pIDsDriverBuffer_Real->SetPosition(dwPosition);
  501. }
  502. STDMETHODIMP CBuf::SetVolumePan(PDSVOLUMEPAN pDsVolumePan)
  503. {
  504. if (m_fDeregistered) return DSERR_NODRIVER;
  505. DRVCALL(("IDsDriverBuffer(%08Xh)->SetVolumePan(%08Xh)", m_pIDsDriverBuffer_Real, pDsVolumePan));
  506. return m_pIDsDriverBuffer_Real->SetVolumePan(pDsVolumePan);
  507. }
  508. STDMETHODIMP CBuf::Stop(void)
  509. {
  510. if (m_fDeregistered) return DSERR_NODRIVER;
  511. DRVCALL(("IDsDriverBuffer(%08Xh)->Stop()", m_pIDsDriverBuffer_Real));
  512. return m_pIDsDriverBuffer_Real->Stop();
  513. }
  514. STDMETHODIMP CBuf::Unlock(LPVOID pvAudio1,
  515. DWORD dwLen1, LPVOID pvAudio2,
  516. DWORD dwLen2)
  517. {
  518. if (m_fDeregistered) return DSERR_NODRIVER;
  519. DRVCALL(("IDsDriverBuffer(%08Xh)->Unlock(%08Xh, %08Xh, %08Xh, %08Xh)",
  520. m_pIDsDriverBuffer_Real, pvAudio1, dwLen1, pvAudio2, dwLen2));
  521. return m_pIDsDriverBuffer_Real->Unlock(pvAudio1, dwLen1, pvAudio2, dwLen2);
  522. }
  523. STDMETHODIMP_(BOOL) CBuf::IsDeregistered(void)
  524. {
  525. return m_fDeregistered;
  526. }
  527. STDMETHODIMP_(IDsDriverBuffer*) CBuf::GetRealDsDriverBuffer(void)
  528. {
  529. return m_pIDsDriverBuffer_Real;
  530. }
  531. //==========================================================================;
  532. //==========================================================================;
  533. //
  534. // CDrv class implementation
  535. //
  536. //==========================================================================;
  537. //==========================================================================;
  538. //--------------------------------------------------------------------------;
  539. //
  540. // CDrv new and delete operators
  541. // These allocate the CDrv objects on a VMMLIST whose handle
  542. // has gobal scope (thus we don't need to same VMMLIST handle trickery
  543. // as we use the new/delete operators for the CBuf class).
  544. //
  545. //--------------------------------------------------------------------------;
  546. void* CDrv::operator new(size_t size)
  547. {
  548. PVOID pv;
  549. ASSERT(0 != gvmmlistDrivers);
  550. pv = List_Allocate(gvmmlistDrivers);
  551. if (NULL != pv) memset(pv, 0x00, size);
  552. return pv;
  553. }
  554. void CDrv::operator delete(void * pv)
  555. {
  556. List_Deallocate(gvmmlistDrivers, pv);
  557. }
  558. //==========================================================================;
  559. //
  560. // CDrv class methods
  561. //
  562. //==========================================================================;
  563. HRESULT CDrv::CreateAndRegisterDriver(IDsDriver *pIDsDriver)
  564. {
  565. CDrv *pDrv;
  566. HRESULT hr;
  567. pDrv = new CDrv;
  568. if (pDrv) {
  569. pDrv->m_cRef=0;
  570. pDrv->m_cOpen = 0;
  571. pDrv->m_fDeregistered = FALSE;
  572. pDrv->m_pIDsDriver_Real = pIDsDriver;
  573. pDrv->m_listBuffers = CBuf::CreateList();
  574. if (pDrv->m_listBuffers) {
  575. pDrv->m_guidDriver = GuidAlloc();
  576. if (!IsEqualGUID(GUID_NULL, pDrv->m_guidDriver)) {
  577. List_Attach_Tail(gvmmlistDrivers, pDrv);
  578. pDrv->AddRef();
  579. hr = S_OK;
  580. } else {
  581. hr = DSERR_GENERIC;
  582. }
  583. if (FAILED(hr)) {
  584. CBuf::DestroyList(pDrv->m_listBuffers);
  585. }
  586. } else {
  587. hr = E_OUTOFMEMORY;
  588. }
  589. if (FAILED(hr)) {
  590. delete pDrv;
  591. }
  592. } else {
  593. hr = E_OUTOFMEMORY;
  594. }
  595. return hr;
  596. }
  597. HRESULT CDrv::DeregisterDriver(IDsDriver *pIDsDriver)
  598. {
  599. CDrv *pDrv;
  600. ASSERT(0 != gvmmlistDrivers);
  601. pDrv = FindFromIDsDriver(pIDsDriver);
  602. if (NULL == pDrv) {
  603. BREAK(("Tried to deregister a driver that's not registered"));
  604. return DSERR_INVALIDPARAM;
  605. }
  606. if (0 != pDrv->m_cOpen) {
  607. DPF(("warning: driver deregistered while it was open"));
  608. }
  609. CBuf::DeregisterBuffers(pDrv->m_listBuffers);
  610. pDrv->m_fDeregistered = TRUE;
  611. pDrv->Release();
  612. return S_OK;
  613. }
  614. //--------------------------------------------------------------------------;
  615. //
  616. // CDrv::GetNextDescFromGuid
  617. //
  618. // Gets the driver description of the next driver after the one having
  619. // the specified GUID
  620. //
  621. // Entry:
  622. //
  623. // Returns (HRESULT):
  624. //
  625. // Notes:
  626. //
  627. //--------------------------------------------------------------------------;
  628. HRESULT CDrv::GetNextDescFromGuid(LPCGUID pGuidLast, LPGUID pGuid, PDSDRIVERDESC pDrvDesc)
  629. {
  630. CDrv *pDrv;
  631. DSVAL dsv;
  632. ASSERT(gvmmlistDrivers);
  633. if ((NULL == pGuidLast) || IsEqualGUID(GUID_NULL, *pGuidLast)) {
  634. pDrv = (CDrv*)List_Get_First(gvmmlistDrivers);
  635. } else {
  636. pDrv = FindFromGuid(*pGuidLast);
  637. if (NULL != pDrv) {
  638. pDrv = (CDrv*)List_Get_Next(gvmmlistDrivers, pDrv);
  639. }
  640. }
  641. if (NULL == pDrv) return DSERR_NODRIVER;
  642. *pGuid = pDrv->m_guidDriver;
  643. dsv = pDrv->GetDriverDesc(pDrvDesc);
  644. return dsv;
  645. }
  646. HRESULT CDrv::GetDescFromGuid(REFGUID rguidDriver, PDSDRIVERDESC pDrvDesc)
  647. {
  648. CDrv *pDrv;
  649. DSVAL dsv;
  650. ASSERT(gvmmlistDrivers);
  651. pDrv = FindFromGuid(rguidDriver);
  652. if (NULL == pDrv) return DSERR_NODRIVER;
  653. dsv = pDrv->GetDriverDesc(pDrvDesc);
  654. return dsv;
  655. }
  656. HRESULT CDrv::OpenFromGuid(REFGUID refGuid, IDsDriver **ppIDsDriver)
  657. {
  658. CDrv *pDrv;
  659. HRESULT hr;
  660. *ppIDsDriver = NULL;
  661. pDrv = FindFromGuid(refGuid);
  662. if (pDrv) {
  663. hr = pDrv->Open();
  664. if (SUCCEEDED(hr)) {
  665. *ppIDsDriver = pDrv;
  666. }
  667. } else {
  668. hr = DSERR_NODRIVER;
  669. }
  670. return hr;
  671. }
  672. CDrv* CDrv::FindFromIDsDriver(IDsDriver *pIDsDriver)
  673. {
  674. CDrv *pDrv;
  675. ASSERT(gvmmlistDrivers);
  676. pDrv = (CDrv*)List_Get_First(gvmmlistDrivers);
  677. while ((NULL != pDrv) && (pDrv->m_pIDsDriver_Real != pIDsDriver)) {
  678. pDrv = (CDrv*)List_Get_Next(gvmmlistDrivers, pDrv);
  679. }
  680. return pDrv;
  681. }
  682. CDrv* CDrv::FindFromGuid(REFGUID riid)
  683. {
  684. CDrv *pDrv;
  685. ASSERT(gvmmlistDrivers);
  686. pDrv = (CDrv*)List_Get_First(gvmmlistDrivers);
  687. while ((NULL != pDrv) && (!IsEqualGUID(riid, pDrv->m_guidDriver))) {
  688. pDrv = (CDrv*)List_Get_Next(gvmmlistDrivers, pDrv);
  689. }
  690. return pDrv;
  691. }
  692. //==========================================================================;
  693. //
  694. // COM interface implementations
  695. //
  696. //==========================================================================;
  697. STDMETHODIMP CDrv::QueryInterface(REFIID riid, PVOID* ppv)
  698. {
  699. *ppv = NULL;
  700. if ((IID_IUnknown == riid) || (IID_IDsDriver == riid))
  701. *ppv = this;
  702. if (NULL == *ppv)
  703. return E_NOINTERFACE;
  704. ((LPUNKNOWN)*ppv)->AddRef();
  705. return NOERROR;
  706. }
  707. STDMETHODIMP_(ULONG) CDrv::AddRef(void)
  708. {
  709. ASSERT(m_cRef >= 0);
  710. return ++m_cRef;
  711. }
  712. STDMETHODIMP_(ULONG) CDrv::Release(void)
  713. {
  714. ASSERT(m_cRef > 0);
  715. if (0 >= --m_cRef) {
  716. ASSERT(gvmmlistDrivers);
  717. List_Remove(gvmmlistDrivers, this);
  718. GuidFree(m_guidDriver);
  719. ASSERT(m_listBuffers);
  720. ASSERT(!List_Get_First(m_listBuffers));
  721. CBuf::DestroyList(m_listBuffers);
  722. m_listBuffers = NULL;
  723. delete this;
  724. return 0;
  725. } else {
  726. return m_cRef;
  727. }
  728. }
  729. STDMETHODIMP CDrv::GetDriverDesc(PDSDRIVERDESC pDsDriverDesc)
  730. {
  731. if (m_fDeregistered) return DSERR_NODRIVER;
  732. DRVCALL(("IDsDriver(%08Xh)->GetDriverDesc(%08Xh)", m_pIDsDriver_Real, pDsDriverDesc));
  733. return m_pIDsDriver_Real->GetDriverDesc(pDsDriverDesc);
  734. }
  735. STDMETHODIMP CDrv::Open(void)
  736. {
  737. HRESULT hr;
  738. ASSERT(0 == m_cOpen);
  739. if (m_fDeregistered) return DSERR_NODRIVER;
  740. DRVCALL(("IDsDriver(%08Xh)->Open()", m_pIDsDriver_Real));
  741. hr = m_pIDsDriver_Real->Open();
  742. if (SUCCEEDED(hr)) {
  743. m_cOpen++;
  744. AddRef();
  745. }
  746. return hr;
  747. }
  748. STDMETHODIMP CDrv::Close(void)
  749. {
  750. HRESULT hr;
  751. ASSERT(m_cOpen > 0);
  752. m_cOpen--;
  753. if (m_fDeregistered) {
  754. DPF(("driver must have deregistered while open"));
  755. Release();
  756. return NOERROR;
  757. }
  758. DRVCALL(("IDsDriver(%08Xh)->Close()", m_pIDsDriver_Real));
  759. hr = m_pIDsDriver_Real->Close();
  760. if (SUCCEEDED(hr)) Release();
  761. // Warning: _this_ object may have been destroyed by
  762. // the above calls to Release();
  763. return hr;
  764. }
  765. STDMETHODIMP CDrv::GetCaps(PDSDRIVERCAPS pDsDriverCaps)
  766. {
  767. if (m_fDeregistered) {
  768. return DSERR_NODRIVER;
  769. } else {
  770. DRVCALL(("IDsDriver(%08Xh)->GetCaps(%08Xh)", m_pIDsDriver_Real, pDsDriverCaps));
  771. return m_pIDsDriver_Real->GetCaps(pDsDriverCaps);
  772. }
  773. }
  774. STDMETHODIMP CDrv::CreateSoundBuffer(LPWAVEFORMATEX pwfx,
  775. DWORD dwFlags,
  776. DWORD dwCardAddress,
  777. LPDWORD pdwcbBufferSize,
  778. LPBYTE *ppbBuffer,
  779. LPVOID *ppv)
  780. {
  781. LPWAVEFORMATEX pwfxKernel;
  782. int cbwfx;
  783. IDsDriverBuffer *pIDsDriverBuffer_Real;
  784. HRESULT hr;
  785. *ppv = NULL;
  786. if (m_fDeregistered) {
  787. return DSERR_NODRIVER;
  788. }
  789. //
  790. // Note that some drivers (mwave) appear to access the WAVEFORMATEX
  791. // structure from another thread. So, we must guarantee that the
  792. // this structure is in the global heap before passing it to the
  793. // driver. As a side effect, this code also ensures that a full
  794. // WAVEFORMATEX structure is passed to the driver, not just a
  795. // PCMWAVEFORMAT. I seem to recall some drivers always expecting
  796. // a full WAVEFORMATEX structure, but I'm not sure.
  797. //
  798. if (WAVE_FORMAT_PCM == pwfx->wFormatTag) {
  799. cbwfx = sizeof(PCMWAVEFORMAT);
  800. } else {
  801. cbwfx = sizeof(WAVEFORMATEX) + pwfx->cbSize;
  802. }
  803. pwfxKernel = (LPWAVEFORMATEX)_HeapAllocate(max(cbwfx, sizeof(WAVEFORMATEX)), HEAPZEROINIT | HEAPSWAP);
  804. if (pwfxKernel) {
  805. memcpy(pwfxKernel, pwfx, cbwfx);
  806. DRVCALL(("IDsDriver(%08Xh)->CreateSoundBuffer(%08X, %08X, %08X, %08X, %08X, %08X)",
  807. m_pIDsDriver_Real, pwfx, dwFlags, dwCardAddress, pdwcbBufferSize, ppbBuffer, &pIDsDriverBuffer_Real));
  808. hr = m_pIDsDriver_Real->CreateSoundBuffer(pwfxKernel, dwFlags, dwCardAddress, pdwcbBufferSize,
  809. ppbBuffer, (PVOID*)&pIDsDriverBuffer_Real);
  810. if (SUCCEEDED(hr)) {
  811. hr = CBuf::CreateBuf(this, m_listBuffers, pIDsDriverBuffer_Real, (IDsDriverBuffer**)ppv);
  812. if (FAILED(hr)) {
  813. pIDsDriverBuffer_Real->Release();
  814. ASSERT(NULL == *ppv);
  815. }
  816. }
  817. _HeapFree(pwfxKernel, 0);
  818. } else {
  819. hr = E_OUTOFMEMORY;
  820. }
  821. return hr;
  822. }
  823. STDMETHODIMP CDrv::DuplicateSoundBuffer(PIDSDRIVERBUFFER pIDsDriverBuffer, LPVOID *ppv)
  824. {
  825. IDsDriverBuffer *pIDsDriverBufferDup_Real;
  826. HRESULT hr;
  827. *ppv = NULL;
  828. if (m_fDeregistered) {
  829. return DSERR_NODRIVER;
  830. }
  831. DRVCALL(("IDsDriver(%08Xh)->DuplicateSoundBuffer(...)", m_pIDsDriver_Real));
  832. hr = m_pIDsDriver_Real->DuplicateSoundBuffer(((CBuf*)pIDsDriverBuffer)->GetRealDsDriverBuffer(), (PVOID*)&pIDsDriverBufferDup_Real);
  833. if (SUCCEEDED(hr)) {
  834. hr = CBuf::CreateBuf(this, m_listBuffers, pIDsDriverBufferDup_Real, (IDsDriverBuffer**)ppv);
  835. if (FAILED(hr)) {
  836. DRVCALL(("IDsDriver(%08Xh)->Release()", m_pIDsDriver_Real));
  837. pIDsDriverBufferDup_Real->Release();
  838. ASSERT(NULL == *ppv);
  839. }
  840. }
  841. return hr;
  842. }
  843. //==========================================================================;
  844. //
  845. // DSOUND_RegisterDeviceDriver
  846. // DSOUND_DeregisterDeviceDriver
  847. //
  848. // These services are called by a direct sound driver when the driver
  849. // initializes or terminates to register/deregister itself as a direct
  850. // sound driver. Typcially, these would be called from
  851. // within the driver's PnP CONFIG_START and CONFIG_STOP handlers.
  852. //
  853. // Entry:
  854. // PIDSDRIVER pIDsDriver: pointer to the driver's interface
  855. //
  856. // DWORD dwFlags: reserved, caller should set to 0
  857. //
  858. // Returns (DSVAL):
  859. //
  860. // Notes:
  861. // We maintain a list of drivers using the VMM List_* services. Each node
  862. // of the list is a DSDRV structure. During registration, a list node is
  863. // created and insterted into the list. The pIDsDriver member is initialized
  864. // with a pointer to the driver's interface. When deregistering, the node
  865. // is marked as deregistered. If there are no open instances on the driver,
  866. // then the node is removed from the list.
  867. //
  868. //==========================================================================;
  869. HRESULT SERVICE DSOUND_RegisterDeviceDriver(PIDSDRIVER pIDsDriver, DWORD dwFlags)
  870. {
  871. DPF(("DSOUND_RegisterDeviceDriver(%08Xh, %08Xh)", pIDsDriver, dwFlags));
  872. return CDrv::CreateAndRegisterDriver(pIDsDriver);
  873. }
  874. HRESULT SERVICE DSOUND_DeregisterDeviceDriver(PIDSDRIVER pIDsDriver, DWORD dwFlags)
  875. {
  876. DPF(("DSOUND_DeregisterDeviceDriver(%08Xh, %08Xh)", pIDsDriver, dwFlags));
  877. return CDrv::DeregisterDriver(pIDsDriver);
  878. }
  879. //==========================================================================;
  880. //
  881. // VxD CONTROL routines for drv
  882. //
  883. //==========================================================================;
  884. int ctrlDrvInit()
  885. {
  886. int i;
  887. gvmmlistDrivers = List_Create(LF_ALLOC_ERROR, sizeof(CDrv));
  888. if (0 == gvmmlistDrivers) return 0;
  889. gpaGuidRec = (PGUIDRECORD)_HeapAllocate( NUMGUIDS*sizeof(gpaGuidRec[0]), HEAPZEROINIT );
  890. if (NULL == gpaGuidRec) {
  891. List_Destroy(gvmmlistDrivers);
  892. gvmmlistDrivers = 0;
  893. return 0;
  894. }
  895. for (i=0; i<NUMGUIDS; i++)
  896. gpaGuidRec[i].pGuid = &guidList[i];
  897. return 1;
  898. }
  899. int ctrlDrvExit()
  900. {
  901. if (NULL != gpaGuidRec) {
  902. _HeapFree(gpaGuidRec, 0);
  903. gpaGuidRec = NULL;
  904. }
  905. if (0 != gvmmlistDrivers) {
  906. List_Destroy(gvmmlistDrivers);
  907. gvmmlistDrivers = 0;
  908. }
  909. return 1;
  910. }