174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20c0d06caSMauro Carvalho Chehab /*
30c0d06caSMauro Carvalho Chehab cx231xx-video.c - driver for Conexant Cx23100/101/102
40c0d06caSMauro Carvalho Chehab USB video capture devices
50c0d06caSMauro Carvalho Chehab
60c0d06caSMauro Carvalho Chehab Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
70c0d06caSMauro Carvalho Chehab Based on em28xx driver
80c0d06caSMauro Carvalho Chehab Based on cx23885 driver
90c0d06caSMauro Carvalho Chehab Based on cx88 driver
100c0d06caSMauro Carvalho Chehab
110c0d06caSMauro Carvalho Chehab */
120c0d06caSMauro Carvalho Chehab
13589dadf2SMauro Carvalho Chehab #include "cx231xx.h"
140c0d06caSMauro Carvalho Chehab #include <linux/init.h>
150c0d06caSMauro Carvalho Chehab #include <linux/list.h>
160c0d06caSMauro Carvalho Chehab #include <linux/module.h>
170c0d06caSMauro Carvalho Chehab #include <linux/kernel.h>
180c0d06caSMauro Carvalho Chehab #include <linux/bitmap.h>
190c0d06caSMauro Carvalho Chehab #include <linux/i2c.h>
200c0d06caSMauro Carvalho Chehab #include <linux/mm.h>
210c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
220c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
230c0d06caSMauro Carvalho Chehab
240c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
250c0d06caSMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
261d08a4faSHans Verkuil #include <media/v4l2-event.h>
27d647f0b7SMauro Carvalho Chehab #include <media/drv-intf/msp3400.h>
280c0d06caSMauro Carvalho Chehab #include <media/tuner.h>
290c0d06caSMauro Carvalho Chehab
30fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
310c0d06caSMauro Carvalho Chehab
320c0d06caSMauro Carvalho Chehab #include "cx231xx-vbi.h"
330c0d06caSMauro Carvalho Chehab
343d28cf3eSMauro Carvalho Chehab #define CX231XX_VERSION "0.0.3"
350c0d06caSMauro Carvalho Chehab
360c0d06caSMauro Carvalho Chehab #define DRIVER_AUTHOR "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
370c0d06caSMauro Carvalho Chehab #define DRIVER_DESC "Conexant cx231xx based USB video device driver"
380c0d06caSMauro Carvalho Chehab
390c0d06caSMauro Carvalho Chehab #define cx231xx_videodbg(fmt, arg...) do {\
400c0d06caSMauro Carvalho Chehab if (video_debug) \
410c0d06caSMauro Carvalho Chehab printk(KERN_INFO "%s %s :"fmt, \
420c0d06caSMauro Carvalho Chehab dev->name, __func__ , ##arg); } while (0)
430c0d06caSMauro Carvalho Chehab
440c0d06caSMauro Carvalho Chehab static unsigned int isoc_debug;
450c0d06caSMauro Carvalho Chehab module_param(isoc_debug, int, 0644);
460c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
470c0d06caSMauro Carvalho Chehab
480c0d06caSMauro Carvalho Chehab #define cx231xx_isocdbg(fmt, arg...) \
490c0d06caSMauro Carvalho Chehab do {\
500c0d06caSMauro Carvalho Chehab if (isoc_debug) { \
510c0d06caSMauro Carvalho Chehab printk(KERN_INFO "%s %s :"fmt, \
520c0d06caSMauro Carvalho Chehab dev->name, __func__ , ##arg); \
530c0d06caSMauro Carvalho Chehab } \
540c0d06caSMauro Carvalho Chehab } while (0)
550c0d06caSMauro Carvalho Chehab
560c0d06caSMauro Carvalho Chehab MODULE_AUTHOR(DRIVER_AUTHOR);
570c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION(DRIVER_DESC);
580c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
590c0d06caSMauro Carvalho Chehab MODULE_VERSION(CX231XX_VERSION);
600c0d06caSMauro Carvalho Chehab
617c617138SHans Verkuil static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
627c617138SHans Verkuil static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
637c617138SHans Verkuil static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
647c617138SHans Verkuil static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
650c0d06caSMauro Carvalho Chehab
660c0d06caSMauro Carvalho Chehab module_param_array(card, int, NULL, 0444);
670c0d06caSMauro Carvalho Chehab module_param_array(video_nr, int, NULL, 0444);
680c0d06caSMauro Carvalho Chehab module_param_array(vbi_nr, int, NULL, 0444);
690c0d06caSMauro Carvalho Chehab module_param_array(radio_nr, int, NULL, 0444);
700c0d06caSMauro Carvalho Chehab
710c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(card, "card type");
720c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(video_nr, "video device numbers");
730c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
740c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(radio_nr, "radio device numbers");
750c0d06caSMauro Carvalho Chehab
760c0d06caSMauro Carvalho Chehab static unsigned int video_debug;
770c0d06caSMauro Carvalho Chehab module_param(video_debug, int, 0644);
780c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
790c0d06caSMauro Carvalho Chehab
800c0d06caSMauro Carvalho Chehab /* supported video standards */
810c0d06caSMauro Carvalho Chehab static struct cx231xx_fmt format[] = {
820c0d06caSMauro Carvalho Chehab {
830c0d06caSMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_YUYV,
840c0d06caSMauro Carvalho Chehab .depth = 16,
850c0d06caSMauro Carvalho Chehab .reg = 0,
860c0d06caSMauro Carvalho Chehab },
870c0d06caSMauro Carvalho Chehab };
880c0d06caSMauro Carvalho Chehab
890c0d06caSMauro Carvalho Chehab
cx231xx_enable_analog_tuner(struct cx231xx * dev)903d263114SMauro Carvalho Chehab static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
913d263114SMauro Carvalho Chehab {
923d263114SMauro Carvalho Chehab #ifdef CONFIG_MEDIA_CONTROLLER
933d263114SMauro Carvalho Chehab struct media_device *mdev = dev->media_dev;
943d263114SMauro Carvalho Chehab struct media_entity *entity, *decoder = NULL, *source;
953d263114SMauro Carvalho Chehab struct media_link *link, *found_link = NULL;
9657208e5eSMauro Carvalho Chehab int ret, active_links = 0;
973d263114SMauro Carvalho Chehab
983d263114SMauro Carvalho Chehab if (!mdev)
993d263114SMauro Carvalho Chehab return 0;
1003d263114SMauro Carvalho Chehab
1013d263114SMauro Carvalho Chehab /*
1023d263114SMauro Carvalho Chehab * This will find the tuner that is connected into the decoder.
1033d263114SMauro Carvalho Chehab * Technically, this is not 100% correct, as the device may be
1043d263114SMauro Carvalho Chehab * using an analog input instead of the tuner. However, as we can't
1053d263114SMauro Carvalho Chehab * do DVB streaming while the DMA engine is being used for V4L2,
1063d263114SMauro Carvalho Chehab * this should be enough for the actual needs.
1073d263114SMauro Carvalho Chehab */
1083d263114SMauro Carvalho Chehab media_device_for_each_entity(entity, mdev) {
1094ca72efaSMauro Carvalho Chehab if (entity->function == MEDIA_ENT_F_ATV_DECODER) {
1103d263114SMauro Carvalho Chehab decoder = entity;
1113d263114SMauro Carvalho Chehab break;
1123d263114SMauro Carvalho Chehab }
1133d263114SMauro Carvalho Chehab }
1143d263114SMauro Carvalho Chehab if (!decoder)
1153d263114SMauro Carvalho Chehab return 0;
1163d263114SMauro Carvalho Chehab
11757208e5eSMauro Carvalho Chehab list_for_each_entry(link, &decoder->links, list) {
1183d263114SMauro Carvalho Chehab if (link->sink->entity == decoder) {
1193d263114SMauro Carvalho Chehab found_link = link;
1203d263114SMauro Carvalho Chehab if (link->flags & MEDIA_LNK_FL_ENABLED)
1213d263114SMauro Carvalho Chehab active_links++;
1223d263114SMauro Carvalho Chehab break;
1233d263114SMauro Carvalho Chehab }
1243d263114SMauro Carvalho Chehab }
1253d263114SMauro Carvalho Chehab
1263d263114SMauro Carvalho Chehab if (active_links == 1 || !found_link)
1273d263114SMauro Carvalho Chehab return 0;
1283d263114SMauro Carvalho Chehab
1293d263114SMauro Carvalho Chehab source = found_link->source->entity;
13057208e5eSMauro Carvalho Chehab list_for_each_entry(link, &source->links, list) {
1313d263114SMauro Carvalho Chehab struct media_entity *sink;
1323d263114SMauro Carvalho Chehab int flags = 0;
1333d263114SMauro Carvalho Chehab
1343d263114SMauro Carvalho Chehab sink = link->sink->entity;
1353d263114SMauro Carvalho Chehab
1363d263114SMauro Carvalho Chehab if (sink == entity)
1373d263114SMauro Carvalho Chehab flags = MEDIA_LNK_FL_ENABLED;
1383d263114SMauro Carvalho Chehab
1393d263114SMauro Carvalho Chehab ret = media_entity_setup_link(link, flags);
1403d263114SMauro Carvalho Chehab if (ret) {
1413d263114SMauro Carvalho Chehab dev_err(dev->dev,
1423d263114SMauro Carvalho Chehab "Couldn't change link %s->%s to %s. Error %d\n",
1433d263114SMauro Carvalho Chehab source->name, sink->name,
1443d263114SMauro Carvalho Chehab flags ? "enabled" : "disabled",
1453d263114SMauro Carvalho Chehab ret);
1463d263114SMauro Carvalho Chehab return ret;
1473d263114SMauro Carvalho Chehab } else
1483d263114SMauro Carvalho Chehab dev_dbg(dev->dev,
1493d263114SMauro Carvalho Chehab "link %s->%s was %s\n",
1503d263114SMauro Carvalho Chehab source->name, sink->name,
1513d263114SMauro Carvalho Chehab flags ? "ENABLED" : "disabled");
1523d263114SMauro Carvalho Chehab }
1533d263114SMauro Carvalho Chehab #endif
1543d263114SMauro Carvalho Chehab return 0;
1553d263114SMauro Carvalho Chehab }
1563d263114SMauro Carvalho Chehab
1570c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------
1580c0d06caSMauro Carvalho Chehab Video buffer and parser functions
1590c0d06caSMauro Carvalho Chehab ------------------------------------------------------------------*/
1600c0d06caSMauro Carvalho Chehab
1610c0d06caSMauro Carvalho Chehab /*
1620c0d06caSMauro Carvalho Chehab * Announces that a buffer were filled and request the next
1630c0d06caSMauro Carvalho Chehab */
buffer_filled(struct cx231xx * dev,struct cx231xx_dmaqueue * dma_q,struct cx231xx_buffer * buf)1640c0d06caSMauro Carvalho Chehab static inline void buffer_filled(struct cx231xx *dev,
1650c0d06caSMauro Carvalho Chehab struct cx231xx_dmaqueue *dma_q,
1660c0d06caSMauro Carvalho Chehab struct cx231xx_buffer *buf)
1670c0d06caSMauro Carvalho Chehab {
1680c0d06caSMauro Carvalho Chehab /* Advice that buffer was filled */
1697c617138SHans Verkuil cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.vb2_buf.index);
1707c617138SHans Verkuil buf->vb.sequence = dma_q->sequence++;
1717c617138SHans Verkuil buf->vb.field = V4L2_FIELD_INTERLACED;
1727c617138SHans Verkuil buf->vb.vb2_buf.timestamp = ktime_get_ns();
1737c617138SHans Verkuil vb2_set_plane_payload(&buf->vb.vb2_buf, 0, dev->size);
1740c0d06caSMauro Carvalho Chehab
1750c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
1760c0d06caSMauro Carvalho Chehab dev->video_mode.isoc_ctl.buf = NULL;
1770c0d06caSMauro Carvalho Chehab else
1780c0d06caSMauro Carvalho Chehab dev->video_mode.bulk_ctl.buf = NULL;
1790c0d06caSMauro Carvalho Chehab
1807c617138SHans Verkuil list_del(&buf->list);
1817c617138SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
1820c0d06caSMauro Carvalho Chehab }
1830c0d06caSMauro Carvalho Chehab
print_err_status(struct cx231xx * dev,int packet,int status)1840c0d06caSMauro Carvalho Chehab static inline void print_err_status(struct cx231xx *dev, int packet, int status)
1850c0d06caSMauro Carvalho Chehab {
1860c0d06caSMauro Carvalho Chehab char *errmsg = "Unknown";
1870c0d06caSMauro Carvalho Chehab
1880c0d06caSMauro Carvalho Chehab switch (status) {
1890c0d06caSMauro Carvalho Chehab case -ENOENT:
190b436e26eSColin Ian King errmsg = "unlinked synchronously";
1910c0d06caSMauro Carvalho Chehab break;
1920c0d06caSMauro Carvalho Chehab case -ECONNRESET:
193b436e26eSColin Ian King errmsg = "unlinked asynchronously";
1940c0d06caSMauro Carvalho Chehab break;
1950c0d06caSMauro Carvalho Chehab case -ENOSR:
1960c0d06caSMauro Carvalho Chehab errmsg = "Buffer error (overrun)";
1970c0d06caSMauro Carvalho Chehab break;
1980c0d06caSMauro Carvalho Chehab case -EPIPE:
1990c0d06caSMauro Carvalho Chehab errmsg = "Stalled (device not responding)";
2000c0d06caSMauro Carvalho Chehab break;
2010c0d06caSMauro Carvalho Chehab case -EOVERFLOW:
2020c0d06caSMauro Carvalho Chehab errmsg = "Babble (bad cable?)";
2030c0d06caSMauro Carvalho Chehab break;
2040c0d06caSMauro Carvalho Chehab case -EPROTO:
2050c0d06caSMauro Carvalho Chehab errmsg = "Bit-stuff error (bad cable?)";
2060c0d06caSMauro Carvalho Chehab break;
2070c0d06caSMauro Carvalho Chehab case -EILSEQ:
2080c0d06caSMauro Carvalho Chehab errmsg = "CRC/Timeout (could be anything)";
2090c0d06caSMauro Carvalho Chehab break;
2100c0d06caSMauro Carvalho Chehab case -ETIME:
2110c0d06caSMauro Carvalho Chehab errmsg = "Device does not respond";
2120c0d06caSMauro Carvalho Chehab break;
2130c0d06caSMauro Carvalho Chehab }
2140c0d06caSMauro Carvalho Chehab if (packet < 0) {
2150c0d06caSMauro Carvalho Chehab cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg);
2160c0d06caSMauro Carvalho Chehab } else {
2170c0d06caSMauro Carvalho Chehab cx231xx_isocdbg("URB packet %d, status %d [%s].\n",
2180c0d06caSMauro Carvalho Chehab packet, status, errmsg);
2190c0d06caSMauro Carvalho Chehab }
2200c0d06caSMauro Carvalho Chehab }
2210c0d06caSMauro Carvalho Chehab
2220c0d06caSMauro Carvalho Chehab /*
223f068a6ceSHans Verkuil * generic routine to get the next available buffer
2240c0d06caSMauro Carvalho Chehab */
get_next_buf(struct cx231xx_dmaqueue * dma_q,struct cx231xx_buffer ** buf)2250c0d06caSMauro Carvalho Chehab static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
2260c0d06caSMauro Carvalho Chehab struct cx231xx_buffer **buf)
2270c0d06caSMauro Carvalho Chehab {
2280c0d06caSMauro Carvalho Chehab struct cx231xx_video_mode *vmode =
2290c0d06caSMauro Carvalho Chehab container_of(dma_q, struct cx231xx_video_mode, vidq);
2300c0d06caSMauro Carvalho Chehab struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
2310c0d06caSMauro Carvalho Chehab
2320c0d06caSMauro Carvalho Chehab char *outp;
2330c0d06caSMauro Carvalho Chehab
2340c0d06caSMauro Carvalho Chehab if (list_empty(&dma_q->active)) {
2350c0d06caSMauro Carvalho Chehab cx231xx_isocdbg("No active queue to serve\n");
2360c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
2370c0d06caSMauro Carvalho Chehab dev->video_mode.isoc_ctl.buf = NULL;
2380c0d06caSMauro Carvalho Chehab else
2390c0d06caSMauro Carvalho Chehab dev->video_mode.bulk_ctl.buf = NULL;
2400c0d06caSMauro Carvalho Chehab *buf = NULL;
2410c0d06caSMauro Carvalho Chehab return;
2420c0d06caSMauro Carvalho Chehab }
2430c0d06caSMauro Carvalho Chehab
2440c0d06caSMauro Carvalho Chehab /* Get the next buffer */
2457c617138SHans Verkuil *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list);
2460c0d06caSMauro Carvalho Chehab
2470c0d06caSMauro Carvalho Chehab /* Cleans up buffer - Useful for testing for frame/URB loss */
2487c617138SHans Verkuil outp = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
2497c617138SHans Verkuil memset(outp, 0, dev->size);
2500c0d06caSMauro Carvalho Chehab
2510c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
2520c0d06caSMauro Carvalho Chehab dev->video_mode.isoc_ctl.buf = *buf;
2530c0d06caSMauro Carvalho Chehab else
2540c0d06caSMauro Carvalho Chehab dev->video_mode.bulk_ctl.buf = *buf;
2550c0d06caSMauro Carvalho Chehab
2560c0d06caSMauro Carvalho Chehab return;
2570c0d06caSMauro Carvalho Chehab }
2580c0d06caSMauro Carvalho Chehab
2590c0d06caSMauro Carvalho Chehab /*
2600c0d06caSMauro Carvalho Chehab * Controls the isoc copy of each urb packet
2610c0d06caSMauro Carvalho Chehab */
cx231xx_isoc_copy(struct cx231xx * dev,struct urb * urb)2620c0d06caSMauro Carvalho Chehab static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
2630c0d06caSMauro Carvalho Chehab {
2640c0d06caSMauro Carvalho Chehab struct cx231xx_dmaqueue *dma_q = urb->context;
2654df16f70SPeter Senna Tschudin int i;
2660c0d06caSMauro Carvalho Chehab unsigned char *p_buffer;
2670c0d06caSMauro Carvalho Chehab u32 bytes_parsed = 0, buffer_size = 0;
2680c0d06caSMauro Carvalho Chehab u8 sav_eav = 0;
2690c0d06caSMauro Carvalho Chehab
2700c0d06caSMauro Carvalho Chehab if (!dev)
2710c0d06caSMauro Carvalho Chehab return 0;
2720c0d06caSMauro Carvalho Chehab
2730c0d06caSMauro Carvalho Chehab if (dev->state & DEV_DISCONNECTED)
2740c0d06caSMauro Carvalho Chehab return 0;
2750c0d06caSMauro Carvalho Chehab
2760c0d06caSMauro Carvalho Chehab if (urb->status < 0) {
2770c0d06caSMauro Carvalho Chehab print_err_status(dev, -1, urb->status);
2780c0d06caSMauro Carvalho Chehab if (urb->status == -ENOENT)
2790c0d06caSMauro Carvalho Chehab return 0;
2800c0d06caSMauro Carvalho Chehab }
2810c0d06caSMauro Carvalho Chehab
2820c0d06caSMauro Carvalho Chehab for (i = 0; i < urb->number_of_packets; i++) {
2830c0d06caSMauro Carvalho Chehab int status = urb->iso_frame_desc[i].status;
2840c0d06caSMauro Carvalho Chehab
2850c0d06caSMauro Carvalho Chehab if (status < 0) {
2860c0d06caSMauro Carvalho Chehab print_err_status(dev, i, status);
2870c0d06caSMauro Carvalho Chehab if (urb->iso_frame_desc[i].status != -EPROTO)
2880c0d06caSMauro Carvalho Chehab continue;
2890c0d06caSMauro Carvalho Chehab }
2900c0d06caSMauro Carvalho Chehab
2910c0d06caSMauro Carvalho Chehab if (urb->iso_frame_desc[i].actual_length <= 0) {
2920c0d06caSMauro Carvalho Chehab /* cx231xx_isocdbg("packet %d is empty",i); - spammy */
2930c0d06caSMauro Carvalho Chehab continue;
2940c0d06caSMauro Carvalho Chehab }
2950c0d06caSMauro Carvalho Chehab if (urb->iso_frame_desc[i].actual_length >
2960c0d06caSMauro Carvalho Chehab dev->video_mode.max_pkt_size) {
2970c0d06caSMauro Carvalho Chehab cx231xx_isocdbg("packet bigger than packet size");
2980c0d06caSMauro Carvalho Chehab continue;
2990c0d06caSMauro Carvalho Chehab }
3000c0d06caSMauro Carvalho Chehab
3010c0d06caSMauro Carvalho Chehab /* get buffer pointer and length */
3020c0d06caSMauro Carvalho Chehab p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
3030c0d06caSMauro Carvalho Chehab buffer_size = urb->iso_frame_desc[i].actual_length;
3040c0d06caSMauro Carvalho Chehab bytes_parsed = 0;
3050c0d06caSMauro Carvalho Chehab
3060c0d06caSMauro Carvalho Chehab if (dma_q->is_partial_line) {
3070c0d06caSMauro Carvalho Chehab /* Handle the case of a partial line */
3080c0d06caSMauro Carvalho Chehab sav_eav = dma_q->last_sav;
3090c0d06caSMauro Carvalho Chehab } else {
3100c0d06caSMauro Carvalho Chehab /* Check for a SAV/EAV overlapping
3110c0d06caSMauro Carvalho Chehab the buffer boundary */
3120c0d06caSMauro Carvalho Chehab sav_eav =
3130c0d06caSMauro Carvalho Chehab cx231xx_find_boundary_SAV_EAV(p_buffer,
3140c0d06caSMauro Carvalho Chehab dma_q->partial_buf,
3150c0d06caSMauro Carvalho Chehab &bytes_parsed);
3160c0d06caSMauro Carvalho Chehab }
3170c0d06caSMauro Carvalho Chehab
3180c0d06caSMauro Carvalho Chehab sav_eav &= 0xF0;
3190c0d06caSMauro Carvalho Chehab /* Get the first line if we have some portion of an SAV/EAV from
3200c0d06caSMauro Carvalho Chehab the last buffer or a partial line */
3210c0d06caSMauro Carvalho Chehab if (sav_eav) {
3220c0d06caSMauro Carvalho Chehab bytes_parsed += cx231xx_get_video_line(dev, dma_q,
3230c0d06caSMauro Carvalho Chehab sav_eav, /* SAV/EAV */
3240c0d06caSMauro Carvalho Chehab p_buffer + bytes_parsed, /* p_buffer */
3250c0d06caSMauro Carvalho Chehab buffer_size - bytes_parsed);/* buf size */
3260c0d06caSMauro Carvalho Chehab }
3270c0d06caSMauro Carvalho Chehab
3280c0d06caSMauro Carvalho Chehab /* Now parse data that is completely in this buffer */
3290c0d06caSMauro Carvalho Chehab /* dma_q->is_partial_line = 0; */
3300c0d06caSMauro Carvalho Chehab
3310c0d06caSMauro Carvalho Chehab while (bytes_parsed < buffer_size) {
3320c0d06caSMauro Carvalho Chehab u32 bytes_used = 0;
3330c0d06caSMauro Carvalho Chehab
3340c0d06caSMauro Carvalho Chehab sav_eav = cx231xx_find_next_SAV_EAV(
3350c0d06caSMauro Carvalho Chehab p_buffer + bytes_parsed, /* p_buffer */
3360c0d06caSMauro Carvalho Chehab buffer_size - bytes_parsed, /* buf size */
3370c0d06caSMauro Carvalho Chehab &bytes_used);/* bytes used to get SAV/EAV */
3380c0d06caSMauro Carvalho Chehab
3390c0d06caSMauro Carvalho Chehab bytes_parsed += bytes_used;
3400c0d06caSMauro Carvalho Chehab
3410c0d06caSMauro Carvalho Chehab sav_eav &= 0xF0;
3420c0d06caSMauro Carvalho Chehab if (sav_eav && (bytes_parsed < buffer_size)) {
3430c0d06caSMauro Carvalho Chehab bytes_parsed += cx231xx_get_video_line(dev,
3440c0d06caSMauro Carvalho Chehab dma_q, sav_eav, /* SAV/EAV */
3450c0d06caSMauro Carvalho Chehab p_buffer + bytes_parsed,/* p_buffer */
3460c0d06caSMauro Carvalho Chehab buffer_size - bytes_parsed);/*buf size*/
3470c0d06caSMauro Carvalho Chehab }
3480c0d06caSMauro Carvalho Chehab }
3490c0d06caSMauro Carvalho Chehab
3500c0d06caSMauro Carvalho Chehab /* Save the last four bytes of the buffer so we can check the
3510c0d06caSMauro Carvalho Chehab buffer boundary condition next time */
3520c0d06caSMauro Carvalho Chehab memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
3530c0d06caSMauro Carvalho Chehab bytes_parsed = 0;
3540c0d06caSMauro Carvalho Chehab
3550c0d06caSMauro Carvalho Chehab }
3564df16f70SPeter Senna Tschudin return 1;
3570c0d06caSMauro Carvalho Chehab }
3580c0d06caSMauro Carvalho Chehab
cx231xx_bulk_copy(struct cx231xx * dev,struct urb * urb)3590c0d06caSMauro Carvalho Chehab static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
3600c0d06caSMauro Carvalho Chehab {
3610c0d06caSMauro Carvalho Chehab struct cx231xx_dmaqueue *dma_q = urb->context;
3620c0d06caSMauro Carvalho Chehab unsigned char *p_buffer;
3630c0d06caSMauro Carvalho Chehab u32 bytes_parsed = 0, buffer_size = 0;
3640c0d06caSMauro Carvalho Chehab u8 sav_eav = 0;
3650c0d06caSMauro Carvalho Chehab
3660c0d06caSMauro Carvalho Chehab if (!dev)
3670c0d06caSMauro Carvalho Chehab return 0;
3680c0d06caSMauro Carvalho Chehab
3690c0d06caSMauro Carvalho Chehab if (dev->state & DEV_DISCONNECTED)
3700c0d06caSMauro Carvalho Chehab return 0;
3710c0d06caSMauro Carvalho Chehab
3720c0d06caSMauro Carvalho Chehab if (urb->status < 0) {
3730c0d06caSMauro Carvalho Chehab print_err_status(dev, -1, urb->status);
3740c0d06caSMauro Carvalho Chehab if (urb->status == -ENOENT)
3750c0d06caSMauro Carvalho Chehab return 0;
3760c0d06caSMauro Carvalho Chehab }
3770c0d06caSMauro Carvalho Chehab
3780c0d06caSMauro Carvalho Chehab if (1) {
3790c0d06caSMauro Carvalho Chehab
3800c0d06caSMauro Carvalho Chehab /* get buffer pointer and length */
3810c0d06caSMauro Carvalho Chehab p_buffer = urb->transfer_buffer;
3820c0d06caSMauro Carvalho Chehab buffer_size = urb->actual_length;
3830c0d06caSMauro Carvalho Chehab bytes_parsed = 0;
3840c0d06caSMauro Carvalho Chehab
3850c0d06caSMauro Carvalho Chehab if (dma_q->is_partial_line) {
3860c0d06caSMauro Carvalho Chehab /* Handle the case of a partial line */
3870c0d06caSMauro Carvalho Chehab sav_eav = dma_q->last_sav;
3880c0d06caSMauro Carvalho Chehab } else {
3890c0d06caSMauro Carvalho Chehab /* Check for a SAV/EAV overlapping
3900c0d06caSMauro Carvalho Chehab the buffer boundary */
3910c0d06caSMauro Carvalho Chehab sav_eav =
3920c0d06caSMauro Carvalho Chehab cx231xx_find_boundary_SAV_EAV(p_buffer,
3930c0d06caSMauro Carvalho Chehab dma_q->partial_buf,
3940c0d06caSMauro Carvalho Chehab &bytes_parsed);
3950c0d06caSMauro Carvalho Chehab }
3960c0d06caSMauro Carvalho Chehab
3970c0d06caSMauro Carvalho Chehab sav_eav &= 0xF0;
3980c0d06caSMauro Carvalho Chehab /* Get the first line if we have some portion of an SAV/EAV from
3990c0d06caSMauro Carvalho Chehab the last buffer or a partial line */
4000c0d06caSMauro Carvalho Chehab if (sav_eav) {
4010c0d06caSMauro Carvalho Chehab bytes_parsed += cx231xx_get_video_line(dev, dma_q,
4020c0d06caSMauro Carvalho Chehab sav_eav, /* SAV/EAV */
4030c0d06caSMauro Carvalho Chehab p_buffer + bytes_parsed, /* p_buffer */
4040c0d06caSMauro Carvalho Chehab buffer_size - bytes_parsed);/* buf size */
4050c0d06caSMauro Carvalho Chehab }
4060c0d06caSMauro Carvalho Chehab
4070c0d06caSMauro Carvalho Chehab /* Now parse data that is completely in this buffer */
4080c0d06caSMauro Carvalho Chehab /* dma_q->is_partial_line = 0; */
4090c0d06caSMauro Carvalho Chehab
4100c0d06caSMauro Carvalho Chehab while (bytes_parsed < buffer_size) {
4110c0d06caSMauro Carvalho Chehab u32 bytes_used = 0;
4120c0d06caSMauro Carvalho Chehab
4130c0d06caSMauro Carvalho Chehab sav_eav = cx231xx_find_next_SAV_EAV(
4140c0d06caSMauro Carvalho Chehab p_buffer + bytes_parsed, /* p_buffer */
4150c0d06caSMauro Carvalho Chehab buffer_size - bytes_parsed, /* buf size */
4160c0d06caSMauro Carvalho Chehab &bytes_used);/* bytes used to get SAV/EAV */
4170c0d06caSMauro Carvalho Chehab
4180c0d06caSMauro Carvalho Chehab bytes_parsed += bytes_used;
4190c0d06caSMauro Carvalho Chehab
4200c0d06caSMauro Carvalho Chehab sav_eav &= 0xF0;
4210c0d06caSMauro Carvalho Chehab if (sav_eav && (bytes_parsed < buffer_size)) {
4220c0d06caSMauro Carvalho Chehab bytes_parsed += cx231xx_get_video_line(dev,
4230c0d06caSMauro Carvalho Chehab dma_q, sav_eav, /* SAV/EAV */
4240c0d06caSMauro Carvalho Chehab p_buffer + bytes_parsed,/* p_buffer */
4250c0d06caSMauro Carvalho Chehab buffer_size - bytes_parsed);/*buf size*/
4260c0d06caSMauro Carvalho Chehab }
4270c0d06caSMauro Carvalho Chehab }
4280c0d06caSMauro Carvalho Chehab
4290c0d06caSMauro Carvalho Chehab /* Save the last four bytes of the buffer so we can check the
4300c0d06caSMauro Carvalho Chehab buffer boundary condition next time */
4310c0d06caSMauro Carvalho Chehab memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
4320c0d06caSMauro Carvalho Chehab bytes_parsed = 0;
4330c0d06caSMauro Carvalho Chehab
4340c0d06caSMauro Carvalho Chehab }
4354df16f70SPeter Senna Tschudin return 1;
4360c0d06caSMauro Carvalho Chehab }
4370c0d06caSMauro Carvalho Chehab
4380c0d06caSMauro Carvalho Chehab
cx231xx_find_boundary_SAV_EAV(u8 * p_buffer,u8 * partial_buf,u32 * p_bytes_used)4390c0d06caSMauro Carvalho Chehab u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
4400c0d06caSMauro Carvalho Chehab u32 *p_bytes_used)
4410c0d06caSMauro Carvalho Chehab {
4420c0d06caSMauro Carvalho Chehab u32 bytes_used;
4430c0d06caSMauro Carvalho Chehab u8 boundary_bytes[8];
4440c0d06caSMauro Carvalho Chehab u8 sav_eav = 0;
4450c0d06caSMauro Carvalho Chehab
4460c0d06caSMauro Carvalho Chehab *p_bytes_used = 0;
4470c0d06caSMauro Carvalho Chehab
4480c0d06caSMauro Carvalho Chehab /* Create an array of the last 4 bytes of the last buffer and the first
4490c0d06caSMauro Carvalho Chehab 4 bytes of the current buffer. */
4500c0d06caSMauro Carvalho Chehab
4510c0d06caSMauro Carvalho Chehab memcpy(boundary_bytes, partial_buf, 4);
4520c0d06caSMauro Carvalho Chehab memcpy(boundary_bytes + 4, p_buffer, 4);
4530c0d06caSMauro Carvalho Chehab
4540c0d06caSMauro Carvalho Chehab /* Check for the SAV/EAV in the boundary buffer */
4550c0d06caSMauro Carvalho Chehab sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8,
4560c0d06caSMauro Carvalho Chehab &bytes_used);
4570c0d06caSMauro Carvalho Chehab
4580c0d06caSMauro Carvalho Chehab if (sav_eav) {
4590c0d06caSMauro Carvalho Chehab /* found a boundary SAV/EAV. Updates the bytes used to reflect
4600c0d06caSMauro Carvalho Chehab only those used in the new buffer */
4610c0d06caSMauro Carvalho Chehab *p_bytes_used = bytes_used - 4;
4620c0d06caSMauro Carvalho Chehab }
4630c0d06caSMauro Carvalho Chehab
4640c0d06caSMauro Carvalho Chehab return sav_eav;
4650c0d06caSMauro Carvalho Chehab }
4660c0d06caSMauro Carvalho Chehab
cx231xx_find_next_SAV_EAV(u8 * p_buffer,u32 buffer_size,u32 * p_bytes_used)4670c0d06caSMauro Carvalho Chehab u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used)
4680c0d06caSMauro Carvalho Chehab {
4690c0d06caSMauro Carvalho Chehab u32 i;
4700c0d06caSMauro Carvalho Chehab u8 sav_eav = 0;
4710c0d06caSMauro Carvalho Chehab
4720c0d06caSMauro Carvalho Chehab /*
4730c0d06caSMauro Carvalho Chehab * Don't search if the buffer size is less than 4. It causes a page
4740c0d06caSMauro Carvalho Chehab * fault since buffer_size - 4 evaluates to a large number in that
4750c0d06caSMauro Carvalho Chehab * case.
4760c0d06caSMauro Carvalho Chehab */
4770c0d06caSMauro Carvalho Chehab if (buffer_size < 4) {
4780c0d06caSMauro Carvalho Chehab *p_bytes_used = buffer_size;
4790c0d06caSMauro Carvalho Chehab return 0;
4800c0d06caSMauro Carvalho Chehab }
4810c0d06caSMauro Carvalho Chehab
4820c0d06caSMauro Carvalho Chehab for (i = 0; i < (buffer_size - 3); i++) {
4830c0d06caSMauro Carvalho Chehab
4840c0d06caSMauro Carvalho Chehab if ((p_buffer[i] == 0xFF) &&
4850c0d06caSMauro Carvalho Chehab (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) {
4860c0d06caSMauro Carvalho Chehab
4870c0d06caSMauro Carvalho Chehab *p_bytes_used = i + 4;
4880c0d06caSMauro Carvalho Chehab sav_eav = p_buffer[i + 3];
4890c0d06caSMauro Carvalho Chehab return sav_eav;
4900c0d06caSMauro Carvalho Chehab }
4910c0d06caSMauro Carvalho Chehab }
4920c0d06caSMauro Carvalho Chehab
4930c0d06caSMauro Carvalho Chehab *p_bytes_used = buffer_size;
4940c0d06caSMauro Carvalho Chehab return 0;
4950c0d06caSMauro Carvalho Chehab }
4960c0d06caSMauro Carvalho Chehab
cx231xx_get_video_line(struct cx231xx * dev,struct cx231xx_dmaqueue * dma_q,u8 sav_eav,u8 * p_buffer,u32 buffer_size)4970c0d06caSMauro Carvalho Chehab u32 cx231xx_get_video_line(struct cx231xx *dev,
4980c0d06caSMauro Carvalho Chehab struct cx231xx_dmaqueue *dma_q, u8 sav_eav,
4990c0d06caSMauro Carvalho Chehab u8 *p_buffer, u32 buffer_size)
5000c0d06caSMauro Carvalho Chehab {
5010c0d06caSMauro Carvalho Chehab u32 bytes_copied = 0;
5020c0d06caSMauro Carvalho Chehab int current_field = -1;
5030c0d06caSMauro Carvalho Chehab
5040c0d06caSMauro Carvalho Chehab switch (sav_eav) {
5050c0d06caSMauro Carvalho Chehab case SAV_ACTIVE_VIDEO_FIELD1:
5060c0d06caSMauro Carvalho Chehab /* looking for skipped line which occurred in PAL 720x480 mode.
5070c0d06caSMauro Carvalho Chehab In this case, there will be no active data contained
5080c0d06caSMauro Carvalho Chehab between the SAV and EAV */
5090c0d06caSMauro Carvalho Chehab if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
5100c0d06caSMauro Carvalho Chehab (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
5110c0d06caSMauro Carvalho Chehab ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
5120c0d06caSMauro Carvalho Chehab (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
5130c0d06caSMauro Carvalho Chehab (p_buffer[3] == EAV_VBLANK_FIELD1) ||
5140c0d06caSMauro Carvalho Chehab (p_buffer[3] == EAV_VBLANK_FIELD2)))
5150c0d06caSMauro Carvalho Chehab return bytes_copied;
5160c0d06caSMauro Carvalho Chehab current_field = 1;
5170c0d06caSMauro Carvalho Chehab break;
5180c0d06caSMauro Carvalho Chehab
5190c0d06caSMauro Carvalho Chehab case SAV_ACTIVE_VIDEO_FIELD2:
5200c0d06caSMauro Carvalho Chehab /* looking for skipped line which occurred in PAL 720x480 mode.
5210c0d06caSMauro Carvalho Chehab In this case, there will be no active data contained between
5220c0d06caSMauro Carvalho Chehab the SAV and EAV */
5230c0d06caSMauro Carvalho Chehab if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
5240c0d06caSMauro Carvalho Chehab (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
5250c0d06caSMauro Carvalho Chehab ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
5260c0d06caSMauro Carvalho Chehab (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
5270c0d06caSMauro Carvalho Chehab (p_buffer[3] == EAV_VBLANK_FIELD1) ||
5280c0d06caSMauro Carvalho Chehab (p_buffer[3] == EAV_VBLANK_FIELD2)))
5290c0d06caSMauro Carvalho Chehab return bytes_copied;
5300c0d06caSMauro Carvalho Chehab current_field = 2;
5310c0d06caSMauro Carvalho Chehab break;
5320c0d06caSMauro Carvalho Chehab }
5330c0d06caSMauro Carvalho Chehab
5340c0d06caSMauro Carvalho Chehab dma_q->last_sav = sav_eav;
5350c0d06caSMauro Carvalho Chehab
5360c0d06caSMauro Carvalho Chehab bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer,
5370c0d06caSMauro Carvalho Chehab buffer_size, current_field);
5380c0d06caSMauro Carvalho Chehab
5390c0d06caSMauro Carvalho Chehab return bytes_copied;
5400c0d06caSMauro Carvalho Chehab }
5410c0d06caSMauro Carvalho Chehab
cx231xx_copy_video_line(struct cx231xx * dev,struct cx231xx_dmaqueue * dma_q,u8 * p_line,u32 length,int field_number)5420c0d06caSMauro Carvalho Chehab u32 cx231xx_copy_video_line(struct cx231xx *dev,
5430c0d06caSMauro Carvalho Chehab struct cx231xx_dmaqueue *dma_q, u8 *p_line,
5440c0d06caSMauro Carvalho Chehab u32 length, int field_number)
5450c0d06caSMauro Carvalho Chehab {
5460c0d06caSMauro Carvalho Chehab u32 bytes_to_copy;
5470c0d06caSMauro Carvalho Chehab struct cx231xx_buffer *buf;
5480c0d06caSMauro Carvalho Chehab u32 _line_size = dev->width * 2;
5490c0d06caSMauro Carvalho Chehab
5500c0d06caSMauro Carvalho Chehab if (dma_q->current_field != field_number)
5510c0d06caSMauro Carvalho Chehab cx231xx_reset_video_buffer(dev, dma_q);
5520c0d06caSMauro Carvalho Chehab
5530c0d06caSMauro Carvalho Chehab /* get the buffer pointer */
5540c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
5550c0d06caSMauro Carvalho Chehab buf = dev->video_mode.isoc_ctl.buf;
5560c0d06caSMauro Carvalho Chehab else
5570c0d06caSMauro Carvalho Chehab buf = dev->video_mode.bulk_ctl.buf;
5580c0d06caSMauro Carvalho Chehab
5590c0d06caSMauro Carvalho Chehab /* Remember the field number for next time */
5600c0d06caSMauro Carvalho Chehab dma_q->current_field = field_number;
5610c0d06caSMauro Carvalho Chehab
5620c0d06caSMauro Carvalho Chehab bytes_to_copy = dma_q->bytes_left_in_line;
5630c0d06caSMauro Carvalho Chehab if (bytes_to_copy > length)
5640c0d06caSMauro Carvalho Chehab bytes_to_copy = length;
5650c0d06caSMauro Carvalho Chehab
5660c0d06caSMauro Carvalho Chehab if (dma_q->lines_completed >= dma_q->lines_per_field) {
5670c0d06caSMauro Carvalho Chehab dma_q->bytes_left_in_line -= bytes_to_copy;
5680c0d06caSMauro Carvalho Chehab dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ?
5690c0d06caSMauro Carvalho Chehab 0 : 1;
5700c0d06caSMauro Carvalho Chehab return 0;
5710c0d06caSMauro Carvalho Chehab }
5720c0d06caSMauro Carvalho Chehab
5730c0d06caSMauro Carvalho Chehab dma_q->is_partial_line = 1;
5740c0d06caSMauro Carvalho Chehab
5750c0d06caSMauro Carvalho Chehab /* If we don't have a buffer, just return the number of bytes we would
5760c0d06caSMauro Carvalho Chehab have copied if we had a buffer. */
5770c0d06caSMauro Carvalho Chehab if (!buf) {
5780c0d06caSMauro Carvalho Chehab dma_q->bytes_left_in_line -= bytes_to_copy;
5790c0d06caSMauro Carvalho Chehab dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0)
5800c0d06caSMauro Carvalho Chehab ? 0 : 1;
5810c0d06caSMauro Carvalho Chehab return bytes_to_copy;
5820c0d06caSMauro Carvalho Chehab }
5830c0d06caSMauro Carvalho Chehab
5840c0d06caSMauro Carvalho Chehab /* copy the data to video buffer */
5850c0d06caSMauro Carvalho Chehab cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy);
5860c0d06caSMauro Carvalho Chehab
5870c0d06caSMauro Carvalho Chehab dma_q->pos += bytes_to_copy;
5880c0d06caSMauro Carvalho Chehab dma_q->bytes_left_in_line -= bytes_to_copy;
5890c0d06caSMauro Carvalho Chehab
5900c0d06caSMauro Carvalho Chehab if (dma_q->bytes_left_in_line == 0) {
5910c0d06caSMauro Carvalho Chehab dma_q->bytes_left_in_line = _line_size;
5920c0d06caSMauro Carvalho Chehab dma_q->lines_completed++;
5930c0d06caSMauro Carvalho Chehab dma_q->is_partial_line = 0;
5940c0d06caSMauro Carvalho Chehab
5950c0d06caSMauro Carvalho Chehab if (cx231xx_is_buffer_done(dev, dma_q) && buf) {
5960c0d06caSMauro Carvalho Chehab buffer_filled(dev, dma_q, buf);
5970c0d06caSMauro Carvalho Chehab
5980c0d06caSMauro Carvalho Chehab dma_q->pos = 0;
5990c0d06caSMauro Carvalho Chehab buf = NULL;
6000c0d06caSMauro Carvalho Chehab dma_q->lines_completed = 0;
6010c0d06caSMauro Carvalho Chehab }
6020c0d06caSMauro Carvalho Chehab }
6030c0d06caSMauro Carvalho Chehab
6040c0d06caSMauro Carvalho Chehab return bytes_to_copy;
6050c0d06caSMauro Carvalho Chehab }
6060c0d06caSMauro Carvalho Chehab
cx231xx_reset_video_buffer(struct cx231xx * dev,struct cx231xx_dmaqueue * dma_q)6070c0d06caSMauro Carvalho Chehab void cx231xx_reset_video_buffer(struct cx231xx *dev,
6080c0d06caSMauro Carvalho Chehab struct cx231xx_dmaqueue *dma_q)
6090c0d06caSMauro Carvalho Chehab {
6100c0d06caSMauro Carvalho Chehab struct cx231xx_buffer *buf;
6110c0d06caSMauro Carvalho Chehab
6120c0d06caSMauro Carvalho Chehab /* handle the switch from field 1 to field 2 */
6130c0d06caSMauro Carvalho Chehab if (dma_q->current_field == 1) {
6140c0d06caSMauro Carvalho Chehab if (dma_q->lines_completed >= dma_q->lines_per_field)
6150c0d06caSMauro Carvalho Chehab dma_q->field1_done = 1;
6160c0d06caSMauro Carvalho Chehab else
6170c0d06caSMauro Carvalho Chehab dma_q->field1_done = 0;
6180c0d06caSMauro Carvalho Chehab }
6190c0d06caSMauro Carvalho Chehab
6200c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
6210c0d06caSMauro Carvalho Chehab buf = dev->video_mode.isoc_ctl.buf;
6220c0d06caSMauro Carvalho Chehab else
6230c0d06caSMauro Carvalho Chehab buf = dev->video_mode.bulk_ctl.buf;
6240c0d06caSMauro Carvalho Chehab
6250c0d06caSMauro Carvalho Chehab if (buf == NULL) {
6260c0d06caSMauro Carvalho Chehab /* first try to get the buffer */
6270c0d06caSMauro Carvalho Chehab get_next_buf(dma_q, &buf);
6280c0d06caSMauro Carvalho Chehab
6290c0d06caSMauro Carvalho Chehab dma_q->pos = 0;
6300c0d06caSMauro Carvalho Chehab dma_q->field1_done = 0;
6310c0d06caSMauro Carvalho Chehab dma_q->current_field = -1;
6320c0d06caSMauro Carvalho Chehab }
6330c0d06caSMauro Carvalho Chehab
6340c0d06caSMauro Carvalho Chehab /* reset the counters */
6350c0d06caSMauro Carvalho Chehab dma_q->bytes_left_in_line = dev->width << 1;
6360c0d06caSMauro Carvalho Chehab dma_q->lines_completed = 0;
6370c0d06caSMauro Carvalho Chehab }
6380c0d06caSMauro Carvalho Chehab
cx231xx_do_copy(struct cx231xx * dev,struct cx231xx_dmaqueue * dma_q,u8 * p_buffer,u32 bytes_to_copy)6390c0d06caSMauro Carvalho Chehab int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
6400c0d06caSMauro Carvalho Chehab u8 *p_buffer, u32 bytes_to_copy)
6410c0d06caSMauro Carvalho Chehab {
6420c0d06caSMauro Carvalho Chehab u8 *p_out_buffer = NULL;
6430c0d06caSMauro Carvalho Chehab u32 current_line_bytes_copied = 0;
6440c0d06caSMauro Carvalho Chehab struct cx231xx_buffer *buf;
6450c0d06caSMauro Carvalho Chehab u32 _line_size = dev->width << 1;
6460c0d06caSMauro Carvalho Chehab void *startwrite;
6470c0d06caSMauro Carvalho Chehab int offset, lencopy;
6480c0d06caSMauro Carvalho Chehab
6490c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
6500c0d06caSMauro Carvalho Chehab buf = dev->video_mode.isoc_ctl.buf;
6510c0d06caSMauro Carvalho Chehab else
6520c0d06caSMauro Carvalho Chehab buf = dev->video_mode.bulk_ctl.buf;
6530c0d06caSMauro Carvalho Chehab
6540c0d06caSMauro Carvalho Chehab if (buf == NULL)
6550c0d06caSMauro Carvalho Chehab return -1;
6560c0d06caSMauro Carvalho Chehab
6577c617138SHans Verkuil p_out_buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
6580c0d06caSMauro Carvalho Chehab
6590c0d06caSMauro Carvalho Chehab current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line;
6600c0d06caSMauro Carvalho Chehab
6610c0d06caSMauro Carvalho Chehab /* Offset field 2 one line from the top of the buffer */
6620c0d06caSMauro Carvalho Chehab offset = (dma_q->current_field == 1) ? 0 : _line_size;
6630c0d06caSMauro Carvalho Chehab
6640c0d06caSMauro Carvalho Chehab /* Offset for field 2 */
6650c0d06caSMauro Carvalho Chehab startwrite = p_out_buffer + offset;
6660c0d06caSMauro Carvalho Chehab
6670c0d06caSMauro Carvalho Chehab /* lines already completed in the current field */
6680c0d06caSMauro Carvalho Chehab startwrite += (dma_q->lines_completed * _line_size * 2);
6690c0d06caSMauro Carvalho Chehab
6700c0d06caSMauro Carvalho Chehab /* bytes already completed in the current line */
6710c0d06caSMauro Carvalho Chehab startwrite += current_line_bytes_copied;
6720c0d06caSMauro Carvalho Chehab
6730c0d06caSMauro Carvalho Chehab lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
6740c0d06caSMauro Carvalho Chehab bytes_to_copy : dma_q->bytes_left_in_line;
6750c0d06caSMauro Carvalho Chehab
6767c617138SHans Verkuil if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + dev->size))
6770c0d06caSMauro Carvalho Chehab return 0;
6780c0d06caSMauro Carvalho Chehab
6790c0d06caSMauro Carvalho Chehab /* The below copies the UYVY data straight into video buffer */
6800c0d06caSMauro Carvalho Chehab cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy);
6810c0d06caSMauro Carvalho Chehab
6820c0d06caSMauro Carvalho Chehab return 0;
6830c0d06caSMauro Carvalho Chehab }
6840c0d06caSMauro Carvalho Chehab
cx231xx_swab(u16 * from,u16 * to,u16 len)6850c0d06caSMauro Carvalho Chehab void cx231xx_swab(u16 *from, u16 *to, u16 len)
6860c0d06caSMauro Carvalho Chehab {
6870c0d06caSMauro Carvalho Chehab u16 i;
6880c0d06caSMauro Carvalho Chehab
6890c0d06caSMauro Carvalho Chehab if (len <= 0)
6900c0d06caSMauro Carvalho Chehab return;
6910c0d06caSMauro Carvalho Chehab
6920c0d06caSMauro Carvalho Chehab for (i = 0; i < len / 2; i++)
6930c0d06caSMauro Carvalho Chehab to[i] = (from[i] << 8) | (from[i] >> 8);
6940c0d06caSMauro Carvalho Chehab }
6950c0d06caSMauro Carvalho Chehab
cx231xx_is_buffer_done(struct cx231xx * dev,struct cx231xx_dmaqueue * dma_q)6960c0d06caSMauro Carvalho Chehab u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q)
6970c0d06caSMauro Carvalho Chehab {
6980c0d06caSMauro Carvalho Chehab u8 buffer_complete = 0;
6990c0d06caSMauro Carvalho Chehab
7000c0d06caSMauro Carvalho Chehab /* Dual field stream */
7010c0d06caSMauro Carvalho Chehab buffer_complete = ((dma_q->current_field == 2) &&
7020c0d06caSMauro Carvalho Chehab (dma_q->lines_completed >= dma_q->lines_per_field) &&
7030c0d06caSMauro Carvalho Chehab dma_q->field1_done);
7040c0d06caSMauro Carvalho Chehab
7050c0d06caSMauro Carvalho Chehab return buffer_complete;
7060c0d06caSMauro Carvalho Chehab }
7070c0d06caSMauro Carvalho Chehab
7080c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------
7090c0d06caSMauro Carvalho Chehab Videobuf operations
7100c0d06caSMauro Carvalho Chehab ------------------------------------------------------------------*/
7110c0d06caSMauro Carvalho Chehab
queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])7127c617138SHans Verkuil static int queue_setup(struct vb2_queue *vq,
7137c617138SHans Verkuil unsigned int *nbuffers, unsigned int *nplanes,
7147c617138SHans Verkuil unsigned int sizes[], struct device *alloc_devs[])
7150c0d06caSMauro Carvalho Chehab {
7167c617138SHans Verkuil struct cx231xx *dev = vb2_get_drv_priv(vq);
717ca44d57aSBenjamin Gaignard unsigned int q_num_bufs = vb2_get_num_buffers(vq);
7180c0d06caSMauro Carvalho Chehab
7197c617138SHans Verkuil dev->size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
7200c0d06caSMauro Carvalho Chehab
721ca44d57aSBenjamin Gaignard if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF)
722ca44d57aSBenjamin Gaignard *nbuffers = CX231XX_MIN_BUF - q_num_bufs;
7230c0d06caSMauro Carvalho Chehab
7247c617138SHans Verkuil if (*nplanes)
7257c617138SHans Verkuil return sizes[0] < dev->size ? -EINVAL : 0;
7267c617138SHans Verkuil *nplanes = 1;
7277c617138SHans Verkuil sizes[0] = dev->size;
7283d263114SMauro Carvalho Chehab
7290c0d06caSMauro Carvalho Chehab return 0;
7300c0d06caSMauro Carvalho Chehab }
7310c0d06caSMauro Carvalho Chehab
buffer_queue(struct vb2_buffer * vb)7327c617138SHans Verkuil static void buffer_queue(struct vb2_buffer *vb)
7330c0d06caSMauro Carvalho Chehab {
7347c617138SHans Verkuil struct cx231xx_buffer *buf =
7357c617138SHans Verkuil container_of(vb, struct cx231xx_buffer, vb.vb2_buf);
7367c617138SHans Verkuil struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue);
7377c617138SHans Verkuil struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
7387c617138SHans Verkuil unsigned long flags;
7390c0d06caSMauro Carvalho Chehab
7400c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&dev->video_mode.slock, flags);
7417c617138SHans Verkuil list_add_tail(&buf->list, &vidq->active);
7427c617138SHans Verkuil spin_unlock_irqrestore(&dev->video_mode.slock, flags);
7437c617138SHans Verkuil }
7447c617138SHans Verkuil
return_all_buffers(struct cx231xx * dev,enum vb2_buffer_state state)7457c617138SHans Verkuil static void return_all_buffers(struct cx231xx *dev,
7467c617138SHans Verkuil enum vb2_buffer_state state)
7477c617138SHans Verkuil {
7487c617138SHans Verkuil struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
7497c617138SHans Verkuil struct cx231xx_buffer *buf, *node;
7507c617138SHans Verkuil unsigned long flags;
7517c617138SHans Verkuil
7527c617138SHans Verkuil spin_lock_irqsave(&dev->video_mode.slock, flags);
7537c617138SHans Verkuil if (dev->USE_ISO)
7540c0d06caSMauro Carvalho Chehab dev->video_mode.isoc_ctl.buf = NULL;
7557c617138SHans Verkuil else
7560c0d06caSMauro Carvalho Chehab dev->video_mode.bulk_ctl.buf = NULL;
7577c617138SHans Verkuil list_for_each_entry_safe(buf, node, &vidq->active, list) {
7587c617138SHans Verkuil list_del(&buf->list);
7597c617138SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, state);
7600c0d06caSMauro Carvalho Chehab }
7610c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&dev->video_mode.slock, flags);
7620c0d06caSMauro Carvalho Chehab }
7630c0d06caSMauro Carvalho Chehab
start_streaming(struct vb2_queue * vq,unsigned int count)7647c617138SHans Verkuil static int start_streaming(struct vb2_queue *vq, unsigned int count)
7650c0d06caSMauro Carvalho Chehab {
7667c617138SHans Verkuil struct cx231xx *dev = vb2_get_drv_priv(vq);
7677c617138SHans Verkuil struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
7687c617138SHans Verkuil int ret = 0;
7690c0d06caSMauro Carvalho Chehab
7707c617138SHans Verkuil vidq->sequence = 0;
7710c0d06caSMauro Carvalho Chehab dev->mode_tv = 0;
7727c617138SHans Verkuil
7737c617138SHans Verkuil cx231xx_enable_analog_tuner(dev);
7740c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
7757c617138SHans Verkuil ret = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
7760c0d06caSMauro Carvalho Chehab CX231XX_NUM_BUFS,
7770c0d06caSMauro Carvalho Chehab dev->video_mode.max_pkt_size,
7780c0d06caSMauro Carvalho Chehab cx231xx_isoc_copy);
7790c0d06caSMauro Carvalho Chehab else
7807c617138SHans Verkuil ret = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
7810c0d06caSMauro Carvalho Chehab CX231XX_NUM_BUFS,
7820c0d06caSMauro Carvalho Chehab dev->video_mode.max_pkt_size,
7830c0d06caSMauro Carvalho Chehab cx231xx_bulk_copy);
7847c617138SHans Verkuil if (ret)
7857c617138SHans Verkuil return_all_buffers(dev, VB2_BUF_STATE_QUEUED);
7867c617138SHans Verkuil call_all(dev, video, s_stream, 1);
7877c617138SHans Verkuil return ret;
7880c0d06caSMauro Carvalho Chehab }
7890c0d06caSMauro Carvalho Chehab
stop_streaming(struct vb2_queue * vq)7907c617138SHans Verkuil static void stop_streaming(struct vb2_queue *vq)
7910c0d06caSMauro Carvalho Chehab {
7927c617138SHans Verkuil struct cx231xx *dev = vb2_get_drv_priv(vq);
7930c0d06caSMauro Carvalho Chehab
7947c617138SHans Verkuil call_all(dev, video, s_stream, 0);
7957c617138SHans Verkuil return_all_buffers(dev, VB2_BUF_STATE_ERROR);
7960c0d06caSMauro Carvalho Chehab }
7970c0d06caSMauro Carvalho Chehab
798*d2ae63c2SChristophe JAILLET static const struct vb2_ops cx231xx_video_qops = {
7997c617138SHans Verkuil .queue_setup = queue_setup,
8000c0d06caSMauro Carvalho Chehab .buf_queue = buffer_queue,
8017c617138SHans Verkuil .start_streaming = start_streaming,
8027c617138SHans Verkuil .stop_streaming = stop_streaming,
8037c617138SHans Verkuil .wait_prepare = vb2_ops_wait_prepare,
8047c617138SHans Verkuil .wait_finish = vb2_ops_wait_finish,
8050c0d06caSMauro Carvalho Chehab };
8060c0d06caSMauro Carvalho Chehab
8070c0d06caSMauro Carvalho Chehab /********************* v4l2 interface **************************************/
8080c0d06caSMauro Carvalho Chehab
video_mux(struct cx231xx * dev,int index)8090c0d06caSMauro Carvalho Chehab void video_mux(struct cx231xx *dev, int index)
8100c0d06caSMauro Carvalho Chehab {
8110c0d06caSMauro Carvalho Chehab dev->video_input = index;
8120c0d06caSMauro Carvalho Chehab dev->ctl_ainput = INPUT(index)->amux;
8130c0d06caSMauro Carvalho Chehab
8140c0d06caSMauro Carvalho Chehab cx231xx_set_video_input_mux(dev, index);
8150c0d06caSMauro Carvalho Chehab
8160c0d06caSMauro Carvalho Chehab cx25840_call(dev, video, s_routing, INPUT(index)->vmux, 0, 0);
8170c0d06caSMauro Carvalho Chehab
8180c0d06caSMauro Carvalho Chehab cx231xx_set_audio_input(dev, dev->ctl_ainput);
8190c0d06caSMauro Carvalho Chehab
820336fea92SMauro Carvalho Chehab dev_dbg(dev->dev, "video_mux : %d\n", index);
8210c0d06caSMauro Carvalho Chehab
8220c0d06caSMauro Carvalho Chehab /* do mode control overrides if required */
8230c0d06caSMauro Carvalho Chehab cx231xx_do_mode_ctrl_overrides(dev);
8240c0d06caSMauro Carvalho Chehab }
8250c0d06caSMauro Carvalho Chehab
8260c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------
8270c0d06caSMauro Carvalho Chehab IOCTL vidioc handling
8280c0d06caSMauro Carvalho Chehab ------------------------------------------------------------------*/
8290c0d06caSMauro Carvalho Chehab
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)8300c0d06caSMauro Carvalho Chehab static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
8310c0d06caSMauro Carvalho Chehab struct v4l2_format *f)
8320c0d06caSMauro Carvalho Chehab {
8337c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
8340c0d06caSMauro Carvalho Chehab
8350c0d06caSMauro Carvalho Chehab f->fmt.pix.width = dev->width;
8360c0d06caSMauro Carvalho Chehab f->fmt.pix.height = dev->height;
8370c0d06caSMauro Carvalho Chehab f->fmt.pix.pixelformat = dev->format->fourcc;
8380c0d06caSMauro Carvalho Chehab f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
8390c0d06caSMauro Carvalho Chehab f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
8400c0d06caSMauro Carvalho Chehab f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
8410c0d06caSMauro Carvalho Chehab
8420c0d06caSMauro Carvalho Chehab f->fmt.pix.field = V4L2_FIELD_INTERLACED;
8430c0d06caSMauro Carvalho Chehab
8440c0d06caSMauro Carvalho Chehab return 0;
8450c0d06caSMauro Carvalho Chehab }
8460c0d06caSMauro Carvalho Chehab
format_by_fourcc(unsigned int fourcc)8470c0d06caSMauro Carvalho Chehab static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc)
8480c0d06caSMauro Carvalho Chehab {
8490c0d06caSMauro Carvalho Chehab unsigned int i;
8500c0d06caSMauro Carvalho Chehab
8510c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(format); i++)
8520c0d06caSMauro Carvalho Chehab if (format[i].fourcc == fourcc)
8530c0d06caSMauro Carvalho Chehab return &format[i];
8540c0d06caSMauro Carvalho Chehab
8550c0d06caSMauro Carvalho Chehab return NULL;
8560c0d06caSMauro Carvalho Chehab }
8570c0d06caSMauro Carvalho Chehab
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)8580c0d06caSMauro Carvalho Chehab static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
8590c0d06caSMauro Carvalho Chehab struct v4l2_format *f)
8600c0d06caSMauro Carvalho Chehab {
8617c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
8620c0d06caSMauro Carvalho Chehab unsigned int width = f->fmt.pix.width;
8630c0d06caSMauro Carvalho Chehab unsigned int height = f->fmt.pix.height;
8640c0d06caSMauro Carvalho Chehab unsigned int maxw = norm_maxw(dev);
8650c0d06caSMauro Carvalho Chehab unsigned int maxh = norm_maxh(dev);
8660c0d06caSMauro Carvalho Chehab struct cx231xx_fmt *fmt;
8670c0d06caSMauro Carvalho Chehab
8680c0d06caSMauro Carvalho Chehab fmt = format_by_fourcc(f->fmt.pix.pixelformat);
8690c0d06caSMauro Carvalho Chehab if (!fmt) {
8700c0d06caSMauro Carvalho Chehab cx231xx_videodbg("Fourcc format (%08x) invalid.\n",
8710c0d06caSMauro Carvalho Chehab f->fmt.pix.pixelformat);
8720c0d06caSMauro Carvalho Chehab return -EINVAL;
8730c0d06caSMauro Carvalho Chehab }
8740c0d06caSMauro Carvalho Chehab
8750c0d06caSMauro Carvalho Chehab /* width must even because of the YUYV format
8760c0d06caSMauro Carvalho Chehab height must be even because of interlacing */
8770c0d06caSMauro Carvalho Chehab v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
8780c0d06caSMauro Carvalho Chehab
8790c0d06caSMauro Carvalho Chehab f->fmt.pix.width = width;
8800c0d06caSMauro Carvalho Chehab f->fmt.pix.height = height;
8810c0d06caSMauro Carvalho Chehab f->fmt.pix.pixelformat = fmt->fourcc;
8828b735c13SHans Verkuil f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
8830c0d06caSMauro Carvalho Chehab f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
8840c0d06caSMauro Carvalho Chehab f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
8850c0d06caSMauro Carvalho Chehab f->fmt.pix.field = V4L2_FIELD_INTERLACED;
8860c0d06caSMauro Carvalho Chehab
8870c0d06caSMauro Carvalho Chehab return 0;
8880c0d06caSMauro Carvalho Chehab }
8890c0d06caSMauro Carvalho Chehab
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)8900c0d06caSMauro Carvalho Chehab static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
8910c0d06caSMauro Carvalho Chehab struct v4l2_format *f)
8920c0d06caSMauro Carvalho Chehab {
8937c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
894ebf984bbSHans Verkuil struct v4l2_subdev_format format = {
895ebf984bbSHans Verkuil .which = V4L2_SUBDEV_FORMAT_ACTIVE,
896ebf984bbSHans Verkuil };
8977c617138SHans Verkuil int rc;
8980c0d06caSMauro Carvalho Chehab
8997c617138SHans Verkuil rc = vidioc_try_fmt_vid_cap(file, priv, f);
9007c617138SHans Verkuil if (rc)
9010c0d06caSMauro Carvalho Chehab return rc;
9020c0d06caSMauro Carvalho Chehab
9037c617138SHans Verkuil if (vb2_is_busy(&dev->vidq)) {
904336fea92SMauro Carvalho Chehab dev_err(dev->dev, "%s: queue busy\n", __func__);
9050c0d06caSMauro Carvalho Chehab return -EBUSY;
9060c0d06caSMauro Carvalho Chehab }
9070c0d06caSMauro Carvalho Chehab
9080c0d06caSMauro Carvalho Chehab /* set new image size */
9090c0d06caSMauro Carvalho Chehab dev->width = f->fmt.pix.width;
9100c0d06caSMauro Carvalho Chehab dev->height = f->fmt.pix.height;
9117c617138SHans Verkuil dev->format = format_by_fourcc(f->fmt.pix.pixelformat);
9120c0d06caSMauro Carvalho Chehab
913ebf984bbSHans Verkuil v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
914ebf984bbSHans Verkuil call_all(dev, pad, set_fmt, NULL, &format);
915ebf984bbSHans Verkuil v4l2_fill_pix_format(&f->fmt.pix, &format.format);
9160c0d06caSMauro Carvalho Chehab
9170c0d06caSMauro Carvalho Chehab return rc;
9180c0d06caSMauro Carvalho Chehab }
9190c0d06caSMauro Carvalho Chehab
vidioc_g_std(struct file * file,void * priv,v4l2_std_id * id)9200c0d06caSMauro Carvalho Chehab static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
9210c0d06caSMauro Carvalho Chehab {
9227c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
9230c0d06caSMauro Carvalho Chehab
9240c0d06caSMauro Carvalho Chehab *id = dev->norm;
9250c0d06caSMauro Carvalho Chehab return 0;
9260c0d06caSMauro Carvalho Chehab }
9270c0d06caSMauro Carvalho Chehab
vidioc_s_std(struct file * file,void * priv,v4l2_std_id norm)928314527acSHans Verkuil static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
9290c0d06caSMauro Carvalho Chehab {
9307c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
931ebf984bbSHans Verkuil struct v4l2_subdev_format format = {
932ebf984bbSHans Verkuil .which = V4L2_SUBDEV_FORMAT_ACTIVE,
933ebf984bbSHans Verkuil };
9340c0d06caSMauro Carvalho Chehab
935314527acSHans Verkuil if (dev->norm == norm)
936d61072a4SHans Verkuil return 0;
937d61072a4SHans Verkuil
9387c617138SHans Verkuil if (vb2_is_busy(&dev->vidq))
939d61072a4SHans Verkuil return -EBUSY;
9400c0d06caSMauro Carvalho Chehab
941314527acSHans Verkuil dev->norm = norm;
9420c0d06caSMauro Carvalho Chehab
9430c0d06caSMauro Carvalho Chehab /* Adjusts width/height, if needed */
944d61072a4SHans Verkuil dev->width = 720;
945d61072a4SHans Verkuil dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480;
9460c0d06caSMauro Carvalho Chehab
9478774bed9SLaurent Pinchart call_all(dev, video, s_std, dev->norm);
9480c0d06caSMauro Carvalho Chehab
9490c0d06caSMauro Carvalho Chehab /* We need to reset basic properties in the decoder related to
9500c0d06caSMauro Carvalho Chehab resolution (since a standard change effects things like the number
9510c0d06caSMauro Carvalho Chehab of lines in VACT, etc) */
952ebf984bbSHans Verkuil format.format.code = MEDIA_BUS_FMT_FIXED;
953ebf984bbSHans Verkuil format.format.width = dev->width;
954ebf984bbSHans Verkuil format.format.height = dev->height;
955ebf984bbSHans Verkuil call_all(dev, pad, set_fmt, NULL, &format);
9560c0d06caSMauro Carvalho Chehab
9570c0d06caSMauro Carvalho Chehab /* do mode control overrides */
9580c0d06caSMauro Carvalho Chehab cx231xx_do_mode_ctrl_overrides(dev);
9590c0d06caSMauro Carvalho Chehab
9600c0d06caSMauro Carvalho Chehab return 0;
9610c0d06caSMauro Carvalho Chehab }
9620c0d06caSMauro Carvalho Chehab
9630c0d06caSMauro Carvalho Chehab static const char *iname[] = {
9640c0d06caSMauro Carvalho Chehab [CX231XX_VMUX_COMPOSITE1] = "Composite1",
9650c0d06caSMauro Carvalho Chehab [CX231XX_VMUX_SVIDEO] = "S-Video",
9660c0d06caSMauro Carvalho Chehab [CX231XX_VMUX_TELEVISION] = "Television",
9670c0d06caSMauro Carvalho Chehab [CX231XX_VMUX_CABLE] = "Cable TV",
9680c0d06caSMauro Carvalho Chehab [CX231XX_VMUX_DVB] = "DVB",
9690c0d06caSMauro Carvalho Chehab };
9700c0d06caSMauro Carvalho Chehab
cx231xx_v4l2_create_entities(struct cx231xx * dev)9716168309aSMauro Carvalho Chehab void cx231xx_v4l2_create_entities(struct cx231xx *dev)
9726168309aSMauro Carvalho Chehab {
9736168309aSMauro Carvalho Chehab #if defined(CONFIG_MEDIA_CONTROLLER)
9746168309aSMauro Carvalho Chehab int ret, i;
9756168309aSMauro Carvalho Chehab
9766168309aSMauro Carvalho Chehab /* Create entities for each input connector */
9776168309aSMauro Carvalho Chehab for (i = 0; i < MAX_CX231XX_INPUT; i++) {
9786168309aSMauro Carvalho Chehab struct media_entity *ent = &dev->input_ent[i];
9796168309aSMauro Carvalho Chehab
9806168309aSMauro Carvalho Chehab if (!INPUT(i)->type)
9816168309aSMauro Carvalho Chehab break;
9826168309aSMauro Carvalho Chehab
9836168309aSMauro Carvalho Chehab ent->name = iname[INPUT(i)->type];
9846168309aSMauro Carvalho Chehab ent->flags = MEDIA_ENT_FL_CONNECTOR;
9856168309aSMauro Carvalho Chehab dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
9866168309aSMauro Carvalho Chehab
9876168309aSMauro Carvalho Chehab switch (INPUT(i)->type) {
9886168309aSMauro Carvalho Chehab case CX231XX_VMUX_COMPOSITE1:
9896168309aSMauro Carvalho Chehab ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
9906168309aSMauro Carvalho Chehab break;
9916168309aSMauro Carvalho Chehab case CX231XX_VMUX_SVIDEO:
9926168309aSMauro Carvalho Chehab ent->function = MEDIA_ENT_F_CONN_SVIDEO;
9936168309aSMauro Carvalho Chehab break;
9946168309aSMauro Carvalho Chehab case CX231XX_VMUX_TELEVISION:
9956168309aSMauro Carvalho Chehab case CX231XX_VMUX_CABLE:
9966168309aSMauro Carvalho Chehab case CX231XX_VMUX_DVB:
9976168309aSMauro Carvalho Chehab /* The DVB core will handle it */
9986168309aSMauro Carvalho Chehab if (dev->tuner_type == TUNER_ABSENT)
9996168309aSMauro Carvalho Chehab continue;
1000df561f66SGustavo A. R. Silva fallthrough;
100122d50e9aSMauro Carvalho Chehab default: /* just to shut up a gcc warning */
10026168309aSMauro Carvalho Chehab ent->function = MEDIA_ENT_F_CONN_RF;
10036168309aSMauro Carvalho Chehab break;
10046168309aSMauro Carvalho Chehab }
10056168309aSMauro Carvalho Chehab
10066168309aSMauro Carvalho Chehab ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
10076168309aSMauro Carvalho Chehab if (ret < 0)
10086168309aSMauro Carvalho Chehab pr_err("failed to initialize input pad[%d]!\n", i);
10096168309aSMauro Carvalho Chehab
10106168309aSMauro Carvalho Chehab ret = media_device_register_entity(dev->media_dev, ent);
10116168309aSMauro Carvalho Chehab if (ret < 0)
10126168309aSMauro Carvalho Chehab pr_err("failed to register input entity %d!\n", i);
10136168309aSMauro Carvalho Chehab }
10146168309aSMauro Carvalho Chehab #endif
10156168309aSMauro Carvalho Chehab }
10166168309aSMauro Carvalho Chehab
cx231xx_enum_input(struct file * file,void * priv,struct v4l2_input * i)1017b86d1544SHans Verkuil int cx231xx_enum_input(struct file *file, void *priv,
10180c0d06caSMauro Carvalho Chehab struct v4l2_input *i)
10190c0d06caSMauro Carvalho Chehab {
10207c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
10210c0d06caSMauro Carvalho Chehab u32 gen_stat;
1022e54560d9SAndrzej Hajda unsigned int n;
1023e54560d9SAndrzej Hajda int ret;
10240c0d06caSMauro Carvalho Chehab
10250c0d06caSMauro Carvalho Chehab n = i->index;
10260c0d06caSMauro Carvalho Chehab if (n >= MAX_CX231XX_INPUT)
10270c0d06caSMauro Carvalho Chehab return -EINVAL;
10280c0d06caSMauro Carvalho Chehab if (0 == INPUT(n)->type)
10290c0d06caSMauro Carvalho Chehab return -EINVAL;
10300c0d06caSMauro Carvalho Chehab
10310c0d06caSMauro Carvalho Chehab i->index = n;
10320c0d06caSMauro Carvalho Chehab i->type = V4L2_INPUT_TYPE_CAMERA;
10330c0d06caSMauro Carvalho Chehab
1034cc1e6315SMauro Carvalho Chehab strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name));
10350c0d06caSMauro Carvalho Chehab
10360c0d06caSMauro Carvalho Chehab if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
10370c0d06caSMauro Carvalho Chehab (CX231XX_VMUX_CABLE == INPUT(n)->type))
10380c0d06caSMauro Carvalho Chehab i->type = V4L2_INPUT_TYPE_TUNER;
10390c0d06caSMauro Carvalho Chehab
104060acf187SHans Verkuil i->std = dev->vdev.tvnorms;
10410c0d06caSMauro Carvalho Chehab
10420c0d06caSMauro Carvalho Chehab /* If they are asking about the active input, read signal status */
10430c0d06caSMauro Carvalho Chehab if (n == dev->video_input) {
10440c0d06caSMauro Carvalho Chehab ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
10450c0d06caSMauro Carvalho Chehab GEN_STAT, 2, &gen_stat, 4);
10460c0d06caSMauro Carvalho Chehab if (ret > 0) {
10470c0d06caSMauro Carvalho Chehab if ((gen_stat & FLD_VPRES) == 0x00)
10480c0d06caSMauro Carvalho Chehab i->status |= V4L2_IN_ST_NO_SIGNAL;
10490c0d06caSMauro Carvalho Chehab if ((gen_stat & FLD_HLOCK) == 0x00)
10500c0d06caSMauro Carvalho Chehab i->status |= V4L2_IN_ST_NO_H_LOCK;
10510c0d06caSMauro Carvalho Chehab }
10520c0d06caSMauro Carvalho Chehab }
10530c0d06caSMauro Carvalho Chehab
10540c0d06caSMauro Carvalho Chehab return 0;
10550c0d06caSMauro Carvalho Chehab }
10560c0d06caSMauro Carvalho Chehab
cx231xx_g_input(struct file * file,void * priv,unsigned int * i)1057b86d1544SHans Verkuil int cx231xx_g_input(struct file *file, void *priv, unsigned int *i)
10580c0d06caSMauro Carvalho Chehab {
10597c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
10600c0d06caSMauro Carvalho Chehab
10610c0d06caSMauro Carvalho Chehab *i = dev->video_input;
10620c0d06caSMauro Carvalho Chehab
10630c0d06caSMauro Carvalho Chehab return 0;
10640c0d06caSMauro Carvalho Chehab }
10650c0d06caSMauro Carvalho Chehab
cx231xx_s_input(struct file * file,void * priv,unsigned int i)1066b86d1544SHans Verkuil int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
10670c0d06caSMauro Carvalho Chehab {
10687c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
10690c0d06caSMauro Carvalho Chehab
10700c0d06caSMauro Carvalho Chehab dev->mode_tv = 0;
10710c0d06caSMauro Carvalho Chehab
10720c0d06caSMauro Carvalho Chehab if (i >= MAX_CX231XX_INPUT)
10730c0d06caSMauro Carvalho Chehab return -EINVAL;
10740c0d06caSMauro Carvalho Chehab if (0 == INPUT(i)->type)
10750c0d06caSMauro Carvalho Chehab return -EINVAL;
10760c0d06caSMauro Carvalho Chehab
10770c0d06caSMauro Carvalho Chehab video_mux(dev, i);
10780c0d06caSMauro Carvalho Chehab
10790c0d06caSMauro Carvalho Chehab if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
10800c0d06caSMauro Carvalho Chehab INPUT(i)->type == CX231XX_VMUX_CABLE) {
10810c0d06caSMauro Carvalho Chehab /* There's a tuner, so reset the standard and put it on the
10820c0d06caSMauro Carvalho Chehab last known frequency (since it was probably powered down
10830c0d06caSMauro Carvalho Chehab until now */
10848774bed9SLaurent Pinchart call_all(dev, video, s_std, dev->norm);
10850c0d06caSMauro Carvalho Chehab }
10860c0d06caSMauro Carvalho Chehab
10870c0d06caSMauro Carvalho Chehab return 0;
10880c0d06caSMauro Carvalho Chehab }
10890c0d06caSMauro Carvalho Chehab
cx231xx_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)1090b86d1544SHans Verkuil int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
10910c0d06caSMauro Carvalho Chehab {
10927c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
10930c0d06caSMauro Carvalho Chehab
10940c0d06caSMauro Carvalho Chehab if (0 != t->index)
10950c0d06caSMauro Carvalho Chehab return -EINVAL;
10960c0d06caSMauro Carvalho Chehab
1097cc1e6315SMauro Carvalho Chehab strscpy(t->name, "Tuner", sizeof(t->name));
10980c0d06caSMauro Carvalho Chehab
10990c0d06caSMauro Carvalho Chehab t->type = V4L2_TUNER_ANALOG_TV;
11000c0d06caSMauro Carvalho Chehab t->capability = V4L2_TUNER_CAP_NORM;
11010c0d06caSMauro Carvalho Chehab t->rangehigh = 0xffffffffUL;
11020c0d06caSMauro Carvalho Chehab t->signal = 0xffff; /* LOCKED */
1103b251f957SHans Verkuil call_all(dev, tuner, g_tuner, t);
11040c0d06caSMauro Carvalho Chehab
11050c0d06caSMauro Carvalho Chehab return 0;
11060c0d06caSMauro Carvalho Chehab }
11070c0d06caSMauro Carvalho Chehab
cx231xx_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)11082f73c7c5SHans Verkuil int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
11090c0d06caSMauro Carvalho Chehab {
11100c0d06caSMauro Carvalho Chehab if (0 != t->index)
11110c0d06caSMauro Carvalho Chehab return -EINVAL;
11120c0d06caSMauro Carvalho Chehab return 0;
11130c0d06caSMauro Carvalho Chehab }
11140c0d06caSMauro Carvalho Chehab
cx231xx_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)1115b86d1544SHans Verkuil int cx231xx_g_frequency(struct file *file, void *priv,
11160c0d06caSMauro Carvalho Chehab struct v4l2_frequency *f)
11170c0d06caSMauro Carvalho Chehab {
11187c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
11190c0d06caSMauro Carvalho Chehab
1120b251f957SHans Verkuil if (f->tuner)
1121b251f957SHans Verkuil return -EINVAL;
1122b251f957SHans Verkuil
11230c0d06caSMauro Carvalho Chehab f->frequency = dev->ctl_freq;
11240c0d06caSMauro Carvalho Chehab
11250c0d06caSMauro Carvalho Chehab return 0;
11260c0d06caSMauro Carvalho Chehab }
11270c0d06caSMauro Carvalho Chehab
cx231xx_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)1128b86d1544SHans Verkuil int cx231xx_s_frequency(struct file *file, void *priv,
1129b530a447SHans Verkuil const struct v4l2_frequency *f)
11300c0d06caSMauro Carvalho Chehab {
11317c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
1132b530a447SHans Verkuil struct v4l2_frequency new_freq = *f;
11333c1ccbadSBrad Love int rc, need_if_freq = 0;
11340c0d06caSMauro Carvalho Chehab u32 if_frequency = 5400000;
11350c0d06caSMauro Carvalho Chehab
1136336fea92SMauro Carvalho Chehab dev_dbg(dev->dev,
1137b7085c08SMauro Carvalho Chehab "Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
11380c0d06caSMauro Carvalho Chehab f->frequency, f->type);
11390c0d06caSMauro Carvalho Chehab
11400c0d06caSMauro Carvalho Chehab if (0 != f->tuner)
11410c0d06caSMauro Carvalho Chehab return -EINVAL;
11420c0d06caSMauro Carvalho Chehab
11430c0d06caSMauro Carvalho Chehab /* set pre channel change settings in DIF first */
11440c0d06caSMauro Carvalho Chehab rc = cx231xx_tuner_pre_channel_change(dev);
11450c0d06caSMauro Carvalho Chehab
11463c1ccbadSBrad Love switch (dev->model) { /* i2c device tuners */
11473c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
11483c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_935C:
11493c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_955Q:
11503c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_975:
11513c1ccbadSBrad Love case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
11523c1ccbadSBrad Love if (dev->cx231xx_set_analog_freq)
11533c1ccbadSBrad Love dev->cx231xx_set_analog_freq(dev, f->frequency);
11543c1ccbadSBrad Love dev->ctl_freq = f->frequency;
11553c1ccbadSBrad Love need_if_freq = 1;
11563c1ccbadSBrad Love break;
11573c1ccbadSBrad Love default:
11580c0d06caSMauro Carvalho Chehab call_all(dev, tuner, s_frequency, f);
1159b530a447SHans Verkuil call_all(dev, tuner, g_frequency, &new_freq);
1160b530a447SHans Verkuil dev->ctl_freq = new_freq.frequency;
11613c1ccbadSBrad Love break;
11623c1ccbadSBrad Love }
11633c1ccbadSBrad Love
11643c1ccbadSBrad Love pr_debug("%s() %u : %u\n", __func__, f->frequency, dev->ctl_freq);
11650c0d06caSMauro Carvalho Chehab
11660c0d06caSMauro Carvalho Chehab /* set post channel change settings in DIF first */
11670c0d06caSMauro Carvalho Chehab rc = cx231xx_tuner_post_channel_change(dev);
11680c0d06caSMauro Carvalho Chehab
11693c1ccbadSBrad Love if (need_if_freq || dev->tuner_type == TUNER_NXP_TDA18271) {
11700c0d06caSMauro Carvalho Chehab if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
11710c0d06caSMauro Carvalho Chehab if_frequency = 5400000; /*5.4MHz */
11720c0d06caSMauro Carvalho Chehab else if (dev->norm & V4L2_STD_B)
11730c0d06caSMauro Carvalho Chehab if_frequency = 6000000; /*6.0MHz */
11740c0d06caSMauro Carvalho Chehab else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK))
11750c0d06caSMauro Carvalho Chehab if_frequency = 6900000; /*6.9MHz */
11760c0d06caSMauro Carvalho Chehab else if (dev->norm & V4L2_STD_GH)
11770c0d06caSMauro Carvalho Chehab if_frequency = 7100000; /*7.1MHz */
11780c0d06caSMauro Carvalho Chehab else if (dev->norm & V4L2_STD_PAL_I)
11790c0d06caSMauro Carvalho Chehab if_frequency = 7250000; /*7.25MHz */
11800c0d06caSMauro Carvalho Chehab else if (dev->norm & V4L2_STD_SECAM_L)
11810c0d06caSMauro Carvalho Chehab if_frequency = 6900000; /*6.9MHz */
11820c0d06caSMauro Carvalho Chehab else if (dev->norm & V4L2_STD_SECAM_LC)
11830c0d06caSMauro Carvalho Chehab if_frequency = 1250000; /*1.25MHz */
11840c0d06caSMauro Carvalho Chehab
1185336fea92SMauro Carvalho Chehab dev_dbg(dev->dev,
1186b7085c08SMauro Carvalho Chehab "if_frequency is set to %d\n", if_frequency);
11870c0d06caSMauro Carvalho Chehab cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
11880c0d06caSMauro Carvalho Chehab
11890c0d06caSMauro Carvalho Chehab update_HH_register_after_set_DIF(dev);
11900c0d06caSMauro Carvalho Chehab }
11910c0d06caSMauro Carvalho Chehab
1192336fea92SMauro Carvalho Chehab dev_dbg(dev->dev, "Set New FREQUENCY to %d\n", f->frequency);
11930c0d06caSMauro Carvalho Chehab
11940c0d06caSMauro Carvalho Chehab return rc;
11950c0d06caSMauro Carvalho Chehab }
11960c0d06caSMauro Carvalho Chehab
119708fe9f7dSHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG
119808fe9f7dSHans Verkuil
cx231xx_g_chip_info(struct file * file,void * fh,struct v4l2_dbg_chip_info * chip)119908fe9f7dSHans Verkuil int cx231xx_g_chip_info(struct file *file, void *fh,
120008fe9f7dSHans Verkuil struct v4l2_dbg_chip_info *chip)
1201fddd14c8SHans Verkuil {
120208fe9f7dSHans Verkuil switch (chip->match.addr) {
120308fe9f7dSHans Verkuil case 0: /* Cx231xx - internal registers */
120408fe9f7dSHans Verkuil return 0;
120508fe9f7dSHans Verkuil case 1: /* AFE - read byte */
1206c0decac1SMauro Carvalho Chehab strscpy(chip->name, "AFE (byte)", sizeof(chip->name));
120708fe9f7dSHans Verkuil return 0;
120808fe9f7dSHans Verkuil case 2: /* Video Block - read byte */
1209c0decac1SMauro Carvalho Chehab strscpy(chip->name, "Video (byte)", sizeof(chip->name));
121008fe9f7dSHans Verkuil return 0;
121108fe9f7dSHans Verkuil case 3: /* I2S block - read byte */
1212c0decac1SMauro Carvalho Chehab strscpy(chip->name, "I2S (byte)", sizeof(chip->name));
121308fe9f7dSHans Verkuil return 0;
121408fe9f7dSHans Verkuil case 4: /* AFE - read dword */
1215c0decac1SMauro Carvalho Chehab strscpy(chip->name, "AFE (dword)", sizeof(chip->name));
121608fe9f7dSHans Verkuil return 0;
121708fe9f7dSHans Verkuil case 5: /* Video Block - read dword */
1218c0decac1SMauro Carvalho Chehab strscpy(chip->name, "Video (dword)", sizeof(chip->name));
121908fe9f7dSHans Verkuil return 0;
122008fe9f7dSHans Verkuil case 6: /* I2S Block - read dword */
1221c0decac1SMauro Carvalho Chehab strscpy(chip->name, "I2S (dword)", sizeof(chip->name));
1222fddd14c8SHans Verkuil return 0;
1223fddd14c8SHans Verkuil }
1224fddd14c8SHans Verkuil return -EINVAL;
1225fddd14c8SHans Verkuil }
1226fddd14c8SHans Verkuil
cx231xx_g_register(struct file * file,void * priv,struct v4l2_dbg_register * reg)1227b86d1544SHans Verkuil int cx231xx_g_register(struct file *file, void *priv,
12280c0d06caSMauro Carvalho Chehab struct v4l2_dbg_register *reg)
12290c0d06caSMauro Carvalho Chehab {
12307c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
123108fe9f7dSHans Verkuil int ret;
12320c0d06caSMauro Carvalho Chehab u8 value[4] = { 0, 0, 0, 0 };
12330c0d06caSMauro Carvalho Chehab u32 data = 0;
12340c0d06caSMauro Carvalho Chehab
12350c0d06caSMauro Carvalho Chehab switch (reg->match.addr) {
12360c0d06caSMauro Carvalho Chehab case 0: /* Cx231xx - internal registers */
12370c0d06caSMauro Carvalho Chehab ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
12380c0d06caSMauro Carvalho Chehab (u16)reg->reg, value, 4);
12390c0d06caSMauro Carvalho Chehab reg->val = value[0] | value[1] << 8 |
124032ae5920SColin Ian King value[2] << 16 | (u32)value[3] << 24;
124104ae4cf2SHans Verkuil reg->size = 4;
12420c0d06caSMauro Carvalho Chehab break;
12430c0d06caSMauro Carvalho Chehab case 1: /* AFE - read byte */
12440c0d06caSMauro Carvalho Chehab ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
12450c0d06caSMauro Carvalho Chehab (u16)reg->reg, 2, &data, 1);
124608fe9f7dSHans Verkuil reg->val = data;
124704ae4cf2SHans Verkuil reg->size = 1;
12480c0d06caSMauro Carvalho Chehab break;
12490c0d06caSMauro Carvalho Chehab case 2: /* Video Block - read byte */
12500c0d06caSMauro Carvalho Chehab ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
12510c0d06caSMauro Carvalho Chehab (u16)reg->reg, 2, &data, 1);
125208fe9f7dSHans Verkuil reg->val = data;
125304ae4cf2SHans Verkuil reg->size = 1;
12540c0d06caSMauro Carvalho Chehab break;
12550c0d06caSMauro Carvalho Chehab case 3: /* I2S block - read byte */
125608fe9f7dSHans Verkuil ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
125708fe9f7dSHans Verkuil (u16)reg->reg, 1, &data, 1);
125808fe9f7dSHans Verkuil reg->val = data;
125904ae4cf2SHans Verkuil reg->size = 1;
12600c0d06caSMauro Carvalho Chehab break;
126108fe9f7dSHans Verkuil case 4: /* AFE - read dword */
126208fe9f7dSHans Verkuil ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
126308fe9f7dSHans Verkuil (u16)reg->reg, 2, &data, 4);
126408fe9f7dSHans Verkuil reg->val = data;
126504ae4cf2SHans Verkuil reg->size = 4;
126608fe9f7dSHans Verkuil break;
126708fe9f7dSHans Verkuil case 5: /* Video Block - read dword */
126808fe9f7dSHans Verkuil ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
126908fe9f7dSHans Verkuil (u16)reg->reg, 2, &data, 4);
127008fe9f7dSHans Verkuil reg->val = data;
127104ae4cf2SHans Verkuil reg->size = 4;
127208fe9f7dSHans Verkuil break;
127308fe9f7dSHans Verkuil case 6: /* I2S Block - read dword */
127408fe9f7dSHans Verkuil ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
12750c0d06caSMauro Carvalho Chehab (u16)reg->reg, 1, &data, 4);
127608fe9f7dSHans Verkuil reg->val = data;
127704ae4cf2SHans Verkuil reg->size = 4;
12780c0d06caSMauro Carvalho Chehab break;
12790c0d06caSMauro Carvalho Chehab default:
12800c0d06caSMauro Carvalho Chehab return -EINVAL;
12810c0d06caSMauro Carvalho Chehab }
128208fe9f7dSHans Verkuil return ret < 0 ? ret : 0;
12830c0d06caSMauro Carvalho Chehab }
12840c0d06caSMauro Carvalho Chehab
cx231xx_s_register(struct file * file,void * priv,const struct v4l2_dbg_register * reg)1285b86d1544SHans Verkuil int cx231xx_s_register(struct file *file, void *priv,
1286977ba3b1SHans Verkuil const struct v4l2_dbg_register *reg)
12870c0d06caSMauro Carvalho Chehab {
12887c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
128908fe9f7dSHans Verkuil int ret;
12900c0d06caSMauro Carvalho Chehab u8 data[4] = { 0, 0, 0, 0 };
12910c0d06caSMauro Carvalho Chehab
12920c0d06caSMauro Carvalho Chehab switch (reg->match.addr) {
12930c0d06caSMauro Carvalho Chehab case 0: /* cx231xx internal registers */
129408fe9f7dSHans Verkuil data[0] = (u8) reg->val;
129508fe9f7dSHans Verkuil data[1] = (u8) (reg->val >> 8);
129608fe9f7dSHans Verkuil data[2] = (u8) (reg->val >> 16);
129708fe9f7dSHans Verkuil data[3] = (u8) (reg->val >> 24);
129808fe9f7dSHans Verkuil ret = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
129908fe9f7dSHans Verkuil (u16)reg->reg, data, 4);
13000c0d06caSMauro Carvalho Chehab break;
130108fe9f7dSHans Verkuil case 1: /* AFE - write byte */
130208fe9f7dSHans Verkuil ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
130308fe9f7dSHans Verkuil (u16)reg->reg, 2, reg->val, 1);
13040c0d06caSMauro Carvalho Chehab break;
130508fe9f7dSHans Verkuil case 2: /* Video Block - write byte */
130608fe9f7dSHans Verkuil ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
130708fe9f7dSHans Verkuil (u16)reg->reg, 2, reg->val, 1);
13080c0d06caSMauro Carvalho Chehab break;
130908fe9f7dSHans Verkuil case 3: /* I2S block - write byte */
131008fe9f7dSHans Verkuil ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
131108fe9f7dSHans Verkuil (u16)reg->reg, 1, reg->val, 1);
13120c0d06caSMauro Carvalho Chehab break;
131308fe9f7dSHans Verkuil case 4: /* AFE - write dword */
131408fe9f7dSHans Verkuil ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
131508fe9f7dSHans Verkuil (u16)reg->reg, 2, reg->val, 4);
13160c0d06caSMauro Carvalho Chehab break;
131708fe9f7dSHans Verkuil case 5: /* Video Block - write dword */
131808fe9f7dSHans Verkuil ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
131908fe9f7dSHans Verkuil (u16)reg->reg, 2, reg->val, 4);
13200c0d06caSMauro Carvalho Chehab break;
132108fe9f7dSHans Verkuil case 6: /* I2S block - write dword */
132208fe9f7dSHans Verkuil ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
132308fe9f7dSHans Verkuil (u16)reg->reg, 1, reg->val, 4);
13240c0d06caSMauro Carvalho Chehab break;
132508fe9f7dSHans Verkuil default:
132608fe9f7dSHans Verkuil return -EINVAL;
13270c0d06caSMauro Carvalho Chehab }
13280c0d06caSMauro Carvalho Chehab return ret < 0 ? ret : 0;
13290c0d06caSMauro Carvalho Chehab }
13300c0d06caSMauro Carvalho Chehab #endif
13310c0d06caSMauro Carvalho Chehab
vidioc_g_pixelaspect(struct file * file,void * priv,int type,struct v4l2_fract * f)13325200ab6aSHans Verkuil static int vidioc_g_pixelaspect(struct file *file, void *priv,
13335200ab6aSHans Verkuil int type, struct v4l2_fract *f)
13340c0d06caSMauro Carvalho Chehab {
13357c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
1336e25cb200SHans Verkuil bool is_50hz = dev->norm & V4L2_STD_625_50;
13370c0d06caSMauro Carvalho Chehab
13385200ab6aSHans Verkuil if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
13390c0d06caSMauro Carvalho Chehab return -EINVAL;
13400c0d06caSMauro Carvalho Chehab
13415200ab6aSHans Verkuil f->numerator = is_50hz ? 54 : 11;
13425200ab6aSHans Verkuil f->denominator = is_50hz ? 59 : 10;
13430c0d06caSMauro Carvalho Chehab
13440c0d06caSMauro Carvalho Chehab return 0;
13450c0d06caSMauro Carvalho Chehab }
13460c0d06caSMauro Carvalho Chehab
vidioc_g_selection(struct file * file,void * priv,struct v4l2_selection * s)1347ee10dc36SHans Verkuil static int vidioc_g_selection(struct file *file, void *priv,
1348ee10dc36SHans Verkuil struct v4l2_selection *s)
1349ee10dc36SHans Verkuil {
13507c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
1351ee10dc36SHans Verkuil
1352ee10dc36SHans Verkuil if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1353ee10dc36SHans Verkuil return -EINVAL;
1354ee10dc36SHans Verkuil
1355ee10dc36SHans Verkuil switch (s->target) {
1356ee10dc36SHans Verkuil case V4L2_SEL_TGT_CROP_BOUNDS:
1357ee10dc36SHans Verkuil case V4L2_SEL_TGT_CROP_DEFAULT:
1358ee10dc36SHans Verkuil s->r.left = 0;
1359ee10dc36SHans Verkuil s->r.top = 0;
1360ee10dc36SHans Verkuil s->r.width = dev->width;
1361ee10dc36SHans Verkuil s->r.height = dev->height;
1362ee10dc36SHans Verkuil break;
1363ee10dc36SHans Verkuil default:
1364ee10dc36SHans Verkuil return -EINVAL;
1365ee10dc36SHans Verkuil }
1366ee10dc36SHans Verkuil return 0;
1367ee10dc36SHans Verkuil }
1368ee10dc36SHans Verkuil
cx231xx_querycap(struct file * file,void * priv,struct v4l2_capability * cap)1369bc08734cSHans Verkuil int cx231xx_querycap(struct file *file, void *priv,
13700c0d06caSMauro Carvalho Chehab struct v4l2_capability *cap)
13710c0d06caSMauro Carvalho Chehab {
13727c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
13730c0d06caSMauro Carvalho Chehab
1374c0decac1SMauro Carvalho Chehab strscpy(cap->driver, "cx231xx", sizeof(cap->driver));
1375c0decac1SMauro Carvalho Chehab strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
13760c0d06caSMauro Carvalho Chehab usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
13778c3854d0SHans Verkuil cap->capabilities = V4L2_CAP_READWRITE |
13784bc837d4SHans Verkuil V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
1379530e01e7SHans Verkuil V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
138060acf187SHans Verkuil if (video_is_registered(&dev->radio_dev))
1381530e01e7SHans Verkuil cap->capabilities |= V4L2_CAP_RADIO;
13823c1ccbadSBrad Love
13833c1ccbadSBrad Love switch (dev->model) {
13843c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
13853c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_935C:
13863c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_955Q:
13873c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_975:
13883c1ccbadSBrad Love case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
13893c1ccbadSBrad Love cap->capabilities |= V4L2_CAP_TUNER;
13903c1ccbadSBrad Love break;
13913c1ccbadSBrad Love default:
13928c3854d0SHans Verkuil if (dev->tuner_type != TUNER_ABSENT)
13938c3854d0SHans Verkuil cap->capabilities |= V4L2_CAP_TUNER;
13943c1ccbadSBrad Love break;
13953c1ccbadSBrad Love }
13960c0d06caSMauro Carvalho Chehab return 0;
13970c0d06caSMauro Carvalho Chehab }
13980c0d06caSMauro Carvalho Chehab
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)13990c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
14000c0d06caSMauro Carvalho Chehab struct v4l2_fmtdesc *f)
14010c0d06caSMauro Carvalho Chehab {
14020c0d06caSMauro Carvalho Chehab if (unlikely(f->index >= ARRAY_SIZE(format)))
14030c0d06caSMauro Carvalho Chehab return -EINVAL;
14040c0d06caSMauro Carvalho Chehab
14050c0d06caSMauro Carvalho Chehab f->pixelformat = format[f->index].fourcc;
14060c0d06caSMauro Carvalho Chehab
14070c0d06caSMauro Carvalho Chehab return 0;
14080c0d06caSMauro Carvalho Chehab }
14090c0d06caSMauro Carvalho Chehab
14100c0d06caSMauro Carvalho Chehab /* RAW VBI ioctls */
14110c0d06caSMauro Carvalho Chehab
vidioc_g_fmt_vbi_cap(struct file * file,void * priv,struct v4l2_format * f)14120c0d06caSMauro Carvalho Chehab static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
14130c0d06caSMauro Carvalho Chehab struct v4l2_format *f)
14140c0d06caSMauro Carvalho Chehab {
14157c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
14166264722cSHans Verkuil
14170c0d06caSMauro Carvalho Chehab f->fmt.vbi.sampling_rate = 6750000 * 4;
14180c0d06caSMauro Carvalho Chehab f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
14190c0d06caSMauro Carvalho Chehab f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
14200c0d06caSMauro Carvalho Chehab f->fmt.vbi.offset = 0;
14210c0d06caSMauro Carvalho Chehab f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
14220c0d06caSMauro Carvalho Chehab PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
14230c0d06caSMauro Carvalho Chehab f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
14240c0d06caSMauro Carvalho Chehab PAL_VBI_LINES : NTSC_VBI_LINES;
14250c0d06caSMauro Carvalho Chehab f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
14260c0d06caSMauro Carvalho Chehab PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
14270c0d06caSMauro Carvalho Chehab f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
14286264722cSHans Verkuil memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
14290c0d06caSMauro Carvalho Chehab
14300c0d06caSMauro Carvalho Chehab return 0;
14310c0d06caSMauro Carvalho Chehab
14320c0d06caSMauro Carvalho Chehab }
14330c0d06caSMauro Carvalho Chehab
vidioc_try_fmt_vbi_cap(struct file * file,void * priv,struct v4l2_format * f)14340c0d06caSMauro Carvalho Chehab static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
14350c0d06caSMauro Carvalho Chehab struct v4l2_format *f)
14360c0d06caSMauro Carvalho Chehab {
14377c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
14380c0d06caSMauro Carvalho Chehab
14390c0d06caSMauro Carvalho Chehab f->fmt.vbi.sampling_rate = 6750000 * 4;
14400c0d06caSMauro Carvalho Chehab f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
14410c0d06caSMauro Carvalho Chehab f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
14420c0d06caSMauro Carvalho Chehab f->fmt.vbi.offset = 0;
14430c0d06caSMauro Carvalho Chehab f->fmt.vbi.flags = 0;
14440c0d06caSMauro Carvalho Chehab f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
14450c0d06caSMauro Carvalho Chehab PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
14460c0d06caSMauro Carvalho Chehab f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
14470c0d06caSMauro Carvalho Chehab PAL_VBI_LINES : NTSC_VBI_LINES;
14480c0d06caSMauro Carvalho Chehab f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
14490c0d06caSMauro Carvalho Chehab PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
14500c0d06caSMauro Carvalho Chehab f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
14516264722cSHans Verkuil memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
14520c0d06caSMauro Carvalho Chehab
14530c0d06caSMauro Carvalho Chehab return 0;
14540c0d06caSMauro Carvalho Chehab
14550c0d06caSMauro Carvalho Chehab }
14560c0d06caSMauro Carvalho Chehab
vidioc_s_fmt_vbi_cap(struct file * file,void * priv,struct v4l2_format * f)14576264722cSHans Verkuil static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
14586264722cSHans Verkuil struct v4l2_format *f)
14596264722cSHans Verkuil {
14606264722cSHans Verkuil return vidioc_try_fmt_vbi_cap(file, priv, f);
14616264722cSHans Verkuil }
14626264722cSHans Verkuil
14630c0d06caSMauro Carvalho Chehab /* ----------------------------------------------------------- */
14640c0d06caSMauro Carvalho Chehab /* RADIO ESPECIFIC IOCTLS */
14650c0d06caSMauro Carvalho Chehab /* ----------------------------------------------------------- */
14660c0d06caSMauro Carvalho Chehab
radio_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)14670c0d06caSMauro Carvalho Chehab static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
14680c0d06caSMauro Carvalho Chehab {
14697c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
14700c0d06caSMauro Carvalho Chehab
1471530e01e7SHans Verkuil if (t->index)
14720c0d06caSMauro Carvalho Chehab return -EINVAL;
14730c0d06caSMauro Carvalho Chehab
1474cc1e6315SMauro Carvalho Chehab strscpy(t->name, "Radio", sizeof(t->name));
14750c0d06caSMauro Carvalho Chehab
1476530e01e7SHans Verkuil call_all(dev, tuner, g_tuner, t);
14770c0d06caSMauro Carvalho Chehab
14780c0d06caSMauro Carvalho Chehab return 0;
14790c0d06caSMauro Carvalho Chehab }
radio_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)14802f73c7c5SHans Verkuil static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
14810c0d06caSMauro Carvalho Chehab {
14827c617138SHans Verkuil struct cx231xx *dev = video_drvdata(file);
14830c0d06caSMauro Carvalho Chehab
1484b86d1544SHans Verkuil if (t->index)
14850c0d06caSMauro Carvalho Chehab return -EINVAL;
14860c0d06caSMauro Carvalho Chehab
14870c0d06caSMauro Carvalho Chehab call_all(dev, tuner, s_tuner, t);
14880c0d06caSMauro Carvalho Chehab
14890c0d06caSMauro Carvalho Chehab return 0;
14900c0d06caSMauro Carvalho Chehab }
14910c0d06caSMauro Carvalho Chehab
14920c0d06caSMauro Carvalho Chehab /*
14930c0d06caSMauro Carvalho Chehab * cx231xx_v4l2_open()
14940c0d06caSMauro Carvalho Chehab * inits the device and starts isoc transfer
14950c0d06caSMauro Carvalho Chehab */
cx231xx_v4l2_open(struct file * filp)14960c0d06caSMauro Carvalho Chehab static int cx231xx_v4l2_open(struct file *filp)
14970c0d06caSMauro Carvalho Chehab {
14980c0d06caSMauro Carvalho Chehab struct video_device *vdev = video_devdata(filp);
14990c0d06caSMauro Carvalho Chehab struct cx231xx *dev = video_drvdata(filp);
15007c617138SHans Verkuil int ret;
15010c0d06caSMauro Carvalho Chehab
15027c617138SHans Verkuil if (mutex_lock_interruptible(&dev->lock))
15030c0d06caSMauro Carvalho Chehab return -ERESTARTSYS;
15040c0d06caSMauro Carvalho Chehab
15057c617138SHans Verkuil ret = v4l2_fh_open(filp);
15067c617138SHans Verkuil if (ret) {
15077c617138SHans Verkuil mutex_unlock(&dev->lock);
15087c617138SHans Verkuil return ret;
15097c617138SHans Verkuil }
15107c617138SHans Verkuil
15117c617138SHans Verkuil if (dev->users++ == 0) {
15120c0d06caSMauro Carvalho Chehab /* Power up in Analog TV mode */
15130c0d06caSMauro Carvalho Chehab if (dev->board.external_av)
15140c0d06caSMauro Carvalho Chehab cx231xx_set_power_mode(dev,
15150c0d06caSMauro Carvalho Chehab POLARIS_AVMODE_ENXTERNAL_AV);
15160c0d06caSMauro Carvalho Chehab else
15170c0d06caSMauro Carvalho Chehab cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
15180c0d06caSMauro Carvalho Chehab
15190c0d06caSMauro Carvalho Chehab /* set video alternate setting */
15200c0d06caSMauro Carvalho Chehab cx231xx_set_video_alternate(dev);
15210c0d06caSMauro Carvalho Chehab
15220c0d06caSMauro Carvalho Chehab /* Needed, since GPIO might have disabled power of
15230c0d06caSMauro Carvalho Chehab some i2c device */
15240c0d06caSMauro Carvalho Chehab cx231xx_config_i2c(dev);
15250c0d06caSMauro Carvalho Chehab
15260c0d06caSMauro Carvalho Chehab /* device needs to be initialized before isoc transfer */
15270c0d06caSMauro Carvalho Chehab dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
15280c0d06caSMauro Carvalho Chehab }
15297c617138SHans Verkuil
15307c617138SHans Verkuil if (vdev->vfl_type == VFL_TYPE_RADIO) {
15310c0d06caSMauro Carvalho Chehab cx231xx_videodbg("video_open: setting radio device\n");
15320c0d06caSMauro Carvalho Chehab
15330c0d06caSMauro Carvalho Chehab /* cx231xx_start_radio(dev); */
15340c0d06caSMauro Carvalho Chehab
15350c0d06caSMauro Carvalho Chehab call_all(dev, tuner, s_radio);
15360c0d06caSMauro Carvalho Chehab }
15377c617138SHans Verkuil if (vdev->vfl_type == VFL_TYPE_VBI) {
15380c0d06caSMauro Carvalho Chehab /* Set the required alternate setting VBI interface works in
15390c0d06caSMauro Carvalho Chehab Bulk mode only */
15400c0d06caSMauro Carvalho Chehab cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
15410c0d06caSMauro Carvalho Chehab }
15420c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
15434df16f70SPeter Senna Tschudin return 0;
15440c0d06caSMauro Carvalho Chehab }
15450c0d06caSMauro Carvalho Chehab
15460c0d06caSMauro Carvalho Chehab /*
15470c0d06caSMauro Carvalho Chehab * cx231xx_realease_resources()
15480c0d06caSMauro Carvalho Chehab * unregisters the v4l2,i2c and usb devices
15496b338c72SGeert Uytterhoeven * called when the device gets disconnected or at module unload
15500c0d06caSMauro Carvalho Chehab */
cx231xx_release_analog_resources(struct cx231xx * dev)15510c0d06caSMauro Carvalho Chehab void cx231xx_release_analog_resources(struct cx231xx *dev)
15520c0d06caSMauro Carvalho Chehab {
15530c0d06caSMauro Carvalho Chehab
15540c0d06caSMauro Carvalho Chehab /*FIXME: I2C IR should be disconnected */
15550c0d06caSMauro Carvalho Chehab
155660acf187SHans Verkuil if (video_is_registered(&dev->radio_dev))
155760acf187SHans Verkuil video_unregister_device(&dev->radio_dev);
155860acf187SHans Verkuil if (video_is_registered(&dev->vbi_dev)) {
1559336fea92SMauro Carvalho Chehab dev_info(dev->dev, "V4L2 device %s deregistered\n",
156060acf187SHans Verkuil video_device_node_name(&dev->vbi_dev));
156160acf187SHans Verkuil video_unregister_device(&dev->vbi_dev);
15620c0d06caSMauro Carvalho Chehab }
156360acf187SHans Verkuil if (video_is_registered(&dev->vdev)) {
1564336fea92SMauro Carvalho Chehab dev_info(dev->dev, "V4L2 device %s deregistered\n",
156560acf187SHans Verkuil video_device_node_name(&dev->vdev));
15660c0d06caSMauro Carvalho Chehab
15670c0d06caSMauro Carvalho Chehab if (dev->board.has_417)
15680c0d06caSMauro Carvalho Chehab cx231xx_417_unregister(dev);
15690c0d06caSMauro Carvalho Chehab
157060acf187SHans Verkuil video_unregister_device(&dev->vdev);
15710c0d06caSMauro Carvalho Chehab }
1572d2370f8eSHans Verkuil v4l2_ctrl_handler_free(&dev->ctrl_handler);
1573d2370f8eSHans Verkuil v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
15740c0d06caSMauro Carvalho Chehab }
15750c0d06caSMauro Carvalho Chehab
15760c0d06caSMauro Carvalho Chehab /*
15770c0d06caSMauro Carvalho Chehab * cx231xx_close()
15780c0d06caSMauro Carvalho Chehab * stops streaming and deallocates all resources allocated by the v4l2
15790c0d06caSMauro Carvalho Chehab * calls and ioctls
15800c0d06caSMauro Carvalho Chehab */
cx231xx_close(struct file * filp)15810c0d06caSMauro Carvalho Chehab static int cx231xx_close(struct file *filp)
15820c0d06caSMauro Carvalho Chehab {
15837c617138SHans Verkuil struct cx231xx *dev = video_drvdata(filp);
15847c617138SHans Verkuil struct video_device *vdev = video_devdata(filp);
15850c0d06caSMauro Carvalho Chehab
15867c617138SHans Verkuil _vb2_fop_release(filp, NULL);
15870c0d06caSMauro Carvalho Chehab
15887c617138SHans Verkuil if (--dev->users == 0) {
15890c0d06caSMauro Carvalho Chehab /* Save some power by putting tuner to sleep */
15903aab15afSHans Verkuil call_all(dev, tuner, standby);
15910c0d06caSMauro Carvalho Chehab
15920c0d06caSMauro Carvalho Chehab /* do this before setting alternate! */
15930c0d06caSMauro Carvalho Chehab if (dev->USE_ISO)
15940c0d06caSMauro Carvalho Chehab cx231xx_uninit_isoc(dev);
15950c0d06caSMauro Carvalho Chehab else
15960c0d06caSMauro Carvalho Chehab cx231xx_uninit_bulk(dev);
15970c0d06caSMauro Carvalho Chehab cx231xx_set_mode(dev, CX231XX_SUSPEND);
15987c617138SHans Verkuil }
15990c0d06caSMauro Carvalho Chehab
16007c617138SHans Verkuil /*
16017c617138SHans Verkuil * To workaround error number=-71 on EP0 for VideoGrabber,
16027c617138SHans Verkuil * need exclude following.
16037c617138SHans Verkuil * FIXME: It is probably safe to remove most of these, as we're
16047c617138SHans Verkuil * now avoiding the alternate setting for INDEX_VANC
16057c617138SHans Verkuil */
16067c617138SHans Verkuil if (!dev->board.no_alt_vanc && vdev->vfl_type == VFL_TYPE_VBI) {
16077c617138SHans Verkuil /* do this before setting alternate! */
16087c617138SHans Verkuil cx231xx_uninit_vbi_isoc(dev);
16097c617138SHans Verkuil
16107c617138SHans Verkuil /* set alternate 0 */
16117c617138SHans Verkuil if (!dev->vbi_or_sliced_cc_mode)
16127c617138SHans Verkuil cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
16137c617138SHans Verkuil else
16147c617138SHans Verkuil cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
16157c617138SHans Verkuil
16167c617138SHans Verkuil wake_up_interruptible_nr(&dev->open, 1);
16177c617138SHans Verkuil return 0;
16187c617138SHans Verkuil }
16197c617138SHans Verkuil
16207c617138SHans Verkuil if (dev->users == 0) {
16210c0d06caSMauro Carvalho Chehab /* set alternate 0 */
16220c0d06caSMauro Carvalho Chehab cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
16230c0d06caSMauro Carvalho Chehab }
16247c617138SHans Verkuil
1625543409a2SSteven Rostedt wake_up_interruptible(&dev->open);
16260c0d06caSMauro Carvalho Chehab return 0;
16270c0d06caSMauro Carvalho Chehab }
16280c0d06caSMauro Carvalho Chehab
cx231xx_v4l2_close(struct file * filp)16290c0d06caSMauro Carvalho Chehab static int cx231xx_v4l2_close(struct file *filp)
16300c0d06caSMauro Carvalho Chehab {
16317c617138SHans Verkuil struct cx231xx *dev = video_drvdata(filp);
16320c0d06caSMauro Carvalho Chehab int rc;
16330c0d06caSMauro Carvalho Chehab
16340c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock);
16350c0d06caSMauro Carvalho Chehab rc = cx231xx_close(filp);
16360c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
16370c0d06caSMauro Carvalho Chehab return rc;
16380c0d06caSMauro Carvalho Chehab }
16390c0d06caSMauro Carvalho Chehab
16400c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations cx231xx_v4l_fops = {
16410c0d06caSMauro Carvalho Chehab .owner = THIS_MODULE,
16420c0d06caSMauro Carvalho Chehab .open = cx231xx_v4l2_open,
16430c0d06caSMauro Carvalho Chehab .release = cx231xx_v4l2_close,
16447c617138SHans Verkuil .read = vb2_fop_read,
16457c617138SHans Verkuil .poll = vb2_fop_poll,
16467c617138SHans Verkuil .mmap = vb2_fop_mmap,
16470c0d06caSMauro Carvalho Chehab .unlocked_ioctl = video_ioctl2,
16480c0d06caSMauro Carvalho Chehab };
16490c0d06caSMauro Carvalho Chehab
16500c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops video_ioctl_ops = {
1651bc08734cSHans Verkuil .vidioc_querycap = cx231xx_querycap,
16520c0d06caSMauro Carvalho Chehab .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
16530c0d06caSMauro Carvalho Chehab .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
16540c0d06caSMauro Carvalho Chehab .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
16550c0d06caSMauro Carvalho Chehab .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
16560c0d06caSMauro Carvalho Chehab .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
16570c0d06caSMauro Carvalho Chehab .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
16586264722cSHans Verkuil .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
16595200ab6aSHans Verkuil .vidioc_g_pixelaspect = vidioc_g_pixelaspect,
1660ee10dc36SHans Verkuil .vidioc_g_selection = vidioc_g_selection,
16617c617138SHans Verkuil .vidioc_reqbufs = vb2_ioctl_reqbufs,
16627c617138SHans Verkuil .vidioc_querybuf = vb2_ioctl_querybuf,
16637c617138SHans Verkuil .vidioc_qbuf = vb2_ioctl_qbuf,
16647c617138SHans Verkuil .vidioc_dqbuf = vb2_ioctl_dqbuf,
16650c0d06caSMauro Carvalho Chehab .vidioc_s_std = vidioc_s_std,
16660c0d06caSMauro Carvalho Chehab .vidioc_g_std = vidioc_g_std,
1667b86d1544SHans Verkuil .vidioc_enum_input = cx231xx_enum_input,
1668b86d1544SHans Verkuil .vidioc_g_input = cx231xx_g_input,
1669b86d1544SHans Verkuil .vidioc_s_input = cx231xx_s_input,
16707c617138SHans Verkuil .vidioc_streamon = vb2_ioctl_streamon,
16717c617138SHans Verkuil .vidioc_streamoff = vb2_ioctl_streamoff,
1672b86d1544SHans Verkuil .vidioc_g_tuner = cx231xx_g_tuner,
1673b86d1544SHans Verkuil .vidioc_s_tuner = cx231xx_s_tuner,
1674b86d1544SHans Verkuil .vidioc_g_frequency = cx231xx_g_frequency,
1675b86d1544SHans Verkuil .vidioc_s_frequency = cx231xx_s_frequency,
16760c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
167708fe9f7dSHans Verkuil .vidioc_g_chip_info = cx231xx_g_chip_info,
1678b86d1544SHans Verkuil .vidioc_g_register = cx231xx_g_register,
1679b86d1544SHans Verkuil .vidioc_s_register = cx231xx_s_register,
16800c0d06caSMauro Carvalho Chehab #endif
16811d08a4faSHans Verkuil .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
16821d08a4faSHans Verkuil .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
16830c0d06caSMauro Carvalho Chehab };
16840c0d06caSMauro Carvalho Chehab
16850c0d06caSMauro Carvalho Chehab static struct video_device cx231xx_vbi_template;
16860c0d06caSMauro Carvalho Chehab
16870c0d06caSMauro Carvalho Chehab static const struct video_device cx231xx_video_template = {
16880c0d06caSMauro Carvalho Chehab .fops = &cx231xx_v4l_fops,
168960acf187SHans Verkuil .release = video_device_release_empty,
16900c0d06caSMauro Carvalho Chehab .ioctl_ops = &video_ioctl_ops,
16910c0d06caSMauro Carvalho Chehab .tvnorms = V4L2_STD_ALL,
16920c0d06caSMauro Carvalho Chehab };
16930c0d06caSMauro Carvalho Chehab
16940c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations radio_fops = {
16950c0d06caSMauro Carvalho Chehab .owner = THIS_MODULE,
16960c0d06caSMauro Carvalho Chehab .open = cx231xx_v4l2_open,
16970c0d06caSMauro Carvalho Chehab .release = cx231xx_v4l2_close,
16981d08a4faSHans Verkuil .poll = v4l2_ctrl_poll,
16991265f080SHans Verkuil .unlocked_ioctl = video_ioctl2,
17000c0d06caSMauro Carvalho Chehab };
17010c0d06caSMauro Carvalho Chehab
17020c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops radio_ioctl_ops = {
1703bc08734cSHans Verkuil .vidioc_querycap = cx231xx_querycap,
17040c0d06caSMauro Carvalho Chehab .vidioc_g_tuner = radio_g_tuner,
17050c0d06caSMauro Carvalho Chehab .vidioc_s_tuner = radio_s_tuner,
1706b86d1544SHans Verkuil .vidioc_g_frequency = cx231xx_g_frequency,
1707b86d1544SHans Verkuil .vidioc_s_frequency = cx231xx_s_frequency,
17080c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
170908fe9f7dSHans Verkuil .vidioc_g_chip_info = cx231xx_g_chip_info,
1710b86d1544SHans Verkuil .vidioc_g_register = cx231xx_g_register,
1711b86d1544SHans Verkuil .vidioc_s_register = cx231xx_s_register,
17120c0d06caSMauro Carvalho Chehab #endif
17131d08a4faSHans Verkuil .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
17141d08a4faSHans Verkuil .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
17150c0d06caSMauro Carvalho Chehab };
17160c0d06caSMauro Carvalho Chehab
17170c0d06caSMauro Carvalho Chehab static struct video_device cx231xx_radio_template = {
17180c0d06caSMauro Carvalho Chehab .name = "cx231xx-radio",
17190c0d06caSMauro Carvalho Chehab .fops = &radio_fops,
17200c0d06caSMauro Carvalho Chehab .ioctl_ops = &radio_ioctl_ops,
17210c0d06caSMauro Carvalho Chehab };
17220c0d06caSMauro Carvalho Chehab
17230c0d06caSMauro Carvalho Chehab /******************************** usb interface ******************************/
17240c0d06caSMauro Carvalho Chehab
cx231xx_vdev_init(struct cx231xx * dev,struct video_device * vfd,const struct video_device * template,const char * type_name)172560acf187SHans Verkuil static void cx231xx_vdev_init(struct cx231xx *dev,
172660acf187SHans Verkuil struct video_device *vfd,
172760acf187SHans Verkuil const struct video_device *template,
172860acf187SHans Verkuil const char *type_name)
17290c0d06caSMauro Carvalho Chehab {
17300c0d06caSMauro Carvalho Chehab *vfd = *template;
17310c0d06caSMauro Carvalho Chehab vfd->v4l2_dev = &dev->v4l2_dev;
173260acf187SHans Verkuil vfd->release = video_device_release_empty;
17330c0d06caSMauro Carvalho Chehab vfd->lock = &dev->lock;
17340c0d06caSMauro Carvalho Chehab
17350c0d06caSMauro Carvalho Chehab snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
17360c0d06caSMauro Carvalho Chehab
17370c0d06caSMauro Carvalho Chehab video_set_drvdata(vfd, dev);
173806c46003SHans Verkuil if (dev->tuner_type == TUNER_ABSENT) {
17393c1ccbadSBrad Love switch (dev->model) {
17403c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
17413c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_935C:
17423c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_955Q:
17433c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_975:
17443c1ccbadSBrad Love case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
17453c1ccbadSBrad Love break;
17463c1ccbadSBrad Love default:
174706c46003SHans Verkuil v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
174806c46003SHans Verkuil v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
174906c46003SHans Verkuil v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
175006c46003SHans Verkuil v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
17513c1ccbadSBrad Love break;
17523c1ccbadSBrad Love }
175306c46003SHans Verkuil }
17540c0d06caSMauro Carvalho Chehab }
17550c0d06caSMauro Carvalho Chehab
cx231xx_register_analog_devices(struct cx231xx * dev)17560c0d06caSMauro Carvalho Chehab int cx231xx_register_analog_devices(struct cx231xx *dev)
17570c0d06caSMauro Carvalho Chehab {
17587c617138SHans Verkuil struct vb2_queue *q;
17590c0d06caSMauro Carvalho Chehab int ret;
17600c0d06caSMauro Carvalho Chehab
1761336fea92SMauro Carvalho Chehab dev_info(dev->dev, "v4l2 driver version %s\n", CX231XX_VERSION);
17620c0d06caSMauro Carvalho Chehab
17630c0d06caSMauro Carvalho Chehab /* set default norm */
1764a25a7012SHans Verkuil dev->norm = V4L2_STD_PAL;
17650c0d06caSMauro Carvalho Chehab dev->width = norm_maxw(dev);
17660c0d06caSMauro Carvalho Chehab dev->height = norm_maxh(dev);
17670c0d06caSMauro Carvalho Chehab dev->interlaced = 0;
17680c0d06caSMauro Carvalho Chehab
17690c0d06caSMauro Carvalho Chehab /* Analog specific initialization */
17700c0d06caSMauro Carvalho Chehab dev->format = &format[0];
17710c0d06caSMauro Carvalho Chehab
17720c0d06caSMauro Carvalho Chehab /* Set the initial input */
17730c0d06caSMauro Carvalho Chehab video_mux(dev, dev->video_input);
17740c0d06caSMauro Carvalho Chehab
17758774bed9SLaurent Pinchart call_all(dev, video, s_std, dev->norm);
1776d61072a4SHans Verkuil
1777d2370f8eSHans Verkuil v4l2_ctrl_handler_init(&dev->ctrl_handler, 10);
1778d2370f8eSHans Verkuil v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5);
1779d2370f8eSHans Verkuil
1780d2370f8eSHans Verkuil if (dev->sd_cx25840) {
1781d2370f8eSHans Verkuil v4l2_ctrl_add_handler(&dev->ctrl_handler,
1782da1b1aeaSHans Verkuil dev->sd_cx25840->ctrl_handler, NULL, true);
1783d2370f8eSHans Verkuil v4l2_ctrl_add_handler(&dev->radio_ctrl_handler,
1784d2370f8eSHans Verkuil dev->sd_cx25840->ctrl_handler,
1785da1b1aeaSHans Verkuil v4l2_ctrl_radio_filter, true);
1786d2370f8eSHans Verkuil }
1787d2370f8eSHans Verkuil
1788d2370f8eSHans Verkuil if (dev->ctrl_handler.error)
1789d2370f8eSHans Verkuil return dev->ctrl_handler.error;
1790d2370f8eSHans Verkuil if (dev->radio_ctrl_handler.error)
1791d2370f8eSHans Verkuil return dev->radio_ctrl_handler.error;
17920c0d06caSMauro Carvalho Chehab
17930c0d06caSMauro Carvalho Chehab /* enable vbi capturing */
17940c0d06caSMauro Carvalho Chehab /* write code here... */
17950c0d06caSMauro Carvalho Chehab
17960c0d06caSMauro Carvalho Chehab /* allocate and fill video video_device struct */
179760acf187SHans Verkuil cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video");
1798b6a40e72SMauro Carvalho Chehab #if defined(CONFIG_MEDIA_CONTROLLER)
1799b6a40e72SMauro Carvalho Chehab dev->video_pad.flags = MEDIA_PAD_FL_SINK;
1800ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad);
1801b6a40e72SMauro Carvalho Chehab if (ret < 0)
1802b6a40e72SMauro Carvalho Chehab dev_err(dev->dev, "failed to initialize video media entity!\n");
1803b6a40e72SMauro Carvalho Chehab #endif
180460acf187SHans Verkuil dev->vdev.ctrl_handler = &dev->ctrl_handler;
18057c617138SHans Verkuil
18067c617138SHans Verkuil q = &dev->vidq;
18077c617138SHans Verkuil q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
18087c617138SHans Verkuil q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
18097c617138SHans Verkuil q->drv_priv = dev;
18107c617138SHans Verkuil q->buf_struct_size = sizeof(struct cx231xx_buffer);
18117c617138SHans Verkuil q->ops = &cx231xx_video_qops;
18127c617138SHans Verkuil q->mem_ops = &vb2_vmalloc_memops;
18137c617138SHans Verkuil q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
181480c2b40aSBenjamin Gaignard q->min_queued_buffers = 1;
18157c617138SHans Verkuil q->lock = &dev->lock;
18167c617138SHans Verkuil ret = vb2_queue_init(q);
18177c617138SHans Verkuil if (ret)
18187c617138SHans Verkuil return ret;
18197c617138SHans Verkuil dev->vdev.queue = q;
18208c3854d0SHans Verkuil dev->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
18218c3854d0SHans Verkuil V4L2_CAP_VIDEO_CAPTURE;
18223c1ccbadSBrad Love
18233c1ccbadSBrad Love switch (dev->model) { /* i2c device tuners */
18243c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
18253c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_935C:
18263c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_955Q:
18273c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_975:
18283c1ccbadSBrad Love case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
18293c1ccbadSBrad Love dev->vdev.device_caps |= V4L2_CAP_TUNER;
18303c1ccbadSBrad Love break;
18313c1ccbadSBrad Love default:
18328c3854d0SHans Verkuil if (dev->tuner_type != TUNER_ABSENT)
18338c3854d0SHans Verkuil dev->vdev.device_caps |= V4L2_CAP_TUNER;
18343c1ccbadSBrad Love break;
18353c1ccbadSBrad Love }
18368c3854d0SHans Verkuil
18370c0d06caSMauro Carvalho Chehab /* register v4l2 video video_device */
18387fbbbc78SHans Verkuil ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO,
18390c0d06caSMauro Carvalho Chehab video_nr[dev->devno]);
18400c0d06caSMauro Carvalho Chehab if (ret) {
1841336fea92SMauro Carvalho Chehab dev_err(dev->dev,
1842b7085c08SMauro Carvalho Chehab "unable to register video device (error=%i).\n",
18430c0d06caSMauro Carvalho Chehab ret);
18440c0d06caSMauro Carvalho Chehab return ret;
18450c0d06caSMauro Carvalho Chehab }
18460c0d06caSMauro Carvalho Chehab
1847336fea92SMauro Carvalho Chehab dev_info(dev->dev, "Registered video device %s [v4l2]\n",
184860acf187SHans Verkuil video_device_node_name(&dev->vdev));
18490c0d06caSMauro Carvalho Chehab
18500c0d06caSMauro Carvalho Chehab /* Initialize VBI template */
18513724dde9SEzequiel Garcia cx231xx_vbi_template = cx231xx_video_template;
1852cc1e6315SMauro Carvalho Chehab strscpy(cx231xx_vbi_template.name, "cx231xx-vbi",
1853cc1e6315SMauro Carvalho Chehab sizeof(cx231xx_vbi_template.name));
18540c0d06caSMauro Carvalho Chehab
18550c0d06caSMauro Carvalho Chehab /* Allocate and fill vbi video_device struct */
185660acf187SHans Verkuil cx231xx_vdev_init(dev, &dev->vbi_dev, &cx231xx_vbi_template, "vbi");
18570c0d06caSMauro Carvalho Chehab
1858b6a40e72SMauro Carvalho Chehab #if defined(CONFIG_MEDIA_CONTROLLER)
1859b6a40e72SMauro Carvalho Chehab dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
1860ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad);
1861b6a40e72SMauro Carvalho Chehab if (ret < 0)
1862b6a40e72SMauro Carvalho Chehab dev_err(dev->dev, "failed to initialize vbi media entity!\n");
1863b6a40e72SMauro Carvalho Chehab #endif
186460acf187SHans Verkuil dev->vbi_dev.ctrl_handler = &dev->ctrl_handler;
18657c617138SHans Verkuil
18667c617138SHans Verkuil q = &dev->vbiq;
18677c617138SHans Verkuil q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
18687c617138SHans Verkuil q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
18697c617138SHans Verkuil q->drv_priv = dev;
18707c617138SHans Verkuil q->buf_struct_size = sizeof(struct cx231xx_buffer);
18717c617138SHans Verkuil q->ops = &cx231xx_vbi_qops;
18727c617138SHans Verkuil q->mem_ops = &vb2_vmalloc_memops;
18737c617138SHans Verkuil q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
187480c2b40aSBenjamin Gaignard q->min_queued_buffers = 1;
18757c617138SHans Verkuil q->lock = &dev->lock;
18767c617138SHans Verkuil ret = vb2_queue_init(q);
18777c617138SHans Verkuil if (ret)
18787c617138SHans Verkuil return ret;
18797c617138SHans Verkuil dev->vbi_dev.queue = q;
18808c3854d0SHans Verkuil dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
18818c3854d0SHans Verkuil V4L2_CAP_VBI_CAPTURE;
18823c1ccbadSBrad Love switch (dev->model) { /* i2c device tuners */
18833c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
18843c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_935C:
18853c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_955Q:
18863c1ccbadSBrad Love case CX231XX_BOARD_HAUPPAUGE_975:
18873c1ccbadSBrad Love case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
18883c1ccbadSBrad Love dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
18893c1ccbadSBrad Love break;
18903c1ccbadSBrad Love default:
18918c3854d0SHans Verkuil if (dev->tuner_type != TUNER_ABSENT)
18928c3854d0SHans Verkuil dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
18933c1ccbadSBrad Love }
18948c3854d0SHans Verkuil
18950c0d06caSMauro Carvalho Chehab /* register v4l2 vbi video_device */
189660acf187SHans Verkuil ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI,
18970c0d06caSMauro Carvalho Chehab vbi_nr[dev->devno]);
18980c0d06caSMauro Carvalho Chehab if (ret < 0) {
1899336fea92SMauro Carvalho Chehab dev_err(dev->dev, "unable to register vbi device\n");
19000c0d06caSMauro Carvalho Chehab return ret;
19010c0d06caSMauro Carvalho Chehab }
19020c0d06caSMauro Carvalho Chehab
1903336fea92SMauro Carvalho Chehab dev_info(dev->dev, "Registered VBI device %s\n",
190460acf187SHans Verkuil video_device_node_name(&dev->vbi_dev));
19050c0d06caSMauro Carvalho Chehab
19060c0d06caSMauro Carvalho Chehab if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
190760acf187SHans Verkuil cx231xx_vdev_init(dev, &dev->radio_dev,
190860acf187SHans Verkuil &cx231xx_radio_template, "radio");
190960acf187SHans Verkuil dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
19108c3854d0SHans Verkuil dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
191160acf187SHans Verkuil ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
19120c0d06caSMauro Carvalho Chehab radio_nr[dev->devno]);
19130c0d06caSMauro Carvalho Chehab if (ret < 0) {
1914336fea92SMauro Carvalho Chehab dev_err(dev->dev,
1915b7085c08SMauro Carvalho Chehab "can't register radio device\n");
19160c0d06caSMauro Carvalho Chehab return ret;
19170c0d06caSMauro Carvalho Chehab }
1918336fea92SMauro Carvalho Chehab dev_info(dev->dev, "Registered radio device as %s\n",
191960acf187SHans Verkuil video_device_node_name(&dev->radio_dev));
19200c0d06caSMauro Carvalho Chehab }
19210c0d06caSMauro Carvalho Chehab
19220c0d06caSMauro Carvalho Chehab return 0;
19230c0d06caSMauro Carvalho Chehab }
1924