~ubuntu-branches/ubuntu/oneiric/ndiswrapper/oneiric

« back to all changes in this revision

Viewing changes to driver/usb.c

  • Committer: Bazaar Package Importer
  • Author(s): Herbert Xu
  • Date: 2004-10-02 17:23:29 UTC
  • Revision ID: james.westby@ubuntu.com-20041002172329-5fpy4fmm2x3nz9sg
Tags: upstream-0.10
ImportĀ upstreamĀ versionĀ 0.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2004 Jan Kiszka
 
3
 *
 
4
 *  This program is free software; you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
 
8
 *
 
9
 *  This program is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
 *  GNU General Public License for more details.
 
13
 *
 
14
 */
 
15
 
 
16
#include "ndis.h"
 
17
#include "usb.h"
 
18
 
 
19
 
 
20
LIST_HEAD(completed_irps);
 
21
static spinlock_t completed_irps_lock = SPIN_LOCK_UNLOCKED;
 
22
 
 
23
 
 
24
void usb_transfer_complete_tasklet(unsigned long dummy);
 
25
DECLARE_TASKLET(completed_irps_tasklet, usb_transfer_complete_tasklet, 0);
 
26
 
 
27
 
 
28
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 
29
void usb_transfer_complete(struct urb *urb, struct pt_regs *regs)
 
30
#else
 
31
void usb_transfer_complete(struct urb *urb)
 
32
#endif
 
33
{
 
34
        struct irp *irp = urb->context;
 
35
 
 
36
 
 
37
        TRACEENTER3("urb = %p", urb);
 
38
 
 
39
        spin_lock(&completed_irps_lock);
 
40
        list_add_tail((struct list_head *)&irp->list_entry, &completed_irps);
 
41
        spin_unlock(&completed_irps_lock);
 
42
 
 
43
        tasklet_schedule(&completed_irps_tasklet);
 
44
}
 
45
 
 
46
void usb_transfer_complete_tasklet(unsigned long dummy)
 
47
{
 
48
        struct irp *irp;
 
49
        struct urb *urb;
 
50
        struct io_stack_location *stack;
 
51
        union nt_urb *nt_urb;
 
52
        unsigned long flags;
 
53
        unsigned long result;
 
54
 
 
55
 
 
56
        while (1) {
 
57
                spin_lock_irqsave(&completed_irps_lock, flags);
 
58
 
 
59
                if (list_empty(&completed_irps)) {
 
60
                        spin_unlock_irqrestore(&completed_irps_lock, flags);
 
61
                        TRACEEXIT3(return);
 
62
                }
 
63
                irp = container_of((struct list_entry *)completed_irps.next,
 
64
                        struct irp, list_entry);
 
65
                list_del((struct list_head *)&irp->list_entry);
 
66
 
 
67
                spin_unlock_irqrestore(&completed_irps_lock, flags);
 
68
 
 
69
                urb    = irp->driver_context[3];
 
70
                stack  = irp->current_stack_location-1;
 
71
                nt_urb = stack->params.generic.arg1;
 
72
 
 
73
                DBGTRACE3("irp = %p, urb = %p, status = %d", irp, urb,
 
74
                        urb->status);
 
75
 
 
76
                irp->pending_returned = 1;
 
77
 
 
78
                if (urb->status)
 
79
                        irp->io_status.status = STATUS_FAILURE;
 
80
                else
 
81
                        irp->io_status.status = STATUS_SUCCESS;
 
82
                irp->io_status.status_info = urb->actual_length;
 
83
 
 
84
                if (irp->user_status) {
 
85
                        irp->user_status->status = irp->io_status.status;
 
86
                        irp->user_status->status_info = urb->actual_length;
 
87
                }
 
88
 
 
89
                nt_urb->bulkIntrTrans.transferBufLen = urb->actual_length;
 
90
 
 
91
#ifdef DUMPURBS
 
92
                if ((urb->pipe & USB_DIR_IN)) {
 
93
                        int i;
 
94
 
 
95
                        printk("Receiving ");
 
96
                        for (i = 0; i < urb->actual_length; i++)
 
97
                                printk("%02X ", *(((unsigned char *)
 
98
                                        urb->transfer_buffer)+i));
 
99
                        printk("\n");
 
100
                }
 
101
#endif /* DUMPURBS */
 
102
 
 
103
                if (irp->driver_context[2]) {
 
104
                        if (urb->pipe & USB_DIR_IN)
 
105
                                memcpy(nt_urb->bulkIntrTrans.transferBuf,
 
106
                                        irp->driver_context[2],
 
107
                                        nt_urb->bulkIntrTrans.transferBufLen);
 
108
                        kfree(irp->driver_context[2]);
 
109
                }
 
110
 
 
111
                if ((stack->completion_handler) &&
 
112
                    ((((urb->status == 0) &&
 
113
                       (stack->control & CALL_ON_SUCCESS)) ||
 
114
                      ((urb->status != 0) &&
 
115
                       (stack->control & CALL_ON_ERROR))))) {
 
116
                        DBGTRACE3("calling %p", stack->completion_handler);
 
117
 
 
118
                        result = stack->completion_handler(stack->dev_obj, irp,
 
119
                                stack->handler_arg);
 
120
                        if (result == STATUS_MORE_PROCESSING_REQUIRED) {
 
121
                                usb_free_urb(urb);
 
122
                                continue;
 
123
                        }
 
124
                }
 
125
 
 
126
                if (irp->user_event) {
 
127
                        DBGTRACE3("setting event %p", irp->user_event);
 
128
                        NdisSetEvent((struct ndis_event *)irp->user_event);
 
129
                }
 
130
 
 
131
                /* To-Do: what about IRP_DEALLOCATE_BUFFER...? */
 
132
                DBGTRACE3("freeing irp %p", irp);
 
133
                kfree(irp);
 
134
 
 
135
                usb_free_urb(urb);
 
136
        }
 
137
}
 
138
 
 
139
void STDCALL usb_cancel_transfer(struct device_object *dev_obj,
 
140
                                 struct irp *irp)
 
141
{
 
142
        TRACEENTER3("irp = %p", irp);
 
143
 
 
144
        usb_unlink_urb(irp->driver_context[3]);
 
145
        usb_free_urb(irp->driver_context[3]);
 
146
        if (irp->driver_context[2])
 
147
                kfree(irp->driver_context[2]);
 
148
 
 
149
        TRACEEXIT3(return);
 
150
}
 
151
 
 
152
unsigned long usb_bulk_or_intr_trans(struct usb_device *dev,
 
153
                                     union nt_urb *nt_urb, struct irp *irp)
 
154
{
 
155
        union pipe_handle pipe_handle;
 
156
        struct urb *urb;
 
157
        unsigned int pipe;
 
158
        int ret;
 
159
 
 
160
 
 
161
        ASSERT(!nt_urb->bulkIntrTrans.transferBufMdl);
 
162
        ASSERT(!nt_urb->bulkIntrTrans.urbLink);
 
163
        DBGTRACE3("flags = %lX, length = %lu, buffer = %p",
 
164
                nt_urb->bulkIntrTrans.transferFlags,
 
165
                nt_urb->bulkIntrTrans.transferBufLen,
 
166
                nt_urb->bulkIntrTrans.transferBuf);
 
167
 
 
168
        /* FIXME: we should better check what GFP_ is required */
 
169
        urb = WRAP_ALLOC_URB(0, GFP_ATOMIC);
 
170
        if (!urb)
 
171
                return -ENOMEM;
 
172
 
 
173
        /* store the linux-urb in the nt-irp and set the cancel routine */
 
174
        irp->driver_context[3] = urb;
 
175
        irp->cancel_routine = usb_cancel_transfer;
 
176
 
 
177
        pipe_handle = nt_urb->bulkIntrTrans.pipeHandle;
 
178
        if (pipe_handle.encoded.pipeType == USB_ENDPOINT_XFER_BULK) {
 
179
                if (nt_urb->bulkIntrTrans.transferFlags &
 
180
                    USBD_TRANSFER_DIRECTION_IN)
 
181
                        pipe = usb_rcvbulkpipe(dev,
 
182
                                pipe_handle.encoded.endpointAddr);
 
183
                else
 
184
                        pipe = usb_sndbulkpipe(dev,
 
185
                                pipe_handle.encoded.endpointAddr);
 
186
 
 
187
                usb_fill_bulk_urb(urb, dev, pipe,
 
188
                        nt_urb->bulkIntrTrans.transferBuf,
 
189
                        nt_urb->bulkIntrTrans.transferBufLen,
 
190
                        usb_transfer_complete, irp);
 
191
        } else { /* USB_ENDPOINT_XFER_INT */
 
192
                pipe = usb_rcvintpipe(dev, pipe_handle.encoded.endpointAddr);
 
193
 
 
194
                usb_fill_int_urb(urb, dev, pipe,
 
195
                        nt_urb->bulkIntrTrans.transferBuf,
 
196
                        nt_urb->bulkIntrTrans.transferBufLen,
 
197
                        usb_transfer_complete, irp,
 
198
                        pipe_handle.encoded.interval);
 
199
        }
 
200
        if ((nt_urb->bulkIntrTrans.transferFlags &
 
201
             (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)) ==
 
202
             USBD_TRANSFER_DIRECTION_IN)
 
203
                urb->transfer_flags |= URB_SHORT_NOT_OK;
 
204
 
 
205
#ifdef DUMPURBS
 
206
        if (!(urb->pipe & USB_DIR_IN)) {
 
207
                int i;
 
208
 
 
209
                printk("Sending ");
 
210
                for (i = 0; i < urb->transfer_buffer_length; i++)
 
211
                        printk("%02X ", *(((unsigned char *)urb->transfer_buffer)+i));
 
212
                printk("\n");
 
213
        }
 
214
#endif /* DUMPURBS */
 
215
 
 
216
        /* non-DMA-capable buffers have to be mirrored */
 
217
        irp->driver_context[2] = NULL;
 
218
        if (!virt_addr_valid(nt_urb->bulkIntrTrans.transferBuf)) {
 
219
                irp->driver_context[2] = kmalloc(
 
220
                        nt_urb->bulkIntrTrans.transferBufLen, GFP_ATOMIC);
 
221
                if (!irp->driver_context[2]) {
 
222
                        ERROR("kmalloc failed!");
 
223
                        usb_free_urb(urb);
 
224
                        return -ENOMEM;
 
225
                }
 
226
 
 
227
                if (!(pipe & USB_DIR_IN))
 
228
                        memcpy(irp->driver_context[2],
 
229
                                nt_urb->bulkIntrTrans.transferBuf,
 
230
                                nt_urb->bulkIntrTrans.transferBufLen);
 
231
                urb->transfer_buffer = irp->driver_context[2];
 
232
                DBGTRACE3("mirroring non-DMA buffer");
 
233
        }
 
234
 
 
235
        DBGTRACE3("submitting urb %p on pipe %p", urb, pipe_handle.handle);
 
236
        /* FIXME: we should better check what GFP_ is required */
 
237
        ret = WRAP_SUBMIT_URB(urb, GFP_ATOMIC);
 
238
        if (ret != 0) {
 
239
                ERROR("usb_submit_urb() = %d", ret);
 
240
                usb_free_urb(urb);
 
241
                if (irp->driver_context[2])
 
242
                        kfree(irp->driver_context[2]);
 
243
        }
 
244
        return ret;
 
245
}
 
246
 
 
247
unsigned long usb_reset_pipe(struct usb_device *dev,
 
248
                             union pipe_handle pipe_handle)
 
249
{
 
250
        int pipe;
 
251
 
 
252
 
 
253
        DBGTRACE3("pipe = %p", pipe_handle.handle);
 
254
        switch (pipe_handle.encoded.pipeType) {
 
255
                case USB_ENDPOINT_XFER_CONTROL:
 
256
                        if (pipe_handle.encoded.endpointAddr &
 
257
                            USB_ENDPOINT_DIR_MASK)
 
258
                                pipe = usb_rcvctrlpipe(dev,
 
259
                                        pipe_handle.encoded.endpointAddr);
 
260
                        else
 
261
                                pipe = usb_sndctrlpipe(dev,
 
262
                                        pipe_handle.encoded.endpointAddr);
 
263
                        break;
 
264
 
 
265
                case USB_ENDPOINT_XFER_ISOC:
 
266
                        if (pipe_handle.encoded.endpointAddr &
 
267
                            USB_ENDPOINT_DIR_MASK)
 
268
                                pipe = usb_rcvisocpipe(dev,
 
269
                                        pipe_handle.encoded.endpointAddr);
 
270
                        else
 
271
                                pipe = usb_sndisocpipe(dev,
 
272
                                        pipe_handle.encoded.endpointAddr);
 
273
                        break;
 
274
 
 
275
                case USB_ENDPOINT_XFER_BULK:
 
276
                        if (pipe_handle.encoded.endpointAddr &
 
277
                            USB_ENDPOINT_DIR_MASK)
 
278
                                pipe = usb_rcvbulkpipe(dev,
 
279
                                        pipe_handle.encoded.endpointAddr);
 
280
                        else
 
281
                                pipe = usb_sndbulkpipe(dev,
 
282
                                        pipe_handle.encoded.endpointAddr);
 
283
                        break;
 
284
 
 
285
                default: /* USB_ENDPOINT_XFER_INT */
 
286
                        pipe = usb_rcvintpipe(dev,
 
287
                                pipe_handle.encoded.endpointAddr);
 
288
                        break;
 
289
        }
 
290
 
 
291
        return usb_clear_halt(dev, pipe);
 
292
}
 
293
 
 
294
unsigned long usb_submit_nt_urb(struct usb_device *dev, union nt_urb *nt_urb,
 
295
                                struct irp *irp)
 
296
{
 
297
        struct usb_interface *intf;
 
298
        struct usbd_pipe_information *pipe_info;
 
299
        int i, ret;
 
300
 
 
301
 
 
302
        TRACEENTER3("nt_urb = %p, irp = %p, length = %d, function = %x",
 
303
                nt_urb, irp, nt_urb->header.length, nt_urb->header.function);
 
304
 
 
305
        nt_urb->header.status = USB_STATUS_SUCCESS;
 
306
 
 
307
        switch (nt_urb->header.function) {
 
308
                case FUNC_SELECT_CONFIGURATION:
 
309
                        ASSERT(nt_urb->selConf.config->bNumInterfaces == 1);
 
310
                        DBGTRACE2("intf.intfNum = %d, intf.altSet = %d",
 
311
                                nt_urb->selConf.intf.intfNum,
 
312
                                nt_urb->selConf.intf.altSet);
 
313
 
 
314
                        ret = usb_set_interface(dev,
 
315
                                nt_urb->selConf.intf.intfNum,
 
316
                                nt_urb->selConf.intf.altSet);
 
317
                        if (ret < 0) {
 
318
                                ERROR("usb_set_interface() = %d", ret);
 
319
                                break;
 
320
                        }
 
321
 
 
322
                        intf = usb_ifnum_to_if(dev,
 
323
                                nt_urb->selConf.intf.intfNum);
 
324
                        if (!intf) {
 
325
                                ERROR("usb_ifnum_to_if() = %d", ret);
 
326
                                break;
 
327
                        }
 
328
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 
329
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,5)
 
330
                        for (i = 0;
 
331
                             i < intf->cur_altsetting->desc.bNumEndpoints;
 
332
                             i++) {
 
333
                                struct usb_host_endpoint *endp =
 
334
                                        intf->cur_altsetting->endpoint + i;
 
335
#else /* 2.6.0...2.6.4 */
 
336
                        for (i = 0;
 
337
                             i < intf->altsetting[intf->act_altsetting].desc.bNumEndpoints;
 
338
                             i++) {
 
339
                                struct usb_host_endpoint *endp =
 
340
                                        intf->altsetting[intf->act_altsetting].endpoint + i;
 
341
#endif
 
342
                                pipe_info = &nt_urb->selConf.intf.pipes[i];
 
343
 
 
344
                                pipe_info->maxPacketSize =
 
345
                                        endp->desc.wMaxPacketSize;
 
346
                                pipe_info->endpointAddr =
 
347
                                        endp->desc.bEndpointAddress;
 
348
                                pipe_info->interval = endp->desc.bInterval;
 
349
                                pipe_info->pipeType = endp->desc.bmAttributes;
 
350
 
 
351
                                pipe_info->pipeHandle.encoded.endpointAddr =
 
352
                                        endp->desc.bEndpointAddress;
 
353
                                pipe_info->pipeHandle.encoded.pipeType =
 
354
                                        endp->desc.bmAttributes &
 
355
                                        USB_ENDPOINT_XFERTYPE_MASK;
 
356
                                pipe_info->pipeHandle.encoded.interval =
 
357
                                        (dev->speed == USB_SPEED_HIGH) ?
 
358
                                        endp->desc.bInterval + 3 :
 
359
                                        endp->desc.bInterval;
 
360
                                pipe_info->pipeHandle.encoded.fill = 0;
 
361
 
 
362
                                DBGTRACE3("%i: Addr %X, Type %d, PkSz %d, "
 
363
                                        "Intv %d, Handle %p", i,
 
364
                                        endp->desc.bEndpointAddress,
 
365
                                        endp->desc.bmAttributes,
 
366
                                        endp->desc.wMaxPacketSize,
 
367
                                        endp->desc.bInterval,
 
368
                                        pipe_info->pipeHandle.handle);
 
369
                        }
 
370
#else
 
371
                        for (i = 0; i < intf->altsetting[
 
372
                             intf->act_altsetting].bNumEndpoints; i++) {
 
373
                                struct usb_endpoint_descriptor *desc;
 
374
 
 
375
                                desc = &intf->altsetting[
 
376
                                        intf->act_altsetting].endpoint[i];
 
377
 
 
378
                                pipe_info = &nt_urb->selConf.intf.pipes[i];
 
379
 
 
380
                                pipe_info->maxPacketSize =
 
381
                                        desc->wMaxPacketSize;
 
382
                                pipe_info->endpointAddr =
 
383
                                        desc->bEndpointAddress;
 
384
                                pipe_info->interval = desc->bInterval;
 
385
                                pipe_info->pipeType = desc->bmAttributes;
 
386
 
 
387
                                pipe_info->pipeHandle.encoded.endpointAddr =
 
388
                                        desc->bEndpointAddress;
 
389
                                pipe_info->pipeHandle.encoded.pipeType =
 
390
                                        desc->bmAttributes &
 
391
                                        USB_ENDPOINT_XFERTYPE_MASK;
 
392
                                pipe_info->pipeHandle.encoded.interval =
 
393
                                        (dev->speed == USB_SPEED_HIGH) ?
 
394
                                        desc->bInterval + 3 : desc->bInterval;
 
395
                                pipe_info->pipeHandle.encoded.fill = 0;
 
396
 
 
397
                                DBGTRACE3("%i: Addr %X, Type %d, PkSz %d, "
 
398
                                        "Intv %d, Handle %p", i,
 
399
                                        desc->bEndpointAddress,
 
400
                                        desc->bmAttributes,
 
401
                                        desc->wMaxPacketSize,
 
402
                                        desc->bInterval,
 
403
                                        pipe_info->pipeHandle.handle);
 
404
                        }
 
405
#endif
 
406
                        TRACEEXIT3(return STATUS_SUCCESS);
 
407
 
 
408
                case FUNC_BULK_OR_INTERRUPT_TRANSFER:
 
409
                        ret = usb_bulk_or_intr_trans(dev, nt_urb, irp);
 
410
                        if (ret < 0)
 
411
                                break;
 
412
                        TRACEEXIT3(return STATUS_PENDING);
 
413
 
 
414
                case FUNC_GET_DESCRIPTOR_FROM_DEVICE:
 
415
                        ASSERT(!nt_urb->ctrlDescReq.transferBufMdl);
 
416
                        ASSERT(!nt_urb->ctrlDescReq.urbLink);
 
417
                        DBGTRACE3("desctype = %d, descindex = %d, "
 
418
                                "transferBuf = %p, transferBufLen = %ld",
 
419
                                nt_urb->ctrlDescReq.desctype,
 
420
                                nt_urb->ctrlDescReq.descindex,
 
421
                                nt_urb->ctrlDescReq.transferBuf,
 
422
                                nt_urb->ctrlDescReq.transferBufLen);
 
423
 
 
424
                        ret = usb_get_descriptor(dev,
 
425
                                nt_urb->ctrlDescReq.desctype,
 
426
                                nt_urb->ctrlDescReq.descindex,
 
427
                                nt_urb->ctrlDescReq.transferBuf,
 
428
                                nt_urb->ctrlDescReq.transferBufLen);
 
429
                        if (ret < 0) {
 
430
                                ERROR("usb_get_descriptor() = %d", ret);
 
431
                                break;
 
432
                        }
 
433
                        nt_urb->ctrlDescReq.transferBufLen = ret;
 
434
                        TRACEEXIT3(return STATUS_SUCCESS);
 
435
 
 
436
                case FUNC_RESET_PIPE:
 
437
                        ret = usb_reset_pipe(dev, nt_urb->pipeReq.pipeHandle);
 
438
                        if (ret < 0) {
 
439
                                ERROR("usb_reset_pipe() = %d", ret);
 
440
                                break;
 
441
                        }
 
442
                        TRACEEXIT3(return STATUS_SUCCESS);
 
443
 
 
444
                default:
 
445
                        ERROR("function %X NOT IMPLEMENTED!\n",
 
446
                                nt_urb->header.function);
 
447
        }
 
448
 
 
449
        nt_urb->header.status = USB_STATUS_ERROR;
 
450
        TRACEEXIT3(return STATUS_FAILURE);
 
451
}
 
452
 
 
453
STDCALL union nt_urb *
 
454
USBD_CreateConfigurationRequestEx(struct usb_config_descriptor *config,
 
455
                                  struct usbd_interface_list_entry *intfList)
 
456
{
 
457
        union nt_urb *urb;
 
458
 
 
459
        int urb_size;
 
460
        struct usb_interface_descriptor *intf_desc;
 
461
        struct usbd_interface_information *intf_info;
 
462
 
 
463
 
 
464
        /*
 
465
         * Note: This function is more or less a hack - due to a lack of
 
466
         *       understanding of the underlying USB details. It only sets up
 
467
         *       an URB with one interface inside. This is what the WUSB54G
 
468
         *       driver requests or what the WUSB54G device provides. However,
 
469
         *       this function warns if the assumption is incorrect.
 
470
         */
 
471
 
 
472
        TRACEENTER2("config = %p, intfList = %p", config, intfList);
 
473
        ASSERT(config->bNumInterfaces < 2);
 
474
 
 
475
        intf_desc = intfList->intfDesc;
 
476
        urb_size = sizeof(union nt_urb) +
 
477
                sizeof(struct usbd_pipe_information) *
 
478
                (intf_desc->bNumEndpoints - 1);
 
479
        /* FIXME: we should better check what GFP_ is required */
 
480
        urb = kmalloc(urb_size, GFP_ATOMIC);
 
481
 
 
482
        if (urb) {
 
483
                urb->selConf.header.length   = urb_size;
 
484
                urb->selConf.header.function = FUNC_SELECT_CONFIGURATION;
 
485
                urb->selConf.config          = config;
 
486
 
 
487
                intf_info = &urb->selConf.intf;
 
488
                intfList->intf = intf_info;
 
489
                intf_info->length = sizeof(struct usbd_interface_information)+
 
490
                        sizeof(struct usbd_pipe_information) *
 
491
                        (intf_desc->bNumEndpoints - 1);
 
492
                intf_info->intfNum  = intf_desc->bInterfaceNumber;
 
493
                intf_info->altSet   = intf_desc->bAlternateSetting;
 
494
                intf_info->class    = intf_desc->bInterfaceClass;
 
495
                intf_info->subClass = intf_desc->bInterfaceSubClass;
 
496
                intf_info->proto    = intf_desc->bInterfaceProtocol;
 
497
                intf_info->pipeNum  = intf_desc->bNumEndpoints;
 
498
 
 
499
                ASSERT(!(intfList+1)->intfDesc);
 
500
        }
 
501
 
 
502
        TRACEEXIT2(return urb);
 
503
}
 
