[media] tm6000-video.c: warning fix
[deliverable/linux.git] / drivers / media / usb / tm6000 / tm6000-video.c
index 4342cd4f5c8a7ad76cef1730348fb9ece2b1ada0..1edc2517603f33a812ef1202dc1541817a4f7900 100644 (file)
 #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 bool 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,
@@ -1802,6 +1871,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
                if (!dev->radio_dev) {
                        printk(KERN_INFO "%s: can't register radio device\n",
                               dev->name);
+                       ret = -ENXIO;
                        return ret; /* FIXME release resource */
                }
 
@@ -1825,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);
@@ -1850,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");
This page took 0.025746 seconds and 5 git commands to generate.