|
@@ -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;
|
|
@@ -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
|
|
|
*/
|
|
@@ -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);
|
|
|
|
|
@@ -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 */
|
|
@@ -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;
|
|
|
|
|
@@ -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);
|
|
@@ -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,
|
|
@@ -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);
|
|
@@ -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");
|