V4L/DVB (7602): em28xx: generalise URB setup code
authorAidan Thornton <makosoft@googlemail.com>
Fri, 18 Apr 2008 00:40:16 +0000 (21:40 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Thu, 24 Apr 2008 17:09:41 +0000 (14:09 -0300)
Move the URB setup and management code to em28xx-core.c and generalise
it slighlty so that the DVB code can use it.

Signed-off-by: Aidan Thornton <makosoft@googlemail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h

index 841c7c2c91b34dc2644f24312c90e268e70bb021..cb9f721ca28007f099bdaa6cd1648b25a748380f 100644 (file)
@@ -53,6 +53,12 @@ static int alt = EM28XX_PINOUT;
 module_param(alt, int, 0644);
 MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 
+/* FIXME */
+#define em28xx_isocdbg(fmt, arg...) do {\
+       if (core_debug) \
+               printk(KERN_INFO "%s %s :"fmt, \
+                        dev->name, __func__ , ##arg); } while (0)
+
 /*
  * em28xx_read_reg_req()
  * reads data from the usb device specifying bRequest
@@ -455,3 +461,178 @@ int em28xx_set_alternate(struct em28xx *dev)
        }
        return 0;
 }
+
+/* ------------------------------------------------------------------
+       URB control
+   ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void em28xx_irq_callback(struct urb *urb)
+{
+       struct em28xx_dmaqueue  *dma_q = urb->context;
+       struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+       int rc, i;
+
+       /* Copy data from URB */
+       spin_lock(&dev->slock);
+       rc = dev->isoc_ctl.isoc_copy(dev, urb);
+       spin_unlock(&dev->slock);
+
+       /* Reset urb buffers */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+       urb->status = 0;
+
+       urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (urb->status) {
+               em28xx_err("urb resubmit failed (error=%i)\n",
+                       urb->status);
+       }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void em28xx_uninit_isoc(struct em28xx *dev)
+{
+       struct urb *urb;
+       int i;
+
+       em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+
+       dev->isoc_ctl.nfields = -1;
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               urb = dev->isoc_ctl.urb[i];
+               if (urb) {
+                       usb_kill_urb(urb);
+                       usb_unlink_urb(urb);
+                       if (dev->isoc_ctl.transfer_buffer[i]) {
+                               usb_buffer_free(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;
+       }
+
+       kfree(dev->isoc_ctl.urb);
+       kfree(dev->isoc_ctl.transfer_buffer);
+
+       dev->isoc_ctl.urb = NULL;
+       dev->isoc_ctl.transfer_buffer = NULL;
+       dev->isoc_ctl.num_bufs = 0;
+
+       em28xx_capture_start(dev, 0);
+}
+EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+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 cap_type)
+{
+       struct em28xx_dmaqueue *dma_q = &dev->vidq;
+       int i;
+       int sb_size, pipe;
+       struct urb *urb;
+       int j, k;
+       int rc;
+
+       em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+
+       /* De-allocates all pending stuff */
+       em28xx_uninit_isoc(dev);
+
+       dev->isoc_ctl.isoc_copy = isoc_copy;
+       dev->isoc_ctl.num_bufs = num_bufs;
+
+       dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+       if (!dev->isoc_ctl.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.urb) {
+               em28xx_errdev("cannot allocate memory for usbtransfer\n");
+               kfree(dev->isoc_ctl.urb);
+               return -ENOMEM;
+       }
+
+       dev->isoc_ctl.max_pkt_size = max_pkt_size;
+       dev->isoc_ctl.buf = NULL;
+
+       sb_size = max_packets * dev->isoc_ctl.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);
+               if (!urb) {
+                       em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
+                       em28xx_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               dev->isoc_ctl.urb[i] = urb;
+
+               dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
+                       sb_size, GFP_KERNEL, &urb->transfer_dma);
+               if (!dev->isoc_ctl.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);
+                       return -ENOMEM;
+               }
+               memset(dev->isoc_ctl.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, cap_type == EM28XX_ANALOG_CAPTURE ? 0x82 : 0x84);
+               usb_fill_int_urb(urb, dev->udev, pipe,
+                                dev->isoc_ctl.transfer_buffer[i], sb_size,
+                                em28xx_irq_callback, dma_q, 1);
+
+               urb->number_of_packets = max_packets;
+               urb->transfer_flags = URB_ISO_ASAP;
+
+               k = 0;
+               for (j = 0; j < max_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;
+               }
+       }
+
+       init_waitqueue_head(&dma_q->wq);
+
+       em28xx_capture_start(dev, cap_type);
+
+       /* 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);
+               if (rc) {
+                       em28xx_err("submit of urb %i failed (error=%i)\n", i,
+                                  rc);
+                       em28xx_uninit_isoc(dev);
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_init_isoc);
index 72a7633b6452c36182468065a749133c52a09c19..1a0b09714af5659473933770bf9d5139718d3030 100644 (file)
@@ -285,11 +285,10 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
 /*
  * Controls the isoc copy of each urb packet
  */
-static inline int em28xx_isoc_copy(struct urb *urb)
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
 {
        struct em28xx_buffer    *buf;
        struct em28xx_dmaqueue  *dma_q = urb->context;
-       struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
        unsigned char *outp = NULL;
        int i, len = 0, rc = 1;
        unsigned char *p;
@@ -370,188 +369,6 @@ static inline int em28xx_isoc_copy(struct urb *urb)
        return rc;
 }
 
-/* ------------------------------------------------------------------
-       URB control
-   ------------------------------------------------------------------*/
-
-/*
- * IRQ callback, called by URB callback
- */
-static void em28xx_irq_callback(struct urb *urb)
-{
-       struct em28xx_dmaqueue  *dma_q = urb->context;
-       struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
-       int rc, i;
-
-       /* Copy data from URB */
-       spin_lock(&dev->slock);
-       rc = em28xx_isoc_copy(urb);
-       spin_unlock(&dev->slock);
-
-       /* Reset urb buffers */
-       for (i = 0; i < urb->number_of_packets; i++) {
-               urb->iso_frame_desc[i].status = 0;
-               urb->iso_frame_desc[i].actual_length = 0;
-       }
-       urb->status = 0;
-
-       urb->status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (urb->status) {
-               em28xx_err("urb resubmit failed (error=%i)\n",
-                       urb->status);
-       }
-}
-
-/*
- * Stop and Deallocate URBs
- */
-static void em28xx_uninit_isoc(struct em28xx *dev)
-{
-       struct urb *urb;
-       int i;
-
-       em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
-
-       dev->isoc_ctl.nfields = -1;
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb = dev->isoc_ctl.urb[i];
-               if (urb) {
-                       usb_kill_urb(urb);
-                       usb_unlink_urb(urb);
-                       if (dev->isoc_ctl.transfer_buffer[i]) {
-                               usb_buffer_free(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;
-       }
-
-       kfree(dev->isoc_ctl.urb);
-       kfree(dev->isoc_ctl.transfer_buffer);
-       dev->isoc_ctl.urb = NULL;
-       dev->isoc_ctl.transfer_buffer = NULL;
-
-       dev->isoc_ctl.num_bufs = 0;
-
-       em28xx_capture_start(dev, 0);
-}
-
-/*
- * Allocate URBs and start IRQ
- */
-static int em28xx_prepare_isoc(struct em28xx *dev, int max_packets,
-                              int num_bufs)
-{
-       struct em28xx_dmaqueue *dma_q = &dev->vidq;
-       int i;
-       int sb_size, pipe;
-       struct urb *urb;
-       int j, k;
-
-       em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
-
-       /* De-allocates all pending stuff */
-       em28xx_uninit_isoc(dev);
-
-       dev->isoc_ctl.num_bufs = num_bufs;
-
-       dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
-       if (!dev->isoc_ctl.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.urb) {
-               em28xx_errdev("cannot allocate memory for usbtransfer\n");
-               kfree(dev->isoc_ctl.urb);
-               return -ENOMEM;
-       }
-
-       dev->isoc_ctl.max_pkt_size = dev->max_pkt_size;
-       dev->isoc_ctl.buf = NULL;
-
-       sb_size = max_packets * dev->isoc_ctl.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);
-               if (!urb) {
-                       em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
-                       em28xx_uninit_isoc(dev);
-                       return -ENOMEM;
-               }
-               dev->isoc_ctl.urb[i] = urb;
-
-               dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
-                       sb_size, GFP_KERNEL, &urb->transfer_dma);
-               if (!dev->isoc_ctl.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);
-                       return -ENOMEM;
-               }
-               memset(dev->isoc_ctl.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, 0x82);
-               usb_fill_int_urb(urb, dev->udev, pipe,
-                                dev->isoc_ctl.transfer_buffer[i], sb_size,
-                                em28xx_irq_callback, dma_q, 1);
-
-               urb->number_of_packets = max_packets;
-               urb->transfer_flags = URB_ISO_ASAP;
-
-               k = 0;
-               for (j = 0; j < max_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;
-               }
-       }
-
-       return 0;
-}
-
-static int em28xx_start_thread(struct em28xx_dmaqueue  *dma_q)
-{
-       struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
-       int i, rc = 0;
-
-       em28xx_videodbg("Called em28xx_start_thread\n");
-
-       init_waitqueue_head(&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);
-               if (rc) {
-                       em28xx_err("submit of urb %i failed (error=%i)\n", i,
-                                  rc);
-                       em28xx_uninit_isoc(dev);
-                       return rc;
-               }
-       }
-
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
@@ -615,7 +432,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        struct em28xx_fh     *fh  = vq->priv_data;
        struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
        struct em28xx        *dev = fh->dev;
