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,
4386bc5a4a1SHans Verkuil 					     !list_empty_careful(&dev->rec_buff_list)))
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) {
4646bc5a4a1SHans Verkuil 				v4l2_info(&dev->v4l2_dev,
465a503ff81SJonathan Sims 					  "timeout: restart streaming\n");
4666bc5a4a1SHans Verkuil 				mutex_lock(&dev->io_mutex);
467a503ff81SJonathan Sims 				hdpvr_stop_streaming(dev);
4686bc5a4a1SHans Verkuil 				mutex_unlock(&dev->io_mutex);
4696bc5a4a1SHans Verkuil 				/*
4706bc5a4a1SHans Verkuil 				 * The FW needs about 4 seconds after streaming
4716bc5a4a1SHans Verkuil 				 * stopped before it is ready to restart
4726bc5a4a1SHans Verkuil 				 * streaming.
4736bc5a4a1SHans Verkuil 				 */
4746bc5a4a1SHans Verkuil 				msleep(4000);
475a503ff81SJonathan Sims 				err = hdpvr_start_streaming(dev);
476a503ff81SJonathan Sims 				if (err) {
477a503ff81SJonathan Sims 					ret = err;
478a503ff81SJonathan Sims 					goto err;
479a503ff81SJonathan Sims 				}
480a503ff81SJonathan Sims 			}
4810c0d06caSMauro Carvalho Chehab 		}
4820c0d06caSMauro Carvalho Chehab 
4830c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY)
4840c0d06caSMauro Carvalho Chehab 			break;
4850c0d06caSMauro Carvalho Chehab 
4860c0d06caSMauro Carvalho Chehab 		/* set remaining bytes to copy */
4870c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
4880c0d06caSMauro Carvalho Chehab 		rem = urb->actual_length - buf->pos;
4890c0d06caSMauro Carvalho Chehab 		cnt = rem > count ? count : rem;
4900c0d06caSMauro Carvalho Chehab 
4910c0d06caSMauro Carvalho Chehab 		if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
4920c0d06caSMauro Carvalho Chehab 				 cnt)) {
4930c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
4940c0d06caSMauro Carvalho Chehab 			if (!ret)
4950c0d06caSMauro Carvalho Chehab 				ret = -EFAULT;
4960c0d06caSMauro Carvalho Chehab 			goto err;
4970c0d06caSMauro Carvalho Chehab 		}
4980c0d06caSMauro Carvalho Chehab 
4990c0d06caSMauro Carvalho Chehab 		buf->pos += cnt;
5000c0d06caSMauro Carvalho Chehab 		count -= cnt;
5010c0d06caSMauro Carvalho Chehab 		buffer += cnt;
5020c0d06caSMauro Carvalho Chehab 		ret += cnt;
5030c0d06caSMauro Carvalho Chehab 
5040c0d06caSMauro Carvalho Chehab 		/* finished, take next buffer */
5050c0d06caSMauro Carvalho Chehab 		if (buf->pos == urb->actual_length) {
5060c0d06caSMauro Carvalho Chehab 			mutex_lock(&dev->io_mutex);
5070c0d06caSMauro Carvalho Chehab 			buf->pos = 0;
5080c0d06caSMauro Carvalho Chehab 			buf->status = BUFSTAT_AVAILABLE;
5090c0d06caSMauro Carvalho Chehab 
5100c0d06caSMauro Carvalho Chehab 			list_move_tail(&buf->buff_list, &dev->free_buff_list);
5110c0d06caSMauro Carvalho Chehab 
5120c0d06caSMauro Carvalho Chehab 			print_buffer_status();
5130c0d06caSMauro Carvalho Chehab 
5140c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
5150c0d06caSMauro Carvalho Chehab 
5160c0d06caSMauro Carvalho Chehab 			wake_up_interruptible(&dev->wait_buffer);
5170c0d06caSMauro Carvalho Chehab 
5180c0d06caSMauro Carvalho Chehab 			buf = hdpvr_get_next_buffer(dev);
5190c0d06caSMauro Carvalho Chehab 		}
5200c0d06caSMauro Carvalho Chehab 	}
5210c0d06caSMauro Carvalho Chehab err:
5220c0d06caSMauro Carvalho Chehab 	if (!ret && !buf)
5230c0d06caSMauro Carvalho Chehab 		ret = -EAGAIN;
5240c0d06caSMauro Carvalho Chehab 	return ret;
5250c0d06caSMauro Carvalho Chehab }
5260c0d06caSMauro Carvalho Chehab 
527c23e0cb8SAl Viro static __poll_t hdpvr_poll(struct file *filp, poll_table *wait)
5280c0d06caSMauro Carvalho Chehab {
52901699437SAl Viro 	__poll_t req_events = poll_requested_events(wait);
5300c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
531ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(filp);
532c23e0cb8SAl Viro 	__poll_t mask = v4l2_ctrl_poll(filp, wait);
53365fe42d6SHans Verkuil 
534a9a08845SLinus Torvalds 	if (!(req_events & (EPOLLIN | EPOLLRDNORM)))
53565fe42d6SHans Verkuil 		return mask;
5360c0d06caSMauro Carvalho Chehab 
5370c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
5380c0d06caSMauro Carvalho Chehab 
5390c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
5400c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
5410c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
5420c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
5430c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
544ede197aaSHans Verkuil 		} else {
545ede197aaSHans Verkuil 			dev->owner = filp->private_data;
5460c0d06caSMauro Carvalho Chehab 		}
5470c0d06caSMauro Carvalho Chehab 
5480c0d06caSMauro Carvalho Chehab 		print_buffer_status();
5490c0d06caSMauro Carvalho Chehab 	}
5500c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
5510c0d06caSMauro Carvalho Chehab 
5520c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
5530c0d06caSMauro Carvalho Chehab 	/* only wait if no data is available */
5540c0d06caSMauro Carvalho Chehab 	if (!buf || buf->status != BUFSTAT_READY) {
5550c0d06caSMauro Carvalho Chehab 		poll_wait(filp, &dev->wait_data, wait);
5560c0d06caSMauro Carvalho Chehab 		buf = hdpvr_get_next_buffer(dev);
5570c0d06caSMauro Carvalho Chehab 	}
5580c0d06caSMauro Carvalho Chehab 	if (buf && buf->status == BUFSTAT_READY)
559a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
5600c0d06caSMauro Carvalho Chehab 
5610c0d06caSMauro Carvalho Chehab 	return mask;
5620c0d06caSMauro Carvalho Chehab }
5630c0d06caSMauro Carvalho Chehab 
5640c0d06caSMauro Carvalho Chehab 
5650c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations hdpvr_fops = {
5660c0d06caSMauro Carvalho Chehab 	.owner		= THIS_MODULE,
5673315c59aSHans Verkuil 	.open		= hdpvr_open,
5680c0d06caSMauro Carvalho Chehab 	.release	= hdpvr_release,
5690c0d06caSMauro Carvalho Chehab 	.read		= hdpvr_read,
5700c0d06caSMauro Carvalho Chehab 	.poll		= hdpvr_poll,
5710c0d06caSMauro Carvalho Chehab 	.unlocked_ioctl	= video_ioctl2,
5720c0d06caSMauro Carvalho Chehab };
5730c0d06caSMauro Carvalho Chehab 
5740c0d06caSMauro Carvalho Chehab /*=======================================================================*/
5750c0d06caSMauro Carvalho Chehab /*
5760c0d06caSMauro Carvalho Chehab  * V4L2 ioctl handling
5770c0d06caSMauro Carvalho Chehab  */
5780c0d06caSMauro Carvalho Chehab 
5790c0d06caSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void  *priv,
5800c0d06caSMauro Carvalho Chehab 			   struct v4l2_capability *cap)
5810c0d06caSMauro Carvalho Chehab {
5820c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_drvdata(file);
5830c0d06caSMauro Carvalho Chehab 
584cc1e6315SMauro Carvalho Chehab 	strscpy(cap->driver, "hdpvr", sizeof(cap->driver));
585cc1e6315SMauro Carvalho Chehab 	strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card));
5860c0d06caSMauro Carvalho Chehab 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
5870c0d06caSMauro Carvalho Chehab 	return 0;
5880c0d06caSMauro Carvalho Chehab }
5890c0d06caSMauro Carvalho Chehab 
5905854bf88SHans Verkuil static int vidioc_s_std(struct file *file, void *_fh,
591314527acSHans Verkuil 			v4l2_std_id std)
5920c0d06caSMauro Carvalho Chehab {
593ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
5945854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
5950c0d06caSMauro Carvalho Chehab 	u8 std_type = 1;
5960c0d06caSMauro Carvalho Chehab 
5975854bf88SHans Verkuil 	if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
5988f69da95SHans Verkuil 		return -ENODATA;
5998f69da95SHans Verkuil 	if (dev->status != STATUS_IDLE)
6008f69da95SHans Verkuil 		return -EBUSY;
6018f69da95SHans Verkuil 	if (std & V4L2_STD_525_60)
6020c0d06caSMauro Carvalho Chehab 		std_type = 0;
6038f69da95SHans Verkuil 	dev->cur_std = std;
6048f69da95SHans Verkuil 	dev->width = 720;
6058f69da95SHans Verkuil 	dev->height = std_type ? 576 : 480;
6060c0d06caSMauro Carvalho Chehab 
6070c0d06caSMauro Carvalho Chehab 	return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
6080c0d06caSMauro Carvalho Chehab }
6090c0d06caSMauro Carvalho Chehab 
6105854bf88SHans Verkuil static int vidioc_g_std(struct file *file, void *_fh,
6118f69da95SHans Verkuil 			v4l2_std_id *std)
6128f69da95SHans Verkuil {
6138f69da95SHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6145854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
6158f69da95SHans Verkuil 
6165854bf88SHans Verkuil 	if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
6178f69da95SHans Verkuil 		return -ENODATA;
6188f69da95SHans Verkuil 	*std = dev->cur_std;
6198f69da95SHans Verkuil 	return 0;
6208f69da95SHans Verkuil }
6218f69da95SHans Verkuil 
6225854bf88SHans Verkuil static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a)
6238f69da95SHans Verkuil {
6248f69da95SHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6254d601c4cSLeonid Kegulskiy 	struct hdpvr_video_info vid_info;
6265854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
6274d601c4cSLeonid Kegulskiy 	int ret;
6288f69da95SHans Verkuil 
629ab6e134aSHans Verkuil 	*a = V4L2_STD_UNKNOWN;
6305854bf88SHans Verkuil 	if (dev->options.video_input == HDPVR_COMPONENT)
6315854bf88SHans Verkuil 		return fh->legacy_mode ? 0 : -ENODATA;
6324d601c4cSLeonid Kegulskiy 	ret = get_video_info(dev, &vid_info);
6335f454d82SHans Verkuil 	if (vid_info.valid && vid_info.width == 720 &&
6344d601c4cSLeonid Kegulskiy 	    (vid_info.height == 480 || vid_info.height == 576)) {
6354d601c4cSLeonid Kegulskiy 		*a = (vid_info.height == 480) ?
6368f69da95SHans Verkuil 			V4L2_STD_525_60 : V4L2_STD_625_50;
6378f69da95SHans Verkuil 	}
6385f454d82SHans Verkuil 	return ret;
6398f69da95SHans Verkuil }
6408f69da95SHans Verkuil 
6413315c59aSHans Verkuil static int vidioc_s_dv_timings(struct file *file, void *_fh,
6423315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6433315c59aSHans Verkuil {
6443315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6453315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6463315c59aSHans Verkuil 	int i;
6473315c59aSHans Verkuil 
6483315c59aSHans Verkuil 	fh->legacy_mode = false;
6493315c59aSHans Verkuil 	if (dev->options.video_input)
6503315c59aSHans Verkuil 		return -ENODATA;
6513315c59aSHans Verkuil 	if (dev->status != STATUS_IDLE)
6523315c59aSHans Verkuil 		return -EBUSY;
6533315c59aSHans Verkuil 	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
65485f9e06cSHans Verkuil 		if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false))
6553315c59aSHans Verkuil 			break;
6563315c59aSHans Verkuil 	if (i == ARRAY_SIZE(hdpvr_dv_timings))
6573315c59aSHans Verkuil 		return -EINVAL;
6583315c59aSHans Verkuil 	dev->cur_dv_timings = hdpvr_dv_timings[i];
6593315c59aSHans Verkuil 	dev->width = hdpvr_dv_timings[i].bt.width;
6603315c59aSHans Verkuil 	dev->height = hdpvr_dv_timings[i].bt.height;
6613315c59aSHans Verkuil 	return 0;
6623315c59aSHans Verkuil }
6633315c59aSHans Verkuil 
6643315c59aSHans Verkuil static int vidioc_g_dv_timings(struct file *file, void *_fh,
6653315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6663315c59aSHans Verkuil {
6673315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6683315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6693315c59aSHans Verkuil 
6703315c59aSHans Verkuil 	fh->legacy_mode = false;
6713315c59aSHans Verkuil 	if (dev->options.video_input)
6723315c59aSHans Verkuil 		return -ENODATA;
6733315c59aSHans Verkuil 	*timings = dev->cur_dv_timings;
6743315c59aSHans Verkuil 	return 0;
6753315c59aSHans Verkuil }
6763315c59aSHans Verkuil 
6773315c59aSHans Verkuil static int vidioc_query_dv_timings(struct file *file, void *_fh,
6783315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6793315c59aSHans Verkuil {
6803315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6813315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6824d601c4cSLeonid Kegulskiy 	struct hdpvr_video_info vid_info;
6833315c59aSHans Verkuil 	bool interlaced;
6843315c59aSHans Verkuil 	int ret = 0;
6853315c59aSHans Verkuil 	int i;
6863315c59aSHans Verkuil 
6873315c59aSHans Verkuil 	fh->legacy_mode = false;
6883315c59aSHans Verkuil 	if (dev->options.video_input)
6893315c59aSHans Verkuil 		return -ENODATA;
6904d601c4cSLeonid Kegulskiy 	ret = get_video_info(dev, &vid_info);
6914d601c4cSLeonid Kegulskiy 	if (ret)
6925f454d82SHans Verkuil 		return ret;
6935f454d82SHans Verkuil 	if (!vid_info.valid)
6943315c59aSHans Verkuil 		return -ENOLCK;
6954d601c4cSLeonid Kegulskiy 	interlaced = vid_info.fps <= 30;
6963315c59aSHans Verkuil 	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
6973315c59aSHans Verkuil 		const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
6983315c59aSHans Verkuil 		unsigned hsize;
6993315c59aSHans Verkuil 		unsigned vsize;
7003315c59aSHans Verkuil 		unsigned fps;
7013315c59aSHans Verkuil 
702eacf8f9aSHans Verkuil 		hsize = V4L2_DV_BT_FRAME_WIDTH(bt);
703eacf8f9aSHans Verkuil 		vsize = V4L2_DV_BT_FRAME_HEIGHT(bt);
7043315c59aSHans Verkuil 		fps = (unsigned)bt->pixelclock / (hsize * vsize);
7054d601c4cSLeonid Kegulskiy 		if (bt->width != vid_info.width ||
7064d601c4cSLeonid Kegulskiy 		    bt->height != vid_info.height ||
7073315c59aSHans Verkuil 		    bt->interlaced != interlaced ||
7084d601c4cSLeonid Kegulskiy 		    (fps != vid_info.fps && fps + 1 != vid_info.fps))
7093315c59aSHans Verkuil 			continue;
7103315c59aSHans Verkuil 		*timings = hdpvr_dv_timings[i];
7113315c59aSHans Verkuil 		break;
7123315c59aSHans Verkuil 	}
7133315c59aSHans Verkuil 	if (i == ARRAY_SIZE(hdpvr_dv_timings))
7143315c59aSHans Verkuil 		ret = -ERANGE;
7154d601c4cSLeonid Kegulskiy 
7163315c59aSHans Verkuil 	return ret;
7173315c59aSHans Verkuil }
7183315c59aSHans Verkuil 
7193315c59aSHans Verkuil static int vidioc_enum_dv_timings(struct file *file, void *_fh,
7203315c59aSHans Verkuil 				    struct v4l2_enum_dv_timings *timings)
7213315c59aSHans Verkuil {
7223315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7233315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
7243315c59aSHans Verkuil 
7253315c59aSHans Verkuil 	fh->legacy_mode = false;
7263315c59aSHans Verkuil 	memset(timings->reserved, 0, sizeof(timings->reserved));
7273315c59aSHans Verkuil 	if (dev->options.video_input)
7283315c59aSHans Verkuil 		return -ENODATA;
7293315c59aSHans Verkuil 	if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings))
7303315c59aSHans Verkuil 		return -EINVAL;
7313315c59aSHans Verkuil 	timings->timings = hdpvr_dv_timings[timings->index];
7323315c59aSHans Verkuil 	return 0;
7333315c59aSHans Verkuil }
7343315c59aSHans Verkuil 
7353315c59aSHans Verkuil static int vidioc_dv_timings_cap(struct file *file, void *_fh,
7363315c59aSHans Verkuil 				    struct v4l2_dv_timings_cap *cap)
7373315c59aSHans Verkuil {
7383315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7393315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
7403315c59aSHans Verkuil 
7413315c59aSHans Verkuil 	fh->legacy_mode = false;
7423315c59aSHans Verkuil 	if (dev->options.video_input)
7433315c59aSHans Verkuil 		return -ENODATA;
7443315c59aSHans Verkuil 	cap->type = V4L2_DV_BT_656_1120;
7453315c59aSHans Verkuil 	cap->bt.min_width = 720;
7463315c59aSHans Verkuil 	cap->bt.max_width = 1920;
7473315c59aSHans Verkuil 	cap->bt.min_height = 480;
7483315c59aSHans Verkuil 	cap->bt.max_height = 1080;
7493315c59aSHans Verkuil 	cap->bt.min_pixelclock = 27000000;
7503315c59aSHans Verkuil 	cap->bt.max_pixelclock = 74250000;
7513315c59aSHans Verkuil 	cap->bt.standards = V4L2_DV_BT_STD_CEA861;
7523315c59aSHans Verkuil 	cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE;
7533315c59aSHans Verkuil 	return 0;
7543315c59aSHans Verkuil }
7553315c59aSHans Verkuil 
7560c0d06caSMauro Carvalho Chehab static const char *iname[] = {
7570c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPONENT] = "Component",
7580c0d06caSMauro Carvalho Chehab 	[HDPVR_SVIDEO]    = "S-Video",
7590c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPOSITE] = "Composite",
7600c0d06caSMauro Carvalho Chehab };
7610c0d06caSMauro Carvalho Chehab 
7625854bf88SHans Verkuil static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i)
7630c0d06caSMauro Carvalho Chehab {
7640c0d06caSMauro Carvalho Chehab 	unsigned int n;
7650c0d06caSMauro Carvalho Chehab 
7660c0d06caSMauro Carvalho Chehab 	n = i->index;
7670c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_VIDEO_INPUTS)
7680c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7690c0d06caSMauro Carvalho Chehab 
7700c0d06caSMauro Carvalho Chehab 	i->type = V4L2_INPUT_TYPE_CAMERA;
7710c0d06caSMauro Carvalho Chehab 
77285709cbfSMauro Carvalho Chehab 	strscpy(i->name, iname[n], sizeof(i->name));
7730c0d06caSMauro Carvalho Chehab 
7740c0d06caSMauro Carvalho Chehab 	i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
7750c0d06caSMauro Carvalho Chehab 
7768f69da95SHans Verkuil 	i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS;
7778f69da95SHans Verkuil 	i->std = n ? V4L2_STD_ALL : 0;
7780c0d06caSMauro Carvalho Chehab 
7790c0d06caSMauro Carvalho Chehab 	return 0;
7800c0d06caSMauro Carvalho Chehab }
7810c0d06caSMauro Carvalho Chehab 
7825854bf88SHans Verkuil static int vidioc_s_input(struct file *file, void *_fh,
7830c0d06caSMauro Carvalho Chehab 			  unsigned int index)
7840c0d06caSMauro Carvalho Chehab {
785ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7860c0d06caSMauro Carvalho Chehab 	int retval;
7870c0d06caSMauro Carvalho Chehab 
7880c0d06caSMauro Carvalho Chehab 	if (index >= HDPVR_VIDEO_INPUTS)
7890c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7900c0d06caSMauro Carvalho Chehab 
7910c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
79297caa318SHans Verkuil 		return -EBUSY;
7930c0d06caSMauro Carvalho Chehab 
7940c0d06caSMauro Carvalho Chehab 	retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
7958f69da95SHans Verkuil 	if (!retval) {
7960c0d06caSMauro Carvalho Chehab 		dev->options.video_input = index;
7975854bf88SHans Verkuil 		/*
7985854bf88SHans Verkuil 		 * Unfortunately gstreamer calls ENUMSTD and bails out if it
7995854bf88SHans Verkuil 		 * won't find any formats, even though component input is
8005854bf88SHans Verkuil 		 * selected. This means that we have to leave tvnorms at
8015854bf88SHans Verkuil 		 * V4L2_STD_ALL. We cannot use the 'legacy' trick since
8025854bf88SHans Verkuil 		 * tvnorms is set at the device node level and not at the
8035854bf88SHans Verkuil 		 * filehandle level.
8045854bf88SHans Verkuil 		 *
8055854bf88SHans Verkuil 		 * Comment this out for now, but if the legacy mode can be
8065854bf88SHans Verkuil 		 * removed in the future, then this code should be enabled
8075854bf88SHans Verkuil 		 * again.
8084b30409bSHans Verkuil 		dev->video_dev.tvnorms =
8095854bf88SHans Verkuil 			(index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0;
8105854bf88SHans Verkuil 		 */
8118f69da95SHans Verkuil 	}
8120c0d06caSMauro Carvalho Chehab 
8130c0d06caSMauro Carvalho Chehab 	return retval;
8140c0d06caSMauro Carvalho Chehab }
8150c0d06caSMauro Carvalho Chehab 
8160c0d06caSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *private_data,
8170c0d06caSMauro Carvalho Chehab 			  unsigned int *index)
8180c0d06caSMauro Carvalho Chehab {
819ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8200c0d06caSMauro Carvalho Chehab 
8210c0d06caSMauro Carvalho Chehab 	*index = dev->options.video_input;
8220c0d06caSMauro Carvalho Chehab 	return 0;
8230c0d06caSMauro Carvalho Chehab }
8240c0d06caSMauro Carvalho Chehab 
8250c0d06caSMauro Carvalho Chehab 
8260c0d06caSMauro Carvalho Chehab static const char *audio_iname[] = {
8270c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_FRONT] = "RCA front",
8280c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_BACK]  = "RCA back",
8290c0d06caSMauro Carvalho Chehab 	[HDPVR_SPDIF]     = "SPDIF",
8300c0d06caSMauro Carvalho Chehab };
8310c0d06caSMauro Carvalho Chehab 
8320c0d06caSMauro Carvalho Chehab static int vidioc_enumaudio(struct file *file, void *priv,
8330c0d06caSMauro Carvalho Chehab 				struct v4l2_audio *audio)
8340c0d06caSMauro Carvalho Chehab {
8350c0d06caSMauro Carvalho Chehab 	unsigned int n;
8360c0d06caSMauro Carvalho Chehab 
8370c0d06caSMauro Carvalho Chehab 	n = audio->index;
8380c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_AUDIO_INPUTS)
8390c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8400c0d06caSMauro Carvalho Chehab 
8410c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
8420c0d06caSMauro Carvalho Chehab 
84385709cbfSMauro Carvalho Chehab 	strscpy(audio->name, audio_iname[n], sizeof(audio->name));
8440c0d06caSMauro Carvalho Chehab 
8450c0d06caSMauro Carvalho Chehab 	return 0;
8460c0d06caSMauro Carvalho Chehab }
8470c0d06caSMauro Carvalho Chehab 
8480c0d06caSMauro Carvalho Chehab static int vidioc_s_audio(struct file *file, void *private_data,
8490e8025b9SHans Verkuil 			  const struct v4l2_audio *audio)
8500c0d06caSMauro Carvalho Chehab {
851ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8520c0d06caSMauro Carvalho Chehab 	int retval;
8530c0d06caSMauro Carvalho Chehab 
8540c0d06caSMauro Carvalho Chehab 	if (audio->index >= HDPVR_AUDIO_INPUTS)
8550c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8560c0d06caSMauro Carvalho Chehab 
8570c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
85897caa318SHans Verkuil 		return -EBUSY;
8590c0d06caSMauro Carvalho Chehab 
8600c0d06caSMauro Carvalho Chehab 	retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
8610c0d06caSMauro Carvalho Chehab 	if (!retval)
8620c0d06caSMauro Carvalho Chehab 		dev->options.audio_input = audio->index;
8630c0d06caSMauro Carvalho Chehab 
8640c0d06caSMauro Carvalho Chehab 	return retval;
8650c0d06caSMauro Carvalho Chehab }
8660c0d06caSMauro Carvalho Chehab 
8670c0d06caSMauro Carvalho Chehab static int vidioc_g_audio(struct file *file, void *private_data,
8680c0d06caSMauro Carvalho Chehab 			  struct v4l2_audio *audio)
8690c0d06caSMauro Carvalho Chehab {
870ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8710c0d06caSMauro Carvalho Chehab 
8720c0d06caSMauro Carvalho Chehab 	audio->index = dev->options.audio_input;
8730c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
874c0decac1SMauro Carvalho Chehab 	strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
8750c0d06caSMauro Carvalho Chehab 	return 0;
8760c0d06caSMauro Carvalho Chehab }
8770c0d06caSMauro Carvalho Chehab 
87899c77aa4SHans Verkuil static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl)
8790c0d06caSMauro Carvalho Chehab {
88099c77aa4SHans Verkuil 	struct hdpvr_device *dev =
88199c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
8820c0d06caSMauro Carvalho Chehab 
8830c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
88499c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
88599c77aa4SHans Verkuil 		if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
88699c77aa4SHans Verkuil 		    dev->video_bitrate->val >= dev->video_bitrate_peak->val)
88799c77aa4SHans Verkuil 			dev->video_bitrate_peak->val =
88899c77aa4SHans Verkuil 					dev->video_bitrate->val + 100000;
8890c0d06caSMauro Carvalho Chehab 		break;
8900c0d06caSMauro Carvalho Chehab 	}
8910c0d06caSMauro Carvalho Chehab 	return 0;
8920c0d06caSMauro Carvalho Chehab }
8930c0d06caSMauro Carvalho Chehab 
89499c77aa4SHans Verkuil static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
8950c0d06caSMauro Carvalho Chehab {
89699c77aa4SHans Verkuil 	struct hdpvr_device *dev =
89799c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
89899c77aa4SHans Verkuil 	struct hdpvr_options *opt = &dev->options;
8990c0d06caSMauro Carvalho Chehab 	int ret = -EINVAL;
9000c0d06caSMauro Carvalho Chehab 
9010c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
90299c77aa4SHans Verkuil 	case V4L2_CID_BRIGHTNESS:
90399c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val);
90499c77aa4SHans Verkuil 		if (ret)
9050c0d06caSMauro Carvalho Chehab 			break;
90699c77aa4SHans Verkuil 		dev->options.brightness = ctrl->val;
90799c77aa4SHans Verkuil 		return 0;
90899c77aa4SHans Verkuil 	case V4L2_CID_CONTRAST:
90999c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val);
91099c77aa4SHans Verkuil 		if (ret)
9110c0d06caSMauro Carvalho Chehab 			break;
91299c77aa4SHans Verkuil 		dev->options.contrast = ctrl->val;
91399c77aa4SHans Verkuil 		return 0;
91499c77aa4SHans Verkuil 	case V4L2_CID_SATURATION:
91599c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val);
91699c77aa4SHans Verkuil 		if (ret)
9170c0d06caSMauro Carvalho Chehab 			break;
91899c77aa4SHans Verkuil 		dev->options.saturation = ctrl->val;
91999c77aa4SHans Verkuil 		return 0;
92099c77aa4SHans Verkuil 	case V4L2_CID_HUE:
92199c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val);
92299c77aa4SHans Verkuil 		if (ret)
9230c0d06caSMauro Carvalho Chehab 			break;
92499c77aa4SHans Verkuil 		dev->options.hue = ctrl->val;
92599c77aa4SHans Verkuil 		return 0;
92699c77aa4SHans Verkuil 	case V4L2_CID_SHARPNESS:
92799c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val);
92899c77aa4SHans Verkuil 		if (ret)
9290c0d06caSMauro Carvalho Chehab 			break;
93099c77aa4SHans Verkuil 		dev->options.sharpness = ctrl->val;
93199c77aa4SHans Verkuil 		return 0;
9320c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
9330c0d06caSMauro Carvalho Chehab 		if (dev->flags & HDPVR_FLAG_AC3_CAP) {
93499c77aa4SHans Verkuil 			opt->audio_codec = ctrl->val;
9353445857bSHans Verkuil 			return hdpvr_set_audio(dev, opt->audio_input + 1,
9360c0d06caSMauro Carvalho Chehab 					      opt->audio_codec);
9370c0d06caSMauro Carvalho Chehab 		}
93899c77aa4SHans Verkuil 		return 0;
9390c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
94099c77aa4SHans Verkuil 		return 0;
9410c0d06caSMauro Carvalho Chehab /*	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
9420c0d06caSMauro Carvalho Chehab /*		if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
9430c0d06caSMauro Carvalho Chehab /*			opt->gop_mode |= 0x2; */
9440c0d06caSMauro Carvalho Chehab /*			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
9450c0d06caSMauro Carvalho Chehab /*					  opt->gop_mode); */
9460c0d06caSMauro Carvalho Chehab /*		} */
9470c0d06caSMauro Carvalho Chehab /*		if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
9480c0d06caSMauro Carvalho Chehab /*			opt->gop_mode &= ~0x2; */
9490c0d06caSMauro Carvalho Chehab /*			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
9500c0d06caSMauro Carvalho Chehab /*					  opt->gop_mode); */
9510c0d06caSMauro Carvalho Chehab /*		} */
9520c0d06caSMauro Carvalho Chehab /*		break; */
95399c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
95499c77aa4SHans Verkuil 		uint peak_bitrate = dev->video_bitrate_peak->val / 100000;
95599c77aa4SHans Verkuil 		uint bitrate = dev->video_bitrate->val / 100000;
95699c77aa4SHans Verkuil 
95799c77aa4SHans Verkuil 		if (ctrl->is_new) {
95899c77aa4SHans Verkuil 			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
9590c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_CONSTANT;
96099c77aa4SHans Verkuil 			else
9610c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
9620c0d06caSMauro Carvalho Chehab 			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
9630c0d06caSMauro Carvalho Chehab 					  opt->bitrate_mode);
96499c77aa4SHans Verkuil 			v4l2_ctrl_activate(dev->video_bitrate_peak,
96599c77aa4SHans Verkuil 				ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
9660c0d06caSMauro Carvalho Chehab 		}
9670c0d06caSMauro Carvalho Chehab 
96899c77aa4SHans Verkuil 		if (dev->video_bitrate_peak->is_new ||
96999c77aa4SHans Verkuil 		    dev->video_bitrate->is_new) {
9700c0d06caSMauro Carvalho Chehab 			opt->bitrate = bitrate;
9710c0d06caSMauro Carvalho Chehab 			opt->peak_bitrate = peak_bitrate;
9720c0d06caSMauro Carvalho Chehab 			hdpvr_set_bitrate(dev);
97399c77aa4SHans Verkuil 		}
97499c77aa4SHans Verkuil 		return 0;
9750c0d06caSMauro Carvalho Chehab 	}
9760c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_STREAM_TYPE:
97799c77aa4SHans Verkuil 		return 0;
9780c0d06caSMauro Carvalho Chehab 	default:
97999c77aa4SHans Verkuil 		break;
9800c0d06caSMauro Carvalho Chehab 	}
9810c0d06caSMauro Carvalho Chehab 	return ret;
9820c0d06caSMauro Carvalho Chehab }
9830c0d06caSMauro Carvalho Chehab 
9840c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
9850c0d06caSMauro Carvalho Chehab 				    struct v4l2_fmtdesc *f)
9860c0d06caSMauro Carvalho Chehab {
98797caa318SHans Verkuil 	if (f->index != 0)
9880c0d06caSMauro Carvalho Chehab 		return -EINVAL;
9890c0d06caSMauro Carvalho Chehab 
9900c0d06caSMauro Carvalho Chehab 	f->flags = V4L2_FMT_FLAG_COMPRESSED;
99185709cbfSMauro Carvalho Chehab 	strscpy(f->description, "MPEG2-TS with AVC/AAC streams",
99285709cbfSMauro Carvalho Chehab 		sizeof(f->description));
9930c0d06caSMauro Carvalho Chehab 	f->pixelformat = V4L2_PIX_FMT_MPEG;
9940c0d06caSMauro Carvalho Chehab 
9950c0d06caSMauro Carvalho Chehab 	return 0;
9960c0d06caSMauro Carvalho Chehab }
9970c0d06caSMauro Carvalho Chehab 
9983315c59aSHans Verkuil static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
9990c0d06caSMauro Carvalho Chehab 				struct v4l2_format *f)
10000c0d06caSMauro Carvalho Chehab {
1001ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
10023315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
10034d601c4cSLeonid Kegulskiy 	int ret;
10040c0d06caSMauro Carvalho Chehab 
10053315c59aSHans Verkuil 	/*
10063315c59aSHans Verkuil 	 * The original driver would always returns the current detected
10073315c59aSHans Verkuil 	 * resolution as the format (and EFAULT if it couldn't be detected).
10083315c59aSHans Verkuil 	 * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a
10093315c59aSHans Verkuil 	 * better way of doing this, but to stay compatible with existing
10103315c59aSHans Verkuil 	 * applications we assume legacy mode every time an application opens
10113315c59aSHans Verkuil 	 * the device. Only if one of the new DV_TIMINGS ioctls is called
10123315c59aSHans Verkuil 	 * will the filehandle go into 'normal' mode where g_fmt returns the
10133315c59aSHans Verkuil 	 * last set format.
10143315c59aSHans Verkuil 	 */
10153315c59aSHans Verkuil 	if (fh->legacy_mode) {
10164d601c4cSLeonid Kegulskiy 		struct hdpvr_video_info vid_info;
10170c0d06caSMauro Carvalho Chehab 
10184d601c4cSLeonid Kegulskiy 		ret = get_video_info(dev, &vid_info);
10195f454d82SHans Verkuil 		if (ret < 0)
10205f454d82SHans Verkuil 			return ret;
10215f454d82SHans Verkuil 		if (!vid_info.valid)
10220c0d06caSMauro Carvalho Chehab 			return -EFAULT;
10234d601c4cSLeonid Kegulskiy 		f->fmt.pix.width = vid_info.width;
10244d601c4cSLeonid Kegulskiy 		f->fmt.pix.height = vid_info.height;
10253315c59aSHans Verkuil 	} else {
10263315c59aSHans Verkuil 		f->fmt.pix.width = dev->width;
10273315c59aSHans Verkuil 		f->fmt.pix.height = dev->height;
10283315c59aSHans Verkuil 	}
10293315c59aSHans Verkuil 	f->fmt.pix.pixelformat	= V4L2_PIX_FMT_MPEG;
10303315c59aSHans Verkuil 	f->fmt.pix.sizeimage	= dev->bulk_in_size;
10313315c59aSHans Verkuil 	f->fmt.pix.bytesperline	= 0;
10323315c59aSHans Verkuil 	if (f->fmt.pix.width == 720) {
10333315c59aSHans Verkuil 		/* SDTV formats */
10343315c59aSHans Verkuil 		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
10353315c59aSHans Verkuil 		f->fmt.pix.field = V4L2_FIELD_INTERLACED;
10363315c59aSHans Verkuil 	} else {
10373315c59aSHans Verkuil 		/* HDTV formats */
103893e6a855SHans Verkuil 		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
10393315c59aSHans Verkuil 		f->fmt.pix.field = V4L2_FIELD_NONE;
10403315c59aSHans Verkuil 	}
10410c0d06caSMauro Carvalho Chehab 	return 0;
10420c0d06caSMauro Carvalho Chehab }
10430c0d06caSMauro Carvalho Chehab 
10440c0d06caSMauro Carvalho Chehab static int vidioc_encoder_cmd(struct file *filp, void *priv,
10450c0d06caSMauro Carvalho Chehab 			       struct v4l2_encoder_cmd *a)
10460c0d06caSMauro Carvalho Chehab {
1047ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(filp);
1048ede197aaSHans Verkuil 	int res = 0;
10490c0d06caSMauro Carvalho Chehab 
10500c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
1051ede197aaSHans Verkuil 	a->flags = 0;
10520c0d06caSMauro Carvalho Chehab 
10530c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
10540c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
1055ede197aaSHans Verkuil 		if (dev->owner && filp->private_data != dev->owner) {
1056ede197aaSHans Verkuil 			res = -EBUSY;
1057ede197aaSHans Verkuil 			break;
1058ede197aaSHans Verkuil 		}
1059ede197aaSHans Verkuil 		if (dev->status == STATUS_STREAMING)
1060ede197aaSHans Verkuil 			break;
10610c0d06caSMauro Carvalho Chehab 		res = hdpvr_start_streaming(dev);
1062ede197aaSHans Verkuil 		if (!res)
1063ede197aaSHans Verkuil 			dev->owner = filp->private_data;
1064ede197aaSHans Verkuil 		else
1065ede197aaSHans Verkuil 			dev->status = STATUS_IDLE;
10660c0d06caSMauro Carvalho Chehab 		break;
10670c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
1068ede197aaSHans Verkuil 		if (dev->owner && filp->private_data != dev->owner) {
1069ede197aaSHans Verkuil 			res = -EBUSY;
1070ede197aaSHans Verkuil 			break;
1071ede197aaSHans Verkuil 		}
1072ede197aaSHans Verkuil 		if (dev->status == STATUS_IDLE)
1073ede197aaSHans Verkuil 			break;
10740c0d06caSMauro Carvalho Chehab 		res = hdpvr_stop_streaming(dev);
1075ede197aaSHans Verkuil 		if (!res)
1076ede197aaSHans Verkuil 			dev->owner = NULL;
10770c0d06caSMauro Carvalho Chehab 		break;
10780c0d06caSMauro Carvalho Chehab 	default:
10790c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
10800c0d06caSMauro Carvalho Chehab 			 "Unsupported encoder cmd %d\n", a->cmd);
10810c0d06caSMauro Carvalho Chehab 		res = -EINVAL;
1082ede197aaSHans Verkuil 		break;
10830c0d06caSMauro Carvalho Chehab 	}
1084ede197aaSHans Verkuil 
10850c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
10860c0d06caSMauro Carvalho Chehab 	return res;
10870c0d06caSMauro Carvalho Chehab }
10880c0d06caSMauro Carvalho Chehab 
10890c0d06caSMauro Carvalho Chehab static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
10900c0d06caSMauro Carvalho Chehab 					struct v4l2_encoder_cmd *a)
10910c0d06caSMauro Carvalho Chehab {
1092ede197aaSHans Verkuil 	a->flags = 0;
10930c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
10940c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
10950c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
10960c0d06caSMauro Carvalho Chehab 		return 0;
10970c0d06caSMauro Carvalho Chehab 	default:
10980c0d06caSMauro Carvalho Chehab 		return -EINVAL;
10990c0d06caSMauro Carvalho Chehab 	}
11000c0d06caSMauro Carvalho Chehab }
11010c0d06caSMauro Carvalho Chehab 
11020c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
11030c0d06caSMauro Carvalho Chehab 	.vidioc_querycap	= vidioc_querycap,
11040c0d06caSMauro Carvalho Chehab 	.vidioc_s_std		= vidioc_s_std,
11058f69da95SHans Verkuil 	.vidioc_g_std		= vidioc_g_std,
11068f69da95SHans Verkuil 	.vidioc_querystd	= vidioc_querystd,
11073315c59aSHans Verkuil 	.vidioc_s_dv_timings	= vidioc_s_dv_timings,
11083315c59aSHans Verkuil 	.vidioc_g_dv_timings	= vidioc_g_dv_timings,
11093315c59aSHans Verkuil 	.vidioc_query_dv_timings= vidioc_query_dv_timings,
11103315c59aSHans Verkuil 	.vidioc_enum_dv_timings	= vidioc_enum_dv_timings,
11113315c59aSHans Verkuil 	.vidioc_dv_timings_cap	= vidioc_dv_timings_cap,
11120c0d06caSMauro Carvalho Chehab 	.vidioc_enum_input	= vidioc_enum_input,
11130c0d06caSMauro Carvalho Chehab 	.vidioc_g_input		= vidioc_g_input,
11140c0d06caSMauro Carvalho Chehab 	.vidioc_s_input		= vidioc_s_input,
11150c0d06caSMauro Carvalho Chehab 	.vidioc_enumaudio	= vidioc_enumaudio,
11160c0d06caSMauro Carvalho Chehab 	.vidioc_g_audio		= vidioc_g_audio,
11170c0d06caSMauro Carvalho Chehab 	.vidioc_s_audio		= vidioc_s_audio,
11180c0d06caSMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap,
11190c0d06caSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
11203315c59aSHans Verkuil 	.vidioc_s_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
11213315c59aSHans Verkuil 	.vidioc_try_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
11220c0d06caSMauro Carvalho Chehab 	.vidioc_encoder_cmd	= vidioc_encoder_cmd,
11230c0d06caSMauro Carvalho Chehab 	.vidioc_try_encoder_cmd	= vidioc_try_encoder_cmd,
112465fe42d6SHans Verkuil 	.vidioc_log_status	= v4l2_ctrl_log_status,
112565fe42d6SHans Verkuil 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
112665fe42d6SHans Verkuil 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
11270c0d06caSMauro Carvalho Chehab };
11280c0d06caSMauro Carvalho Chehab 
11290c0d06caSMauro Carvalho Chehab static void hdpvr_device_release(struct video_device *vdev)
11300c0d06caSMauro Carvalho Chehab {
11310c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_get_drvdata(vdev);
11320c0d06caSMauro Carvalho Chehab 
11330c0d06caSMauro Carvalho Chehab 	hdpvr_delete(dev);
11345612e191SBhaktipriya Shridhar 	flush_work(&dev->worker);
11350c0d06caSMauro Carvalho Chehab 
11360c0d06caSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
113799c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(&dev->hdl);
11380c0d06caSMauro Carvalho Chehab 
11390c0d06caSMauro Carvalho Chehab 	/* deregister I2C adapter */
114054d80904SMauro Carvalho Chehab #if IS_ENABLED(CONFIG_I2C)
11410c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->i2c_mutex);
11420c0d06caSMauro Carvalho Chehab 	i2c_del_adapter(&dev->i2c_adapter);
11430c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->i2c_mutex);
11440c0d06caSMauro Carvalho Chehab #endif /* CONFIG_I2C */
11450c0d06caSMauro Carvalho Chehab 
11460c0d06caSMauro Carvalho Chehab 	kfree(dev->usbc_buf);
11470c0d06caSMauro Carvalho Chehab 	kfree(dev);
11480c0d06caSMauro Carvalho Chehab }
11490c0d06caSMauro Carvalho Chehab 
11500c0d06caSMauro Carvalho Chehab static const struct video_device hdpvr_video_template = {
11510c0d06caSMauro Carvalho Chehab 	.fops			= &hdpvr_fops,
11520c0d06caSMauro Carvalho Chehab 	.release		= hdpvr_device_release,
11530c0d06caSMauro Carvalho Chehab 	.ioctl_ops		= &hdpvr_ioctl_ops,
11545854bf88SHans Verkuil 	.tvnorms		= V4L2_STD_ALL,
11558c3854d0SHans Verkuil 	.device_caps		= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
11568c3854d0SHans Verkuil 				  V4L2_CAP_READWRITE,
11570c0d06caSMauro Carvalho Chehab };
11580c0d06caSMauro Carvalho Chehab 
115999c77aa4SHans Verkuil static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
116099c77aa4SHans Verkuil 	.try_ctrl = hdpvr_try_ctrl,
116199c77aa4SHans Verkuil 	.s_ctrl = hdpvr_s_ctrl,
116299c77aa4SHans Verkuil };
116399c77aa4SHans Verkuil 
11640c0d06caSMauro Carvalho Chehab int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
11650c0d06caSMauro Carvalho Chehab 			    int devnum)
11660c0d06caSMauro Carvalho Chehab {
116799c77aa4SHans Verkuil 	struct v4l2_ctrl_handler *hdl = &dev->hdl;
116899c77aa4SHans Verkuil 	bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
116999c77aa4SHans Verkuil 	int res;
117099c77aa4SHans Verkuil 
11718f69da95SHans Verkuil 	dev->cur_std = V4L2_STD_525_60;
11728f69da95SHans Verkuil 	dev->width = 720;
11738f69da95SHans Verkuil 	dev->height = 480;
11743315c59aSHans Verkuil 	dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX];
117599c77aa4SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 11);
117699c77aa4SHans Verkuil 	if (dev->fw_ver > 0x15) {
117799c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
117899c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80);
117999c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118099c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40);
118199c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118299c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40);
118399c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118499c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf);
118599c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118699c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
118799c77aa4SHans Verkuil 	} else {
118899c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118999c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86);
119099c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119199c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80);
119299c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119399c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80);
119499c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119599c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0xff, 1, 0x80);
119699c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119799c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
119899c77aa4SHans Verkuil 	}
119999c77aa4SHans Verkuil 
120099c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120199c77aa4SHans Verkuil 		V4L2_CID_MPEG_STREAM_TYPE,
120299c77aa4SHans Verkuil 		V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
120399c77aa4SHans Verkuil 		0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
120499c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120599c77aa4SHans Verkuil 		V4L2_CID_MPEG_AUDIO_ENCODING,
120699c77aa4SHans Verkuil 		ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
12073445857bSHans Verkuil 		0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC);
120899c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120999c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_ENCODING,
121099c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
121199c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
121299c77aa4SHans Verkuil 
121399c77aa4SHans Verkuil 	dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
121499c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
121599c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
121699c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
121799c77aa4SHans Verkuil 
121899c77aa4SHans Verkuil 	dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
121999c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE,
122099c77aa4SHans Verkuil 		1000000, 13500000, 100000, 6500000);
122199c77aa4SHans Verkuil 	dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
122299c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
122399c77aa4SHans Verkuil 		1100000, 20200000, 100000, 9000000);
122499c77aa4SHans Verkuil 	dev->v4l2_dev.ctrl_handler = hdl;
122599c77aa4SHans Verkuil 	if (hdl->error) {
122699c77aa4SHans Verkuil 		res = hdl->error;
122799c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not register controls\n");
122899c77aa4SHans Verkuil 		goto error;
122999c77aa4SHans Verkuil 	}
123099c77aa4SHans Verkuil 	v4l2_ctrl_cluster(3, &dev->video_mode);
123199c77aa4SHans Verkuil 	res = v4l2_ctrl_handler_setup(hdl);
123299c77aa4SHans Verkuil 	if (res < 0) {
123399c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not setup controls\n");
123499c77aa4SHans Verkuil 		goto error;
123599c77aa4SHans Verkuil 	}
123699c77aa4SHans Verkuil 
12370c0d06caSMauro Carvalho Chehab 	/* setup and register video device */
12384b30409bSHans Verkuil 	dev->video_dev = hdpvr_video_template;
1239cc1e6315SMauro Carvalho Chehab 	strscpy(dev->video_dev.name, "Hauppauge HD PVR",
1240cc1e6315SMauro Carvalho Chehab 		sizeof(dev->video_dev.name));
12414b30409bSHans Verkuil 	dev->video_dev.v4l2_dev = &dev->v4l2_dev;
12424b30409bSHans Verkuil 	video_set_drvdata(&dev->video_dev, dev);
12430c0d06caSMauro Carvalho Chehab 
12444b30409bSHans Verkuil 	res = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, devnum);
124599c77aa4SHans Verkuil 	if (res < 0) {
12460c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
12470c0d06caSMauro Carvalho Chehab 		goto error;
12480c0d06caSMauro Carvalho Chehab 	}
12490c0d06caSMauro Carvalho Chehab 
12500c0d06caSMauro Carvalho Chehab 	return 0;
12510c0d06caSMauro Carvalho Chehab error:
125299c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(hdl);
125399c77aa4SHans Verkuil 	return res;
12540c0d06caSMauro Carvalho Chehab }
1255