Subversion Repositories shark

Rev

Rev 846 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
846 giacomo 1
#include <linuxcomp.h>
2
#include <linux/usb.h>
3
#include <linux/module.h>
4
#include <linux/init.h>
5
#include <linux/slab.h>
6
#include <asm/byteorder.h>
7
 
8
 
9
#define USB_MAXALTSETTING               128     /* Hard limit */
10
#define USB_MAXENDPOINTS                30      /* Hard limit */
11
 
12
/* these maximums are arbitrary */
13
#define USB_MAXCONFIG                   8
14
#define USB_MAXINTERFACES               32
15
 
16
static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size)
17
{
18
        unsigned char *buffer0 = buffer;
19
        struct usb_descriptor_header *header;
20
        unsigned char *begin;
21
        int numskipped;
22
 
23
        header = (struct usb_descriptor_header *)buffer;
24
        if (header->bDescriptorType != USB_DT_ENDPOINT) {
25
                warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X",
26
                        header->bDescriptorType, USB_DT_ENDPOINT);
27
                return -EINVAL;
28
        }
29
 
30
        if (header->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE)
31
                memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
32
        else if (header->bLength >= USB_DT_ENDPOINT_SIZE)
33
                memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE);
34
        else {
35
                warn("invalid endpoint descriptor");
36
                return -EINVAL;
37
        }
38
 
39
        if ((endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK) >= 16) {
40
                warn("invalid endpoint address 0x%X",
41
                    endpoint->desc.bEndpointAddress);
42
                return -EINVAL;
43
        }
44
 
45
        le16_to_cpus(&endpoint->desc.wMaxPacketSize);
46
 
47
        buffer += header->bLength;
48
        size -= header->bLength;
49
 
50
        /* Skip over any Class Specific or Vendor Specific descriptors */
51
        begin = buffer;
52
        numskipped = 0;
53
        while (size >= sizeof(struct usb_descriptor_header)) {
54
                header = (struct usb_descriptor_header *)buffer;
55
 
56
                /* If we find another "proper" descriptor then we're done  */
57
                if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
58
                    (header->bDescriptorType == USB_DT_INTERFACE))
59
                        break;
60
 
61
                dbg("skipping descriptor 0x%X", header->bDescriptorType);
62
                numskipped++;
63
 
64
                buffer += header->bLength;
65
                size -= header->bLength;
66
        }
67
        if (numskipped) {
68
                dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
69
                endpoint->extra = begin;
70
                endpoint->extralen = buffer - begin;
71
        }
72
 
73
        return buffer - buffer0;
74
}
75
 
76
static void usb_release_intf(struct device *dev)
77
{
78
        struct usb_interface *intf;
79
        int j;
80
 
81
        intf = to_usb_interface(dev);
82
 
83
        if (intf->altsetting) {
84
                for (j = 0; j < intf->num_altsetting; j++) {
85
                        struct usb_host_interface *as = &intf->altsetting[j];
86
 
87
                        kfree(as->endpoint);
88
                }
89
                kfree(intf->altsetting);
90
        }
91
        kfree(intf);
92
}
93
 
