1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
|
//*****************************************************************************
//
// usbdesc.c - USB descriptor parsing functions.
//
// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.1.0.12573 of the Tiva USB Library.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "usblib/usblib.h"
//*****************************************************************************
//
// Assumptions:
// ------------
//
// The following assumptions are made in this module. From reading chapter 9
// of the USB 2.0 specification, these appear to be perfectly valid.
//
// 1. The interface number, bInterfaceNumber in the interface descriptor, is
// a zero based index and takes values between 0 and
// (pConfigDescriptor->bNumInterfaces - 1) inclusive.
// 2. Similarly, the alternate setting number, bAlternateSetting in the
// interface descriptor, is a zero based index.
// 3. Interface descriptors are ordered by interface number in the
// configuration descriptor.
// 4. If alternate settings are available for an interface, the interface
// descriptors are ordered by alternate setting value bAlternateSetting.
// 5. Although the endpoints associated with a given interface must follow
// their associated interface descriptor, it is possible for other,
// device specific descriptors to be found between an interface descriptor
// and its endpoints or between endpoint descriptors for the same
// interface.
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup general_usblib_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
//! Determines the number of individual descriptors of a particular type within
//! a supplied buffer.
//!
//! \param psDesc points to the first byte of a block of standard USB
//! descriptors.
//! \param ui32Size is the number of bytes of descriptor data found at pointer
//! \e psDesc.
//! \param ui32Type identifies the type of descriptor that is to be counted.
//! If the value is \b USB_DESC_ANY, the function returns the total number of
//! descriptors regardless of type.
//!
//! This function can be used to count the number of descriptors of a
//! particular type within a block of descriptors. The caller can provide a
//! specific type value which the function matches against the second byte of
//! each descriptor or, alternatively, can specify \b USB_DESC_ANY to have the
//! function count all descriptors regardless of their type.
//!
//! \return Returns the number of descriptors found in the supplied block of
//! data.
//
//*****************************************************************************
uint32_t
USBDescGetNum(tDescriptorHeader *psDesc, uint32_t ui32Size,
uint32_t ui32Type)
{
tDescriptorHeader *psDescCheck;
uint32_t ui32TotLength;
uint32_t ui32Count;
//
// Set up for our descriptor counting loop.
//
psDescCheck = psDesc;
ui32TotLength = 0;
ui32Count = 0;
//
// Keep looking through the supplied data until we reach the end.
//
while(ui32TotLength < ui32Size)
{
//
// Does this descriptor match the type passed (if a specific type
// has been specified)?
//
if((ui32Type == USB_DESC_ANY) ||
(psDescCheck->bDescriptorType == (uint8_t)(ui32Type & 0xFF)))
{
ui32Count++;
}
//
// Move on to the next descriptor.
//
ui32TotLength += (uint32_t)psDescCheck->bLength;
psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
}
//
// Return the descriptor count to the caller.
//
return(ui32Count);
}
//*****************************************************************************
//
//! Determines the number of individual descriptors of a particular type within
//! a supplied buffer.
//!
//! \param psDesc points to the first byte of a block of standard USB
//! descriptors.
//! \param ui32Size is the number of bytes of descriptor data found at pointer
//! \e psDesc.
//! \param ui32Type identifies the type of descriptor that is to be found. If
//! the value is \b USB_DESC_ANY, the function returns a pointer to the n-th
//! descriptor regardless of type.
//! \param ui32Index is the zero based index of the descriptor whose pointer is
//! to be returned. For example, passing value 1 in \e ui32Index returns the
//! second matching descriptor.
//!
//! Return a pointer to the n-th descriptor of a particular type found in the
//! block of \e ui32Size bytes starting at \e psDesc.
//!
//! \return Returns a pointer to the header of the required descriptor if
//! found or NULL otherwise.
//
//*****************************************************************************
tDescriptorHeader *
USBDescGet(tDescriptorHeader *psDesc, uint32_t ui32Size,
uint32_t ui32Type, uint32_t ui32Index)
{
tDescriptorHeader *psDescCheck;
uint32_t ui32TotLength;
uint32_t ui32Count;
//
// Set up for our descriptor counting loop.
//
psDescCheck = psDesc;
ui32TotLength = 0;
ui32Count = 0;
//
// Keep looking through the supplied data until we reach the end.
//
while(ui32TotLength < ui32Size)
{
//
// Does this descriptor match the type passed (if a specific type
// has been specified)?
//
if((ui32Type == USB_DESC_ANY) ||
(psDescCheck->bDescriptorType == (uint8_t)(ui32Type & 0xFF)))
{
//
// We found a matching descriptor. If our count matches the
// supplied index, we are done so return the pointer.
//
if(ui32Count == ui32Index)
{
return(psDescCheck);
}
//
// We have not found enough descriptors yet to satisfy the supplied
// index so increment our count and continue.
//
ui32Count++;
}
//
// Move on to the next descriptor.
//
ui32TotLength += (uint32_t)psDescCheck->bLength;
psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
}
//
// If we get here, we reached the end of the data without finding the
// required descriptor. Return NULL.
//
return((tDescriptorHeader *)0);
}
//*****************************************************************************
//
//! Determines the number of different alternate configurations for a given
//! interface within a configuration descriptor.
//!
//! \param psConfig points to the first byte of a standard USB configuration
//! descriptor.
//! \param ui8InterfaceNumber is the interface number for which the number of
//! alternate configurations is to be counted.
//!
//! This function can be used to count the number of alternate settings for a
//! specific interface within a configuration.
//!
//! \return Returns the number of alternate versions of the specified interface
//! or 0 if the interface number supplied cannot be found in the config
//! descriptor.
//
//*****************************************************************************
uint32_t
USBDescGetNumAlternateInterfaces(tConfigDescriptor *psConfig,
uint8_t ui8InterfaceNumber)
{
tDescriptorHeader *psDescCheck;
uint32_t ui32TotLength;
uint32_t ui32Count;
//
// Set up for our descriptor counting loop.
//
psDescCheck = (tDescriptorHeader *)psConfig;
ui32TotLength = 0;
ui32Count = 0;
//
// Keep looking through the supplied data until we reach the end.
//
while(ui32TotLength < (uint32_t)psConfig->wTotalLength)
{
//
// Is this an interface descriptor with the required interface number?
//
if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
(((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
ui8InterfaceNumber))
{
//
// Yes - increment our count.
//
ui32Count++;
}
//
// Move on to the next descriptor.
//
ui32TotLength += (uint32_t)psDescCheck->bLength;
psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
}
//
// Return the descriptor count to the caller.
//
return(ui32Count);
}
//*****************************************************************************
//
//! Returns a pointer to the n-th interface descriptor in a config descriptor
//! with the supplied interface number.
//!
//! \param psConfig points to the first byte of a standard USB configuration
//! descriptor.
//! \param ui8InterfaceNumber is the interface number of the descriptor that is
//! being queried.
//! \param ui32Index is the zero based index of the descriptor to return.
//!
//! This function returns a pointer to the n-th interface descriptor in the
//! supplied configuration which has the requested interface number. It may be
//! used by a client to retrieve the descriptors for each alternate setting
//! of a given interface within the configuration passed.
//!
//! \return Returns a pointer to the n-th interface descriptor with interface
//! number as specified or NULL of this descriptor does not exist.
//
//*****************************************************************************
static tInterfaceDescriptor *
USBDescGetAlternateInterface(tConfigDescriptor *psConfig,
uint8_t ui8InterfaceNumber,
uint32_t ui32Index)
{
tDescriptorHeader *psDescCheck;
uint32_t ui32TotLength;
uint32_t ui32Count;
//
// Set up for our descriptor counting loop.
//
psDescCheck = (tDescriptorHeader *)psConfig;
ui32TotLength = 0;
ui32Count = 0;
//
// Keep looking through the supplied data until we reach the end.
//
while(ui32TotLength < (uint32_t)psConfig->wTotalLength)
{
//
// Does this descriptor match the type passed (if a specific type
// has been specified)?
//
if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
(((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
ui8InterfaceNumber))
{
//
// This is an interface descriptor for interface
// ui8InterfaceNumber. Determine if this is the n-th one we have
// found and, if so, return its pointer.
//
if(ui32Count == ui32Index)
{
//
// Found it - return the pointer.
//
return((tInterfaceDescriptor *)psDescCheck);
}
//
// Increment our count of matching descriptors found and go back
// to look for another since we have not yet reached the n-th
// match.
//
ui32Count++;
}
//
// Move on to the next descriptor.
//
ui32TotLength += (uint32_t)psDescCheck->bLength;
psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
}
//
// If we drop out the end of the loop, we did not find the requested
// descriptor so return NULL.
//
return((tInterfaceDescriptor *)0);
}
//*****************************************************************************
//
//! Returns a pointer to the n-th interface descriptor in a configuration
//! descriptor that applies to the supplied alternate setting number.
//!
//! \param psConfig points to the first byte of a standard USB configuration
//! descriptor.
//! \param ui32Index is the zero based index of the interface that is to be
//! found. If \e ui32Alt is set to a value other than \b USB_DESC_ANY, this
//! will be equivalent to the interface number being searched for.
//! \param ui32Alt is the alternate setting number which is to be
//! searched for. If this value is \b USB_DESC_ANY, the alternate setting
//! is ignored and all interface descriptors are considered in the search.
//!
//! Return a pointer to the n-th interface descriptor found in the supplied
//! configuration descriptor. If \e ui32Alt is not \b USB_DESC_ANY, only
//! interface descriptors which are part of the supplied alternate setting are
//! considered in the search otherwise all interface descriptors are
//! considered.
//!
//! Note that, although alternate settings can be applied on an interface-by-
//! interface basis, the number of interfaces offered is fixed for a given
//! config descriptor. Hence, this function will correctly find the unique
//! interface descriptor for that interface's alternate setting number
//! \e ui32Alt if \e ui32Index is set to the required interface number and
//! \e ui32Alt is set to a valid alternate setting number for that interface.
//!
//! \return Returns a pointer to the required interface descriptor if
//! found or NULL otherwise.
//
//*****************************************************************************
tInterfaceDescriptor *
USBDescGetInterface(tConfigDescriptor *psConfig, uint32_t ui32Index,
uint32_t ui32Alt)
{
//
// If we are being told to ignore the alternate configuration, this boils
// down to a very simple query.
//
if(ui32Alt == USB_DESC_ANY)
{
//
// Return the ui32Index-th interface descriptor we find in the
// configuration descriptor.
//
return((tInterfaceDescriptor *)USBDescGet(
(tDescriptorHeader *)psConfig,
(uint32_t)psConfig->wTotalLength,
USB_DTYPE_INTERFACE, ui32Index));
}
else
{
//
// In this case, a specific alternate setting number is required.
// Given that interface numbers are zero based indices, we can
// pass the supplied ui32Index parameter directly as the interface
// number to USBDescGetAlternateInterface to retrieve the requested
// interface descriptor pointer.
//
return(USBDescGetAlternateInterface(psConfig, ui32Index, ui32Alt));
}
}
//*****************************************************************************
//
//! Return a pointer to the n-th endpoint descriptor in the supplied
//! interface descriptor.
//!
//! \param psInterface points to the first byte of a standard USB interface
//! descriptor.
//! \param ui32Index is the zero based index of the endpoint that is to be
//! found.
//! \param ui32Size contains the maximum number of bytes that the function may
//! search beyond \e psInterface while looking for the requested endpoint
//! descriptor.
//!
//! Return a pointer to the n-th endpoint descriptor found in the supplied
//! interface descriptor. If the \e ui32Index parameter is invalid (greater
//! than or equal to the bNumEndpoints field of the interface descriptor) or
//! the endpoint cannot be found within \e ui32Size bytes of the interface
//! descriptor pointer, the function will return NULL.
//!
//! Note that, although the USB 2.0 specification states that endpoint
//! descriptors must follow the interface descriptor that they relate to, it
//! also states that device specific descriptors should follow any standard
//! descriptor that they relate to. As a result, we cannot assume that each
//! interface descriptor will be followed by nothing but an ordered list of
//! its own endpoints and, hence, the function needs to be provided \e ui32Size
//! to limit the search range.
//!
//! \return Returns a pointer to the requested endpoint descriptor if
//! found or NULL otherwise.
//
//*****************************************************************************
tEndpointDescriptor *
USBDescGetInterfaceEndpoint(tInterfaceDescriptor *psInterface,
uint32_t ui32Index, uint32_t ui32Size)
{
//
// Is the index passed valid?
//
if(ui32Index >= psInterface->bNumEndpoints)
{
//
// It's out of bounds so return a NULL.
//
return((tEndpointDescriptor *)0);
}
else
{
//
// Endpoint index is valid so find the descriptor.
//
return((tEndpointDescriptor *)USBDescGet(
(tDescriptorHeader *)psInterface,
ui32Size, USB_DTYPE_ENDPOINT, ui32Index));
}
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
|