/* * 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; }