mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-19 02:04:19 +08:00
V4L/DVB (7602): em28xx: generalise URB setup code
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>
This commit is contained in:
parent
7e6388a1b9
commit
579f72e44f
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user