1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20c0d06caSMauro Carvalho Chehab /*
30c0d06caSMauro Carvalho Chehab  * Hauppauge HD PVR USB driver - video 4 linux 2 interface
40c0d06caSMauro Carvalho Chehab  *
50c0d06caSMauro Carvalho Chehab  * Copyright (C) 2008      Janne Grunau (j@jannau.net)
60c0d06caSMauro Carvalho Chehab  */
70c0d06caSMauro Carvalho Chehab 
80c0d06caSMauro Carvalho Chehab #include <linux/kernel.h>
90c0d06caSMauro Carvalho Chehab #include <linux/errno.h>
100c0d06caSMauro Carvalho Chehab #include <linux/init.h>
110c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
120c0d06caSMauro Carvalho Chehab #include <linux/module.h>
130c0d06caSMauro Carvalho Chehab #include <linux/uaccess.h>
140c0d06caSMauro Carvalho Chehab #include <linux/usb.h>
150c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
160c0d06caSMauro Carvalho Chehab #include <linux/workqueue.h>
170c0d06caSMauro Carvalho Chehab 
180c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h>
193315c59aSHans Verkuil #include <linux/v4l2-dv-timings.h>
200c0d06caSMauro Carvalho Chehab #include <media/v4l2-dev.h>
210c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
2225764158SHans Verkuil #include <media/v4l2-dv-timings.h>
230c0d06caSMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
2465fe42d6SHans Verkuil #include <media/v4l2-event.h>
250c0d06caSMauro Carvalho Chehab #include "hdpvr.h"
260c0d06caSMauro Carvalho Chehab 
270c0d06caSMauro Carvalho Chehab #define BULK_URB_TIMEOUT   90 /* 0.09 seconds */
280c0d06caSMauro Carvalho Chehab 
290c0d06caSMauro Carvalho Chehab #define print_buffer_status() { \
300c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,	\
310c0d06caSMauro Carvalho Chehab 			 "%s:%d buffer stat: %d free, %d proc\n",	\
320c0d06caSMauro Carvalho Chehab 			 __func__, __LINE__,				\
330c0d06caSMauro Carvalho Chehab 			 list_size(&dev->free_buff_list),		\
340c0d06caSMauro Carvalho Chehab 			 list_size(&dev->rec_buff_list)); }
350c0d06caSMauro Carvalho Chehab 
363315c59aSHans Verkuil static const struct v4l2_dv_timings hdpvr_dv_timings[] = {
373315c59aSHans Verkuil 	V4L2_DV_BT_CEA_720X480I59_94,
383315c59aSHans Verkuil 	V4L2_DV_BT_CEA_720X576I50,
393315c59aSHans Verkuil 	V4L2_DV_BT_CEA_720X480P59_94,
403315c59aSHans Verkuil 	V4L2_DV_BT_CEA_720X576P50,
413315c59aSHans Verkuil 	V4L2_DV_BT_CEA_1280X720P50,
423315c59aSHans Verkuil 	V4L2_DV_BT_CEA_1280X720P60,
433315c59aSHans Verkuil 	V4L2_DV_BT_CEA_1920X1080I50,
443315c59aSHans Verkuil 	V4L2_DV_BT_CEA_1920X1080I60,
453315c59aSHans Verkuil };
463315c59aSHans Verkuil 
473315c59aSHans Verkuil /* Use 480i59 as the default timings */
483315c59aSHans Verkuil #define HDPVR_DEF_DV_TIMINGS_IDX (0)
493315c59aSHans Verkuil 
503315c59aSHans Verkuil struct hdpvr_fh {
513315c59aSHans Verkuil 	struct v4l2_fh fh;
523315c59aSHans Verkuil 	bool legacy_mode;
533315c59aSHans Verkuil };
543315c59aSHans Verkuil 
550c0d06caSMauro Carvalho Chehab static uint list_size(struct list_head *list)
560c0d06caSMauro Carvalho Chehab {
570c0d06caSMauro Carvalho Chehab 	struct list_head *tmp;
580c0d06caSMauro Carvalho Chehab 	uint count = 0;
590c0d06caSMauro Carvalho Chehab 
600c0d06caSMauro Carvalho Chehab 	list_for_each(tmp, list) {
610c0d06caSMauro Carvalho Chehab 		count++;
620c0d06caSMauro Carvalho Chehab 	}
630c0d06caSMauro Carvalho Chehab 
640c0d06caSMauro Carvalho Chehab 	return count;
650c0d06caSMauro Carvalho Chehab }
660c0d06caSMauro Carvalho Chehab 
670c0d06caSMauro Carvalho Chehab /*=========================================================================*/
680c0d06caSMauro Carvalho Chehab /* urb callback */
690c0d06caSMauro Carvalho Chehab static void hdpvr_read_bulk_callback(struct urb *urb)
700c0d06caSMauro Carvalho Chehab {
710c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
720c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = buf->dev;
730c0d06caSMauro Carvalho Chehab 
740c0d06caSMauro Carvalho Chehab 	/* marking buffer as received and wake waiting */
750c0d06caSMauro Carvalho Chehab 	buf->status = BUFSTAT_READY;
760c0d06caSMauro Carvalho Chehab 	wake_up_interruptible(&dev->wait_data);
770c0d06caSMauro Carvalho Chehab }
780c0d06caSMauro Carvalho Chehab 
790c0d06caSMauro Carvalho Chehab /*=========================================================================*/
803445857bSHans Verkuil /* buffer bits */
810c0d06caSMauro Carvalho Chehab 
820c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
830c0d06caSMauro Carvalho Chehab int hdpvr_cancel_queue(struct hdpvr_device *dev)
840c0d06caSMauro Carvalho Chehab {
850c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
860c0d06caSMauro Carvalho Chehab 
870c0d06caSMauro Carvalho Chehab 	list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
880c0d06caSMauro Carvalho Chehab 		usb_kill_urb(buf->urb);
890c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_AVAILABLE;
900c0d06caSMauro Carvalho Chehab 	}
910c0d06caSMauro Carvalho Chehab 
920c0d06caSMauro Carvalho Chehab 	list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
930c0d06caSMauro Carvalho Chehab 
940c0d06caSMauro Carvalho Chehab 	return 0;
950c0d06caSMauro Carvalho Chehab }
960c0d06caSMauro Carvalho Chehab 
970c0d06caSMauro Carvalho Chehab static int hdpvr_free_queue(struct list_head *q)
980c0d06caSMauro Carvalho Chehab {
990c0d06caSMauro Carvalho Chehab 	struct list_head *tmp;
1000c0d06caSMauro Carvalho Chehab 	struct list_head *p;
1010c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
1020c0d06caSMauro Carvalho Chehab 	struct urb *urb;
1030c0d06caSMauro Carvalho Chehab 
1040c0d06caSMauro Carvalho Chehab 	for (p = q->next; p != q;) {
1050c0d06caSMauro Carvalho Chehab 		buf = list_entry(p, struct hdpvr_buffer, buff_list);
1060c0d06caSMauro Carvalho Chehab 
1070c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
1080c0d06caSMauro Carvalho Chehab 		usb_free_coherent(urb->dev, urb->transfer_buffer_length,
1090c0d06caSMauro Carvalho Chehab 				  urb->transfer_buffer, urb->transfer_dma);
1100c0d06caSMauro Carvalho Chehab 		usb_free_urb(urb);
1110c0d06caSMauro Carvalho Chehab 		tmp = p->next;
1120c0d06caSMauro Carvalho Chehab 		list_del(p);
1130c0d06caSMauro Carvalho Chehab 		kfree(buf);
1140c0d06caSMauro Carvalho Chehab 		p = tmp;
1150c0d06caSMauro Carvalho Chehab 	}
1160c0d06caSMauro Carvalho Chehab 
1170c0d06caSMauro Carvalho Chehab 	return 0;
1180c0d06caSMauro Carvalho Chehab }
1190c0d06caSMauro Carvalho Chehab 
1200c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
1210c0d06caSMauro Carvalho Chehab int hdpvr_free_buffers(struct hdpvr_device *dev)
1220c0d06caSMauro Carvalho Chehab {
1230c0d06caSMauro Carvalho Chehab 	hdpvr_cancel_queue(dev);
1240c0d06caSMauro Carvalho Chehab 
1250c0d06caSMauro Carvalho Chehab 	hdpvr_free_queue(&dev->free_buff_list);
1260c0d06caSMauro Carvalho Chehab 	hdpvr_free_queue(&dev->rec_buff_list);
1270c0d06caSMauro Carvalho Chehab 
1280c0d06caSMauro Carvalho Chehab 	return 0;
1290c0d06caSMauro Carvalho Chehab }
1300c0d06caSMauro Carvalho Chehab 
1310c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
1320c0d06caSMauro Carvalho Chehab int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
1330c0d06caSMauro Carvalho Chehab {
1340c0d06caSMauro Carvalho Chehab 	uint i;
1350c0d06caSMauro Carvalho Chehab 	int retval = -ENOMEM;
1360c0d06caSMauro Carvalho Chehab 	u8 *mem;
1370c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
1380c0d06caSMauro Carvalho Chehab 	struct urb *urb;
1390c0d06caSMauro Carvalho Chehab 
1400c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
1410c0d06caSMauro Carvalho Chehab 		 "allocating %u buffers\n", count);
1420c0d06caSMauro Carvalho Chehab 
1430c0d06caSMauro Carvalho Chehab 	for (i = 0; i < count; i++) {
1440c0d06caSMauro Carvalho Chehab 
1450c0d06caSMauro Carvalho Chehab 		buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
1460c0d06caSMauro Carvalho Chehab 		if (!buf) {
1470c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n");
1480c0d06caSMauro Carvalho Chehab 			goto exit;
1490c0d06caSMauro Carvalho Chehab 		}
1500c0d06caSMauro Carvalho Chehab 		buf->dev = dev;
1510c0d06caSMauro Carvalho Chehab 
1520c0d06caSMauro Carvalho Chehab 		urb = usb_alloc_urb(0, GFP_KERNEL);
15390831662SWolfram Sang 		if (!urb)
1540c0d06caSMauro Carvalho Chehab 			goto exit_urb;
1550c0d06caSMauro Carvalho Chehab 		buf->urb = urb;
1560c0d06caSMauro Carvalho Chehab 
1570c0d06caSMauro Carvalho Chehab 		mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL,
1580c0d06caSMauro Carvalho Chehab 					 &urb->transfer_dma);
1590c0d06caSMauro Carvalho Chehab 		if (!mem) {
1600c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
1610c0d06caSMauro Carvalho Chehab 				 "cannot allocate usb transfer buffer\n");
1620c0d06caSMauro Carvalho Chehab 			goto exit_urb_buffer;
1630c0d06caSMauro Carvalho Chehab 		}
1640c0d06caSMauro Carvalho Chehab 
1650c0d06caSMauro Carvalho Chehab 		usb_fill_bulk_urb(buf->urb, dev->udev,
1660c0d06caSMauro Carvalho Chehab 				  usb_rcvbulkpipe(dev->udev,
1670c0d06caSMauro Carvalho Chehab 						  dev->bulk_in_endpointAddr),
1680c0d06caSMauro Carvalho Chehab 				  mem, dev->bulk_in_size,
1690c0d06caSMauro Carvalho Chehab 				  hdpvr_read_bulk_callback, buf);
1700c0d06caSMauro Carvalho Chehab 
1710c0d06caSMauro Carvalho Chehab 		buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1720c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_AVAILABLE;
1730c0d06caSMauro Carvalho Chehab 		list_add_tail(&buf->buff_list, &dev->free_buff_list);
1740c0d06caSMauro Carvalho Chehab 	}
1750c0d06caSMauro Carvalho Chehab 	return 0;
1760c0d06caSMauro Carvalho Chehab exit_urb_buffer:
1770c0d06caSMauro Carvalho Chehab 	usb_free_urb(urb);
1780c0d06caSMauro Carvalho Chehab exit_urb:
1790c0d06caSMauro Carvalho Chehab 	kfree(buf);
1800c0d06caSMauro Carvalho Chehab exit:
1810c0d06caSMauro Carvalho Chehab 	hdpvr_free_buffers(dev);
1820c0d06caSMauro Carvalho Chehab 	return retval;
1830c0d06caSMauro Carvalho Chehab }
1840c0d06caSMauro Carvalho Chehab 
1850c0d06caSMauro Carvalho Chehab static int hdpvr_submit_buffers(struct hdpvr_device *dev)
1860c0d06caSMauro Carvalho Chehab {
1870c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
1880c0d06caSMauro Carvalho Chehab 	struct urb *urb;
1890c0d06caSMauro Carvalho Chehab 	int ret = 0, err_count = 0;
1900c0d06caSMauro Carvalho Chehab 
1910c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
1920c0d06caSMauro Carvalho Chehab 
1930c0d06caSMauro Carvalho Chehab 	while (dev->status == STATUS_STREAMING &&
1940c0d06caSMauro Carvalho Chehab 	       !list_empty(&dev->free_buff_list)) {
1950c0d06caSMauro Carvalho Chehab 
1960c0d06caSMauro Carvalho Chehab 		buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
1970c0d06caSMauro Carvalho Chehab 				 buff_list);
1980c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_AVAILABLE) {
1990c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
2000c0d06caSMauro Carvalho Chehab 				 "buffer not marked as available\n");
2010c0d06caSMauro Carvalho Chehab 			ret = -EFAULT;
2020c0d06caSMauro Carvalho Chehab 			goto err;
2030c0d06caSMauro Carvalho Chehab 		}
2040c0d06caSMauro Carvalho Chehab 
2050c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
2060c0d06caSMauro Carvalho Chehab 		urb->status = 0;
2070c0d06caSMauro Carvalho Chehab 		urb->actual_length = 0;
2080c0d06caSMauro Carvalho Chehab 		ret = usb_submit_urb(urb, GFP_KERNEL);
2090c0d06caSMauro Carvalho Chehab 		if (ret) {
2100c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
2110c0d06caSMauro Carvalho Chehab 				 "usb_submit_urb in %s returned %d\n",
2120c0d06caSMauro Carvalho Chehab 				 __func__, ret);
2130c0d06caSMauro Carvalho Chehab 			if (++err_count > 2)
2140c0d06caSMauro Carvalho Chehab 				break;
2150c0d06caSMauro Carvalho Chehab 			continue;
2160c0d06caSMauro Carvalho Chehab 		}
2170c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_INPROGRESS;
2180c0d06caSMauro Carvalho Chehab 		list_move_tail(&buf->buff_list, &dev->rec_buff_list);
2190c0d06caSMauro Carvalho Chehab 	}
2200c0d06caSMauro Carvalho Chehab err:
2210c0d06caSMauro Carvalho Chehab 	print_buffer_status();
2220c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
2230c0d06caSMauro Carvalho Chehab 	return ret;
2240c0d06caSMauro Carvalho Chehab }
2250c0d06caSMauro Carvalho Chehab 
2260c0d06caSMauro Carvalho Chehab static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev)
2270c0d06caSMauro Carvalho Chehab {
2280c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
2290c0d06caSMauro Carvalho Chehab 
2300c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
2310c0d06caSMauro Carvalho Chehab 
2320c0d06caSMauro Carvalho Chehab 	if (list_empty(&dev->rec_buff_list)) {
2330c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->io_mutex);
2340c0d06caSMauro Carvalho Chehab 		return NULL;
2350c0d06caSMauro Carvalho Chehab 	}
2360c0d06caSMauro Carvalho Chehab 
2370c0d06caSMauro Carvalho Chehab 	buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer,
2380c0d06caSMauro Carvalho Chehab 			 buff_list);
2390c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
2400c0d06caSMauro Carvalho Chehab 
2410c0d06caSMauro Carvalho Chehab 	return buf;
2420c0d06caSMauro Carvalho Chehab }
2430c0d06caSMauro Carvalho Chehab 
2440c0d06caSMauro Carvalho Chehab static void hdpvr_transmit_buffers(struct work_struct *work)
2450c0d06caSMauro Carvalho Chehab {
2460c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = container_of(work, struct hdpvr_device,
2470c0d06caSMauro Carvalho Chehab 						worker);
2480c0d06caSMauro Carvalho Chehab 
2490c0d06caSMauro Carvalho Chehab 	while (dev->status == STATUS_STREAMING) {
2500c0d06caSMauro Carvalho Chehab 
2510c0d06caSMauro Carvalho Chehab 		if (hdpvr_submit_buffers(dev)) {
2520c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n");
2530c0d06caSMauro Carvalho Chehab 			goto error;
2540c0d06caSMauro Carvalho Chehab 		}
2550c0d06caSMauro Carvalho Chehab 		if (wait_event_interruptible(dev->wait_buffer,
2560c0d06caSMauro Carvalho Chehab 				!list_empty(&dev->free_buff_list) ||
2570c0d06caSMauro Carvalho Chehab 					     dev->status != STATUS_STREAMING))
2580c0d06caSMauro Carvalho Chehab 			goto error;
2590c0d06caSMauro Carvalho Chehab 	}
2600c0d06caSMauro Carvalho Chehab 
2610c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2620c0d06caSMauro Carvalho Chehab 		 "transmit worker exited\n");
2630c0d06caSMauro Carvalho Chehab 	return;
2640c0d06caSMauro Carvalho Chehab error:
2650c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2660c0d06caSMauro Carvalho Chehab 		 "transmit buffers errored\n");
2670c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_ERROR;
2680c0d06caSMauro Carvalho Chehab }
2690c0d06caSMauro Carvalho Chehab 
2700c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
2710c0d06caSMauro Carvalho Chehab static int hdpvr_start_streaming(struct hdpvr_device *dev)
2720c0d06caSMauro Carvalho Chehab {
2730c0d06caSMauro Carvalho Chehab 	int ret;
2744d601c4cSLeonid Kegulskiy 	struct hdpvr_video_info vidinf;
2750c0d06caSMauro Carvalho Chehab 
2760c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_STREAMING)
2770c0d06caSMauro Carvalho Chehab 		return 0;
27879f10b62SHans Verkuil 	if (dev->status != STATUS_IDLE)
2790c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
2800c0d06caSMauro Carvalho Chehab 
2814d601c4cSLeonid Kegulskiy 	ret = get_video_info(dev, &vidinf);
2825f454d82SHans Verkuil 	if (ret < 0)
2835f454d82SHans Verkuil 		return ret;
2845f454d82SHans Verkuil 
2855f454d82SHans Verkuil 	if (!vidinf.valid) {
28679f10b62SHans Verkuil 		msleep(250);
28779f10b62SHans Verkuil 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
28879f10b62SHans Verkuil 				"no video signal at input %d\n", dev->options.video_input);
28979f10b62SHans Verkuil 		return -EAGAIN;
29079f10b62SHans Verkuil 	}
2910c0d06caSMauro Carvalho Chehab 
2920c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
2934d601c4cSLeonid Kegulskiy 			"video signal: %dx%d@%dhz\n", vidinf.width,
2944d601c4cSLeonid Kegulskiy 			vidinf.height, vidinf.fps);
2950c0d06caSMauro Carvalho Chehab 
2960c0d06caSMauro Carvalho Chehab 	/* start streaming 2 request */
2970c0d06caSMauro Carvalho Chehab 	ret = usb_control_msg(dev->udev,
2980c0d06caSMauro Carvalho Chehab 			usb_sndctrlpipe(dev->udev, 0),
2990c0d06caSMauro Carvalho Chehab 			0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
3000c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3010c0d06caSMauro Carvalho Chehab 			"encoder start control request returned %d\n", ret);
302f7436876SLeonid Kegulskiy 	if (ret < 0)
303f7436876SLeonid Kegulskiy 		return ret;
3040c0d06caSMauro Carvalho Chehab 
305f7436876SLeonid Kegulskiy 	ret = hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
306f7436876SLeonid Kegulskiy 	if (ret)
307f7436876SLeonid Kegulskiy 		return ret;
3080c0d06caSMauro Carvalho Chehab 
3090c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_STREAMING;
3100c0d06caSMauro Carvalho Chehab 
3110c0d06caSMauro Carvalho Chehab 	INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
3125612e191SBhaktipriya Shridhar 	schedule_work(&dev->worker);
3130c0d06caSMauro Carvalho Chehab 
3140c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3150c0d06caSMauro Carvalho Chehab 			"streaming started\n");
3160c0d06caSMauro Carvalho Chehab 
3170c0d06caSMauro Carvalho Chehab 	return 0;
3180c0d06caSMauro Carvalho Chehab }
3190c0d06caSMauro Carvalho Chehab 
3200c0d06caSMauro Carvalho Chehab 
3210c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
3220c0d06caSMauro Carvalho Chehab static int hdpvr_stop_streaming(struct hdpvr_device *dev)
3230c0d06caSMauro Carvalho Chehab {
3240c0d06caSMauro Carvalho Chehab 	int actual_length;
3250c0d06caSMauro Carvalho Chehab 	uint c = 0;
3260c0d06caSMauro Carvalho Chehab 	u8 *buf;
3270c0d06caSMauro Carvalho Chehab 
3280c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE)
3290c0d06caSMauro Carvalho Chehab 		return 0;
3300c0d06caSMauro Carvalho Chehab 	else if (dev->status != STATUS_STREAMING)
3310c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
3320c0d06caSMauro Carvalho Chehab 
3330c0d06caSMauro Carvalho Chehab 	buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
3340c0d06caSMauro Carvalho Chehab 	if (!buf)
3354d5ded75SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer for emptying the internal device buffer. Next capture start will be slow\n");
3360c0d06caSMauro Carvalho Chehab 
3370c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_SHUTTING_DOWN;
3380c0d06caSMauro Carvalho Chehab 	hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
3390c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3400c0d06caSMauro Carvalho Chehab 
3410c0d06caSMauro Carvalho Chehab 	wake_up_interruptible(&dev->wait_buffer);
3420c0d06caSMauro Carvalho Chehab 	msleep(50);
3430c0d06caSMauro Carvalho Chehab 
3445612e191SBhaktipriya Shridhar 	flush_work(&dev->worker);
3450c0d06caSMauro Carvalho Chehab 
3460c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
3470c0d06caSMauro Carvalho Chehab 	/* kill the still outstanding urbs */
3480c0d06caSMauro Carvalho Chehab 	hdpvr_cancel_queue(dev);
3490c0d06caSMauro Carvalho Chehab 
3500c0d06caSMauro Carvalho Chehab 	/* emptying the device buffer beforeshutting it down */
3510c0d06caSMauro Carvalho Chehab 	while (buf && ++c < 500 &&
3520c0d06caSMauro Carvalho Chehab 	       !usb_bulk_msg(dev->udev,
3530c0d06caSMauro Carvalho Chehab 			     usb_rcvbulkpipe(dev->udev,
3540c0d06caSMauro Carvalho Chehab 					     dev->bulk_in_endpointAddr),
3550c0d06caSMauro Carvalho Chehab 			     buf, dev->bulk_in_size, &actual_length,
3560c0d06caSMauro Carvalho Chehab 			     BULK_URB_TIMEOUT)) {
3570c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3580c0d06caSMauro Carvalho Chehab 			 "%2d: got %d bytes\n", c, actual_length);
3590c0d06caSMauro Carvalho Chehab 	}
3600c0d06caSMauro Carvalho Chehab 	kfree(buf);
3610c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3620c0d06caSMauro Carvalho Chehab 		 "used %d urbs to empty device buffers\n", c-1);
3630c0d06caSMauro Carvalho Chehab 	msleep(10);
3640c0d06caSMauro Carvalho Chehab 
3650c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_IDLE;
3660c0d06caSMauro Carvalho Chehab 
3670c0d06caSMauro Carvalho Chehab 	return 0;
3680c0d06caSMauro Carvalho Chehab }
3690c0d06caSMauro Carvalho Chehab 
3700c0d06caSMauro Carvalho Chehab 
3710c0d06caSMauro Carvalho Chehab /*=======================================================================*/
3720c0d06caSMauro Carvalho Chehab /*
3730c0d06caSMauro Carvalho Chehab  * video 4 linux 2 file operations
3740c0d06caSMauro Carvalho Chehab  */
3750c0d06caSMauro Carvalho Chehab 
3763315c59aSHans Verkuil static int hdpvr_open(struct file *file)
3773315c59aSHans Verkuil {
3783315c59aSHans Verkuil 	struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL);
3793315c59aSHans Verkuil 
3803315c59aSHans Verkuil 	if (fh == NULL)
3813315c59aSHans Verkuil 		return -ENOMEM;
3823315c59aSHans Verkuil 	fh->legacy_mode = true;
3833315c59aSHans Verkuil 	v4l2_fh_init(&fh->fh, video_devdata(file));
3843315c59aSHans Verkuil 	v4l2_fh_add(&fh->fh);
3853315c59aSHans Verkuil 	file->private_data = fh;
3863315c59aSHans Verkuil 	return 0;
3873315c59aSHans Verkuil }
3883315c59aSHans Verkuil 
3890c0d06caSMauro Carvalho Chehab static int hdpvr_release(struct file *file)
3900c0d06caSMauro Carvalho Chehab {
391ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
3920c0d06caSMauro Carvalho Chehab 
3930c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
394ede197aaSHans Verkuil 	if (file->private_data == dev->owner) {
3950c0d06caSMauro Carvalho Chehab 		hdpvr_stop_streaming(dev);
396ede197aaSHans Verkuil 		dev->owner = NULL;
397ede197aaSHans Verkuil 	}
3980c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3990c0d06caSMauro Carvalho Chehab 
400ede197aaSHans Verkuil 	return v4l2_fh_release(file);
4010c0d06caSMauro Carvalho Chehab }
4020c0d06caSMauro Carvalho Chehab 
4030c0d06caSMauro Carvalho Chehab /*
4040c0d06caSMauro Carvalho Chehab  * hdpvr_v4l2_read()
4050c0d06caSMauro Carvalho Chehab  * will allocate buffers when called for the first time
4060c0d06caSMauro Carvalho Chehab  */
4070c0d06caSMauro Carvalho Chehab static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
4080c0d06caSMauro Carvalho Chehab 			  loff_t *pos)
4090c0d06caSMauro Carvalho Chehab {
410ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
4110c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
4120c0d06caSMauro Carvalho Chehab 	struct urb *urb;
4130c0d06caSMauro Carvalho Chehab 	unsigned int ret = 0;
4140c0d06caSMauro Carvalho Chehab 	int rem, cnt;
4150c0d06caSMauro Carvalho Chehab 
4160c0d06caSMauro Carvalho Chehab 	if (*pos)
4170c0d06caSMauro Carvalho Chehab 		return -ESPIPE;
4180c0d06caSMauro Carvalho Chehab 
4190c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
4200c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
4210c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
4220c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
4230c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
4240c0d06caSMauro Carvalho Chehab 			ret = -EIO;
4250c0d06caSMauro Carvalho Chehab 			msleep(200);
4260c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
4270c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
4280c0d06caSMauro Carvalho Chehab 			goto err;
4290c0d06caSMauro Carvalho Chehab 		}
430ede197aaSHans Verkuil 		dev->owner = file->private_data;
4310c0d06caSMauro Carvalho Chehab 		print_buffer_status();
4320c0d06caSMauro Carvalho Chehab 	}
4330c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
4340c0d06caSMauro Carvalho Chehab 
4350c0d06caSMauro Carvalho Chehab 	/* wait for the first buffer */
4360c0d06caSMauro Carvalho Chehab 	if (!(file->f_flags & O_NONBLOCK)) {
4370c0d06caSMauro Carvalho Chehab 		if (wait_event_interruptible(dev->wait_data,
4380c0d06caSMauro Carvalho Chehab 					     hdpvr_get_next_buffer(dev)))
4390c0d06caSMauro Carvalho Chehab 			return -ERESTARTSYS;
4400c0d06caSMauro Carvalho Chehab 	}
4410c0d06caSMauro Carvalho Chehab 
4420c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
4430c0d06caSMauro Carvalho Chehab 
4440c0d06caSMauro Carvalho Chehab 	while (count > 0 && buf) {
4450c0d06caSMauro Carvalho Chehab 
4460c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY &&
4470c0d06caSMauro Carvalho Chehab 		    dev->status != STATUS_DISCONNECTED) {
448a503ff81SJonathan Sims 			int err;
4490c0d06caSMauro Carvalho Chehab 			/* return nonblocking */
4500c0d06caSMauro Carvalho Chehab 			if (file->f_flags & O_NONBLOCK) {
4510c0d06caSMauro Carvalho Chehab 				if (!ret)
4520c0d06caSMauro Carvalho Chehab 					ret = -EAGAIN;
4530c0d06caSMauro Carvalho Chehab 				goto err;
4540c0d06caSMauro Carvalho Chehab 			}
4550c0d06caSMauro Carvalho Chehab 
456a503ff81SJonathan Sims 			err = wait_event_interruptible_timeout(dev->wait_data,
457a503ff81SJonathan Sims 				buf->status == BUFSTAT_READY,
458a503ff81SJonathan Sims 				msecs_to_jiffies(1000));
459a503ff81SJonathan Sims 			if (err < 0) {
460a503ff81SJonathan Sims 				ret = err;
461a503ff81SJonathan Sims 				goto err;
462a503ff81SJonathan Sims 			}
463a503ff81SJonathan Sims 			if (!err) {
464a503ff81SJonathan Sims 				v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
465a503ff81SJonathan Sims 					"timeout: restart streaming\n");
466a503ff81SJonathan Sims 				hdpvr_stop_streaming(dev);
467a503ff81SJonathan Sims 				msecs_to_jiffies(4000);
468a503ff81SJonathan Sims 				err = hdpvr_start_streaming(dev);
469a503ff81SJonathan Sims 				if (err) {
470a503ff81SJonathan Sims 					ret = err;
471a503ff81SJonathan Sims 					goto err;
472a503ff81SJonathan Sims 				}
473a503ff81SJonathan Sims 			}
4740c0d06caSMauro Carvalho Chehab 		}
4750c0d06caSMauro Carvalho Chehab 
4760c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY)
4770c0d06caSMauro Carvalho Chehab 			break;
4780c0d06caSMauro Carvalho Chehab 
4790c0d06caSMauro Carvalho Chehab 		/* set remaining bytes to copy */
4800c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
4810c0d06caSMauro Carvalho Chehab 		rem = urb->actual_length - buf->pos;
4820c0d06caSMauro Carvalho Chehab 		cnt = rem > count ? count : rem;
4830c0d06caSMauro Carvalho Chehab 
4840c0d06caSMauro Carvalho Chehab 		if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
4850c0d06caSMauro Carvalho Chehab 				 cnt)) {
4860c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
4870c0d06caSMauro Carvalho Chehab 			if (!ret)
4880c0d06caSMauro Carvalho Chehab 				ret = -EFAULT;
4890c0d06caSMauro Carvalho Chehab 			goto err;
4900c0d06caSMauro Carvalho Chehab 		}
4910c0d06caSMauro Carvalho Chehab 
4920c0d06caSMauro Carvalho Chehab 		buf->pos += cnt;
4930c0d06caSMauro Carvalho Chehab 		count -= cnt;
4940c0d06caSMauro Carvalho Chehab 		buffer += cnt;
4950c0d06caSMauro Carvalho Chehab 		ret += cnt;
4960c0d06caSMauro Carvalho Chehab 
4970c0d06caSMauro Carvalho Chehab 		/* finished, take next buffer */
4980c0d06caSMauro Carvalho Chehab 		if (buf->pos == urb->actual_length) {
4990c0d06caSMauro Carvalho Chehab 			mutex_lock(&dev->io_mutex);
5000c0d06caSMauro Carvalho Chehab 			buf->pos = 0;
5010c0d06caSMauro Carvalho Chehab 			buf->status = BUFSTAT_AVAILABLE;
5020c0d06caSMauro Carvalho Chehab 
5030c0d06caSMauro Carvalho Chehab 			list_move_tail(&buf->buff_list, &dev->free_buff_list);
5040c0d06caSMauro Carvalho Chehab 
5050c0d06caSMauro Carvalho Chehab 			print_buffer_status();
5060c0d06caSMauro Carvalho Chehab 
5070c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
5080c0d06caSMauro Carvalho Chehab 
5090c0d06caSMauro Carvalho Chehab 			wake_up_interruptible(&dev->wait_buffer);
5100c0d06caSMauro Carvalho Chehab 
5110c0d06caSMauro Carvalho Chehab 			buf = hdpvr_get_next_buffer(dev);
5120c0d06caSMauro Carvalho Chehab 		}
5130c0d06caSMauro Carvalho Chehab 	}
5140c0d06caSMauro Carvalho Chehab err:
5150c0d06caSMauro Carvalho Chehab 	if (!ret && !buf)
5160c0d06caSMauro Carvalho Chehab 		ret = -EAGAIN;
5170c0d06caSMauro Carvalho Chehab 	return ret;
5180c0d06caSMauro Carvalho Chehab }
5190c0d06caSMauro Carvalho Chehab 
520c23e0cb8SAl Viro static __poll_t hdpvr_poll(struct file *filp, poll_table *wait)
5210c0d06caSMauro Carvalho Chehab {
52201699437SAl Viro 	__poll_t req_events = poll_requested_events(wait);
5230c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
524ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(filp);
525c23e0cb8SAl Viro 	__poll_t mask = v4l2_ctrl_poll(filp, wait);
52665fe42d6SHans Verkuil 
527a9a08845SLinus Torvalds 	if (!(req_events & (EPOLLIN | EPOLLRDNORM)))
52865fe42d6SHans Verkuil 		return mask;
5290c0d06caSMauro Carvalho Chehab 
5300c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
5310c0d06caSMauro Carvalho Chehab 
5320c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
5330c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
5340c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
5350c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
5360c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
537ede197aaSHans Verkuil 		} else {
538ede197aaSHans Verkuil 			dev->owner = filp->private_data;
5390c0d06caSMauro Carvalho Chehab 		}
5400c0d06caSMauro Carvalho Chehab 
5410c0d06caSMauro Carvalho Chehab 		print_buffer_status();
5420c0d06caSMauro Carvalho Chehab 	}
5430c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
5440c0d06caSMauro Carvalho Chehab 
5450c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
5460c0d06caSMauro Carvalho Chehab 	/* only wait if no data is available */
5470c0d06caSMauro Carvalho Chehab 	if (!buf || buf->status != BUFSTAT_READY) {
5480c0d06caSMauro Carvalho Chehab 		poll_wait(filp, &dev->wait_data, wait);
5490c0d06caSMauro Carvalho Chehab 		buf = hdpvr_get_next_buffer(dev);
5500c0d06caSMauro Carvalho Chehab 	}
5510c0d06caSMauro Carvalho Chehab 	if (buf && buf->status == BUFSTAT_READY)
552a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
5530c0d06caSMauro Carvalho Chehab 
5540c0d06caSMauro Carvalho Chehab 	return mask;
5550c0d06caSMauro Carvalho Chehab }
5560c0d06caSMauro Carvalho Chehab 
5570c0d06caSMauro Carvalho Chehab 
5580c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations hdpvr_fops = {
5590c0d06caSMauro Carvalho Chehab 	.owner		= THIS_MODULE,
5603315c59aSHans Verkuil 	.open		= hdpvr_open,
5610c0d06caSMauro Carvalho Chehab 	.release	= hdpvr_release,
5620c0d06caSMauro Carvalho Chehab 	.read		= hdpvr_read,
5630c0d06caSMauro Carvalho Chehab 	.poll		= hdpvr_poll,
5640c0d06caSMauro Carvalho Chehab 	.unlocked_ioctl	= video_ioctl2,
5650c0d06caSMauro Carvalho Chehab };
5660c0d06caSMauro Carvalho Chehab 
5670c0d06caSMauro Carvalho Chehab /*=======================================================================*/
5680c0d06caSMauro Carvalho Chehab /*
5690c0d06caSMauro Carvalho Chehab  * V4L2 ioctl handling
5700c0d06caSMauro Carvalho Chehab  */
5710c0d06caSMauro Carvalho Chehab 
5720c0d06caSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void  *priv,
5730c0d06caSMauro Carvalho Chehab 			   struct v4l2_capability *cap)
5740c0d06caSMauro Carvalho Chehab {
5750c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_drvdata(file);
5760c0d06caSMauro Carvalho Chehab 
577cc1e6315SMauro Carvalho Chehab 	strscpy(cap->driver, "hdpvr", sizeof(cap->driver));
578cc1e6315SMauro Carvalho Chehab 	strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card));
5790c0d06caSMauro Carvalho Chehab 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
58041022fcbSHans Verkuil 	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
5810c0d06caSMauro Carvalho Chehab 			    V4L2_CAP_READWRITE;
58241022fcbSHans Verkuil 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
5830c0d06caSMauro Carvalho Chehab 	return 0;
5840c0d06caSMauro Carvalho Chehab }
5850c0d06caSMauro Carvalho Chehab 
5865854bf88SHans Verkuil static int vidioc_s_std(struct file *file, void *_fh,
587314527acSHans Verkuil 			v4l2_std_id std)
5880c0d06caSMauro Carvalho Chehab {
589ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
5905854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
5910c0d06caSMauro Carvalho Chehab 	u8 std_type = 1;
5920c0d06caSMauro Carvalho Chehab 
5935854bf88SHans Verkuil 	if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
5948f69da95SHans Verkuil 		return -ENODATA;
5958f69da95SHans Verkuil 	if (dev->status != STATUS_IDLE)
5968f69da95SHans Verkuil 		return -EBUSY;
5978f69da95SHans Verkuil 	if (std & V4L2_STD_525_60)
5980c0d06caSMauro Carvalho Chehab 		std_type = 0;
5998f69da95SHans Verkuil 	dev->cur_std = std;
6008f69da95SHans Verkuil 	dev->width = 720;
6018f69da95SHans Verkuil 	dev->height = std_type ? 576 : 480;
6020c0d06caSMauro Carvalho Chehab 
6030c0d06caSMauro Carvalho Chehab 	return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
6040c0d06caSMauro Carvalho Chehab }
6050c0d06caSMauro Carvalho Chehab 
6065854bf88SHans Verkuil static int vidioc_g_std(struct file *file, void *_fh,
6078f69da95SHans Verkuil 			v4l2_std_id *std)
6088f69da95SHans Verkuil {
6098f69da95SHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6105854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
6118f69da95SHans Verkuil 
6125854bf88SHans Verkuil 	if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
6138f69da95SHans Verkuil 		return -ENODATA;
6148f69da95SHans Verkuil 	*std = dev->cur_std;
6158f69da95SHans Verkuil 	return 0;
6168f69da95SHans Verkuil }
6178f69da95SHans Verkuil 
6185854bf88SHans Verkuil static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a)
6198f69da95SHans Verkuil {
6208f69da95SHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6214d601c4cSLeonid Kegulskiy 	struct hdpvr_video_info vid_info;
6225854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
6234d601c4cSLeonid Kegulskiy 	int ret;
6248f69da95SHans Verkuil 
625ab6e134aSHans Verkuil 	*a = V4L2_STD_UNKNOWN;
6265854bf88SHans Verkuil 	if (dev->options.video_input == HDPVR_COMPONENT)
6275854bf88SHans Verkuil 		return fh->legacy_mode ? 0 : -ENODATA;
6284d601c4cSLeonid Kegulskiy 	ret = get_video_info(dev, &vid_info);
6295f454d82SHans Verkuil 	if (vid_info.valid && vid_info.width == 720 &&
6304d601c4cSLeonid Kegulskiy 	    (vid_info.height == 480 || vid_info.height == 576)) {
6314d601c4cSLeonid Kegulskiy 		*a = (vid_info.height == 480) ?
6328f69da95SHans Verkuil 			V4L2_STD_525_60 : V4L2_STD_625_50;
6338f69da95SHans Verkuil 	}
6345f454d82SHans Verkuil 	return ret;
6358f69da95SHans Verkuil }
6368f69da95SHans Verkuil 
6373315c59aSHans Verkuil static int vidioc_s_dv_timings(struct file *file, void *_fh,
6383315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6393315c59aSHans Verkuil {
6403315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6413315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6423315c59aSHans Verkuil 	int i;
6433315c59aSHans Verkuil 
6443315c59aSHans Verkuil 	fh->legacy_mode = false;
6453315c59aSHans Verkuil 	if (dev->options.video_input)
6463315c59aSHans Verkuil 		return -ENODATA;
6473315c59aSHans Verkuil 	if (dev->status != STATUS_IDLE)
6483315c59aSHans Verkuil 		return -EBUSY;
6493315c59aSHans Verkuil 	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
65085f9e06cSHans Verkuil 		if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false))
6513315c59aSHans Verkuil 			break;
6523315c59aSHans Verkuil 	if (i == ARRAY_SIZE(hdpvr_dv_timings))
6533315c59aSHans Verkuil 		return -EINVAL;
6543315c59aSHans Verkuil 	dev->cur_dv_timings = hdpvr_dv_timings[i];
6553315c59aSHans Verkuil 	dev->width = hdpvr_dv_timings[i].bt.width;
6563315c59aSHans Verkuil 	dev->height = hdpvr_dv_timings[i].bt.height;
6573315c59aSHans Verkuil 	return 0;
6583315c59aSHans Verkuil }
6593315c59aSHans Verkuil 
6603315c59aSHans Verkuil static int vidioc_g_dv_timings(struct file *file, void *_fh,
6613315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6623315c59aSHans Verkuil {
6633315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6643315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6653315c59aSHans Verkuil 
6663315c59aSHans Verkuil 	fh->legacy_mode = false;
6673315c59aSHans Verkuil 	if (dev->options.video_input)
6683315c59aSHans Verkuil 		return -ENODATA;
6693315c59aSHans Verkuil 	*timings = dev->cur_dv_timings;
6703315c59aSHans Verkuil 	return 0;
6713315c59aSHans Verkuil }
6723315c59aSHans Verkuil 
6733315c59aSHans Verkuil static int vidioc_query_dv_timings(struct file *file, void *_fh,
6743315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6753315c59aSHans Verkuil {
6763315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6773315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6784d601c4cSLeonid Kegulskiy 	struct hdpvr_video_info vid_info;
6793315c59aSHans Verkuil 	bool interlaced;
6803315c59aSHans Verkuil 	int ret = 0;
6813315c59aSHans Verkuil 	int i;
6823315c59aSHans Verkuil 
6833315c59aSHans Verkuil 	fh->legacy_mode = false;
6843315c59aSHans Verkuil 	if (dev->options.video_input)
6853315c59aSHans Verkuil 		return -ENODATA;
6864d601c4cSLeonid Kegulskiy 	ret = get_video_info(dev, &vid_info);
6874d601c4cSLeonid Kegulskiy 	if (ret)
6885f454d82SHans Verkuil 		return ret;
6895f454d82SHans Verkuil 	if (!vid_info.valid)
6903315c59aSHans Verkuil 		return -ENOLCK;
6914d601c4cSLeonid Kegulskiy 	interlaced = vid_info.fps <= 30;
6923315c59aSHans Verkuil 	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
6933315c59aSHans Verkuil 		const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
6943315c59aSHans Verkuil 		unsigned hsize;
6953315c59aSHans Verkuil 		unsigned vsize;
6963315c59aSHans Verkuil 		unsigned fps;
6973315c59aSHans Verkuil 
698eacf8f9aSHans Verkuil 		hsize = V4L2_DV_BT_FRAME_WIDTH(bt);
699eacf8f9aSHans Verkuil 		vsize = V4L2_DV_BT_FRAME_HEIGHT(bt);
7003315c59aSHans Verkuil 		fps = (unsigned)bt->pixelclock / (hsize * vsize);
7014d601c4cSLeonid Kegulskiy 		if (bt->width != vid_info.width ||
7024d601c4cSLeonid Kegulskiy 		    bt->height != vid_info.height ||
7033315c59aSHans Verkuil 		    bt->interlaced != interlaced ||
7044d601c4cSLeonid Kegulskiy 		    (fps != vid_info.fps && fps + 1 != vid_info.fps))
7053315c59aSHans Verkuil 			continue;
7063315c59aSHans Verkuil 		*timings = hdpvr_dv_timings[i];
7073315c59aSHans Verkuil 		break;
7083315c59aSHans Verkuil 	}
7093315c59aSHans Verkuil 	if (i == ARRAY_SIZE(hdpvr_dv_timings))
7103315c59aSHans Verkuil 		ret = -ERANGE;
7114d601c4cSLeonid Kegulskiy 
7123315c59aSHans Verkuil 	return ret;
7133315c59aSHans Verkuil }
7143315c59aSHans Verkuil 
7153315c59aSHans Verkuil static int vidioc_enum_dv_timings(struct file *file, void *_fh,
7163315c59aSHans Verkuil 				    struct v4l2_enum_dv_timings *timings)
7173315c59aSHans Verkuil {
7183315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7193315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
7203315c59aSHans Verkuil 
7213315c59aSHans Verkuil 	fh->legacy_mode = false;
7223315c59aSHans Verkuil 	memset(timings->reserved, 0, sizeof(timings->reserved));
7233315c59aSHans Verkuil 	if (dev->options.video_input)
7243315c59aSHans Verkuil 		return -ENODATA;
7253315c59aSHans Verkuil 	if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings))
7263315c59aSHans Verkuil 		return -EINVAL;
7273315c59aSHans Verkuil 	timings->timings = hdpvr_dv_timings[timings->index];
7283315c59aSHans Verkuil 	return 0;
7293315c59aSHans Verkuil }
7303315c59aSHans Verkuil 
7313315c59aSHans Verkuil static int vidioc_dv_timings_cap(struct file *file, void *_fh,
7323315c59aSHans Verkuil 				    struct v4l2_dv_timings_cap *cap)
7333315c59aSHans Verkuil {
7343315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7353315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
7363315c59aSHans Verkuil 
7373315c59aSHans Verkuil 	fh->legacy_mode = false;
7383315c59aSHans Verkuil 	if (dev->options.video_input)
7393315c59aSHans Verkuil 		return -ENODATA;
7403315c59aSHans Verkuil 	cap->type = V4L2_DV_BT_656_1120;
7413315c59aSHans Verkuil 	cap->bt.min_width = 720;
7423315c59aSHans Verkuil 	cap->bt.max_width = 1920;
7433315c59aSHans Verkuil 	cap->bt.min_height = 480;
7443315c59aSHans Verkuil 	cap->bt.max_height = 1080;
7453315c59aSHans Verkuil 	cap->bt.min_pixelclock = 27000000;
7463315c59aSHans Verkuil 	cap->bt.max_pixelclock = 74250000;
7473315c59aSHans Verkuil 	cap->bt.standards = V4L2_DV_BT_STD_CEA861;
7483315c59aSHans Verkuil 	cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE;
7493315c59aSHans Verkuil 	return 0;
7503315c59aSHans Verkuil }
7513315c59aSHans Verkuil 
7520c0d06caSMauro Carvalho Chehab static const char *iname[] = {
7530c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPONENT] = "Component",
7540c0d06caSMauro Carvalho Chehab 	[HDPVR_SVIDEO]    = "S-Video",
7550c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPOSITE] = "Composite",
7560c0d06caSMauro Carvalho Chehab };
7570c0d06caSMauro Carvalho Chehab 
7585854bf88SHans Verkuil static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i)
7590c0d06caSMauro Carvalho Chehab {
7600c0d06caSMauro Carvalho Chehab 	unsigned int n;
7610c0d06caSMauro Carvalho Chehab 
7620c0d06caSMauro Carvalho Chehab 	n = i->index;
7630c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_VIDEO_INPUTS)
7640c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7650c0d06caSMauro Carvalho Chehab 
7660c0d06caSMauro Carvalho Chehab 	i->type = V4L2_INPUT_TYPE_CAMERA;
7670c0d06caSMauro Carvalho Chehab 
76885709cbfSMauro Carvalho Chehab 	strscpy(i->name, iname[n], sizeof(i->name));
7690c0d06caSMauro Carvalho Chehab 
7700c0d06caSMauro Carvalho Chehab 	i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
7710c0d06caSMauro Carvalho Chehab 
7728f69da95SHans Verkuil 	i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS;
7738f69da95SHans Verkuil 	i->std = n ? V4L2_STD_ALL : 0;
7740c0d06caSMauro Carvalho Chehab 
7750c0d06caSMauro Carvalho Chehab 	return 0;
7760c0d06caSMauro Carvalho Chehab }
7770c0d06caSMauro Carvalho Chehab 
7785854bf88SHans Verkuil static int vidioc_s_input(struct file *file, void *_fh,
7790c0d06caSMauro Carvalho Chehab 			  unsigned int index)
7800c0d06caSMauro Carvalho Chehab {
781ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7820c0d06caSMauro Carvalho Chehab 	int retval;
7830c0d06caSMauro Carvalho Chehab 
7840c0d06caSMauro Carvalho Chehab 	if (index >= HDPVR_VIDEO_INPUTS)
7850c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7860c0d06caSMauro Carvalho Chehab 
7870c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
78897caa318SHans Verkuil 		return -EBUSY;
7890c0d06caSMauro Carvalho Chehab 
7900c0d06caSMauro Carvalho Chehab 	retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
7918f69da95SHans Verkuil 	if (!retval) {
7920c0d06caSMauro Carvalho Chehab 		dev->options.video_input = index;
7935854bf88SHans Verkuil 		/*
7945854bf88SHans Verkuil 		 * Unfortunately gstreamer calls ENUMSTD and bails out if it
7955854bf88SHans Verkuil 		 * won't find any formats, even though component input is
7965854bf88SHans Verkuil 		 * selected. This means that we have to leave tvnorms at
7975854bf88SHans Verkuil 		 * V4L2_STD_ALL. We cannot use the 'legacy' trick since
7985854bf88SHans Verkuil 		 * tvnorms is set at the device node level and not at the
7995854bf88SHans Verkuil 		 * filehandle level.
8005854bf88SHans Verkuil 		 *
8015854bf88SHans Verkuil 		 * Comment this out for now, but if the legacy mode can be
8025854bf88SHans Verkuil 		 * removed in the future, then this code should be enabled
8035854bf88SHans Verkuil 		 * again.
8044b30409bSHans Verkuil 		dev->video_dev.tvnorms =
8055854bf88SHans Verkuil 			(index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0;
8065854bf88SHans Verkuil 		 */
8078f69da95SHans Verkuil 	}
8080c0d06caSMauro Carvalho Chehab 
8090c0d06caSMauro Carvalho Chehab 	return retval;
8100c0d06caSMauro Carvalho Chehab }
8110c0d06caSMauro Carvalho Chehab 
8120c0d06caSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *private_data,
8130c0d06caSMauro Carvalho Chehab 			  unsigned int *index)
8140c0d06caSMauro Carvalho Chehab {
815ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8160c0d06caSMauro Carvalho Chehab 
8170c0d06caSMauro Carvalho Chehab 	*index = dev->options.video_input;
8180c0d06caSMauro Carvalho Chehab 	return 0;
8190c0d06caSMauro Carvalho Chehab }
8200c0d06caSMauro Carvalho Chehab 
8210c0d06caSMauro Carvalho Chehab 
8220c0d06caSMauro Carvalho Chehab static const char *audio_iname[] = {
8230c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_FRONT] = "RCA front",
8240c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_BACK]  = "RCA back",
8250c0d06caSMauro Carvalho Chehab 	[HDPVR_SPDIF]     = "SPDIF",
8260c0d06caSMauro Carvalho Chehab };
8270c0d06caSMauro Carvalho Chehab 
8280c0d06caSMauro Carvalho Chehab static int vidioc_enumaudio(struct file *file, void *priv,
8290c0d06caSMauro Carvalho Chehab 				struct v4l2_audio *audio)
8300c0d06caSMauro Carvalho Chehab {
8310c0d06caSMauro Carvalho Chehab 	unsigned int n;
8320c0d06caSMauro Carvalho Chehab 
8330c0d06caSMauro Carvalho Chehab 	n = audio->index;
8340c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_AUDIO_INPUTS)
8350c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8360c0d06caSMauro Carvalho Chehab 
8370c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
8380c0d06caSMauro Carvalho Chehab 
83985709cbfSMauro Carvalho Chehab 	strscpy(audio->name, audio_iname[n], sizeof(audio->name));
8400c0d06caSMauro Carvalho Chehab 
8410c0d06caSMauro Carvalho Chehab 	return 0;
8420c0d06caSMauro Carvalho Chehab }
8430c0d06caSMauro Carvalho Chehab 
8440c0d06caSMauro Carvalho Chehab static int vidioc_s_audio(struct file *file, void *private_data,
8450e8025b9SHans Verkuil 			  const struct v4l2_audio *audio)
8460c0d06caSMauro Carvalho Chehab {
847ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8480c0d06caSMauro Carvalho Chehab 	int retval;
8490c0d06caSMauro Carvalho Chehab 
8500c0d06caSMauro Carvalho Chehab 	if (audio->index >= HDPVR_AUDIO_INPUTS)
8510c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8520c0d06caSMauro Carvalho Chehab 
8530c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
85497caa318SHans Verkuil 		return -EBUSY;
8550c0d06caSMauro Carvalho Chehab 
8560c0d06caSMauro Carvalho Chehab 	retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
8570c0d06caSMauro Carvalho Chehab 	if (!retval)
8580c0d06caSMauro Carvalho Chehab 		dev->options.audio_input = audio->index;
8590c0d06caSMauro Carvalho Chehab 
8600c0d06caSMauro Carvalho Chehab 	return retval;
8610c0d06caSMauro Carvalho Chehab }
8620c0d06caSMauro Carvalho Chehab 
8630c0d06caSMauro Carvalho Chehab static int vidioc_g_audio(struct file *file, void *private_data,
8640c0d06caSMauro Carvalho Chehab 			  struct v4l2_audio *audio)
8650c0d06caSMauro Carvalho Chehab {
866ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8670c0d06caSMauro Carvalho Chehab 
8680c0d06caSMauro Carvalho Chehab 	audio->index = dev->options.audio_input;
8690c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
870c0decac1SMauro Carvalho Chehab 	strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
8710c0d06caSMauro Carvalho Chehab 	return 0;
8720c0d06caSMauro Carvalho Chehab }
8730c0d06caSMauro Carvalho Chehab 
87499c77aa4SHans Verkuil static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl)
8750c0d06caSMauro Carvalho Chehab {
87699c77aa4SHans Verkuil 	struct hdpvr_device *dev =
87799c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
8780c0d06caSMauro Carvalho Chehab 
8790c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
88099c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
88199c77aa4SHans Verkuil 		if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
88299c77aa4SHans Verkuil 		    dev->video_bitrate->val >= dev->video_bitrate_peak->val)
88399c77aa4SHans Verkuil 			dev->video_bitrate_peak->val =
88499c77aa4SHans Verkuil 					dev->video_bitrate->val + 100000;
8850c0d06caSMauro Carvalho Chehab 		break;
8860c0d06caSMauro Carvalho Chehab 	}
8870c0d06caSMauro Carvalho Chehab 	return 0;
8880c0d06caSMauro Carvalho Chehab }
8890c0d06caSMauro Carvalho Chehab 
89099c77aa4SHans Verkuil static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
8910c0d06caSMauro Carvalho Chehab {
89299c77aa4SHans Verkuil 	struct hdpvr_device *dev =
89399c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
89499c77aa4SHans Verkuil 	struct hdpvr_options *opt = &dev->options;
8950c0d06caSMauro Carvalho Chehab 	int ret = -EINVAL;
8960c0d06caSMauro Carvalho Chehab 
8970c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
89899c77aa4SHans Verkuil 	case V4L2_CID_BRIGHTNESS:
89999c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val);
90099c77aa4SHans Verkuil 		if (ret)
9010c0d06caSMauro Carvalho Chehab 			break;
90299c77aa4SHans Verkuil 		dev->options.brightness = ctrl->val;
90399c77aa4SHans Verkuil 		return 0;
90499c77aa4SHans Verkuil 	case V4L2_CID_CONTRAST:
90599c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val);
90699c77aa4SHans Verkuil 		if (ret)
9070c0d06caSMauro Carvalho Chehab 			break;
90899c77aa4SHans Verkuil 		dev->options.contrast = ctrl->val;
90999c77aa4SHans Verkuil 		return 0;
91099c77aa4SHans Verkuil 	case V4L2_CID_SATURATION:
91199c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val);
91299c77aa4SHans Verkuil 		if (ret)
9130c0d06caSMauro Carvalho Chehab 			break;
91499c77aa4SHans Verkuil 		dev->options.saturation = ctrl->val;
91599c77aa4SHans Verkuil 		return 0;
91699c77aa4SHans Verkuil 	case V4L2_CID_HUE:
91799c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val);
91899c77aa4SHans Verkuil 		if (ret)
9190c0d06caSMauro Carvalho Chehab 			break;
92099c77aa4SHans Verkuil 		dev->options.hue = ctrl->val;
92199c77aa4SHans Verkuil 		return 0;
92299c77aa4SHans Verkuil 	case V4L2_CID_SHARPNESS:
92399c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val);
92499c77aa4SHans Verkuil 		if (ret)
9250c0d06caSMauro Carvalho Chehab 			break;
92699c77aa4SHans Verkuil 		dev->options.sharpness = ctrl->val;
92799c77aa4SHans Verkuil 		return 0;
9280c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
9290c0d06caSMauro Carvalho Chehab 		if (dev->flags & HDPVR_FLAG_AC3_CAP) {
93099c77aa4SHans Verkuil 			opt->audio_codec = ctrl->val;
9313445857bSHans Verkuil 			return hdpvr_set_audio(dev, opt->audio_input + 1,
9320c0d06caSMauro Carvalho Chehab 					      opt->audio_codec);
9330c0d06caSMauro Carvalho Chehab 		}
93499c77aa4SHans Verkuil 		return 0;
9350c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
93699c77aa4SHans Verkuil 		return 0;
9370c0d06caSMauro Carvalho Chehab /*	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
9380c0d06caSMauro Carvalho Chehab /*		if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
9390c0d06caSMauro Carvalho Chehab /*			opt->gop_mode |= 0x2; */
9400c0d06caSMauro Carvalho Chehab /*			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
9410c0d06caSMauro Carvalho Chehab /*					  opt->gop_mode); */
9420c0d06caSMauro Carvalho Chehab /*		} */
9430c0d06caSMauro Carvalho Chehab /*		if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
9440c0d06caSMauro Carvalho Chehab /*			opt->gop_mode &= ~0x2; */
9450c0d06caSMauro Carvalho Chehab /*			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
9460c0d06caSMauro Carvalho Chehab /*					  opt->gop_mode); */
9470c0d06caSMauro Carvalho Chehab /*		} */
9480c0d06caSMauro Carvalho Chehab /*		break; */
94999c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
95099c77aa4SHans Verkuil 		uint peak_bitrate = dev->video_bitrate_peak->val / 100000;
95199c77aa4SHans Verkuil 		uint bitrate = dev->video_bitrate->val / 100000;
95299c77aa4SHans Verkuil 
95399c77aa4SHans Verkuil 		if (ctrl->is_new) {
95499c77aa4SHans Verkuil 			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
9550c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_CONSTANT;
95699c77aa4SHans Verkuil 			else
9570c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
9580c0d06caSMauro Carvalho Chehab 			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
9590c0d06caSMauro Carvalho Chehab 					  opt->bitrate_mode);
96099c77aa4SHans Verkuil 			v4l2_ctrl_activate(dev->video_bitrate_peak,
96199c77aa4SHans Verkuil 				ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
9620c0d06caSMauro Carvalho Chehab 		}
9630c0d06caSMauro Carvalho Chehab 
96499c77aa4SHans Verkuil 		if (dev->video_bitrate_peak->is_new ||
96599c77aa4SHans Verkuil 		    dev->video_bitrate->is_new) {
9660c0d06caSMauro Carvalho Chehab 			opt->bitrate = bitrate;
9670c0d06caSMauro Carvalho Chehab 			opt->peak_bitrate = peak_bitrate;
9680c0d06caSMauro Carvalho Chehab 			hdpvr_set_bitrate(dev);
96999c77aa4SHans Verkuil 		}
97099c77aa4SHans Verkuil 		return 0;
9710c0d06caSMauro Carvalho Chehab 	}
9720c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_STREAM_TYPE:
97399c77aa4SHans Verkuil 		return 0;
9740c0d06caSMauro Carvalho Chehab 	default:
97599c77aa4SHans Verkuil 		break;
9760c0d06caSMauro Carvalho Chehab 	}
9770c0d06caSMauro Carvalho Chehab 	return ret;
9780c0d06caSMauro Carvalho Chehab }
9790c0d06caSMauro Carvalho Chehab 
9800c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
9810c0d06caSMauro Carvalho Chehab 				    struct v4l2_fmtdesc *f)
9820c0d06caSMauro Carvalho Chehab {
98397caa318SHans Verkuil 	if (f->index != 0)
9840c0d06caSMauro Carvalho Chehab 		return -EINVAL;
9850c0d06caSMauro Carvalho Chehab 
9860c0d06caSMauro Carvalho Chehab 	f->flags = V4L2_FMT_FLAG_COMPRESSED;
98785709cbfSMauro Carvalho Chehab 	strscpy(f->description, "MPEG2-TS with AVC/AAC streams",
98885709cbfSMauro Carvalho Chehab 		sizeof(f->description));
9890c0d06caSMauro Carvalho Chehab 	f->pixelformat = V4L2_PIX_FMT_MPEG;
9900c0d06caSMauro Carvalho Chehab 
9910c0d06caSMauro Carvalho Chehab 	return 0;
9920c0d06caSMauro Carvalho Chehab }
9930c0d06caSMauro Carvalho Chehab 
9943315c59aSHans Verkuil static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
9950c0d06caSMauro Carvalho Chehab 				struct v4l2_format *f)
9960c0d06caSMauro Carvalho Chehab {
997ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
9983315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
9994d601c4cSLeonid Kegulskiy 	int ret;
10000c0d06caSMauro Carvalho Chehab 
10013315c59aSHans Verkuil 	/*
10023315c59aSHans Verkuil 	 * The original driver would always returns the current detected
10033315c59aSHans Verkuil 	 * resolution as the format (and EFAULT if it couldn't be detected).
10043315c59aSHans Verkuil 	 * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a
10053315c59aSHans Verkuil 	 * better way of doing this, but to stay compatible with existing
10063315c59aSHans Verkuil 	 * applications we assume legacy mode every time an application opens
10073315c59aSHans Verkuil 	 * the device. Only if one of the new DV_TIMINGS ioctls is called
10083315c59aSHans Verkuil 	 * will the filehandle go into 'normal' mode where g_fmt returns the
10093315c59aSHans Verkuil 	 * last set format.
10103315c59aSHans Verkuil 	 */
10113315c59aSHans Verkuil 	if (fh->legacy_mode) {
10124d601c4cSLeonid Kegulskiy 		struct hdpvr_video_info vid_info;
10130c0d06caSMauro Carvalho Chehab 
10144d601c4cSLeonid Kegulskiy 		ret = get_video_info(dev, &vid_info);
10155f454d82SHans Verkuil 		if (ret < 0)
10165f454d82SHans Verkuil 			return ret;
10175f454d82SHans Verkuil 		if (!vid_info.valid)
10180c0d06caSMauro Carvalho Chehab 			return -EFAULT;
10194d601c4cSLeonid Kegulskiy 		f->fmt.pix.width = vid_info.width;
10204d601c4cSLeonid Kegulskiy 		f->fmt.pix.height = vid_info.height;
10213315c59aSHans Verkuil 	} else {
10223315c59aSHans Verkuil 		f->fmt.pix.width = dev->width;
10233315c59aSHans Verkuil 		f->fmt.pix.height = dev->height;
10243315c59aSHans Verkuil 	}
10253315c59aSHans Verkuil 	f->fmt.pix.pixelformat	= V4L2_PIX_FMT_MPEG;
10263315c59aSHans Verkuil 	f->fmt.pix.sizeimage	= dev->bulk_in_size;
10273315c59aSHans Verkuil 	f->fmt.pix.bytesperline	= 0;
10283315c59aSHans Verkuil 	if (f->fmt.pix.width == 720) {
10293315c59aSHans Verkuil 		/* SDTV formats */
10303315c59aSHans Verkuil 		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
10313315c59aSHans Verkuil 		f->fmt.pix.field = V4L2_FIELD_INTERLACED;
10323315c59aSHans Verkuil 	} else {
10333315c59aSHans Verkuil 		/* HDTV formats */
103493e6a855SHans Verkuil 		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
10353315c59aSHans Verkuil 		f->fmt.pix.field = V4L2_FIELD_NONE;
10363315c59aSHans Verkuil 	}
10370c0d06caSMauro Carvalho Chehab 	return 0;
10380c0d06caSMauro Carvalho Chehab }
10390c0d06caSMauro Carvalho Chehab 
10400c0d06caSMauro Carvalho Chehab static int vidioc_encoder_cmd(struct file *filp, void *priv,
10410c0d06caSMauro Carvalho Chehab 			       struct v4l2_encoder_cmd *a)
10420c0d06caSMauro Carvalho Chehab {
1043ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(filp);
1044ede197aaSHans Verkuil 	int res = 0;
10450c0d06caSMauro Carvalho Chehab 
10460c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
1047ede197aaSHans Verkuil 	a->flags = 0;
10480c0d06caSMauro Carvalho Chehab 
10490c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
10500c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
1051ede197aaSHans Verkuil 		if (dev->owner && filp->private_data != dev->owner) {
1052ede197aaSHans Verkuil 			res = -EBUSY;
1053ede197aaSHans Verkuil 			break;
1054ede197aaSHans Verkuil 		}
1055ede197aaSHans Verkuil 		if (dev->status == STATUS_STREAMING)
1056ede197aaSHans Verkuil 			break;
10570c0d06caSMauro Carvalho Chehab 		res = hdpvr_start_streaming(dev);
1058ede197aaSHans Verkuil 		if (!res)
1059ede197aaSHans Verkuil 			dev->owner = filp->private_data;
1060ede197aaSHans Verkuil 		else
1061ede197aaSHans Verkuil 			dev->status = STATUS_IDLE;
10620c0d06caSMauro Carvalho Chehab 		break;
10630c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
1064ede197aaSHans Verkuil 		if (dev->owner && filp->private_data != dev->owner) {
1065ede197aaSHans Verkuil 			res = -EBUSY;
1066ede197aaSHans Verkuil 			break;
1067ede197aaSHans Verkuil 		}
1068ede197aaSHans Verkuil 		if (dev->status == STATUS_IDLE)
1069ede197aaSHans Verkuil 			break;
10700c0d06caSMauro Carvalho Chehab 		res = hdpvr_stop_streaming(dev);
1071ede197aaSHans Verkuil 		if (!res)
1072ede197aaSHans Verkuil 			dev->owner = NULL;
10730c0d06caSMauro Carvalho Chehab 		break;
10740c0d06caSMauro Carvalho Chehab 	default:
10750c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
10760c0d06caSMauro Carvalho Chehab 			 "Unsupported encoder cmd %d\n", a->cmd);
10770c0d06caSMauro Carvalho Chehab 		res = -EINVAL;
1078ede197aaSHans Verkuil 		break;
10790c0d06caSMauro Carvalho Chehab 	}
1080ede197aaSHans Verkuil 
10810c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
10820c0d06caSMauro Carvalho Chehab 	return res;
10830c0d06caSMauro Carvalho Chehab }
10840c0d06caSMauro Carvalho Chehab 
10850c0d06caSMauro Carvalho Chehab static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
10860c0d06caSMauro Carvalho Chehab 					struct v4l2_encoder_cmd *a)
10870c0d06caSMauro Carvalho Chehab {
1088ede197aaSHans Verkuil 	a->flags = 0;
10890c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
10900c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
10910c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
10920c0d06caSMauro Carvalho Chehab 		return 0;
10930c0d06caSMauro Carvalho Chehab 	default:
10940c0d06caSMauro Carvalho Chehab 		return -EINVAL;
10950c0d06caSMauro Carvalho Chehab 	}
10960c0d06caSMauro Carvalho Chehab }
10970c0d06caSMauro Carvalho Chehab 
10980c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
10990c0d06caSMauro Carvalho Chehab 	.vidioc_querycap	= vidioc_querycap,
11000c0d06caSMauro Carvalho Chehab 	.vidioc_s_std		= vidioc_s_std,
11018f69da95SHans Verkuil 	.vidioc_g_std		= vidioc_g_std,
11028f69da95SHans Verkuil 	.vidioc_querystd	= vidioc_querystd,
11033315c59aSHans Verkuil 	.vidioc_s_dv_timings	= vidioc_s_dv_timings,
11043315c59aSHans Verkuil 	.vidioc_g_dv_timings	= vidioc_g_dv_timings,
11053315c59aSHans Verkuil 	.vidioc_query_dv_timings= vidioc_query_dv_timings,
11063315c59aSHans Verkuil 	.vidioc_enum_dv_timings	= vidioc_enum_dv_timings,
11073315c59aSHans Verkuil 	.vidioc_dv_timings_cap	= vidioc_dv_timings_cap,
11080c0d06caSMauro Carvalho Chehab 	.vidioc_enum_input	= vidioc_enum_input,
11090c0d06caSMauro Carvalho Chehab 	.vidioc_g_input		= vidioc_g_input,
11100c0d06caSMauro Carvalho Chehab 	.vidioc_s_input		= vidioc_s_input,
11110c0d06caSMauro Carvalho Chehab 	.vidioc_enumaudio	= vidioc_enumaudio,
11120c0d06caSMauro Carvalho Chehab 	.vidioc_g_audio		= vidioc_g_audio,
11130c0d06caSMauro Carvalho Chehab 	.vidioc_s_audio		= vidioc_s_audio,
11140c0d06caSMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap,
11150c0d06caSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
11163315c59aSHans Verkuil 	.vidioc_s_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
11173315c59aSHans Verkuil 	.vidioc_try_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
11180c0d06caSMauro Carvalho Chehab 	.vidioc_encoder_cmd	= vidioc_encoder_cmd,
11190c0d06caSMauro Carvalho Chehab 	.vidioc_try_encoder_cmd	= vidioc_try_encoder_cmd,
112065fe42d6SHans Verkuil 	.vidioc_log_status	= v4l2_ctrl_log_status,
112165fe42d6SHans Verkuil 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
112265fe42d6SHans Verkuil 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
11230c0d06caSMauro Carvalho Chehab };
11240c0d06caSMauro Carvalho Chehab 
11250c0d06caSMauro Carvalho Chehab static void hdpvr_device_release(struct video_device *vdev)
11260c0d06caSMauro Carvalho Chehab {
11270c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_get_drvdata(vdev);
11280c0d06caSMauro Carvalho Chehab 
11290c0d06caSMauro Carvalho Chehab 	hdpvr_delete(dev);
11300c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
11315612e191SBhaktipriya Shridhar 	flush_work(&dev->worker);
11320c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
11330c0d06caSMauro Carvalho Chehab 
11340c0d06caSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
113599c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(&dev->hdl);
11360c0d06caSMauro Carvalho Chehab 
11370c0d06caSMauro Carvalho Chehab 	/* deregister I2C adapter */
113854d80904SMauro Carvalho Chehab #if IS_ENABLED(CONFIG_I2C)
11390c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->i2c_mutex);
11400c0d06caSMauro Carvalho Chehab 	i2c_del_adapter(&dev->i2c_adapter);
11410c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->i2c_mutex);
11420c0d06caSMauro Carvalho Chehab #endif /* CONFIG_I2C */
11430c0d06caSMauro Carvalho Chehab 
11440c0d06caSMauro Carvalho Chehab 	kfree(dev->usbc_buf);
11450c0d06caSMauro Carvalho Chehab 	kfree(dev);
11460c0d06caSMauro Carvalho Chehab }
11470c0d06caSMauro Carvalho Chehab 
11480c0d06caSMauro Carvalho Chehab static const struct video_device hdpvr_video_template = {
11490c0d06caSMauro Carvalho Chehab 	.fops			= &hdpvr_fops,
11500c0d06caSMauro Carvalho Chehab 	.release		= hdpvr_device_release,
11510c0d06caSMauro Carvalho Chehab 	.ioctl_ops		= &hdpvr_ioctl_ops,
11525854bf88SHans Verkuil 	.tvnorms		= V4L2_STD_ALL,
11530c0d06caSMauro Carvalho Chehab };
11540c0d06caSMauro Carvalho Chehab 
115599c77aa4SHans Verkuil static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
115699c77aa4SHans Verkuil 	.try_ctrl = hdpvr_try_ctrl,
115799c77aa4SHans Verkuil 	.s_ctrl = hdpvr_s_ctrl,
115899c77aa4SHans Verkuil };
115999c77aa4SHans Verkuil 
11600c0d06caSMauro Carvalho Chehab int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
11610c0d06caSMauro Carvalho Chehab 			    int devnum)
11620c0d06caSMauro Carvalho Chehab {
116399c77aa4SHans Verkuil 	struct v4l2_ctrl_handler *hdl = &dev->hdl;
116499c77aa4SHans Verkuil 	bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
116599c77aa4SHans Verkuil 	int res;
116699c77aa4SHans Verkuil 
11678f69da95SHans Verkuil 	dev->cur_std = V4L2_STD_525_60;
11688f69da95SHans Verkuil 	dev->width = 720;
11698f69da95SHans Verkuil 	dev->height = 480;
11703315c59aSHans Verkuil 	dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX];
117199c77aa4SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 11);
117299c77aa4SHans Verkuil 	if (dev->fw_ver > 0x15) {
117399c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
117499c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80);
117599c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
117699c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40);
117799c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
117899c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40);
117999c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118099c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf);
118199c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118299c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
118399c77aa4SHans Verkuil 	} else {
118499c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118599c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86);
118699c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118799c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80);
118899c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118999c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80);
119099c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119199c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0xff, 1, 0x80);
119299c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119399c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
119499c77aa4SHans Verkuil 	}
119599c77aa4SHans Verkuil 
119699c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
119799c77aa4SHans Verkuil 		V4L2_CID_MPEG_STREAM_TYPE,
119899c77aa4SHans Verkuil 		V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
119999c77aa4SHans Verkuil 		0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
120099c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120199c77aa4SHans Verkuil 		V4L2_CID_MPEG_AUDIO_ENCODING,
120299c77aa4SHans Verkuil 		ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
12033445857bSHans Verkuil 		0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC);
120499c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120599c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_ENCODING,
120699c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
120799c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
120899c77aa4SHans Verkuil 
120999c77aa4SHans Verkuil 	dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
121099c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
121199c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
121299c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
121399c77aa4SHans Verkuil 
121499c77aa4SHans Verkuil 	dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
121599c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE,
121699c77aa4SHans Verkuil 		1000000, 13500000, 100000, 6500000);
121799c77aa4SHans Verkuil 	dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
121899c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
121999c77aa4SHans Verkuil 		1100000, 20200000, 100000, 9000000);
122099c77aa4SHans Verkuil 	dev->v4l2_dev.ctrl_handler = hdl;
122199c77aa4SHans Verkuil 	if (hdl->error) {
122299c77aa4SHans Verkuil 		res = hdl->error;
122399c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not register controls\n");
122499c77aa4SHans Verkuil 		goto error;
122599c77aa4SHans Verkuil 	}
122699c77aa4SHans Verkuil 	v4l2_ctrl_cluster(3, &dev->video_mode);
122799c77aa4SHans Verkuil 	res = v4l2_ctrl_handler_setup(hdl);
122899c77aa4SHans Verkuil 	if (res < 0) {
122999c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not setup controls\n");
123099c77aa4SHans Verkuil 		goto error;
123199c77aa4SHans Verkuil 	}
123299c77aa4SHans Verkuil 
12330c0d06caSMauro Carvalho Chehab 	/* setup and register video device */
12344b30409bSHans Verkuil 	dev->video_dev = hdpvr_video_template;
1235cc1e6315SMauro Carvalho Chehab 	strscpy(dev->video_dev.name, "Hauppauge HD PVR",
1236cc1e6315SMauro Carvalho Chehab 		sizeof(dev->video_dev.name));
12374b30409bSHans Verkuil 	dev->video_dev.v4l2_dev = &dev->v4l2_dev;
12384b30409bSHans Verkuil 	video_set_drvdata(&dev->video_dev, dev);
12390c0d06caSMauro Carvalho Chehab 
12404b30409bSHans Verkuil 	res = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, devnum);
124199c77aa4SHans Verkuil 	if (res < 0) {
12420c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
12430c0d06caSMauro Carvalho Chehab 		goto error;
12440c0d06caSMauro Carvalho Chehab 	}
12450c0d06caSMauro Carvalho Chehab 
12460c0d06caSMauro Carvalho Chehab 	return 0;
12470c0d06caSMauro Carvalho Chehab error:
124899c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(hdl);
124999c77aa4SHans Verkuil 	return res;
12500c0d06caSMauro Carvalho Chehab }
1251