#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;
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
*/
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);
}
/*
- * 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 */
max_packets = TM6000_MAX_ISO_PACKETS;
sb_size = max_packets * size;
+ dev->urb_size = sb_size;
dev->isoc_ctl.num_bufs = num_bufs;
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);
}
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,
{
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);
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");