94
static int usb_parse_interface(struct usb_host_config *config, unsigned char *buffer, int size)
95
{
96
        unsigned char *buffer0 = buffer;
97
        struct usb_interface_descriptor *d;
98
        int inum, asnum;
99
        struct usb_interface *interface;
100
        struct usb_host_interface *ifp;
101
        int len, numskipped;
102
        struct usb_descriptor_header *header;
103
        unsigned char *begin;
104
        int i, retval;
105
 
106
        d = (struct usb_interface_descriptor *) buffer;
107
        if (d->bDescriptorType != USB_DT_INTERFACE) {
108
                warn("unexpected descriptor 0x%X, expecting interface, 0x%X",
109
                        d->bDescriptorType, USB_DT_INTERFACE);
110
                return -EINVAL;
111
        }
112
 
113
        inum = d->bInterfaceNumber;
114
        if (inum >= config->desc.bNumInterfaces) {
115
 
116
                /* Skip to the next interface descriptor */
117
                buffer += d->bLength;
118
                size -= d->bLength;
119
                while (size >= sizeof(struct usb_descriptor_header)) {
120
                        header = (struct usb_descriptor_header *) buffer;
121
 
122
                        if (header->bDescriptorType == USB_DT_INTERFACE)
123
                                break;
124
                        buffer += header->bLength;
125
                        size -= header->bLength;
126
                }
127
                return buffer - buffer0;
128
        }
129
 
130
        interface = config->interface[inum];
131
        asnum = d->bAlternateSetting;
132
        if (asnum >= interface->num_altsetting) {
133
                warn("invalid alternate setting %d for interface %d",
134
                    asnum, inum);
135
                return -EINVAL;
136
        }
137
 
138
        ifp = &interface->altsetting[asnum];
139
        if (ifp->desc.bLength) {
140
                warn("duplicate descriptor for interface %d altsetting %d",
141
                    inum, asnum);
142
                return -EINVAL;
143
        }
144
        memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
145
 
146
        buffer += d->bLength;
147
        size -= d->bLength;
148
 
149
        /* Skip over any Class Specific or Vendor Specific descriptors */
150
        begin = buffer;
151
        numskipped = 0;
152
        while (size >= sizeof(struct usb_descriptor_header)) {
153
                header = (struct usb_descriptor_header *)buffer;
154
 
155
                /* If we find another "proper" descriptor then we're done  */
156
                if ((header->bDescriptorType == USB_DT_INTERFACE) ||
157
                    (header->bDescriptorType == USB_DT_ENDPOINT))
158
                        break;
159
 
160
                dbg("skipping descriptor 0x%X", header->bDescriptorType);
161
                numskipped++;
162
 
163
                buffer += header->bLength;
164
                size -= header->bLength;
165
        }
166
        if (numskipped) {
167
                dbg("skipped %d class/vendor specific interface descriptors", numskipped);
168
                ifp->extra = begin;
169
                ifp->extralen = buffer - begin;
170
        }
171
 
172
        if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
173
                warn("too many endpoints for interface %d altsetting %d",
174
                    inum, asnum);
175
                return -EINVAL;
176
        }
177
 
178
        len = ifp->desc.bNumEndpoints * sizeof(struct usb_host_endpoint);
179
        ifp->endpoint = kmalloc(len, GFP_KERNEL);
180
        if (!ifp->endpoint) {
181
                err("out of memory");
182
                return -ENOMEM;
183
        }
184
        memset(ifp->endpoint, 0, len);
185
 
186
        for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
187
                if (size < USB_DT_ENDPOINT_SIZE) {
188
                        warn("ran out of descriptors while parsing endpoints");
189
                        return -EINVAL;
190
                }
191
 
192
                retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
193
                if (retval < 0)
194
                        return retval;
195
 
196
                buffer += retval;
197
                size -= retval;
198
        }
199
 
200
        return buffer - buffer0;
201
}
202
 
