Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 92680
b: refs/heads/master
c: 579f72e
h: refs/heads/master
v: v3
  • Loading branch information
Aidan Thornton authored and Mauro Carvalho Chehab committed Apr 24, 2008
1 parent fbd1c49 commit bb9e58d
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 192 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7e6388a1b97cca57a1906df6104feb4001721576
refs/heads/master: 579f72e44fb1c991352f44c20b471c3001357f68
181 changes: 181 additions & 0 deletions trunk/drivers/media/video/em28xx/em28xx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Loading

0 comments on commit bb9e58d

Please sign in to comment.