├── Bin ├── 2k3_amd64 │ └── rtsdaudio.sys ├── 2k3_ia64 │ └── rtsdaudio.sys ├── 2k3_x86 │ └── rtsdaudio.sys └── XP_x86 │ └── rtsdaudio.sys ├── adapter.cpp ├── common.cpp ├── common.h ├── hw.cpp ├── hw.h ├── kshelper.cpp ├── kshelper.h ├── makefile ├── rtsdaudio.h ├── rtsdaudio.inf ├── rtsdaudio.rc ├── rtsdtopo.cpp ├── rtsdtopo.h ├── rtsdwave.cpp ├── rtsdwave.h ├── rtsdwavestream.cpp ├── rtsdwavestream.h ├── sources ├── toptable.h └── wavtable.h /Bin/2k3_amd64/rtsdaudio.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/02strich/LoopbackAudioDriver/7b582ea0867f407899dc7374762a24fcb6e61c21/Bin/2k3_amd64/rtsdaudio.sys -------------------------------------------------------------------------------- /Bin/2k3_ia64/rtsdaudio.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/02strich/LoopbackAudioDriver/7b582ea0867f407899dc7374762a24fcb6e61c21/Bin/2k3_ia64/rtsdaudio.sys -------------------------------------------------------------------------------- /Bin/2k3_x86/rtsdaudio.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/02strich/LoopbackAudioDriver/7b582ea0867f407899dc7374762a24fcb6e61c21/Bin/2k3_x86/rtsdaudio.sys -------------------------------------------------------------------------------- /Bin/XP_x86/rtsdaudio.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/02strich/LoopbackAudioDriver/7b582ea0867f407899dc7374762a24fcb6e61c21/Bin/XP_x86/rtsdaudio.sys -------------------------------------------------------------------------------- /adapter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | adapter.cpp 4 | 5 | Abstract: 6 | Setup and miniport installation. No resources are used by msvad. 7 | */ 8 | 9 | // All the GUIDS for all the miniports end up in this object. 10 | #define PUT_GUIDS_HERE 11 | 12 | #include "rtsdaudio.h" 13 | #include "common.h" 14 | 15 | //----------------------------------------------------------------------------- 16 | // Defines 17 | //----------------------------------------------------------------------------- 18 | // BUGBUG set this to number of miniports 19 | #define MAX_MINIPORTS 3 // Number of maximum miniports. 20 | 21 | //----------------------------------------------------------------------------- 22 | // Externals 23 | //----------------------------------------------------------------------------- 24 | NTSTATUS CreateMiniportWaveCyclic( 25 | OUT PUNKNOWN *, 26 | IN REFCLSID, 27 | IN PUNKNOWN, 28 | IN POOL_TYPE 29 | ); 30 | 31 | NTSTATUS CreateMiniportTopology( 32 | OUT PUNKNOWN *, 33 | IN REFCLSID, 34 | IN PUNKNOWN, 35 | IN POOL_TYPE 36 | ); 37 | 38 | //----------------------------------------------------------------------------- 39 | // Referenced forward. 40 | //----------------------------------------------------------------------------- 41 | extern "C" NTSTATUS AddDevice( 42 | IN PDRIVER_OBJECT, 43 | IN PDEVICE_OBJECT 44 | ); 45 | 46 | NTSTATUS StartDevice( 47 | IN PDEVICE_OBJECT, 48 | IN PIRP, 49 | IN PRESOURCELIST 50 | ); 51 | 52 | //----------------------------------------------------------------------------- 53 | // Functions 54 | //----------------------------------------------------------------------------- 55 | #pragma code_seg("INIT") 56 | extern "C" NTSTATUS DriverEntry( 57 | IN PDRIVER_OBJECT DriverObject, 58 | IN PUNICODE_STRING RegistryPathName 59 | ) 60 | { 61 | /* 62 | Routine Description: 63 | Installable driver initialization entry point. 64 | This entry point is called directly by the I/O system. 65 | 66 | All audio adapter drivers can use this code without change. 67 | 68 | Arguments: 69 | DriverObject - pointer to the driver object 70 | RegistryPath - pointer to a unicode string representing the path, 71 | to driver-specific key in the registry. 72 | 73 | Return Value: 74 | STATUS_SUCCESS if successful, 75 | STATUS_UNSUCCESSFUL otherwise. 76 | */ 77 | PAGED_CODE(); 78 | 79 | NTSTATUS ntStatus; 80 | 81 | DPF(D_TERSE, ("[DriverEntry]")); 82 | 83 | // Tell the class driver to initialize the driver. 84 | ntStatus = PcInitializeAdapterDriver( 85 | DriverObject, 86 | RegistryPathName, 87 | AddDevice 88 | ); 89 | 90 | return ntStatus; 91 | } // DriverEntry 92 | #pragma code_seg() 93 | 94 | #pragma code_seg("PAGE") 95 | //============================================================================= 96 | extern "C" NTSTATUS AddDevice( 97 | IN PDRIVER_OBJECT DriverObject, 98 | IN PDEVICE_OBJECT PhysicalDeviceObject 99 | ) 100 | /* 101 | Routine Description: 102 | The Plug & Play subsystem is handing us a brand new PDO, for which we 103 | (by means of INF registration) have been asked to provide a driver. 104 | 105 | We need to determine if we need to be in the driver stack for the device. 106 | Create a function device object to attach to the stack 107 | Initialize that device object 108 | Return status success. 109 | 110 | All audio adapter drivers can use this code without change. 111 | Set MAX_MINIPORTS depending on the number of miniports that the driver 112 | uses. 113 | 114 | Arguments: 115 | DriverObject - pointer to a driver object 116 | PhysicalDeviceObject - pointer to a device object created by the 117 | underlying bus driver. 118 | 119 | Return Value: 120 | NT status code. 121 | */ 122 | { 123 | PAGED_CODE(); 124 | 125 | NTSTATUS ntStatus; 126 | 127 | DPF(D_TERSE, ("[AddDevice]")); 128 | 129 | // Tell the class driver to add the device. 130 | ntStatus = PcAddAdapterDevice( 131 | DriverObject, 132 | PhysicalDeviceObject, 133 | PCPFNSTARTDEVICE(StartDevice), 134 | MAX_MINIPORTS, 135 | 0 136 | ); 137 | 138 | return ntStatus; 139 | } // AddDevice 140 | 141 | //============================================================================= 142 | NTSTATUS InstallSubdevice( 143 | IN PDEVICE_OBJECT DeviceObject, 144 | IN PIRP Irp, 145 | IN PWCHAR Name, 146 | IN REFGUID PortClassId, 147 | IN REFGUID MiniportClassId, 148 | IN PFNCREATEINSTANCE MiniportCreate OPTIONAL, 149 | IN PUNKNOWN UnknownAdapter OPTIONAL, 150 | IN PRESOURCELIST ResourceList, 151 | IN REFGUID PortInterfaceId, 152 | OUT PUNKNOWN * OutPortInterface OPTIONAL, 153 | OUT PUNKNOWN * OutPortUnknown OPTIONAL 154 | ) 155 | { 156 | /*++ 157 | Routine Description: 158 | This function creates and registers a subdevice consisting of a port 159 | driver, a minport driver and a set of resources bound together. It will 160 | also optionally place a pointer to an interface on the port driver in a 161 | specified location before initializing the port driver. This is done so 162 | that a common ISR can have access to the port driver during 163 | initialization, when the ISR might fire. 164 | 165 | Arguments: 166 | DeviceObject - pointer to the driver object 167 | Irp - pointer to the irp object. 168 | Name - name of the miniport. Passes to PcRegisterSubDevice 169 | PortClassId - port class id. Passed to PcNewPort. 170 | MiniportClassId - miniport class id. Passed to PcNewMiniport. 171 | MiniportCreate - pointer to a miniport creation function. If NULL, 172 | PcNewMiniport is used. 173 | UnknownAdapter - pointer to the adapter object. 174 | Used for initializing the port. 175 | ResourceList - pointer to the resource list. 176 | PortInterfaceId - GUID that represents the port interface. 177 | OutPortInterface - pointer to store the port interface 178 | OutPortUnknown - pointer to store the unknown port interface. 179 | 180 | Return Value: 181 | NT status code. 182 | --*/ 183 | PAGED_CODE(); 184 | 185 | ASSERT(DeviceObject); 186 | ASSERT(Irp); 187 | ASSERT(Name); 188 | 189 | NTSTATUS ntStatus; 190 | PPORT port = NULL; 191 | PUNKNOWN miniport = NULL; 192 | 193 | DPF_ENTER(("[InstallSubDevice %s]", Name)); 194 | 195 | // Create the port driver object 196 | ntStatus = PcNewPort(&port, PortClassId); 197 | 198 | // Create the miniport object 199 | if (NT_SUCCESS(ntStatus)) { 200 | if (MiniportCreate) { 201 | ntStatus = MiniportCreate( 202 | &miniport, 203 | MiniportClassId, 204 | NULL, 205 | NonPagedPool 206 | ); 207 | } else { 208 | ntStatus = PcNewMiniport( 209 | (PMINIPORT *) &miniport, 210 | MiniportClassId 211 | ); 212 | } 213 | } 214 | 215 | // Init the port driver and miniport in one go. 216 | if (NT_SUCCESS(ntStatus)) { 217 | ntStatus = port->Init( 218 | DeviceObject, 219 | Irp, 220 | miniport, 221 | UnknownAdapter, 222 | ResourceList 223 | ); 224 | 225 | if (NT_SUCCESS(ntStatus)) { 226 | // Register the subdevice (port/miniport combination). 227 | ntStatus = PcRegisterSubdevice( 228 | DeviceObject, 229 | Name, 230 | port 231 | ); 232 | } 233 | 234 | // We don't need the miniport any more. Either the port has it, 235 | // or we've failed, and it should be deleted. 236 | miniport->Release(); 237 | } 238 | 239 | // Deposit the port interfaces if it's needed. 240 | if (NT_SUCCESS(ntStatus)) { 241 | if (OutPortUnknown) { 242 | ntStatus = port->QueryInterface( 243 | IID_IUnknown, 244 | (PVOID *)OutPortUnknown 245 | ); 246 | } 247 | 248 | if (OutPortInterface) { 249 | ntStatus = port->QueryInterface( 250 | PortInterfaceId, 251 | (PVOID *) OutPortInterface 252 | ); 253 | } 254 | } 255 | 256 | if (port) { 257 | port->Release(); 258 | } 259 | 260 | return ntStatus; 261 | } // InstallSubDevice 262 | 263 | //============================================================================= 264 | NTSTATUS StartDevice 265 | ( 266 | IN PDEVICE_OBJECT DeviceObject, 267 | IN PIRP Irp, 268 | IN PRESOURCELIST ResourceList 269 | ) 270 | { 271 | /*++ 272 | Routine Description: 273 | This function is called by the operating system when the device is 274 | started. 275 | It is responsible for starting the miniports. This code is specific to 276 | the adapter because it calls out miniports for functions that are specific 277 | to the adapter. 278 | 279 | Arguments: 280 | DeviceObject - pointer to the driver object 281 | Irp - pointer to the irp 282 | ResourceList - pointer to the resource list assigned by PnP manager 283 | 284 | Return Value: 285 | NT status code. 286 | --*/ 287 | PAGED_CODE(); 288 | 289 | ASSERT(DeviceObject); 290 | ASSERT(Irp); 291 | ASSERT(ResourceList); 292 | 293 | NTSTATUS ntStatus = STATUS_SUCCESS; 294 | PUNKNOWN unknownTopology = NULL; 295 | PUNKNOWN unknownWave = NULL; 296 | PADAPTERCOMMON pAdapterCommon = NULL; 297 | PUNKNOWN pUnknownCommon = NULL; 298 | 299 | DPF_ENTER(("[StartDevice]")); 300 | 301 | // create a new adapter common object 302 | ntStatus = NewAdapterCommon( 303 | &pUnknownCommon, 304 | IID_IAdapterCommon, 305 | NULL, 306 | NonPagedPool 307 | ); 308 | 309 | if (NT_SUCCESS(ntStatus)) { 310 | ntStatus = pUnknownCommon->QueryInterface( 311 | IID_IAdapterCommon, 312 | (PVOID *) &pAdapterCommon 313 | ); 314 | 315 | if (NT_SUCCESS(ntStatus)) { 316 | ntStatus = pAdapterCommon->Init(DeviceObject); 317 | 318 | if (NT_SUCCESS(ntStatus)) { 319 | // register with PortCls for power-management services 320 | ntStatus = PcRegisterAdapterPowerManagement( 321 | PUNKNOWN(pAdapterCommon), 322 | DeviceObject 323 | ); 324 | } 325 | } 326 | } 327 | 328 | // install MSVAD topology miniport. 329 | if (NT_SUCCESS(ntStatus)) { 330 | ntStatus = InstallSubdevice( 331 | DeviceObject, 332 | Irp, 333 | L"Topology", 334 | CLSID_PortTopology, 335 | CLSID_PortTopology, 336 | CreateMiniportTopology, 337 | pAdapterCommon, 338 | NULL, 339 | IID_IPortTopology, 340 | NULL, 341 | &unknownTopology 342 | ); 343 | } 344 | 345 | // install MSVAD wavecyclic miniport. 346 | if (NT_SUCCESS(ntStatus)) { 347 | ntStatus = InstallSubdevice( 348 | DeviceObject, 349 | Irp, 350 | L"Wave", 351 | CLSID_PortWaveCyclic, 352 | CLSID_PortWaveCyclic, 353 | CreateMiniportWaveCyclic, 354 | pAdapterCommon, 355 | NULL, 356 | IID_IPortWaveCyclic, 357 | pAdapterCommon->WavePortDriverDest(), 358 | &unknownWave 359 | ); 360 | } 361 | 362 | if (unknownTopology && unknownWave) 363 | { 364 | // register wave <=> topology connections 365 | // This will connect bridge pins of wavecyclic and topology 366 | // miniports. 367 | ntStatus = PcRegisterPhysicalConnection( 368 | DeviceObject, 369 | unknownTopology, 370 | TopologyPhysicalConnections.ulTopologyOut, 371 | unknownWave, 372 | TopologyPhysicalConnections.ulWaveIn 373 | ); 374 | 375 | if (NT_SUCCESS(ntStatus)) { 376 | ntStatus = PcRegisterPhysicalConnection( 377 | DeviceObject, 378 | unknownWave, 379 | TopologyPhysicalConnections.ulWaveOut, 380 | unknownTopology, 381 | TopologyPhysicalConnections.ulTopologyIn 382 | ); 383 | } 384 | } 385 | 386 | // Release the adapter common object. It either has other references, 387 | // or we need to delete it anyway. 388 | if (pAdapterCommon) 389 | pAdapterCommon->Release(); 390 | 391 | if (pUnknownCommon) 392 | pUnknownCommon->Release(); 393 | 394 | if (unknownTopology) 395 | unknownTopology->Release(); 396 | 397 | if (unknownWave) 398 | unknownWave->Release(); 399 | 400 | return ntStatus; 401 | } // StartDevice 402 | #pragma code_seg() 403 | -------------------------------------------------------------------------------- /common.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | common.cpp 4 | 5 | Abstract: 6 | Implementation of the AdapterCommon class. 7 | */ 8 | 9 | #include "rtsdaudio.h" 10 | #include "common.h" 11 | #include "hw.h" 12 | 13 | //============================================================================= 14 | // Classes 15 | //============================================================================= 16 | 17 | /////////////////////////////////////////////////////////////////////////////// 18 | // CAdapterCommon 19 | // 20 | 21 | class CAdapterCommon : public IAdapterCommon, public IAdapterPowerManagement, public CUnknown { 22 | private: 23 | PPORTWAVECYCLIC m_pPortWave; // Port interface 24 | PSERVICEGROUP m_pServiceGroupWave; 25 | PDEVICE_OBJECT m_pDeviceObject; 26 | DEVICE_POWER_STATE m_PowerState; 27 | 28 | PCRTSDAudioHW m_pHW; // Virtual MSVAD HW object 29 | 30 | public: 31 | //===================================================================== 32 | // Default CUnknown 33 | DECLARE_STD_UNKNOWN(); 34 | DEFINE_STD_CONSTRUCTOR(CAdapterCommon); 35 | ~CAdapterCommon(); 36 | 37 | //===================================================================== 38 | // Default IAdapterPowerManagement 39 | IMP_IAdapterPowerManagement; 40 | 41 | //===================================================================== 42 | // IAdapterCommon methods 43 | STDMETHODIMP_(NTSTATUS) Init ( 44 | IN PDEVICE_OBJECT DeviceObject 45 | ); 46 | 47 | STDMETHODIMP_(PDEVICE_OBJECT) GetDeviceObject(void); 48 | 49 | STDMETHODIMP_(PUNKNOWN *) WavePortDriverDest(void); 50 | 51 | STDMETHODIMP_(void) SetWaveServiceGroup ( 52 | IN PSERVICEGROUP ServiceGroup 53 | ); 54 | 55 | STDMETHODIMP_(BOOL) MixerMuteRead 56 | ( 57 | IN ULONG Index 58 | ); 59 | 60 | STDMETHODIMP_(void) MixerMuteWrite 61 | ( 62 | IN ULONG Index, 63 | IN BOOL Value 64 | ); 65 | 66 | STDMETHODIMP_(ULONG) MixerMuxRead(void); 67 | 68 | STDMETHODIMP_(void) MixerMuxWrite 69 | ( 70 | IN ULONG Index 71 | ); 72 | 73 | STDMETHODIMP_(void) MixerReset(void); 74 | 75 | STDMETHODIMP_(LONG) MixerVolumeRead 76 | ( 77 | IN ULONG Index, 78 | IN LONG Channel 79 | ); 80 | 81 | STDMETHODIMP_(void) MixerVolumeWrite 82 | ( 83 | IN ULONG Index, 84 | IN LONG Channel, 85 | IN LONG Value 86 | ); 87 | 88 | //===================================================================== 89 | // friends 90 | 91 | friend NTSTATUS NewAdapterCommon 92 | ( 93 | OUT PADAPTERCOMMON * OutAdapterCommon, 94 | IN PRESOURCELIST ResourceList 95 | ); 96 | }; 97 | 98 | //----------------------------------------------------------------------------- 99 | // Functions 100 | //----------------------------------------------------------------------------- 101 | 102 | //============================================================================= 103 | #pragma code_seg("PAGE") 104 | NTSTATUS 105 | NewAdapterCommon 106 | ( 107 | OUT PUNKNOWN * Unknown, 108 | IN REFCLSID, 109 | IN PUNKNOWN UnknownOuter OPTIONAL, 110 | IN POOL_TYPE PoolType 111 | ) 112 | /*++ 113 | 114 | Routine Description: 115 | 116 | Creates a new CAdapterCommon 117 | 118 | Arguments: 119 | 120 | Unknown - 121 | 122 | UnknownOuter - 123 | 124 | PoolType 125 | 126 | Return Value: 127 | 128 | NT status code. 129 | 130 | --*/ 131 | { 132 | PAGED_CODE(); 133 | 134 | ASSERT(Unknown); 135 | 136 | STD_CREATE_BODY_ 137 | ( 138 | CAdapterCommon, 139 | Unknown, 140 | UnknownOuter, 141 | PoolType, 142 | PADAPTERCOMMON 143 | ); 144 | } // NewAdapterCommon 145 | 146 | //============================================================================= 147 | CAdapterCommon::~CAdapterCommon(void) 148 | /* 149 | Routine Description: 150 | Destructor for CAdapterCommon. 151 | 152 | Arguments: 153 | 154 | Return Value: 155 | void 156 | */ 157 | { 158 | PAGED_CODE(); 159 | 160 | DPF_ENTER(("[CAdapterCommon::~CAdapterCommon]")); 161 | 162 | if (m_pHW) 163 | delete m_pHW; 164 | 165 | if (m_pPortWave) 166 | m_pPortWave->Release(); 167 | 168 | if (m_pServiceGroupWave) 169 | m_pServiceGroupWave->Release(); 170 | } // ~CAdapterCommon 171 | 172 | //============================================================================= 173 | STDMETHODIMP_(PDEVICE_OBJECT) 174 | CAdapterCommon::GetDeviceObject 175 | ( 176 | void 177 | ) 178 | /*++ 179 | 180 | Routine Description: 181 | 182 | Returns the deviceobject 183 | 184 | Arguments: 185 | 186 | Return Value: 187 | 188 | PDEVICE_OBJECT 189 | 190 | --*/ 191 | { 192 | PAGED_CODE(); 193 | 194 | return m_pDeviceObject; 195 | } // GetDeviceObject 196 | 197 | //============================================================================= 198 | NTSTATUS 199 | CAdapterCommon::Init 200 | ( 201 | IN PDEVICE_OBJECT DeviceObject 202 | ) 203 | /*++ 204 | 205 | Routine Description: 206 | 207 | Initialize adapter common object. 208 | 209 | Arguments: 210 | 211 | DeviceObject - pointer to the device object 212 | 213 | Return Value: 214 | 215 | NT status code. 216 | 217 | --*/ 218 | { 219 | PAGED_CODE(); 220 | 221 | ASSERT(DeviceObject); 222 | 223 | NTSTATUS ntStatus = STATUS_SUCCESS; 224 | 225 | DPF_ENTER(("[CAdapterCommon::Init]")); 226 | 227 | m_pDeviceObject = DeviceObject; 228 | m_PowerState = PowerDeviceD0; 229 | 230 | // Initialize HW. 231 | // 232 | m_pHW = new (NonPagedPool, RTSDAUDIO_POOLTAG) CRTSDAudioHW; 233 | if (!m_pHW) 234 | { 235 | DPF(D_TERSE, ("Insufficient memory for MSVAD HW")); 236 | ntStatus = STATUS_INSUFFICIENT_RESOURCES; 237 | } 238 | else 239 | { 240 | m_pHW->MixerReset(); 241 | } 242 | 243 | return ntStatus; 244 | } // Init 245 | 246 | //============================================================================= 247 | STDMETHODIMP_(void) 248 | CAdapterCommon::MixerReset 249 | ( 250 | void 251 | ) 252 | /*++ 253 | 254 | Routine Description: 255 | 256 | Reset mixer registers from registry. 257 | 258 | Arguments: 259 | 260 | Return Value: 261 | 262 | void 263 | 264 | --*/ 265 | { 266 | PAGED_CODE(); 267 | 268 | if (m_pHW) 269 | { 270 | m_pHW->MixerReset(); 271 | } 272 | } // MixerReset 273 | 274 | //============================================================================= 275 | STDMETHODIMP 276 | CAdapterCommon::NonDelegatingQueryInterface 277 | ( 278 | REFIID Interface, 279 | PVOID * Object 280 | ) 281 | /*++ 282 | 283 | Routine Description: 284 | 285 | QueryInterface routine for AdapterCommon 286 | 287 | Arguments: 288 | 289 | Interface - 290 | 291 | Object - 292 | 293 | Return Value: 294 | 295 | NT status code. 296 | 297 | --*/ 298 | { 299 | PAGED_CODE(); 300 | 301 | ASSERT(Object); 302 | 303 | if (IsEqualGUIDAligned(Interface, IID_IUnknown)) 304 | { 305 | *Object = PVOID(PUNKNOWN(PADAPTERCOMMON(this))); 306 | } 307 | else if (IsEqualGUIDAligned(Interface, IID_IAdapterCommon)) 308 | { 309 | *Object = PVOID(PADAPTERCOMMON(this)); 310 | } 311 | else if (IsEqualGUIDAligned(Interface, IID_IAdapterPowerManagement)) 312 | { 313 | *Object = PVOID(PADAPTERPOWERMANAGEMENT(this)); 314 | } 315 | else 316 | { 317 | *Object = NULL; 318 | } 319 | 320 | if (*Object) 321 | { 322 | PUNKNOWN(*Object)->AddRef(); 323 | return STATUS_SUCCESS; 324 | } 325 | 326 | return STATUS_INVALID_PARAMETER; 327 | } // NonDelegatingQueryInterface 328 | 329 | //============================================================================= 330 | STDMETHODIMP_(void) 331 | CAdapterCommon::SetWaveServiceGroup 332 | ( 333 | IN PSERVICEGROUP ServiceGroup 334 | ) 335 | /*++ 336 | 337 | Routine Description: 338 | 339 | 340 | Arguments: 341 | 342 | Return Value: 343 | 344 | NT status code. 345 | 346 | --*/ 347 | { 348 | PAGED_CODE(); 349 | 350 | DPF_ENTER(("[CAdapterCommon::SetWaveServiceGroup]")); 351 | 352 | if (m_pServiceGroupWave) 353 | { 354 | m_pServiceGroupWave->Release(); 355 | } 356 | 357 | m_pServiceGroupWave = ServiceGroup; 358 | 359 | if (m_pServiceGroupWave) 360 | { 361 | m_pServiceGroupWave->AddRef(); 362 | } 363 | } // SetWaveServiceGroup 364 | 365 | //============================================================================= 366 | STDMETHODIMP_(PUNKNOWN *) 367 | CAdapterCommon::WavePortDriverDest 368 | ( 369 | void 370 | ) 371 | /*++ 372 | 373 | Routine Description: 374 | 375 | Returns the wave port. 376 | 377 | Arguments: 378 | 379 | Return Value: 380 | 381 | PUNKNOWN : pointer to waveport 382 | 383 | --*/ 384 | { 385 | PAGED_CODE(); 386 | 387 | return (PUNKNOWN *)&m_pPortWave; 388 | } // WavePortDriverDest 389 | #pragma code_seg() 390 | 391 | //============================================================================= 392 | STDMETHODIMP_(BOOL) 393 | CAdapterCommon::MixerMuteRead 394 | ( 395 | IN ULONG Index 396 | ) 397 | /*++ 398 | 399 | Routine Description: 400 | 401 | Store the new value in mixer register array. 402 | 403 | Arguments: 404 | 405 | Index - node id 406 | 407 | Return Value: 408 | 409 | BOOL - mixer mute setting for this node 410 | 411 | --*/ 412 | { 413 | if (m_pHW) 414 | { 415 | return m_pHW->GetMixerMute(Index); 416 | } 417 | 418 | return 0; 419 | } // MixerMuteRead 420 | 421 | //============================================================================= 422 | STDMETHODIMP_(void) 423 | CAdapterCommon::MixerMuteWrite 424 | ( 425 | IN ULONG Index, 426 | IN BOOL Value 427 | ) 428 | /*++ 429 | 430 | Routine Description: 431 | 432 | Store the new value in mixer register array. 433 | 434 | Arguments: 435 | 436 | Index - node id 437 | 438 | Value - new mute settings 439 | 440 | Return Value: 441 | 442 | NT status code. 443 | 444 | --*/ 445 | { 446 | if (m_pHW) 447 | { 448 | m_pHW->SetMixerMute(Index, Value); 449 | } 450 | } // MixerMuteWrite 451 | 452 | //============================================================================= 453 | STDMETHODIMP_(ULONG) 454 | CAdapterCommon::MixerMuxRead() 455 | /*++ 456 | 457 | Routine Description: 458 | 459 | Return the mux selection 460 | 461 | Arguments: 462 | 463 | Index - node id 464 | 465 | Value - new mute settings 466 | 467 | Return Value: 468 | 469 | NT status code. 470 | 471 | --*/ 472 | { 473 | if (m_pHW) 474 | { 475 | return m_pHW->GetMixerMux(); 476 | } 477 | 478 | return 0; 479 | } // MixerMuxRead 480 | 481 | //============================================================================= 482 | STDMETHODIMP_(void) 483 | CAdapterCommon::MixerMuxWrite 484 | ( 485 | IN ULONG Index 486 | ) 487 | /*++ 488 | 489 | Routine Description: 490 | 491 | Store the new mux selection 492 | 493 | Arguments: 494 | 495 | Index - node id 496 | 497 | Value - new mute settings 498 | 499 | Return Value: 500 | 501 | NT status code. 502 | 503 | --*/ 504 | { 505 | if (m_pHW) 506 | { 507 | m_pHW->SetMixerMux(Index); 508 | } 509 | } // MixerMuxWrite 510 | 511 | //============================================================================= 512 | STDMETHODIMP_(LONG) 513 | CAdapterCommon::MixerVolumeRead 514 | ( 515 | IN ULONG Index, 516 | IN LONG Channel 517 | ) 518 | /*++ 519 | 520 | Routine Description: 521 | 522 | Return the value in mixer register array. 523 | 524 | Arguments: 525 | 526 | Index - node id 527 | 528 | Channel = which channel 529 | 530 | Return Value: 531 | 532 | Byte - mixer volume settings for this line 533 | 534 | --*/ 535 | { 536 | if (m_pHW) 537 | { 538 | return m_pHW->GetMixerVolume(Index, Channel); 539 | } 540 | 541 | return 0; 542 | } // MixerVolumeRead 543 | 544 | //============================================================================= 545 | STDMETHODIMP_(void) 546 | CAdapterCommon::MixerVolumeWrite 547 | ( 548 | IN ULONG Index, 549 | IN LONG Channel, 550 | IN LONG Value 551 | ) 552 | /*++ 553 | 554 | Routine Description: 555 | 556 | Store the new value in mixer register array. 557 | 558 | Arguments: 559 | 560 | Index - node id 561 | 562 | Channel - which channel 563 | 564 | Value - new volume level 565 | 566 | Return Value: 567 | 568 | void 569 | 570 | --*/ 571 | { 572 | if (m_pHW) 573 | { 574 | m_pHW->SetMixerVolume(Index, Channel, Value); 575 | } 576 | } // MixerVolumeWrite 577 | 578 | //============================================================================= 579 | STDMETHODIMP_(void) 580 | CAdapterCommon::PowerChangeState 581 | ( 582 | IN POWER_STATE NewState 583 | ) 584 | /*++ 585 | 586 | Routine Description: 587 | 588 | 589 | Arguments: 590 | 591 | NewState - The requested, new power state for the device. 592 | 593 | Return Value: 594 | 595 | void 596 | 597 | --*/ 598 | { 599 | UINT i; 600 | 601 | DPF_ENTER(("[CAdapterCommon::PowerChangeState]")); 602 | 603 | // is this actually a state change?? 604 | // 605 | if (NewState.DeviceState != m_PowerState) 606 | { 607 | // switch on new state 608 | // 609 | switch (NewState.DeviceState) 610 | { 611 | case PowerDeviceD0: 612 | case PowerDeviceD1: 613 | case PowerDeviceD2: 614 | case PowerDeviceD3: 615 | m_PowerState = NewState.DeviceState; 616 | 617 | DPF 618 | ( 619 | D_VERBOSE, 620 | ("Entering D%d", ULONG(m_PowerState) - ULONG(PowerDeviceD0)) 621 | ); 622 | 623 | break; 624 | 625 | default: 626 | 627 | DPF(D_VERBOSE, ("Unknown Device Power State")); 628 | break; 629 | } 630 | } 631 | } // PowerStateChange 632 | 633 | //============================================================================= 634 | STDMETHODIMP_(NTSTATUS) 635 | CAdapterCommon::QueryDeviceCapabilities 636 | ( 637 | IN PDEVICE_CAPABILITIES PowerDeviceCaps 638 | ) 639 | /*++ 640 | 641 | Routine Description: 642 | 643 | Called at startup to get the caps for the device. This structure provides 644 | the system with the mappings between system power state and device power 645 | state. This typically will not need modification by the driver. 646 | 647 | Arguments: 648 | 649 | PowerDeviceCaps - The device's capabilities. 650 | 651 | Return Value: 652 | 653 | NT status code. 654 | 655 | --*/ 656 | { 657 | DPF_ENTER(("[CAdapterCommon::QueryDeviceCapabilities]")); 658 | 659 | return (STATUS_SUCCESS); 660 | } // QueryDeviceCapabilities 661 | 662 | //============================================================================= 663 | STDMETHODIMP_(NTSTATUS) 664 | CAdapterCommon::QueryPowerChangeState 665 | ( 666 | IN POWER_STATE NewStateQuery 667 | ) 668 | /*++ 669 | 670 | Routine Description: 671 | 672 | Query to see if the device can change to this power state 673 | 674 | Arguments: 675 | 676 | NewStateQuery - The requested, new power state for the device 677 | 678 | Return Value: 679 | 680 | NT status code. 681 | 682 | --*/ 683 | { 684 | DPF_ENTER(("[CAdapterCommon::QueryPowerChangeState]")); 685 | 686 | return STATUS_SUCCESS; 687 | } // QueryPowerChangeState 688 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | Common.h 4 | 5 | Abstract: 6 | CAdapterCommon class declaration. 7 | */ 8 | 9 | #ifndef __COMMON_H_ 10 | #define __COMMON_H_ 11 | 12 | //============================================================================= 13 | // Defines 14 | //============================================================================= 15 | 16 | DEFINE_GUID(IID_IAdapterCommon, 0x7eda2950, 0xbf9f, 0x11d0, 0x87, 0x1f, 0x0, 0xa0, 0xc9, 0x11, 0xb5, 0x44); 17 | 18 | //============================================================================= 19 | // Interfaces 20 | //============================================================================= 21 | 22 | /////////////////////////////////////////////////////////////////////////////// 23 | // IAdapterCommon 24 | DECLARE_INTERFACE_(IAdapterCommon, IUnknown) { 25 | STDMETHOD_(NTSTATUS, Init) ( THIS_ IN PDEVICE_OBJECT DeviceObject ) PURE; 26 | STDMETHOD_(PDEVICE_OBJECT, GetDeviceObject) ( THIS ) PURE; 27 | STDMETHOD_(VOID, SetWaveServiceGroup) ( THIS_ IN PSERVICEGROUP ServiceGroup ) PURE; 28 | STDMETHOD_(PUNKNOWN *, WavePortDriverDest) ( THIS ) PURE; 29 | STDMETHOD_(BOOL, MixerMuteRead) ( THIS_ IN ULONG Index ) PURE; 30 | STDMETHOD_(VOID, MixerMuteWrite) ( THIS_ IN ULONG Index, IN BOOL Value ); 31 | STDMETHOD_(ULONG, MixerMuxRead) ( THIS ); 32 | STDMETHOD_(VOID, MixerMuxWrite) ( THIS_ IN ULONG Index ); 33 | STDMETHOD_(LONG, MixerVolumeRead) ( THIS_ IN ULONG Index, IN LONG Channel ) PURE; 34 | STDMETHOD_(VOID, MixerVolumeWrite) ( THIS_ IN ULONG Index, IN LONG Channel, IN LONG Value ) PURE; 35 | STDMETHOD_(VOID, MixerReset) ( THIS ) PURE; 36 | }; 37 | typedef IAdapterCommon *PADAPTERCOMMON; 38 | 39 | //============================================================================= 40 | // Function Prototypes 41 | //============================================================================= 42 | NTSTATUS NewAdapterCommon( 43 | OUT PUNKNOWN * Unknown, 44 | IN REFCLSID, 45 | IN PUNKNOWN UnknownOuter OPTIONAL, 46 | IN POOL_TYPE PoolType 47 | ); 48 | 49 | #endif //_COMMON_H_ 50 | 51 | -------------------------------------------------------------------------------- /hw.cpp: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) 1997-2000 Microsoft Corporation All Rights Reserved 4 | 5 | Module Name: 6 | 7 | hw.cpp 8 | 9 | Abstract: 10 | 11 | Implementation of MSVAD HW class. 12 | MSVAD HW has an array for storing mixer and volume settings 13 | for the topology. 14 | 15 | 16 | --*/ 17 | #include "rtsdaudio.h" 18 | #include "hw.h" 19 | 20 | //============================================================================= 21 | // CRTSDAudioHW 22 | //============================================================================= 23 | 24 | //============================================================================= 25 | #pragma code_seg("PAGE") 26 | CRTSDAudioHW::CRTSDAudioHW() 27 | : m_ulMux(0) 28 | /*++ 29 | 30 | Routine Description: 31 | 32 | Constructor for MSVADHW. 33 | 34 | Arguments: 35 | 36 | Return Value: 37 | 38 | void 39 | 40 | --*/ 41 | { 42 | PAGED_CODE(); 43 | 44 | MixerReset(); 45 | } // CRTSDAudioHW 46 | #pragma code_seg() 47 | 48 | //============================================================================= 49 | BOOL 50 | CRTSDAudioHW::GetMixerMute 51 | ( 52 | IN ULONG ulNode 53 | ) 54 | /*++ 55 | 56 | Routine Description: 57 | 58 | Gets the HW (!) mute levels for MSVAD 59 | 60 | Arguments: 61 | 62 | ulNode - topology node id 63 | 64 | Return Value: 65 | 66 | mute setting 67 | 68 | --*/ 69 | { 70 | if (ulNode < MAX_TOPOLOGY_NODES) 71 | { 72 | return m_MuteControls[ulNode]; 73 | } 74 | 75 | return 0; 76 | } // GetMixerMute 77 | 78 | //============================================================================= 79 | ULONG 80 | CRTSDAudioHW::GetMixerMux() 81 | /*++ 82 | 83 | Routine Description: 84 | 85 | Return the current mux selection 86 | 87 | Arguments: 88 | 89 | Return Value: 90 | 91 | ULONG 92 | 93 | --*/ 94 | { 95 | return m_ulMux; 96 | } // GetMixerMux 97 | 98 | //============================================================================= 99 | LONG 100 | CRTSDAudioHW::GetMixerVolume 101 | ( 102 | IN ULONG ulNode, 103 | IN LONG lChannel 104 | ) 105 | /*++ 106 | 107 | Routine Description: 108 | 109 | Gets the HW (!) volume for MSVAD. 110 | 111 | Arguments: 112 | 113 | ulNode - topology node id 114 | 115 | lChannel - which channel are we setting? 116 | 117 | Return Value: 118 | 119 | LONG - volume level 120 | 121 | --*/ 122 | { 123 | if (ulNode < MAX_TOPOLOGY_NODES) 124 | { 125 | return m_VolumeControls[ulNode]; 126 | } 127 | 128 | return 0; 129 | } // GetMixerVolume 130 | 131 | //============================================================================= 132 | #pragma code_seg("PAGE") 133 | void 134 | CRTSDAudioHW::MixerReset() 135 | /*++ 136 | 137 | Routine Description: 138 | 139 | Resets the mixer registers. 140 | 141 | Arguments: 142 | 143 | Return Value: 144 | 145 | void 146 | 147 | --*/ 148 | { 149 | PAGED_CODE(); 150 | 151 | RtlFillMemory(m_VolumeControls, sizeof(LONG) * MAX_TOPOLOGY_NODES, 0xFF); 152 | RtlFillMemory(m_MuteControls, sizeof(BOOL) * MAX_TOPOLOGY_NODES, TRUE); 153 | 154 | // BUGBUG change this depending on the topology 155 | m_ulMux = 2; 156 | } // MixerReset 157 | #pragma code_seg() 158 | 159 | //============================================================================= 160 | void 161 | CRTSDAudioHW::SetMixerMute 162 | ( 163 | IN ULONG ulNode, 164 | IN BOOL fMute 165 | ) 166 | /*++ 167 | 168 | Routine Description: 169 | 170 | Sets the HW (!) mute levels for MSVAD 171 | 172 | Arguments: 173 | 174 | ulNode - topology node id 175 | 176 | fMute - mute flag 177 | 178 | Return Value: 179 | 180 | void 181 | 182 | --*/ 183 | { 184 | if (ulNode < MAX_TOPOLOGY_NODES) 185 | { 186 | m_MuteControls[ulNode] = fMute; 187 | } 188 | } // SetMixerMute 189 | 190 | //============================================================================= 191 | void 192 | CRTSDAudioHW::SetMixerMux 193 | ( 194 | IN ULONG ulNode 195 | ) 196 | /*++ 197 | 198 | Routine Description: 199 | 200 | Sets the HW (!) mux selection 201 | 202 | Arguments: 203 | 204 | ulNode - topology node id 205 | 206 | Return Value: 207 | 208 | void 209 | 210 | --*/ 211 | { 212 | m_ulMux = ulNode; 213 | } // SetMixMux 214 | 215 | //============================================================================= 216 | void 217 | CRTSDAudioHW::SetMixerVolume 218 | ( 219 | IN ULONG ulNode, 220 | IN LONG lChannel, 221 | IN LONG lVolume 222 | ) 223 | /*++ 224 | 225 | Routine Description: 226 | 227 | Sets the HW (!) volume for MSVAD. 228 | 229 | Arguments: 230 | 231 | ulNode - topology node id 232 | 233 | lChannel - which channel are we setting? 234 | 235 | lVolume - volume level 236 | 237 | Return Value: 238 | 239 | void 240 | 241 | --*/ 242 | { 243 | if (ulNode < MAX_TOPOLOGY_NODES) 244 | { 245 | m_VolumeControls[ulNode] = lVolume; 246 | } 247 | } // SetMixerVolume 248 | -------------------------------------------------------------------------------- /hw.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | hw.h 4 | 5 | Abstract: 6 | Declaration of MSVAD HW class. 7 | MSVAD HW has an array for storing mixer and volume settings 8 | for the topology. 9 | */ 10 | 11 | #ifndef __HW_H_ 12 | #define __HW_H_ 13 | 14 | //============================================================================= 15 | // Defines 16 | //============================================================================= 17 | // BUGBUG we should dynamically allocate this... 18 | #define MAX_TOPOLOGY_NODES 20 19 | 20 | //============================================================================= 21 | // Classes 22 | //============================================================================= 23 | /////////////////////////////////////////////////////////////////////////////// 24 | // CRTSDAudioHW 25 | // This class represents virtual MSVAD HW. An array representing volume 26 | // registers and mute registers. 27 | 28 | class CRTSDAudioHW { 29 | protected: 30 | BOOL m_MuteControls[MAX_TOPOLOGY_NODES]; 31 | LONG m_VolumeControls[MAX_TOPOLOGY_NODES]; 32 | ULONG m_ulMux; // Mux selection 33 | 34 | public: 35 | CRTSDAudioHW(); 36 | void MixerReset(); 37 | 38 | BOOL GetMixerMute(IN ULONG ulNode); 39 | void SetMixerMute(IN ULONG ulNode, IN BOOL fMute); 40 | 41 | ULONG GetMixerMux(); 42 | void SetMixerMux(IN ULONG ulNode); 43 | 44 | LONG GetMixerVolume(IN ULONG ulNode, IN LONG lChannel); 45 | void SetMixerVolume(IN ULONG ulNode, IN LONG lChannel, IN LONG lVolume); 46 | }; 47 | typedef CRTSDAudioHW *PCRTSDAudioHW; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /kshelper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | kshelper.cpp 4 | 5 | Abstract: 6 | Helper functions for msvad 7 | */ 8 | 9 | #include "kshelper.h" 10 | 11 | //----------------------------------------------------------------------------- 12 | PWAVEFORMATEX 13 | GetWaveFormatEx 14 | ( 15 | IN PKSDATAFORMAT pDataFormat 16 | ) 17 | /* 18 | Routine Description: 19 | Returns the waveformatex for known formats. 20 | 21 | Arguments: 22 | pDataFormat - data format. 23 | 24 | Return Value: 25 | 26 | waveformatex in DataFormat. 27 | NULL for unknown data formats. 28 | 29 | --*/ 30 | { 31 | PWAVEFORMATEX pWfx = NULL; 32 | 33 | // If this is a known dataformat extract the waveformat info. 34 | // 35 | if 36 | ( 37 | pDataFormat && 38 | ( IsEqualGUIDAligned(pDataFormat->MajorFormat, 39 | KSDATAFORMAT_TYPE_AUDIO) && 40 | ( IsEqualGUIDAligned(pDataFormat->Specifier, 41 | KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) || 42 | IsEqualGUIDAligned(pDataFormat->Specifier, 43 | KSDATAFORMAT_SPECIFIER_DSOUND) ) ) 44 | ) 45 | { 46 | pWfx = PWAVEFORMATEX(pDataFormat + 1); 47 | 48 | if (IsEqualGUIDAligned(pDataFormat->Specifier, 49 | KSDATAFORMAT_SPECIFIER_DSOUND)) 50 | { 51 | PKSDSOUND_BUFFERDESC pwfxds; 52 | 53 | pwfxds = PKSDSOUND_BUFFERDESC(pDataFormat + 1); 54 | pWfx = &pwfxds->WaveFormatEx; 55 | } 56 | } 57 | 58 | return pWfx; 59 | } // GetWaveFormatEx 60 | 61 | //----------------------------------------------------------------------------- 62 | NTSTATUS 63 | PropertyHandler_BasicSupport 64 | ( 65 | IN PPCPROPERTY_REQUEST PropertyRequest, 66 | IN ULONG Flags, 67 | IN DWORD PropTypeSetId 68 | ) 69 | /*++ 70 | 71 | Routine Description: 72 | 73 | Default basic support handler. Basic processing depends on the size of data. 74 | For ULONG it only returns Flags. For KSPROPERTY_DESCRIPTION, the structure 75 | is filled. 76 | 77 | Arguments: 78 | 79 | PropertyRequest - 80 | 81 | Flags - Support flags. 82 | 83 | PropTypeSetId - PropTypeSetId 84 | 85 | Return Value: 86 | 87 | NT status code. 88 | 89 | --*/ 90 | { 91 | PAGED_CODE(); 92 | 93 | ASSERT(Flags & KSPROPERTY_TYPE_BASICSUPPORT); 94 | 95 | NTSTATUS ntStatus = STATUS_INVALID_PARAMETER; 96 | 97 | if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)) && 98 | VT_ILLEGAL != PropTypeSetId) 99 | { 100 | // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it 101 | // 102 | PKSPROPERTY_DESCRIPTION PropDesc = 103 | PKSPROPERTY_DESCRIPTION(PropertyRequest->Value); 104 | 105 | PropDesc->AccessFlags = Flags; 106 | PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION); 107 | PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General; 108 | PropDesc->PropTypeSet.Id = PropTypeSetId; 109 | PropDesc->PropTypeSet.Flags = 0; 110 | PropDesc->MembersListCount = 0; 111 | PropDesc->Reserved = 0; 112 | 113 | PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION); 114 | ntStatus = STATUS_SUCCESS; 115 | } 116 | else if (PropertyRequest->ValueSize >= sizeof(ULONG)) 117 | { 118 | // if return buffer can hold a ULONG, return the access flags 119 | // 120 | *(PULONG(PropertyRequest->Value)) = Flags; 121 | 122 | PropertyRequest->ValueSize = sizeof(ULONG); 123 | ntStatus = STATUS_SUCCESS; 124 | } 125 | else if (0 == PropertyRequest->ValueSize) 126 | { 127 | // Send the caller required value size. 128 | PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION); 129 | ntStatus = STATUS_BUFFER_OVERFLOW; 130 | } 131 | else 132 | { 133 | PropertyRequest->ValueSize = 0; 134 | ntStatus = STATUS_BUFFER_TOO_SMALL; 135 | } 136 | 137 | return ntStatus; 138 | } // PropertyHandler_BasicSupport 139 | 140 | //----------------------------------------------------------------------------- 141 | NTSTATUS 142 | ValidatePropertyParams 143 | ( 144 | IN PPCPROPERTY_REQUEST PropertyRequest, 145 | IN ULONG cbSize, 146 | IN ULONG cbInstanceSize /* = 0 */ 147 | ) 148 | /*++ 149 | 150 | Routine Description: 151 | 152 | Validates property parameters. 153 | 154 | Arguments: 155 | 156 | PropertyRequest - 157 | cbSize - 158 | cbInstanceSize - 159 | 160 | Return Value: 161 | 162 | NT status code. 163 | 164 | --*/ 165 | { 166 | NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; 167 | 168 | if (PropertyRequest && cbSize) 169 | { 170 | // If the caller is asking for ValueSize. 171 | // 172 | if (0 == PropertyRequest->ValueSize) 173 | { 174 | PropertyRequest->ValueSize = cbSize; 175 | ntStatus = STATUS_BUFFER_OVERFLOW; 176 | } 177 | // If the caller passed an invalid ValueSize. 178 | // 179 | else if (PropertyRequest->ValueSize < cbSize) 180 | { 181 | ntStatus = STATUS_BUFFER_TOO_SMALL; 182 | } 183 | else if (PropertyRequest->InstanceSize < cbInstanceSize) 184 | { 185 | ntStatus = STATUS_BUFFER_TOO_SMALL; 186 | } 187 | // If all parameters are OK. 188 | // 189 | else if (PropertyRequest->ValueSize == cbSize) 190 | { 191 | if (PropertyRequest->Value) 192 | { 193 | ntStatus = STATUS_SUCCESS; 194 | // 195 | // Caller should set ValueSize, if the property 196 | // call is successful. 197 | // 198 | } 199 | } 200 | } 201 | else 202 | { 203 | ntStatus = STATUS_INVALID_PARAMETER; 204 | } 205 | 206 | // Clear the ValueSize if unsuccessful. 207 | // 208 | if (PropertyRequest && 209 | STATUS_SUCCESS != ntStatus && 210 | STATUS_BUFFER_OVERFLOW != ntStatus) 211 | { 212 | PropertyRequest->ValueSize = 0; 213 | } 214 | 215 | return ntStatus; 216 | } // ValidatePropertyParams 217 | 218 | 219 | -------------------------------------------------------------------------------- /kshelper.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | kshelper.h 4 | 5 | Abstract: 6 | Helper functions for msvad 7 | */ 8 | #ifndef __KSHELPER_H_ 9 | #define __KSHELPER_H_ 10 | 11 | #include 12 | #include 13 | 14 | PWAVEFORMATEX GetWaveFormatEx(IN PKSDATAFORMAT pDataFormat); 15 | 16 | NTSTATUS PropertyHandler_BasicSupport(IN PPCPROPERTY_REQUEST PropertyRequest, IN ULONG Flags, IN DWORD PropTypeSetId); 17 | 18 | NTSTATUS ValidatePropertyParams(IN PPCPROPERTY_REQUEST PropertyRequest, IN ULONG cbValueSize, IN ULONG cbInstanceSize = 0); 19 | #endif 20 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Copyright (c) 1998-2000 Microsoft Corporation 4 | # All Rights Reserved. 5 | # 6 | # Makefile for wdm\audio\sb16 7 | # 8 | ############################################################################# 9 | 10 | # 11 | # DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source 12 | # file to this component. This file merely indirects to the real make file 13 | # that is shared by all the components of NT. 14 | # 15 | !IF DEFINED(_NT_TARGET_VERSION) 16 | ! IF $(_NT_TARGET_VERSION)>=0x501 17 | ! INCLUDE $(NTMAKEENV)\makefile.def 18 | ! ELSE 19 | # Only warn once per directory 20 | ! INCLUDE $(NTMAKEENV)\makefile.plt 21 | ! IF "$(BUILD_PASS)"=="PASS1" 22 | ! message BUILDMSG: Warning : The sample "$(MAKEDIR)" is not valid for the current OS target. 23 | ! ENDIF 24 | ! ENDIF 25 | !ELSE 26 | ! INCLUDE $(NTMAKEENV)\makefile.def 27 | !ENDIF 28 | -------------------------------------------------------------------------------- /rtsdaudio.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | rtsdaudio.h 4 | 5 | Abstract: 6 | Header file for common stuff. 7 | */ 8 | 9 | #ifndef __RTSDAUDIO_H_ 10 | #define __RTSDAUDIO_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include "kshelper.h" 16 | 17 | //============================================================================= 18 | // Defines 19 | //============================================================================= 20 | 21 | // Version number. Revision numbers are specified for each sample. 22 | #define RTSDAUDIO_VERSION 1 23 | #define RTSDAUDIO_REVISION 0 24 | 25 | // Product Id 26 | // {5B722BF8-F0AB-47ee-B9C8-8D61D31375A1} 27 | #define STATIC_PID_RTSDAUDIO 0x5b722bf8, 0xf0ab, 0x47ee, 0xb9, 0xc8, 0x8d, 0x61, 0xd3, 0x13, 0x75, 0xa1 28 | DEFINE_GUIDSTRUCT("5B722BF8-F0AB-47ee-B9C8-8D61D31375A1", PID_RTSDAUDIO); 29 | #define PID_RTSDAUDIO DEFINE_GUIDNAMED(PID_RTSDAUDIO) 30 | 31 | // Name Guid 32 | // {946A7B1A-EBBC-422a-A81F-F07C8D40D3B4} 33 | #define STATIC_NAME_RTSDAUDIO 0x946a7b1a, 0xebbc, 0x422a, 0xa8, 0x1f, 0xf0, 0x7c, 0x8d, 0x40, 0xd3, 0xb4 34 | DEFINE_GUIDSTRUCT("946A7B1A-EBBC-422a-A81F-F07C8D40D3B4", NAME_RTSDAUDIO); 35 | #define NAME_RTSDAUDIO DEFINE_GUIDNAMED(NAME_RTSDAUDIO) 36 | 37 | // Pool tag used for MSVAD allocations 38 | #define RTSDAUDIO_POOLTAG 'RTSD' 39 | 40 | // Debug module name 41 | #define STR_MODULENAME "RTSDAudio: " 42 | 43 | // Debug utility macros 44 | #define D_FUNC 4 45 | #define D_BLAB DEBUGLVL_BLAB 46 | #define D_VERBOSE DEBUGLVL_VERBOSE 47 | #define D_TERSE DEBUGLVL_TERSE 48 | #define D_ERROR DEBUGLVL_ERROR 49 | #define DPF _DbgPrintF 50 | #define DPF_ENTER(x) DPF(D_BLAB, x) 51 | 52 | // Channel orientation 53 | #define CHAN_LEFT 0 54 | #define CHAN_RIGHT 1 55 | #define CHAN_MASTER (-1) 56 | 57 | // Pin properties. 58 | #define MAX_OUTPUT_STREAMS 1 // Number of capture streams. 59 | #define MAX_INPUT_STREAMS 1 // Number of render streams. 60 | #define MAX_TOTAL_STREAMS MAX_OUTPUT_STREAMS + MAX_INPUT_STREAMS 61 | 62 | // PCM Info 63 | #define MIN_CHANNELS 2 // Min Channels. 64 | #define MAX_CHANNELS_PCM 2 // Max Channels. 65 | #define MIN_BITS_PER_SAMPLE_PCM 16 // Min Bits Per Sample 66 | #define MAX_BITS_PER_SAMPLE_PCM 16 // Max Bits Per Sample 67 | #define MIN_SAMPLE_RATE 44100 // Min Sample Rate 68 | #define MAX_SAMPLE_RATE 44100 // Max Sample Rate 69 | 70 | // Dma Settings. 71 | #define DMA_BUFFER_SIZE 0x16000 72 | 73 | #define KSPROPERTY_TYPE_ALL KSPROPERTY_TYPE_BASICSUPPORT | \ 74 | KSPROPERTY_TYPE_GET | \ 75 | KSPROPERTY_TYPE_SET 76 | 77 | //============================================================================= 78 | // Enumerations 79 | //============================================================================= 80 | 81 | // Wave pins 82 | enum 83 | { 84 | KSPIN_WAVE_CAPTURE_SINK = 0, 85 | KSPIN_WAVE_CAPTURE_SOURCE, 86 | KSPIN_WAVE_RENDER_SINK, 87 | KSPIN_WAVE_RENDER_SOURCE 88 | }; 89 | 90 | // Wave Topology nodes. 91 | enum 92 | { 93 | KSNODE_WAVE_ADC = 0, 94 | KSNODE_WAVE_DAC 95 | }; 96 | 97 | // topology pins. 98 | enum 99 | { 100 | KSPIN_TOPO_WAVEOUT_SOURCE = 0, 101 | KSPIN_TOPO_SYNTHOUT_SOURCE, 102 | KSPIN_TOPO_SYNTHIN_SOURCE, 103 | KSPIN_TOPO_MIC_SOURCE, 104 | KSPIN_TOPO_LINEOUT_DEST, 105 | KSPIN_TOPO_WAVEIN_DEST 106 | }; 107 | 108 | // topology nodes. 109 | enum 110 | { 111 | KSNODE_TOPO_WAVEOUT_VOLUME = 0, 112 | KSNODE_TOPO_WAVEOUT_MUTE, 113 | KSNODE_TOPO_SYNTHOUT_VOLUME, 114 | KSNODE_TOPO_SYNTHOUT_MUTE, 115 | KSNODE_TOPO_MIC_VOLUME, 116 | KSNODE_TOPO_SYNTHIN_VOLUME, 117 | KSNODE_TOPO_LINEOUT_MIX, 118 | KSNODE_TOPO_LINEOUT_VOLUME, 119 | KSNODE_TOPO_WAVEIN_MUX 120 | }; 121 | 122 | //============================================================================= 123 | // Typedefs 124 | //============================================================================= 125 | 126 | // Connection table for registering topology/wave bridge connection 127 | typedef struct _PHYSICALCONNECTIONTABLE { 128 | ULONG ulTopologyIn; 129 | ULONG ulTopologyOut; 130 | ULONG ulWaveIn; 131 | ULONG ulWaveOut; 132 | } PHYSICALCONNECTIONTABLE, *PPHYSICALCONNECTIONTABLE; 133 | 134 | //============================================================================= 135 | // Externs 136 | //============================================================================= 137 | 138 | // Physical connection table. Defined in mintopo.cpp for each sample 139 | extern PHYSICALCONNECTIONTABLE TopologyPhysicalConnections; 140 | 141 | // Generic topology handler 142 | extern NTSTATUS PropertyHandler_Topology(IN PPCPROPERTY_REQUEST PropertyRequest); 143 | 144 | // Generic wave port handler 145 | extern NTSTATUS PropertyHandler_Wave(IN PPCPROPERTY_REQUEST PropertyRequest); 146 | 147 | // Default WaveFilter automation table. 148 | // Handles the GeneralComponentId request. 149 | extern NTSTATUS PropertyHandler_WaveFilter(IN PPCPROPERTY_REQUEST PropertyRequest); 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /rtsdaudio.inf: -------------------------------------------------------------------------------- 1 | [Version] 2 | Signature="$CHICAGO$" 3 | Class=MEDIA 4 | ClassGUID={4d36e96c-e325-11ce-bfc1-08002be10318} 5 | Provider=%GroupName% 6 | DriverVer = 09/08/2005, 1.0.0.0 7 | 8 | [SourceDisksNames] 9 | 222="RTSD-Audio Driver Disk","",222 10 | 11 | [SourceDisksFiles] 12 | rtsdaudio.sys=222 13 | 14 | ;;This syntax is only recognized on Windows XP and above- it is needed to install 64-bit drivers on 15 | ;;Windows Server 2003 Service Pack 1 and above. 16 | [Manufacturer] 17 | %RTSDMfg%=RTSDProject,NTAMD64,NTIA64 18 | 19 | ;; For Windows Server 2003 Service Pack 1 and above, a 64-bit OS will not install a driver 20 | ;; unless the Manufacturer and Models Sections explicitly show it is a driver for that platform 21 | ;; But the individual model section decorations (or lack thereof) work as they always have. 22 | ;; All of the model sections referred to are undecorated or NT-decorated, hence work on all platforms 23 | [RTSDProject] 24 | %RTSDAudio.DeviceDesc%=RTSDAudio,,*RTSDAudio 25 | 26 | ;; This section enables installing on x64 systems 27 | [RTSDProject.NTAMD64] 28 | %RTSDAudio.DeviceDesc%=RTSDAudio,,*RTSDAudio 29 | 30 | ;; This section enables installing on Itanium systems 31 | [RTSDProject.NTIA64] 32 | %RTSDAudio.DeviceDesc%=RTSDAudio,,*RTSDAudio 33 | 34 | [DestinationDirs] 35 | RTSDAudio.CopyList=12 36 | 37 | ;================================================== 38 | ; DDInstall 39 | ;================================================== 40 | [RTSDAudio] 41 | AlsoInstall=ks.registration(ks.inf),wdmaudio.registration(wdmaudio.inf) 42 | CopyFiles=RTSDAudio.CopyList 43 | AddReg=RTSDAudio.AddReg 44 | 45 | [RTSDAudio.CopyList] 46 | rtsdaudio.sys 47 | 48 | [RTSDAudio.Interfaces] 49 | AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Wave%,RTSDAudio.Wave 50 | AddInterface=%KSCATEGORY_RENDER%,%KSNAME_Wave%,RTSDAudio.Wave 51 | AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Topology%,RTSDAudio.Topo 52 | 53 | [RTSDAudio.AddReg] 54 | HKR,,AssociatedFilters,,"wdmaud,swmidi,redbook" 55 | HKR,,Driver,,rtsdaudio.sys 56 | HKR,,NTMPDriver,,"rtsdaudio.sys,sbemul.sys" 57 | 58 | HKR,Drivers,SubClasses,,"wave,midi,mixer" 59 | 60 | HKR,Drivers\wave\wdmaud.drv,Driver,,wdmaud.drv 61 | HKR,Drivers\midi\wdmaud.drv,Driver,,wdmaud.drv 62 | HKR,Drivers\mixer\wdmaud.drv,Driver,,wdmaud.drv 63 | 64 | HKR,Drivers\wave\wdmaud.drv,Description,,%RTSDAudio.DeviceDesc% 65 | HKR,Drivers\midi\wdmaud.drv,Description,,%RTSDAudio.MIDI% 66 | HKR,Drivers\mixer\wdmaud.drv,Description,,%RTSDAudio.DeviceDesc% 67 | 68 | HKLM,%MediaCategories%\%RTSDAudio.NameGuid%,Name,,%RTSDAudio.Name% 69 | 70 | ;================================================= 71 | ; DDInstall.NT 72 | ;================================================= 73 | [RTSDAudio.NT] 74 | Include=ks.inf,wdmaudio.inf 75 | Needs=KS.Registration, WDMAUDIO.Registration 76 | CopyFiles=RTSDAudio.CopyList 77 | AddReg=RTSDAudio.AddReg 78 | 79 | [RTSDAudio.NT.Interfaces] 80 | AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Wave%,RTSDAudio.Wave 81 | AddInterface=%KSCATEGORY_RENDER%,%KSNAME_Wave%,RTSDAudio.Wave 82 | AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Topology%,RTSDAudio.Topo 83 | 84 | [RTSDAudio.NT.Services] 85 | AddService=RTSDAudio,0x00000002,RTSDAudio_Service_Inst 86 | 87 | ;====================================================== 88 | ; Interface install 89 | ;====================================================== 90 | [RTSDAudio.Wave] 91 | AddReg=RTSDAudio.Wave.AddReg 92 | [RTSDAudio.Wave.AddReg] 93 | HKR,,CLSID,,%Proxy.CLSID% 94 | HKR,,FriendlyName,,%RTSDAudio.Wave.szPname% 95 | 96 | [RTSDAudio.Topo] 97 | AddReg=MSVAD.I.Topo.AddReg 98 | [RTSDAudio.Topo.AddReg] 99 | HKR,,CLSID,,%Proxy.CLSID% 100 | HKR,,FriendlyName,,%RTSDAudio.Topo.szPname% 101 | 102 | ;====================================================== 103 | ; Service install 104 | ;====================================================== 105 | [RTSDAudio_Service_Inst] 106 | DisplayName=%RTSDAudio.SvcDesc% 107 | ServiceType=1 108 | StartType=3 109 | ErrorControl=1 110 | ServiceBinary=%10%\system32\drivers\rtsdaudio.sys 111 | 112 | ;====================================================== 113 | ; Strings 114 | ;====================================================== 115 | [Strings] 116 | GroupName="RTSD Project" 117 | RTSDMfg="RTSD Project" 118 | RTSDAudio.Name="RTSD-Audio" 119 | RTSDAudio.NameGuid="{946A7B1A-EBBC-422a-A81F-F07C8D40D3B4}" 120 | RTSDAudio.DeviceDesc="RTSD Network Audio Device (WDM)" 121 | RTSDAudio.SvcDesc="RTSD Network Audio Device (WDM)" 122 | 123 | RTSDAudio.Wave.szPname="RTSDAudio Wave" 124 | RTSDAudio.Topo.szPname="RTSDAudio Topology" 125 | RTSDAudio.MIDI="RTSDAudio -> WDM Midi Device" 126 | 127 | Proxy.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}" 128 | KSCATEGORY_AUDIO="{6994AD04-93EF-11D0-A3CC-00A0C9223196}" 129 | KSCATEGORY_RENDER="{65E8773E-8F56-11D0-A3B9-00A0C9223196}" 130 | KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}" 131 | KSNAME_Wave="Wave" 132 | KSNAME_Topology="Topology" 133 | 134 | MediaCategories="SYSTEM\CurrentControlSet\Control\MediaCategories" 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /rtsdaudio.rc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 1997-2000 Microsoft Corporation All Rights Reserved 3 | 4 | Module Name: 5 | rtsdaudio.rc 6 | 7 | Abstract: 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #define VER_FILETYPE VFT_DRV 14 | #define VER_FILESUBTYPE VFT2_DRV_SOUND 15 | #define OFFICIAL_BUILD 16 | #define VER_FILEDESCRIPTION_STR "RTSD - Network Audio Device" 17 | #define VER_COMPANYNAME_STR "RTSD Project" 18 | #define VER_PRODUCTNAME_STR "Real Time Streaming Device" 19 | 20 | #define VER_INTERNALNAME_STR "rtsdaudio.sys" 21 | #define VER_ORIGINALFILENAME_STR "rtsdaudio.sys" 22 | 23 | #define VER_PRODUCTVERSION 1,20,00,000 24 | #define VER_PRODUCTVERSION_STR "1.20" 25 | 26 | #define VER_LEGALCOPYRIGHT_YEARS "2002-2006" 27 | #define VER_LEGALCOPYRIGHT_STR "Copyright (C) RTSD Project " VER_LEGALCOPYRIGHT_YEARS 28 | 29 | #include "common.ver" 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /rtsdtopo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | rtsdtopo.cpp 4 | 5 | Abstract: 6 | Implementation of topology miniport. 7 | */ 8 | 9 | #include "rtsdaudio.h" 10 | #include "common.h" 11 | #include "rtsdwave.h" 12 | #include "rtsdtopo.h" 13 | #include "toptable.h" 14 | 15 | 16 | /********************************************************************* 17 | * Topology/Wave bridge connection * 18 | * * 19 | * +------+ +------+ * 20 | * | Wave | | Topo | * 21 | * | | | | * 22 | * Capture <---|0 1|<===|4 1|<--- Synth * 23 | * | | | | * 24 | * Render --->|2 3|===>|0 | * 25 | * +------+ | | * 26 | * | 2|<--- Mic * 27 | * | | * 28 | * | 3|---> Line Out * 29 | * +------+ * 30 | *********************************************************************/ 31 | PHYSICALCONNECTIONTABLE TopologyPhysicalConnections = 32 | { 33 | KSPIN_TOPO_WAVEOUT_SOURCE, // TopologyIn 34 | KSPIN_TOPO_WAVEIN_DEST, // TopologyOut 35 | KSPIN_WAVE_CAPTURE_SOURCE, // WaveIn 36 | KSPIN_WAVE_RENDER_SOURCE // WaveOut 37 | }; 38 | 39 | #pragma code_seg("PAGE") 40 | 41 | //============================================================================= 42 | NTSTATUS CreateMiniportTopology( 43 | OUT PUNKNOWN * Unknown, 44 | IN REFCLSID, 45 | IN PUNKNOWN UnknownOuter OPTIONAL, 46 | IN POOL_TYPE PoolType 47 | ) 48 | /* 49 | Routine Description: 50 | Creates a new topology miniport. 51 | 52 | Arguments: 53 | Unknown - 54 | RefclsId - 55 | UnknownOuter - 56 | PoolType - 57 | 58 | Return Value: 59 | NT status code. 60 | */ 61 | { 62 | PAGED_CODE(); 63 | ASSERT(Unknown); 64 | STD_CREATE_BODY(CMiniportTopology, Unknown, UnknownOuter, PoolType); 65 | } 66 | 67 | //============================================================================= 68 | NTSTATUS PropertyHandler_Topology ( 69 | IN PPCPROPERTY_REQUEST PropertyRequest 70 | ) 71 | /* 72 | Routine Description: 73 | Redirects property request to miniport object 74 | 75 | Arguments: 76 | PropertyRequest - 77 | 78 | Return Value: 79 | NT status code. 80 | */ 81 | { 82 | PAGED_CODE(); 83 | ASSERT(PropertyRequest); 84 | DPF_ENTER(("[PropertyHandler_Topology]")); 85 | 86 | // PropertryRequest structure is filled by portcls. 87 | // MajorTarget is a pointer to miniport object for miniports. 88 | return ((PCMiniportTopology)(PropertyRequest->MajorTarget))->PropertyHandlerGeneric(PropertyRequest); 89 | } 90 | 91 | //============================================================================= 92 | CMiniportTopology::~CMiniportTopology(void) 93 | /* 94 | Routine Description: 95 | Topology miniport destructor 96 | 97 | Arguments: 98 | 99 | Return Value: 100 | NT status code. 101 | */ 102 | { 103 | PAGED_CODE(); 104 | DPF_ENTER(("[CMiniportTopology::~CMiniportTopology]")); 105 | if (m_AdapterCommon) { 106 | m_AdapterCommon->Release(); 107 | } 108 | } 109 | 110 | //============================================================================= 111 | NTSTATUS CMiniportTopology::DataRangeIntersection( 112 | IN ULONG PinId, 113 | IN PKSDATARANGE ClientDataRange, 114 | IN PKSDATARANGE MyDataRange, 115 | IN ULONG OutputBufferLength, 116 | OUT PVOID ResultantFormat OPTIONAL, 117 | OUT PULONG ResultantFormatLength 118 | ) 119 | /* 120 | Routine Description: 121 | The DataRangeIntersection function determines the highest quality 122 | intersection of two data ranges. 123 | 124 | Arguments: 125 | PinId - Pin for which data intersection is being determined. 126 | ClientDataRange - Pointer to KSDATARANGE structure which contains the data range 127 | submitted by client in the data range intersection property 128 | request. 129 | MyDataRange - Pin's data range to be compared with client's data range. 130 | OutputBufferLength - Size of the buffer pointed to by the resultant format 131 | parameter. 132 | ResultantFormat - Pointer to value where the resultant format should be 133 | returned. 134 | ResultantFormatLength - Actual length of the resultant format that is placed 135 | at ResultantFormat. This should be less than or equal 136 | to OutputBufferLength. 137 | 138 | Return Value: 139 | NT status code. 140 | */ 141 | { 142 | PAGED_CODE(); 143 | DPF_ENTER(("[CMiniportTopology::DataRangeIntersection]")); 144 | return (STATUS_NOT_IMPLEMENTED); 145 | } 146 | 147 | //============================================================================= 148 | STDMETHODIMP CMiniportTopology::GetDescription( 149 | OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor 150 | ) 151 | /* 152 | Routine Description: 153 | The GetDescription function gets a pointer to a filter description. 154 | It provides a location to deposit a pointer in miniport's description 155 | structure. This is the placeholder for the FromNode or ToNode fields in 156 | connections which describe connections to the filter's pins. 157 | 158 | Arguments: 159 | OutFilterDescriptor - Pointer to the filter description. 160 | 161 | Return Value: 162 | NT status code. 163 | */ 164 | { 165 | PAGED_CODE(); 166 | ASSERT(OutFilterDescriptor); 167 | DPF_ENTER(("[CMiniportTopology::GetDescription]")); 168 | 169 | *OutFilterDescriptor = m_FilterDescriptor; 170 | return (STATUS_SUCCESS); 171 | } 172 | 173 | //============================================================================= 174 | STDMETHODIMP CMiniportTopology::Init( 175 | IN PUNKNOWN UnknownAdapter, 176 | IN PRESOURCELIST ResourceList, 177 | IN PPORTTOPOLOGY Port_ 178 | ) 179 | /* 180 | Routine Description: 181 | The Init function initializes the miniport. Callers of this function 182 | should run at IRQL PASSIVE_LEVEL 183 | 184 | Arguments: 185 | UnknownAdapter - A pointer to the Iuknown interface of the adapter object. 186 | ResourceList - Pointer to the resource list to be supplied to the miniport 187 | during initialization. The port driver is free to examine the 188 | contents of the ResourceList. The port driver will not be 189 | modify the ResourceList contents. 190 | Port - Pointer to the topology port object that is linked with this miniport. 191 | 192 | Return Value: 193 | NT status code. 194 | */ 195 | { 196 | PAGED_CODE(); 197 | ASSERT(UnknownAdapter); 198 | ASSERT(Port_); 199 | 200 | DPF_ENTER(("[CMiniportTopology::Init]")); 201 | 202 | // aus dem Konstruktor 203 | m_AdapterCommon = NULL; 204 | m_FilterDescriptor = NULL; 205 | 206 | NTSTATUS ntStatus; 207 | 208 | ntStatus = UnknownAdapter->QueryInterface( 209 | IID_IAdapterCommon, 210 | (PVOID *) &m_AdapterCommon 211 | ); 212 | if (NT_SUCCESS(ntStatus)) { 213 | m_AdapterCommon->MixerReset(); 214 | } 215 | 216 | if (!NT_SUCCESS(ntStatus)) { 217 | // clean up AdapterCommon 218 | if (m_AdapterCommon) { 219 | m_AdapterCommon->Release(); 220 | m_AdapterCommon = NULL; 221 | } 222 | } 223 | 224 | if (NT_SUCCESS(ntStatus)) { 225 | m_FilterDescriptor = &MiniportFilterDescriptor; 226 | m_AdapterCommon->MixerMuxWrite(KSPIN_TOPO_MIC_SOURCE); 227 | } 228 | 229 | return ntStatus; 230 | } // Init 231 | 232 | //============================================================================= 233 | STDMETHODIMP CMiniportTopology::NonDelegatingQueryInterface( 234 | IN REFIID Interface, 235 | OUT PVOID * Object 236 | ) 237 | /* 238 | Routine Description: 239 | QueryInterface for MiniportTopology 240 | 241 | Arguments: 242 | Interface - GUID of the interface 243 | Object - interface object to be returned. 244 | 245 | Return Value: 246 | NT status code. 247 | */ 248 | { 249 | PAGED_CODE(); 250 | ASSERT(Object); 251 | 252 | if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { 253 | *Object = PVOID(PUNKNOWN(this)); 254 | } else if (IsEqualGUIDAligned(Interface, IID_IMiniport)) { 255 | *Object = PVOID(PMINIPORT(this)); 256 | } else if (IsEqualGUIDAligned(Interface, IID_IMiniportTopology)) { 257 | *Object = PVOID(PMINIPORTTOPOLOGY(this)); 258 | } else { 259 | *Object = NULL; 260 | } 261 | 262 | if (*Object) { 263 | // We reference the interface for the caller. 264 | PUNKNOWN(*Object)->AddRef(); 265 | return(STATUS_SUCCESS); 266 | } 267 | return(STATUS_INVALID_PARAMETER); 268 | } // NonDelegatingQueryInterface 269 | 270 | //============================================================================= 271 | NTSTATUS CMiniportTopology::PropertyHandlerGeneric( 272 | IN PPCPROPERTY_REQUEST PropertyRequest 273 | ) 274 | /* 275 | Routine Description: 276 | Handles all properties for this miniport. 277 | 278 | Arguments: 279 | PropertyRequest - property request structure 280 | 281 | Return Value: 282 | NT status code. 283 | */ 284 | { 285 | PAGED_CODE(); 286 | 287 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 288 | switch (PropertyRequest->PropertyItem->Id) 289 | { 290 | case KSPROPERTY_AUDIO_VOLUMELEVEL: 291 | ntStatus = PropertyHandlerVolume(PropertyRequest); 292 | break; 293 | 294 | case KSPROPERTY_AUDIO_CPU_RESOURCES: 295 | ntStatus = PropertyHandlerCpuResources(PropertyRequest); 296 | break; 297 | 298 | case KSPROPERTY_AUDIO_MUTE: 299 | ntStatus = PropertyHandlerMute(PropertyRequest); 300 | break; 301 | 302 | case KSPROPERTY_AUDIO_MUX_SOURCE: 303 | ntStatus = PropertyHandlerMuxSource(PropertyRequest); 304 | break; 305 | 306 | default: 307 | DPF(D_TERSE, ("[PropertyHandlerGeneric: Invalid Device Request]")); 308 | } 309 | 310 | return ntStatus; 311 | } // PropertyHandlerGeneric 312 | 313 | //============================================================================= 314 | NTSTATUS CMiniportTopology::PropertyHandlerBasicSupportVolume( 315 | IN PPCPROPERTY_REQUEST PropertyRequest 316 | ) 317 | /* 318 | Routine Description: 319 | Handles BasicSupport for Volume nodes. 320 | 321 | Arguments: 322 | PropertyRequest - property request structure 323 | 324 | Return Value: 325 | NT status code. 326 | */ 327 | { 328 | PAGED_CODE(); 329 | 330 | NTSTATUS ntStatus = STATUS_SUCCESS; 331 | ULONG cbFullProperty = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG); 332 | 333 | if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION))) { 334 | PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value); 335 | 336 | PropDesc->AccessFlags = KSPROPERTY_TYPE_ALL; 337 | PropDesc->DescriptionSize = cbFullProperty; 338 | PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General; 339 | PropDesc->PropTypeSet.Id = VT_I4; 340 | PropDesc->PropTypeSet.Flags = 0; 341 | PropDesc->MembersListCount = 1; 342 | PropDesc->Reserved = 0; 343 | 344 | // if return buffer can also hold a range description, return it too 345 | if(PropertyRequest->ValueSize >= cbFullProperty) { 346 | // fill in the members header 347 | PKSPROPERTY_MEMBERSHEADER Members = PKSPROPERTY_MEMBERSHEADER(PropDesc + 1); 348 | 349 | Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES; 350 | Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG); 351 | Members->MembersCount = 1; 352 | Members->Flags = 0; 353 | 354 | // fill in the stepped range 355 | PKSPROPERTY_STEPPING_LONG Range = PKSPROPERTY_STEPPING_LONG(Members + 1); 356 | 357 | // BUGBUG these are from SB16 driver. 358 | // Are these valid. 359 | Range->Bounds.SignedMaximum = 0xE0000; // 14 (dB) * 0x10000 360 | Range->Bounds.SignedMinimum = 0xFFF20000; // -14 (dB) * 0x10000 361 | Range->SteppingDelta = 0x20000; // 2 (dB) * 0x10000 362 | Range->Reserved = 0; 363 | 364 | // set the return value size 365 | PropertyRequest->ValueSize = cbFullProperty; 366 | } else { 367 | PropertyRequest->ValueSize = 0; 368 | ntStatus = STATUS_BUFFER_TOO_SMALL; 369 | } 370 | } else if(PropertyRequest->ValueSize >= sizeof(ULONG)) { 371 | // if return buffer can hold a ULONG, return the access flags 372 | PULONG AccessFlags = PULONG(PropertyRequest->Value); 373 | 374 | PropertyRequest->ValueSize = sizeof(ULONG); 375 | *AccessFlags = KSPROPERTY_TYPE_ALL; 376 | } else if (PropertyRequest->ValueSize == 0) { 377 | // Send the caller required value size. 378 | PropertyRequest->ValueSize = cbFullProperty; 379 | ntStatus = STATUS_BUFFER_OVERFLOW; 380 | } else { 381 | PropertyRequest->ValueSize = 0; 382 | ntStatus = STATUS_BUFFER_TOO_SMALL; 383 | } 384 | return ntStatus; 385 | } // PropertyHandlerBasicSupportVolume 386 | 387 | //============================================================================= 388 | NTSTATUS CMiniportTopology::PropertyHandlerCpuResources( 389 | IN PPCPROPERTY_REQUEST PropertyRequest 390 | ) 391 | /* 392 | Routine Description: 393 | Processes KSPROPERTY_AUDIO_CPURESOURCES 394 | 395 | Arguments: 396 | PropertyRequest - property request structure 397 | 398 | Return Value: 399 | NT status code. 400 | */ 401 | { 402 | PAGED_CODE(); 403 | DPF_ENTER(("[CMiniportTopology::PropertyHandlerCpuResources]")); 404 | 405 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 406 | 407 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) { 408 | ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(ULONG)); 409 | if (NT_SUCCESS(ntStatus)) { 410 | *(PLONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU; 411 | PropertyRequest->ValueSize = sizeof(LONG); 412 | } 413 | } else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) { 414 | ntStatus = PropertyHandler_BasicSupport( 415 | PropertyRequest, 416 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 417 | VT_ILLEGAL 418 | ); 419 | } 420 | return ntStatus; 421 | } // PropertyHandlerCpuResources 422 | 423 | //============================================================================= 424 | NTSTATUS CMiniportTopology::PropertyHandlerMute( 425 | IN PPCPROPERTY_REQUEST PropertyRequest 426 | ) 427 | /* 428 | Routine Description: 429 | Property handler for KSPROPERTY_AUDIO_MUTE 430 | 431 | Arguments: 432 | PropertyRequest - property request structure 433 | 434 | Return Value: 435 | NT status code. 436 | */ 437 | { 438 | PAGED_CODE(); 439 | 440 | DPF_ENTER(("[CMiniportTopology::PropertyHandlerMute]")); 441 | 442 | NTSTATUS ntStatus; 443 | LONG lChannel; 444 | PBOOL pfMute; 445 | 446 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) { 447 | ntStatus = PropertyHandler_BasicSupport( 448 | PropertyRequest, 449 | KSPROPERTY_TYPE_ALL, 450 | VT_BOOL 451 | ); 452 | } else { 453 | ntStatus = ValidatePropertyParams( 454 | PropertyRequest, 455 | sizeof(BOOL), 456 | sizeof(LONG) 457 | ); 458 | if (NT_SUCCESS(ntStatus)) { 459 | lChannel = * PLONG (PropertyRequest->Instance); 460 | pfMute = PBOOL (PropertyRequest->Value); 461 | 462 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) { 463 | *pfMute = m_AdapterCommon->MixerMuteRead(PropertyRequest->Node); 464 | PropertyRequest->ValueSize = sizeof(BOOL); 465 | ntStatus = STATUS_SUCCESS; 466 | } else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET) { 467 | m_AdapterCommon->MixerMuteWrite(PropertyRequest->Node, *pfMute); 468 | ntStatus = STATUS_SUCCESS; 469 | } 470 | } else { 471 | DPF(D_TERSE, ("[PropertyHandlerMute - Invalid parameter]")); 472 | ntStatus = STATUS_INVALID_PARAMETER; 473 | } 474 | } 475 | return ntStatus; 476 | } // PropertyHandlerMute 477 | 478 | //============================================================================= 479 | NTSTATUS CMiniportTopology::PropertyHandlerMuxSource( 480 | IN PPCPROPERTY_REQUEST PropertyRequest 481 | ) 482 | /* 483 | Routine Description: 484 | PropertyHandler for KSPROPERTY_AUDIO_MUX_SOURCE. 485 | 486 | Arguments: 487 | PropertyRequest - property request structure 488 | 489 | Return Value: 490 | NT status code. 491 | */ 492 | { 493 | PAGED_CODE(); 494 | DPF_ENTER(("[CMiniportTopology::PropertyHandlerMuxSource]")); 495 | 496 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 497 | 498 | // Validate node 499 | // This property is only valid for WAVEIN_MUX node. 500 | // 501 | // TODO if (WAVEIN_MUX == PropertyRequest->Node) 502 | { 503 | if (PropertyRequest->ValueSize >= sizeof(ULONG)) { 504 | PULONG pulMuxValue = PULONG(PropertyRequest->Value); 505 | 506 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) { 507 | *pulMuxValue = m_AdapterCommon->MixerMuxRead(); 508 | PropertyRequest->ValueSize = sizeof(ULONG); 509 | ntStatus = STATUS_SUCCESS; 510 | } else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET) { 511 | m_AdapterCommon->MixerMuxWrite(*pulMuxValue); 512 | ntStatus = STATUS_SUCCESS; 513 | } else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) { 514 | ntStatus = PropertyHandler_BasicSupport(PropertyRequest, KSPROPERTY_TYPE_ALL, VT_I4); 515 | } 516 | } else { 517 | DPF(D_TERSE, ("[PropertyHandlerMuxSource - Invalid parameter]")); 518 | ntStatus = STATUS_INVALID_PARAMETER; 519 | } 520 | } 521 | return ntStatus; 522 | } // PropertyHandlerMuxSource 523 | 524 | //============================================================================= 525 | NTSTATUS CMiniportTopology::PropertyHandlerVolume( 526 | IN PPCPROPERTY_REQUEST PropertyRequest 527 | ) 528 | /* 529 | Routine Description: 530 | Property handler for KSPROPERTY_AUDIO_VOLUMELEVEL 531 | 532 | Arguments: 533 | PropertyRequest - property request structure 534 | 535 | Return Value: 536 | NT status code. 537 | */ 538 | { 539 | PAGED_CODE(); 540 | DPF_ENTER(("[CMiniportTopology::PropertyHandlerVolume]")); 541 | 542 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 543 | LONG lChannel; 544 | PULONG pulVolume; 545 | 546 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) { 547 | ntStatus = PropertyHandlerBasicSupportVolume(PropertyRequest); 548 | } else { 549 | ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(ULONG), sizeof(KSNODEPROPERTY_AUDIO_CHANNEL)-sizeof(KSNODEPROPERTY)); 550 | if (NT_SUCCESS(ntStatus)) { 551 | lChannel = * (PLONG (PropertyRequest->Instance)); 552 | pulVolume = PULONG (PropertyRequest->Value); 553 | 554 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) { 555 | *pulVolume = m_AdapterCommon->MixerVolumeRead(PropertyRequest->Node, lChannel); 556 | PropertyRequest->ValueSize = sizeof(ULONG); 557 | ntStatus = STATUS_SUCCESS; 558 | } else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET) { 559 | m_AdapterCommon->MixerVolumeWrite(PropertyRequest->Node, lChannel, *pulVolume); 560 | ntStatus = STATUS_SUCCESS; 561 | } 562 | } else { 563 | DPF(D_TERSE, ("[PropertyHandlerVolume - Invalid parameter]")); 564 | ntStatus = STATUS_INVALID_PARAMETER; 565 | } 566 | } 567 | return ntStatus; 568 | } // PropertyHandlerVolume 569 | 570 | #pragma code_seg() 571 | 572 | -------------------------------------------------------------------------------- /rtsdtopo.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | rtsdtopo.h 4 | 5 | Abstract: 6 | Declaration of topology miniport. 7 | */ 8 | 9 | #ifndef __RTSDTOPO_H_ 10 | #define __RTSDTOPO_H_ 11 | 12 | //============================================================================= 13 | // Classes 14 | //============================================================================= 15 | 16 | /////////////////////////////////////////////////////////////////////////////// 17 | // CMiniportTopology 18 | // 19 | 20 | class CMiniportTopology : public IMiniportTopology, public CUnknown { 21 | protected: 22 | PADAPTERCOMMON m_AdapterCommon; // Adapter common object. 23 | PPCFILTER_DESCRIPTOR m_FilterDescriptor; // Filter descriptor. 24 | public: 25 | DECLARE_STD_UNKNOWN(); 26 | DEFINE_STD_CONSTRUCTOR(CMiniportTopology); 27 | ~CMiniportTopology(); 28 | 29 | IMP_IMiniportTopology; 30 | 31 | NTSTATUS Init( 32 | IN PUNKNOWN UnknownAdapter, 33 | IN PPORTTOPOLOGY Port_ 34 | ); 35 | 36 | // PropertyHandlers 37 | NTSTATUS PropertyHandlerBasicSupportVolume( 38 | IN PPCPROPERTY_REQUEST PropertyRequest 39 | ); 40 | 41 | NTSTATUS PropertyHandlerCpuResources( 42 | IN PPCPROPERTY_REQUEST PropertyRequest 43 | ); 44 | 45 | NTSTATUS PropertyHandlerGeneric( 46 | IN PPCPROPERTY_REQUEST PropertyRequest 47 | ); 48 | 49 | NTSTATUS PropertyHandlerMute( 50 | IN PPCPROPERTY_REQUEST PropertyRequest 51 | ); 52 | 53 | NTSTATUS PropertyHandlerMuxSource( 54 | IN PPCPROPERTY_REQUEST PropertyRequest 55 | ); 56 | 57 | NTSTATUS PropertyHandlerVolume( 58 | IN PPCPROPERTY_REQUEST PropertyRequest 59 | ); 60 | }; 61 | typedef CMiniportTopology *PCMiniportTopology; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /rtsdwave.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | rtsdwave.cpp 4 | 5 | Abstract: 6 | Implementation of wavecyclic miniport. 7 | */ 8 | 9 | #include "rtsdaudio.h" 10 | #include "common.h" 11 | #include "rtsdwave.h" 12 | #include "rtsdwavestream.h" 13 | #include "wavtable.h" 14 | 15 | #pragma code_seg("PAGE") 16 | 17 | //============================================================================= 18 | // CMiniportWaveCyclic 19 | //============================================================================= 20 | 21 | //============================================================================= 22 | NTSTATUS CreateMiniportWaveCyclic( 23 | OUT PUNKNOWN * Unknown, 24 | IN REFCLSID, 25 | IN PUNKNOWN UnknownOuter OPTIONAL, 26 | IN POOL_TYPE PoolType 27 | ) 28 | /* 29 | Routine Description: 30 | Create the wavecyclic miniport. 31 | 32 | Arguments: 33 | Unknown - 34 | RefClsId - 35 | UnknownOuter - 36 | PoolType - 37 | 38 | Return Value: 39 | NT status code. 40 | */ 41 | { 42 | PAGED_CODE(); 43 | ASSERT(Unknown); 44 | 45 | STD_CREATE_BODY(CMiniportWaveCyclic, Unknown, UnknownOuter, PoolType); 46 | } 47 | 48 | //============================================================================= 49 | CMiniportWaveCyclic::~CMiniportWaveCyclic(void) 50 | /* 51 | Routine Description: 52 | Destructor for wavecyclic miniport 53 | 54 | Arguments: 55 | 56 | Return Value: 57 | NT status code. 58 | */ 59 | { 60 | PAGED_CODE(); 61 | DPF_ENTER(("[CMiniportWaveCyclic::~CMiniportWaveCyclic]")); 62 | 63 | if (m_Port) 64 | m_Port->Release(); 65 | 66 | if (m_ServiceGroup) 67 | m_ServiceGroup->Release(); 68 | 69 | if (m_AdapterCommon) 70 | m_AdapterCommon->Release(); 71 | } 72 | 73 | 74 | //============================================================================= 75 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclic::DataRangeIntersection( 76 | IN ULONG PinId, 77 | IN PKSDATARANGE ClientDataRange, 78 | IN PKSDATARANGE MyDataRange, 79 | IN ULONG OutputBufferLength, 80 | OUT PVOID ResultantFormat, 81 | OUT PULONG ResultantFormatLength 82 | ) 83 | /* 84 | Routine Description: 85 | The DataRangeIntersection function determines the highest quality 86 | intersection of two data ranges. 87 | 88 | Arguments: 89 | PinId - Pin for which data intersection is being determined. 90 | ClientDataRange - Pointer to KSDATARANGE structure which contains the data 91 | range submitted by client in the data range intersection 92 | property request. 93 | MyDataRange - Pin's data range to be compared with client's data 94 | range. In this case we actually ignore our own data 95 | range, because we know that we only support one range. 96 | OutputBufferLength - Size of the buffer pointed to by the resultant format 97 | parameter. 98 | ResultantFormat - Pointer to value where the resultant format should be 99 | returned. 100 | ResultantFormatLength - Actual length of the resultant format placed in 101 | ResultantFormat. This should be less than or equal 102 | to OutputBufferLength. 103 | 104 | Return Value: 105 | NT status code. 106 | */ 107 | { 108 | PAGED_CODE(); 109 | 110 | // This driver only supports PCM formats. 111 | // Portcls will handle the request for us. 112 | 113 | return STATUS_NOT_IMPLEMENTED; 114 | } // DataRangeIntersection 115 | 116 | //============================================================================= 117 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclic::GetDescription(OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor) 118 | /* 119 | Routine Description: 120 | The GetDescription function gets a pointer to a filter description. 121 | It provides a location to deposit a pointer in miniport's description 122 | structure. This is the placeholder for the FromNode or ToNode fields in 123 | connections which describe connections to the filter's pins. 124 | 125 | Arguments: 126 | OutFilterDescriptor - Pointer to the filter description. 127 | 128 | Return Value: 129 | NT status code. 130 | */ 131 | { 132 | PAGED_CODE(); 133 | ASSERT(OutFilterDescriptor); 134 | DPF_ENTER(("[CMiniportWaveCyclic::GetDescription]")); 135 | 136 | *OutFilterDescriptor = m_FilterDescriptor; 137 | return (STATUS_SUCCESS); 138 | } // GetDescription 139 | 140 | //============================================================================= 141 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclic::Init( 142 | IN PUNKNOWN UnknownAdapter_, 143 | IN PRESOURCELIST ResourceList_, 144 | IN PPORTWAVECYCLIC Port_ 145 | ) 146 | /* 147 | Routine Description: 148 | The Init function initializes the miniport. Callers of this function 149 | should run at IRQL PASSIVE_LEVEL 150 | 151 | Arguments: 152 | UnknownAdapter - A pointer to the Iuknown interface of the adapter object. 153 | ResourceList - Pointer to the resource list to be supplied to the miniport 154 | during initialization. The port driver is free to examine the 155 | contents of the ResourceList. The port driver will not be 156 | modify the ResourceList contents. 157 | Port - Pointer to the topology port object that is linked with this miniport. 158 | 159 | Return Value: 160 | NT status code. 161 | */ 162 | { 163 | PAGED_CODE(); 164 | ASSERT(UnknownAdapter_); 165 | ASSERT(Port_); 166 | DPF_ENTER(("[CMiniportWaveCyclic::Init]")); 167 | 168 | NTSTATUS ntStatus; 169 | 170 | m_AdapterCommon = NULL; 171 | m_Port = NULL; 172 | m_FilterDescriptor = NULL; 173 | 174 | m_NotificationInterval = 0; 175 | m_SamplingFrequency = 0; 176 | 177 | m_ServiceGroup = NULL; 178 | m_MaxDmaBufferSize = DMA_BUFFER_SIZE; 179 | 180 | m_MaxOutputStreams = MAX_OUTPUT_STREAMS; 181 | m_MaxInputStreams = MAX_INPUT_STREAMS; 182 | m_MaxTotalStreams = MAX_TOTAL_STREAMS; 183 | 184 | m_MinChannels = MIN_CHANNELS; 185 | m_MaxChannelsPcm = MAX_CHANNELS_PCM; 186 | 187 | m_MinBitsPerSamplePcm = MIN_BITS_PER_SAMPLE_PCM; 188 | m_MaxBitsPerSamplePcm = MAX_BITS_PER_SAMPLE_PCM; 189 | m_MinSampleRatePcm = MIN_SAMPLE_RATE; 190 | m_MaxSampleRatePcm = MAX_SAMPLE_RATE; 191 | 192 | // eigenes 193 | myBuffer=NULL; 194 | myBufferSize = 0; 195 | myBufferLocked = TRUE; 196 | myBufferWritePos = 0; 197 | myBufferReadPos = 0; 198 | myBufferReading = FALSE; 199 | // eigenes 200 | 201 | // AddRef() is required because we are keeping this pointer. 202 | m_Port = Port_; 203 | m_Port->AddRef(); 204 | 205 | // We want the IAdapterCommon interface on the adapter common object, 206 | // which is given to us as a IUnknown. The QueryInterface call gives us 207 | // an AddRefed pointer to the interface we want. 208 | ntStatus = UnknownAdapter_->QueryInterface(IID_IAdapterCommon, (PVOID *) &m_AdapterCommon); 209 | if (NT_SUCCESS(ntStatus)) { 210 | KeInitializeMutex(&m_SampleRateSync, 1); 211 | ntStatus = PcNewServiceGroup(&m_ServiceGroup, NULL); 212 | 213 | if (NT_SUCCESS(ntStatus)) { 214 | m_AdapterCommon->SetWaveServiceGroup(m_ServiceGroup); 215 | } 216 | } 217 | 218 | if (!NT_SUCCESS(ntStatus)) { 219 | // clean up AdapterCommon 220 | if (m_AdapterCommon) { 221 | // clean up the service group 222 | if (m_ServiceGroup) { 223 | m_AdapterCommon->SetWaveServiceGroup(NULL); 224 | m_ServiceGroup->Release(); 225 | m_ServiceGroup = NULL; 226 | } 227 | 228 | m_AdapterCommon->Release(); 229 | m_AdapterCommon = NULL; 230 | } 231 | 232 | // release the port 233 | m_Port->Release(); 234 | m_Port = NULL; 235 | } 236 | 237 | if (NT_SUCCESS(ntStatus)) { 238 | // Set filter descriptor. 239 | m_FilterDescriptor = &MiniportFilterDescriptor; 240 | 241 | m_fCaptureAllocated = FALSE; 242 | m_fRenderAllocated = FALSE; 243 | } 244 | 245 | return ntStatus; 246 | } // Init 247 | 248 | //============================================================================= 249 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclic::NewStream( 250 | OUT PMINIPORTWAVECYCLICSTREAM * OutStream, 251 | IN PUNKNOWN OuterUnknown, 252 | IN POOL_TYPE PoolType, 253 | IN ULONG Pin, 254 | IN BOOLEAN Capture, 255 | IN PKSDATAFORMAT DataFormat, 256 | OUT PDMACHANNEL * OutDmaChannel, 257 | OUT PSERVICEGROUP * OutServiceGroup 258 | ) 259 | /* 260 | Routine Description: 261 | The NewStream function creates a new instance of a logical stream 262 | associated with a specified physical channel. Callers of NewStream should 263 | run at IRQL PASSIVE_LEVEL. 264 | 265 | Arguments: 266 | OutStream - 267 | OuterUnknown - 268 | PoolType - 269 | Pin - 270 | Capture - 271 | DataFormat - 272 | OutDmaChannel - 273 | OutServiceGroup - 274 | 275 | Return Value: 276 | NT status code. 277 | */ 278 | { 279 | PAGED_CODE(); 280 | 281 | ASSERT(OutStream); 282 | ASSERT(DataFormat); 283 | ASSERT(OutDmaChannel); 284 | ASSERT(OutServiceGroup); 285 | 286 | DPF_ENTER(("[CMiniportWaveCyclic::NewStream]")); 287 | 288 | NTSTATUS ntStatus = STATUS_SUCCESS; 289 | PCMiniportWaveCyclicStream stream = NULL; 290 | 291 | // Check if we have enough streams. 292 | if (Capture) { 293 | if (m_fCaptureAllocated) { 294 | DPF(D_TERSE, ("[Only one capture stream supported]")); 295 | ntStatus = STATUS_INSUFFICIENT_RESOURCES; 296 | } 297 | } else { 298 | if (m_fRenderAllocated) { 299 | DPF(D_TERSE, ("[Only one render stream supported]")); 300 | ntStatus = STATUS_INSUFFICIENT_RESOURCES; 301 | } 302 | } 303 | 304 | // Determine if the format is valid. 305 | if (NT_SUCCESS(ntStatus)) { 306 | ntStatus = ValidateFormat(DataFormat); 307 | } 308 | 309 | // Instantiate a stream. Stream must be in 310 | // NonPagedPool because of file saving. 311 | if (NT_SUCCESS(ntStatus)) { 312 | stream = new (NonPagedPool, RTSDAUDIO_POOLTAG) CMiniportWaveCyclicStream(OuterUnknown); 313 | if (stream) { 314 | stream->AddRef(); 315 | ntStatus = stream->Init(this, Pin, Capture, DataFormat); 316 | } else { 317 | ntStatus = STATUS_INSUFFICIENT_RESOURCES; 318 | } 319 | } 320 | 321 | if (NT_SUCCESS(ntStatus)) { 322 | if (Capture) { 323 | m_fCaptureAllocated = TRUE; 324 | } else { 325 | m_fRenderAllocated = TRUE; 326 | } 327 | 328 | *OutStream = PMINIPORTWAVECYCLICSTREAM(stream); 329 | (*OutStream)->AddRef(); 330 | 331 | *OutDmaChannel = PDMACHANNEL(stream); 332 | (*OutDmaChannel)->AddRef(); 333 | 334 | *OutServiceGroup = m_ServiceGroup; 335 | (*OutServiceGroup)->AddRef(); 336 | 337 | // The stream, the DMA channel, and the service group have 338 | // references now for the caller. The caller expects these 339 | // references to be there. 340 | } 341 | 342 | // This is our private reference to the stream. The caller has 343 | // its own, so we can release in any case. 344 | if (stream) 345 | stream->Release(); 346 | 347 | return ntStatus; 348 | } // NewStream 349 | 350 | //============================================================================= 351 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclic::NonDelegatingQueryInterface( 352 | IN REFIID Interface, 353 | OUT PVOID * Object 354 | ) 355 | /* 356 | Routine Description: 357 | QueryInterface 358 | 359 | Arguments: 360 | Interface - GUID 361 | Object - interface pointer to be returned. 362 | 363 | Return Value: 364 | NT status code. 365 | */ 366 | { 367 | PAGED_CODE(); 368 | ASSERT(Object); 369 | 370 | if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { 371 | *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLIC(this))); 372 | } else if (IsEqualGUIDAligned(Interface, IID_IMiniport)) { 373 | *Object = PVOID(PMINIPORT(this)); 374 | } else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclic)) { 375 | *Object = PVOID(PMINIPORTWAVECYCLIC(this)); 376 | } else { 377 | *Object = NULL; 378 | } 379 | 380 | if (*Object) { 381 | // We reference the interface for the caller. 382 | PUNKNOWN(*Object)->AddRef(); 383 | return STATUS_SUCCESS; 384 | } 385 | 386 | return STATUS_INVALID_PARAMETER; 387 | } // NonDelegatingQueryInterface 388 | 389 | //============================================================================= 390 | NTSTATUS CMiniportWaveCyclic::PropertyHandlerComponentId( 391 | IN PPCPROPERTY_REQUEST PropertyRequest 392 | ) 393 | /* 394 | Routine Description: 395 | Handles KSPROPERTY_GENERAL_COMPONENTID 396 | 397 | Arguments: 398 | PropertyRequest - 399 | 400 | Return Value: 401 | NT status code. 402 | */ 403 | { 404 | PAGED_CODE(); 405 | DPF_ENTER(("[PropertyHandlerComponentId]")); 406 | 407 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 408 | 409 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) { 410 | ntStatus = PropertyHandler_BasicSupport( 411 | PropertyRequest, 412 | KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET, 413 | VT_ILLEGAL 414 | ); 415 | } else { 416 | ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(KSCOMPONENTID), 0); 417 | if (NT_SUCCESS(ntStatus)) { 418 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) { 419 | PKSCOMPONENTID pComponentId = (PKSCOMPONENTID) PropertyRequest->Value; 420 | 421 | INIT_MMREG_MID(&pComponentId->Manufacturer, MM_MICROSOFT); 422 | pComponentId->Product = PID_RTSDAUDIO; 423 | pComponentId->Name = NAME_RTSDAUDIO; 424 | pComponentId->Component = GUID_NULL; // Not used for extended caps. 425 | pComponentId->Version = RTSDAUDIO_VERSION; 426 | pComponentId->Revision = RTSDAUDIO_REVISION; 427 | 428 | PropertyRequest->ValueSize = sizeof(KSCOMPONENTID); 429 | ntStatus = STATUS_SUCCESS; 430 | } 431 | } else { 432 | DPF(D_TERSE, ("[PropertyHandlerComponentId - Invalid parameter]")); 433 | ntStatus = STATUS_INVALID_PARAMETER; 434 | } 435 | } 436 | 437 | return ntStatus; 438 | } // PropertyHandlerComponentId 439 | 440 | //============================================================================= 441 | NTSTATUS PropertyHandler_WaveFilter( 442 | IN PPCPROPERTY_REQUEST PropertyRequest 443 | ) 444 | /* 445 | Routine Description: 446 | Redirects general property request to miniport object 447 | 448 | Arguments: 449 | PropertyRequest - 450 | 451 | Return Value: 452 | NT status code. 453 | */ 454 | { 455 | PAGED_CODE(); 456 | 457 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 458 | PCMiniportWaveCyclic pWave = (PCMiniportWaveCyclic) PropertyRequest->MajorTarget; 459 | 460 | switch (PropertyRequest->PropertyItem->Id) { 461 | case KSPROPERTY_GENERAL_COMPONENTID: 462 | ntStatus = pWave->PropertyHandlerComponentId(PropertyRequest); 463 | break; 464 | 465 | default: 466 | DPF(D_TERSE, ("[PropertyHandler_WaveFilter: Invalid Device Request]")); 467 | } 468 | 469 | return ntStatus; 470 | } // PropertyHandler_WaveFilter 471 | 472 | //============================================================================= 473 | NTSTATUS CMiniportWaveCyclic::PropertyHandlerCpuResources( 474 | IN PPCPROPERTY_REQUEST PropertyRequest 475 | ) 476 | /* 477 | Routine Description: 478 | Processes KSPROPERTY_AUDIO_CPURESOURCES 479 | 480 | Arguments: 481 | PropertyRequest - property request structure 482 | 483 | Return Value: 484 | NT status code. 485 | */ 486 | { 487 | PAGED_CODE(); 488 | ASSERT(PropertyRequest); 489 | DPF_ENTER(("[CMiniportWaveCyclic::PropertyHandlerCpuResources]")); 490 | 491 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 492 | 493 | if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) { 494 | ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(LONG), 0); 495 | if (NT_SUCCESS(ntStatus)) { 496 | *(PLONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU; 497 | PropertyRequest->ValueSize = sizeof(LONG); 498 | ntStatus = STATUS_SUCCESS; 499 | } 500 | } else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) { 501 | ntStatus =PropertyHandler_BasicSupport(PropertyRequest, KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, VT_I4); 502 | } 503 | 504 | return ntStatus; 505 | } // PropertyHandlerCpuResources 506 | 507 | //============================================================================= 508 | NTSTATUS CMiniportWaveCyclic::PropertyHandlerGeneric( 509 | IN PPCPROPERTY_REQUEST PropertyRequest 510 | ) 511 | /* 512 | Routine Description: 513 | Handles all properties for this miniport. 514 | 515 | Arguments: 516 | PropertyRequest - property request structure 517 | 518 | Return Value: 519 | NT status code. 520 | */ 521 | { 522 | PAGED_CODE(); 523 | ASSERT(PropertyRequest); 524 | ASSERT(PropertyRequest->PropertyItem); 525 | 526 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 527 | 528 | switch (PropertyRequest->PropertyItem->Id) { 529 | case KSPROPERTY_AUDIO_CPU_RESOURCES: 530 | ntStatus = PropertyHandlerCpuResources(PropertyRequest); 531 | break; 532 | 533 | default: 534 | DPF(D_TERSE, ("[PropertyHandlerGeneric: Invalid Device Request]")); 535 | ntStatus = STATUS_INVALID_DEVICE_REQUEST; 536 | } 537 | 538 | return ntStatus; 539 | } // PropertyHandlerGeneric 540 | 541 | //============================================================================= 542 | NTSTATUS CMiniportWaveCyclic::ValidateFormat( 543 | IN PKSDATAFORMAT pDataFormat 544 | ) 545 | /* 546 | Routine Description: 547 | Validates that the given dataformat is valid. 548 | This version of the driver only supports PCM. 549 | 550 | Arguments: 551 | pDataFormat - The dataformat for validation. 552 | 553 | Return Value: 554 | NT status code. 555 | */ 556 | { 557 | PAGED_CODE(); 558 | ASSERT(pDataFormat); 559 | DPF_ENTER(("[CMiniportWaveCyclic::ValidateFormat]")); 560 | 561 | NTSTATUS ntStatus = STATUS_INVALID_PARAMETER; 562 | PWAVEFORMATEX pwfx; 563 | 564 | pwfx = GetWaveFormatEx(pDataFormat); 565 | if (pwfx) { 566 | if (IS_VALID_WAVEFORMATEX_GUID(&pDataFormat->SubFormat)) { 567 | USHORT wfxID = EXTRACT_WAVEFORMATEX_ID(&pDataFormat->SubFormat); 568 | 569 | switch (wfxID) { 570 | case WAVE_FORMAT_PCM: 571 | switch (pwfx->wFormatTag) { 572 | case WAVE_FORMAT_PCM: 573 | ntStatus = ValidatePcm(pwfx); 574 | break; 575 | } 576 | break; 577 | default: 578 | DPF(D_TERSE, ("Invalid format EXTRACT_WAVEFORMATEX_ID!")); 579 | break; 580 | } 581 | } else { 582 | DPF(D_TERSE, ("Invalid pDataFormat->SubFormat!") ); 583 | } 584 | } 585 | 586 | return ntStatus; 587 | } // ValidateFormat 588 | 589 | //============================================================================= 590 | NTSTATUS CMiniportWaveCyclic::ValidatePcm( 591 | IN PWAVEFORMATEX pWfx 592 | ) 593 | /* 594 | Routine Description: 595 | Given a waveformatex and format size validates that the format is in device 596 | datarange. 597 | 598 | Arguments: 599 | pWfx - wave format structure. 600 | 601 | Return Value: 602 | NT status code. 603 | */ 604 | { 605 | PAGED_CODE(); 606 | DPF_ENTER(("CMiniportWaveCyclic::ValidatePcm")); 607 | 608 | if ( pWfx && 609 | (pWfx->cbSize == 0) && 610 | (pWfx->nChannels >= m_MinChannels) && 611 | (pWfx->nChannels <= m_MaxChannelsPcm) && 612 | (pWfx->nSamplesPerSec >= m_MinSampleRatePcm) && 613 | (pWfx->nSamplesPerSec <= m_MaxSampleRatePcm) && 614 | (pWfx->wBitsPerSample >= m_MinBitsPerSamplePcm) && 615 | (pWfx->wBitsPerSample <= m_MaxBitsPerSamplePcm)) 616 | { 617 | return STATUS_SUCCESS; 618 | } 619 | 620 | DPF(D_TERSE, ("Invalid PCM format")); 621 | return STATUS_INVALID_PARAMETER; 622 | } // ValidatePcm 623 | 624 | //============================================================================= 625 | void TimerNotify( 626 | IN PKDPC Dpc, 627 | IN PVOID DeferredContext, 628 | IN PVOID SA1, 629 | IN PVOID SA2 630 | ) 631 | /* 632 | Routine Description: 633 | Dpc routine. This simulates an interrupt service routine. The Dpc will be 634 | called whenever CMiniportWaveCyclicStreamMSVAD::m_pTimer triggers. 635 | 636 | Arguments: 637 | Dpc - the Dpc object 638 | DeferredContext - Pointer to a caller-supplied context to be passed to 639 | the DeferredRoutine when it is called 640 | SA1 - System argument 1 641 | SA2 - System argument 2 642 | 643 | Return Value: 644 | NT status code. 645 | */ 646 | { 647 | PCMiniportWaveCyclic pMiniport = (PCMiniportWaveCyclic) DeferredContext; 648 | 649 | if (pMiniport && pMiniport->m_Port) { 650 | pMiniport->m_Port->Notify(pMiniport->m_ServiceGroup); 651 | } 652 | } // TimerNotify 653 | 654 | -------------------------------------------------------------------------------- /rtsdwave.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | rtsdwave.h 4 | 5 | Abstract: 6 | Definition of wavecyclic miniport class. 7 | */ 8 | 9 | #ifndef __RTSDWAVE_H_ 10 | #define __RTSDWAVE_H_ 11 | 12 | #include "rtsdwave.h" 13 | 14 | //============================================================================= 15 | // Referenced Forward 16 | //============================================================================= 17 | void TimerNotify( 18 | IN PKDPC Dpc, 19 | IN PVOID DeferredContext, 20 | IN PVOID SA1, 21 | IN PVOID SA2 22 | ); 23 | 24 | //============================================================================= 25 | // Classes 26 | //============================================================================= 27 | /////////////////////////////////////////////////////////////////////////////// 28 | // CMiniportWaveCyclic 29 | // 30 | 31 | class CMiniportWaveCyclic : public IMiniportWaveCyclic, public CUnknown { 32 | private: 33 | BOOL m_fCaptureAllocated; 34 | BOOL m_fRenderAllocated; 35 | 36 | protected: 37 | PADAPTERCOMMON m_AdapterCommon; // Adapter common object 38 | PPORTWAVECYCLIC m_Port; // Callback interface 39 | PPCFILTER_DESCRIPTOR m_FilterDescriptor; // Filter descriptor 40 | 41 | ULONG m_NotificationInterval; // milliseconds. 42 | ULONG m_SamplingFrequency; // Frames per second. 43 | 44 | PSERVICEGROUP m_ServiceGroup; // For notification. 45 | KMUTEX m_SampleRateSync; // Sync for sample rate 46 | 47 | ULONG m_MaxDmaBufferSize; // Dma buffer size. 48 | 49 | // All the below members should be updated by the child classes 50 | ULONG m_MaxOutputStreams; // Max stream caps 51 | ULONG m_MaxInputStreams; 52 | ULONG m_MaxTotalStreams; 53 | 54 | ULONG m_MinChannels; // Format caps 55 | ULONG m_MaxChannelsPcm; 56 | ULONG m_MinBitsPerSamplePcm; 57 | ULONG m_MaxBitsPerSamplePcm; 58 | ULONG m_MinSampleRatePcm; 59 | ULONG m_MaxSampleRatePcm; 60 | 61 | protected: 62 | NTSTATUS ValidateFormat(IN PKSDATAFORMAT pDataFormat); 63 | NTSTATUS ValidatePcm(IN PWAVEFORMATEX pWfx); 64 | 65 | public: 66 | DECLARE_STD_UNKNOWN(); 67 | DEFINE_STD_CONSTRUCTOR(CMiniportWaveCyclic); 68 | ~CMiniportWaveCyclic(); 69 | 70 | IMP_IMiniportWaveCyclic; 71 | 72 | //--> muss hier her, da CopyTo und CopyFrom in verschiedenen Stream-Instanzen aufgerufen werden. 73 | PVOID myBuffer; 74 | LONG myBufferSize; 75 | LONG myBufferLocked; 76 | LONG myBufferWritePos; 77 | LONG myBufferReadPos; 78 | LONG myBufferReading; //Determines wether there is a client that still reads data 79 | 80 | 81 | // Property Handler 82 | NTSTATUS PropertyHandlerGeneric(IN PPCPROPERTY_REQUEST PropertyRequest); 83 | NTSTATUS PropertyHandlerComponentId(IN PPCPROPERTY_REQUEST PropertyRequest); 84 | NTSTATUS PropertyHandlerCpuResources(IN PPCPROPERTY_REQUEST PropertyRequest); 85 | 86 | // Friends 87 | friend class CMiniportWaveCyclicStream; 88 | friend class CMiniportTopologySimple; 89 | friend void TimerNotify( 90 | IN PKDPC Dpc, 91 | IN PVOID DeferredContext, 92 | IN PVOID SA1, 93 | IN PVOID SA2 94 | ); 95 | }; 96 | typedef CMiniportWaveCyclic *PCMiniportWaveCyclic; 97 | #endif 98 | 99 | -------------------------------------------------------------------------------- /rtsdwavestream.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | rtsdwavestream.cpp 4 | 5 | Abstract: 6 | WaveCyclicStream-Miniport and IDmaChannel implementation. Does nothing HW related. 7 | */ 8 | #include "rtsdaudio.h" 9 | #include "common.h" 10 | #include "rtsdwave.h" 11 | #include "rtsdwavestream.h" 12 | 13 | #define DBGMESSAGE "[RTSD-Audio] rtsdwavestream.cpp: " 14 | #define DBGPRINT(x) DbgPrint(DBGMESSAGE x) 15 | 16 | /*PVOID myBuffer=NULL; 17 | LONG myBufferSize=0; 18 | LONG myBufferLocked=TRUE; 19 | LONG myBufferWritePos=0; 20 | LONG myBufferReadPos=0; 21 | LONG myBufferReading=FALSE; //Determines wether there is a client that still reads data 22 | //*/ 23 | 24 | 25 | //============================================================================= 26 | CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream(void) 27 | /* 28 | Routine Description: 29 | Destructor for wavecyclicstream 30 | 31 | Arguments: 32 | 33 | Return Value: 34 | NT status code. 35 | */ 36 | { 37 | PAGED_CODE(); 38 | DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]")); 39 | 40 | if (NULL != m_pMiniport) { 41 | if (m_fCapture) 42 | m_pMiniport->m_fCaptureAllocated = FALSE; 43 | else 44 | m_pMiniport->m_fRenderAllocated = FALSE; 45 | } 46 | if (m_pTimer) { 47 | KeCancelTimer(m_pTimer); 48 | ExFreePool(m_pTimer); 49 | } 50 | 51 | if (m_pDpc) 52 | ExFreePool( m_pDpc ); 53 | 54 | // Free the DMA buffer 55 | FreeBuffer(); 56 | 57 | } // ~CMiniportWaveCyclicStream 58 | 59 | //============================================================================= 60 | NTSTATUS CMiniportWaveCyclicStream::Init( 61 | IN PCMiniportWaveCyclic Miniport_, 62 | IN ULONG Pin_, 63 | IN BOOLEAN Capture_, 64 | IN PKSDATAFORMAT DataFormat_ 65 | ) 66 | /* 67 | Routine Description: 68 | Initializes the stream object. Allocate a DMA buffer, timer and DPC 69 | 70 | Arguments: 71 | Miniport_ - 72 | Pin_ - 73 | Capture_ - 74 | DataFormat - 75 | DmaChannel_ - 76 | 77 | Return Value: 78 | NT status code. 79 | */ 80 | { 81 | PAGED_CODE(); 82 | DPF_ENTER(("[CMiniportWaveCyclicStream::Init]")); 83 | ASSERT(Miniport_); 84 | ASSERT(DataFormat_); 85 | 86 | m_pMiniport = Miniport_; 87 | 88 | m_fCapture = FALSE; 89 | m_fFormat16Bit = FALSE; 90 | m_fFormatStereo = FALSE; 91 | m_ksState = KSSTATE_STOP; 92 | m_ulPin = (ULONG)-1; 93 | 94 | m_pDpc = NULL; 95 | m_pTimer = NULL; 96 | 97 | m_fDmaActive = FALSE; 98 | m_ulDmaPosition = 0; 99 | m_pvDmaBuffer = NULL; 100 | m_ulDmaBufferSize = 0; 101 | m_ulDmaMovementRate = 0; 102 | m_ullDmaTimeStamp = 0; 103 | 104 | 105 | NTSTATUS ntStatus = STATUS_SUCCESS; 106 | PWAVEFORMATEX pWfx; 107 | 108 | pWfx = GetWaveFormatEx(DataFormat_); 109 | if (!pWfx) { 110 | DPF(D_TERSE, ("Invalid DataFormat param in NewStream")); 111 | ntStatus = STATUS_INVALID_PARAMETER; 112 | } 113 | 114 | if (NT_SUCCESS(ntStatus)) { 115 | m_ulPin = Pin_; 116 | m_fCapture = Capture_; 117 | m_fFormatStereo = (pWfx->nChannels == 2); 118 | m_fFormat16Bit = (pWfx->wBitsPerSample == 16); 119 | m_ksState = KSSTATE_STOP; 120 | m_ulDmaPosition = 0; 121 | m_fDmaActive = FALSE; 122 | m_pDpc = NULL; 123 | m_pTimer = NULL; 124 | m_pvDmaBuffer = NULL; 125 | } 126 | 127 | // Allocate DMA buffer for this stream. 128 | if (NT_SUCCESS(ntStatus)) { 129 | ntStatus = AllocateBuffer(m_pMiniport->m_MaxDmaBufferSize, NULL); 130 | } 131 | 132 | // Set sample frequency. Note that m_SampleRateSync access should 133 | // be syncronized. 134 | if (NT_SUCCESS(ntStatus)) { 135 | ntStatus = KeWaitForSingleObject( 136 | &m_pMiniport->m_SampleRateSync, 137 | Executive, 138 | KernelMode, 139 | FALSE, 140 | NULL 141 | ); 142 | if (NT_SUCCESS(ntStatus)) { 143 | m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec; 144 | KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE); 145 | } else { 146 | DPF(D_TERSE, ("[SamplingFrequency Sync failed: %08X]", ntStatus)); 147 | } 148 | } 149 | 150 | if (NT_SUCCESS(ntStatus)) { 151 | ntStatus = SetFormat(DataFormat_); 152 | } 153 | 154 | if (NT_SUCCESS(ntStatus)) { 155 | m_pDpc = (PRKDPC) ExAllocatePoolWithTag( 156 | NonPagedPool, 157 | sizeof(KDPC), 158 | RTSDAUDIO_POOLTAG 159 | ); 160 | if (!m_pDpc) { 161 | DPF(D_TERSE, ("[Could not allocate memory for DPC]")); 162 | ntStatus = STATUS_INSUFFICIENT_RESOURCES; 163 | } 164 | } 165 | 166 | if (NT_SUCCESS(ntStatus)) { 167 | m_pTimer = (PKTIMER) ExAllocatePoolWithTag( 168 | NonPagedPool, 169 | sizeof(KTIMER), 170 | RTSDAUDIO_POOLTAG 171 | ); 172 | if (!m_pTimer) { 173 | DPF(D_TERSE, ("[Could not allocate memory for Timer]")); 174 | ntStatus = STATUS_INSUFFICIENT_RESOURCES; 175 | } 176 | } 177 | 178 | if (NT_SUCCESS(ntStatus)) { 179 | KeInitializeDpc(m_pDpc, TimerNotify, m_pMiniport); 180 | KeInitializeTimerEx(m_pTimer, NotificationTimer); 181 | } 182 | 183 | return ntStatus; 184 | } // Init 185 | 186 | //============================================================================= 187 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::NonDelegatingQueryInterface( 188 | IN REFIID Interface, 189 | OUT PVOID * Object 190 | ) 191 | /* 192 | Routine Description: 193 | QueryInterface 194 | 195 | Arguments: 196 | Interface - GUID 197 | Object - interface pointer to be returned 198 | 199 | Return Value: 200 | NT status code. 201 | */ 202 | { 203 | PAGED_CODE(); 204 | ASSERT(Object); 205 | 206 | if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { 207 | *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this))); 208 | } else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream)) { 209 | *Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this)); 210 | } else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel)) { 211 | *Object = PVOID(PDMACHANNEL(this)); 212 | } else { 213 | *Object = NULL; 214 | } 215 | 216 | if (*Object) { 217 | PUNKNOWN(*Object)->AddRef(); 218 | return STATUS_SUCCESS; 219 | } 220 | 221 | return STATUS_INVALID_PARAMETER; 222 | } // NonDelegatingQueryInterface 223 | #pragma code_seg() 224 | 225 | //============================================================================= 226 | STDMETHODIMP CMiniportWaveCyclicStream::GetPosition( 227 | OUT PULONG Position 228 | ) 229 | /* 230 | Routine Description: 231 | The GetPosition function gets the current position of the DMA read or write 232 | pointer for the stream. Callers of GetPosition should run at 233 | IRQL <= DISPATCH_LEVEL. 234 | 235 | Arguments: 236 | Position - Position of the DMA pointer 237 | 238 | Return Value: 239 | NT status code. 240 | */ 241 | { 242 | if (m_fDmaActive) { 243 | ULONGLONG CurrentTime = KeQueryInterruptTime(); 244 | 245 | ULONG TimeElapsedInMS = ( (ULONG) (CurrentTime - m_ullDmaTimeStamp) ) / 10000; 246 | 247 | ULONG ByteDisplacement = (m_ulDmaMovementRate * TimeElapsedInMS) / 1000; 248 | 249 | m_ulDmaPosition = (m_ulDmaPosition + ByteDisplacement) % m_ulDmaBufferSize; 250 | 251 | *Position = m_ulDmaPosition; 252 | 253 | m_ullDmaTimeStamp = CurrentTime; 254 | } else { 255 | *Position = m_ulDmaPosition; 256 | } 257 | 258 | return STATUS_SUCCESS; 259 | } // GetPosition 260 | 261 | //============================================================================= 262 | STDMETHODIMP CMiniportWaveCyclicStream::NormalizePhysicalPosition( 263 | IN OUT PLONGLONG PhysicalPosition 264 | ) 265 | /* 266 | Routine Description: 267 | Given a physical position based on the actual number of bytes transferred, 268 | NormalizePhysicalPosition converts the position to a time-based value of 269 | 100 nanosecond units. Callers of NormalizePhysicalPosition can run at any IRQL. 270 | 271 | Arguments: 272 | PhysicalPosition - On entry this variable contains the value to convert. 273 | On return it contains the converted value 274 | 275 | Return Value: 276 | NT status code. 277 | */ 278 | { 279 | *PhysicalPosition = ( _100NS_UNITS_PER_SECOND / ( 1 << ( m_fFormatStereo + m_fFormat16Bit ) ) * *PhysicalPosition ) / m_pMiniport->m_SamplingFrequency; 280 | return STATUS_SUCCESS; 281 | } // NormalizePhysicalPosition 282 | 283 | #pragma code_seg("PAGE") 284 | 285 | //============================================================================= 286 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::SetFormat( 287 | IN PKSDATAFORMAT Format 288 | ) 289 | /* 290 | Routine Description: 291 | The SetFormat function changes the format associated with a stream. 292 | Callers of SetFormat should run at IRQL PASSIVE_LEVEL 293 | 294 | Arguments: 295 | Format - Pointer to a KSDATAFORMAT structure which indicates the new format 296 | of the stream. 297 | 298 | Return Value: 299 | NT status code. 300 | */ 301 | { 302 | PAGED_CODE(); 303 | ASSERT(Format); 304 | DPF_ENTER(("[CMiniportWaveCyclicStream::SetFormat]")); 305 | 306 | NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; 307 | PWAVEFORMATEX pWfx; 308 | 309 | if (m_ksState != KSSTATE_RUN) { 310 | //First validate the format 311 | NTSTATUS ntValidFormat; 312 | ntValidFormat = m_pMiniport->ValidateFormat(Format); 313 | if (NT_SUCCESS(ntValidFormat)) { 314 | pWfx = GetWaveFormatEx(Format); 315 | if (pWfx) { 316 | ntStatus = KeWaitForSingleObject( 317 | &m_pMiniport->m_SampleRateSync, 318 | Executive, 319 | KernelMode, 320 | FALSE, 321 | NULL 322 | ); 323 | if (NT_SUCCESS(ntStatus)) { 324 | m_fFormatStereo = (pWfx->nChannels == 2); 325 | m_fFormat16Bit = (pWfx->wBitsPerSample == 16); 326 | m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec; 327 | m_ulDmaMovementRate = pWfx->nAvgBytesPerSec; 328 | 329 | DPF(D_TERSE, ("New Format: %d", pWfx->nSamplesPerSec)); 330 | } 331 | KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE); 332 | } 333 | } 334 | } 335 | 336 | return ntStatus; 337 | } // SetFormat 338 | 339 | //============================================================================= 340 | STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::SetNotificationFreq( 341 | IN ULONG Interval, 342 | OUT PULONG FramingSize 343 | ) 344 | /* 345 | Routine Description: 346 | The SetNotificationFrequency function sets the frequency at which 347 | notification interrupts are generated. Callers of SetNotificationFrequency 348 | should run at IRQL PASSIVE_LEVEL. 349 | 350 | Arguments: 351 | Interval - Value indicating the interval between interrupts, 352 | expressed in milliseconds 353 | FramingSize - Pointer to a ULONG value where the number of bytes equivalent 354 | to Interval milliseconds is returned 355 | 356 | Return Value: 357 | NT status code. 358 | */ 359 | { 360 | PAGED_CODE(); 361 | ASSERT(FramingSize); 362 | DPF_ENTER(("[CMiniportWaveCyclicStream::SetNotificationFreq]")); 363 | 364 | m_pMiniport->m_NotificationInterval = Interval; 365 | 366 | *FramingSize = ( 1 << ( m_fFormatStereo + m_fFormat16Bit ) ) * m_pMiniport->m_SamplingFrequency * Interval / 1000; 367 | 368 | return m_pMiniport->m_NotificationInterval; 369 | } // SetNotificationFreq 370 | 371 | //============================================================================= 372 | STDMETHODIMP CMiniportWaveCyclicStream::SetState( 373 | IN KSSTATE NewState 374 | ) 375 | /* 376 | Routine Description: 377 | The SetState function sets the new state of playback or recording for the 378 | stream. SetState should run at IRQL PASSIVE_LEVEL 379 | 380 | Arguments: 381 | NewState - KSSTATE indicating the new state for the stream. 382 | 383 | Return Value: 384 | NT status code. 385 | */ 386 | { 387 | PAGED_CODE(); 388 | DPF_ENTER(("[CMiniportWaveCyclicStream::SetState]")); 389 | 390 | NTSTATUS ntStatus = STATUS_SUCCESS; 391 | 392 | // The acquire state is not distinguishable from the stop state for our purposes. 393 | if (NewState == KSSTATE_ACQUIRE) { 394 | NewState = KSSTATE_STOP; 395 | } 396 | 397 | if (m_ksState != NewState) { 398 | switch(NewState) { 399 | case KSSTATE_PAUSE: 400 | DPF(D_TERSE, ("KSSTATE_PAUSE")); 401 | m_fDmaActive = FALSE; 402 | break; 403 | 404 | case KSSTATE_RUN: 405 | DPF(D_TERSE, ("KSSTATE_RUN")); 406 | 407 | LARGE_INTEGER delay; 408 | 409 | // Set the timer for DPC. 410 | m_ullDmaTimeStamp = KeQueryInterruptTime(); 411 | m_fDmaActive = TRUE; 412 | delay.HighPart = 0; 413 | delay.LowPart = m_pMiniport->m_NotificationInterval; 414 | 415 | KeSetTimerEx(m_pTimer, delay, m_pMiniport->m_NotificationInterval, m_pDpc); 416 | break; 417 | 418 | case KSSTATE_STOP: 419 | DPF(D_TERSE, ("KSSTATE_STOP")); 420 | 421 | m_fDmaActive = FALSE; 422 | m_ulDmaPosition = 0; 423 | 424 | KeCancelTimer( m_pTimer ); 425 | break; 426 | } 427 | 428 | m_ksState = NewState; 429 | } 430 | 431 | return ntStatus; 432 | } // SetState 433 | 434 | #pragma code_seg() 435 | 436 | //============================================================================= 437 | STDMETHODIMP_(void) CMiniportWaveCyclicStream::Silence( 438 | IN PVOID Buffer, 439 | IN ULONG ByteCount 440 | ) 441 | /* 442 | Routine Description: 443 | The Silence function is used to copy silence samplings to a certain location. 444 | Callers of Silence can run at any IRQL 445 | 446 | Arguments: 447 | Buffer - Pointer to the buffer where the silence samplings should 448 | be deposited. 449 | ByteCount - Size of buffer indicating number of bytes to be deposited. 450 | 451 | Return Value: 452 | NT status code. 453 | */ 454 | { 455 | RtlFillMemory(Buffer, ByteCount, m_fFormat16Bit ? 0 : 0x80); 456 | } // Silence 457 | 458 | #pragma code_seg("PAGE") 459 | //============================================================================= 460 | STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::AllocateBuffer( 461 | IN ULONG BufferSize, 462 | IN PPHYSICAL_ADDRESS PhysicalAddressConstraint OPTIONAL 463 | ) 464 | /* 465 | Routine Description: 466 | The AllocateBuffer function allocates a buffer associated with the DMA object. 467 | The buffer is nonPaged. 468 | Callers of AllocateBuffer should run at a passive IRQL. 469 | 470 | Arguments: 471 | BufferSize - Size in bytes of the buffer to be allocated. 472 | PhysicalAddressConstraint - Optional constraint to place on the physical 473 | address of the buffer. If supplied, only the bits 474 | that are set in the constraint address may vary 475 | from the beginning to the end of the buffer. 476 | For example, if the desired buffer should not 477 | cross a 64k boundary, the physical address 478 | constraint 0x000000000000ffff should be specified 479 | 480 | Return Value: 481 | NT status code. 482 | */ 483 | { 484 | DBGPRINT("[CMiniportWaveCyclicStream::AllocateBuffer]"); 485 | 486 | // Adjust this cap as needed... 487 | ASSERT (BufferSize <= DMA_BUFFER_SIZE); 488 | 489 | NTSTATUS ntStatus = STATUS_SUCCESS; 490 | 491 | m_pvDmaBuffer = (PVOID) ExAllocatePoolWithTag(NonPagedPool, BufferSize, RTSDAUDIO_POOLTAG); 492 | if (!m_pvDmaBuffer) { 493 | ntStatus = STATUS_INSUFFICIENT_RESOURCES; 494 | } else { 495 | m_ulDmaBufferSize = BufferSize; 496 | } 497 | 498 | return ntStatus; 499 | } // AllocateBuffer 500 | #pragma code_seg() 501 | 502 | //============================================================================= 503 | STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::AllocatedBufferSize(void) 504 | /* 505 | Routine Description: 506 | AllocatedBufferSize returns the size of the allocated buffer. 507 | Callers of AllocatedBufferSize can run at any IRQL. 508 | 509 | Arguments: 510 | 511 | Return Value: 512 | ULONG 513 | */ 514 | { 515 | DBGPRINT("[CMiniportWaveCyclicStream::AllocatedBufferSize]"); 516 | return m_ulDmaBufferSize; 517 | } // AllocatedBufferSize 518 | 519 | //============================================================================= 520 | STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::BufferSize(void) 521 | /* 522 | Routine Description: 523 | BufferSize returns the size set by SetBufferSize or the allocated buffer size 524 | if the buffer size has not been set. The DMA object does not actually use 525 | this value internally. This value is maintained by the object to allow its 526 | various clients to communicate the intended size of the buffer. This call 527 | is often used to obtain the map size parameter to the Start member 528 | function. Callers of BufferSize can run at any IRQL 529 | 530 | Arguments: 531 | 532 | Return Value: 533 | ULONG 534 | */ 535 | { 536 | return m_ulDmaBufferSize; 537 | } // BufferSize 538 | 539 | //============================================================================= 540 | STDMETHODIMP_(void) CMiniportWaveCyclicStream::CopyFrom( 541 | IN PVOID Destination, 542 | IN PVOID Source, 543 | IN ULONG ByteCount 544 | ) 545 | /* 546 | Routine Description: 547 | The CopyFrom function copies sample data from the DMA buffer. 548 | Callers of CopyFrom can run at any IRQL 549 | 550 | Arguments: 551 | Destination - Points to the destination buffer. 552 | Source - Points to the source buffer. 553 | ByteCount - Points to the source buffer. 554 | 555 | Return Value: 556 | void 557 | */ 558 | { 559 | ULONG i=0; 560 | ULONG FrameCount = ByteCount/2; //we guess 16-Bit sample rate 561 | //DbgPrint(DBGMESSAGE "CopyFrom - ReadPos=%d",myBufferReadPos); DbgPrint(DBGMESSAGE "CopyFrom - WritePos=%d",myBufferWritePos); 562 | if (!m_pMiniport->myBufferLocked) { 563 | //DbgPrint(DBGMESSAGE "CopyFrom - ByteCount=%d", ByteCount); 564 | InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE); 565 | 566 | ULONG umyBufferSize=(ULONG)m_pMiniport->myBufferSize; 567 | ULONG availableDataCount = (umyBufferSize + m_pMiniport->myBufferWritePos) - m_pMiniport->myBufferReadPos; 568 | if (availableDataCount >= umyBufferSize) 569 | availableDataCount -= umyBufferSize; 570 | if (availableDataCount < FrameCount) { 571 | //if the caller wants to read more data than the buffer size is, 572 | //we fill the rest with silence 573 | //we write the silence at the beginning, 574 | //because in the most cases we need to do this the caller begins to read - so we care 575 | //for a continually stream of sound data 576 | ULONG silenceCount = FrameCount - availableDataCount; 577 | //DbgPrint(DBGMESSAGE "CopyFrom - need more data! NeedCount=%d", silenceCount); 578 | for (i=0; i<=silenceCount ; i++) { 579 | ((PWORD)Destination)[i]=0; 580 | } 581 | } 582 | 583 | //i=0; 584 | while ((i < FrameCount) && //we have more data in the buffer than the caller would like to get 585 | ((m_pMiniport->myBufferWritePos != m_pMiniport->myBufferReadPos+1) && !((m_pMiniport->myBufferWritePos==0) && (m_pMiniport->myBufferReadPos==m_pMiniport->myBufferSize))) ) { 586 | ((PWORD)Destination)[i]=((PWORD)m_pMiniport->myBuffer)[m_pMiniport->myBufferReadPos]; 587 | i++; 588 | m_pMiniport->myBufferReadPos++; 589 | if (m_pMiniport->myBufferReadPos >= m_pMiniport->myBufferSize) //Loop the buffer 590 | m_pMiniport->myBufferReadPos=0; 591 | } 592 | InterlockedExchange(&m_pMiniport->myBufferReading, TRUE); //now the caller reads from the buffer - so we can notify the CopyTo function 593 | 594 | //DbgPrint(DBGMESSAGE "CopyFrom TRUE ByteCount=%d", ByteCount); 595 | InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE); 596 | } else { 597 | //in this case we can't obtain the data from buffer because it is locked 598 | //the best we can do (to satisfy the caller) is to fill the whole buffer with silence 599 | for (i=0; i < FrameCount ; i++) { 600 | ((PWORD)Destination)[i]=0; 601 | } 602 | DBGPRINT("CopyFrom FALSE"); 603 | } 604 | } // CopyFrom 605 | 606 | //============================================================================= 607 | STDMETHODIMP_(void) CMiniportWaveCyclicStream::CopyTo( 608 | IN PVOID Destination, 609 | IN PVOID Source, 610 | IN ULONG ByteCount 611 | ) 612 | /* 613 | Routine Description: 614 | The CopyTo function copies sample data to the DMA buffer. 615 | Callers of CopyTo can run at any IRQL. 616 | 617 | Arguments: 618 | Destination - Points to the destination buffer. 619 | Source - Points to the source buffer 620 | ByteCount - Number of bytes to be copied 621 | 622 | Return Value: 623 | void 624 | */ 625 | 626 | { 627 | ULONG i=0; 628 | ULONG FrameCount = ByteCount/2; //we guess 16-Bit sample rate 629 | if (m_pMiniport->myBuffer==NULL) { 630 | ULONG bufSize=64*1024; //size in bytes 631 | DBGPRINT("Try to allocate buffer"); 632 | m_pMiniport->myBuffer = (PVOID) ExAllocatePoolWithTag(NonPagedPool, bufSize, RTSDAUDIO_POOLTAG); 633 | if (!m_pMiniport->myBuffer) { 634 | DBGPRINT("FAILED to allocate buffer"); 635 | } else { 636 | DBGPRINT("Successfully allocated buffer"); 637 | m_pMiniport->myBufferSize = bufSize/2; //myBufferSize in frames 638 | InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE); 639 | } 640 | } 641 | 642 | if (!m_pMiniport->myBufferLocked) { 643 | //DbgPrint(DBGMESSAGE "Fill Buffer ByteCount=%d", ByteCount); 644 | InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE); 645 | 646 | i=0; 647 | while (i < FrameCount) {//while data is available 648 | //test wether we arrived at the read-pos 649 | //if (! ((myBufferWritePos+1 != myBufferReadPos) && !((myBufferReadPos==0) && (myBufferWritePos==myBufferSize)))) { 650 | if ((m_pMiniport->myBufferWritePos+1==m_pMiniport->myBufferReadPos) || (m_pMiniport->myBufferReadPos==0 && m_pMiniport->myBufferWritePos==m_pMiniport->myBufferSize)){ 651 | //DbgPrint(DBGMESSAGE "CopyTo - there is no space for new data! NeedCount=%d", FrameCount-i); 652 | if (m_pMiniport->myBufferReadPos==m_pMiniport->myBufferSize) 653 | m_pMiniport->myBufferReadPos=0; 654 | else 655 | m_pMiniport->myBufferReadPos++; 656 | //break; //we have to break - because there is no space for the rest data 657 | } 658 | 659 | ((PWORD)m_pMiniport->myBuffer)[m_pMiniport->myBufferWritePos]=((PWORD)Source)[i]; 660 | i++; 661 | m_pMiniport->myBufferWritePos++; 662 | if (m_pMiniport->myBufferWritePos >= m_pMiniport->myBufferSize) //Loop the buffer 663 | m_pMiniport->myBufferWritePos=0; 664 | } 665 | //DbgPrint(DBGMESSAGE "CopyTo - ReadPos=%d",myBufferReadPos); DbgPrint(DBGMESSAGE "CopyTo - WritePos=%d",myBufferWritePos); 666 | InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE); 667 | //DbgPrint(DBGMESSAGE "(2) CopyTo - ReadPos=%d",myBufferReadPos); DbgPrint(DBGMESSAGE "(2) CopyTo - WritePos=%d",myBufferWritePos); 668 | //DbgPrint(DBGMESSAGE "(2) CopyTo - Locked=%d",myBufferLocked); 669 | } 670 | } // CopyTo 671 | 672 | //============================================================================= 673 | #pragma code_seg("PAGE") 674 | STDMETHODIMP_(void) CMiniportWaveCyclicStream::FreeBuffer(void) 675 | /* 676 | Routine Description: 677 | The FreeBuffer function frees the buffer allocated by AllocateBuffer. Because 678 | the buffer is automatically freed when the DMA object is deleted, this 679 | function is not normally used. Callers of FreeBuffer should run at 680 | IRQL PASSIVE_LEVEL. 681 | 682 | Arguments: 683 | 684 | Return Value: 685 | void 686 | */ 687 | { 688 | DBGPRINT("[CMiniportWaveCyclicStream::FreeBuffer]"); 689 | 690 | if ( m_pvDmaBuffer ) { 691 | ExFreePool( m_pvDmaBuffer ); 692 | m_ulDmaBufferSize = 0; 693 | m_pvDmaBuffer = NULL; 694 | } 695 | if (m_pMiniport->myBuffer) { 696 | if (!m_pMiniport->myBufferLocked) 697 | { 698 | InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE); //first lock the buffer, so nobody would try to read from myBuffer 699 | ExFreePool(m_pMiniport->myBuffer); 700 | m_pMiniport->myBufferSize = 0; 701 | m_pMiniport->myBuffer = NULL; 702 | } 703 | } 704 | } // FreeBuffer 705 | #pragma code_seg() 706 | 707 | //============================================================================= 708 | STDMETHODIMP_(PADAPTER_OBJECT) CMiniportWaveCyclicStream::GetAdapterObject(void) 709 | /* 710 | Routine Description: 711 | The GetAdapterObject function returns the DMA object's internal adapter 712 | object. Callers of GetAdapterObject can run at any IRQL. 713 | 714 | Arguments: 715 | 716 | Return Value: 717 | PADAPTER_OBJECT - The return value is the object's internal adapter object. 718 | */ 719 | { 720 | DBGPRINT("[CMiniportWaveCyclicStream::GetAdapterObject]"); 721 | 722 | // MSVAD does not have need a physical DMA channel. Therefore it 723 | // does not have physical DMA structure. 724 | 725 | return NULL; 726 | } // GetAdapterObject 727 | 728 | //============================================================================= 729 | STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::MaximumBufferSize(void) 730 | /* 731 | Routine Description: 732 | 733 | Arguments: 734 | 735 | Return Value: 736 | NT status code. 737 | */ 738 | { 739 | DBGPRINT("[CMiniportWaveCyclicStream::MaximumBufferSize]"); 740 | return m_pMiniport->m_MaxDmaBufferSize; 741 | } // MaximumBufferSize 742 | 743 | //============================================================================= 744 | STDMETHODIMP_(PHYSICAL_ADDRESS) CMiniportWaveCyclicStream::PhysicalAddress(void) 745 | /* 746 | Routine Description: 747 | MaximumBufferSize returns the size in bytes of the largest buffer this DMA 748 | object is configured to support. Callers of MaximumBufferSize can run 749 | at any IRQL 750 | 751 | Arguments: 752 | 753 | Return Value: 754 | PHYSICAL_ADDRESS - The return value is the size in bytes of the largest 755 | buffer this DMA object is configured to support. 756 | */ 757 | { 758 | DBGPRINT("[CMiniportWaveCyclicStream::PhysicalAddress]"); 759 | 760 | PHYSICAL_ADDRESS pAddress; 761 | pAddress.QuadPart = (LONGLONG) m_pvDmaBuffer; 762 | return pAddress; 763 | } // PhysicalAddress 764 | 765 | //============================================================================= 766 | STDMETHODIMP_(void) CMiniportWaveCyclicStream::SetBufferSize( 767 | IN ULONG BufferSize 768 | ) 769 | /* 770 | Routine Description: 771 | The SetBufferSize function sets the current buffer size. This value is set to 772 | the allocated buffer size when AllocateBuffer is called. The DMA object does 773 | not actually use this value internally. This value is maintained by the object 774 | to allow its various clients to communicate the intended size of the buffer. 775 | Callers of SetBufferSize can run at any IRQL. 776 | 777 | Arguments: 778 | BufferSize - Current size in bytes. 779 | 780 | Return Value: 781 | void 782 | */ 783 | { 784 | DBGPRINT("[CMiniportWaveCyclicStream::SetBufferSize]"); 785 | 786 | if ( BufferSize <= m_ulDmaBufferSize ) { 787 | m_ulDmaBufferSize = BufferSize; 788 | } else { 789 | DPF(D_ERROR, ("Tried to enlarge dma buffer size")); 790 | } 791 | } // SetBufferSize 792 | 793 | //============================================================================= 794 | STDMETHODIMP_(PVOID) CMiniportWaveCyclicStream::SystemAddress(void) 795 | /* 796 | Routine Description: 797 | The SystemAddress function returns the virtual system address of the 798 | allocated buffer. Callers of SystemAddress can run at any IRQL. 799 | 800 | Arguments: 801 | 802 | Return Value: 803 | PVOID - The return value is the virtual system address of the 804 | allocated buffer. 805 | */ 806 | { 807 | return m_pvDmaBuffer; 808 | } // SystemAddress 809 | 810 | //============================================================================= 811 | STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::TransferCount(void) 812 | /* 813 | Routine Description: 814 | The TransferCount function returns the size in bytes of the buffer currently 815 | being transferred by a slave DMA object. Callers of TransferCount can run 816 | at any IRQL. 817 | 818 | Arguments: 819 | 820 | Return Value: 821 | ULONG - The return value is the size in bytes of the buffer currently 822 | being transferred. 823 | */ 824 | { 825 | DBGPRINT("[CMiniportWaveCyclicStream::TransferCount]"); 826 | return m_ulDmaBufferSize; 827 | } 828 | 829 | //============================================================================= 830 | /*long CMiniportWaveCyclicStream::zoh_process (PWORD source, PWORD destination, long input_frames, long output_frames, int channels) 831 | { 832 | KFLOATING_SAVE saveData; 833 | NTSTATUS status; 834 | status = KeSaveFloatingPointState(&saveData); 835 | 836 | if(NT_SUCCESS(status)) { 837 | long in_count, out_count, in_used, out_gen; 838 | double src_ratio, input_index; 839 | int ch; 840 | 841 | in_count = input_frames * channels; 842 | out_count = output_frames * channels; 843 | in_used = out_gen = 0; 844 | 845 | src_ratio = m_pMiniport->m_SamplingFrequency / 44100; 846 | input_index = 0; // TODO: Unbekannt 847 | 848 | in_used += channels * (long)(floor(input_index)); 849 | input_index -= floor(input_index); 850 | 851 | // Main processing loop. 852 | while (out_gen < out_count && in_used + channels * input_index <= in_count) { 853 | for (ch = 0 ; ch < channels ; ch++) { 854 | destination[out_gen] = source[in_used - channels + ch]; 855 | out_gen ++ ; 856 | } ; 857 | 858 | // Figure out the next index. 859 | input_index += 1.0 / src_ratio ; 860 | 861 | in_used += channels * (long)(floor(input_index)) ; 862 | input_index -= floor(input_index) ; 863 | } ; 864 | 865 | if (in_used > in_count) { 866 | input_index += in_used - in_count ; 867 | in_used = in_count ; 868 | } ; 869 | KeRestoreFloatingPointState(&saveData); 870 | return out_gen; 871 | } else { 872 | return 0; 873 | } 874 | }*/ 875 | -------------------------------------------------------------------------------- /rtsdwavestream.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | rtsdwave.h 4 | 5 | Abstract: 6 | Definition of wavecyclic miniport class. 7 | */ 8 | 9 | #ifndef __RTSDWAVESTREAM_H_ 10 | #define __RTSDWAVESTREAM_H_ 11 | 12 | #include "rtsdwave.h" 13 | 14 | /////////////////////////////////////////////////////////////////////////////// 15 | // CMiniportWaveCyclicStream 16 | // 17 | 18 | class CMiniportWaveCyclicStream : public IMiniportWaveCyclicStream, public IDmaChannel, public CUnknown { 19 | protected: 20 | PCMiniportWaveCyclic m_pMiniport; // Miniport that created us 21 | BOOLEAN m_fCapture; // Capture or render. 22 | BOOLEAN m_fFormat16Bit; // 16- or 8-bit samples. 23 | BOOLEAN m_fFormatStereo; // Two or one channel. 24 | KSSTATE m_ksState; // Stop, pause, run. 25 | ULONG m_ulPin; // Pin Id. 26 | 27 | PRKDPC m_pDpc; // Deferred procedure call object 28 | PKTIMER m_pTimer; // Timer object 29 | 30 | BOOLEAN m_fDmaActive; // Dma currently active? 31 | ULONG m_ulDmaPosition; // Position in Dma 32 | PVOID m_pvDmaBuffer; // Dma buffer pointer 33 | ULONG m_ulDmaBufferSize; // Size of dma buffer 34 | ULONG m_ulDmaMovementRate;// Rate of transfer specific to system 35 | ULONGLONG m_ullDmaTimeStamp; // Dma time elasped 36 | 37 | public: 38 | DECLARE_STD_UNKNOWN(); 39 | DEFINE_STD_CONSTRUCTOR(CMiniportWaveCyclicStream); 40 | ~CMiniportWaveCyclicStream(); 41 | 42 | IMP_IMiniportWaveCyclicStream; 43 | IMP_IDmaChannel; 44 | 45 | NTSTATUS Init 46 | ( 47 | IN PCMiniportWaveCyclic Miniport, 48 | IN ULONG Channel, 49 | IN BOOLEAN Capture, 50 | IN PKSDATAFORMAT DataFormat 51 | ); 52 | 53 | // Friends 54 | friend class CMiniportWaveCyclic; 55 | }; 56 | typedef CMiniportWaveCyclicStream *PCMiniportWaveCyclicStream; 57 | 58 | #endif 59 | 60 | -------------------------------------------------------------------------------- /sources: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved. 3 | 4 | TARGETTYPE=DRIVER 5 | TARGETPATH=obj 6 | TARGETNAME=rtsdaudio 7 | DRIVERTYPE=WDM 8 | 9 | TARGETLIBS= $(DDK_LIB_PATH)\portcls.lib\ 10 | $(DDK_LIB_PATH)\stdunk.lib 11 | 12 | INCLUDES= $(DDK_INC_PATH); 13 | 14 | MSC_WARNING_LEVEL=-W3 -WX 15 | 16 | C_DEFINES= $(C_DEFINES) -D_WIN32 -DUNICODE -D_UNICODE -DPC_IMPLEMENTATION 17 | 18 | # 19 | # Different levels of debug printage. First is nothing but 20 | # catastrophic errors, last is everything under the sun. 21 | # 22 | #C_DEFINES= $(C_DEFINES) -DDEBUG_LEVEL=DEBUGLVL_ERROR 23 | C_DEFINES= $(C_DEFINES) -DDEBUG_LEVEL=DEBUGLVL_TERSE 24 | #C_DEFINES= $(C_DEFINES) -DDEBUG_LEVEL=DEBUGLVL_VERBOSE 25 | #C_DEFINES= $(C_DEFINES) -DDEBUG_LEVEL=DEBUGLVL_BLAB 26 | 27 | #LINKER_FLAGS=-map 28 | 29 | SOURCES=\ 30 | adapter.cpp \ 31 | rtsdwavestream.cpp \ 32 | common.cpp \ 33 | hw.cpp \ 34 | kshelper.cpp \ 35 | rtsdtopo.cpp \ 36 | rtsdwave.cpp \ 37 | rtsdaudio.rc 38 | 39 | -------------------------------------------------------------------------------- /toptable.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | toptable.h 4 | 5 | Abstract: 6 | Declaration of topology tables. 7 | */ 8 | 9 | #ifndef __TOPTABLE_H_ 10 | #define __TOPTABLE_H_ 11 | 12 | 13 | //============================================================================= 14 | static KSDATARANGE PinDataRangesBridge[] = { 15 | { 16 | sizeof(KSDATARANGE), 17 | 0, 18 | 0, 19 | 0, 20 | STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), 21 | STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), 22 | STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) 23 | } 24 | }; 25 | 26 | //============================================================================= 27 | static PKSDATARANGE PinDataRangePointersBridge[] = { 28 | &PinDataRangesBridge[0] 29 | }; 30 | 31 | //============================================================================= 32 | static PCPIN_DESCRIPTOR MiniportPins[] = { 33 | // KSPIN_TOPO_WAVEOUT_SOURCE 34 | { 35 | 0, 36 | 0, 37 | 0, // InstanceCount 38 | NULL, // AutomationTable 39 | { // KsPinDescriptor 40 | 0, // InterfacesCount 41 | NULL, // Interfaces 42 | 0, // MediumsCount 43 | NULL, // Mediums 44 | SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 45 | PinDataRangePointersBridge, // DataRanges 46 | KSPIN_DATAFLOW_IN, // DataFlow 47 | KSPIN_COMMUNICATION_NONE, // Communication 48 | &KSCATEGORY_AUDIO, // Category 49 | NULL, // Name 50 | 0 // Reserved 51 | } 52 | }, 53 | 54 | // KSPIN_TOPO_SYNTHOUT_SOURCE 55 | { 56 | 0, 57 | 0, 58 | 0, // InstanceCount 59 | NULL, // AutomationTable 60 | { // KsPinDescriptor 61 | 0, // InterfacesCount 62 | NULL, // Interfaces 63 | 0, // MediumsCount 64 | NULL, // Mediums 65 | SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 66 | PinDataRangePointersBridge, // DataRanges 67 | KSPIN_DATAFLOW_IN, // DataFlow 68 | KSPIN_COMMUNICATION_NONE, // Communication 69 | &KSNODETYPE_SYNTHESIZER, // Category 70 | &KSAUDFNAME_MIDI, // Name 71 | 0 // Reserved 72 | } 73 | }, 74 | 75 | // KSPIN_TOPO_SYNTHIN_SOURCE 76 | { 77 | 0, 78 | 0, 79 | 0, // InstanceCount 80 | NULL, // AutomationTable 81 | { // KsPinDescriptor 82 | 0, // InterfacesCount 83 | NULL, // Interfaces 84 | 0, // MediumsCount 85 | NULL, // Mediums 86 | SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 87 | PinDataRangePointersBridge, // DataRanges 88 | KSPIN_DATAFLOW_IN, // DataFlow 89 | KSPIN_COMMUNICATION_NONE, // Communication 90 | &KSNODETYPE_SYNTHESIZER, // Category 91 | &KSAUDFNAME_MIDI, // Name 92 | 0 // Reserved 93 | } 94 | }, 95 | 96 | // KSPIN_TOPO_MIC_SOURCE 97 | { 98 | 0, 99 | 0, 100 | 0, // InstanceCount 101 | NULL, // AutomationTable 102 | { // KsPinDescriptor 103 | 0, // InterfacesCount 104 | NULL, // Interfaces 105 | 0, // MediumsCount 106 | NULL, // Mediums 107 | SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 108 | PinDataRangePointersBridge, // DataRanges 109 | KSPIN_DATAFLOW_IN, // DataFlow 110 | KSPIN_COMMUNICATION_NONE, // Communication 111 | &KSNODETYPE_MICROPHONE, // Category 112 | NULL, // Name 113 | 0 // Reserved 114 | } 115 | }, 116 | 117 | // KSPIN_TOPO_LINEOUT_DEST 118 | { 119 | 0, 120 | 0, 121 | 0, // InstanceCount 122 | NULL, // AutomationTable 123 | { // KsPinDescriptor 124 | 0, // InterfacesCount 125 | NULL, // Interfaces 126 | 0, // MediumsCount 127 | NULL, // Mediums 128 | SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 129 | PinDataRangePointersBridge, // DataRanges 130 | KSPIN_DATAFLOW_OUT, // DataFlow 131 | KSPIN_COMMUNICATION_NONE, // Communication 132 | &KSNODETYPE_SPEAKER, // Category 133 | &KSAUDFNAME_VOLUME_CONTROL, // Name (this name shows up as 134 | // the playback panel name in SoundVol) 135 | 0 // Reserved 136 | } 137 | }, 138 | 139 | // KSPIN_TOPO_WAVEIN_DEST 140 | { 141 | 0, 142 | 0, 143 | 0, // InstanceCount 144 | NULL, // AutomationTable 145 | { // KsPinDescriptor 146 | 0, // InterfacesCount 147 | NULL, // Interfaces 148 | 0, // MediumsCount 149 | NULL, // Mediums 150 | SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 151 | PinDataRangePointersBridge, // DataRanges 152 | KSPIN_DATAFLOW_OUT, // DataFlow 153 | KSPIN_COMMUNICATION_NONE, // Communication 154 | &KSCATEGORY_AUDIO, // Category 155 | NULL, // Name 156 | 0 // Reserved 157 | } 158 | } 159 | }; 160 | 161 | //============================================================================= 162 | static PCPROPERTY_ITEM PropertiesVolume[] = { 163 | { 164 | &KSPROPSETID_Audio, 165 | KSPROPERTY_AUDIO_VOLUMELEVEL, 166 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT, 167 | PropertyHandler_Topology 168 | }, 169 | { 170 | &KSPROPSETID_Audio, 171 | KSPROPERTY_AUDIO_CPU_RESOURCES, 172 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 173 | PropertyHandler_Topology 174 | } 175 | }; 176 | 177 | DEFINE_PCAUTOMATION_TABLE_PROP(AutomationVolume, PropertiesVolume); 178 | 179 | //============================================================================= 180 | static PCPROPERTY_ITEM PropertiesMute[] = { 181 | { 182 | &KSPROPSETID_Audio, 183 | KSPROPERTY_AUDIO_MUTE, 184 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT, 185 | PropertyHandler_Topology 186 | }, 187 | { 188 | &KSPROPSETID_Audio, 189 | KSPROPERTY_AUDIO_CPU_RESOURCES, 190 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 191 | PropertyHandler_Topology 192 | } 193 | }; 194 | 195 | DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMute, PropertiesMute); 196 | 197 | //============================================================================= 198 | static PCPROPERTY_ITEM PropertiesMux[] = { 199 | { 200 | &KSPROPSETID_Audio, 201 | KSPROPERTY_AUDIO_MUX_SOURCE, 202 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT, 203 | PropertyHandler_Topology 204 | }, 205 | { 206 | &KSPROPSETID_Audio, 207 | KSPROPERTY_AUDIO_CPU_RESOURCES, 208 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 209 | PropertyHandler_Topology 210 | } 211 | }; 212 | 213 | DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMux, PropertiesMux); 214 | 215 | //============================================================================= 216 | static PCNODE_DESCRIPTOR TopologyNodes[] = { 217 | // KSNODE_TOPO_WAVEOUT_VOLUME 218 | { 219 | 0, // Flags 220 | &AutomationVolume, // AutomationTable 221 | &KSNODETYPE_VOLUME, // Type 222 | &KSAUDFNAME_WAVE_VOLUME // Name 223 | }, 224 | 225 | // KSNODE_TOPO_WAVEOUT_MUTE 226 | { 227 | 0, // Flags 228 | &AutomationMute, // AutomationTable 229 | &KSNODETYPE_MUTE, // Type 230 | &KSAUDFNAME_WAVE_MUTE // Name 231 | }, 232 | 233 | // KSNODE_TOPO_SYNTHOUT_VOLUME 234 | { 235 | 0, // Flags 236 | &AutomationVolume, // AutomationTable 237 | &KSNODETYPE_VOLUME, // Type 238 | &KSAUDFNAME_MIDI_VOLUME // Name 239 | }, 240 | 241 | // KSNODE_TOPO_SYNTHOUT_MUTE 242 | { 243 | 0, // Flags 244 | &AutomationMute, // AutomationTable 245 | &KSNODETYPE_MUTE, // Type 246 | &KSAUDFNAME_MIDI_MUTE // Name 247 | }, 248 | 249 | // KSNODE_TOPO_MIC_VOLUME 250 | { 251 | 0, // Flags 252 | &AutomationVolume, // AutomationTable 253 | &KSNODETYPE_VOLUME, // Type 254 | &KSAUDFNAME_MIC_VOLUME // Name 255 | }, 256 | 257 | // KSNODE_TOPO_SYNTHIN_VOLUME 258 | { 259 | 0, // Flags 260 | &AutomationVolume, // AutomationTable 261 | &KSNODETYPE_VOLUME, // Type 262 | &KSAUDFNAME_MIDI_VOLUME // Name 263 | }, 264 | 265 | // KSNODE_TOPO_LINEOUT_MIX 266 | { 267 | 0, // Flags 268 | NULL, // AutomationTable 269 | &KSNODETYPE_SUM, // Type 270 | NULL // Name 271 | }, 272 | 273 | // KSNODE_TOPO_LINEOUT_VOLUME 274 | { 275 | 0, // Flags 276 | &AutomationVolume, // AutomationTable 277 | &KSNODETYPE_VOLUME, // Type 278 | &KSAUDFNAME_MASTER_VOLUME // Name 279 | }, 280 | 281 | // KSNODE_TOPO_WAVEIN_MUX 282 | { 283 | 0, // Flags 284 | &AutomationMux, // AutomationTable 285 | &KSNODETYPE_MUX, // Type 286 | &KSAUDFNAME_RECORDING_SOURCE // Name 287 | }, 288 | }; 289 | 290 | //============================================================================= 291 | static PCCONNECTION_DESCRIPTOR MiniportConnections[] = { 292 | // FromNode, FromPin, ToNode, ToPin 293 | { PCFILTER_NODE, KSPIN_TOPO_WAVEOUT_SOURCE, KSNODE_TOPO_WAVEOUT_VOLUME, 1 }, 294 | { KSNODE_TOPO_WAVEOUT_VOLUME, 0, KSNODE_TOPO_WAVEOUT_MUTE, 1 }, 295 | { KSNODE_TOPO_WAVEOUT_MUTE, 0, KSNODE_TOPO_LINEOUT_MIX, 1 }, 296 | 297 | { PCFILTER_NODE, KSPIN_TOPO_SYNTHOUT_SOURCE, KSNODE_TOPO_SYNTHOUT_VOLUME, 1 }, 298 | { KSNODE_TOPO_SYNTHOUT_VOLUME, 0, KSNODE_TOPO_SYNTHOUT_MUTE, 1 }, 299 | { KSNODE_TOPO_SYNTHOUT_MUTE, 0, KSNODE_TOPO_LINEOUT_MIX, 1 }, 300 | 301 | { PCFILTER_NODE, KSPIN_TOPO_SYNTHIN_SOURCE, KSNODE_TOPO_SYNTHIN_VOLUME, 1 }, 302 | { KSNODE_TOPO_SYNTHIN_VOLUME, 0, KSNODE_TOPO_WAVEIN_MUX, 4 }, 303 | 304 | { PCFILTER_NODE, KSPIN_TOPO_MIC_SOURCE, KSNODE_TOPO_MIC_VOLUME, 1 }, 305 | { KSNODE_TOPO_MIC_VOLUME, 0, KSNODE_TOPO_WAVEIN_MUX, 4 }, 306 | 307 | { KSNODE_TOPO_LINEOUT_MIX, 0, KSNODE_TOPO_LINEOUT_VOLUME, 1 }, 308 | { KSNODE_TOPO_LINEOUT_VOLUME, 0, PCFILTER_NODE, KSPIN_TOPO_LINEOUT_DEST }, 309 | 310 | { KSNODE_TOPO_WAVEIN_MUX, 0, PCFILTER_NODE, KSPIN_TOPO_WAVEIN_DEST } 311 | }; 312 | 313 | //============================================================================= 314 | static PCFILTER_DESCRIPTOR MiniportFilterDescriptor = { 315 | 0, // Version 316 | NULL, // AutomationTable 317 | sizeof(PCPIN_DESCRIPTOR), // PinSize 318 | SIZEOF_ARRAY(MiniportPins), // PinCount 319 | MiniportPins, // Pins 320 | sizeof(PCNODE_DESCRIPTOR), // NodeSize 321 | SIZEOF_ARRAY(TopologyNodes), // NodeCount 322 | TopologyNodes, // Nodes 323 | SIZEOF_ARRAY(MiniportConnections), // ConnectionCount 324 | MiniportConnections, // Connections 325 | 0, // CategoryCount 326 | NULL // Categories 327 | }; 328 | 329 | #endif 330 | 331 | -------------------------------------------------------------------------------- /wavtable.h: -------------------------------------------------------------------------------- 1 | /* 2 | Module Name: 3 | wavtable.h 4 | 5 | Abstract: 6 | Declaration of wave miniport tables. 7 | */ 8 | 9 | #ifndef __WAVTABLE_H_ 10 | #define __WAVTABLE_H_ 11 | 12 | //============================================================================= 13 | static KSDATARANGE_AUDIO PinDataRangesStream[] = { 14 | { 15 | { 16 | sizeof(KSDATARANGE_AUDIO), 17 | 0, 18 | 0, 19 | 0, 20 | STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), 21 | STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), 22 | STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) 23 | }, 24 | MAX_CHANNELS_PCM, 25 | MIN_BITS_PER_SAMPLE_PCM, 26 | MAX_BITS_PER_SAMPLE_PCM, 27 | MIN_SAMPLE_RATE, 28 | MAX_SAMPLE_RATE 29 | }, 30 | }; 31 | 32 | static PKSDATARANGE PinDataRangePointersStream[] = { 33 | PKSDATARANGE(&PinDataRangesStream[0]) 34 | }; 35 | 36 | //============================================================================= 37 | static KSDATARANGE PinDataRangesBridge[] = { 38 | { 39 | sizeof(KSDATARANGE), 40 | 0, 41 | 0, 42 | 0, 43 | STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), 44 | STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), 45 | STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) 46 | } 47 | }; 48 | 49 | static PKSDATARANGE PinDataRangePointersBridge[] = { 50 | &PinDataRangesBridge[0] 51 | }; 52 | 53 | //============================================================================= 54 | static PCPIN_DESCRIPTOR MiniportPins[] = { 55 | // Wave In Streaming Pin (Capture) KSPIN_WAVE_CAPTURE_SINK 56 | { 57 | MAX_OUTPUT_STREAMS, 58 | MAX_OUTPUT_STREAMS, 59 | 0, 60 | NULL, 61 | { 62 | 0, 63 | NULL, 64 | 0, 65 | NULL, 66 | SIZEOF_ARRAY(PinDataRangePointersStream), 67 | PinDataRangePointersStream, 68 | KSPIN_DATAFLOW_OUT, 69 | KSPIN_COMMUNICATION_SINK, 70 | &KSCATEGORY_AUDIO, 71 | &KSAUDFNAME_RECORDING_CONTROL, 72 | 0 73 | } 74 | }, 75 | 76 | // Wave In Bridge Pin (Capture - From Topology) KSPIN_WAVE_CAPTURE_SOURCE 77 | { 78 | 0, 79 | 0, 80 | 0, 81 | NULL, 82 | { 83 | 0, 84 | NULL, 85 | 0, 86 | NULL, 87 | SIZEOF_ARRAY(PinDataRangePointersBridge), 88 | PinDataRangePointersBridge, 89 | KSPIN_DATAFLOW_IN, 90 | KSPIN_COMMUNICATION_NONE, 91 | &KSCATEGORY_AUDIO, 92 | NULL, 93 | 0 94 | } 95 | }, 96 | 97 | // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_RENDER_SINK 98 | { 99 | MAX_INPUT_STREAMS, 100 | MAX_INPUT_STREAMS, 101 | 0, 102 | NULL, 103 | { 104 | 0, 105 | NULL, 106 | 0, 107 | NULL, 108 | SIZEOF_ARRAY(PinDataRangePointersStream), 109 | PinDataRangePointersStream, 110 | KSPIN_DATAFLOW_IN, 111 | KSPIN_COMMUNICATION_SINK, 112 | &KSCATEGORY_AUDIO, 113 | &KSAUDFNAME_VOLUME_CONTROL, 114 | 0 115 | } 116 | }, 117 | 118 | // Wave Out Bridge Pin (Renderer) KSPIN_WAVE_RENDER_SOURCE 119 | { 120 | 0, 121 | 0, 122 | 0, 123 | NULL, 124 | { 125 | 0, 126 | NULL, 127 | 0, 128 | NULL, 129 | SIZEOF_ARRAY(PinDataRangePointersBridge), 130 | PinDataRangePointersBridge, 131 | KSPIN_DATAFLOW_OUT, 132 | KSPIN_COMMUNICATION_NONE, 133 | &KSCATEGORY_AUDIO, 134 | NULL, 135 | 0 136 | } 137 | }, 138 | }; 139 | 140 | //============================================================================= 141 | static PCNODE_DESCRIPTOR MiniportNodes[] = { 142 | // KSNODE_WAVE_ADC 143 | { 144 | 0, // Flags 145 | NULL, // AutomationTable 146 | &KSNODETYPE_ADC, // Type 147 | NULL // Name 148 | }, 149 | // KSNODE_WAVE_DAC 150 | { 151 | 0, // Flags 152 | NULL, // AutomationTable 153 | &KSNODETYPE_DAC, // Type 154 | NULL // Name 155 | } 156 | }; 157 | 158 | //============================================================================= 159 | static PCCONNECTION_DESCRIPTOR MiniportConnections[] = { 160 | { PCFILTER_NODE, KSPIN_WAVE_CAPTURE_SOURCE, KSNODE_WAVE_ADC, 1 }, 161 | { KSNODE_WAVE_ADC, 0, PCFILTER_NODE, KSPIN_WAVE_CAPTURE_SINK }, 162 | 163 | { PCFILTER_NODE, KSPIN_WAVE_RENDER_SINK, KSNODE_WAVE_DAC, 1 }, 164 | { KSNODE_WAVE_DAC, 0, PCFILTER_NODE, KSPIN_WAVE_RENDER_SOURCE }, 165 | }; 166 | 167 | //============================================================================= 168 | static PCPROPERTY_ITEM PropertiesWaveFilter[] = { 169 | { 170 | &KSPROPSETID_General, 171 | KSPROPERTY_GENERAL_COMPONENTID, 172 | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 173 | PropertyHandler_WaveFilter 174 | }, 175 | }; 176 | 177 | DEFINE_PCAUTOMATION_TABLE_PROP(AutomationWaveFilter, PropertiesWaveFilter); 178 | 179 | //============================================================================= 180 | static PCFILTER_DESCRIPTOR MiniportFilterDescriptor = { 181 | 0, // Version 182 | &AutomationWaveFilter, // AutomationTable 183 | sizeof(PCPIN_DESCRIPTOR), // PinSize 184 | SIZEOF_ARRAY(MiniportPins), // PinCount 185 | MiniportPins, // Pins 186 | sizeof(PCNODE_DESCRIPTOR), // NodeSize 187 | SIZEOF_ARRAY(MiniportNodes), // NodeCount 188 | MiniportNodes, // Nodes 189 | SIZEOF_ARRAY(MiniportConnections), // ConnectionCount 190 | MiniportConnections, // Connections 191 | 0, // CategoryCount 192 | NULL // Categories - use defaults (audio, render, capture) 193 | }; 194 | 195 | #endif 196 | --------------------------------------------------------------------------------