18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci   cx231xx-video.c - driver for Conexant Cx23100/101/102
48c2ecf20Sopenharmony_ci		     USB video capture devices
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
78c2ecf20Sopenharmony_ci	Based on em28xx driver
88c2ecf20Sopenharmony_ci	Based on cx23885 driver
98c2ecf20Sopenharmony_ci	Based on cx88 driver
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "cx231xx.h"
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/list.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
198c2ecf20Sopenharmony_ci#include <linux/i2c.h>
208c2ecf20Sopenharmony_ci#include <linux/mm.h>
218c2ecf20Sopenharmony_ci#include <linux/mutex.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
258c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h>
268c2ecf20Sopenharmony_ci#include <media/v4l2-event.h>
278c2ecf20Sopenharmony_ci#include <media/drv-intf/msp3400.h>
288c2ecf20Sopenharmony_ci#include <media/tuner.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "cx231xx-vbi.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define CX231XX_VERSION "0.0.3"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR   "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
378c2ecf20Sopenharmony_ci#define DRIVER_DESC     "Conexant cx231xx based USB video device driver"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define cx231xx_videodbg(fmt, arg...) do {\
408c2ecf20Sopenharmony_ci	if (video_debug) \
418c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s %s :"fmt, \
428c2ecf20Sopenharmony_ci			 dev->name, __func__ , ##arg); } while (0)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic unsigned int isoc_debug;
458c2ecf20Sopenharmony_cimodule_param(isoc_debug, int, 0644);
468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define cx231xx_isocdbg(fmt, arg...) \
498c2ecf20Sopenharmony_cido {\
508c2ecf20Sopenharmony_ci	if (isoc_debug) { \
518c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s %s :"fmt, \
528c2ecf20Sopenharmony_ci			 dev->name, __func__ , ##arg); \
538c2ecf20Sopenharmony_ci	} \
548c2ecf20Sopenharmony_ci  } while (0)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
598c2ecf20Sopenharmony_ciMODULE_VERSION(CX231XX_VERSION);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic unsigned int card[]     = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
628c2ecf20Sopenharmony_cistatic unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
638c2ecf20Sopenharmony_cistatic unsigned int vbi_nr[]   = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
648c2ecf20Sopenharmony_cistatic unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cimodule_param_array(card, int, NULL, 0444);
678c2ecf20Sopenharmony_cimodule_param_array(video_nr, int, NULL, 0444);
688c2ecf20Sopenharmony_cimodule_param_array(vbi_nr, int, NULL, 0444);
698c2ecf20Sopenharmony_cimodule_param_array(radio_nr, int, NULL, 0444);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(card, "card type");
728c2ecf20Sopenharmony_ciMODULE_PARM_DESC(video_nr, "video device numbers");
738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vbi_nr, "vbi device numbers");
748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(radio_nr, "radio device numbers");
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic unsigned int video_debug;
778c2ecf20Sopenharmony_cimodule_param(video_debug, int, 0644);
788c2ecf20Sopenharmony_ciMODULE_PARM_DESC(video_debug, "enable debug messages [video]");
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* supported video standards */
818c2ecf20Sopenharmony_cistatic struct cx231xx_fmt format[] = {
828c2ecf20Sopenharmony_ci	{
838c2ecf20Sopenharmony_ci	 .fourcc = V4L2_PIX_FMT_YUYV,
848c2ecf20Sopenharmony_ci	 .depth = 16,
858c2ecf20Sopenharmony_ci	 .reg = 0,
868c2ecf20Sopenharmony_ci	 },
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int cx231xx_enable_analog_tuner(struct cx231xx *dev)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
938c2ecf20Sopenharmony_ci	struct media_device *mdev = dev->media_dev;
948c2ecf20Sopenharmony_ci	struct media_entity  *entity, *decoder = NULL, *source;
958c2ecf20Sopenharmony_ci	struct media_link *link, *found_link = NULL;
968c2ecf20Sopenharmony_ci	int ret, active_links = 0;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (!mdev)
998c2ecf20Sopenharmony_ci		return 0;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/*
1028c2ecf20Sopenharmony_ci	 * This will find the tuner that is connected into the decoder.
1038c2ecf20Sopenharmony_ci	 * Technically, this is not 100% correct, as the device may be
1048c2ecf20Sopenharmony_ci	 * using an analog input instead of the tuner. However, as we can't
1058c2ecf20Sopenharmony_ci	 * do DVB streaming while the DMA engine is being used for V4L2,
1068c2ecf20Sopenharmony_ci	 * this should be enough for the actual needs.
1078c2ecf20Sopenharmony_ci	 */
1088c2ecf20Sopenharmony_ci	media_device_for_each_entity(entity, mdev) {
1098c2ecf20Sopenharmony_ci		if (entity->function == MEDIA_ENT_F_ATV_DECODER) {
1108c2ecf20Sopenharmony_ci			decoder = entity;
1118c2ecf20Sopenharmony_ci			break;
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	if (!decoder)
1158c2ecf20Sopenharmony_ci		return 0;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	list_for_each_entry(link, &decoder->links, list) {
1188c2ecf20Sopenharmony_ci		if (link->sink->entity == decoder) {
1198c2ecf20Sopenharmony_ci			found_link = link;
1208c2ecf20Sopenharmony_ci			if (link->flags & MEDIA_LNK_FL_ENABLED)
1218c2ecf20Sopenharmony_ci				active_links++;
1228c2ecf20Sopenharmony_ci			break;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (active_links == 1 || !found_link)
1278c2ecf20Sopenharmony_ci		return 0;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	source = found_link->source->entity;
1308c2ecf20Sopenharmony_ci	list_for_each_entry(link, &source->links, list) {
1318c2ecf20Sopenharmony_ci		struct media_entity *sink;
1328c2ecf20Sopenharmony_ci		int flags = 0;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		sink = link->sink->entity;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		if (sink == entity)
1378c2ecf20Sopenharmony_ci			flags = MEDIA_LNK_FL_ENABLED;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		ret = media_entity_setup_link(link, flags);
1408c2ecf20Sopenharmony_ci		if (ret) {
1418c2ecf20Sopenharmony_ci			dev_err(dev->dev,
1428c2ecf20Sopenharmony_ci				"Couldn't change link %s->%s to %s. Error %d\n",
1438c2ecf20Sopenharmony_ci				source->name, sink->name,
1448c2ecf20Sopenharmony_ci				flags ? "enabled" : "disabled",
1458c2ecf20Sopenharmony_ci				ret);
1468c2ecf20Sopenharmony_ci			return ret;
1478c2ecf20Sopenharmony_ci		} else
1488c2ecf20Sopenharmony_ci			dev_dbg(dev->dev,
1498c2ecf20Sopenharmony_ci				"link %s->%s was %s\n",
1508c2ecf20Sopenharmony_ci				source->name, sink->name,
1518c2ecf20Sopenharmony_ci				flags ? "ENABLED" : "disabled");
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci#endif
1548c2ecf20Sopenharmony_ci	return 0;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------
1588c2ecf20Sopenharmony_ci	Video buffer and parser functions
1598c2ecf20Sopenharmony_ci   ------------------------------------------------------------------*/
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/*
1628c2ecf20Sopenharmony_ci * Announces that a buffer were filled and request the next
1638c2ecf20Sopenharmony_ci */
1648c2ecf20Sopenharmony_cistatic inline void buffer_filled(struct cx231xx *dev,
1658c2ecf20Sopenharmony_ci				 struct cx231xx_dmaqueue *dma_q,
1668c2ecf20Sopenharmony_ci				 struct cx231xx_buffer *buf)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	/* Advice that buffer was filled */
1698c2ecf20Sopenharmony_ci	cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.vb2_buf.index);
1708c2ecf20Sopenharmony_ci	buf->vb.sequence = dma_q->sequence++;
1718c2ecf20Sopenharmony_ci	buf->vb.field = V4L2_FIELD_INTERLACED;
1728c2ecf20Sopenharmony_ci	buf->vb.vb2_buf.timestamp = ktime_get_ns();
1738c2ecf20Sopenharmony_ci	vb2_set_plane_payload(&buf->vb.vb2_buf, 0, dev->size);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
1768c2ecf20Sopenharmony_ci		dev->video_mode.isoc_ctl.buf = NULL;
1778c2ecf20Sopenharmony_ci	else
1788c2ecf20Sopenharmony_ci		dev->video_mode.bulk_ctl.buf = NULL;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	list_del(&buf->list);
1818c2ecf20Sopenharmony_ci	vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic inline void print_err_status(struct cx231xx *dev, int packet, int status)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	char *errmsg = "Unknown";
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	switch (status) {
1898c2ecf20Sopenharmony_ci	case -ENOENT:
1908c2ecf20Sopenharmony_ci		errmsg = "unlinked synchronously";
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci	case -ECONNRESET:
1938c2ecf20Sopenharmony_ci		errmsg = "unlinked asynchronously";
1948c2ecf20Sopenharmony_ci		break;
1958c2ecf20Sopenharmony_ci	case -ENOSR:
1968c2ecf20Sopenharmony_ci		errmsg = "Buffer error (overrun)";
1978c2ecf20Sopenharmony_ci		break;
1988c2ecf20Sopenharmony_ci	case -EPIPE:
1998c2ecf20Sopenharmony_ci		errmsg = "Stalled (device not responding)";
2008c2ecf20Sopenharmony_ci		break;
2018c2ecf20Sopenharmony_ci	case -EOVERFLOW:
2028c2ecf20Sopenharmony_ci		errmsg = "Babble (bad cable?)";
2038c2ecf20Sopenharmony_ci		break;
2048c2ecf20Sopenharmony_ci	case -EPROTO:
2058c2ecf20Sopenharmony_ci		errmsg = "Bit-stuff error (bad cable?)";
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci	case -EILSEQ:
2088c2ecf20Sopenharmony_ci		errmsg = "CRC/Timeout (could be anything)";
2098c2ecf20Sopenharmony_ci		break;
2108c2ecf20Sopenharmony_ci	case -ETIME:
2118c2ecf20Sopenharmony_ci		errmsg = "Device does not respond";
2128c2ecf20Sopenharmony_ci		break;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	if (packet < 0) {
2158c2ecf20Sopenharmony_ci		cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg);
2168c2ecf20Sopenharmony_ci	} else {
2178c2ecf20Sopenharmony_ci		cx231xx_isocdbg("URB packet %d, status %d [%s].\n",
2188c2ecf20Sopenharmony_ci				packet, status, errmsg);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/*
2238c2ecf20Sopenharmony_ci * video-buf generic routine to get the next available buffer
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistatic inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
2268c2ecf20Sopenharmony_ci				struct cx231xx_buffer **buf)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct cx231xx_video_mode *vmode =
2298c2ecf20Sopenharmony_ci	    container_of(dma_q, struct cx231xx_video_mode, vidq);
2308c2ecf20Sopenharmony_ci	struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	char *outp;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (list_empty(&dma_q->active)) {
2358c2ecf20Sopenharmony_ci		cx231xx_isocdbg("No active queue to serve\n");
2368c2ecf20Sopenharmony_ci		if (dev->USE_ISO)
2378c2ecf20Sopenharmony_ci			dev->video_mode.isoc_ctl.buf = NULL;
2388c2ecf20Sopenharmony_ci		else
2398c2ecf20Sopenharmony_ci			dev->video_mode.bulk_ctl.buf = NULL;
2408c2ecf20Sopenharmony_ci		*buf = NULL;
2418c2ecf20Sopenharmony_ci		return;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* Get the next buffer */
2458c2ecf20Sopenharmony_ci	*buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/* Cleans up buffer - Useful for testing for frame/URB loss */
2488c2ecf20Sopenharmony_ci	outp = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
2498c2ecf20Sopenharmony_ci	memset(outp, 0, dev->size);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
2528c2ecf20Sopenharmony_ci		dev->video_mode.isoc_ctl.buf = *buf;
2538c2ecf20Sopenharmony_ci	else
2548c2ecf20Sopenharmony_ci		dev->video_mode.bulk_ctl.buf = *buf;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return;
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/*
2608c2ecf20Sopenharmony_ci * Controls the isoc copy of each urb packet
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_cistatic inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *dma_q = urb->context;
2658c2ecf20Sopenharmony_ci	int i;
2668c2ecf20Sopenharmony_ci	unsigned char *p_buffer;
2678c2ecf20Sopenharmony_ci	u32 bytes_parsed = 0, buffer_size = 0;
2688c2ecf20Sopenharmony_ci	u8 sav_eav = 0;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (!dev)
2718c2ecf20Sopenharmony_ci		return 0;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (dev->state & DEV_DISCONNECTED)
2748c2ecf20Sopenharmony_ci		return 0;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (urb->status < 0) {
2778c2ecf20Sopenharmony_ci		print_err_status(dev, -1, urb->status);
2788c2ecf20Sopenharmony_ci		if (urb->status == -ENOENT)
2798c2ecf20Sopenharmony_ci			return 0;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	for (i = 0; i < urb->number_of_packets; i++) {
2838c2ecf20Sopenharmony_ci		int status = urb->iso_frame_desc[i].status;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		if (status < 0) {
2868c2ecf20Sopenharmony_ci			print_err_status(dev, i, status);
2878c2ecf20Sopenharmony_ci			if (urb->iso_frame_desc[i].status != -EPROTO)
2888c2ecf20Sopenharmony_ci				continue;
2898c2ecf20Sopenharmony_ci		}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		if (urb->iso_frame_desc[i].actual_length <= 0) {
2928c2ecf20Sopenharmony_ci			/* cx231xx_isocdbg("packet %d is empty",i); - spammy */
2938c2ecf20Sopenharmony_ci			continue;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci		if (urb->iso_frame_desc[i].actual_length >
2968c2ecf20Sopenharmony_ci		    dev->video_mode.max_pkt_size) {
2978c2ecf20Sopenharmony_ci			cx231xx_isocdbg("packet bigger than packet size");
2988c2ecf20Sopenharmony_ci			continue;
2998c2ecf20Sopenharmony_ci		}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		/*  get buffer pointer and length */
3028c2ecf20Sopenharmony_ci		p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
3038c2ecf20Sopenharmony_ci		buffer_size = urb->iso_frame_desc[i].actual_length;
3048c2ecf20Sopenharmony_ci		bytes_parsed = 0;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		if (dma_q->is_partial_line) {
3078c2ecf20Sopenharmony_ci			/* Handle the case of a partial line */
3088c2ecf20Sopenharmony_ci			sav_eav = dma_q->last_sav;
3098c2ecf20Sopenharmony_ci		} else {
3108c2ecf20Sopenharmony_ci			/* Check for a SAV/EAV overlapping
3118c2ecf20Sopenharmony_ci				the buffer boundary */
3128c2ecf20Sopenharmony_ci			sav_eav =
3138c2ecf20Sopenharmony_ci			    cx231xx_find_boundary_SAV_EAV(p_buffer,
3148c2ecf20Sopenharmony_ci							  dma_q->partial_buf,
3158c2ecf20Sopenharmony_ci							  &bytes_parsed);
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		sav_eav &= 0xF0;
3198c2ecf20Sopenharmony_ci		/* Get the first line if we have some portion of an SAV/EAV from
3208c2ecf20Sopenharmony_ci		   the last buffer or a partial line  */
3218c2ecf20Sopenharmony_ci		if (sav_eav) {
3228c2ecf20Sopenharmony_ci			bytes_parsed += cx231xx_get_video_line(dev, dma_q,
3238c2ecf20Sopenharmony_ci				sav_eav,	/* SAV/EAV */
3248c2ecf20Sopenharmony_ci				p_buffer + bytes_parsed,	/* p_buffer */
3258c2ecf20Sopenharmony_ci				buffer_size - bytes_parsed);/* buf size */
3268c2ecf20Sopenharmony_ci		}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		/* Now parse data that is completely in this buffer */
3298c2ecf20Sopenharmony_ci		/* dma_q->is_partial_line = 0;  */
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci		while (bytes_parsed < buffer_size) {
3328c2ecf20Sopenharmony_ci			u32 bytes_used = 0;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci			sav_eav = cx231xx_find_next_SAV_EAV(
3358c2ecf20Sopenharmony_ci				p_buffer + bytes_parsed,	/* p_buffer */
3368c2ecf20Sopenharmony_ci				buffer_size - bytes_parsed,	/* buf size */
3378c2ecf20Sopenharmony_ci				&bytes_used);/* bytes used to get SAV/EAV */
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci			bytes_parsed += bytes_used;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci			sav_eav &= 0xF0;
3428c2ecf20Sopenharmony_ci			if (sav_eav && (bytes_parsed < buffer_size)) {
3438c2ecf20Sopenharmony_ci				bytes_parsed += cx231xx_get_video_line(dev,
3448c2ecf20Sopenharmony_ci					dma_q, sav_eav,	/* SAV/EAV */
3458c2ecf20Sopenharmony_ci					p_buffer + bytes_parsed,/* p_buffer */
3468c2ecf20Sopenharmony_ci					buffer_size - bytes_parsed);/*buf size*/
3478c2ecf20Sopenharmony_ci			}
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		/* Save the last four bytes of the buffer so we can check the
3518c2ecf20Sopenharmony_ci		   buffer boundary condition next time */
3528c2ecf20Sopenharmony_ci		memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
3538c2ecf20Sopenharmony_ci		bytes_parsed = 0;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci	return 1;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *dma_q = urb->context;
3628c2ecf20Sopenharmony_ci	unsigned char *p_buffer;
3638c2ecf20Sopenharmony_ci	u32 bytes_parsed = 0, buffer_size = 0;
3648c2ecf20Sopenharmony_ci	u8 sav_eav = 0;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (!dev)
3678c2ecf20Sopenharmony_ci		return 0;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (dev->state & DEV_DISCONNECTED)
3708c2ecf20Sopenharmony_ci		return 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (urb->status < 0) {
3738c2ecf20Sopenharmony_ci		print_err_status(dev, -1, urb->status);
3748c2ecf20Sopenharmony_ci		if (urb->status == -ENOENT)
3758c2ecf20Sopenharmony_ci			return 0;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (1) {
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		/*  get buffer pointer and length */
3818c2ecf20Sopenharmony_ci		p_buffer = urb->transfer_buffer;
3828c2ecf20Sopenharmony_ci		buffer_size = urb->actual_length;
3838c2ecf20Sopenharmony_ci		bytes_parsed = 0;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		if (dma_q->is_partial_line) {
3868c2ecf20Sopenharmony_ci			/* Handle the case of a partial line */
3878c2ecf20Sopenharmony_ci			sav_eav = dma_q->last_sav;
3888c2ecf20Sopenharmony_ci		} else {
3898c2ecf20Sopenharmony_ci			/* Check for a SAV/EAV overlapping
3908c2ecf20Sopenharmony_ci				the buffer boundary */
3918c2ecf20Sopenharmony_ci			sav_eav =
3928c2ecf20Sopenharmony_ci			    cx231xx_find_boundary_SAV_EAV(p_buffer,
3938c2ecf20Sopenharmony_ci							  dma_q->partial_buf,
3948c2ecf20Sopenharmony_ci							  &bytes_parsed);
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		sav_eav &= 0xF0;
3988c2ecf20Sopenharmony_ci		/* Get the first line if we have some portion of an SAV/EAV from
3998c2ecf20Sopenharmony_ci		   the last buffer or a partial line  */
4008c2ecf20Sopenharmony_ci		if (sav_eav) {
4018c2ecf20Sopenharmony_ci			bytes_parsed += cx231xx_get_video_line(dev, dma_q,
4028c2ecf20Sopenharmony_ci				sav_eav,	/* SAV/EAV */
4038c2ecf20Sopenharmony_ci				p_buffer + bytes_parsed,	/* p_buffer */
4048c2ecf20Sopenharmony_ci				buffer_size - bytes_parsed);/* buf size */
4058c2ecf20Sopenharmony_ci		}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		/* Now parse data that is completely in this buffer */
4088c2ecf20Sopenharmony_ci		/* dma_q->is_partial_line = 0;  */
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci		while (bytes_parsed < buffer_size) {
4118c2ecf20Sopenharmony_ci			u32 bytes_used = 0;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci			sav_eav = cx231xx_find_next_SAV_EAV(
4148c2ecf20Sopenharmony_ci				p_buffer + bytes_parsed,	/* p_buffer */
4158c2ecf20Sopenharmony_ci				buffer_size - bytes_parsed,	/* buf size */
4168c2ecf20Sopenharmony_ci				&bytes_used);/* bytes used to get SAV/EAV */
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci			bytes_parsed += bytes_used;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci			sav_eav &= 0xF0;
4218c2ecf20Sopenharmony_ci			if (sav_eav && (bytes_parsed < buffer_size)) {
4228c2ecf20Sopenharmony_ci				bytes_parsed += cx231xx_get_video_line(dev,
4238c2ecf20Sopenharmony_ci					dma_q, sav_eav,	/* SAV/EAV */
4248c2ecf20Sopenharmony_ci					p_buffer + bytes_parsed,/* p_buffer */
4258c2ecf20Sopenharmony_ci					buffer_size - bytes_parsed);/*buf size*/
4268c2ecf20Sopenharmony_ci			}
4278c2ecf20Sopenharmony_ci		}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		/* Save the last four bytes of the buffer so we can check the
4308c2ecf20Sopenharmony_ci		   buffer boundary condition next time */
4318c2ecf20Sopenharmony_ci		memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
4328c2ecf20Sopenharmony_ci		bytes_parsed = 0;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci	return 1;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ciu8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
4408c2ecf20Sopenharmony_ci				 u32 *p_bytes_used)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	u32 bytes_used;
4438c2ecf20Sopenharmony_ci	u8 boundary_bytes[8];
4448c2ecf20Sopenharmony_ci	u8 sav_eav = 0;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	*p_bytes_used = 0;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* Create an array of the last 4 bytes of the last buffer and the first
4498c2ecf20Sopenharmony_ci	   4 bytes of the current buffer. */
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	memcpy(boundary_bytes, partial_buf, 4);
4528c2ecf20Sopenharmony_ci	memcpy(boundary_bytes + 4, p_buffer, 4);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* Check for the SAV/EAV in the boundary buffer */
4558c2ecf20Sopenharmony_ci	sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8,
4568c2ecf20Sopenharmony_ci					    &bytes_used);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (sav_eav) {
4598c2ecf20Sopenharmony_ci		/* found a boundary SAV/EAV.  Updates the bytes used to reflect
4608c2ecf20Sopenharmony_ci		   only those used in the new buffer */
4618c2ecf20Sopenharmony_ci		*p_bytes_used = bytes_used - 4;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return sav_eav;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ciu8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	u32 i;
4708c2ecf20Sopenharmony_ci	u8 sav_eav = 0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/*
4738c2ecf20Sopenharmony_ci	 * Don't search if the buffer size is less than 4.  It causes a page
4748c2ecf20Sopenharmony_ci	 * fault since buffer_size - 4 evaluates to a large number in that
4758c2ecf20Sopenharmony_ci	 * case.
4768c2ecf20Sopenharmony_ci	 */
4778c2ecf20Sopenharmony_ci	if (buffer_size < 4) {
4788c2ecf20Sopenharmony_ci		*p_bytes_used = buffer_size;
4798c2ecf20Sopenharmony_ci		return 0;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	for (i = 0; i < (buffer_size - 3); i++) {
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		if ((p_buffer[i] == 0xFF) &&
4858c2ecf20Sopenharmony_ci		    (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) {
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci			*p_bytes_used = i + 4;
4888c2ecf20Sopenharmony_ci			sav_eav = p_buffer[i + 3];
4898c2ecf20Sopenharmony_ci			return sav_eav;
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	*p_bytes_used = buffer_size;
4948c2ecf20Sopenharmony_ci	return 0;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ciu32 cx231xx_get_video_line(struct cx231xx *dev,
4988c2ecf20Sopenharmony_ci			   struct cx231xx_dmaqueue *dma_q, u8 sav_eav,
4998c2ecf20Sopenharmony_ci			   u8 *p_buffer, u32 buffer_size)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	u32 bytes_copied = 0;
5028c2ecf20Sopenharmony_ci	int current_field = -1;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	switch (sav_eav) {
5058c2ecf20Sopenharmony_ci	case SAV_ACTIVE_VIDEO_FIELD1:
5068c2ecf20Sopenharmony_ci		/* looking for skipped line which occurred in PAL 720x480 mode.
5078c2ecf20Sopenharmony_ci		   In this case, there will be no active data contained
5088c2ecf20Sopenharmony_ci		   between the SAV and EAV */
5098c2ecf20Sopenharmony_ci		if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
5108c2ecf20Sopenharmony_ci		    (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
5118c2ecf20Sopenharmony_ci		    ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
5128c2ecf20Sopenharmony_ci		     (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
5138c2ecf20Sopenharmony_ci		     (p_buffer[3] == EAV_VBLANK_FIELD1) ||
5148c2ecf20Sopenharmony_ci		     (p_buffer[3] == EAV_VBLANK_FIELD2)))
5158c2ecf20Sopenharmony_ci			return bytes_copied;
5168c2ecf20Sopenharmony_ci		current_field = 1;
5178c2ecf20Sopenharmony_ci		break;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	case SAV_ACTIVE_VIDEO_FIELD2:
5208c2ecf20Sopenharmony_ci		/* looking for skipped line which occurred in PAL 720x480 mode.
5218c2ecf20Sopenharmony_ci		   In this case, there will be no active data contained between
5228c2ecf20Sopenharmony_ci		   the SAV and EAV */
5238c2ecf20Sopenharmony_ci		if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
5248c2ecf20Sopenharmony_ci		    (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
5258c2ecf20Sopenharmony_ci		    ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
5268c2ecf20Sopenharmony_ci		     (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
5278c2ecf20Sopenharmony_ci		     (p_buffer[3] == EAV_VBLANK_FIELD1)       ||
5288c2ecf20Sopenharmony_ci		     (p_buffer[3] == EAV_VBLANK_FIELD2)))
5298c2ecf20Sopenharmony_ci			return bytes_copied;
5308c2ecf20Sopenharmony_ci		current_field = 2;
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	dma_q->last_sav = sav_eav;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer,
5378c2ecf20Sopenharmony_ci					       buffer_size, current_field);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return bytes_copied;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ciu32 cx231xx_copy_video_line(struct cx231xx *dev,
5438c2ecf20Sopenharmony_ci			    struct cx231xx_dmaqueue *dma_q, u8 *p_line,
5448c2ecf20Sopenharmony_ci			    u32 length, int field_number)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	u32 bytes_to_copy;
5478c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf;
5488c2ecf20Sopenharmony_ci	u32 _line_size = dev->width * 2;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (dma_q->current_field != field_number)
5518c2ecf20Sopenharmony_ci		cx231xx_reset_video_buffer(dev, dma_q);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/* get the buffer pointer */
5548c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
5558c2ecf20Sopenharmony_ci		buf = dev->video_mode.isoc_ctl.buf;
5568c2ecf20Sopenharmony_ci	else
5578c2ecf20Sopenharmony_ci		buf = dev->video_mode.bulk_ctl.buf;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* Remember the field number for next time */
5608c2ecf20Sopenharmony_ci	dma_q->current_field = field_number;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	bytes_to_copy = dma_q->bytes_left_in_line;
5638c2ecf20Sopenharmony_ci	if (bytes_to_copy > length)
5648c2ecf20Sopenharmony_ci		bytes_to_copy = length;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (dma_q->lines_completed >= dma_q->lines_per_field) {
5678c2ecf20Sopenharmony_ci		dma_q->bytes_left_in_line -= bytes_to_copy;
5688c2ecf20Sopenharmony_ci		dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ?
5698c2ecf20Sopenharmony_ci					  0 : 1;
5708c2ecf20Sopenharmony_ci		return 0;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	dma_q->is_partial_line = 1;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* If we don't have a buffer, just return the number of bytes we would
5768c2ecf20Sopenharmony_ci	   have copied if we had a buffer. */
5778c2ecf20Sopenharmony_ci	if (!buf) {
5788c2ecf20Sopenharmony_ci		dma_q->bytes_left_in_line -= bytes_to_copy;
5798c2ecf20Sopenharmony_ci		dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0)
5808c2ecf20Sopenharmony_ci					 ? 0 : 1;
5818c2ecf20Sopenharmony_ci		return bytes_to_copy;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/* copy the data to video buffer */
5858c2ecf20Sopenharmony_ci	cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	dma_q->pos += bytes_to_copy;
5888c2ecf20Sopenharmony_ci	dma_q->bytes_left_in_line -= bytes_to_copy;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if (dma_q->bytes_left_in_line == 0) {
5918c2ecf20Sopenharmony_ci		dma_q->bytes_left_in_line = _line_size;
5928c2ecf20Sopenharmony_ci		dma_q->lines_completed++;
5938c2ecf20Sopenharmony_ci		dma_q->is_partial_line = 0;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		if (cx231xx_is_buffer_done(dev, dma_q) && buf) {
5968c2ecf20Sopenharmony_ci			buffer_filled(dev, dma_q, buf);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci			dma_q->pos = 0;
5998c2ecf20Sopenharmony_ci			buf = NULL;
6008c2ecf20Sopenharmony_ci			dma_q->lines_completed = 0;
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	return bytes_to_copy;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_civoid cx231xx_reset_video_buffer(struct cx231xx *dev,
6088c2ecf20Sopenharmony_ci				struct cx231xx_dmaqueue *dma_q)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* handle the switch from field 1 to field 2 */
6138c2ecf20Sopenharmony_ci	if (dma_q->current_field == 1) {
6148c2ecf20Sopenharmony_ci		if (dma_q->lines_completed >= dma_q->lines_per_field)
6158c2ecf20Sopenharmony_ci			dma_q->field1_done = 1;
6168c2ecf20Sopenharmony_ci		else
6178c2ecf20Sopenharmony_ci			dma_q->field1_done = 0;
6188c2ecf20Sopenharmony_ci	}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
6218c2ecf20Sopenharmony_ci		buf = dev->video_mode.isoc_ctl.buf;
6228c2ecf20Sopenharmony_ci	else
6238c2ecf20Sopenharmony_ci		buf = dev->video_mode.bulk_ctl.buf;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	if (buf == NULL) {
6268c2ecf20Sopenharmony_ci		/* first try to get the buffer */
6278c2ecf20Sopenharmony_ci		get_next_buf(dma_q, &buf);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		dma_q->pos = 0;
6308c2ecf20Sopenharmony_ci		dma_q->field1_done = 0;
6318c2ecf20Sopenharmony_ci		dma_q->current_field = -1;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/* reset the counters */
6358c2ecf20Sopenharmony_ci	dma_q->bytes_left_in_line = dev->width << 1;
6368c2ecf20Sopenharmony_ci	dma_q->lines_completed = 0;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ciint cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
6408c2ecf20Sopenharmony_ci		    u8 *p_buffer, u32 bytes_to_copy)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	u8 *p_out_buffer = NULL;
6438c2ecf20Sopenharmony_ci	u32 current_line_bytes_copied = 0;
6448c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf;
6458c2ecf20Sopenharmony_ci	u32 _line_size = dev->width << 1;
6468c2ecf20Sopenharmony_ci	void *startwrite;
6478c2ecf20Sopenharmony_ci	int offset, lencopy;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
6508c2ecf20Sopenharmony_ci		buf = dev->video_mode.isoc_ctl.buf;
6518c2ecf20Sopenharmony_ci	else
6528c2ecf20Sopenharmony_ci		buf = dev->video_mode.bulk_ctl.buf;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	if (buf == NULL)
6558c2ecf20Sopenharmony_ci		return -1;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	p_out_buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	/* Offset field 2 one line from the top of the buffer */
6628c2ecf20Sopenharmony_ci	offset = (dma_q->current_field == 1) ? 0 : _line_size;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	/* Offset for field 2 */
6658c2ecf20Sopenharmony_ci	startwrite = p_out_buffer + offset;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	/* lines already completed in the current field */
6688c2ecf20Sopenharmony_ci	startwrite += (dma_q->lines_completed * _line_size * 2);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	/* bytes already completed in the current line */
6718c2ecf20Sopenharmony_ci	startwrite += current_line_bytes_copied;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
6748c2ecf20Sopenharmony_ci		  bytes_to_copy : dma_q->bytes_left_in_line;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + dev->size))
6778c2ecf20Sopenharmony_ci		return 0;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* The below copies the UYVY data straight into video buffer */
6808c2ecf20Sopenharmony_ci	cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	return 0;
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_civoid cx231xx_swab(u16 *from, u16 *to, u16 len)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	u16 i;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (len <= 0)
6908c2ecf20Sopenharmony_ci		return;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	for (i = 0; i < len / 2; i++)
6938c2ecf20Sopenharmony_ci		to[i] = (from[i] << 8) | (from[i] >> 8);
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ciu8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	u8 buffer_complete = 0;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* Dual field stream */
7018c2ecf20Sopenharmony_ci	buffer_complete = ((dma_q->current_field == 2) &&
7028c2ecf20Sopenharmony_ci			   (dma_q->lines_completed >= dma_q->lines_per_field) &&
7038c2ecf20Sopenharmony_ci			    dma_q->field1_done);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	return buffer_complete;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------
7098c2ecf20Sopenharmony_ci	Videobuf operations
7108c2ecf20Sopenharmony_ci   ------------------------------------------------------------------*/
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int queue_setup(struct vb2_queue *vq,
7138c2ecf20Sopenharmony_ci		       unsigned int *nbuffers, unsigned int *nplanes,
7148c2ecf20Sopenharmony_ci		       unsigned int sizes[], struct device *alloc_devs[])
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	dev->size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF)
7218c2ecf20Sopenharmony_ci		*nbuffers = CX231XX_MIN_BUF - vq->num_buffers;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if (*nplanes)
7248c2ecf20Sopenharmony_ci		return sizes[0] < dev->size ? -EINVAL : 0;
7258c2ecf20Sopenharmony_ci	*nplanes = 1;
7268c2ecf20Sopenharmony_ci	sizes[0] = dev->size;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	return 0;
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic void buffer_queue(struct vb2_buffer *vb)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf =
7348c2ecf20Sopenharmony_ci	    container_of(vb, struct cx231xx_buffer, vb.vb2_buf);
7358c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue);
7368c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
7378c2ecf20Sopenharmony_ci	unsigned long flags;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
7408c2ecf20Sopenharmony_ci	list_add_tail(&buf->list, &vidq->active);
7418c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic void return_all_buffers(struct cx231xx *dev,
7458c2ecf20Sopenharmony_ci			       enum vb2_buffer_state state)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
7488c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf, *node;
7498c2ecf20Sopenharmony_ci	unsigned long flags;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
7528c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
7538c2ecf20Sopenharmony_ci		dev->video_mode.isoc_ctl.buf = NULL;
7548c2ecf20Sopenharmony_ci	else
7558c2ecf20Sopenharmony_ci		dev->video_mode.bulk_ctl.buf = NULL;
7568c2ecf20Sopenharmony_ci	list_for_each_entry_safe(buf, node, &vidq->active, list) {
7578c2ecf20Sopenharmony_ci		list_del(&buf->list);
7588c2ecf20Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, state);
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic int start_streaming(struct vb2_queue *vq, unsigned int count)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
7668c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
7678c2ecf20Sopenharmony_ci	int ret = 0;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	vidq->sequence = 0;
7708c2ecf20Sopenharmony_ci	dev->mode_tv = 0;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	cx231xx_enable_analog_tuner(dev);
7738c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
7748c2ecf20Sopenharmony_ci		ret = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
7758c2ecf20Sopenharmony_ci					CX231XX_NUM_BUFS,
7768c2ecf20Sopenharmony_ci					dev->video_mode.max_pkt_size,
7778c2ecf20Sopenharmony_ci					cx231xx_isoc_copy);
7788c2ecf20Sopenharmony_ci	else
7798c2ecf20Sopenharmony_ci		ret = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
7808c2ecf20Sopenharmony_ci					CX231XX_NUM_BUFS,
7818c2ecf20Sopenharmony_ci					dev->video_mode.max_pkt_size,
7828c2ecf20Sopenharmony_ci					cx231xx_bulk_copy);
7838c2ecf20Sopenharmony_ci	if (ret)
7848c2ecf20Sopenharmony_ci		return_all_buffers(dev, VB2_BUF_STATE_QUEUED);
7858c2ecf20Sopenharmony_ci	call_all(dev, video, s_stream, 1);
7868c2ecf20Sopenharmony_ci	return ret;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic void stop_streaming(struct vb2_queue *vq)
7908c2ecf20Sopenharmony_ci{
7918c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	call_all(dev, video, s_stream, 0);
7948c2ecf20Sopenharmony_ci	return_all_buffers(dev, VB2_BUF_STATE_ERROR);
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic struct vb2_ops cx231xx_video_qops = {
7988c2ecf20Sopenharmony_ci	.queue_setup		= queue_setup,
7998c2ecf20Sopenharmony_ci	.buf_queue		= buffer_queue,
8008c2ecf20Sopenharmony_ci	.start_streaming	= start_streaming,
8018c2ecf20Sopenharmony_ci	.stop_streaming		= stop_streaming,
8028c2ecf20Sopenharmony_ci	.wait_prepare		= vb2_ops_wait_prepare,
8038c2ecf20Sopenharmony_ci	.wait_finish		= vb2_ops_wait_finish,
8048c2ecf20Sopenharmony_ci};
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci/*********************  v4l2 interface  **************************************/
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_civoid video_mux(struct cx231xx *dev, int index)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	dev->video_input = index;
8118c2ecf20Sopenharmony_ci	dev->ctl_ainput = INPUT(index)->amux;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	cx231xx_set_video_input_mux(dev, index);
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	cx25840_call(dev, video, s_routing, INPUT(index)->vmux, 0, 0);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	cx231xx_set_audio_input(dev, dev->ctl_ainput);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "video_mux : %d\n", index);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	/* do mode control overrides if required */
8228c2ecf20Sopenharmony_ci	cx231xx_do_mode_ctrl_overrides(dev);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------
8268c2ecf20Sopenharmony_ci	IOCTL vidioc handling
8278c2ecf20Sopenharmony_ci   ------------------------------------------------------------------*/
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
8308c2ecf20Sopenharmony_ci				struct v4l2_format *f)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	f->fmt.pix.width = dev->width;
8358c2ecf20Sopenharmony_ci	f->fmt.pix.height = dev->height;
8368c2ecf20Sopenharmony_ci	f->fmt.pix.pixelformat = dev->format->fourcc;
8378c2ecf20Sopenharmony_ci	f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
8388c2ecf20Sopenharmony_ci	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
8398c2ecf20Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	return 0;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	unsigned int i;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(format); i++)
8518c2ecf20Sopenharmony_ci		if (format[i].fourcc == fourcc)
8528c2ecf20Sopenharmony_ci			return &format[i];
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	return NULL;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
8588c2ecf20Sopenharmony_ci				  struct v4l2_format *f)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
8618c2ecf20Sopenharmony_ci	unsigned int width = f->fmt.pix.width;
8628c2ecf20Sopenharmony_ci	unsigned int height = f->fmt.pix.height;
8638c2ecf20Sopenharmony_ci	unsigned int maxw = norm_maxw(dev);
8648c2ecf20Sopenharmony_ci	unsigned int maxh = norm_maxh(dev);
8658c2ecf20Sopenharmony_ci	struct cx231xx_fmt *fmt;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
8688c2ecf20Sopenharmony_ci	if (!fmt) {
8698c2ecf20Sopenharmony_ci		cx231xx_videodbg("Fourcc format (%08x) invalid.\n",
8708c2ecf20Sopenharmony_ci				 f->fmt.pix.pixelformat);
8718c2ecf20Sopenharmony_ci		return -EINVAL;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/* width must even because of the YUYV format
8758c2ecf20Sopenharmony_ci	   height must be even because of interlacing */
8768c2ecf20Sopenharmony_ci	v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	f->fmt.pix.width = width;
8798c2ecf20Sopenharmony_ci	f->fmt.pix.height = height;
8808c2ecf20Sopenharmony_ci	f->fmt.pix.pixelformat = fmt->fourcc;
8818c2ecf20Sopenharmony_ci	f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
8828c2ecf20Sopenharmony_ci	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
8838c2ecf20Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
8848c2ecf20Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	return 0;
8878c2ecf20Sopenharmony_ci}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_cistatic int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
8908c2ecf20Sopenharmony_ci				struct v4l2_format *f)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
8938c2ecf20Sopenharmony_ci	struct v4l2_subdev_format format = {
8948c2ecf20Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
8958c2ecf20Sopenharmony_ci	};
8968c2ecf20Sopenharmony_ci	int rc;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	rc = vidioc_try_fmt_vid_cap(file, priv, f);
8998c2ecf20Sopenharmony_ci	if (rc)
9008c2ecf20Sopenharmony_ci		return rc;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	if (vb2_is_busy(&dev->vidq)) {
9038c2ecf20Sopenharmony_ci		dev_err(dev->dev, "%s: queue busy\n", __func__);
9048c2ecf20Sopenharmony_ci		return -EBUSY;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* set new image size */
9088c2ecf20Sopenharmony_ci	dev->width = f->fmt.pix.width;
9098c2ecf20Sopenharmony_ci	dev->height = f->fmt.pix.height;
9108c2ecf20Sopenharmony_ci	dev->format = format_by_fourcc(f->fmt.pix.pixelformat);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
9138c2ecf20Sopenharmony_ci	call_all(dev, pad, set_fmt, NULL, &format);
9148c2ecf20Sopenharmony_ci	v4l2_fill_pix_format(&f->fmt.pix, &format.format);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	return rc;
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	*id = dev->norm;
9248c2ecf20Sopenharmony_ci	return 0;
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
9308c2ecf20Sopenharmony_ci	struct v4l2_subdev_format format = {
9318c2ecf20Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
9328c2ecf20Sopenharmony_ci	};
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	if (dev->norm == norm)
9358c2ecf20Sopenharmony_ci		return 0;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	if (vb2_is_busy(&dev->vidq))
9388c2ecf20Sopenharmony_ci		return -EBUSY;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	dev->norm = norm;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	/* Adjusts width/height, if needed */
9438c2ecf20Sopenharmony_ci	dev->width = 720;
9448c2ecf20Sopenharmony_ci	dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	call_all(dev, video, s_std, dev->norm);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	/* We need to reset basic properties in the decoder related to
9498c2ecf20Sopenharmony_ci	   resolution (since a standard change effects things like the number
9508c2ecf20Sopenharmony_ci	   of lines in VACT, etc) */
9518c2ecf20Sopenharmony_ci	format.format.code = MEDIA_BUS_FMT_FIXED;
9528c2ecf20Sopenharmony_ci	format.format.width = dev->width;
9538c2ecf20Sopenharmony_ci	format.format.height = dev->height;
9548c2ecf20Sopenharmony_ci	call_all(dev, pad, set_fmt, NULL, &format);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	/* do mode control overrides */
9578c2ecf20Sopenharmony_ci	cx231xx_do_mode_ctrl_overrides(dev);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	return 0;
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_cistatic const char *iname[] = {
9638c2ecf20Sopenharmony_ci	[CX231XX_VMUX_COMPOSITE1] = "Composite1",
9648c2ecf20Sopenharmony_ci	[CX231XX_VMUX_SVIDEO]     = "S-Video",
9658c2ecf20Sopenharmony_ci	[CX231XX_VMUX_TELEVISION] = "Television",
9668c2ecf20Sopenharmony_ci	[CX231XX_VMUX_CABLE]      = "Cable TV",
9678c2ecf20Sopenharmony_ci	[CX231XX_VMUX_DVB]        = "DVB",
9688c2ecf20Sopenharmony_ci};
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_civoid cx231xx_v4l2_create_entities(struct cx231xx *dev)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
9738c2ecf20Sopenharmony_ci	int ret, i;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	/* Create entities for each input connector */
9768c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_CX231XX_INPUT; i++) {
9778c2ecf20Sopenharmony_ci		struct media_entity *ent = &dev->input_ent[i];
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci		if (!INPUT(i)->type)
9808c2ecf20Sopenharmony_ci			break;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci		ent->name = iname[INPUT(i)->type];
9838c2ecf20Sopenharmony_ci		ent->flags = MEDIA_ENT_FL_CONNECTOR;
9848c2ecf20Sopenharmony_ci		dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci		switch (INPUT(i)->type) {
9878c2ecf20Sopenharmony_ci		case CX231XX_VMUX_COMPOSITE1:
9888c2ecf20Sopenharmony_ci			ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
9898c2ecf20Sopenharmony_ci			break;
9908c2ecf20Sopenharmony_ci		case CX231XX_VMUX_SVIDEO:
9918c2ecf20Sopenharmony_ci			ent->function = MEDIA_ENT_F_CONN_SVIDEO;
9928c2ecf20Sopenharmony_ci			break;
9938c2ecf20Sopenharmony_ci		case CX231XX_VMUX_TELEVISION:
9948c2ecf20Sopenharmony_ci		case CX231XX_VMUX_CABLE:
9958c2ecf20Sopenharmony_ci		case CX231XX_VMUX_DVB:
9968c2ecf20Sopenharmony_ci			/* The DVB core will handle it */
9978c2ecf20Sopenharmony_ci			if (dev->tuner_type == TUNER_ABSENT)
9988c2ecf20Sopenharmony_ci				continue;
9998c2ecf20Sopenharmony_ci			fallthrough;
10008c2ecf20Sopenharmony_ci		default: /* just to shut up a gcc warning */
10018c2ecf20Sopenharmony_ci			ent->function = MEDIA_ENT_F_CONN_RF;
10028c2ecf20Sopenharmony_ci			break;
10038c2ecf20Sopenharmony_ci		}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci		ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
10068c2ecf20Sopenharmony_ci		if (ret < 0)
10078c2ecf20Sopenharmony_ci			pr_err("failed to initialize input pad[%d]!\n", i);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		ret = media_device_register_entity(dev->media_dev, ent);
10108c2ecf20Sopenharmony_ci		if (ret < 0)
10118c2ecf20Sopenharmony_ci			pr_err("failed to register input entity %d!\n", i);
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci#endif
10148c2ecf20Sopenharmony_ci}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ciint cx231xx_enum_input(struct file *file, void *priv,
10178c2ecf20Sopenharmony_ci			     struct v4l2_input *i)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
10208c2ecf20Sopenharmony_ci	u32 gen_stat;
10218c2ecf20Sopenharmony_ci	unsigned int n;
10228c2ecf20Sopenharmony_ci	int ret;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	n = i->index;
10258c2ecf20Sopenharmony_ci	if (n >= MAX_CX231XX_INPUT)
10268c2ecf20Sopenharmony_ci		return -EINVAL;
10278c2ecf20Sopenharmony_ci	if (0 == INPUT(n)->type)
10288c2ecf20Sopenharmony_ci		return -EINVAL;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	i->index = n;
10318c2ecf20Sopenharmony_ci	i->type = V4L2_INPUT_TYPE_CAMERA;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name));
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
10368c2ecf20Sopenharmony_ci	    (CX231XX_VMUX_CABLE == INPUT(n)->type))
10378c2ecf20Sopenharmony_ci		i->type = V4L2_INPUT_TYPE_TUNER;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	i->std = dev->vdev.tvnorms;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	/* If they are asking about the active input, read signal status */
10428c2ecf20Sopenharmony_ci	if (n == dev->video_input) {
10438c2ecf20Sopenharmony_ci		ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
10448c2ecf20Sopenharmony_ci					    GEN_STAT, 2, &gen_stat, 4);
10458c2ecf20Sopenharmony_ci		if (ret > 0) {
10468c2ecf20Sopenharmony_ci			if ((gen_stat & FLD_VPRES) == 0x00)
10478c2ecf20Sopenharmony_ci				i->status |= V4L2_IN_ST_NO_SIGNAL;
10488c2ecf20Sopenharmony_ci			if ((gen_stat & FLD_HLOCK) == 0x00)
10498c2ecf20Sopenharmony_ci				i->status |= V4L2_IN_ST_NO_H_LOCK;
10508c2ecf20Sopenharmony_ci		}
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	return 0;
10548c2ecf20Sopenharmony_ci}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ciint cx231xx_g_input(struct file *file, void *priv, unsigned int *i)
10578c2ecf20Sopenharmony_ci{
10588c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	*i = dev->video_input;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	return 0;
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ciint cx231xx_s_input(struct file *file, void *priv, unsigned int i)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	dev->mode_tv = 0;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	if (i >= MAX_CX231XX_INPUT)
10728c2ecf20Sopenharmony_ci		return -EINVAL;
10738c2ecf20Sopenharmony_ci	if (0 == INPUT(i)->type)
10748c2ecf20Sopenharmony_ci		return -EINVAL;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	video_mux(dev, i);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
10798c2ecf20Sopenharmony_ci	    INPUT(i)->type == CX231XX_VMUX_CABLE) {
10808c2ecf20Sopenharmony_ci		/* There's a tuner, so reset the standard and put it on the
10818c2ecf20Sopenharmony_ci		   last known frequency (since it was probably powered down
10828c2ecf20Sopenharmony_ci		   until now */
10838c2ecf20Sopenharmony_ci		call_all(dev, video, s_std, dev->norm);
10848c2ecf20Sopenharmony_ci	}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	return 0;
10878c2ecf20Sopenharmony_ci}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ciint cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	if (0 != t->index)
10948c2ecf20Sopenharmony_ci		return -EINVAL;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	strscpy(t->name, "Tuner", sizeof(t->name));
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	t->type = V4L2_TUNER_ANALOG_TV;
10998c2ecf20Sopenharmony_ci	t->capability = V4L2_TUNER_CAP_NORM;
11008c2ecf20Sopenharmony_ci	t->rangehigh = 0xffffffffUL;
11018c2ecf20Sopenharmony_ci	t->signal = 0xffff;	/* LOCKED */
11028c2ecf20Sopenharmony_ci	call_all(dev, tuner, g_tuner, t);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	return 0;
11058c2ecf20Sopenharmony_ci}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ciint cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
11088c2ecf20Sopenharmony_ci{
11098c2ecf20Sopenharmony_ci	if (0 != t->index)
11108c2ecf20Sopenharmony_ci		return -EINVAL;
11118c2ecf20Sopenharmony_ci	return 0;
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ciint cx231xx_g_frequency(struct file *file, void *priv,
11158c2ecf20Sopenharmony_ci			      struct v4l2_frequency *f)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (f->tuner)
11208c2ecf20Sopenharmony_ci		return -EINVAL;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	f->frequency = dev->ctl_freq;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	return 0;
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ciint cx231xx_s_frequency(struct file *file, void *priv,
11288c2ecf20Sopenharmony_ci			      const struct v4l2_frequency *f)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
11318c2ecf20Sopenharmony_ci	struct v4l2_frequency new_freq = *f;
11328c2ecf20Sopenharmony_ci	int rc, need_if_freq = 0;
11338c2ecf20Sopenharmony_ci	u32 if_frequency = 5400000;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	dev_dbg(dev->dev,
11368c2ecf20Sopenharmony_ci		"Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
11378c2ecf20Sopenharmony_ci		f->frequency, f->type);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if (0 != f->tuner)
11408c2ecf20Sopenharmony_ci		return -EINVAL;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	/* set pre channel change settings in DIF first */
11438c2ecf20Sopenharmony_ci	rc = cx231xx_tuner_pre_channel_change(dev);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	switch (dev->model) { /* i2c device tuners */
11468c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
11478c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_935C:
11488c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_955Q:
11498c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_975:
11508c2ecf20Sopenharmony_ci	case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
11518c2ecf20Sopenharmony_ci		if (dev->cx231xx_set_analog_freq)
11528c2ecf20Sopenharmony_ci			dev->cx231xx_set_analog_freq(dev, f->frequency);
11538c2ecf20Sopenharmony_ci		dev->ctl_freq = f->frequency;
11548c2ecf20Sopenharmony_ci		need_if_freq = 1;
11558c2ecf20Sopenharmony_ci		break;
11568c2ecf20Sopenharmony_ci	default:
11578c2ecf20Sopenharmony_ci		call_all(dev, tuner, s_frequency, f);
11588c2ecf20Sopenharmony_ci		call_all(dev, tuner, g_frequency, &new_freq);
11598c2ecf20Sopenharmony_ci		dev->ctl_freq = new_freq.frequency;
11608c2ecf20Sopenharmony_ci		break;
11618c2ecf20Sopenharmony_ci	}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	pr_debug("%s() %u  :  %u\n", __func__, f->frequency, dev->ctl_freq);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	/* set post channel change settings in DIF first */
11668c2ecf20Sopenharmony_ci	rc = cx231xx_tuner_post_channel_change(dev);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	if (need_if_freq || dev->tuner_type == TUNER_NXP_TDA18271) {
11698c2ecf20Sopenharmony_ci		if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
11708c2ecf20Sopenharmony_ci			if_frequency = 5400000;  /*5.4MHz	*/
11718c2ecf20Sopenharmony_ci		else if (dev->norm & V4L2_STD_B)
11728c2ecf20Sopenharmony_ci			if_frequency = 6000000;  /*6.0MHz	*/
11738c2ecf20Sopenharmony_ci		else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK))
11748c2ecf20Sopenharmony_ci			if_frequency = 6900000;  /*6.9MHz	*/
11758c2ecf20Sopenharmony_ci		else if (dev->norm & V4L2_STD_GH)
11768c2ecf20Sopenharmony_ci			if_frequency = 7100000;  /*7.1MHz	*/
11778c2ecf20Sopenharmony_ci		else if (dev->norm & V4L2_STD_PAL_I)
11788c2ecf20Sopenharmony_ci			if_frequency = 7250000;  /*7.25MHz	*/
11798c2ecf20Sopenharmony_ci		else if (dev->norm & V4L2_STD_SECAM_L)
11808c2ecf20Sopenharmony_ci			if_frequency = 6900000;  /*6.9MHz	*/
11818c2ecf20Sopenharmony_ci		else if (dev->norm & V4L2_STD_SECAM_LC)
11828c2ecf20Sopenharmony_ci			if_frequency = 1250000;  /*1.25MHz	*/
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci		dev_dbg(dev->dev,
11858c2ecf20Sopenharmony_ci			"if_frequency is set to %d\n", if_frequency);
11868c2ecf20Sopenharmony_ci		cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci		update_HH_register_after_set_DIF(dev);
11898c2ecf20Sopenharmony_ci	}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "Set New FREQUENCY to %d\n", f->frequency);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	return rc;
11948c2ecf20Sopenharmony_ci}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ciint cx231xx_g_chip_info(struct file *file, void *fh,
11998c2ecf20Sopenharmony_ci			struct v4l2_dbg_chip_info *chip)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	switch (chip->match.addr) {
12028c2ecf20Sopenharmony_ci	case 0:	/* Cx231xx - internal registers */
12038c2ecf20Sopenharmony_ci		return 0;
12048c2ecf20Sopenharmony_ci	case 1:	/* AFE - read byte */
12058c2ecf20Sopenharmony_ci		strscpy(chip->name, "AFE (byte)", sizeof(chip->name));
12068c2ecf20Sopenharmony_ci		return 0;
12078c2ecf20Sopenharmony_ci	case 2:	/* Video Block - read byte */
12088c2ecf20Sopenharmony_ci		strscpy(chip->name, "Video (byte)", sizeof(chip->name));
12098c2ecf20Sopenharmony_ci		return 0;
12108c2ecf20Sopenharmony_ci	case 3:	/* I2S block - read byte */
12118c2ecf20Sopenharmony_ci		strscpy(chip->name, "I2S (byte)", sizeof(chip->name));
12128c2ecf20Sopenharmony_ci		return 0;
12138c2ecf20Sopenharmony_ci	case 4: /* AFE - read dword */
12148c2ecf20Sopenharmony_ci		strscpy(chip->name, "AFE (dword)", sizeof(chip->name));
12158c2ecf20Sopenharmony_ci		return 0;
12168c2ecf20Sopenharmony_ci	case 5: /* Video Block - read dword */
12178c2ecf20Sopenharmony_ci		strscpy(chip->name, "Video (dword)", sizeof(chip->name));
12188c2ecf20Sopenharmony_ci		return 0;
12198c2ecf20Sopenharmony_ci	case 6: /* I2S Block - read dword */
12208c2ecf20Sopenharmony_ci		strscpy(chip->name, "I2S (dword)", sizeof(chip->name));
12218c2ecf20Sopenharmony_ci		return 0;
12228c2ecf20Sopenharmony_ci	}
12238c2ecf20Sopenharmony_ci	return -EINVAL;
12248c2ecf20Sopenharmony_ci}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ciint cx231xx_g_register(struct file *file, void *priv,
12278c2ecf20Sopenharmony_ci			     struct v4l2_dbg_register *reg)
12288c2ecf20Sopenharmony_ci{
12298c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
12308c2ecf20Sopenharmony_ci	int ret;
12318c2ecf20Sopenharmony_ci	u8 value[4] = { 0, 0, 0, 0 };
12328c2ecf20Sopenharmony_ci	u32 data = 0;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	switch (reg->match.addr) {
12358c2ecf20Sopenharmony_ci	case 0:	/* Cx231xx - internal registers */
12368c2ecf20Sopenharmony_ci		ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
12378c2ecf20Sopenharmony_ci				(u16)reg->reg, value, 4);
12388c2ecf20Sopenharmony_ci		reg->val = value[0] | value[1] << 8 |
12398c2ecf20Sopenharmony_ci			value[2] << 16 | (u32)value[3] << 24;
12408c2ecf20Sopenharmony_ci		reg->size = 4;
12418c2ecf20Sopenharmony_ci		break;
12428c2ecf20Sopenharmony_ci	case 1:	/* AFE - read byte */
12438c2ecf20Sopenharmony_ci		ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
12448c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, &data, 1);
12458c2ecf20Sopenharmony_ci		reg->val = data;
12468c2ecf20Sopenharmony_ci		reg->size = 1;
12478c2ecf20Sopenharmony_ci		break;
12488c2ecf20Sopenharmony_ci	case 2:	/* Video Block - read byte */
12498c2ecf20Sopenharmony_ci		ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
12508c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, &data, 1);
12518c2ecf20Sopenharmony_ci		reg->val = data;
12528c2ecf20Sopenharmony_ci		reg->size = 1;
12538c2ecf20Sopenharmony_ci		break;
12548c2ecf20Sopenharmony_ci	case 3:	/* I2S block - read byte */
12558c2ecf20Sopenharmony_ci		ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
12568c2ecf20Sopenharmony_ci				(u16)reg->reg, 1, &data, 1);
12578c2ecf20Sopenharmony_ci		reg->val = data;
12588c2ecf20Sopenharmony_ci		reg->size = 1;
12598c2ecf20Sopenharmony_ci		break;
12608c2ecf20Sopenharmony_ci	case 4: /* AFE - read dword */
12618c2ecf20Sopenharmony_ci		ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
12628c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, &data, 4);
12638c2ecf20Sopenharmony_ci		reg->val = data;
12648c2ecf20Sopenharmony_ci		reg->size = 4;
12658c2ecf20Sopenharmony_ci		break;
12668c2ecf20Sopenharmony_ci	case 5: /* Video Block - read dword */
12678c2ecf20Sopenharmony_ci		ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
12688c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, &data, 4);
12698c2ecf20Sopenharmony_ci		reg->val = data;
12708c2ecf20Sopenharmony_ci		reg->size = 4;
12718c2ecf20Sopenharmony_ci		break;
12728c2ecf20Sopenharmony_ci	case 6: /* I2S Block - read dword */
12738c2ecf20Sopenharmony_ci		ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
12748c2ecf20Sopenharmony_ci				(u16)reg->reg, 1, &data, 4);
12758c2ecf20Sopenharmony_ci		reg->val = data;
12768c2ecf20Sopenharmony_ci		reg->size = 4;
12778c2ecf20Sopenharmony_ci		break;
12788c2ecf20Sopenharmony_ci	default:
12798c2ecf20Sopenharmony_ci		return -EINVAL;
12808c2ecf20Sopenharmony_ci	}
12818c2ecf20Sopenharmony_ci	return ret < 0 ? ret : 0;
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ciint cx231xx_s_register(struct file *file, void *priv,
12858c2ecf20Sopenharmony_ci			     const struct v4l2_dbg_register *reg)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
12888c2ecf20Sopenharmony_ci	int ret;
12898c2ecf20Sopenharmony_ci	u8 data[4] = { 0, 0, 0, 0 };
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	switch (reg->match.addr) {
12928c2ecf20Sopenharmony_ci	case 0:	/* cx231xx internal registers */
12938c2ecf20Sopenharmony_ci		data[0] = (u8) reg->val;
12948c2ecf20Sopenharmony_ci		data[1] = (u8) (reg->val >> 8);
12958c2ecf20Sopenharmony_ci		data[2] = (u8) (reg->val >> 16);
12968c2ecf20Sopenharmony_ci		data[3] = (u8) (reg->val >> 24);
12978c2ecf20Sopenharmony_ci		ret = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
12988c2ecf20Sopenharmony_ci				(u16)reg->reg, data, 4);
12998c2ecf20Sopenharmony_ci		break;
13008c2ecf20Sopenharmony_ci	case 1:	/* AFE - write byte */
13018c2ecf20Sopenharmony_ci		ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
13028c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, reg->val, 1);
13038c2ecf20Sopenharmony_ci		break;
13048c2ecf20Sopenharmony_ci	case 2:	/* Video Block - write byte */
13058c2ecf20Sopenharmony_ci		ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
13068c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, reg->val, 1);
13078c2ecf20Sopenharmony_ci		break;
13088c2ecf20Sopenharmony_ci	case 3:	/* I2S block - write byte */
13098c2ecf20Sopenharmony_ci		ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
13108c2ecf20Sopenharmony_ci				(u16)reg->reg, 1, reg->val, 1);
13118c2ecf20Sopenharmony_ci		break;
13128c2ecf20Sopenharmony_ci	case 4: /* AFE - write dword */
13138c2ecf20Sopenharmony_ci		ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
13148c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, reg->val, 4);
13158c2ecf20Sopenharmony_ci		break;
13168c2ecf20Sopenharmony_ci	case 5: /* Video Block - write dword */
13178c2ecf20Sopenharmony_ci		ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
13188c2ecf20Sopenharmony_ci				(u16)reg->reg, 2, reg->val, 4);
13198c2ecf20Sopenharmony_ci		break;
13208c2ecf20Sopenharmony_ci	case 6: /* I2S block - write dword */
13218c2ecf20Sopenharmony_ci		ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
13228c2ecf20Sopenharmony_ci				(u16)reg->reg, 1, reg->val, 4);
13238c2ecf20Sopenharmony_ci		break;
13248c2ecf20Sopenharmony_ci	default:
13258c2ecf20Sopenharmony_ci		return -EINVAL;
13268c2ecf20Sopenharmony_ci	}
13278c2ecf20Sopenharmony_ci	return ret < 0 ? ret : 0;
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci#endif
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic int vidioc_g_pixelaspect(struct file *file, void *priv,
13328c2ecf20Sopenharmony_ci				int type, struct v4l2_fract *f)
13338c2ecf20Sopenharmony_ci{
13348c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
13358c2ecf20Sopenharmony_ci	bool is_50hz = dev->norm & V4L2_STD_625_50;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
13388c2ecf20Sopenharmony_ci		return -EINVAL;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	f->numerator = is_50hz ? 54 : 11;
13418c2ecf20Sopenharmony_ci	f->denominator = is_50hz ? 59 : 10;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	return 0;
13448c2ecf20Sopenharmony_ci}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_cistatic int vidioc_g_selection(struct file *file, void *priv,
13478c2ecf20Sopenharmony_ci			      struct v4l2_selection *s)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
13528c2ecf20Sopenharmony_ci		return -EINVAL;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	switch (s->target) {
13558c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
13568c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP_DEFAULT:
13578c2ecf20Sopenharmony_ci		s->r.left = 0;
13588c2ecf20Sopenharmony_ci		s->r.top = 0;
13598c2ecf20Sopenharmony_ci		s->r.width = dev->width;
13608c2ecf20Sopenharmony_ci		s->r.height = dev->height;
13618c2ecf20Sopenharmony_ci		break;
13628c2ecf20Sopenharmony_ci	default:
13638c2ecf20Sopenharmony_ci		return -EINVAL;
13648c2ecf20Sopenharmony_ci	}
13658c2ecf20Sopenharmony_ci	return 0;
13668c2ecf20Sopenharmony_ci}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ciint cx231xx_querycap(struct file *file, void *priv,
13698c2ecf20Sopenharmony_ci			   struct v4l2_capability *cap)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	strscpy(cap->driver, "cx231xx", sizeof(cap->driver));
13748c2ecf20Sopenharmony_ci	strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
13758c2ecf20Sopenharmony_ci	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
13768c2ecf20Sopenharmony_ci	cap->capabilities = V4L2_CAP_READWRITE |
13778c2ecf20Sopenharmony_ci		V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
13788c2ecf20Sopenharmony_ci		V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
13798c2ecf20Sopenharmony_ci	if (video_is_registered(&dev->radio_dev))
13808c2ecf20Sopenharmony_ci		cap->capabilities |= V4L2_CAP_RADIO;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	switch (dev->model) {
13838c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
13848c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_935C:
13858c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_955Q:
13868c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_975:
13878c2ecf20Sopenharmony_ci	case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
13888c2ecf20Sopenharmony_ci		cap->capabilities |= V4L2_CAP_TUNER;
13898c2ecf20Sopenharmony_ci		break;
13908c2ecf20Sopenharmony_ci	default:
13918c2ecf20Sopenharmony_ci		if (dev->tuner_type != TUNER_ABSENT)
13928c2ecf20Sopenharmony_ci			cap->capabilities |= V4L2_CAP_TUNER;
13938c2ecf20Sopenharmony_ci		break;
13948c2ecf20Sopenharmony_ci	}
13958c2ecf20Sopenharmony_ci	return 0;
13968c2ecf20Sopenharmony_ci}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
13998c2ecf20Sopenharmony_ci				   struct v4l2_fmtdesc *f)
14008c2ecf20Sopenharmony_ci{
14018c2ecf20Sopenharmony_ci	if (unlikely(f->index >= ARRAY_SIZE(format)))
14028c2ecf20Sopenharmony_ci		return -EINVAL;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	f->pixelformat = format[f->index].fourcc;
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	return 0;
14078c2ecf20Sopenharmony_ci}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci/* RAW VBI ioctls */
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
14128c2ecf20Sopenharmony_ci				struct v4l2_format *f)
14138c2ecf20Sopenharmony_ci{
14148c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	f->fmt.vbi.sampling_rate = 6750000 * 4;
14178c2ecf20Sopenharmony_ci	f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
14188c2ecf20Sopenharmony_ci	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
14198c2ecf20Sopenharmony_ci	f->fmt.vbi.offset = 0;
14208c2ecf20Sopenharmony_ci	f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
14218c2ecf20Sopenharmony_ci	    PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
14228c2ecf20Sopenharmony_ci	f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
14238c2ecf20Sopenharmony_ci	    PAL_VBI_LINES : NTSC_VBI_LINES;
14248c2ecf20Sopenharmony_ci	f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
14258c2ecf20Sopenharmony_ci	    PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
14268c2ecf20Sopenharmony_ci	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
14278c2ecf20Sopenharmony_ci	memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	return 0;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci}
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
14348c2ecf20Sopenharmony_ci				  struct v4l2_format *f)
14358c2ecf20Sopenharmony_ci{
14368c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	f->fmt.vbi.sampling_rate = 6750000 * 4;
14398c2ecf20Sopenharmony_ci	f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
14408c2ecf20Sopenharmony_ci	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
14418c2ecf20Sopenharmony_ci	f->fmt.vbi.offset = 0;
14428c2ecf20Sopenharmony_ci	f->fmt.vbi.flags = 0;
14438c2ecf20Sopenharmony_ci	f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
14448c2ecf20Sopenharmony_ci	    PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
14458c2ecf20Sopenharmony_ci	f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
14468c2ecf20Sopenharmony_ci	    PAL_VBI_LINES : NTSC_VBI_LINES;
14478c2ecf20Sopenharmony_ci	f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
14488c2ecf20Sopenharmony_ci	    PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
14498c2ecf20Sopenharmony_ci	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
14508c2ecf20Sopenharmony_ci	memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	return 0;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_cistatic int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
14578c2ecf20Sopenharmony_ci				  struct v4l2_format *f)
14588c2ecf20Sopenharmony_ci{
14598c2ecf20Sopenharmony_ci	return vidioc_try_fmt_vbi_cap(file, priv, f);
14608c2ecf20Sopenharmony_ci}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci/* ----------------------------------------------------------- */
14638c2ecf20Sopenharmony_ci/* RADIO ESPECIFIC IOCTLS                                      */
14648c2ecf20Sopenharmony_ci/* ----------------------------------------------------------- */
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_cistatic int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
14678c2ecf20Sopenharmony_ci{
14688c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	if (t->index)
14718c2ecf20Sopenharmony_ci		return -EINVAL;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	strscpy(t->name, "Radio", sizeof(t->name));
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	call_all(dev, tuner, g_tuner, t);
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	return 0;
14788c2ecf20Sopenharmony_ci}
14798c2ecf20Sopenharmony_cistatic int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
14808c2ecf20Sopenharmony_ci{
14818c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	if (t->index)
14848c2ecf20Sopenharmony_ci		return -EINVAL;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	call_all(dev, tuner, s_tuner, t);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	return 0;
14898c2ecf20Sopenharmony_ci}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci/*
14928c2ecf20Sopenharmony_ci * cx231xx_v4l2_open()
14938c2ecf20Sopenharmony_ci * inits the device and starts isoc transfer
14948c2ecf20Sopenharmony_ci */
14958c2ecf20Sopenharmony_cistatic int cx231xx_v4l2_open(struct file *filp)
14968c2ecf20Sopenharmony_ci{
14978c2ecf20Sopenharmony_ci	struct video_device *vdev = video_devdata(filp);
14988c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(filp);
14998c2ecf20Sopenharmony_ci	int ret;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&dev->lock))
15028c2ecf20Sopenharmony_ci		return -ERESTARTSYS;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	ret = v4l2_fh_open(filp);
15058c2ecf20Sopenharmony_ci	if (ret) {
15068c2ecf20Sopenharmony_ci		mutex_unlock(&dev->lock);
15078c2ecf20Sopenharmony_ci		return ret;
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	if (dev->users++ == 0) {
15118c2ecf20Sopenharmony_ci		/* Power up in Analog TV mode */
15128c2ecf20Sopenharmony_ci		if (dev->board.external_av)
15138c2ecf20Sopenharmony_ci			cx231xx_set_power_mode(dev,
15148c2ecf20Sopenharmony_ci				 POLARIS_AVMODE_ENXTERNAL_AV);
15158c2ecf20Sopenharmony_ci		else
15168c2ecf20Sopenharmony_ci			cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		/* set video alternate setting */
15198c2ecf20Sopenharmony_ci		cx231xx_set_video_alternate(dev);
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci		/* Needed, since GPIO might have disabled power of
15228c2ecf20Sopenharmony_ci		   some i2c device */
15238c2ecf20Sopenharmony_ci		cx231xx_config_i2c(dev);
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci		/* device needs to be initialized before isoc transfer */
15268c2ecf20Sopenharmony_ci		dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
15278c2ecf20Sopenharmony_ci	}
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	if (vdev->vfl_type == VFL_TYPE_RADIO) {
15308c2ecf20Sopenharmony_ci		cx231xx_videodbg("video_open: setting radio device\n");
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci		/* cx231xx_start_radio(dev); */
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci		call_all(dev, tuner, s_radio);
15358c2ecf20Sopenharmony_ci	}
15368c2ecf20Sopenharmony_ci	if (vdev->vfl_type == VFL_TYPE_VBI) {
15378c2ecf20Sopenharmony_ci		/* Set the required alternate setting  VBI interface works in
15388c2ecf20Sopenharmony_ci		   Bulk mode only */
15398c2ecf20Sopenharmony_ci		cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci	mutex_unlock(&dev->lock);
15428c2ecf20Sopenharmony_ci	return 0;
15438c2ecf20Sopenharmony_ci}
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci/*
15468c2ecf20Sopenharmony_ci * cx231xx_realease_resources()
15478c2ecf20Sopenharmony_ci * unregisters the v4l2,i2c and usb devices
15488c2ecf20Sopenharmony_ci * called when the device gets disconnected or at module unload
15498c2ecf20Sopenharmony_ci*/
15508c2ecf20Sopenharmony_civoid cx231xx_release_analog_resources(struct cx231xx *dev)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	/*FIXME: I2C IR should be disconnected */
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	if (video_is_registered(&dev->radio_dev))
15568c2ecf20Sopenharmony_ci		video_unregister_device(&dev->radio_dev);
15578c2ecf20Sopenharmony_ci	if (video_is_registered(&dev->vbi_dev)) {
15588c2ecf20Sopenharmony_ci		dev_info(dev->dev, "V4L2 device %s deregistered\n",
15598c2ecf20Sopenharmony_ci			video_device_node_name(&dev->vbi_dev));
15608c2ecf20Sopenharmony_ci		video_unregister_device(&dev->vbi_dev);
15618c2ecf20Sopenharmony_ci	}
15628c2ecf20Sopenharmony_ci	if (video_is_registered(&dev->vdev)) {
15638c2ecf20Sopenharmony_ci		dev_info(dev->dev, "V4L2 device %s deregistered\n",
15648c2ecf20Sopenharmony_ci			video_device_node_name(&dev->vdev));
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci		if (dev->board.has_417)
15678c2ecf20Sopenharmony_ci			cx231xx_417_unregister(dev);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci		video_unregister_device(&dev->vdev);
15708c2ecf20Sopenharmony_ci	}
15718c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&dev->ctrl_handler);
15728c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
15738c2ecf20Sopenharmony_ci}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci/*
15768c2ecf20Sopenharmony_ci * cx231xx_close()
15778c2ecf20Sopenharmony_ci * stops streaming and deallocates all resources allocated by the v4l2
15788c2ecf20Sopenharmony_ci * calls and ioctls
15798c2ecf20Sopenharmony_ci */
15808c2ecf20Sopenharmony_cistatic int cx231xx_close(struct file *filp)
15818c2ecf20Sopenharmony_ci{
15828c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(filp);
15838c2ecf20Sopenharmony_ci	struct video_device *vdev = video_devdata(filp);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	_vb2_fop_release(filp, NULL);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	if (--dev->users == 0) {
15888c2ecf20Sopenharmony_ci		/* Save some power by putting tuner to sleep */
15898c2ecf20Sopenharmony_ci		call_all(dev, tuner, standby);
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci		/* do this before setting alternate! */
15928c2ecf20Sopenharmony_ci		if (dev->USE_ISO)
15938c2ecf20Sopenharmony_ci			cx231xx_uninit_isoc(dev);
15948c2ecf20Sopenharmony_ci		else
15958c2ecf20Sopenharmony_ci			cx231xx_uninit_bulk(dev);
15968c2ecf20Sopenharmony_ci		cx231xx_set_mode(dev, CX231XX_SUSPEND);
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	/*
16008c2ecf20Sopenharmony_ci	 * To workaround error number=-71 on EP0 for VideoGrabber,
16018c2ecf20Sopenharmony_ci	 *	 need exclude following.
16028c2ecf20Sopenharmony_ci	 * FIXME: It is probably safe to remove most of these, as we're
16038c2ecf20Sopenharmony_ci	 * now avoiding the alternate setting for INDEX_VANC
16048c2ecf20Sopenharmony_ci	 */
16058c2ecf20Sopenharmony_ci	if (!dev->board.no_alt_vanc && vdev->vfl_type == VFL_TYPE_VBI) {
16068c2ecf20Sopenharmony_ci		/* do this before setting alternate! */
16078c2ecf20Sopenharmony_ci		cx231xx_uninit_vbi_isoc(dev);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci		/* set alternate 0 */
16108c2ecf20Sopenharmony_ci		if (!dev->vbi_or_sliced_cc_mode)
16118c2ecf20Sopenharmony_ci			cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
16128c2ecf20Sopenharmony_ci		else
16138c2ecf20Sopenharmony_ci			cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci		wake_up_interruptible_nr(&dev->open, 1);
16168c2ecf20Sopenharmony_ci		return 0;
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	if (dev->users == 0) {
16208c2ecf20Sopenharmony_ci		/* set alternate 0 */
16218c2ecf20Sopenharmony_ci		cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
16228c2ecf20Sopenharmony_ci	}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	wake_up_interruptible(&dev->open);
16258c2ecf20Sopenharmony_ci	return 0;
16268c2ecf20Sopenharmony_ci}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_cistatic int cx231xx_v4l2_close(struct file *filp)
16298c2ecf20Sopenharmony_ci{
16308c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(filp);
16318c2ecf20Sopenharmony_ci	int rc;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	mutex_lock(&dev->lock);
16348c2ecf20Sopenharmony_ci	rc = cx231xx_close(filp);
16358c2ecf20Sopenharmony_ci	mutex_unlock(&dev->lock);
16368c2ecf20Sopenharmony_ci	return rc;
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations cx231xx_v4l_fops = {
16408c2ecf20Sopenharmony_ci	.owner   = THIS_MODULE,
16418c2ecf20Sopenharmony_ci	.open    = cx231xx_v4l2_open,
16428c2ecf20Sopenharmony_ci	.release = cx231xx_v4l2_close,
16438c2ecf20Sopenharmony_ci	.read    = vb2_fop_read,
16448c2ecf20Sopenharmony_ci	.poll    = vb2_fop_poll,
16458c2ecf20Sopenharmony_ci	.mmap    = vb2_fop_mmap,
16468c2ecf20Sopenharmony_ci	.unlocked_ioctl   = video_ioctl2,
16478c2ecf20Sopenharmony_ci};
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops video_ioctl_ops = {
16508c2ecf20Sopenharmony_ci	.vidioc_querycap               = cx231xx_querycap,
16518c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_cap       = vidioc_enum_fmt_vid_cap,
16528c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_cap          = vidioc_g_fmt_vid_cap,
16538c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_cap        = vidioc_try_fmt_vid_cap,
16548c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_cap          = vidioc_s_fmt_vid_cap,
16558c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vbi_cap          = vidioc_g_fmt_vbi_cap,
16568c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vbi_cap        = vidioc_try_fmt_vbi_cap,
16578c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vbi_cap          = vidioc_s_fmt_vbi_cap,
16588c2ecf20Sopenharmony_ci	.vidioc_g_pixelaspect          = vidioc_g_pixelaspect,
16598c2ecf20Sopenharmony_ci	.vidioc_g_selection            = vidioc_g_selection,
16608c2ecf20Sopenharmony_ci	.vidioc_reqbufs                = vb2_ioctl_reqbufs,
16618c2ecf20Sopenharmony_ci	.vidioc_querybuf               = vb2_ioctl_querybuf,
16628c2ecf20Sopenharmony_ci	.vidioc_qbuf                   = vb2_ioctl_qbuf,
16638c2ecf20Sopenharmony_ci	.vidioc_dqbuf                  = vb2_ioctl_dqbuf,
16648c2ecf20Sopenharmony_ci	.vidioc_s_std                  = vidioc_s_std,
16658c2ecf20Sopenharmony_ci	.vidioc_g_std                  = vidioc_g_std,
16668c2ecf20Sopenharmony_ci	.vidioc_enum_input             = cx231xx_enum_input,
16678c2ecf20Sopenharmony_ci	.vidioc_g_input                = cx231xx_g_input,
16688c2ecf20Sopenharmony_ci	.vidioc_s_input                = cx231xx_s_input,
16698c2ecf20Sopenharmony_ci	.vidioc_streamon               = vb2_ioctl_streamon,
16708c2ecf20Sopenharmony_ci	.vidioc_streamoff              = vb2_ioctl_streamoff,
16718c2ecf20Sopenharmony_ci	.vidioc_g_tuner                = cx231xx_g_tuner,
16728c2ecf20Sopenharmony_ci	.vidioc_s_tuner                = cx231xx_s_tuner,
16738c2ecf20Sopenharmony_ci	.vidioc_g_frequency            = cx231xx_g_frequency,
16748c2ecf20Sopenharmony_ci	.vidioc_s_frequency            = cx231xx_s_frequency,
16758c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
16768c2ecf20Sopenharmony_ci	.vidioc_g_chip_info            = cx231xx_g_chip_info,
16778c2ecf20Sopenharmony_ci	.vidioc_g_register             = cx231xx_g_register,
16788c2ecf20Sopenharmony_ci	.vidioc_s_register             = cx231xx_s_register,
16798c2ecf20Sopenharmony_ci#endif
16808c2ecf20Sopenharmony_ci	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
16818c2ecf20Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
16828c2ecf20Sopenharmony_ci};
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_cistatic struct video_device cx231xx_vbi_template;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_cistatic const struct video_device cx231xx_video_template = {
16878c2ecf20Sopenharmony_ci	.fops         = &cx231xx_v4l_fops,
16888c2ecf20Sopenharmony_ci	.release      = video_device_release_empty,
16898c2ecf20Sopenharmony_ci	.ioctl_ops    = &video_ioctl_ops,
16908c2ecf20Sopenharmony_ci	.tvnorms      = V4L2_STD_ALL,
16918c2ecf20Sopenharmony_ci};
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations radio_fops = {
16948c2ecf20Sopenharmony_ci	.owner   = THIS_MODULE,
16958c2ecf20Sopenharmony_ci	.open   = cx231xx_v4l2_open,
16968c2ecf20Sopenharmony_ci	.release = cx231xx_v4l2_close,
16978c2ecf20Sopenharmony_ci	.poll = v4l2_ctrl_poll,
16988c2ecf20Sopenharmony_ci	.unlocked_ioctl = video_ioctl2,
16998c2ecf20Sopenharmony_ci};
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops radio_ioctl_ops = {
17028c2ecf20Sopenharmony_ci	.vidioc_querycap    = cx231xx_querycap,
17038c2ecf20Sopenharmony_ci	.vidioc_g_tuner     = radio_g_tuner,
17048c2ecf20Sopenharmony_ci	.vidioc_s_tuner     = radio_s_tuner,
17058c2ecf20Sopenharmony_ci	.vidioc_g_frequency = cx231xx_g_frequency,
17068c2ecf20Sopenharmony_ci	.vidioc_s_frequency = cx231xx_s_frequency,
17078c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
17088c2ecf20Sopenharmony_ci	.vidioc_g_chip_info = cx231xx_g_chip_info,
17098c2ecf20Sopenharmony_ci	.vidioc_g_register  = cx231xx_g_register,
17108c2ecf20Sopenharmony_ci	.vidioc_s_register  = cx231xx_s_register,
17118c2ecf20Sopenharmony_ci#endif
17128c2ecf20Sopenharmony_ci	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
17138c2ecf20Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
17148c2ecf20Sopenharmony_ci};
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_cistatic struct video_device cx231xx_radio_template = {
17178c2ecf20Sopenharmony_ci	.name      = "cx231xx-radio",
17188c2ecf20Sopenharmony_ci	.fops      = &radio_fops,
17198c2ecf20Sopenharmony_ci	.ioctl_ops = &radio_ioctl_ops,
17208c2ecf20Sopenharmony_ci};
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci/******************************** usb interface ******************************/
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_cistatic void cx231xx_vdev_init(struct cx231xx *dev,
17258c2ecf20Sopenharmony_ci		struct video_device *vfd,
17268c2ecf20Sopenharmony_ci		const struct video_device *template,
17278c2ecf20Sopenharmony_ci		const char *type_name)
17288c2ecf20Sopenharmony_ci{
17298c2ecf20Sopenharmony_ci	*vfd = *template;
17308c2ecf20Sopenharmony_ci	vfd->v4l2_dev = &dev->v4l2_dev;
17318c2ecf20Sopenharmony_ci	vfd->release = video_device_release_empty;
17328c2ecf20Sopenharmony_ci	vfd->lock = &dev->lock;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	video_set_drvdata(vfd, dev);
17378c2ecf20Sopenharmony_ci	if (dev->tuner_type == TUNER_ABSENT) {
17388c2ecf20Sopenharmony_ci		switch (dev->model) {
17398c2ecf20Sopenharmony_ci		case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
17408c2ecf20Sopenharmony_ci		case CX231XX_BOARD_HAUPPAUGE_935C:
17418c2ecf20Sopenharmony_ci		case CX231XX_BOARD_HAUPPAUGE_955Q:
17428c2ecf20Sopenharmony_ci		case CX231XX_BOARD_HAUPPAUGE_975:
17438c2ecf20Sopenharmony_ci		case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
17448c2ecf20Sopenharmony_ci			break;
17458c2ecf20Sopenharmony_ci		default:
17468c2ecf20Sopenharmony_ci			v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
17478c2ecf20Sopenharmony_ci			v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
17488c2ecf20Sopenharmony_ci			v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
17498c2ecf20Sopenharmony_ci			v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
17508c2ecf20Sopenharmony_ci			break;
17518c2ecf20Sopenharmony_ci		}
17528c2ecf20Sopenharmony_ci	}
17538c2ecf20Sopenharmony_ci}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ciint cx231xx_register_analog_devices(struct cx231xx *dev)
17568c2ecf20Sopenharmony_ci{
17578c2ecf20Sopenharmony_ci	struct vb2_queue *q;
17588c2ecf20Sopenharmony_ci	int ret;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	dev_info(dev->dev, "v4l2 driver version %s\n", CX231XX_VERSION);
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	/* set default norm */
17638c2ecf20Sopenharmony_ci	dev->norm = V4L2_STD_PAL;
17648c2ecf20Sopenharmony_ci	dev->width = norm_maxw(dev);
17658c2ecf20Sopenharmony_ci	dev->height = norm_maxh(dev);
17668c2ecf20Sopenharmony_ci	dev->interlaced = 0;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	/* Analog specific initialization */
17698c2ecf20Sopenharmony_ci	dev->format = &format[0];
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	/* Set the initial input */
17728c2ecf20Sopenharmony_ci	video_mux(dev, dev->video_input);
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	call_all(dev, video, s_std, dev->norm);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(&dev->ctrl_handler, 10);
17778c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5);
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	if (dev->sd_cx25840) {
17808c2ecf20Sopenharmony_ci		v4l2_ctrl_add_handler(&dev->ctrl_handler,
17818c2ecf20Sopenharmony_ci				dev->sd_cx25840->ctrl_handler, NULL, true);
17828c2ecf20Sopenharmony_ci		v4l2_ctrl_add_handler(&dev->radio_ctrl_handler,
17838c2ecf20Sopenharmony_ci				dev->sd_cx25840->ctrl_handler,
17848c2ecf20Sopenharmony_ci				v4l2_ctrl_radio_filter, true);
17858c2ecf20Sopenharmony_ci	}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	if (dev->ctrl_handler.error)
17888c2ecf20Sopenharmony_ci		return dev->ctrl_handler.error;
17898c2ecf20Sopenharmony_ci	if (dev->radio_ctrl_handler.error)
17908c2ecf20Sopenharmony_ci		return dev->radio_ctrl_handler.error;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	/* enable vbi capturing */
17938c2ecf20Sopenharmony_ci	/* write code here...  */
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	/* allocate and fill video video_device struct */
17968c2ecf20Sopenharmony_ci	cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video");
17978c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
17988c2ecf20Sopenharmony_ci	dev->video_pad.flags = MEDIA_PAD_FL_SINK;
17998c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad);
18008c2ecf20Sopenharmony_ci	if (ret < 0)
18018c2ecf20Sopenharmony_ci		dev_err(dev->dev, "failed to initialize video media entity!\n");
18028c2ecf20Sopenharmony_ci#endif
18038c2ecf20Sopenharmony_ci	dev->vdev.ctrl_handler = &dev->ctrl_handler;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	q = &dev->vidq;
18068c2ecf20Sopenharmony_ci	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
18078c2ecf20Sopenharmony_ci	q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
18088c2ecf20Sopenharmony_ci	q->drv_priv = dev;
18098c2ecf20Sopenharmony_ci	q->buf_struct_size = sizeof(struct cx231xx_buffer);
18108c2ecf20Sopenharmony_ci	q->ops = &cx231xx_video_qops;
18118c2ecf20Sopenharmony_ci	q->mem_ops = &vb2_vmalloc_memops;
18128c2ecf20Sopenharmony_ci	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
18138c2ecf20Sopenharmony_ci	q->min_buffers_needed = 1;
18148c2ecf20Sopenharmony_ci	q->lock = &dev->lock;
18158c2ecf20Sopenharmony_ci	ret = vb2_queue_init(q);
18168c2ecf20Sopenharmony_ci	if (ret)
18178c2ecf20Sopenharmony_ci		return ret;
18188c2ecf20Sopenharmony_ci	dev->vdev.queue = q;
18198c2ecf20Sopenharmony_ci	dev->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
18208c2ecf20Sopenharmony_ci				V4L2_CAP_VIDEO_CAPTURE;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	switch (dev->model) { /* i2c device tuners */
18238c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
18248c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_935C:
18258c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_955Q:
18268c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_975:
18278c2ecf20Sopenharmony_ci	case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
18288c2ecf20Sopenharmony_ci		dev->vdev.device_caps |= V4L2_CAP_TUNER;
18298c2ecf20Sopenharmony_ci		break;
18308c2ecf20Sopenharmony_ci	default:
18318c2ecf20Sopenharmony_ci		if (dev->tuner_type != TUNER_ABSENT)
18328c2ecf20Sopenharmony_ci			dev->vdev.device_caps |= V4L2_CAP_TUNER;
18338c2ecf20Sopenharmony_ci		break;
18348c2ecf20Sopenharmony_ci	}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	/* register v4l2 video video_device */
18378c2ecf20Sopenharmony_ci	ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO,
18388c2ecf20Sopenharmony_ci				    video_nr[dev->devno]);
18398c2ecf20Sopenharmony_ci	if (ret) {
18408c2ecf20Sopenharmony_ci		dev_err(dev->dev,
18418c2ecf20Sopenharmony_ci			"unable to register video device (error=%i).\n",
18428c2ecf20Sopenharmony_ci			ret);
18438c2ecf20Sopenharmony_ci		return ret;
18448c2ecf20Sopenharmony_ci	}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	dev_info(dev->dev, "Registered video device %s [v4l2]\n",
18478c2ecf20Sopenharmony_ci		video_device_node_name(&dev->vdev));
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	/* Initialize VBI template */
18508c2ecf20Sopenharmony_ci	cx231xx_vbi_template = cx231xx_video_template;
18518c2ecf20Sopenharmony_ci	strscpy(cx231xx_vbi_template.name, "cx231xx-vbi",
18528c2ecf20Sopenharmony_ci		sizeof(cx231xx_vbi_template.name));
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	/* Allocate and fill vbi video_device struct */
18558c2ecf20Sopenharmony_ci	cx231xx_vdev_init(dev, &dev->vbi_dev, &cx231xx_vbi_template, "vbi");
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
18588c2ecf20Sopenharmony_ci	dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
18598c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad);
18608c2ecf20Sopenharmony_ci	if (ret < 0)
18618c2ecf20Sopenharmony_ci		dev_err(dev->dev, "failed to initialize vbi media entity!\n");
18628c2ecf20Sopenharmony_ci#endif
18638c2ecf20Sopenharmony_ci	dev->vbi_dev.ctrl_handler = &dev->ctrl_handler;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	q = &dev->vbiq;
18668c2ecf20Sopenharmony_ci	q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
18678c2ecf20Sopenharmony_ci	q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
18688c2ecf20Sopenharmony_ci	q->drv_priv = dev;
18698c2ecf20Sopenharmony_ci	q->buf_struct_size = sizeof(struct cx231xx_buffer);
18708c2ecf20Sopenharmony_ci	q->ops = &cx231xx_vbi_qops;
18718c2ecf20Sopenharmony_ci	q->mem_ops = &vb2_vmalloc_memops;
18728c2ecf20Sopenharmony_ci	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
18738c2ecf20Sopenharmony_ci	q->min_buffers_needed = 1;
18748c2ecf20Sopenharmony_ci	q->lock = &dev->lock;
18758c2ecf20Sopenharmony_ci	ret = vb2_queue_init(q);
18768c2ecf20Sopenharmony_ci	if (ret)
18778c2ecf20Sopenharmony_ci		return ret;
18788c2ecf20Sopenharmony_ci	dev->vbi_dev.queue = q;
18798c2ecf20Sopenharmony_ci	dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
18808c2ecf20Sopenharmony_ci				   V4L2_CAP_VBI_CAPTURE;
18818c2ecf20Sopenharmony_ci	switch (dev->model) { /* i2c device tuners */
18828c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
18838c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_935C:
18848c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_955Q:
18858c2ecf20Sopenharmony_ci	case CX231XX_BOARD_HAUPPAUGE_975:
18868c2ecf20Sopenharmony_ci	case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
18878c2ecf20Sopenharmony_ci		dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
18888c2ecf20Sopenharmony_ci		break;
18898c2ecf20Sopenharmony_ci	default:
18908c2ecf20Sopenharmony_ci		if (dev->tuner_type != TUNER_ABSENT)
18918c2ecf20Sopenharmony_ci			dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
18928c2ecf20Sopenharmony_ci	}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	/* register v4l2 vbi video_device */
18958c2ecf20Sopenharmony_ci	ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI,
18968c2ecf20Sopenharmony_ci				    vbi_nr[dev->devno]);
18978c2ecf20Sopenharmony_ci	if (ret < 0) {
18988c2ecf20Sopenharmony_ci		dev_err(dev->dev, "unable to register vbi device\n");
18998c2ecf20Sopenharmony_ci		return ret;
19008c2ecf20Sopenharmony_ci	}
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	dev_info(dev->dev, "Registered VBI device %s\n",
19038c2ecf20Sopenharmony_ci		video_device_node_name(&dev->vbi_dev));
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
19068c2ecf20Sopenharmony_ci		cx231xx_vdev_init(dev, &dev->radio_dev,
19078c2ecf20Sopenharmony_ci				&cx231xx_radio_template, "radio");
19088c2ecf20Sopenharmony_ci		dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
19098c2ecf20Sopenharmony_ci		dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
19108c2ecf20Sopenharmony_ci		ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
19118c2ecf20Sopenharmony_ci					    radio_nr[dev->devno]);
19128c2ecf20Sopenharmony_ci		if (ret < 0) {
19138c2ecf20Sopenharmony_ci			dev_err(dev->dev,
19148c2ecf20Sopenharmony_ci				"can't register radio device\n");
19158c2ecf20Sopenharmony_ci			return ret;
19168c2ecf20Sopenharmony_ci		}
19178c2ecf20Sopenharmony_ci		dev_info(dev->dev, "Registered radio device as %s\n",
19188c2ecf20Sopenharmony_ci			video_device_node_name(&dev->radio_dev));
19198c2ecf20Sopenharmony_ci	}
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	return 0;
19228c2ecf20Sopenharmony_ci}
1923