]> Pileus Git - ~andy/linux/blobdiff - drivers/media/video/em28xx/em28xx-core.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into next
[~andy/linux] / drivers / media / video / em28xx / em28xx-core.c
index 0aacc96f9a232416928e8a07346620f223ef0cbc..53a9fb91e97ed893038c82db78714135816028b4 100644 (file)
@@ -666,6 +666,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(em28xx_capture_start);
 
 int em28xx_vbi_supported(struct em28xx *dev)
 {
@@ -961,146 +962,192 @@ static void em28xx_irq_callback(struct urb *urb)
 /*
  * Stop and Deallocate URBs
  */
-void em28xx_uninit_isoc(struct em28xx *dev)
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
 {
        struct urb *urb;
+       struct em28xx_usb_isoc_bufs *isoc_bufs;
        int i;
 
-       em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+       em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode);
+
+       if (mode == EM28XX_DIGITAL_MODE)
+               isoc_bufs = &dev->isoc_ctl.digital_bufs;
+       else
+               isoc_bufs = &dev->isoc_ctl.analog_bufs;
 
        dev->isoc_ctl.nfields = -1;
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb = dev->isoc_ctl.urb[i];
+       for (i = 0; i < isoc_bufs->num_bufs; i++) {
+               urb = isoc_bufs->urb[i];
                if (urb) {
                        if (!irqs_disabled())
                                usb_kill_urb(urb);
                        else
                                usb_unlink_urb(urb);
 
-                       if (dev->isoc_ctl.transfer_buffer[i]) {
+                       if (isoc_bufs->transfer_buffer[i]) {
                                usb_free_coherent(dev->udev,
                                        urb->transfer_buffer_length,
-                                       dev->isoc_ctl.transfer_buffer[i],
+                                       isoc_bufs->transfer_buffer[i],
                                        urb->transfer_dma);
                        }
                        usb_free_urb(urb);
-                       dev->isoc_ctl.urb[i] = NULL;
+                       isoc_bufs->urb[i] = NULL;
                }
-               dev->isoc_ctl.transfer_buffer[i] = NULL;
+               isoc_bufs->transfer_buffer[i] = NULL;
        }
 
-       kfree(dev->isoc_ctl.urb);
-       kfree(dev->isoc_ctl.transfer_buffer);
+       kfree(isoc_bufs->urb);
+       kfree(isoc_bufs->transfer_buffer);
 
-       dev->isoc_ctl.urb = NULL;
-       dev->isoc_ctl.transfer_buffer = NULL;
-       dev->isoc_ctl.num_bufs = 0;
+       isoc_bufs->urb = NULL;
+       isoc_bufs->transfer_buffer = NULL;
+       isoc_bufs->num_bufs = 0;
 
        em28xx_capture_start(dev, 0);
 }
 EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
 
 /*
- * Allocate URBs and start IRQ
+ * Allocate URBs
  */
-int em28xx_init_isoc(struct em28xx *dev, int max_packets,
-                    int num_bufs, int max_pkt_size,
-                    int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+                     int max_packets, int num_bufs, int max_pkt_size)
 {
-       struct em28xx_dmaqueue *dma_q = &dev->vidq;
-       struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+       struct em28xx_usb_isoc_bufs *isoc_bufs;
        int i;
        int sb_size, pipe;
        struct urb *urb;
        int j, k;
-       int rc;
 
-       em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+       em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
+
+       if (mode == EM28XX_DIGITAL_MODE)
+               isoc_bufs = &dev->isoc_ctl.digital_bufs;
+       else
+               isoc_bufs = &dev->isoc_ctl.analog_bufs;
 
        /* De-allocates all pending stuff */
-       em28xx_uninit_isoc(dev);
+       em28xx_uninit_isoc(dev, mode);
 
-       dev->isoc_ctl.isoc_copy = isoc_copy;
-       dev->isoc_ctl.num_bufs = num_bufs;
+       isoc_bufs->num_bufs = num_bufs;
 
-       dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
-       if (!dev->isoc_ctl.urb) {
+       isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+       if (!isoc_bufs->urb) {
                em28xx_errdev("cannot alloc memory for usb buffers\n");
                return -ENOMEM;
        }
 
-       dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
-                                             GFP_KERNEL);
-       if (!dev->isoc_ctl.transfer_buffer) {
+       isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+                                            GFP_KERNEL);
+       if (!isoc_bufs->transfer_buffer) {
                em28xx_errdev("cannot allocate memory for usb transfer\n");
-               kfree(dev->isoc_ctl.urb);
+               kfree(isoc_bufs->urb);
                return -ENOMEM;
        }
 
-       dev->isoc_ctl.max_pkt_size = max_pkt_size;
+       isoc_bufs->max_pkt_size = max_pkt_size;
+       isoc_bufs->num_packets = max_packets;
        dev->isoc_ctl.vid_buf = NULL;
        dev->isoc_ctl.vbi_buf = NULL;
 
-       sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+       sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
 
        /* allocate urbs and transfer buffers */
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+       for (i = 0; i < isoc_bufs->num_bufs; i++) {
+               urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL);
                if (!urb) {
                        em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
-                       em28xx_uninit_isoc(dev);
+                       em28xx_uninit_isoc(dev, mode);
                        return -ENOMEM;
                }
-               dev->isoc_ctl.urb[i] = urb;
+               isoc_bufs->urb[i] = urb;
 
-               dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+               isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
                        sb_size, GFP_KERNEL, &urb->transfer_dma);
-               if (!dev->isoc_ctl.transfer_buffer[i]) {
+               if (!isoc_bufs->transfer_buffer[i]) {
                        em28xx_err("unable to allocate %i bytes for transfer"
                                        " buffer %i%s\n",
                                        sb_size, i,
                                        in_interrupt() ? " while in int" : "");
-                       em28xx_uninit_isoc(dev);
+                       em28xx_uninit_isoc(dev, mode);
                        return -ENOMEM;
                }
-               memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+               memset(isoc_bufs->transfer_buffer[i], 0, sb_size);
 
                /* FIXME: this is a hack - should be
                        'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
                        should also be using 'desc.bInterval'
                 */
                pipe = usb_rcvisocpipe(dev->udev,
-                                      dev->mode == EM28XX_ANALOG_MODE ?
+                                      mode == EM28XX_ANALOG_MODE ?
                                       EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
 
                usb_fill_int_urb(urb, dev->udev, pipe,
-                                dev->isoc_ctl.transfer_buffer[i], sb_size,
+                                isoc_bufs->transfer_buffer[i], sb_size,
                                 em28xx_irq_callback, dev, 1);
 
-               urb->number_of_packets = max_packets;
+               urb->number_of_packets = isoc_bufs->num_packets;
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 
                k = 0;
-               for (j = 0; j < max_packets; j++) {
+               for (j = 0; j < isoc_bufs->num_packets; j++) {
                        urb->iso_frame_desc[j].offset = k;
                        urb->iso_frame_desc[j].length =
-                                               dev->isoc_ctl.max_pkt_size;
-                       k += dev->isoc_ctl.max_pkt_size;
+                                               isoc_bufs->max_pkt_size;
+                       k += isoc_bufs->max_pkt_size;
                }
        }
 
+       return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_alloc_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+                    int max_packets, int num_bufs, int max_pkt_size,
+                    int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+{
+       struct em28xx_dmaqueue *dma_q = &dev->vidq;
+       struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+       struct em28xx_usb_isoc_bufs *isoc_bufs;
+       int i;
+       int rc;
+       int alloc;
+
+       em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode);
+
+       dev->isoc_ctl.isoc_copy = isoc_copy;
+
+       if (mode == EM28XX_DIGITAL_MODE) {
+               isoc_bufs = &dev->isoc_ctl.digital_bufs;
+               /* no need to free/alloc isoc buffers in digital mode */
+               alloc = 0;
+       } else {
+               isoc_bufs = &dev->isoc_ctl.analog_bufs;
+               alloc = 1;
+       }
+
+       if (alloc) {
+               rc = em28xx_alloc_isoc(dev, mode, max_packets,
+                                      num_bufs, max_pkt_size);
+               if (rc)
+                       return rc;
+       }
+
        init_waitqueue_head(&dma_q->wq);
        init_waitqueue_head(&vbi_dma_q->wq);
 
        em28xx_capture_start(dev, 1);
 
        /* submit urbs and enables IRQ */
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+       for (i = 0; i < isoc_bufs->num_bufs; i++) {
+               rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC);
                if (rc) {
                        em28xx_err("submit of urb %i failed (error=%i)\n", i,
                                   rc);
-                       em28xx_uninit_isoc(dev);
+                       em28xx_uninit_isoc(dev, mode);
                        return rc;
                }
        }