From bce1c0290270fbc8c18414de4cbdb035521230d6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 28 May 2012 17:25:40 -0300 Subject: [PATCH] [media] dvb_usb_v2: dynamic USB stream URB configuration Change URB count, buffer size and type [BULK/ISOC] dynamically when needed if existing URB buffers are big enough. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 3 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 2 +- drivers/media/dvb/dvb-usb/usb_urb.c | 220 ++++++++++++++------- 3 files changed, 151 insertions(+), 74 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 60f8ccba8dcd..2c73829f2764 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -33,7 +33,8 @@ extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); extern int usb_urb_exit(struct usb_data_stream *stream); -extern int usb_urb_submit(struct usb_data_stream *stream); +extern int usb_urb_submit(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); extern int usb_urb_kill(struct usb_data_stream *stream); extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 85db3f46e77d..fd02be30b532 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -57,7 +57,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) */ if (adap->feedcount == onoff && adap->feedcount > 0) { deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream, NULL); deb_ts("controlling pid parser\n"); if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index 065f67c67538..8792334642a2 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -11,6 +11,10 @@ #include "dvb_usb_common.h" /* URB stuff for streaming */ + +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); + static void usb_urb_complete(struct urb *urb) { struct usb_data_stream *stream = urb->context; @@ -79,9 +83,17 @@ int usb_urb_kill(struct usb_data_stream *stream) return 0; } -int usb_urb_submit(struct usb_data_stream *stream) +int usb_urb_submit(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) { int i, ret; + + if (props) { + ret = usb_urb_reconfig(stream, props); + if (ret < 0) + return ret; + } + for (i = 0; i < stream->urbs_initialized; i++) { deb_ts("submitting URB no. %d\n", i); ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); @@ -96,65 +108,32 @@ int usb_urb_submit(struct usb_data_stream *stream) return 0; } -static int usb_free_stream_buffers(struct usb_data_stream *stream) +int usb_urb_free_urbs(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_free_coherent(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; + int i; - deb_mem("all in all I will use %lu bytes for streaming\n", num * size); + usb_urb_kill(stream); - for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - deb_mem("allocating buffer %d\n", stream->buf_num); - stream->buf_list[stream->buf_num] = usb_alloc_coherent( - stream->udev, size, GFP_ATOMIC, - &stream->dma_addr[stream->buf_num]); - if (stream->buf_list[stream->buf_num] == NULL) { - deb_mem("not enough memory for urb-buffer" \ - " allocation.\n"); - usb_free_stream_buffers(stream); - return -ENOMEM; + for (i = 0; i < stream->urbs_initialized; i++) { + if (stream->urb_list[i] != NULL) { + deb_mem("freeing URB no. %d.\n", i); + pr_debug("%s: free URB=%d\n", __func__, i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); } - deb_mem("buffer %d: %p (dma: %llu)\n", - stream->buf_num, - stream->buf_list[stream->buf_num], - (long long)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"); + stream->urbs_initialized = 0; return 0; } -static int usb_bulk_urb_init(struct usb_data_stream *stream) +static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) { int i, j; - i = usb_allocate_stream_buffers(stream, stream->props.count, - stream->props.u.bulk.buffersize); - if (i < 0) - return i; - /* allocate the URBs */ for (i = 0; i < stream->props.count; i++) { + pr_debug("%s: alloc URB=%d\n", __func__, i); stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!stream->urb_list[i]) { deb_mem("not enough memory for urb_alloc_urb!.\n"); @@ -162,9 +141,10 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) usb_free_urb(stream->urb_list[j]); return -ENOMEM; } - usb_fill_bulk_urb(stream->urb_list[i], stream->udev, + usb_fill_bulk_urb(stream->urb_list[i], + stream->udev, usb_rcvbulkpipe(stream->udev, - stream->props.endpoint), + stream->props.endpoint), stream->buf_list[i], stream->props.u.bulk.buffersize, usb_urb_complete, stream); @@ -176,21 +156,15 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) return 0; } -static int usb_isoc_urb_init(struct usb_data_stream *stream) +static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) { int i, j; - i = usb_allocate_stream_buffers(stream, stream->props.count, - stream->props.u.isoc.framesize * - stream->props.u.isoc.framesperurb); - if (i < 0) - return i; - /* allocate the URBs */ for (i = 0; i < stream->props.count; i++) { struct urb *urb; int frame_offset = 0; - + pr_debug("%s: alloc URB=%d\n", __func__, i); stream->urb_list[i] = usb_alloc_urb( stream->props.u.isoc.framesperurb, GFP_ATOMIC); if (!stream->urb_list[i]) { @@ -210,7 +184,8 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) 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_length = stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb; urb->transfer_buffer = stream->buf_list[i]; urb->transfer_dma = stream->dma_addr[i]; @@ -226,9 +201,110 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) return 0; } +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_free_coherent(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; +} + +int usb_alloc_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); + stream->buf_list[stream->buf_num] = usb_alloc_coherent( + stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]); + if (stream->buf_list[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: %llu)\n", + stream->buf_num, + stream->buf_list[stream->buf_num], + (long long)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; +} + +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) +{ + int buf_size; + + if (props == NULL) + return 0; + + /* check allocated buffers are large enough for the request */ + if (props->type == USB_BULK) + buf_size = stream->props.u.bulk.buffersize; + else if (props->type == USB_ISOC) + buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; + else + return -EINVAL; + + if (stream->buf_num < props->count || stream->buf_size < buf_size) { + err("cannot reconfigure as allocated buffers are too small"); + return -EINVAL; + } + + /* check if all fields are same */ + if (stream->props.type == props->type && + stream->props.count == props->count && + stream->props.endpoint == props->endpoint) { + if (props->type == USB_BULK && + props->u.bulk.buffersize == + stream->props.u.bulk.buffersize) + return 0; + else if (props->type == USB_ISOC && + props->u.isoc.framesperurb == + stream->props.u.isoc.framesperurb && + props->u.isoc.framesize == + stream->props.u.isoc.framesize && + props->u.isoc.interval == + stream->props.u.isoc.interval) + return 0; + } + + pr_debug("%s: re-alloc URBs\n", __func__); + + usb_urb_free_urbs(stream); + memcpy(&stream->props, props, sizeof(*props)); + if (props->type == USB_BULK) + return usb_urb_alloc_bulk_urbs(stream); + else if (props->type == USB_ISOC) + return usb_urb_alloc_isoc_urbs(stream); + + return 0; +} + int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) { + int ret; + if (stream == NULL || props == NULL) return -EINVAL; @@ -244,9 +320,20 @@ int usb_urb_init(struct usb_data_stream *stream, switch (stream->props.type) { case USB_BULK: - return usb_bulk_urb_init(stream); + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.bulk.buffersize); + if (ret < 0) + return ret; + + return usb_urb_alloc_bulk_urbs(stream); case USB_ISOC: - return usb_isoc_urb_init(stream); + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb); + if (ret < 0) + return ret; + + return usb_urb_alloc_isoc_urbs(stream); default: err("unknown URB-type for data transfer."); return -EINVAL; @@ -255,19 +342,8 @@ int usb_urb_init(struct usb_data_stream *stream, 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_urb_free_urbs(stream); usb_free_stream_buffers(stream); + return 0; } -- 2.20.1