|
@@ -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;
|
|
|
}
|
|
|
}
|