mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
460 lines
11 KiB
C
460 lines
11 KiB
C
/*
|
|
* PROJECT: ReactOS Universal Audio Class Driver
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: drivers/usb/usbaudio/usbaudio.c
|
|
* PURPOSE: USB Audio device driver.
|
|
* PROGRAMMERS:
|
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
|
*/
|
|
|
|
#include "usbaudio.h"
|
|
|
|
static KSDEVICE_DISPATCH KsDeviceDispatch = {
|
|
USBAudioAddDevice,
|
|
USBAudioPnPStart,
|
|
NULL,
|
|
USBAudioPnPQueryStop,
|
|
USBAudioPnPCancelStop,
|
|
USBAudioPnPStop,
|
|
USBAudioPnPQueryRemove,
|
|
USBAudioPnPCancelRemove,
|
|
USBAudioPnPRemove,
|
|
USBAudioPnPQueryCapabilities,
|
|
USBAudioPnPSurpriseRemoval,
|
|
USBAudioPnPQueryPower,
|
|
USBAudioPnPSetPower
|
|
};
|
|
|
|
static KSDEVICE_DESCRIPTOR KsDeviceDescriptor = {
|
|
&KsDeviceDispatch,
|
|
0,
|
|
NULL,
|
|
0x100, //KSDEVICE_DESCRIPTOR_VERSION,
|
|
0
|
|
};
|
|
|
|
NTSTATUS
|
|
SubmitUrbSync(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PURB Urb)
|
|
{
|
|
PIRP Irp;
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
// init event
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
// build irp
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&IoStatus);
|
|
|
|
if (!Irp)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// get next stack location
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
// store urb
|
|
IoStack->Parameters.Others.Argument1 = Urb;
|
|
|
|
// call driver
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
// wait for the request to finish
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatus.Status;
|
|
}
|
|
|
|
// done
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioSelectConfiguration(
|
|
IN PKSDEVICE Device,
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
|
|
PUSBD_INTERFACE_LIST_ENTRY InterfaceList;
|
|
PURB Urb;
|
|
NTSTATUS Status;
|
|
ULONG InterfaceDescriptorCount;
|
|
|
|
/* alloc item for configuration request */
|
|
InterfaceList = AllocFunction(sizeof(USBD_INTERFACE_LIST_ENTRY) * (ConfigurationDescriptor->bNumInterfaces + 1));
|
|
if (!InterfaceList)
|
|
{
|
|
/* insufficient resources*/
|
|
return USBD_STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* grab interface descriptor */
|
|
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
|
|
if (!InterfaceDescriptor)
|
|
{
|
|
/* no such interface */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* lets enumerate the interfaces */
|
|
InterfaceDescriptorCount = 0;
|
|
while (InterfaceDescriptor != NULL)
|
|
{
|
|
if (InterfaceDescriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL*/
|
|
{
|
|
InterfaceList[InterfaceDescriptorCount++].InterfaceDescriptor = InterfaceDescriptor;
|
|
}
|
|
else if (InterfaceDescriptor->bInterfaceSubClass == 0x03) /* MIDI_STREAMING*/
|
|
{
|
|
InterfaceList[InterfaceDescriptorCount++].InterfaceDescriptor = InterfaceDescriptor;
|
|
}
|
|
|
|
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
|
|
}
|
|
|
|
/* build urb */
|
|
Urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, InterfaceList);
|
|
if (!Urb)
|
|
{
|
|
/* no memory */
|
|
FreeFunction(InterfaceList);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* device extension */
|
|
DeviceExtension = Device->Context;
|
|
|
|
/* submit configuration urb */
|
|
Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* free resources */
|
|
ExFreePool(Urb);
|
|
FreeFunction(InterfaceList);
|
|
return Status;
|
|
}
|
|
|
|
/* store configuration handle */
|
|
DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
|
|
|
|
/* alloc interface info */
|
|
DeviceExtension->InterfaceInfo = AllocFunction(Urb->UrbSelectConfiguration.Interface.Length);
|
|
if (DeviceExtension->InterfaceInfo)
|
|
{
|
|
/* copy interface info */
|
|
RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioStartDevice(
|
|
IN PKSDEVICE Device)
|
|
{
|
|
PURB Urb;
|
|
PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
NTSTATUS Status;
|
|
ULONG Length;
|
|
|
|
/* get device extension */
|
|
DeviceExtension = Device->Context;
|
|
|
|
/* allocate urb */
|
|
Urb = AllocFunction(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
|
|
if (!Urb)
|
|
{
|
|
/* no memory */
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* alloc buffer for device descriptor */
|
|
DeviceDescriptor = AllocFunction(sizeof(USB_DEVICE_DESCRIPTOR));
|
|
if (!DeviceDescriptor)
|
|
{
|
|
/* insufficient resources */
|
|
FreeFunction(Urb);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* build descriptor request */
|
|
UsbBuildGetDescriptorRequest(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, DeviceDescriptor, NULL, sizeof(USB_DEVICE_DESCRIPTOR), NULL);
|
|
|
|
/* submit urb */
|
|
Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* free resources */
|
|
FreeFunction(Urb);
|
|
FreeFunction(DeviceDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* now allocate some space for partial configuration descriptor */
|
|
ConfigurationDescriptor = AllocFunction(sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
|
if (!ConfigurationDescriptor)
|
|
{
|
|
/* free resources */
|
|
FreeFunction(Urb);
|
|
FreeFunction(DeviceDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* build descriptor request */
|
|
UsbBuildGetDescriptorRequest(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, ConfigurationDescriptor, NULL, sizeof(USB_CONFIGURATION_DESCRIPTOR), NULL);
|
|
|
|
/* submit urb */
|
|
Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* free resources */
|
|
FreeFunction(Urb);
|
|
FreeFunction(DeviceDescriptor);
|
|
FreeFunction(ConfigurationDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* backup length */
|
|
Length = ConfigurationDescriptor->wTotalLength;
|
|
|
|
/* free old descriptor */
|
|
FreeFunction(ConfigurationDescriptor);
|
|
|
|
/* now allocate some space for full configuration descriptor */
|
|
ConfigurationDescriptor = AllocFunction(Length);
|
|
if (!ConfigurationDescriptor)
|
|
{
|
|
/* free resources */
|
|
FreeFunction(Urb);
|
|
FreeFunction(DeviceDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* build descriptor request */
|
|
UsbBuildGetDescriptorRequest(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, ConfigurationDescriptor, NULL, Length, NULL);
|
|
|
|
/* submit urb */
|
|
Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
|
|
|
|
/* free urb */
|
|
FreeFunction(Urb);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* free resources */
|
|
FreeFunction(DeviceDescriptor);
|
|
FreeFunction(ConfigurationDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* lets add to object bag */
|
|
KsAddItemToObjectBag(Device->Bag, DeviceDescriptor, ExFreePool);
|
|
KsAddItemToObjectBag(Device->Bag, ConfigurationDescriptor, ExFreePool);
|
|
|
|
Status = USBAudioSelectConfiguration(Device, ConfigurationDescriptor);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
|
|
DeviceExtension->ConfigurationDescriptor = ConfigurationDescriptor;
|
|
DeviceExtension->DeviceDescriptor = DeviceDescriptor;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioAddDevice(
|
|
_In_ PKSDEVICE Device)
|
|
{
|
|
/* no op */
|
|
DPRINT1("USBAudioAddDevice\n");
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioPnPStart(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp,
|
|
_In_opt_ PCM_RESOURCE_LIST TranslatedResourceList,
|
|
_In_opt_ PCM_RESOURCE_LIST UntranslatedResourceList)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
if (!Device->Started)
|
|
{
|
|
/* alloc context */
|
|
DeviceExtension = AllocFunction(sizeof(DEVICE_EXTENSION));
|
|
if (DeviceExtension == NULL)
|
|
{
|
|
/* insufficient resources */
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* init context */
|
|
Device->Context = DeviceExtension;
|
|
DeviceExtension->LowerDevice = Device->NextDeviceObject;
|
|
|
|
/* add to object bag*/
|
|
KsAddItemToObjectBag(Device->Bag, Device->Context, ExFreePool);
|
|
|
|
/* init device*/
|
|
Status = USBAudioStartDevice(Device);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* TODO retrieve interface */
|
|
Status = USBAudioCreateFilterContext(Device);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioPnPQueryStop(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp)
|
|
{
|
|
/* no op */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBAudioPnPCancelStop(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp)
|
|
{
|
|
/* no op */
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBAudioPnPStop(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp)
|
|
{
|
|
/* TODO: stop device */
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioPnPQueryRemove(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp)
|
|
{
|
|
/* no op */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
USBAudioPnPCancelRemove(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp)
|
|
{
|
|
/* no op */
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBAudioPnPRemove(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp)
|
|
{
|
|
/* TODO: stop device */
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioPnPQueryCapabilities(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp,
|
|
_Inout_ PDEVICE_CAPABILITIES Capabilities)
|
|
{
|
|
/* TODO: set caps */
|
|
UNIMPLEMENTED;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBAudioPnPSurpriseRemoval(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp)
|
|
{
|
|
/* TODO: stop streams */
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBAudioPnPQueryPower(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp,
|
|
_In_ DEVICE_POWER_STATE DeviceTo,
|
|
_In_ DEVICE_POWER_STATE DeviceFrom,
|
|
_In_ SYSTEM_POWER_STATE SystemTo,
|
|
_In_ SYSTEM_POWER_STATE SystemFrom,
|
|
_In_ POWER_ACTION Action)
|
|
{
|
|
/* no op */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBAudioPnPSetPower(
|
|
_In_ PKSDEVICE Device,
|
|
_In_ PIRP Irp,
|
|
_In_ DEVICE_POWER_STATE To,
|
|
_In_ DEVICE_POWER_STATE From)
|
|
{
|
|
/* TODO: stop streams */
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
// initialize driver
|
|
Status = KsInitializeDriver(DriverObject, RegistryPath, &KsDeviceDescriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// failed to initialize driver
|
|
DPRINT1("Failed to initialize driver with %x\n", Status);
|
|
return Status;
|
|
}
|
|
return Status;
|
|
}
|