162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci cx231xx_vbi.c - driver for Conexant Cx23100/101/102 USB video capture devices 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci Copyright (C) 2008 <srinivasa.deevi at conexant dot com> 662306a36Sopenharmony_ci Based on cx88 driver 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "cx231xx.h" 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/list.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/bitmap.h> 1662306a36Sopenharmony_ci#include <linux/i2c.h> 1762306a36Sopenharmony_ci#include <linux/mm.h> 1862306a36Sopenharmony_ci#include <linux/mutex.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <media/v4l2-common.h> 2262306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 2362306a36Sopenharmony_ci#include <media/drv-intf/msp3400.h> 2462306a36Sopenharmony_ci#include <media/tuner.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "cx231xx-vbi.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic inline void print_err_status(struct cx231xx *dev, int packet, int status) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci char *errmsg = "Unknown"; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci switch (status) { 3362306a36Sopenharmony_ci case -ENOENT: 3462306a36Sopenharmony_ci errmsg = "unlinked synchronously"; 3562306a36Sopenharmony_ci break; 3662306a36Sopenharmony_ci case -ECONNRESET: 3762306a36Sopenharmony_ci errmsg = "unlinked asynchronously"; 3862306a36Sopenharmony_ci break; 3962306a36Sopenharmony_ci case -ENOSR: 4062306a36Sopenharmony_ci errmsg = "Buffer error (overrun)"; 4162306a36Sopenharmony_ci break; 4262306a36Sopenharmony_ci case -EPIPE: 4362306a36Sopenharmony_ci errmsg = "Stalled (device not responding)"; 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci case -EOVERFLOW: 4662306a36Sopenharmony_ci errmsg = "Babble (bad cable?)"; 4762306a36Sopenharmony_ci break; 4862306a36Sopenharmony_ci case -EPROTO: 4962306a36Sopenharmony_ci errmsg = "Bit-stuff error (bad cable?)"; 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci case -EILSEQ: 5262306a36Sopenharmony_ci errmsg = "CRC/Timeout (could be anything)"; 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci case -ETIME: 5562306a36Sopenharmony_ci errmsg = "Device does not respond"; 5662306a36Sopenharmony_ci break; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci if (packet < 0) { 5962306a36Sopenharmony_ci dev_err(dev->dev, 6062306a36Sopenharmony_ci "URB status %d [%s].\n", status, errmsg); 6162306a36Sopenharmony_ci } else { 6262306a36Sopenharmony_ci dev_err(dev->dev, 6362306a36Sopenharmony_ci "URB packet %d, status %d [%s].\n", 6462306a36Sopenharmony_ci packet, status, errmsg); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * Controls the isoc copy of each urb packet 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_cistatic inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct cx231xx_dmaqueue *dma_q = urb->context; 7462306a36Sopenharmony_ci int rc = 1; 7562306a36Sopenharmony_ci unsigned char *p_buffer; 7662306a36Sopenharmony_ci u32 bytes_parsed = 0, buffer_size = 0; 7762306a36Sopenharmony_ci u8 sav_eav = 0; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!dev) 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (dev->state & DEV_DISCONNECTED) 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (urb->status < 0) { 8662306a36Sopenharmony_ci print_err_status(dev, -1, urb->status); 8762306a36Sopenharmony_ci if (urb->status == -ENOENT) 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* get buffer pointer and length */ 9262306a36Sopenharmony_ci p_buffer = urb->transfer_buffer; 9362306a36Sopenharmony_ci buffer_size = urb->actual_length; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (buffer_size > 0) { 9662306a36Sopenharmony_ci bytes_parsed = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (dma_q->is_partial_line) { 9962306a36Sopenharmony_ci /* Handle the case where we were working on a partial 10062306a36Sopenharmony_ci line */ 10162306a36Sopenharmony_ci sav_eav = dma_q->last_sav; 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci /* Check for a SAV/EAV overlapping the 10462306a36Sopenharmony_ci buffer boundary */ 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci sav_eav = cx231xx_find_boundary_SAV_EAV(p_buffer, 10762306a36Sopenharmony_ci dma_q->partial_buf, 10862306a36Sopenharmony_ci &bytes_parsed); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci sav_eav &= 0xF0; 11262306a36Sopenharmony_ci /* Get the first line if we have some portion of an SAV/EAV from 11362306a36Sopenharmony_ci the last buffer or a partial line */ 11462306a36Sopenharmony_ci if (sav_eav) { 11562306a36Sopenharmony_ci bytes_parsed += cx231xx_get_vbi_line(dev, dma_q, 11662306a36Sopenharmony_ci sav_eav, /* SAV/EAV */ 11762306a36Sopenharmony_ci p_buffer + bytes_parsed, /* p_buffer */ 11862306a36Sopenharmony_ci buffer_size - bytes_parsed); /* buffer size */ 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* Now parse data that is completely in this buffer */ 12262306a36Sopenharmony_ci dma_q->is_partial_line = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci while (bytes_parsed < buffer_size) { 12562306a36Sopenharmony_ci u32 bytes_used = 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci sav_eav = cx231xx_find_next_SAV_EAV( 12862306a36Sopenharmony_ci p_buffer + bytes_parsed, /* p_buffer */ 12962306a36Sopenharmony_ci buffer_size - bytes_parsed, /* buffer size */ 13062306a36Sopenharmony_ci &bytes_used); /* bytes used to get SAV/EAV */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci bytes_parsed += bytes_used; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci sav_eav &= 0xF0; 13562306a36Sopenharmony_ci if (sav_eav && (bytes_parsed < buffer_size)) { 13662306a36Sopenharmony_ci bytes_parsed += cx231xx_get_vbi_line(dev, 13762306a36Sopenharmony_ci dma_q, sav_eav, /* SAV/EAV */ 13862306a36Sopenharmony_ci p_buffer+bytes_parsed, /* p_buffer */ 13962306a36Sopenharmony_ci buffer_size-bytes_parsed);/*buf size*/ 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Save the last four bytes of the buffer so we can 14462306a36Sopenharmony_ci check the buffer boundary condition next time */ 14562306a36Sopenharmony_ci memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4); 14662306a36Sopenharmony_ci bytes_parsed = 0; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return rc; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* ------------------------------------------------------------------ 15362306a36Sopenharmony_ci Vbi buf operations 15462306a36Sopenharmony_ci ------------------------------------------------------------------*/ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int vbi_queue_setup(struct vb2_queue *vq, 15762306a36Sopenharmony_ci unsigned int *nbuffers, unsigned int *nplanes, 15862306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct cx231xx *dev = vb2_get_drv_priv(vq); 16162306a36Sopenharmony_ci u32 height = 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci height = ((dev->norm & V4L2_STD_625_50) ? 16462306a36Sopenharmony_ci PAL_VBI_LINES : NTSC_VBI_LINES); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci *nplanes = 1; 16762306a36Sopenharmony_ci sizes[0] = (dev->width * height * 2 * 2); 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* This is called *without* dev->slock held; please keep it that way */ 17262306a36Sopenharmony_cistatic int vbi_buf_prepare(struct vb2_buffer *vb) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue); 17562306a36Sopenharmony_ci u32 height = 0; 17662306a36Sopenharmony_ci u32 size; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci height = ((dev->norm & V4L2_STD_625_50) ? 17962306a36Sopenharmony_ci PAL_VBI_LINES : NTSC_VBI_LINES); 18062306a36Sopenharmony_ci size = ((dev->width << 1) * height * 2); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) 18362306a36Sopenharmony_ci return -EINVAL; 18462306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, size); 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void vbi_buf_queue(struct vb2_buffer *vb) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue); 19162306a36Sopenharmony_ci struct cx231xx_buffer *buf = 19262306a36Sopenharmony_ci container_of(vb, struct cx231xx_buffer, vb.vb2_buf); 19362306a36Sopenharmony_ci struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; 19462306a36Sopenharmony_ci unsigned long flags; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci spin_lock_irqsave(&dev->vbi_mode.slock, flags); 19762306a36Sopenharmony_ci list_add_tail(&buf->list, &vidq->active); 19862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic void return_all_buffers(struct cx231xx *dev, 20262306a36Sopenharmony_ci enum vb2_buffer_state state) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; 20562306a36Sopenharmony_ci struct cx231xx_buffer *buf, *node; 20662306a36Sopenharmony_ci unsigned long flags; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci spin_lock_irqsave(&dev->vbi_mode.slock, flags); 20962306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.buf = NULL; 21062306a36Sopenharmony_ci list_for_each_entry_safe(buf, node, &vidq->active, list) { 21162306a36Sopenharmony_ci list_del(&buf->list); 21262306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, state); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int vbi_start_streaming(struct vb2_queue *vq, unsigned int count) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct cx231xx *dev = vb2_get_drv_priv(vq); 22062306a36Sopenharmony_ci struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; 22162306a36Sopenharmony_ci int ret; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci vidq->sequence = 0; 22462306a36Sopenharmony_ci ret = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS, 22562306a36Sopenharmony_ci CX231XX_NUM_VBI_BUFS, 22662306a36Sopenharmony_ci dev->vbi_mode.alt_max_pkt_size[0], 22762306a36Sopenharmony_ci cx231xx_isoc_vbi_copy); 22862306a36Sopenharmony_ci if (ret) 22962306a36Sopenharmony_ci return_all_buffers(dev, VB2_BUF_STATE_QUEUED); 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void vbi_stop_streaming(struct vb2_queue *vq) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct cx231xx *dev = vb2_get_drv_priv(vq); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return_all_buffers(dev, VB2_BUF_STATE_ERROR); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistruct vb2_ops cx231xx_vbi_qops = { 24162306a36Sopenharmony_ci .queue_setup = vbi_queue_setup, 24262306a36Sopenharmony_ci .buf_prepare = vbi_buf_prepare, 24362306a36Sopenharmony_ci .buf_queue = vbi_buf_queue, 24462306a36Sopenharmony_ci .start_streaming = vbi_start_streaming, 24562306a36Sopenharmony_ci .stop_streaming = vbi_stop_streaming, 24662306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 24762306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* ------------------------------------------------------------------ 25162306a36Sopenharmony_ci URB control 25262306a36Sopenharmony_ci ------------------------------------------------------------------*/ 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 25562306a36Sopenharmony_ci * IRQ callback, called by URB callback 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_cistatic void cx231xx_irq_vbi_callback(struct urb *urb) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct cx231xx_dmaqueue *dma_q = urb->context; 26062306a36Sopenharmony_ci struct cx231xx_video_mode *vmode = 26162306a36Sopenharmony_ci container_of(dma_q, struct cx231xx_video_mode, vidq); 26262306a36Sopenharmony_ci struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); 26362306a36Sopenharmony_ci unsigned long flags; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci switch (urb->status) { 26662306a36Sopenharmony_ci case 0: /* success */ 26762306a36Sopenharmony_ci case -ETIMEDOUT: /* NAK */ 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci case -ECONNRESET: /* kill */ 27062306a36Sopenharmony_ci case -ENOENT: 27162306a36Sopenharmony_ci case -ESHUTDOWN: 27262306a36Sopenharmony_ci return; 27362306a36Sopenharmony_ci default: /* error */ 27462306a36Sopenharmony_ci dev_err(dev->dev, 27562306a36Sopenharmony_ci "urb completion error %d.\n", urb->status); 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Copy data from URB */ 28062306a36Sopenharmony_ci spin_lock_irqsave(&dev->vbi_mode.slock, flags); 28162306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb); 28262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Reset status */ 28562306a36Sopenharmony_ci urb->status = 0; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci urb->status = usb_submit_urb(urb, GFP_ATOMIC); 28862306a36Sopenharmony_ci if (urb->status) { 28962306a36Sopenharmony_ci dev_err(dev->dev, "urb resubmit failed (error=%i)\n", 29062306a36Sopenharmony_ci urb->status); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* 29562306a36Sopenharmony_ci * Stop and Deallocate URBs 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_civoid cx231xx_uninit_vbi_isoc(struct cx231xx *dev) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct urb *urb; 30062306a36Sopenharmony_ci int i; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci dev_dbg(dev->dev, "called cx231xx_uninit_vbi_isoc\n"); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.nfields = -1; 30562306a36Sopenharmony_ci for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { 30662306a36Sopenharmony_ci urb = dev->vbi_mode.bulk_ctl.urb[i]; 30762306a36Sopenharmony_ci if (urb) { 30862306a36Sopenharmony_ci if (!irqs_disabled()) 30962306a36Sopenharmony_ci usb_kill_urb(urb); 31062306a36Sopenharmony_ci else 31162306a36Sopenharmony_ci usb_unlink_urb(urb); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci kfree(dev->vbi_mode.bulk_ctl. 31662306a36Sopenharmony_ci transfer_buffer[i]); 31762306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.transfer_buffer[i] = 31862306a36Sopenharmony_ci NULL; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci usb_free_urb(urb); 32162306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.urb[i] = NULL; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.transfer_buffer[i] = NULL; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci kfree(dev->vbi_mode.bulk_ctl.urb); 32762306a36Sopenharmony_ci kfree(dev->vbi_mode.bulk_ctl.transfer_buffer); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.urb = NULL; 33062306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.transfer_buffer = NULL; 33162306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.num_bufs = 0; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci cx231xx_capture_start(dev, 0, Vbi); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cx231xx_uninit_vbi_isoc); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/* 33862306a36Sopenharmony_ci * Allocate URBs and start IRQ 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ciint cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, 34162306a36Sopenharmony_ci int num_bufs, int max_pkt_size, 34262306a36Sopenharmony_ci int (*bulk_copy) (struct cx231xx *dev, 34362306a36Sopenharmony_ci struct urb *urb)) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct cx231xx_dmaqueue *dma_q = &dev->vbi_mode.vidq; 34662306a36Sopenharmony_ci int i; 34762306a36Sopenharmony_ci int sb_size, pipe; 34862306a36Sopenharmony_ci struct urb *urb; 34962306a36Sopenharmony_ci int rc; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci dev_dbg(dev->dev, "called cx231xx_vbi_isoc\n"); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* De-allocates all pending stuff */ 35462306a36Sopenharmony_ci cx231xx_uninit_vbi_isoc(dev); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* clear if any halt */ 35762306a36Sopenharmony_ci usb_clear_halt(dev->udev, 35862306a36Sopenharmony_ci usb_rcvbulkpipe(dev->udev, 35962306a36Sopenharmony_ci dev->vbi_mode.end_point_addr)); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.bulk_copy = bulk_copy; 36262306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.num_bufs = num_bufs; 36362306a36Sopenharmony_ci dma_q->pos = 0; 36462306a36Sopenharmony_ci dma_q->is_partial_line = 0; 36562306a36Sopenharmony_ci dma_q->last_sav = 0; 36662306a36Sopenharmony_ci dma_q->current_field = -1; 36762306a36Sopenharmony_ci dma_q->bytes_left_in_line = dev->width << 1; 36862306a36Sopenharmony_ci dma_q->lines_per_field = ((dev->norm & V4L2_STD_625_50) ? 36962306a36Sopenharmony_ci PAL_VBI_LINES : NTSC_VBI_LINES); 37062306a36Sopenharmony_ci dma_q->lines_completed = 0; 37162306a36Sopenharmony_ci for (i = 0; i < 8; i++) 37262306a36Sopenharmony_ci dma_q->partial_buf[i] = 0; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.urb = kcalloc(num_bufs, sizeof(void *), 37562306a36Sopenharmony_ci GFP_KERNEL); 37662306a36Sopenharmony_ci if (!dev->vbi_mode.bulk_ctl.urb) { 37762306a36Sopenharmony_ci dev_err(dev->dev, 37862306a36Sopenharmony_ci "cannot alloc memory for usb buffers\n"); 37962306a36Sopenharmony_ci return -ENOMEM; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.transfer_buffer = 38362306a36Sopenharmony_ci kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); 38462306a36Sopenharmony_ci if (!dev->vbi_mode.bulk_ctl.transfer_buffer) { 38562306a36Sopenharmony_ci dev_err(dev->dev, 38662306a36Sopenharmony_ci "cannot allocate memory for usbtransfer\n"); 38762306a36Sopenharmony_ci kfree(dev->vbi_mode.bulk_ctl.urb); 38862306a36Sopenharmony_ci return -ENOMEM; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.max_pkt_size = max_pkt_size; 39262306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.buf = NULL; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci sb_size = max_packets * dev->vbi_mode.bulk_ctl.max_pkt_size; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* allocate urbs and transfer buffers */ 39762306a36Sopenharmony_ci for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 40062306a36Sopenharmony_ci if (!urb) { 40162306a36Sopenharmony_ci cx231xx_uninit_vbi_isoc(dev); 40262306a36Sopenharmony_ci return -ENOMEM; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.urb[i] = urb; 40562306a36Sopenharmony_ci urb->transfer_flags = 0; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.transfer_buffer[i] = 40862306a36Sopenharmony_ci kzalloc(sb_size, GFP_KERNEL); 40962306a36Sopenharmony_ci if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { 41062306a36Sopenharmony_ci dev_err(dev->dev, 41162306a36Sopenharmony_ci "unable to allocate %i bytes for transfer buffer %i\n", 41262306a36Sopenharmony_ci sb_size, i); 41362306a36Sopenharmony_ci cx231xx_uninit_vbi_isoc(dev); 41462306a36Sopenharmony_ci return -ENOMEM; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci pipe = usb_rcvbulkpipe(dev->udev, dev->vbi_mode.end_point_addr); 41862306a36Sopenharmony_ci usb_fill_bulk_urb(urb, dev->udev, pipe, 41962306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.transfer_buffer[i], 42062306a36Sopenharmony_ci sb_size, cx231xx_irq_vbi_callback, dma_q); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci init_waitqueue_head(&dma_q->wq); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* submit urbs and enables IRQ */ 42662306a36Sopenharmony_ci for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { 42762306a36Sopenharmony_ci rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC); 42862306a36Sopenharmony_ci if (rc) { 42962306a36Sopenharmony_ci dev_err(dev->dev, 43062306a36Sopenharmony_ci "submit of urb %i failed (error=%i)\n", i, rc); 43162306a36Sopenharmony_ci cx231xx_uninit_vbi_isoc(dev); 43262306a36Sopenharmony_ci return rc; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci cx231xx_capture_start(dev, 1, Vbi); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cx231xx_init_vbi_isoc); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ciu32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, 44362306a36Sopenharmony_ci u8 sav_eav, u8 *p_buffer, u32 buffer_size) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci u32 bytes_copied = 0; 44662306a36Sopenharmony_ci int current_field = -1; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci switch (sav_eav) { 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci case SAV_VBI_FIELD1: 45162306a36Sopenharmony_ci current_field = 1; 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci case SAV_VBI_FIELD2: 45562306a36Sopenharmony_ci current_field = 2; 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci default: 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (current_field < 0) 46262306a36Sopenharmony_ci return bytes_copied; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci dma_q->last_sav = sav_eav; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci bytes_copied = 46762306a36Sopenharmony_ci cx231xx_copy_vbi_line(dev, dma_q, p_buffer, buffer_size, 46862306a36Sopenharmony_ci current_field); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return bytes_copied; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* 47462306a36Sopenharmony_ci * Announces that a buffer were filled and request the next 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_cistatic inline void vbi_buffer_filled(struct cx231xx *dev, 47762306a36Sopenharmony_ci struct cx231xx_dmaqueue *dma_q, 47862306a36Sopenharmony_ci struct cx231xx_buffer *buf) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci /* Advice that buffer was filled */ 48162306a36Sopenharmony_ci /* dev_dbg(dev->dev, "[%p/%d] wakeup\n", buf, buf->vb.index); */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci buf->vb.sequence = dma_q->sequence++; 48462306a36Sopenharmony_ci buf->vb.vb2_buf.timestamp = ktime_get_ns(); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.buf = NULL; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci list_del(&buf->list); 48962306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ciu32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, 49362306a36Sopenharmony_ci u8 *p_line, u32 length, int field_number) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci u32 bytes_to_copy; 49662306a36Sopenharmony_ci struct cx231xx_buffer *buf; 49762306a36Sopenharmony_ci u32 _line_size = dev->width * 2; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (dma_q->current_field == -1) { 50062306a36Sopenharmony_ci /* Just starting up */ 50162306a36Sopenharmony_ci cx231xx_reset_vbi_buffer(dev, dma_q); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (dma_q->current_field != field_number) 50562306a36Sopenharmony_ci dma_q->lines_completed = 0; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* get the buffer pointer */ 50862306a36Sopenharmony_ci buf = dev->vbi_mode.bulk_ctl.buf; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* Remember the field number for next time */ 51162306a36Sopenharmony_ci dma_q->current_field = field_number; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci bytes_to_copy = dma_q->bytes_left_in_line; 51462306a36Sopenharmony_ci if (bytes_to_copy > length) 51562306a36Sopenharmony_ci bytes_to_copy = length; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (dma_q->lines_completed >= dma_q->lines_per_field) { 51862306a36Sopenharmony_ci dma_q->bytes_left_in_line -= bytes_to_copy; 51962306a36Sopenharmony_ci dma_q->is_partial_line = 52062306a36Sopenharmony_ci (dma_q->bytes_left_in_line == 0) ? 0 : 1; 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci dma_q->is_partial_line = 1; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* If we don't have a buffer, just return the number of bytes we would 52762306a36Sopenharmony_ci have copied if we had a buffer. */ 52862306a36Sopenharmony_ci if (!buf) { 52962306a36Sopenharmony_ci dma_q->bytes_left_in_line -= bytes_to_copy; 53062306a36Sopenharmony_ci dma_q->is_partial_line = 53162306a36Sopenharmony_ci (dma_q->bytes_left_in_line == 0) ? 0 : 1; 53262306a36Sopenharmony_ci return bytes_to_copy; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* copy the data to video buffer */ 53662306a36Sopenharmony_ci cx231xx_do_vbi_copy(dev, dma_q, p_line, bytes_to_copy); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci dma_q->pos += bytes_to_copy; 53962306a36Sopenharmony_ci dma_q->bytes_left_in_line -= bytes_to_copy; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (dma_q->bytes_left_in_line == 0) { 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci dma_q->bytes_left_in_line = _line_size; 54462306a36Sopenharmony_ci dma_q->lines_completed++; 54562306a36Sopenharmony_ci dma_q->is_partial_line = 0; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (cx231xx_is_vbi_buffer_done(dev, dma_q) && buf) { 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci vbi_buffer_filled(dev, dma_q, buf); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci dma_q->pos = 0; 55262306a36Sopenharmony_ci dma_q->lines_completed = 0; 55362306a36Sopenharmony_ci cx231xx_reset_vbi_buffer(dev, dma_q); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return bytes_to_copy; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/* 56162306a36Sopenharmony_ci * generic routine to get the next available buffer 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_cistatic inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, 56462306a36Sopenharmony_ci struct cx231xx_buffer **buf) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct cx231xx_video_mode *vmode = 56762306a36Sopenharmony_ci container_of(dma_q, struct cx231xx_video_mode, vidq); 56862306a36Sopenharmony_ci struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); 56962306a36Sopenharmony_ci char *outp; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (list_empty(&dma_q->active)) { 57262306a36Sopenharmony_ci dev_err(dev->dev, "No active queue to serve\n"); 57362306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.buf = NULL; 57462306a36Sopenharmony_ci *buf = NULL; 57562306a36Sopenharmony_ci return; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* Get the next buffer */ 57962306a36Sopenharmony_ci *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Cleans up buffer - Useful for testing for frame/URB loss */ 58262306a36Sopenharmony_ci outp = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0); 58362306a36Sopenharmony_ci memset(outp, 0, vb2_plane_size(&(*buf)->vb.vb2_buf, 0)); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci dev->vbi_mode.bulk_ctl.buf = *buf; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_civoid cx231xx_reset_vbi_buffer(struct cx231xx *dev, 59162306a36Sopenharmony_ci struct cx231xx_dmaqueue *dma_q) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct cx231xx_buffer *buf; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci buf = dev->vbi_mode.bulk_ctl.buf; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (buf == NULL) { 59862306a36Sopenharmony_ci /* first try to get the buffer */ 59962306a36Sopenharmony_ci get_next_vbi_buf(dma_q, &buf); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci dma_q->pos = 0; 60262306a36Sopenharmony_ci dma_q->current_field = -1; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci dma_q->bytes_left_in_line = dev->width << 1; 60662306a36Sopenharmony_ci dma_q->lines_completed = 0; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ciint cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, 61062306a36Sopenharmony_ci u8 *p_buffer, u32 bytes_to_copy) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci u8 *p_out_buffer = NULL; 61362306a36Sopenharmony_ci u32 current_line_bytes_copied = 0; 61462306a36Sopenharmony_ci struct cx231xx_buffer *buf; 61562306a36Sopenharmony_ci u32 _line_size = dev->width << 1; 61662306a36Sopenharmony_ci void *startwrite; 61762306a36Sopenharmony_ci int offset, lencopy; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci buf = dev->vbi_mode.bulk_ctl.buf; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (buf == NULL) 62262306a36Sopenharmony_ci return -EINVAL; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci p_out_buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (dma_q->bytes_left_in_line != _line_size) { 62762306a36Sopenharmony_ci current_line_bytes_copied = 62862306a36Sopenharmony_ci _line_size - dma_q->bytes_left_in_line; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci offset = (dma_q->lines_completed * _line_size) + 63262306a36Sopenharmony_ci current_line_bytes_copied; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (dma_q->current_field == 2) { 63562306a36Sopenharmony_ci /* Populate the second half of the frame */ 63662306a36Sopenharmony_ci offset += (dev->width * 2 * dma_q->lines_per_field); 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci /* prepare destination address */ 64062306a36Sopenharmony_ci startwrite = p_out_buffer + offset; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci lencopy = dma_q->bytes_left_in_line > bytes_to_copy ? 64362306a36Sopenharmony_ci bytes_to_copy : dma_q->bytes_left_in_line; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci memcpy(startwrite, p_buffer, lencopy); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ciu8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev, 65162306a36Sopenharmony_ci struct cx231xx_dmaqueue *dma_q) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci u32 height = 0; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci height = ((dev->norm & V4L2_STD_625_50) ? 65662306a36Sopenharmony_ci PAL_VBI_LINES : NTSC_VBI_LINES); 65762306a36Sopenharmony_ci if (dma_q->lines_completed == height && dma_q->current_field == 2) 65862306a36Sopenharmony_ci return 1; 65962306a36Sopenharmony_ci else 66062306a36Sopenharmony_ci return 0; 66162306a36Sopenharmony_ci} 662