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 
list_size(struct list_head * list)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 */
hdpvr_read_bulk_callback(struct urb * urb)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 */
hdpvr_cancel_queue(struct hdpvr_device * dev)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 
hdpvr_free_queue(struct list_head * q)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 */
hdpvr_free_buffers(struct hdpvr_device * dev)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 */
hdpvr_alloc_buffers(struct hdpvr_device * dev,uint count)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 
hdpvr_submit_buffers(struct hdpvr_device * dev)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 
hdpvr_get_next_buffer(struct hdpvr_device * dev)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 
hdpvr_transmit_buffers(struct work_struct * work)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 */
hdpvr_start_streaming(struct hdpvr_device * dev)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 
3115612e191SBhaktipriya Shridhar 	schedule_work(&dev->worker);
3120c0d06caSMauro Carvalho Chehab 
3130c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3140c0d06caSMauro Carvalho Chehab 			"streaming started\n");
3150c0d06caSMauro Carvalho Chehab 
3160c0d06caSMauro Carvalho Chehab 	return 0;
3170c0d06caSMauro Carvalho Chehab }
3180c0d06caSMauro Carvalho Chehab 
3190c0d06caSMauro Carvalho Chehab 
3200c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
hdpvr_stop_streaming(struct hdpvr_device * dev)3210c0d06caSMauro Carvalho Chehab static int hdpvr_stop_streaming(struct hdpvr_device *dev)
3220c0d06caSMauro Carvalho Chehab {
3230c0d06caSMauro Carvalho Chehab 	int actual_length;
3240c0d06caSMauro Carvalho Chehab 	uint c = 0;
3250c0d06caSMauro Carvalho Chehab 	u8 *buf;
3260c0d06caSMauro Carvalho Chehab 
3270c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE)
3280c0d06caSMauro Carvalho Chehab 		return 0;
3290c0d06caSMauro Carvalho Chehab 	else if (dev->status != STATUS_STREAMING)
3300c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
3310c0d06caSMauro Carvalho Chehab 
3320c0d06caSMauro Carvalho Chehab 	buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
3330c0d06caSMauro Carvalho Chehab 	if (!buf)
3344d5ded75SMauro 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");
3350c0d06caSMauro Carvalho Chehab 
3360c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_SHUTTING_DOWN;
3370c0d06caSMauro Carvalho Chehab 	hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
3380c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3390c0d06caSMauro Carvalho Chehab 
3400c0d06caSMauro Carvalho Chehab 	wake_up_interruptible(&dev->wait_buffer);
3410c0d06caSMauro Carvalho Chehab 	msleep(50);
3420c0d06caSMauro Carvalho Chehab 
3435612e191SBhaktipriya Shridhar 	flush_work(&dev->worker);
3440c0d06caSMauro Carvalho Chehab 
3450c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
3460c0d06caSMauro Carvalho Chehab 	/* kill the still outstanding urbs */
3470c0d06caSMauro Carvalho Chehab 	hdpvr_cancel_queue(dev);
3480c0d06caSMauro Carvalho Chehab 
3490c0d06caSMauro Carvalho Chehab 	/* emptying the device buffer beforeshutting it down */
3500c0d06caSMauro Carvalho Chehab 	while (buf && ++c < 500 &&
3510c0d06caSMauro Carvalho Chehab 	       !usb_bulk_msg(dev->udev,
3520c0d06caSMauro Carvalho Chehab 			     usb_rcvbulkpipe(dev->udev,
3530c0d06caSMauro Carvalho Chehab 					     dev->bulk_in_endpointAddr),
3540c0d06caSMauro Carvalho Chehab 			     buf, dev->bulk_in_size, &actual_length,
3550c0d06caSMauro Carvalho Chehab 			     BULK_URB_TIMEOUT)) {
3560c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3570c0d06caSMauro Carvalho Chehab 			 "%2d: got %d bytes\n", c, actual_length);
3580c0d06caSMauro Carvalho Chehab 	}
3590c0d06caSMauro Carvalho Chehab 	kfree(buf);
3600c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3610c0d06caSMauro Carvalho Chehab 		 "used %d urbs to empty device buffers\n", c-1);
3620c0d06caSMauro Carvalho Chehab 	msleep(10);
3630c0d06caSMauro Carvalho Chehab 
3640c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_IDLE;
3650c0d06caSMauro Carvalho Chehab 
3660c0d06caSMauro Carvalho Chehab 	return 0;
3670c0d06caSMauro Carvalho Chehab }
3680c0d06caSMauro Carvalho Chehab 
3690c0d06caSMauro Carvalho Chehab 
3700c0d06caSMauro Carvalho Chehab /*=======================================================================*/
3710c0d06caSMauro Carvalho Chehab /*
3720c0d06caSMauro Carvalho Chehab  * video 4 linux 2 file operations
3730c0d06caSMauro Carvalho Chehab  */
3740c0d06caSMauro Carvalho Chehab 
hdpvr_open(struct file * file)3753315c59aSHans Verkuil static int hdpvr_open(struct file *file)
3763315c59aSHans Verkuil {
3773315c59aSHans Verkuil 	struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL);
3783315c59aSHans Verkuil 
3793315c59aSHans Verkuil 	if (fh == NULL)
3803315c59aSHans Verkuil 		return -ENOMEM;
3813315c59aSHans Verkuil 	fh->legacy_mode = true;
3823315c59aSHans Verkuil 	v4l2_fh_init(&fh->fh, video_devdata(file));
3833315c59aSHans Verkuil 	v4l2_fh_add(&fh->fh);
3843315c59aSHans Verkuil 	file->private_data = fh;
3853315c59aSHans Verkuil 	return 0;
3863315c59aSHans Verkuil }
3873315c59aSHans Verkuil 
hdpvr_release(struct file * file)3880c0d06caSMauro Carvalho Chehab static int hdpvr_release(struct file *file)
3890c0d06caSMauro Carvalho Chehab {
390ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
3910c0d06caSMauro Carvalho Chehab 
3920c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
393ede197aaSHans Verkuil 	if (file->private_data == dev->owner) {
3940c0d06caSMauro Carvalho Chehab 		hdpvr_stop_streaming(dev);
395ede197aaSHans Verkuil 		dev->owner = NULL;
396ede197aaSHans Verkuil 	}
3970c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3980c0d06caSMauro Carvalho Chehab 
399ede197aaSHans Verkuil 	return v4l2_fh_release(file);
4000c0d06caSMauro Carvalho Chehab }
4010c0d06caSMauro Carvalho Chehab 
4020c0d06caSMauro Carvalho Chehab /*
4030c0d06caSMauro Carvalho Chehab  * hdpvr_v4l2_read()
4040c0d06caSMauro Carvalho Chehab  * will allocate buffers when called for the first time
4050c0d06caSMauro Carvalho Chehab  */
hdpvr_read(struct file * file,char __user * buffer,size_t count,loff_t * pos)4060c0d06caSMauro Carvalho Chehab static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
4070c0d06caSMauro Carvalho Chehab 			  loff_t *pos)
4080c0d06caSMauro Carvalho Chehab {
409ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
4100c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
4110c0d06caSMauro Carvalho Chehab 	struct urb *urb;
412*7ca91b2dSNiels Dossche 	int ret = 0;
4130c0d06caSMauro Carvalho Chehab 	int rem, cnt;
4140c0d06caSMauro Carvalho Chehab 
4150c0d06caSMauro Carvalho Chehab 	if (*pos)
4160c0d06caSMauro Carvalho Chehab 		return -ESPIPE;
4170c0d06caSMauro Carvalho Chehab 
4180c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
4190c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
4200c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
4210c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
4220c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
4230c0d06caSMauro Carvalho Chehab 			ret = -EIO;
4240c0d06caSMauro Carvalho Chehab 			msleep(200);
4250c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
4260c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
4270c0d06caSMauro Carvalho Chehab 			goto err;
4280c0d06caSMauro Carvalho Chehab 		}
429ede197aaSHans Verkuil 		dev->owner = file->private_data;
4300c0d06caSMauro Carvalho Chehab 		print_buffer_status();
4310c0d06caSMauro Carvalho Chehab 	}
4320c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
4330c0d06caSMauro Carvalho Chehab 
4340c0d06caSMauro Carvalho Chehab 	/* wait for the first buffer */
4350c0d06caSMauro Carvalho Chehab 	if (!(file->f_flags & O_NONBLOCK)) {
4360c0d06caSMauro Carvalho Chehab 		if (wait_event_interruptible(dev->wait_data,
4376bc5a4a1SHans Verkuil 					     !list_empty_careful(&dev->rec_buff_list)))
4380c0d06caSMauro Carvalho Chehab 			return -ERESTARTSYS;
4390c0d06caSMauro Carvalho Chehab 	}
4400c0d06caSMauro Carvalho Chehab 
4410c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
4420c0d06caSMauro Carvalho Chehab 
4430c0d06caSMauro Carvalho Chehab 	while (count > 0 && buf) {
4440c0d06caSMauro Carvalho Chehab 
4450c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY &&
4460c0d06caSMauro Carvalho Chehab 		    dev->status != STATUS_DISCONNECTED) {
447a503ff81SJonathan Sims 			int err;
4480c0d06caSMauro Carvalho Chehab 			/* return nonblocking */
4490c0d06caSMauro Carvalho Chehab 			if (file->f_flags & O_NONBLOCK) {
4500c0d06caSMauro Carvalho Chehab 				if (!ret)
4510c0d06caSMauro Carvalho Chehab 					ret = -EAGAIN;
4520c0d06caSMauro Carvalho Chehab 				goto err;
4530c0d06caSMauro Carvalho Chehab 			}
4540c0d06caSMauro Carvalho Chehab 
455a503ff81SJonathan Sims 			err = wait_event_interruptible_timeout(dev->wait_data,
456a503ff81SJonathan Sims 				buf->status == BUFSTAT_READY,
457a503ff81SJonathan Sims 				msecs_to_jiffies(1000));
458a503ff81SJonathan Sims 			if (err < 0) {
459a503ff81SJonathan Sims 				ret = err;
460a503ff81SJonathan Sims 				goto err;
461a503ff81SJonathan Sims 			}
462a503ff81SJonathan Sims 			if (!err) {
4636bc5a4a1SHans Verkuil 				v4l2_info(&dev->v4l2_dev,
464a503ff81SJonathan Sims 					  "timeout: restart streaming\n");
4656bc5a4a1SHans Verkuil 				mutex_lock(&dev->io_mutex);
466a503ff81SJonathan Sims 				hdpvr_stop_streaming(dev);
4676bc5a4a1SHans Verkuil 				mutex_unlock(&dev->io_mutex);
4686bc5a4a1SHans Verkuil 				/*
4696bc5a4a1SHans Verkuil 				 * The FW needs about 4 seconds after streaming
4706bc5a4a1SHans Verkuil 				 * stopped before it is ready to restart
4716bc5a4a1SHans Verkuil 				 * streaming.
4726bc5a4a1SHans Verkuil 				 */
4736bc5a4a1SHans Verkuil 				msleep(4000);
474a503ff81SJonathan Sims 				err = hdpvr_start_streaming(dev);
475a503ff81SJonathan Sims 				if (err) {
476a503ff81SJonathan Sims 					ret = err;
477a503ff81SJonathan Sims 					goto err;
478a503ff81SJonathan Sims 				}
479a503ff81SJonathan Sims 			}
4800c0d06caSMauro Carvalho Chehab 		}
4810c0d06caSMauro Carvalho Chehab 
4820c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY)
4830c0d06caSMauro Carvalho Chehab 			break;
4840c0d06caSMauro Carvalho Chehab 
4850c0d06caSMauro Carvalho Chehab 		/* set remaining bytes to copy */
4860c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
4870c0d06caSMauro Carvalho Chehab 		rem = urb->actual_length - buf->pos;
4880c0d06caSMauro Carvalho Chehab 		cnt = rem > count ? count : rem;
4890c0d06caSMauro Carvalho Chehab 
4900c0d06caSMauro Carvalho Chehab 		if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
4910c0d06caSMauro Carvalho Chehab 				 cnt)) {
4920c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
4930c0d06caSMauro Carvalho Chehab 			if (!ret)
4940c0d06caSMauro Carvalho Chehab 				ret = -EFAULT;
4950c0d06caSMauro Carvalho Chehab 			goto err;
4960c0d06caSMauro Carvalho Chehab 		}
4970c0d06caSMauro Carvalho Chehab 
4980c0d06caSMauro Carvalho Chehab 		buf->pos += cnt;
4990c0d06caSMauro Carvalho Chehab 		count -= cnt;
5000c0d06caSMauro Carvalho Chehab 		buffer += cnt;
5010c0d06caSMauro Carvalho Chehab 		ret += cnt;
5020c0d06caSMauro Carvalho Chehab 
5030c0d06caSMauro Carvalho Chehab 		/* finished, take next buffer */
5040c0d06caSMauro Carvalho Chehab 		if (buf->pos == urb->actual_length) {
5050c0d06caSMauro Carvalho Chehab 			mutex_lock(&dev->io_mutex);
5060c0d06caSMauro Carvalho Chehab 			buf->pos = 0;
5070c0d06caSMauro Carvalho Chehab 			buf->status = BUFSTAT_AVAILABLE;
5080c0d06caSMauro Carvalho Chehab 
5090c0d06caSMauro Carvalho Chehab 			list_move_tail(&buf->buff_list, &dev->free_buff_list);
5100c0d06caSMauro Carvalho Chehab 
5110c0d06caSMauro Carvalho Chehab 			print_buffer_status();
5120c0d06caSMauro Carvalho Chehab 
5130c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
5140c0d06caSMauro Carvalho Chehab 
5150c0d06caSMauro Carvalho Chehab 			wake_up_interruptible(&dev->wait_buffer);
5160c0d06caSMauro Carvalho Chehab 
5170c0d06caSMauro Carvalho Chehab 			buf = hdpvr_get_next_buffer(dev);
5180c0d06caSMauro Carvalho Chehab 		}
5190c0d06caSMauro Carvalho Chehab 	}
5200c0d06caSMauro Carvalho Chehab err:
5210c0d06caSMauro Carvalho Chehab 	if (!ret && !buf)
5220c0d06caSMauro Carvalho Chehab 		ret = -EAGAIN;
5230c0d06caSMauro Carvalho Chehab 	return ret;
5240c0d06caSMauro Carvalho Chehab }
5250c0d06caSMauro Carvalho Chehab 
hdpvr_poll(struct file * filp,poll_table * wait)526c23e0cb8SAl Viro static __poll_t hdpvr_poll(struct file *filp, poll_table *wait)
5270c0d06caSMauro Carvalho Chehab {
52801699437SAl Viro 	__poll_t req_events = poll_requested_events(wait);
5290c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
530ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(filp);
531c23e0cb8SAl Viro 	__poll_t mask = v4l2_ctrl_poll(filp, wait);
53265fe42d6SHans Verkuil 
533a9a08845SLinus Torvalds 	if (!(req_events & (EPOLLIN | EPOLLRDNORM)))
53465fe42d6SHans Verkuil 		return mask;
5350c0d06caSMauro Carvalho Chehab 
5360c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
5370c0d06caSMauro Carvalho Chehab 
5380c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
5390c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
5400c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
5410c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
5420c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
543ede197aaSHans Verkuil 		} else {
544ede197aaSHans Verkuil 			dev->owner = filp->private_data;
5450c0d06caSMauro Carvalho Chehab 		}
5460c0d06caSMauro Carvalho Chehab 
5470c0d06caSMauro Carvalho Chehab 		print_buffer_status();
5480c0d06caSMauro Carvalho Chehab 	}
5490c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
5500c0d06caSMauro Carvalho Chehab 
5510c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
5520c0d06caSMauro Carvalho Chehab 	/* only wait if no data is available */
5530c0d06caSMauro Carvalho Chehab 	if (!buf || buf->status != BUFSTAT_READY) {
5540c0d06caSMauro Carvalho Chehab 		poll_wait(filp, &dev->wait_data, wait);
5550c0d06caSMauro Carvalho Chehab 		buf = hdpvr_get_next_buffer(dev);
5560c0d06caSMauro Carvalho Chehab 	}
5570c0d06caSMauro Carvalho Chehab 	if (buf && buf->status == BUFSTAT_READY)
558a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
5590c0d06caSMauro Carvalho Chehab 
5600c0d06caSMauro Carvalho Chehab 	return mask;
5610c0d06caSMauro Carvalho Chehab }
5620c0d06caSMauro Carvalho Chehab 
5630c0d06caSMauro Carvalho Chehab 
5640c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations hdpvr_fops = {
5650c0d06caSMauro Carvalho Chehab 	.owner		= THIS_MODULE,
5663315c59aSHans Verkuil 	.open		= hdpvr_open,
5670c0d06caSMauro Carvalho Chehab 	.release	= hdpvr_release,
5680c0d06caSMauro Carvalho Chehab 	.read		= hdpvr_read,
5690c0d06caSMauro Carvalho Chehab 	.poll		= hdpvr_poll,
5700c0d06caSMauro Carvalho Chehab 	.unlocked_ioctl	= video_ioctl2,
5710c0d06caSMauro Carvalho Chehab };
5720c0d06caSMauro Carvalho Chehab 
5730c0d06caSMauro Carvalho Chehab /*=======================================================================*/
5740c0d06caSMauro Carvalho Chehab /*
5750c0d06caSMauro Carvalho Chehab  * V4L2 ioctl handling
5760c0d06caSMauro Carvalho Chehab  */
5770c0d06caSMauro Carvalho Chehab 
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)5780c0d06caSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void  *priv,
5790c0d06caSMauro Carvalho Chehab 			   struct v4l2_capability *cap)
5800c0d06caSMauro Carvalho Chehab {
5810c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_drvdata(file);
5820c0d06caSMauro Carvalho Chehab 
583cc1e6315SMauro Carvalho Chehab 	strscpy(cap->driver, "hdpvr", sizeof(cap->driver));
584cc1e6315SMauro Carvalho Chehab 	strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card));
5850c0d06caSMauro Carvalho Chehab 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
5860c0d06caSMauro Carvalho Chehab 	return 0;
5870c0d06caSMauro Carvalho Chehab }
5880c0d06caSMauro Carvalho Chehab 
vidioc_s_std(struct file * file,void * _fh,v4l2_std_id std)5895854bf88SHans Verkuil static int vidioc_s_std(struct file *file, void *_fh,
590314527acSHans Verkuil 			v4l2_std_id std)
5910c0d06caSMauro Carvalho Chehab {
592ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
5935854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
5940c0d06caSMauro Carvalho Chehab 	u8 std_type = 1;
5950c0d06caSMauro Carvalho Chehab 
5965854bf88SHans Verkuil 	if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
5978f69da95SHans Verkuil 		return -ENODATA;
5988f69da95SHans Verkuil 	if (dev->status != STATUS_IDLE)
5998f69da95SHans Verkuil 		return -EBUSY;
6008f69da95SHans Verkuil 	if (std & V4L2_STD_525_60)
6010c0d06caSMauro Carvalho Chehab 		std_type = 0;
6028f69da95SHans Verkuil 	dev->cur_std = std;
6038f69da95SHans Verkuil 	dev->width = 720;
6048f69da95SHans Verkuil 	dev->height = std_type ? 576 : 480;
6050c0d06caSMauro Carvalho Chehab 
6060c0d06caSMauro Carvalho Chehab 	return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
6070c0d06caSMauro Carvalho Chehab }
6080c0d06caSMauro Carvalho Chehab 
vidioc_g_std(struct file * file,void * _fh,v4l2_std_id * std)6095854bf88SHans Verkuil static int vidioc_g_std(struct file *file, void *_fh,
6108f69da95SHans Verkuil 			v4l2_std_id *std)
6118f69da95SHans Verkuil {
6128f69da95SHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6135854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
6148f69da95SHans Verkuil 
6155854bf88SHans Verkuil 	if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
6168f69da95SHans Verkuil 		return -ENODATA;
6178f69da95SHans Verkuil 	*std = dev->cur_std;
6188f69da95SHans Verkuil 	return 0;
6198f69da95SHans Verkuil }
6208f69da95SHans Verkuil 
vidioc_querystd(struct file * file,void * _fh,v4l2_std_id * a)6215854bf88SHans Verkuil static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a)
6228f69da95SHans Verkuil {
6238f69da95SHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6244d601c4cSLeonid Kegulskiy 	struct hdpvr_video_info vid_info;
6255854bf88SHans Verkuil 	struct hdpvr_fh *fh = _fh;
6264d601c4cSLeonid Kegulskiy 	int ret;
6278f69da95SHans Verkuil 
628ab6e134aSHans Verkuil 	*a = V4L2_STD_UNKNOWN;
6295854bf88SHans Verkuil 	if (dev->options.video_input == HDPVR_COMPONENT)
6305854bf88SHans Verkuil 		return fh->legacy_mode ? 0 : -ENODATA;
6314d601c4cSLeonid Kegulskiy 	ret = get_video_info(dev, &vid_info);
6325f454d82SHans Verkuil 	if (vid_info.valid && vid_info.width == 720 &&
6334d601c4cSLeonid Kegulskiy 	    (vid_info.height == 480 || vid_info.height == 576)) {
6344d601c4cSLeonid Kegulskiy 		*a = (vid_info.height == 480) ?
6358f69da95SHans Verkuil 			V4L2_STD_525_60 : V4L2_STD_625_50;
6368f69da95SHans Verkuil 	}
6375f454d82SHans Verkuil 	return ret;
6388f69da95SHans Verkuil }
6398f69da95SHans Verkuil 
vidioc_s_dv_timings(struct file * file,void * _fh,struct v4l2_dv_timings * timings)6403315c59aSHans Verkuil static int vidioc_s_dv_timings(struct file *file, void *_fh,
6413315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6423315c59aSHans Verkuil {
6433315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6443315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6453315c59aSHans Verkuil 	int i;
6463315c59aSHans Verkuil 
6473315c59aSHans Verkuil 	fh->legacy_mode = false;
6483315c59aSHans Verkuil 	if (dev->options.video_input)
6493315c59aSHans Verkuil 		return -ENODATA;
6503315c59aSHans Verkuil 	if (dev->status != STATUS_IDLE)
6513315c59aSHans Verkuil 		return -EBUSY;
6523315c59aSHans Verkuil 	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
65385f9e06cSHans Verkuil 		if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false))
6543315c59aSHans Verkuil 			break;
6553315c59aSHans Verkuil 	if (i == ARRAY_SIZE(hdpvr_dv_timings))
6563315c59aSHans Verkuil 		return -EINVAL;
6573315c59aSHans Verkuil 	dev->cur_dv_timings = hdpvr_dv_timings[i];
6583315c59aSHans Verkuil 	dev->width = hdpvr_dv_timings[i].bt.width;
6593315c59aSHans Verkuil 	dev->height = hdpvr_dv_timings[i].bt.height;
6603315c59aSHans Verkuil 	return 0;
6613315c59aSHans Verkuil }
6623315c59aSHans Verkuil 
vidioc_g_dv_timings(struct file * file,void * _fh,struct v4l2_dv_timings * timings)6633315c59aSHans Verkuil static int vidioc_g_dv_timings(struct file *file, void *_fh,
6643315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6653315c59aSHans Verkuil {
6663315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6673315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6683315c59aSHans Verkuil 
6693315c59aSHans Verkuil 	fh->legacy_mode = false;
6703315c59aSHans Verkuil 	if (dev->options.video_input)
6713315c59aSHans Verkuil 		return -ENODATA;
6723315c59aSHans Verkuil 	*timings = dev->cur_dv_timings;
6733315c59aSHans Verkuil 	return 0;
6743315c59aSHans Verkuil }
6753315c59aSHans Verkuil 
vidioc_query_dv_timings(struct file * file,void * _fh,struct v4l2_dv_timings * timings)6763315c59aSHans Verkuil static int vidioc_query_dv_timings(struct file *file, void *_fh,
6773315c59aSHans Verkuil 				    struct v4l2_dv_timings *timings)
6783315c59aSHans Verkuil {
6793315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6803315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
6814d601c4cSLeonid Kegulskiy 	struct hdpvr_video_info vid_info;
6823315c59aSHans Verkuil 	bool interlaced;
6833315c59aSHans Verkuil 	int ret = 0;
6843315c59aSHans Verkuil 	int i;
6853315c59aSHans Verkuil 
6863315c59aSHans Verkuil 	fh->legacy_mode = false;
6873315c59aSHans Verkuil 	if (dev->options.video_input)
6883315c59aSHans Verkuil 		return -ENODATA;
6894d601c4cSLeonid Kegulskiy 	ret = get_video_info(dev, &vid_info);
6904d601c4cSLeonid Kegulskiy 	if (ret)
6915f454d82SHans Verkuil 		return ret;
6925f454d82SHans Verkuil 	if (!vid_info.valid)
6933315c59aSHans Verkuil 		return -ENOLCK;
6944d601c4cSLeonid Kegulskiy 	interlaced = vid_info.fps <= 30;
6953315c59aSHans Verkuil 	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
6963315c59aSHans Verkuil 		const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
6973315c59aSHans Verkuil 		unsigned hsize;
6983315c59aSHans Verkuil 		unsigned vsize;
6993315c59aSHans Verkuil 		unsigned fps;
7003315c59aSHans Verkuil 
701eacf8f9aSHans Verkuil 		hsize = V4L2_DV_BT_FRAME_WIDTH(bt);
702eacf8f9aSHans Verkuil 		vsize = V4L2_DV_BT_FRAME_HEIGHT(bt);
7033315c59aSHans Verkuil 		fps = (unsigned)bt->pixelclock / (hsize * vsize);
7044d601c4cSLeonid Kegulskiy 		if (bt->width != vid_info.width ||
7054d601c4cSLeonid Kegulskiy 		    bt->height != vid_info.height ||
7063315c59aSHans Verkuil 		    bt->interlaced != interlaced ||
7074d601c4cSLeonid Kegulskiy 		    (fps != vid_info.fps && fps + 1 != vid_info.fps))
7083315c59aSHans Verkuil 			continue;
7093315c59aSHans Verkuil 		*timings = hdpvr_dv_timings[i];
7103315c59aSHans Verkuil 		break;
7113315c59aSHans Verkuil 	}
7123315c59aSHans Verkuil 	if (i == ARRAY_SIZE(hdpvr_dv_timings))
7133315c59aSHans Verkuil 		ret = -ERANGE;
7144d601c4cSLeonid Kegulskiy 
7153315c59aSHans Verkuil 	return ret;
7163315c59aSHans Verkuil }
7173315c59aSHans Verkuil 
vidioc_enum_dv_timings(struct file * file,void * _fh,struct v4l2_enum_dv_timings * timings)7183315c59aSHans Verkuil static int vidioc_enum_dv_timings(struct file *file, void *_fh,
7193315c59aSHans Verkuil 				    struct v4l2_enum_dv_timings *timings)
7203315c59aSHans Verkuil {
7213315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7223315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
7233315c59aSHans Verkuil 
7243315c59aSHans Verkuil 	fh->legacy_mode = false;
7253315c59aSHans Verkuil 	memset(timings->reserved, 0, sizeof(timings->reserved));
7263315c59aSHans Verkuil 	if (dev->options.video_input)
7273315c59aSHans Verkuil 		return -ENODATA;
7283315c59aSHans Verkuil 	if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings))
7293315c59aSHans Verkuil 		return -EINVAL;
7303315c59aSHans Verkuil 	timings->timings = hdpvr_dv_timings[timings->index];
7313315c59aSHans Verkuil 	return 0;
7323315c59aSHans Verkuil }
7333315c59aSHans Verkuil 
vidioc_dv_timings_cap(struct file * file,void * _fh,struct v4l2_dv_timings_cap * cap)7343315c59aSHans Verkuil static int vidioc_dv_timings_cap(struct file *file, void *_fh,
7353315c59aSHans Verkuil 				    struct v4l2_dv_timings_cap *cap)
7363315c59aSHans Verkuil {
7373315c59aSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7383315c59aSHans Verkuil 	struct hdpvr_fh *fh = _fh;
7393315c59aSHans Verkuil 
7403315c59aSHans Verkuil 	fh->legacy_mode = false;
7413315c59aSHans Verkuil 	if (dev->options.video_input)
7423315c59aSHans Verkuil 		return -ENODATA;
7433315c59aSHans Verkuil 	cap->type = V4L2_DV_BT_656_1120;
7443315c59aSHans Verkuil 	cap->bt.min_width = 720;
7453315c59aSHans Verkuil 	cap->bt.max_width = 1920;
7463315c59aSHans Verkuil 	cap->bt.min_height = 480;
7473315c59aSHans Verkuil 	cap->bt.max_height = 1080;
7483315c59aSHans Verkuil 	cap->bt.min_pixelclock = 27000000;
7493315c59aSHans Verkuil 	cap->bt.max_pixelclock = 74250000;
7503315c59aSHans Verkuil 	cap->bt.standards = V4L2_DV_BT_STD_CEA861;
7513315c59aSHans Verkuil 	cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE;
7523315c59aSHans Verkuil 	return 0;
7533315c59aSHans Verkuil }
7543315c59aSHans Verkuil 
7550c0d06caSMauro Carvalho Chehab static const char *iname[] = {
7560c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPONENT] = "Component",
7570c0d06caSMauro Carvalho Chehab 	[HDPVR_SVIDEO]    = "S-Video",
7580c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPOSITE] = "Composite",
7590c0d06caSMauro Carvalho Chehab };
7600c0d06caSMauro Carvalho Chehab 
vidioc_enum_input(struct file * file,void * _fh,struct v4l2_input * i)7615854bf88SHans Verkuil static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i)
7620c0d06caSMauro Carvalho Chehab {
7630c0d06caSMauro Carvalho Chehab 	unsigned int n;
7640c0d06caSMauro Carvalho Chehab 
7650c0d06caSMauro Carvalho Chehab 	n = i->index;
7660c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_VIDEO_INPUTS)
7670c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7680c0d06caSMauro Carvalho Chehab 
7690c0d06caSMauro Carvalho Chehab 	i->type = V4L2_INPUT_TYPE_CAMERA;
7700c0d06caSMauro Carvalho Chehab 
77185709cbfSMauro Carvalho Chehab 	strscpy(i->name, iname[n], sizeof(i->name));
7720c0d06caSMauro Carvalho Chehab 
7730c0d06caSMauro Carvalho Chehab 	i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
7740c0d06caSMauro Carvalho Chehab 
7758f69da95SHans Verkuil 	i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS;
7768f69da95SHans Verkuil 	i->std = n ? V4L2_STD_ALL : 0;
7770c0d06caSMauro Carvalho Chehab 
7780c0d06caSMauro Carvalho Chehab 	return 0;
7790c0d06caSMauro Carvalho Chehab }
7800c0d06caSMauro Carvalho Chehab 
vidioc_s_input(struct file * file,void * _fh,unsigned int index)7815854bf88SHans Verkuil static int vidioc_s_input(struct file *file, void *_fh,
7820c0d06caSMauro Carvalho Chehab 			  unsigned int index)
7830c0d06caSMauro Carvalho Chehab {
784ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7850c0d06caSMauro Carvalho Chehab 	int retval;
7860c0d06caSMauro Carvalho Chehab 
7870c0d06caSMauro Carvalho Chehab 	if (index >= HDPVR_VIDEO_INPUTS)
7880c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7890c0d06caSMauro Carvalho Chehab 
7900c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
79197caa318SHans Verkuil 		return -EBUSY;
7920c0d06caSMauro Carvalho Chehab 
7930c0d06caSMauro Carvalho Chehab 	retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
7948f69da95SHans Verkuil 	if (!retval) {
7950c0d06caSMauro Carvalho Chehab 		dev->options.video_input = index;
7965854bf88SHans Verkuil 		/*
7975854bf88SHans Verkuil 		 * Unfortunately gstreamer calls ENUMSTD and bails out if it
7985854bf88SHans Verkuil 		 * won't find any formats, even though component input is
7995854bf88SHans Verkuil 		 * selected. This means that we have to leave tvnorms at
8005854bf88SHans Verkuil 		 * V4L2_STD_ALL. We cannot use the 'legacy' trick since
8015854bf88SHans Verkuil 		 * tvnorms is set at the device node level and not at the
8025854bf88SHans Verkuil 		 * filehandle level.
8035854bf88SHans Verkuil 		 *
8045854bf88SHans Verkuil 		 * Comment this out for now, but if the legacy mode can be
8055854bf88SHans Verkuil 		 * removed in the future, then this code should be enabled
8065854bf88SHans Verkuil 		 * again.
8074b30409bSHans Verkuil 		dev->video_dev.tvnorms =
8085854bf88SHans Verkuil 			(index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0;
8095854bf88SHans Verkuil 		 */
8108f69da95SHans Verkuil 	}
8110c0d06caSMauro Carvalho Chehab 
8120c0d06caSMauro Carvalho Chehab 	return retval;
8130c0d06caSMauro Carvalho Chehab }
8140c0d06caSMauro Carvalho Chehab 
vidioc_g_input(struct file * file,void * private_data,unsigned int * index)8150c0d06caSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *private_data,
8160c0d06caSMauro Carvalho Chehab 			  unsigned int *index)
8170c0d06caSMauro Carvalho Chehab {
818ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8190c0d06caSMauro Carvalho Chehab 
8200c0d06caSMauro Carvalho Chehab 	*index = dev->options.video_input;
8210c0d06caSMauro Carvalho Chehab 	return 0;
8220c0d06caSMauro Carvalho Chehab }
8230c0d06caSMauro Carvalho Chehab 
8240c0d06caSMauro Carvalho Chehab 
8250c0d06caSMauro Carvalho Chehab static const char *audio_iname[] = {
8260c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_FRONT] = "RCA front",
8270c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_BACK]  = "RCA back",
8280c0d06caSMauro Carvalho Chehab 	[HDPVR_SPDIF]     = "SPDIF",
8290c0d06caSMauro Carvalho Chehab };
8300c0d06caSMauro Carvalho Chehab 
vidioc_enumaudio(struct file * file,void * priv,struct v4l2_audio * audio)8310c0d06caSMauro Carvalho Chehab static int vidioc_enumaudio(struct file *file, void *priv,
8320c0d06caSMauro Carvalho Chehab 				struct v4l2_audio *audio)
8330c0d06caSMauro Carvalho Chehab {
8340c0d06caSMauro Carvalho Chehab 	unsigned int n;
8350c0d06caSMauro Carvalho Chehab 
8360c0d06caSMauro Carvalho Chehab 	n = audio->index;
8370c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_AUDIO_INPUTS)
8380c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8390c0d06caSMauro Carvalho Chehab 
8400c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
8410c0d06caSMauro Carvalho Chehab 
84285709cbfSMauro Carvalho Chehab 	strscpy(audio->name, audio_iname[n], sizeof(audio->name));
8430c0d06caSMauro Carvalho Chehab 
8440c0d06caSMauro Carvalho Chehab 	return 0;
8450c0d06caSMauro Carvalho Chehab }
8460c0d06caSMauro Carvalho Chehab 
vidioc_s_audio(struct file * file,void * private_data,const struct v4l2_audio * audio)8470c0d06caSMauro Carvalho Chehab static int vidioc_s_audio(struct file *file, void *private_data,
8480e8025b9SHans Verkuil 			  const struct v4l2_audio *audio)
8490c0d06caSMauro Carvalho Chehab {
850ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8510c0d06caSMauro Carvalho Chehab 	int retval;
8520c0d06caSMauro Carvalho Chehab 
8530c0d06caSMauro Carvalho Chehab 	if (audio->index >= HDPVR_AUDIO_INPUTS)
8540c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8550c0d06caSMauro Carvalho Chehab 
8560c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
85797caa318SHans Verkuil 		return -EBUSY;
8580c0d06caSMauro Carvalho Chehab 
8590c0d06caSMauro Carvalho Chehab 	retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
8600c0d06caSMauro Carvalho Chehab 	if (!retval)
8610c0d06caSMauro Carvalho Chehab 		dev->options.audio_input = audio->index;
8620c0d06caSMauro Carvalho Chehab 
8630c0d06caSMauro Carvalho Chehab 	return retval;
8640c0d06caSMauro Carvalho Chehab }
8650c0d06caSMauro Carvalho Chehab 
vidioc_g_audio(struct file * file,void * private_data,struct v4l2_audio * audio)8660c0d06caSMauro Carvalho Chehab static int vidioc_g_audio(struct file *file, void *private_data,
8670c0d06caSMauro Carvalho Chehab 			  struct v4l2_audio *audio)
8680c0d06caSMauro Carvalho Chehab {
869ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
8700c0d06caSMauro Carvalho Chehab 
8710c0d06caSMauro Carvalho Chehab 	audio->index = dev->options.audio_input;
8720c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
873c0decac1SMauro Carvalho Chehab 	strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
8740c0d06caSMauro Carvalho Chehab 	return 0;
8750c0d06caSMauro Carvalho Chehab }
8760c0d06caSMauro Carvalho Chehab 
hdpvr_try_ctrl(struct v4l2_ctrl * ctrl)87799c77aa4SHans Verkuil static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl)
8780c0d06caSMauro Carvalho Chehab {
87999c77aa4SHans Verkuil 	struct hdpvr_device *dev =
88099c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
8810c0d06caSMauro Carvalho Chehab 
8820c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
88399c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
88499c77aa4SHans Verkuil 		if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
88599c77aa4SHans Verkuil 		    dev->video_bitrate->val >= dev->video_bitrate_peak->val)
88699c77aa4SHans Verkuil 			dev->video_bitrate_peak->val =
88799c77aa4SHans Verkuil 					dev->video_bitrate->val + 100000;
8880c0d06caSMauro Carvalho Chehab 		break;
8890c0d06caSMauro Carvalho Chehab 	}
8900c0d06caSMauro Carvalho Chehab 	return 0;
8910c0d06caSMauro Carvalho Chehab }
8920c0d06caSMauro Carvalho Chehab 
hdpvr_s_ctrl(struct v4l2_ctrl * ctrl)89399c77aa4SHans Verkuil static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
8940c0d06caSMauro Carvalho Chehab {
89599c77aa4SHans Verkuil 	struct hdpvr_device *dev =
89699c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
89799c77aa4SHans Verkuil 	struct hdpvr_options *opt = &dev->options;
8980c0d06caSMauro Carvalho Chehab 	int ret = -EINVAL;
8990c0d06caSMauro Carvalho Chehab 
9000c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
90199c77aa4SHans Verkuil 	case V4L2_CID_BRIGHTNESS:
90299c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val);
90399c77aa4SHans Verkuil 		if (ret)
9040c0d06caSMauro Carvalho Chehab 			break;
90599c77aa4SHans Verkuil 		dev->options.brightness = ctrl->val;
90699c77aa4SHans Verkuil 		return 0;
90799c77aa4SHans Verkuil 	case V4L2_CID_CONTRAST:
90899c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val);
90999c77aa4SHans Verkuil 		if (ret)
9100c0d06caSMauro Carvalho Chehab 			break;
91199c77aa4SHans Verkuil 		dev->options.contrast = ctrl->val;
91299c77aa4SHans Verkuil 		return 0;
91399c77aa4SHans Verkuil 	case V4L2_CID_SATURATION:
91499c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val);
91599c77aa4SHans Verkuil 		if (ret)
9160c0d06caSMauro Carvalho Chehab 			break;
91799c77aa4SHans Verkuil 		dev->options.saturation = ctrl->val;
91899c77aa4SHans Verkuil 		return 0;
91999c77aa4SHans Verkuil 	case V4L2_CID_HUE:
92099c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val);
92199c77aa4SHans Verkuil 		if (ret)
9220c0d06caSMauro Carvalho Chehab 			break;
92399c77aa4SHans Verkuil 		dev->options.hue = ctrl->val;
92499c77aa4SHans Verkuil 		return 0;
92599c77aa4SHans Verkuil 	case V4L2_CID_SHARPNESS:
92699c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val);
92799c77aa4SHans Verkuil 		if (ret)
9280c0d06caSMauro Carvalho Chehab 			break;
92999c77aa4SHans Verkuil 		dev->options.sharpness = ctrl->val;
93099c77aa4SHans Verkuil 		return 0;
9310c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
9320c0d06caSMauro Carvalho Chehab 		if (dev->flags & HDPVR_FLAG_AC3_CAP) {
93399c77aa4SHans Verkuil 			opt->audio_codec = ctrl->val;
9343445857bSHans Verkuil 			return hdpvr_set_audio(dev, opt->audio_input + 1,
9350c0d06caSMauro Carvalho Chehab 					      opt->audio_codec);
9360c0d06caSMauro Carvalho Chehab 		}
93799c77aa4SHans Verkuil 		return 0;
9380c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
93999c77aa4SHans Verkuil 		return 0;
9400c0d06caSMauro Carvalho Chehab /*	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
9410c0d06caSMauro Carvalho Chehab /*		if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
9420c0d06caSMauro Carvalho Chehab /*			opt->gop_mode |= 0x2; */
9430c0d06caSMauro Carvalho Chehab /*			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
9440c0d06caSMauro Carvalho Chehab /*					  opt->gop_mode); */
9450c0d06caSMauro Carvalho Chehab /*		} */
9460c0d06caSMauro Carvalho Chehab /*		if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
9470c0d06caSMauro Carvalho Chehab /*			opt->gop_mode &= ~0x2; */
9480c0d06caSMauro Carvalho Chehab /*			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
9490c0d06caSMauro Carvalho Chehab /*					  opt->gop_mode); */
9500c0d06caSMauro Carvalho Chehab /*		} */
9510c0d06caSMauro Carvalho Chehab /*		break; */
95299c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
95399c77aa4SHans Verkuil 		uint peak_bitrate = dev->video_bitrate_peak->val / 100000;
95499c77aa4SHans Verkuil 		uint bitrate = dev->video_bitrate->val / 100000;
95599c77aa4SHans Verkuil 
95699c77aa4SHans Verkuil 		if (ctrl->is_new) {
95799c77aa4SHans Verkuil 			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
9580c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_CONSTANT;
95999c77aa4SHans Verkuil 			else
9600c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
9610c0d06caSMauro Carvalho Chehab 			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
9620c0d06caSMauro Carvalho Chehab 					  opt->bitrate_mode);
96399c77aa4SHans Verkuil 			v4l2_ctrl_activate(dev->video_bitrate_peak,
96499c77aa4SHans Verkuil 				ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
9650c0d06caSMauro Carvalho Chehab 		}
9660c0d06caSMauro Carvalho Chehab 
96799c77aa4SHans Verkuil 		if (dev->video_bitrate_peak->is_new ||
96899c77aa4SHans Verkuil 		    dev->video_bitrate->is_new) {
9690c0d06caSMauro Carvalho Chehab 			opt->bitrate = bitrate;
9700c0d06caSMauro Carvalho Chehab 			opt->peak_bitrate = peak_bitrate;
9710c0d06caSMauro Carvalho Chehab 			hdpvr_set_bitrate(dev);
97299c77aa4SHans Verkuil 		}
97399c77aa4SHans Verkuil 		return 0;
9740c0d06caSMauro Carvalho Chehab 	}
9750c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_STREAM_TYPE:
97699c77aa4SHans Verkuil 		return 0;
9770c0d06caSMauro Carvalho Chehab 	default:
97899c77aa4SHans Verkuil 		break;
9790c0d06caSMauro Carvalho Chehab 	}
9800c0d06caSMauro Carvalho Chehab 	return ret;
9810c0d06caSMauro Carvalho Chehab }
9820c0d06caSMauro Carvalho Chehab 
vidioc_enum_fmt_vid_cap(struct file * file,void * private_data,struct v4l2_fmtdesc * f)9830c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
9840c0d06caSMauro Carvalho Chehab 				    struct v4l2_fmtdesc *f)
9850c0d06caSMauro Carvalho Chehab {
98697caa318SHans Verkuil 	if (f->index != 0)
9870c0d06caSMauro Carvalho Chehab 		return -EINVAL;
9880c0d06caSMauro Carvalho Chehab 
9890c0d06caSMauro Carvalho Chehab 	f->pixelformat = V4L2_PIX_FMT_MPEG;
9900c0d06caSMauro Carvalho Chehab 
9910c0d06caSMauro Carvalho Chehab 	return 0;
9920c0d06caSMauro Carvalho Chehab }
9930c0d06caSMauro Carvalho Chehab 
vidioc_g_fmt_vid_cap(struct file * file,void * _fh,struct v4l2_format * f)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 
vidioc_encoder_cmd(struct file * filp,void * priv,struct v4l2_encoder_cmd * a)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 
vidioc_try_encoder_cmd(struct file * filp,void * priv,struct v4l2_encoder_cmd * a)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 
hdpvr_device_release(struct video_device * vdev)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);
11305612e191SBhaktipriya Shridhar 	flush_work(&dev->worker);
11310c0d06caSMauro Carvalho Chehab 
11320c0d06caSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
113399c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(&dev->hdl);
11340c0d06caSMauro Carvalho Chehab 
11350c0d06caSMauro Carvalho Chehab 	/* deregister I2C adapter */
113654d80904SMauro Carvalho Chehab #if IS_ENABLED(CONFIG_I2C)
11370c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->i2c_mutex);
11380c0d06caSMauro Carvalho Chehab 	i2c_del_adapter(&dev->i2c_adapter);
11390c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->i2c_mutex);
11400c0d06caSMauro Carvalho Chehab #endif /* CONFIG_I2C */
11410c0d06caSMauro Carvalho Chehab 
11420c0d06caSMauro Carvalho Chehab 	kfree(dev->usbc_buf);
11430c0d06caSMauro Carvalho Chehab 	kfree(dev);
11440c0d06caSMauro Carvalho Chehab }
11450c0d06caSMauro Carvalho Chehab 
11460c0d06caSMauro Carvalho Chehab static const struct video_device hdpvr_video_template = {
11470c0d06caSMauro Carvalho Chehab 	.fops			= &hdpvr_fops,
11480c0d06caSMauro Carvalho Chehab 	.release		= hdpvr_device_release,
11490c0d06caSMauro Carvalho Chehab 	.ioctl_ops		= &hdpvr_ioctl_ops,
11505854bf88SHans Verkuil 	.tvnorms		= V4L2_STD_ALL,
11518c3854d0SHans Verkuil 	.device_caps		= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
11528c3854d0SHans Verkuil 				  V4L2_CAP_READWRITE,
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 
hdpvr_register_videodev(struct hdpvr_device * dev,struct device * parent,int devnum)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 
1167f90db7ccSDongliang Mu 	// initialize dev->worker
1168f90db7ccSDongliang Mu 	INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
1169f90db7ccSDongliang Mu 
11708f69da95SHans Verkuil 	dev->cur_std = V4L2_STD_525_60;
11718f69da95SHans Verkuil 	dev->width = 720;
11728f69da95SHans Verkuil 	dev->height = 480;
11733315c59aSHans Verkuil 	dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX];
117499c77aa4SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 11);
117599c77aa4SHans Verkuil 	if (dev->fw_ver > 0x15) {
117699c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
117799c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80);
117899c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
117999c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40);
118099c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118199c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40);
118299c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118399c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf);
118499c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118599c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
118699c77aa4SHans Verkuil 	} else {
118799c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
118899c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86);
118999c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119099c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80);
119199c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119299c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80);
119399c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119499c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0xff, 1, 0x80);
119599c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
119699c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
119799c77aa4SHans Verkuil 	}
119899c77aa4SHans Verkuil 
119999c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120099c77aa4SHans Verkuil 		V4L2_CID_MPEG_STREAM_TYPE,
120199c77aa4SHans Verkuil 		V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
120299c77aa4SHans Verkuil 		0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
120399c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120499c77aa4SHans Verkuil 		V4L2_CID_MPEG_AUDIO_ENCODING,
120599c77aa4SHans Verkuil 		ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
12063445857bSHans Verkuil 		0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC);
120799c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
120899c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_ENCODING,
120999c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
121099c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
121199c77aa4SHans Verkuil 
121299c77aa4SHans Verkuil 	dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
121399c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
121499c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
121599c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
121699c77aa4SHans Verkuil 
121799c77aa4SHans Verkuil 	dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
121899c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE,
121999c77aa4SHans Verkuil 		1000000, 13500000, 100000, 6500000);
122099c77aa4SHans Verkuil 	dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
122199c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
122299c77aa4SHans Verkuil 		1100000, 20200000, 100000, 9000000);
122399c77aa4SHans Verkuil 	dev->v4l2_dev.ctrl_handler = hdl;
122499c77aa4SHans Verkuil 	if (hdl->error) {
122599c77aa4SHans Verkuil 		res = hdl->error;
122699c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not register controls\n");
122799c77aa4SHans Verkuil 		goto error;
122899c77aa4SHans Verkuil 	}
122999c77aa4SHans Verkuil 	v4l2_ctrl_cluster(3, &dev->video_mode);
123099c77aa4SHans Verkuil 	res = v4l2_ctrl_handler_setup(hdl);
123199c77aa4SHans Verkuil 	if (res < 0) {
123299c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not setup controls\n");
123399c77aa4SHans Verkuil 		goto error;
123499c77aa4SHans Verkuil 	}
123599c77aa4SHans Verkuil 
12360c0d06caSMauro Carvalho Chehab 	/* setup and register video device */
12374b30409bSHans Verkuil 	dev->video_dev = hdpvr_video_template;
1238cc1e6315SMauro Carvalho Chehab 	strscpy(dev->video_dev.name, "Hauppauge HD PVR",
1239cc1e6315SMauro Carvalho Chehab 		sizeof(dev->video_dev.name));
12404b30409bSHans Verkuil 	dev->video_dev.v4l2_dev = &dev->v4l2_dev;
12414b30409bSHans Verkuil 	video_set_drvdata(&dev->video_dev, dev);
12420c0d06caSMauro Carvalho Chehab 
12437fbbbc78SHans Verkuil 	res = video_register_device(&dev->video_dev, VFL_TYPE_VIDEO, devnum);
124499c77aa4SHans Verkuil 	if (res < 0) {
12450c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
12460c0d06caSMauro Carvalho Chehab 		goto error;
12470c0d06caSMauro Carvalho Chehab 	}
12480c0d06caSMauro Carvalho Chehab 
12490c0d06caSMauro Carvalho Chehab 	return 0;
12500c0d06caSMauro Carvalho Chehab error:
125199c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(hdl);
125299c77aa4SHans Verkuil 	return res;
12530c0d06caSMauro Carvalho Chehab }
1254