203
int usb_parse_configuration(struct usb_host_config *config, char *buffer, int size)
204
{
205
        int nintf, nintf_orig;
206
        int i, j;
207
        struct usb_interface *interface;
208
        char *buffer2;
209
        int size2;
210
        struct usb_descriptor_header *header;
211
        int numskipped, len;
212
        char *begin;
213
        int retval;
214
 
215
        memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
216
        if (config->desc.bDescriptorType != USB_DT_CONFIG ||
217
            config->desc.bLength < USB_DT_CONFIG_SIZE) {
218
                warn("invalid configuration descriptor");
219
                return -EINVAL;
220
        }
221
        config->desc.wTotalLength = size;
222
 
223
        nintf = nintf_orig = config->desc.bNumInterfaces;
224
        if (nintf > USB_MAXINTERFACES) {
225
                warn("too many interfaces (%d max %d)",
226
                    nintf, USB_MAXINTERFACES);
227
                config->desc.bNumInterfaces = nintf = USB_MAXINTERFACES;
228
        }
229
 
230
        for (i = 0; i < nintf; ++i) {
231
                interface = config->interface[i] =
232
                    kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
233
                dbg("kmalloc IF %p, numif %i", interface, i);
234
                if (!interface) {
235
                        err("out of memory");
236
                        return -ENOMEM;
237
                }
238
                memset(interface, 0, sizeof(struct usb_interface));
239
                interface->dev.release = usb_release_intf;
240
                device_initialize(&interface->dev);
241
        }
242
 
243
        /* Go through the descriptors, checking their length and counting the
244
         * number of altsettings for each interface */
245
        buffer2 = buffer;
246
        size2 = size;
247
        j = 0;
248
        while (size2 >= sizeof(struct usb_descriptor_header)) {
249
                header = (struct usb_descriptor_header *) buffer2;
250
                if ((header->bLength > size2) || (header->bLength < 2)) {
251
                        warn("invalid descriptor of length %d", header->bLength);
252
                        return -EINVAL;
253
                }
254
 
255
                if (header->bDescriptorType == USB_DT_INTERFACE) {
256
                        struct usb_interface_descriptor *d;
257
 
258
                        if (header->bLength < USB_DT_INTERFACE_SIZE) {
259
                                warn("invalid interface descriptor");
260
                                return -EINVAL;
261
                        }
262
                        d = (struct usb_interface_descriptor *) header;
263
                        i = d->bInterfaceNumber;
264
                        if (i >= nintf_orig) {
265
                                warn("invalid interface number (%d/%d)",
266
                                    i, nintf_orig);
267
                                return -EINVAL;
268
                        }
269
                        if (i < nintf)
270
                                ++config->interface[i]->num_altsetting;
271
 
272
                } else if ((header->bDescriptorType == USB_DT_DEVICE ||
273
                    header->bDescriptorType == USB_DT_CONFIG) && j) {
274
                        warn("unexpected descriptor type 0x%X", header->bDescriptorType);
275
                        return -EINVAL;
276
                }
277
 
278
                j = 1;
279
                buffer2 += header->bLength;
280
                size2 -= header->bLength;
281
        }
282
 
283
        /* Allocate the altsetting arrays */
284
        for (i = 0; i < config->desc.bNumInterfaces; ++i) {
285
                interface = config->interface[i];
286
                if (interface->num_altsetting > USB_MAXALTSETTING) {
287
                        warn("too many alternate settings for interface %d (%d max %d)\n",
288
                            i, interface->num_altsetting, USB_MAXALTSETTING);
289
                        return -EINVAL;
290
                }
291
                if (interface->num_altsetting == 0) {
292
                        warn("no alternate settings for interface %d", i);
293
                        return -EINVAL;
294
                }
295
 
296
                len = sizeof(*interface->altsetting) * interface->num_altsetting;
297
                interface->altsetting = kmalloc(len, GFP_KERNEL);
298
                if (!interface->altsetting) {
299
                        err("couldn't kmalloc interface->altsetting");
300
                        return -ENOMEM;
301
                }
302
                memset(interface->altsetting, 0, len);
303
        }
304
 
305
        buffer += config->desc.bLength;
306
        size -= config->desc.bLength;
307
 
308
        /* Skip over any Class Specific or Vendor Specific descriptors */
309
        begin = buffer;
310
        numskipped = 0;
311
        while (size >= sizeof(struct usb_descriptor_header)) {
312
                header = (struct usb_descriptor_header *)buffer;
313
 
314
                /* If we find another "proper" descriptor then we're done  */
315
                if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
316
                    (header->bDescriptorType == USB_DT_INTERFACE))
317
                        break;
318
 
319
                dbg("skipping descriptor 0x%X", header->bDescriptorType);
320
                numskipped++;
321
 
322
                buffer += header->bLength;
323
                size -= header->bLength;
324
        }
325
        if (numskipped) {
326
                dbg("skipped %d class/vendor specific configuration descriptors", numskipped);
327
                config->extra = begin;
328
                config->extralen = buffer - begin;
329
        }
330
 
331
        /* Parse all the interface/altsetting descriptors */
332
        while (size >= sizeof(struct usb_descriptor_header)) {
333
                retval = usb_parse_interface(config, buffer, size);
334
                if (retval < 0)
335
                        return retval;
336
 
337
                buffer += retval;
338
                size -= retval;
339
        }
340
 
341
        /* Check for missing altsettings */
342
        for (i = 0; i < nintf; ++i) {
343
                interface = config->interface[i];
344
                for (j = 0; j < interface->num_altsetting; ++j) {
345
                        if (!interface->altsetting[j].desc.bLength) {
346
                                warn("missing altsetting %d for interface %d", j, i);
347
                                return -EINVAL;
348
                        }
349
                }
350
        }
351
 
352
        return size;
353
}
354
 
