📄 devices.c
字号:
return result;
}
}
/*
GetDeviceCount
Pretty straightforward - pass the device type (WDMAUD_WAVE_IN, ...) and
a topology device (NT object path) to obtain the number of devices
present in that topology of that particular type.
The topology path is supplied to us by winmm.
*/
DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path)
{
PWDMAUD_DEVICE_INFO device_data;
int device_count = 0;
DPRINT("Topology path %S\n", topology_path);
device_data = CreateDeviceData(device_type, 0, topology_path, FALSE);
if (! device_data)
{
DPRINT1("Couldn't allocate device data\n");
goto cleanup;
}
DPRINT("Getting num devs\n");
device_data->with_critical_section = FALSE;
if ( CallKernelDevice(device_data,
IOCTL_WDMAUD_GET_DEVICE_COUNT,
0,
0) != MMSYSERR_NOERROR )
{
DPRINT1("Failed\n");
goto cleanup;
}
device_count = device_data->id;
DPRINT("There are %d devs\n", device_count);
cleanup :
{
if ( device_data )
DeleteDeviceData(device_data);
return device_count;
}
}
/*
GetDeviceCapabilities
This uses a different structure to the traditional documentation, because
we handle plug and play devices.
Much sleep was lost over implementing this. I got the ID and type
parameters the wrong way round!
*/
MMRESULT GetDeviceCapabilities(
CHAR device_type,
DWORD device_id,
WCHAR* device_path,
LPMDEVICECAPSEX caps
)
{
PWDMAUD_DEVICE_INFO device = NULL;
MMRESULT result = MMSYSERR_ERROR;
DPRINT("Device path %S\n", device_path);
/* Is this right? */
if (caps->cbSize == 0)
{
DPRINT1("We appear to have been given an invalid parameter\n");
return MMSYSERR_INVALPARAM;
}
DPRINT("Going to have to query the kernel-mode part\n");
device = CreateDeviceData(device_type, device_id, device_path, FALSE);
if ( ! device )
{
DPRINT("Unable to allocate device data memory\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
/* These are not needed as they're already initialized */
ASSERT( device_id == device->id );
ASSERT( ! device->with_critical_section );
*(LPWORD)caps->pCaps = (WORD) 0x43;
DPRINT("Calling kernel device\n");
result = CallKernelDevice(device,
IOCTL_WDMAUD_GET_CAPABILITIES,
(DWORD)caps->cbSize,
(DWORD)caps->pCaps);
if ( result != MMSYSERR_NOERROR )
{
DPRINT("IoControl failed\n");
goto cleanup;
}
/* Return code will already be MMSYSERR_NOERROR by now */
cleanup :
{
if ( device )
DeleteDeviceData(device);
return result;
}
}
/*
OpenDeviceViaKernel
Internal function to rub the kernel mode part of wdmaud the right way
so it opens a device on our behalf.
*/
MMRESULT
OpenDeviceViaKernel(
PWDMAUD_DEVICE_INFO device,
LPWAVEFORMATEX format
)
{
DWORD format_struct_len = 0;
DPRINT("Opening device via kernel\n");
if ( format->wFormatTag == 1 ) /* FIXME */
{
/* Standard PCM format */
DWORD sample_size;
DPRINT("Standard (PCM) format\n");
sample_size = format->nChannels * format->wBitsPerSample;
device->state->sample_size = sample_size;
format_struct_len = 16; /* FIXME */
}
else
{
/* Non-standard format */
return MMSYSERR_NOTSUPPORTED; /* TODO */
}
return CallKernelDevice(device,
IOCTL_WDMAUD_OPEN_DEVICE,
format_struct_len,
(DWORD)format);
}
/* MOVEME */
LPCRITICAL_SECTION CreateCriticalSection()
{
LPCRITICAL_SECTION cs;
cs = AllocMem(sizeof(CRITICAL_SECTION));
if ( ! cs )
return NULL;
InitializeCriticalSection(cs);
return cs;
}
/*
OpenDevice
A generic "open device" function, which makes use of the above function
once parameters have been checked. This is capable of handling both
MIDI and wave devices, which is an improvement over the previous
implementation (which had a lot of duplicate functionality.)
*/
MMRESULT
OpenDevice(
CHAR device_type,
DWORD device_id,
LPVOID open_descriptor,
DWORD flags,
PWDMAUD_DEVICE_INFO* user_data
)
{
MMRESULT result = MMSYSERR_ERROR;
WCHAR* device_path;
PWDMAUD_DEVICE_INFO device;
LPWAVEFORMATEX format;
/* As we support both types */
LPWAVEOPENDESC wave_opendesc = (LPWAVEOPENDESC) open_descriptor;
LPMIDIOPENDESC midi_opendesc = (LPMIDIOPENDESC) open_descriptor;
/* FIXME: Does this just apply to wave, or MIDI also? */
if ( device_id > 100 )
return MMSYSERR_BADDEVICEID;
/* Copy the appropriate dnDevNode value */
if ( IsWaveDeviceType(device_type) )
device_path = (WCHAR*) wave_opendesc->dnDevNode;
else if ( IsMidiDeviceType(device_type) )
device_path = (WCHAR*) midi_opendesc->dnDevNode;
else
return MMSYSERR_INVALPARAM;
device = CreateDeviceData(device_type, device_id, device_path, TRUE);
if ( ! device )
{
DPRINT1("Couldn't allocate memory for device data\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
device->flags = flags;
if ( ( IsWaveDeviceType(device->type) ) &&
( device->flags & WAVE_FORMAT_QUERY ) )
{
result = OpenDeviceViaKernel(device, wave_opendesc->lpFormat);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Format not supported (mmsys error %d)\n", (int) result);
result = WAVERR_BADFORMAT;
}
else
{
DPRINT("Format supported\n");
result = MMSYSERR_NOERROR;
}
goto cleanup;
}
device->state->device_queue_guard = CreateCriticalSection();
if ( ! device->state->device_queue_guard )
{
DPRINT1("Couldn't create queue cs\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
/* Set up the callbacks */
device->client_instance = IsWaveDeviceType(device->type)
? wave_opendesc->dwInstance
: midi_opendesc->dwInstance;
device->client_callback = IsWaveDeviceType(device->type)
? wave_opendesc->dwCallback
: midi_opendesc->dwCallback;
/*
The device state will be stopped and unpaused already, but in some
cases this isn't the desired behaviour.
*/
/* FIXME: What do our friends MIDI in and out need? */
device->state->is_paused = IsWaveOutDeviceType(device->type) ? TRUE : FALSE;
if ( IsMidiOutDeviceType(device->type) )
{
device->state->midi_buffer = AllocMem(2048);
if ( ! device->state->midi_buffer )
{
DPRINT1("Couldn't allocate MIDI buffer\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
}
/* Format is only for wave devices */
format = IsWaveDeviceType(device->type) ? wave_opendesc->lpFormat : NULL;
result = OpenDeviceViaKernel(device, format);
if ( MM_FAILURE(result) )
{
DPRINT1("FAILED to open device - mm error %d\n", (int) result);
goto cleanup;
}
EnterCriticalSection(device->state->device_queue_guard);
/* TODO */
LeaveCriticalSection(device->state->device_queue_guard);
if ( IsWaveDeviceType(device->type) )
wave_opendesc->hWave = (HWAVE) device;
else
midi_opendesc->hMidi = (HMIDI) device;
/* Our "user data" is actually the device information */
*user_data = device;
if ( device->client_callback )
{
DWORD message = IsWaveInDeviceType(device->type) ? WIM_OPEN :
IsWaveOutDeviceType(device->type) ? WOM_OPEN :
IsMidiInDeviceType(device->type) ? MIM_OPEN :
MOM_OPEN;
DPRINT("Calling client with message %d\n", (int) message);
NotifyClient(device, message, 0, 0);
}
result = MMSYSERR_NOERROR;
cleanup :
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -