2
* Copyright (C) 2004 Jan Kiszka
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.
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.
20
LIST_HEAD(completed_irps);
21
static spinlock_t completed_irps_lock = SPIN_LOCK_UNLOCKED;
24
void usb_transfer_complete_tasklet(unsigned long dummy);
25
DECLARE_TASKLET(completed_irps_tasklet, usb_transfer_complete_tasklet, 0);
28
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
29
void usb_transfer_complete(struct urb *urb, struct pt_regs *regs)
31
void usb_transfer_complete(struct urb *urb)
34
struct irp *irp = urb->context;
37
TRACEENTER3("urb = %p", urb);
39
spin_lock(&completed_irps_lock);
40
list_add_tail((struct list_head *)&irp->list_entry, &completed_irps);
41
spin_unlock(&completed_irps_lock);
43
tasklet_schedule(&completed_irps_tasklet);
46
void usb_transfer_complete_tasklet(unsigned long dummy)
50
struct io_stack_location *stack;
57
spin_lock_irqsave(&completed_irps_lock, flags);
59
if (list_empty(&completed_irps)) {
60
spin_unlock_irqrestore(&completed_irps_lock, flags);
63
irp = container_of((struct list_entry *)completed_irps.next,
64
struct irp, list_entry);
65
list_del((struct list_head *)&irp->list_entry);
67
spin_unlock_irqrestore(&completed_irps_lock, flags);
69
urb = irp->driver_context[3];
70
stack = irp->current_stack_location-1;
71
nt_urb = stack->params.generic.arg1;
73
DBGTRACE3("irp = %p, urb = %p, status = %d", irp, urb,
76
irp->pending_returned = 1;
79
irp->io_status.status = STATUS_FAILURE;
81
irp->io_status.status = STATUS_SUCCESS;
82
irp->io_status.status_info = urb->actual_length;
84
if (irp->user_status) {
85
irp->user_status->status = irp->io_status.status;
86
irp->user_status->status_info = urb->actual_length;
89
nt_urb->bulkIntrTrans.transferBufLen = urb->actual_length;
92
if ((urb->pipe & USB_DIR_IN)) {
96
for (i = 0; i < urb->actual_length; i++)
97
printk("%02X ", *(((unsigned char *)
98
urb->transfer_buffer)+i));
101
#endif /* DUMPURBS */
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]);
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);
118
result = stack->completion_handler(stack->dev_obj, irp,
120
if (result == STATUS_MORE_PROCESSING_REQUIRED) {
126
if (irp->user_event) {
127
DBGTRACE3("setting event %p", irp->user_event);
128
NdisSetEvent((struct ndis_event *)irp->user_event);
131
/* To-Do: what about IRP_DEALLOCATE_BUFFER...? */
132
DBGTRACE3("freeing irp %p", irp);
139
void STDCALL usb_cancel_transfer(struct device_object *dev_obj,
142
TRACEENTER3("irp = %p", irp);
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]);
152
unsigned long usb_bulk_or_intr_trans(struct usb_device *dev,
153
union nt_urb *nt_urb, struct irp *irp)
155
union pipe_handle pipe_handle;
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);
168
/* FIXME: we should better check what GFP_ is required */
169
urb = WRAP_ALLOC_URB(0, GFP_ATOMIC);
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;
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);
184
pipe = usb_sndbulkpipe(dev,
185
pipe_handle.encoded.endpointAddr);
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);
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);
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;
206
if (!(urb->pipe & USB_DIR_IN)) {
210
for (i = 0; i < urb->transfer_buffer_length; i++)
211
printk("%02X ", *(((unsigned char *)urb->transfer_buffer)+i));
214
#endif /* DUMPURBS */
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!");
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");
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);
239
ERROR("usb_submit_urb() = %d", ret);
241
if (irp->driver_context[2])
242
kfree(irp->driver_context[2]);
247
unsigned long usb_reset_pipe(struct usb_device *dev,
248
union pipe_handle pipe_handle)
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);
261
pipe = usb_sndctrlpipe(dev,
262
pipe_handle.encoded.endpointAddr);
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);
271
pipe = usb_sndisocpipe(dev,
272
pipe_handle.encoded.endpointAddr);
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);
281
pipe = usb_sndbulkpipe(dev,
282
pipe_handle.encoded.endpointAddr);
285
default: /* USB_ENDPOINT_XFER_INT */
286
pipe = usb_rcvintpipe(dev,
287
pipe_handle.encoded.endpointAddr);
291
return usb_clear_halt(dev, pipe);
294
unsigned long usb_submit_nt_urb(struct usb_device *dev, union nt_urb *nt_urb,
297
struct usb_interface *intf;
298
struct usbd_pipe_information *pipe_info;
302
TRACEENTER3("nt_urb = %p, irp = %p, length = %d, function = %x",
303
nt_urb, irp, nt_urb->header.length, nt_urb->header.function);
305
nt_urb->header.status = USB_STATUS_SUCCESS;
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);
314
ret = usb_set_interface(dev,
315
nt_urb->selConf.intf.intfNum,
316
nt_urb->selConf.intf.altSet);
318
ERROR("usb_set_interface() = %d", ret);
322
intf = usb_ifnum_to_if(dev,
323
nt_urb->selConf.intf.intfNum);
325
ERROR("usb_ifnum_to_if() = %d", ret);
328
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
329
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,5)
331
i < intf->cur_altsetting->desc.bNumEndpoints;
333
struct usb_host_endpoint *endp =
334
intf->cur_altsetting->endpoint + i;
335
#else /* 2.6.0...2.6.4 */
337
i < intf->altsetting[intf->act_altsetting].desc.bNumEndpoints;
339
struct usb_host_endpoint *endp =
340
intf->altsetting[intf->act_altsetting].endpoint + i;
342
pipe_info = &nt_urb->selConf.intf.pipes[i];
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;
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;
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);
371
for (i = 0; i < intf->altsetting[
372
intf->act_altsetting].bNumEndpoints; i++) {
373
struct usb_endpoint_descriptor *desc;
375
desc = &intf->altsetting[
376
intf->act_altsetting].endpoint[i];
378
pipe_info = &nt_urb->selConf.intf.pipes[i];
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;
387
pipe_info->pipeHandle.encoded.endpointAddr =
388
desc->bEndpointAddress;
389
pipe_info->pipeHandle.encoded.pipeType =
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;
397
DBGTRACE3("%i: Addr %X, Type %d, PkSz %d, "
398
"Intv %d, Handle %p", i,
399
desc->bEndpointAddress,
401
desc->wMaxPacketSize,
403
pipe_info->pipeHandle.handle);
406
TRACEEXIT3(return STATUS_SUCCESS);
408
case FUNC_BULK_OR_INTERRUPT_TRANSFER:
409
ret = usb_bulk_or_intr_trans(dev, nt_urb, irp);
412
TRACEEXIT3(return STATUS_PENDING);
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);
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);
430
ERROR("usb_get_descriptor() = %d", ret);
433
nt_urb->ctrlDescReq.transferBufLen = ret;
434
TRACEEXIT3(return STATUS_SUCCESS);
436
case FUNC_RESET_PIPE:
437
ret = usb_reset_pipe(dev, nt_urb->pipeReq.pipeHandle);
439
ERROR("usb_reset_pipe() = %d", ret);
442
TRACEEXIT3(return STATUS_SUCCESS);
445
ERROR("function %X NOT IMPLEMENTED!\n",
446
nt_urb->header.function);
449
nt_urb->header.status = USB_STATUS_ERROR;
450
TRACEEXIT3(return STATUS_FAILURE);
453
STDCALL union nt_urb *
454
USBD_CreateConfigurationRequestEx(struct usb_config_descriptor *config,
455
struct usbd_interface_list_entry *intfList)
460
struct usb_interface_descriptor *intf_desc;
461
struct usbd_interface_information *intf_info;
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.
472
TRACEENTER2("config = %p, intfList = %p", config, intfList);
473
ASSERT(config->bNumInterfaces < 2);
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);
483
urb->selConf.header.length = urb_size;
484
urb->selConf.header.function = FUNC_SELECT_CONFIGURATION;
485
urb->selConf.config = config;
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;
499
ASSERT(!(intfList+1)->intfDesc);
502
TRACEEXIT2(return urb);
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,
511
int size = config->wTotalLength;
512
char *pos = startPos;
513
struct usb_interface_descriptor *intf;
516
TRACEENTER2("config = %p, startPos = %p, intfNum = %ld, altSet = %ld,"
517
" intfClass = %ld, intfSubClass = %ld, intfProto = %ld",
518
config, startPos, intfNum, altSet, intfClass, intfSubClass,
521
while ((char *)pos - (char *)config < size) {
522
intf = (struct usb_interface_descriptor *)pos;
523
pos = pos + intf->bLength;
525
if (intf->bDescriptorType != USB_DT_INTERFACE)
527
if ((intfNum != -1) && (intf->bInterfaceNumber != intfNum))
529
if ((altSet != -1) && (intf->bAlternateSetting != altSet))
531
if ((intfClass != -1) && (intf->bInterfaceClass != intfClass))
533
if ((intfSubClass != -1) &&
534
(intf->bInterfaceSubClass != intfSubClass))
536
if ((intfProto != -1) &&
537
(intf->bInterfaceProtocol != intfProto))
540
DBGTRACE2("selected interface = %p", intf);
541
TRACEEXIT2(return intf);
544
TRACEEXIT2(return NULL);
547
struct wrap_func usb_wrap_funcs[] =
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},