[USBAUDIO]
[reactos.git] / reactos / drivers / usb / usbaudio / pin.c
1 /*
2 * PROJECT: ReactOS Universal Audio Class Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbaudio/pin.c
5 * PURPOSE: USB Audio device driver.
6 * PROGRAMMERS:
7 * Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbaudio.h"
11
12 NTSTATUS
13 UsbAudioSetFormat(
14 IN PKSPIN Pin)
15 {
16 PURB Urb;
17 PUCHAR SampleRateBuffer;
18 PPIN_CONTEXT PinContext;
19 NTSTATUS Status;
20 PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
21
22 /* allocate sample rate buffer */
23 SampleRateBuffer = AllocFunction(sizeof(ULONG));
24 if (!SampleRateBuffer)
25 {
26 /* no memory */
27 return STATUS_INSUFFICIENT_RESOURCES;
28 }
29
30 if (IsEqualGUIDAligned(&Pin->ConnectionFormat->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
31 IsEqualGUIDAligned(&Pin->ConnectionFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
32 IsEqualGUIDAligned(&Pin->ConnectionFormat->Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
33 {
34 WaveFormatEx = (PKSDATAFORMAT_WAVEFORMATEX)Pin->ConnectionFormat;
35 SampleRateBuffer[0] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 16) & 0xFF;
36 SampleRateBuffer[1] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 8) & 0xFF;
37 SampleRateBuffer[2] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 0) & 0xFF;
38
39 /* TODO: verify connection format */
40 }
41 else
42 {
43 /* not supported yet*/
44 UNIMPLEMENTED;
45 FreeFunction(SampleRateBuffer);
46 return STATUS_INVALID_PARAMETER;
47 }
48
49 /* allocate urb */
50 Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
51 if (!Urb)
52 {
53 /* no memory */
54 FreeFunction(SampleRateBuffer);
55 return STATUS_INSUFFICIENT_RESOURCES;
56 }
57
58 /* format urb */
59 UsbBuildVendorRequest(Urb,
60 URB_FUNCTION_CLASS_ENDPOINT,
61 sizeof(URB),
62 USBD_TRANSFER_DIRECTION_OUT,
63 0,
64 0x01,
65 0x100,
66 0x81, //FIXME bEndpointAddress
67 SampleRateBuffer,
68 NULL,
69 3,
70 NULL);
71
72 /* get pin context */
73 PinContext = Pin->Context;
74 DbgBreakPoint();
75 /* submit urb */
76 Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
77
78 DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin, Status);
79 FreeFunction(Urb);
80 FreeFunction(SampleRateBuffer);
81 return Status;
82 }
83
84 NTSTATUS
85 USBAudioSelectAudioStreamingInterface(
86 IN PDEVICE_EXTENSION DeviceExtension,
87 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
88 {
89 PURB Urb;
90 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
91 NTSTATUS Status;
92
93 /* grab interface descriptor */
94 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
95 if (!InterfaceDescriptor)
96 {
97 /* no such interface */
98 return STATUS_INVALID_PARAMETER;
99 }
100
101 /* select the first interface with audio streaming and non zero num of endpoints */
102 while (InterfaceDescriptor != NULL)
103 {
104 if (InterfaceDescriptor->bInterfaceSubClass == 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor->bNumEndpoints > 0)
105 {
106 break;
107 }
108 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
109 }
110
111 if (!InterfaceDescriptor)
112 {
113 /* no such interface */
114 return STATUS_INVALID_PARAMETER;
115 }
116
117 Urb = AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints));
118 if (!Urb)
119 {
120 /* no memory */
121 return USBD_STATUS_INSUFFICIENT_RESOURCES;
122 }
123
124 /* now prepare interface urb */
125 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
126
127 /* copy interface information */
128 RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInfo, DeviceExtension->InterfaceInfo->Length);
129
130 /* set configuration handle */
131 Urb->UrbSelectInterface.ConfigurationHandle = DeviceExtension->ConfigurationHandle;
132
133 /* now select the interface */
134 Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
135
136 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status, Urb->UrbSelectInterface.Hdr.Status);
137
138 /* did it succeeed */
139 if (NT_SUCCESS(Status))
140 {
141 /* update configuration info */
142 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInfo->Length);
143 RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
144 }
145
146 /* free urb */
147 FreeFunction(Urb);
148 return Status;
149 }
150
151 NTSTATUS
152 InitCapturePin(
153 IN PKSPIN Pin)
154 {
155 NTSTATUS Status;
156
157 /* set sample rate */
158 Status = UsbAudioSetFormat(Pin);
159
160 /* TODO: init pin */
161 return Status;
162 }
163
164 NTSTATUS
165 InitStreamPin(
166 IN PKSPIN Pin)
167 {
168 UNIMPLEMENTED
169 return STATUS_NOT_IMPLEMENTED;
170 }
171
172
173 NTSTATUS
174 NTAPI
175 USBAudioPinCreate(
176 _In_ PKSPIN Pin,
177 _In_ PIRP Irp)
178 {
179 PKSFILTER Filter;
180 PFILTER_CONTEXT FilterContext;
181 PPIN_CONTEXT PinContext;
182 NTSTATUS Status;
183
184 Filter = KsPinGetParentFilter(Pin);
185 if (Filter == NULL)
186 {
187 /* invalid parameter */
188 return STATUS_INVALID_PARAMETER;
189 }
190
191 /* get filter context */
192 FilterContext = Filter->Context;
193
194 /* allocate pin context */
195 PinContext = AllocFunction(sizeof(PIN_CONTEXT));
196 if (!PinContext)
197 {
198 /* no memory*/
199 return STATUS_INSUFFICIENT_RESOURCES;
200 }
201
202 /* init pin context */
203 PinContext->DeviceExtension = FilterContext->DeviceExtension;
204 PinContext->LowerDevice = FilterContext->LowerDevice;
205
206 /* store pin context*/
207 Pin->Context = PinContext;
208
209 /* select streaming interface */
210 Status = USBAudioSelectAudioStreamingInterface(PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor);
211 if (!NT_SUCCESS(Status))
212 {
213 /* failed */
214 return Status;
215 }
216
217 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
218 {
219 /* init capture pin */
220 Status = InitCapturePin(Pin);
221 }
222 else
223 {
224 /* audio streaming pin*/
225 Status = InitStreamPin(Pin);
226 }
227
228 return STATUS_SUCCESS;
229 }
230
231 NTSTATUS
232 NTAPI
233 USBAudioPinClose(
234 _In_ PKSPIN Pin,
235 _In_ PIRP Irp)
236 {
237 UNIMPLEMENTED
238 return STATUS_NOT_IMPLEMENTED;
239 }
240
241
242 NTSTATUS
243 NTAPI
244 USBAudioPinProcess(
245 _In_ PKSPIN Pin)
246 {
247 return STATUS_SUCCESS;
248 }
249
250
251 VOID
252 NTAPI
253 USBAudioPinReset(
254 _In_ PKSPIN Pin)
255 {
256 UNIMPLEMENTED
257 }
258
259 NTSTATUS
260 NTAPI
261 USBAudioPinSetDataFormat(
262 _In_ PKSPIN Pin,
263 _In_opt_ PKSDATAFORMAT OldFormat,
264 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
265 _In_ const KSDATARANGE* DataRange,
266 _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
267 {
268 if (OldFormat == NULL)
269 {
270 /* TODO: verify connection format */
271 UNIMPLEMENTED
272 return STATUS_SUCCESS;
273 }
274
275 return UsbAudioSetFormat(Pin);
276 }
277
278 NTSTATUS
279 NTAPI
280 USBAudioPinSetDeviceState(
281 _In_ PKSPIN Pin,
282 _In_ KSSTATE ToState,
283 _In_ KSSTATE FromState)
284 {
285 UNIMPLEMENTED
286 return STATUS_SUCCESS;
287 }