[USBAUDIO]
[reactos.git] / reactos / sdk / lib / drivers / sound / libusbaudio / parser.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/libusbaudio/libusbaudio.c
5 * PURPOSE: USB AUDIO Parser
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "priv.h"
10
11 USBAUDIO_STATUS
12 UsbAudio_CountDescriptors(
13 IN PUCHAR ConfigurationDescriptor,
14 IN ULONG ConfigurationDescriptorLength,
15 IN UCHAR DescriptorType,
16 IN PUSB_COMMON_DESCRIPTOR StartPosition,
17 IN PUSB_COMMON_DESCRIPTOR EndPosition,
18 OUT PULONG DescriptorCount)
19 {
20 PUSB_COMMON_DESCRIPTOR Descriptor;
21 ULONG Count = 0;
22
23 /* init result */
24 *DescriptorCount = 0;
25
26 /* enumerate descriptors */
27 Descriptor = StartPosition;
28 if (Descriptor == NULL)
29 Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigurationDescriptor;
30
31 if (EndPosition == NULL)
32 EndPosition = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptorLength);
33
34
35 while((ULONG_PTR)Descriptor < ((ULONG_PTR)EndPosition))
36 {
37 if (!Descriptor->bLength || !Descriptor->bDescriptorType)
38 {
39 /* bogus descriptor */
40 return UA_STATUS_UNSUCCESSFUL;
41 }
42
43 if (Descriptor->bDescriptorType == DescriptorType)
44 {
45 /* found descriptor */
46 Count++;
47 }
48
49 /* move to next descriptor */
50 Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength);
51
52 }
53
54 /* store result */
55 *DescriptorCount = Count;
56 return UA_STATUS_SUCCESS;
57 }
58
59 USBAUDIO_STATUS
60 UsbAudio_GetDescriptors(
61 IN PUCHAR ConfigurationDescriptor,
62 IN ULONG ConfigurationDescriptorLength,
63 IN UCHAR DescriptorType,
64 IN ULONG DescriptorCount,
65 IN PUSB_COMMON_DESCRIPTOR StartPosition,
66 IN PUSB_COMMON_DESCRIPTOR EndPosition,
67 OUT PUSB_COMMON_DESCRIPTOR *Descriptors)
68 {
69 PUSB_COMMON_DESCRIPTOR Descriptor;
70 ULONG Count = 0;
71
72 /* enumerate descriptors */
73 Descriptor = StartPosition;
74 if (Descriptor == NULL)
75 Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigurationDescriptor;
76
77 if (EndPosition == NULL)
78 EndPosition = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptorLength);
79
80 while((ULONG_PTR)Descriptor < ((ULONG_PTR)EndPosition))
81 {
82 if (!Descriptor->bLength || !Descriptor->bDescriptorType)
83 {
84 /* bogus descriptor */
85 return UA_STATUS_UNSUCCESSFUL;
86 }
87
88 if (Descriptor->bDescriptorType == DescriptorType)
89 {
90 /* found descriptor */
91 if (Count >= DescriptorCount)
92 break;
93
94 /* store result */
95 Descriptors[Count] = Descriptor;
96 Count++;
97 }
98
99 /* move to next descriptor */
100 Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength);
101 }
102
103 /* done */
104 return UA_STATUS_SUCCESS;
105 }
106
107 USBAUDIO_STATUS
108 UsbAudio_CountInterfaceDescriptors(
109 IN PUCHAR ConfigurationDescriptor,
110 IN ULONG ConfigurationDescriptorLength,
111 OUT PULONG DescriptorCount)
112 {
113 return UsbAudio_CountDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, USB_INTERFACE_DESCRIPTOR_TYPE, NULL, NULL, DescriptorCount);
114 }
115
116 USBAUDIO_STATUS
117 UsbAudio_CreateDescriptorArray(
118 IN PUSBAUDIO_CONTEXT Context,
119 IN PUCHAR ConfigurationDescriptor,
120 IN ULONG ConfigurationDescriptorLength,
121 IN ULONG ArrayLength,
122 IN ULONG DescriptorType,
123 IN PUSB_COMMON_DESCRIPTOR StartPosition,
124 IN PUSB_COMMON_DESCRIPTOR EndPosition,
125 OUT PUSB_COMMON_DESCRIPTOR ** Array)
126 {
127 USBAUDIO_STATUS Status;
128 PUSB_COMMON_DESCRIPTOR * Descriptors;
129
130 /* zero result */
131 *Array = NULL;
132
133 /* first allocate descriptor array */
134 Descriptors = (PUSB_COMMON_DESCRIPTOR*)Context->Alloc(sizeof(PUSB_COMMON_DESCRIPTOR) * ArrayLength);
135 if (!Descriptors)
136 {
137 /* no memory */
138 return UA_STATUS_NO_MEMORY;
139 }
140
141 /* extract control terminal descriptors */
142 Status = UsbAudio_GetDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, DescriptorType, ArrayLength, StartPosition, EndPosition, Descriptors);
143 if (Status != UA_STATUS_SUCCESS)
144 {
145 /* failed */
146 Context->Free(Descriptors);
147 return Status;
148 }
149
150 /* store result */
151 *Array = Descriptors;
152 return UA_STATUS_SUCCESS;
153 }
154
155 USBAUDIO_STATUS
156 UsbAudio_CountAudioDescriptors(
157 IN PUCHAR ConfigurationDescriptor,
158 IN ULONG ConfigurationDescriptorLength,
159 IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
160 IN ULONG InterfaceDescriptorCount,
161 IN ULONG InterfaceDescriptorIndex,
162 OUT PULONG DescriptorCount)
163 {
164 if (InterfaceDescriptorIndex + 1 == InterfaceDescriptorCount)
165 return UsbAudio_CountDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE, InterfaceDescriptors[InterfaceDescriptorIndex], NULL, DescriptorCount);
166 else
167 return UsbAudio_CountDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE, InterfaceDescriptors[InterfaceDescriptorIndex], InterfaceDescriptors[InterfaceDescriptorIndex + 1], DescriptorCount);
168 }
169
170 USBAUDIO_STATUS
171 UsbAudio_CreateInterfaceDescriptorsArray(
172 IN PUSBAUDIO_CONTEXT Context,
173 IN PUCHAR ConfigurationDescriptor,
174 IN ULONG ConfigurationDescriptorLength,
175 IN ULONG ArrayLength,
176 OUT PUSB_COMMON_DESCRIPTOR ** Array)
177 {
178 return UsbAudio_CreateDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorLength, ArrayLength, USB_INTERFACE_DESCRIPTOR_TYPE, NULL, NULL, Array);
179 }
180
181 USBAUDIO_STATUS
182 UsbAudio_CreateAudioDescriptorArray(
183 IN PUSBAUDIO_CONTEXT Context,
184 IN PUCHAR ConfigurationDescriptor,
185 IN ULONG ConfigurationDescriptorLength,
186 IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
187 IN ULONG InterfaceDescriptorCount,
188 IN ULONG InterfaceDescriptorIndex,
189 IN ULONG ArrayLength,
190 OUT PUSB_COMMON_DESCRIPTOR ** Array)
191 {
192 if (InterfaceDescriptorIndex + 1 == InterfaceDescriptorCount)
193 return UsbAudio_CreateDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorLength, ArrayLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE, InterfaceDescriptors[InterfaceDescriptorIndex], NULL, Array);
194 else
195 return UsbAudio_CreateDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorLength, ArrayLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE,
196 InterfaceDescriptors[InterfaceDescriptorIndex], InterfaceDescriptors[InterfaceDescriptorIndex + 1], Array);
197 }
198
199 PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR
200 UsbAudio_GetTerminalDescriptorById(
201 IN PUSB_COMMON_DESCRIPTOR *Descriptors,
202 IN ULONG DescriptorCount,
203 IN ULONG TerminalId)
204 {
205 ULONG Index;
206 PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR Descriptor;
207
208 for(Index = 0; Index < DescriptorCount; Index++)
209 {
210 /* get descriptor */
211 Descriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)Descriptors[Index];
212
213 /* is it an input / output terminal */
214 DPRINT("Descriptor %p Type %x SubType %x TerminalID %x\n", Descriptor, Descriptor->bDescriptorType, Descriptor->bDescriptorSubtype, Descriptor->bTerminalID);
215 if (Descriptor->bDescriptorSubtype != USB_AUDIO_INPUT_TERMINAL && Descriptor->bDescriptorSubtype != USB_AUDIO_OUTPUT_TERMINAL)
216 continue;
217
218 if (Descriptor->bTerminalID == TerminalId)
219 return Descriptor;
220 }
221 return NULL;
222 }
223
224 ULONG
225 UsbAudio_GetAudioControlInterfaceIndex(
226 IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
227 IN ULONG DescriptorCount)
228 {
229 ULONG Index;
230 PUSB_INTERFACE_DESCRIPTOR Descriptor;
231
232
233 for(Index = 0; Index < DescriptorCount; Index++)
234 {
235 /* get descriptor */
236 Descriptor = (PUSB_INTERFACE_DESCRIPTOR)InterfaceDescriptors[Index];
237 ASSERT(Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
238 ASSERT(Descriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
239
240 /* compare interface class */
241 if (Descriptor->bInterfaceClass == 0x01 && Descriptor->bInterfaceSubClass == 0x01)
242 {
243 /* found audio control class */
244 return Index;
245 }
246 }
247
248 /* not found */
249 return MAXULONG;
250 }
251
252
253 USBAUDIO_STATUS
254 UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(
255 IN ULONG DescriptorCount,
256 IN PUSB_COMMON_DESCRIPTOR *Descriptors,
257 IN ULONG DescriptorIndex,
258 IN UCHAR Subtype,
259 IN USHORT TerminalType,
260 OUT PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR * OutDescriptor,
261 OUT PULONG OutDescriptorIndex)
262 {
263 ULONG Index;
264 ULONG Count = 0;
265 PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR CurrentDescriptor;
266
267 for(Index = 0; Index < DescriptorCount; Index++)
268 {
269 /* get current descriptor */
270 CurrentDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)Descriptors[Index];
271 ASSERT(CurrentDescriptor->bDescriptorType == USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
272
273 if (CurrentDescriptor->bDescriptorSubtype == Subtype &&
274 (TerminalType == USB_AUDIO_UNDEFINED_TERMINAL_TYPE || CurrentDescriptor->wTerminalType == TerminalType))
275 {
276 /* found descriptor */
277 if (Count == DescriptorIndex)
278 {
279 /* store result */
280 *OutDescriptor = CurrentDescriptor;
281 *OutDescriptorIndex = Index;
282 return UA_STATUS_SUCCESS;
283 }
284
285 Count++;
286 }
287 }
288
289 /* not found */
290 return UA_STATUS_UNSUCCESSFUL;
291 }
292
293 USBAUDIO_STATUS
294 UsbAudio_AssignTerminalIds(
295 IN PUSBAUDIO_CONTEXT Context,
296 IN ULONG TerminalIdsLength,
297 IN PUSB_COMMON_DESCRIPTOR * TerminalIds,
298 OUT PULONG PinArray,
299 OUT PULONG PinArrayCount)
300 {
301 ULONG Consumed = 0;
302 ULONG PinIndex = 0;
303 ULONG Index, DescriptorIndex;
304 PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR Descriptor;
305 USBAUDIO_STATUS Status;
306
307 /* FIXME: support more than 32 terminals */
308 ASSERT(TerminalIdsLength <= 32);
309
310 /* first search for an output terminal with streaming type */
311 Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, 0, USB_AUDIO_OUTPUT_TERMINAL, USB_AUDIO_STREAMING_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
312 if (Status == UA_STATUS_SUCCESS)
313 {
314 /* found output terminal */
315 PinArray[PinIndex] = Descriptor->bTerminalID;
316 Consumed |= 1 << DescriptorIndex;
317 DPRINT("Assigned TerminalId %x to PinIndex %lx Consumed %lx DescriptorIndex %lx\n", Descriptor->bTerminalID, PinIndex, Consumed, DescriptorIndex);
318 PinIndex++;
319 }
320
321 /* now search for an input terminal with streaming type */
322 Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, 0, USB_AUDIO_INPUT_TERMINAL, USB_AUDIO_STREAMING_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
323 if (Status == UA_STATUS_SUCCESS)
324 {
325 /* found output terminal */
326 PinArray[PinIndex] = Descriptor->bTerminalID;
327 Consumed |= 1 << DescriptorIndex;
328 PinIndex++;
329 }
330
331 /* now assign all other input terminals */
332 Index = 0;
333 do
334 {
335 /* find an input terminal */
336 Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, Index, USB_AUDIO_INPUT_TERMINAL, USB_AUDIO_UNDEFINED_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
337 if (Status != UA_STATUS_SUCCESS)
338 {
339 /* no more items */
340 break;
341 }
342
343 if (Consumed & (1 << DescriptorIndex))
344 {
345 /* terminal has already been assigned to an pin */
346 Index++;
347 continue;
348 }
349
350 /* assign terminal */
351 PinArray[PinIndex] = Descriptor->bTerminalID;
352 Consumed |= 1 << DescriptorIndex;
353 PinIndex++;
354 Index++;
355
356 }while(Status == UA_STATUS_SUCCESS);
357
358
359 /* now assign all other output terminals */
360 Index = 0;
361 do
362 {
363 /* find an input terminal */
364 Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, Index, USB_AUDIO_OUTPUT_TERMINAL, USB_AUDIO_UNDEFINED_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
365 if (Status != UA_STATUS_SUCCESS)
366 {
367 /* no more items */
368 break;
369 }
370
371 if (Consumed & (1 << DescriptorIndex))
372 {
373 /* terminal has already been assigned to an pin */
374 Index++;
375 continue;
376 }
377
378 /* assign terminal */
379 PinArray[PinIndex] = Descriptor->bTerminalID;
380 Consumed |= 1 << DescriptorIndex;
381 PinIndex++;
382 Index++;
383
384 }while(Status == UA_STATUS_SUCCESS);
385
386 /* store pin count */
387 DPRINT("Consumed %lx PinIndex %lu\n", Consumed, PinIndex);
388 *PinArrayCount = PinIndex;
389 return UA_STATUS_SUCCESS;
390 }