-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
V4L/DVB (4645): Added new file for multiple input rewrite
Forgot to add usb-urb.c which is new after adding support for multiple inputs Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
- Loading branch information
Patrick Boettcher
authored and
Mauro Carvalho Chehab
committed
Oct 3, 2006
1 parent
c19da7e
commit 6870ab5
Showing
1 changed file
with
242 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
/* usb-urb.c is part of the DVB USB library. | ||
* | ||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) | ||
* see dvb-usb-init.c for copyright information. | ||
* | ||
* This file keeps functions for initializing and handling the | ||
* BULK and ISOC USB data transfers in a generic way. | ||
* Can be used for DVB-only and also, that's the plan, for | ||
* Hybrid USB devices (analog and DVB). | ||
*/ | ||
#include "dvb-usb-common.h" | ||
|
||
/* URB stuff for streaming */ | ||
static void usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) | ||
{ | ||
struct usb_data_stream *stream = urb->context; | ||
int ptype = usb_pipetype(urb->pipe); | ||
int i; | ||
u8 *b; | ||
|
||
deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", | ||
ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", | ||
urb->status,urb->actual_length,urb->transfer_buffer_length, | ||
urb->number_of_packets,urb->error_count); | ||
|
||
switch (urb->status) { | ||
case 0: /* success */ | ||
case -ETIMEDOUT: /* NAK */ | ||
break; | ||
case -ECONNRESET: /* kill */ | ||
case -ENOENT: | ||
case -ESHUTDOWN: | ||
return; | ||
default: /* error */ | ||
deb_ts("urb completition error %d.\n", urb->status); | ||
break; | ||
} | ||
|
||
b = (u8 *) urb->transfer_buffer; | ||
switch (ptype) { | ||
case PIPE_ISOCHRONOUS: | ||
for (i = 0; i < urb->number_of_packets; i++) { | ||
|
||
if (urb->iso_frame_desc[i].status != 0) | ||
deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); | ||
else if (urb->iso_frame_desc[i].actual_length > 0) | ||
stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); | ||
|
||
urb->iso_frame_desc[i].status = 0; | ||
urb->iso_frame_desc[i].actual_length = 0; | ||
} | ||
debug_dump(b,20,deb_uxfer); | ||
break; | ||
case PIPE_BULK: | ||
if (urb->actual_length > 0) | ||
stream->complete(stream, b, urb->actual_length); | ||
break; | ||
default: | ||
err("unkown endpoint type in completition handler."); | ||
return; | ||
} | ||
usb_submit_urb(urb,GFP_ATOMIC); | ||
} | ||
|
||
int usb_urb_kill(struct usb_data_stream *stream) | ||
{ | ||
int i; | ||
for (i = 0; i < stream->urbs_submitted; i++) { | ||
deb_ts("killing URB no. %d.\n",i); | ||
|
||
/* stop the URB */ | ||
usb_kill_urb(stream->urb_list[i]); | ||
} | ||
stream->urbs_submitted = 0; | ||
return 0; | ||
} | ||
|
||
int usb_urb_submit(struct usb_data_stream *stream) | ||
{ | ||
int i,ret; | ||
for (i = 0; i < stream->urbs_initialized; i++) { | ||
deb_ts("submitting URB no. %d\n",i); | ||
if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { | ||
err("could not submit URB no. %d - get them all back",i); | ||
usb_urb_kill(stream); | ||
return ret; | ||
} | ||
stream->urbs_submitted++; | ||
} | ||
return 0; | ||
} | ||
|
||
static int usb_free_stream_buffers(struct usb_data_stream *stream) | ||
{ | ||
if (stream->state & USB_STATE_URB_BUF) { | ||
while (stream->buf_num) { | ||
stream->buf_num--; | ||
deb_mem("freeing buffer %d\n",stream->buf_num); | ||
usb_buffer_free(stream->udev, stream->buf_size, | ||
stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]); | ||
} | ||
} | ||
|
||
stream->state &= ~USB_STATE_URB_BUF; | ||
|
||
return 0; | ||
} | ||
|
||
static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) | ||
{ | ||
stream->buf_num = 0; | ||
stream->buf_size = size; | ||
|
||
deb_mem("all in all I will use %lu bytes for streaming\n",num*size); | ||
|
||
for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { | ||
deb_mem("allocating buffer %d\n",stream->buf_num); | ||
if (( stream->buf_list[stream->buf_num] = | ||
usb_buffer_alloc(stream->udev, size, SLAB_ATOMIC, | ||
&stream->dma_addr[stream->buf_num]) ) == NULL) { | ||
deb_mem("not enough memory for urb-buffer allocation.\n"); | ||
usb_free_stream_buffers(stream); | ||
return -ENOMEM; | ||
} | ||
deb_mem("buffer %d: %p (dma: %ld)\n", | ||
stream->buf_num, stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]); | ||
memset(stream->buf_list[stream->buf_num],0,size); | ||
stream->state |= USB_STATE_URB_BUF; | ||
} | ||
deb_mem("allocation successful\n"); | ||
|
||
return 0; | ||
} | ||
|
||
static int usb_bulk_urb_init(struct usb_data_stream *stream) | ||
{ | ||
int i; | ||
|
||
if ((i = usb_allocate_stream_buffers(stream,stream->props.count, | ||
stream->props.u.bulk.buffersize)) < 0) | ||
return i; | ||
|
||
/* allocate the URBs */ | ||
for (i = 0; i < stream->props.count; i++) { | ||
if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL) | ||
return -ENOMEM; | ||
|
||
usb_fill_bulk_urb( stream->urb_list[i], stream->udev, | ||
usb_rcvbulkpipe(stream->udev,stream->props.endpoint), | ||
stream->buf_list[i], | ||
stream->props.u.bulk.buffersize, | ||
usb_urb_complete, stream); | ||
|
||
stream->urb_list[i]->transfer_flags = 0; | ||
stream->urbs_initialized++; | ||
} | ||
return 0; | ||
} | ||
|
||
static int usb_isoc_urb_init(struct usb_data_stream *stream) | ||
{ | ||
int i,j; | ||
|
||
if ((i = usb_allocate_stream_buffers(stream,stream->props.count, | ||
stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) | ||
return i; | ||
|
||
/* allocate the URBs */ | ||
for (i = 0; i < stream->props.count; i++) { | ||
struct urb *urb; | ||
int frame_offset = 0; | ||
if ((stream->urb_list[i] = | ||
usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL) | ||
return -ENOMEM; | ||
|
||
urb = stream->urb_list[i]; | ||
|
||
urb->dev = stream->udev; | ||
urb->context = stream; | ||
urb->complete = usb_urb_complete; | ||
urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); | ||
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | ||
urb->interval = stream->props.u.isoc.interval; | ||
urb->number_of_packets = stream->props.u.isoc.framesperurb; | ||
urb->transfer_buffer_length = stream->buf_size; | ||
urb->transfer_buffer = stream->buf_list[i]; | ||
urb->transfer_dma = stream->dma_addr[i]; | ||
|
||
for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { | ||
urb->iso_frame_desc[j].offset = frame_offset; | ||
urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; | ||
frame_offset += stream->props.u.isoc.framesize; | ||
} | ||
|
||
stream->urbs_initialized++; | ||
} | ||
return 0; | ||
} | ||
|
||
int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) | ||
{ | ||
if (stream == NULL || props == NULL) | ||
return -EINVAL; | ||
|
||
memcpy(&stream->props, props, sizeof(*props)); | ||
|
||
usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); | ||
|
||
if (stream->complete == NULL) { | ||
err("there is no data callback - this doesn't make sense."); | ||
return -EINVAL; | ||
} | ||
|
||
switch (stream->props.type) { | ||
case USB_BULK: | ||
return usb_bulk_urb_init(stream); | ||
case USB_ISOC: | ||
return usb_isoc_urb_init(stream); | ||
default: | ||
err("unkown URB-type for data transfer."); | ||
return -EINVAL; | ||
} | ||
} | ||
|
||
int usb_urb_exit(struct usb_data_stream *stream) | ||
{ | ||
int i; | ||
|
||
usb_urb_kill(stream); | ||
|
||
for (i = 0; i < stream->urbs_initialized; i++) { | ||
if (stream->urb_list[i] != NULL) { | ||
deb_mem("freeing URB no. %d.\n",i); | ||
/* free the URBs */ | ||
usb_free_urb(stream->urb_list[i]); | ||
} | ||
} | ||
stream->urbs_initialized = 0; | ||
|
||
usb_free_stream_buffers(stream); | ||
return 0; | ||
} |