355
// hub-only!! ... and only exported for reset/reinit path.
356
// otherwise used internally on disconnect/destroy path
357
void usb_destroy_configuration(struct usb_device *dev)
358
{
359
        int c, i;
360
 
361
        if (!dev->config)
362
                return;
363
 
364
        if (dev->rawdescriptors) {
365
                for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
366
                        kfree(dev->rawdescriptors[i]);
367
 
368
                kfree(dev->rawdescriptors);
369
        }
370
 
371
        for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
372
                struct usb_host_config *cf = &dev->config[c];
373
 
374
                for (i = 0; i < cf->desc.bNumInterfaces; i++) {
375
                        struct usb_interface *ifp = cf->interface[i];
376
 
377
                        if (ifp)
378
                                put_device(&ifp->dev);
379
                }
380
        }
381
        kfree(dev->config);
382
}
383
 
384
 
385
// hub-only!! ... and only in reset path, or usb_new_device()
386
// (used by real hubs and virtual root hubs)
387
int usb_get_configuration(struct usb_device *dev)
388
{
389
        int ncfg = dev->descriptor.bNumConfigurations;
390
        int result;
391
        unsigned int cfgno, length;
392
        unsigned char *buffer;
393
        unsigned char *bigbuffer;
394
        struct usb_config_descriptor *desc;
395
 
396
        if (ncfg > USB_MAXCONFIG) {
397
                warn("too many configurations (%d max %d)",
398
                    ncfg, USB_MAXCONFIG);
399
                dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
400
        }
401
 
402
        if (ncfg < 1) {
403
                warn("no configurations");
404
                return -EINVAL;
405
        }
406
 
407
        length = ncfg * sizeof(struct usb_host_config);
408
        dev->config = kmalloc(length, GFP_KERNEL);
409
        if (!dev->config) {
410
                err("out of memory");
411
                return -ENOMEM;
412
        }
413
        memset(dev->config, 0, length);
414
 
415
        length = ncfg * sizeof(char *);
416
        dev->rawdescriptors = kmalloc(length, GFP_KERNEL);
417
        if (!dev->rawdescriptors) {
418
                err("out of memory");
419
                return -ENOMEM;
420
        }
421
        memset(dev->rawdescriptors, 0, length);
422
 
423
        buffer = kmalloc(8, GFP_KERNEL);
424
        if (!buffer) {
425
                err("unable to allocate memory for configuration descriptors");
426
                return -ENOMEM;
427
        }
428
        desc = (struct usb_config_descriptor *)buffer;
429
 
430
        for (cfgno = 0; cfgno < ncfg; cfgno++) {
431
                /* We grab the first 8 bytes so we know how long the whole */
432
                /*  configuration is */
433
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
434
                if (result < 8) {
435
                        if (result < 0)
436
                                err("unable to get descriptor");
437
                        else {
438
                                warn("config descriptor too short (expected %i, got %i)", 8, result);
439
                                result = -EINVAL;
440
                        }
441
                        goto err;
442
                }
443
 
444
                /* Get the full buffer */
445
                length = max((int) le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE);
446
 
447
                bigbuffer = kmalloc(length, GFP_KERNEL);
448
                if (!bigbuffer) {
449
                        err("unable to allocate memory for configuration descriptors");
450
                        result = -ENOMEM;
451
                        goto err;
452
                }
453
 
454
                /* Now that we know the length, get the whole thing */
455
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
456
                if (result < 0) {
457
                        err("couldn't get all of config descriptors");
458
                        kfree(bigbuffer);
459
                        goto err;
460
                }
461
 
462
                if (result < length) {
463
                        err("config descriptor too short (expected %i, got %i)", length, result);
464
                        result = -EINVAL;
465
                        kfree(bigbuffer);
466
                        goto err;
467
                }
468
 
469
                dev->rawdescriptors[cfgno] = bigbuffer;
470
 
471
                result = usb_parse_configuration(&dev->config[cfgno], bigbuffer, length);
472
                if (result > 0)
473
                        dbg("descriptor data left");
474
                else if (result < 0) {
475
                        ++cfgno;
476
                        goto err;
477
                }
478
        }
479
 
480
        kfree(buffer);
481
        return 0;
482
err:
483
        kfree(buffer);
484
        dev->descriptor.bNumConfigurations = cfgno;
485
        return result;
486
}
487