504
 
 
505
STDCALL struct usb_interface_descriptor *
 
506
USBD_ParseConfigurationDescriptorEx(struct usb_config_descriptor *config,
 
507
                                    void *startPos, long intfNum, long altSet,
 
508
                                    long intfClass, long intfSubClass,
 
509
                                    long intfProto)
 
510
{
 
511
        int size = config->wTotalLength;
 
512
        char *pos = startPos;
 
513
        struct usb_interface_descriptor *intf;
 
514
 
 
515
 
 
516
        TRACEENTER2("config = %p, startPos = %p, intfNum = %ld, altSet = %ld,"
 
517
                " intfClass = %ld, intfSubClass = %ld, intfProto = %ld",
 
518
                config, startPos, intfNum, altSet, intfClass, intfSubClass,
 
519
                intfProto);
 
520
 
 
521
        while ((char *)pos - (char *)config < size) {
 
522
                intf = (struct usb_interface_descriptor *)pos;
 
523
                pos = pos + intf->bLength;
 
524
 
 
525
                if (intf->bDescriptorType != USB_DT_INTERFACE)
 
526
                        continue;
 
527
                if ((intfNum != -1) && (intf->bInterfaceNumber != intfNum))
 
528
                        continue;
 
529
                if ((altSet != -1) && (intf->bAlternateSetting != altSet))
 
530
                        continue;
 
531
                if ((intfClass != -1) && (intf->bInterfaceClass != intfClass))
 
532
                        continue;
 
533
                if ((intfSubClass != -1) &&
 
534
                    (intf->bInterfaceSubClass != intfSubClass))
 
535
                        continue;
 
536
                if ((intfProto != -1) &&
 
537
                    (intf->bInterfaceProtocol != intfProto))
 
538
                        continue;
 
539
 
 
540
                DBGTRACE2("selected interface = %p", intf);
 
541
                TRACEEXIT2(return intf);
 
542
        }
 
543
 
 
544
        TRACEEXIT2(return NULL);
 
545
}
 
546
 
 
547
struct wrap_func usb_wrap_funcs[] =
 
548
{
 
549
        WRAP_FUNC_ENTRY(USBD_CreateConfigurationRequestEx),
 
550
        WRAP_FUNC_ENTRY(USBD_ParseConfigurationDescriptorEx),
 
551
        {"_USBD_CreateConfigurationRequestEx@8",
 
552
         (WRAP_FUNC *)USBD_CreateConfigurationRequestEx},
 
553
        {"_USBD_ParseConfigurationDescriptorEx@28",
 
554
         (WRAP_FUNC *)USBD_ParseConfigurationDescriptorEx},
 
555
        {NULL, NULL}
 
556
};