-       struct em28xx_dmaqueue *vidq = &dev->vidq;
        int                  rc = 0, urb_init = 0;
 
        /* FIXME: It assumes depth = 16 */
@@ -639,12 +455,9 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                urb_init = 1;
 
        if (urb_init) {
-               rc = em28xx_prepare_isoc(dev, EM28XX_NUM_PACKETS,
-                                        EM28XX_NUM_BUFS);
-               if (rc < 0)
-                       goto fail;
-
-               rc = em28xx_start_thread(vidq);
+               rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+                                     EM28XX_NUM_BUFS, dev->max_pkt_size,
+                                     em28xx_isoc_copy, EM28XX_ANALOG_CAPTURE);
                if (rc < 0)
                        goto fail;
        }
index 3786dd819bbdaedd4ae76232592d3a11b4ba62e2..151bc57bd08b4662bdf53c2c4ecbdf4fc59b8c7a 100644 (file)
@@ -119,6 +119,8 @@ enum em28xx_stream_state {
        STREAM_ON,
 };
 
+struct em28xx;
+
 struct em28xx_usb_isoc_ctl {
                /* max packet size of isoc transaction */
        int                             max_pkt_size;
@@ -148,6 +150,10 @@ struct em28xx_usb_isoc_ctl {
 
                /* Stores the number of received fields */
        int                             nfields;
+
+               /* isoc urb callback */
+       int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+
 };
 
 struct em28xx_fmt {
@@ -279,6 +285,12 @@ enum em28xx_dev_state {
        DEV_MISCONFIGURED = 0x04,
 };
 
+enum em28xx_capture_mode {
+       EM28XX_CAPTURE_OFF = 0,
+       EM28XX_ANALOG_CAPTURE,
+       EM28XX_DIGITAL_CAPTURE,
+};
+
 #define EM28XX_AUDIO_BUFS 5
 #define EM28XX_NUM_AUDIO_PACKETS 64
 #define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
@@ -452,6 +464,11 @@ int em28xx_capture_start(struct em28xx *dev, int start);
 int em28xx_outfmt_set_yuv422(struct em28xx *dev);
 int em28xx_resolution_set(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
+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 cap_type);
+void em28xx_uninit_isoc(struct em28xx *dev);
 
 /* Provided by em28xx-video.c */
 int em28xx_register_extension(struct em28xx_ops *dev);