Skip to content

Commit

Permalink
[media] tm6000: Add parameter to keep urb bufs allocated
Browse files Browse the repository at this point in the history
On systems where it cannot be assured that enough continous memory is available
all the time it can be very useful to only allocate the memory once when it is
needed the first time. Afterwards the initially allocated memory will be
reused, so it is ensured that the memory will stay available until the driver
is unloaded.

[mchehab@redhat.com: Codingstyle fixups]
Signed-off-by: Julian Scheel <julian@jusst.de>

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Julian Scheel authored and Mauro Carvalho Chehab committed Dec 4, 2012
1 parent 6823627 commit 16427fa
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 19 deletions.
112 changes: 93 additions & 19 deletions drivers/media/usb/tm6000/tm6000-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,15 @@
#define TM6000_MIN_BUF 4
#define TM6000_DEF_BUF 8

#define TM6000_NUM_URB_BUF 8

#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */

/* Declare static vars that will be used as parameters */
static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */
static int keep_urb; /* keep urb buffers allocated */

/* Debug level */
int tm6000_debug;
Expand Down Expand Up @@ -537,6 +540,71 @@ static void tm6000_irq_callback(struct urb *urb)
urb->status);
}

/*
* Allocate URB buffers
*/
static int tm6000_alloc_urb_buffers(struct tm6000_core *dev)
{
int num_bufs = TM6000_NUM_URB_BUF;
int i;

if (dev->urb_buffer != NULL)
return 0;

dev->urb_buffer = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
if (!dev->urb_buffer) {
tm6000_err("cannot allocate memory for urb buffers\n");
return -ENOMEM;
}

dev->urb_dma = kmalloc(sizeof(dma_addr_t *)*num_bufs, GFP_KERNEL);
if (!dev->urb_dma) {
tm6000_err("cannot allocate memory for urb dma pointers\n");
return -ENOMEM;
}

for (i = 0; i < num_bufs; i++) {
dev->urb_buffer[i] = usb_alloc_coherent(
dev->udev, dev->urb_size,
GFP_KERNEL, &dev->urb_dma[i]);
if (!dev->urb_buffer[i]) {
tm6000_err("unable to allocate %i bytes for transfer buffer %i\n",
dev->urb_size, i);
return -ENOMEM;
}
memset(dev->urb_buffer[i], 0, dev->urb_size);
}

return 0;
}

/*
* Free URB buffers
*/
static int tm6000_free_urb_buffers(struct tm6000_core *dev)
{
int i;

if (dev->urb_buffer == NULL)
return 0;

for (i = 0; i < TM6000_NUM_URB_BUF; i++) {
if (dev->urb_buffer[i]) {
usb_free_coherent(dev->udev,
dev->urb_size,
dev->urb_buffer[i],
dev->urb_dma[i]);
dev->urb_buffer[i] = NULL;
}
}
kfree(dev->urb_buffer);
kfree(dev->urb_dma);
dev->urb_buffer = NULL;
dev->urb_dma = NULL;

return 0;
}

/*
* Stop and Deallocate URBs
*/
Expand All @@ -551,18 +619,15 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
if (urb) {
usb_kill_urb(urb);
usb_unlink_urb(urb);
if (dev->isoc_ctl.transfer_buffer[i]) {
usb_free_coherent(dev->udev,
urb->transfer_buffer_length,
dev->isoc_ctl.transfer_buffer[i],
urb->transfer_dma);
}
usb_free_urb(urb);
dev->isoc_ctl.urb[i] = NULL;
}
dev->isoc_ctl.transfer_buffer[i] = NULL;
}

if (!keep_urb)
tm6000_free_urb_buffers(dev);

kfree(dev->isoc_ctl.urb);
kfree(dev->isoc_ctl.transfer_buffer);

Expand All @@ -572,12 +637,13 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
}

/*
* Allocate URBs and start IRQ
* Assign URBs and start IRQ
*/
static int tm6000_prepare_isoc(struct tm6000_core *dev)
{
struct tm6000_dmaqueue *dma_q = &dev->vidq;
int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
int i, j, sb_size, pipe, size, max_packets;
int num_bufs = TM6000_NUM_URB_BUF;
struct urb *urb;

/* De-allocates all pending stuff */
Expand Down Expand Up @@ -605,6 +671,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev)

max_packets = TM6000_MAX_ISO_PACKETS;
sb_size = max_packets * size;
dev->urb_size = sb_size;

dev->isoc_ctl.num_bufs = num_bufs;

Expand All @@ -627,6 +694,17 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev)
max_packets, num_bufs, sb_size,
dev->isoc_in.maxsize, size);


if (!dev->urb_buffer && tm6000_alloc_urb_buffers(dev) < 0) {
tm6000_err("cannot allocate memory for urb buffers\n");

/* call free, as some buffers might have been allocated */
tm6000_free_urb_buffers(dev);
kfree(dev->isoc_ctl.urb);
kfree(dev->isoc_ctl.transfer_buffer);
return -ENOMEM;
}

/* allocate urbs and transfer buffers */
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
urb = usb_alloc_urb(max_packets, GFP_KERNEL);
Expand All @@ -638,17 +716,8 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev)
}
dev->isoc_ctl.urb[i] = urb;

dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
sb_size, GFP_KERNEL, &urb->transfer_dma);
if (!dev->isoc_ctl.transfer_buffer[i]) {
tm6000_err("unable to allocate %i bytes for transfer"
" buffer %i%s\n",
sb_size, i,
in_interrupt() ? " while in int" : "");
tm6000_uninit_isoc(dev);
return -ENOMEM;
}
memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
urb->transfer_dma = dev->urb_dma[i];
dev->isoc_ctl.transfer_buffer[i] = dev->urb_buffer[i];

usb_fill_bulk_urb(urb, dev->udev, pipe,
dev->isoc_ctl.transfer_buffer[i], sb_size,
Expand Down Expand Up @@ -1826,6 +1895,9 @@ int tm6000_v4l2_unregister(struct tm6000_core *dev)
{
video_unregister_device(dev->vfd);

/* if URB buffers are still allocated free them now */
tm6000_free_urb_buffers(dev);

if (dev->radio_dev) {
if (video_is_registered(dev->radio_dev))
video_unregister_device(dev->radio_dev);
Expand All @@ -1851,3 +1923,5 @@ MODULE_PARM_DESC(debug, "activates debug info");
module_param(vid_limit, int, 0644);
MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");

module_param(keep_urb, bool, 0);
MODULE_PARM_DESC(keep_urb, "Keep urb buffers allocated even when the device is closed by the user");
5 changes: 5 additions & 0 deletions drivers/media/usb/tm6000/tm6000.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ struct tm6000_core {

spinlock_t slock;

/* urb dma buffers */
char **urb_buffer;
dma_addr_t *urb_dma;
unsigned int urb_size;

unsigned long quirks;
};

Expand Down

0 comments on commit 16427fa

Please sign in to comment.