10c0d06caSMauro Carvalho Chehab /*
20c0d06caSMauro Carvalho Chehab  * Hauppauge HD PVR USB driver - video 4 linux 2 interface
30c0d06caSMauro Carvalho Chehab  *
40c0d06caSMauro Carvalho Chehab  * Copyright (C) 2008      Janne Grunau (j@jannau.net)
50c0d06caSMauro Carvalho Chehab  *
60c0d06caSMauro Carvalho Chehab  *	This program is free software; you can redistribute it and/or
70c0d06caSMauro Carvalho Chehab  *	modify it under the terms of the GNU General Public License as
80c0d06caSMauro Carvalho Chehab  *	published by the Free Software Foundation, version 2.
90c0d06caSMauro Carvalho Chehab  *
100c0d06caSMauro Carvalho Chehab  */
110c0d06caSMauro Carvalho Chehab 
120c0d06caSMauro Carvalho Chehab #include <linux/kernel.h>
1354d80904SMauro Carvalho Chehab #include <linux/kconfig.h>
140c0d06caSMauro Carvalho Chehab #include <linux/errno.h>
150c0d06caSMauro Carvalho Chehab #include <linux/init.h>
160c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
170c0d06caSMauro Carvalho Chehab #include <linux/module.h>
180c0d06caSMauro Carvalho Chehab #include <linux/uaccess.h>
190c0d06caSMauro Carvalho Chehab #include <linux/usb.h>
200c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
210c0d06caSMauro Carvalho Chehab #include <linux/workqueue.h>
220c0d06caSMauro Carvalho Chehab 
230c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h>
240c0d06caSMauro Carvalho Chehab #include <media/v4l2-dev.h>
250c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
260c0d06caSMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
2765fe42d6SHans Verkuil #include <media/v4l2-event.h>
280c0d06caSMauro Carvalho Chehab #include "hdpvr.h"
290c0d06caSMauro Carvalho Chehab 
300c0d06caSMauro Carvalho Chehab #define BULK_URB_TIMEOUT   90 /* 0.09 seconds */
310c0d06caSMauro Carvalho Chehab 
320c0d06caSMauro Carvalho Chehab #define print_buffer_status() { \
330c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,	\
340c0d06caSMauro Carvalho Chehab 			 "%s:%d buffer stat: %d free, %d proc\n",	\
350c0d06caSMauro Carvalho Chehab 			 __func__, __LINE__,				\
360c0d06caSMauro Carvalho Chehab 			 list_size(&dev->free_buff_list),		\
370c0d06caSMauro Carvalho Chehab 			 list_size(&dev->rec_buff_list)); }
380c0d06caSMauro Carvalho Chehab 
390c0d06caSMauro Carvalho Chehab static uint list_size(struct list_head *list)
400c0d06caSMauro Carvalho Chehab {
410c0d06caSMauro Carvalho Chehab 	struct list_head *tmp;
420c0d06caSMauro Carvalho Chehab 	uint count = 0;
430c0d06caSMauro Carvalho Chehab 
440c0d06caSMauro Carvalho Chehab 	list_for_each(tmp, list) {
450c0d06caSMauro Carvalho Chehab 		count++;
460c0d06caSMauro Carvalho Chehab 	}
470c0d06caSMauro Carvalho Chehab 
480c0d06caSMauro Carvalho Chehab 	return count;
490c0d06caSMauro Carvalho Chehab }
500c0d06caSMauro Carvalho Chehab 
510c0d06caSMauro Carvalho Chehab /*=========================================================================*/
520c0d06caSMauro Carvalho Chehab /* urb callback */
530c0d06caSMauro Carvalho Chehab static void hdpvr_read_bulk_callback(struct urb *urb)
540c0d06caSMauro Carvalho Chehab {
550c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
560c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = buf->dev;
570c0d06caSMauro Carvalho Chehab 
580c0d06caSMauro Carvalho Chehab 	/* marking buffer as received and wake waiting */
590c0d06caSMauro Carvalho Chehab 	buf->status = BUFSTAT_READY;
600c0d06caSMauro Carvalho Chehab 	wake_up_interruptible(&dev->wait_data);
610c0d06caSMauro Carvalho Chehab }
620c0d06caSMauro Carvalho Chehab 
630c0d06caSMauro Carvalho Chehab /*=========================================================================*/
640c0d06caSMauro Carvalho Chehab /* bufffer bits */
650c0d06caSMauro Carvalho Chehab 
660c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
670c0d06caSMauro Carvalho Chehab int hdpvr_cancel_queue(struct hdpvr_device *dev)
680c0d06caSMauro Carvalho Chehab {
690c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
700c0d06caSMauro Carvalho Chehab 
710c0d06caSMauro Carvalho Chehab 	list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
720c0d06caSMauro Carvalho Chehab 		usb_kill_urb(buf->urb);
730c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_AVAILABLE;
740c0d06caSMauro Carvalho Chehab 	}
750c0d06caSMauro Carvalho Chehab 
760c0d06caSMauro Carvalho Chehab 	list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
770c0d06caSMauro Carvalho Chehab 
780c0d06caSMauro Carvalho Chehab 	return 0;
790c0d06caSMauro Carvalho Chehab }
800c0d06caSMauro Carvalho Chehab 
810c0d06caSMauro Carvalho Chehab static int hdpvr_free_queue(struct list_head *q)
820c0d06caSMauro Carvalho Chehab {
830c0d06caSMauro Carvalho Chehab 	struct list_head *tmp;
840c0d06caSMauro Carvalho Chehab 	struct list_head *p;
850c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
860c0d06caSMauro Carvalho Chehab 	struct urb *urb;
870c0d06caSMauro Carvalho Chehab 
880c0d06caSMauro Carvalho Chehab 	for (p = q->next; p != q;) {
890c0d06caSMauro Carvalho Chehab 		buf = list_entry(p, struct hdpvr_buffer, buff_list);
900c0d06caSMauro Carvalho Chehab 
910c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
920c0d06caSMauro Carvalho Chehab 		usb_free_coherent(urb->dev, urb->transfer_buffer_length,
930c0d06caSMauro Carvalho Chehab 				  urb->transfer_buffer, urb->transfer_dma);
940c0d06caSMauro Carvalho Chehab 		usb_free_urb(urb);
950c0d06caSMauro Carvalho Chehab 		tmp = p->next;
960c0d06caSMauro Carvalho Chehab 		list_del(p);
970c0d06caSMauro Carvalho Chehab 		kfree(buf);
980c0d06caSMauro Carvalho Chehab 		p = tmp;
990c0d06caSMauro Carvalho Chehab 	}
1000c0d06caSMauro Carvalho Chehab 
1010c0d06caSMauro Carvalho Chehab 	return 0;
1020c0d06caSMauro Carvalho Chehab }
1030c0d06caSMauro Carvalho Chehab 
1040c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
1050c0d06caSMauro Carvalho Chehab int hdpvr_free_buffers(struct hdpvr_device *dev)
1060c0d06caSMauro Carvalho Chehab {
1070c0d06caSMauro Carvalho Chehab 	hdpvr_cancel_queue(dev);
1080c0d06caSMauro Carvalho Chehab 
1090c0d06caSMauro Carvalho Chehab 	hdpvr_free_queue(&dev->free_buff_list);
1100c0d06caSMauro Carvalho Chehab 	hdpvr_free_queue(&dev->rec_buff_list);
1110c0d06caSMauro Carvalho Chehab 
1120c0d06caSMauro Carvalho Chehab 	return 0;
1130c0d06caSMauro Carvalho Chehab }
1140c0d06caSMauro Carvalho Chehab 
1150c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
1160c0d06caSMauro Carvalho Chehab int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
1170c0d06caSMauro Carvalho Chehab {
1180c0d06caSMauro Carvalho Chehab 	uint i;
1190c0d06caSMauro Carvalho Chehab 	int retval = -ENOMEM;
1200c0d06caSMauro Carvalho Chehab 	u8 *mem;
1210c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
1220c0d06caSMauro Carvalho Chehab 	struct urb *urb;
1230c0d06caSMauro Carvalho Chehab 
1240c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
1250c0d06caSMauro Carvalho Chehab 		 "allocating %u buffers\n", count);
1260c0d06caSMauro Carvalho Chehab 
1270c0d06caSMauro Carvalho Chehab 	for (i = 0; i < count; i++) {
1280c0d06caSMauro Carvalho Chehab 
1290c0d06caSMauro Carvalho Chehab 		buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
1300c0d06caSMauro Carvalho Chehab 		if (!buf) {
1310c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n");
1320c0d06caSMauro Carvalho Chehab 			goto exit;
1330c0d06caSMauro Carvalho Chehab 		}
1340c0d06caSMauro Carvalho Chehab 		buf->dev = dev;
1350c0d06caSMauro Carvalho Chehab 
1360c0d06caSMauro Carvalho Chehab 		urb = usb_alloc_urb(0, GFP_KERNEL);
1370c0d06caSMauro Carvalho Chehab 		if (!urb) {
1380c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n");
1390c0d06caSMauro Carvalho Chehab 			goto exit_urb;
1400c0d06caSMauro Carvalho Chehab 		}
1410c0d06caSMauro Carvalho Chehab 		buf->urb = urb;
1420c0d06caSMauro Carvalho Chehab 
1430c0d06caSMauro Carvalho Chehab 		mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL,
1440c0d06caSMauro Carvalho Chehab 					 &urb->transfer_dma);
1450c0d06caSMauro Carvalho Chehab 		if (!mem) {
1460c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
1470c0d06caSMauro Carvalho Chehab 				 "cannot allocate usb transfer buffer\n");
1480c0d06caSMauro Carvalho Chehab 			goto exit_urb_buffer;
1490c0d06caSMauro Carvalho Chehab 		}
1500c0d06caSMauro Carvalho Chehab 
1510c0d06caSMauro Carvalho Chehab 		usb_fill_bulk_urb(buf->urb, dev->udev,
1520c0d06caSMauro Carvalho Chehab 				  usb_rcvbulkpipe(dev->udev,
1530c0d06caSMauro Carvalho Chehab 						  dev->bulk_in_endpointAddr),
1540c0d06caSMauro Carvalho Chehab 				  mem, dev->bulk_in_size,
1550c0d06caSMauro Carvalho Chehab 				  hdpvr_read_bulk_callback, buf);
1560c0d06caSMauro Carvalho Chehab 
1570c0d06caSMauro Carvalho Chehab 		buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1580c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_AVAILABLE;
1590c0d06caSMauro Carvalho Chehab 		list_add_tail(&buf->buff_list, &dev->free_buff_list);
1600c0d06caSMauro Carvalho Chehab 	}
1610c0d06caSMauro Carvalho Chehab 	return 0;
1620c0d06caSMauro Carvalho Chehab exit_urb_buffer:
1630c0d06caSMauro Carvalho Chehab 	usb_free_urb(urb);
1640c0d06caSMauro Carvalho Chehab exit_urb:
1650c0d06caSMauro Carvalho Chehab 	kfree(buf);
1660c0d06caSMauro Carvalho Chehab exit:
1670c0d06caSMauro Carvalho Chehab 	hdpvr_free_buffers(dev);
1680c0d06caSMauro Carvalho Chehab 	return retval;
1690c0d06caSMauro Carvalho Chehab }
1700c0d06caSMauro Carvalho Chehab 
1710c0d06caSMauro Carvalho Chehab static int hdpvr_submit_buffers(struct hdpvr_device *dev)
1720c0d06caSMauro Carvalho Chehab {
1730c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
1740c0d06caSMauro Carvalho Chehab 	struct urb *urb;
1750c0d06caSMauro Carvalho Chehab 	int ret = 0, err_count = 0;
1760c0d06caSMauro Carvalho Chehab 
1770c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
1780c0d06caSMauro Carvalho Chehab 
1790c0d06caSMauro Carvalho Chehab 	while (dev->status == STATUS_STREAMING &&
1800c0d06caSMauro Carvalho Chehab 	       !list_empty(&dev->free_buff_list)) {
1810c0d06caSMauro Carvalho Chehab 
1820c0d06caSMauro Carvalho Chehab 		buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
1830c0d06caSMauro Carvalho Chehab 				 buff_list);
1840c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_AVAILABLE) {
1850c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
1860c0d06caSMauro Carvalho Chehab 				 "buffer not marked as available\n");
1870c0d06caSMauro Carvalho Chehab 			ret = -EFAULT;
1880c0d06caSMauro Carvalho Chehab 			goto err;
1890c0d06caSMauro Carvalho Chehab 		}
1900c0d06caSMauro Carvalho Chehab 
1910c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
1920c0d06caSMauro Carvalho Chehab 		urb->status = 0;
1930c0d06caSMauro Carvalho Chehab 		urb->actual_length = 0;
1940c0d06caSMauro Carvalho Chehab 		ret = usb_submit_urb(urb, GFP_KERNEL);
1950c0d06caSMauro Carvalho Chehab 		if (ret) {
1960c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
1970c0d06caSMauro Carvalho Chehab 				 "usb_submit_urb in %s returned %d\n",
1980c0d06caSMauro Carvalho Chehab 				 __func__, ret);
1990c0d06caSMauro Carvalho Chehab 			if (++err_count > 2)
2000c0d06caSMauro Carvalho Chehab 				break;
2010c0d06caSMauro Carvalho Chehab 			continue;
2020c0d06caSMauro Carvalho Chehab 		}
2030c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_INPROGRESS;
2040c0d06caSMauro Carvalho Chehab 		list_move_tail(&buf->buff_list, &dev->rec_buff_list);
2050c0d06caSMauro Carvalho Chehab 	}
2060c0d06caSMauro Carvalho Chehab err:
2070c0d06caSMauro Carvalho Chehab 	print_buffer_status();
2080c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
2090c0d06caSMauro Carvalho Chehab 	return ret;
2100c0d06caSMauro Carvalho Chehab }
2110c0d06caSMauro Carvalho Chehab 
2120c0d06caSMauro Carvalho Chehab static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev)
2130c0d06caSMauro Carvalho Chehab {
2140c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
2150c0d06caSMauro Carvalho Chehab 
2160c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
2170c0d06caSMauro Carvalho Chehab 
2180c0d06caSMauro Carvalho Chehab 	if (list_empty(&dev->rec_buff_list)) {
2190c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->io_mutex);
2200c0d06caSMauro Carvalho Chehab 		return NULL;
2210c0d06caSMauro Carvalho Chehab 	}
2220c0d06caSMauro Carvalho Chehab 
2230c0d06caSMauro Carvalho Chehab 	buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer,
2240c0d06caSMauro Carvalho Chehab 			 buff_list);
2250c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
2260c0d06caSMauro Carvalho Chehab 
2270c0d06caSMauro Carvalho Chehab 	return buf;
2280c0d06caSMauro Carvalho Chehab }
2290c0d06caSMauro Carvalho Chehab 
2300c0d06caSMauro Carvalho Chehab static void hdpvr_transmit_buffers(struct work_struct *work)
2310c0d06caSMauro Carvalho Chehab {
2320c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = container_of(work, struct hdpvr_device,
2330c0d06caSMauro Carvalho Chehab 						worker);
2340c0d06caSMauro Carvalho Chehab 
2350c0d06caSMauro Carvalho Chehab 	while (dev->status == STATUS_STREAMING) {
2360c0d06caSMauro Carvalho Chehab 
2370c0d06caSMauro Carvalho Chehab 		if (hdpvr_submit_buffers(dev)) {
2380c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n");
2390c0d06caSMauro Carvalho Chehab 			goto error;
2400c0d06caSMauro Carvalho Chehab 		}
2410c0d06caSMauro Carvalho Chehab 		if (wait_event_interruptible(dev->wait_buffer,
2420c0d06caSMauro Carvalho Chehab 				!list_empty(&dev->free_buff_list) ||
2430c0d06caSMauro Carvalho Chehab 					     dev->status != STATUS_STREAMING))
2440c0d06caSMauro Carvalho Chehab 			goto error;
2450c0d06caSMauro Carvalho Chehab 	}
2460c0d06caSMauro Carvalho Chehab 
2470c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2480c0d06caSMauro Carvalho Chehab 		 "transmit worker exited\n");
2490c0d06caSMauro Carvalho Chehab 	return;
2500c0d06caSMauro Carvalho Chehab error:
2510c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2520c0d06caSMauro Carvalho Chehab 		 "transmit buffers errored\n");
2530c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_ERROR;
2540c0d06caSMauro Carvalho Chehab }
2550c0d06caSMauro Carvalho Chehab 
2560c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
2570c0d06caSMauro Carvalho Chehab static int hdpvr_start_streaming(struct hdpvr_device *dev)
2580c0d06caSMauro Carvalho Chehab {
2590c0d06caSMauro Carvalho Chehab 	int ret;
2600c0d06caSMauro Carvalho Chehab 	struct hdpvr_video_info *vidinf;
2610c0d06caSMauro Carvalho Chehab 
2620c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_STREAMING)
2630c0d06caSMauro Carvalho Chehab 		return 0;
2640c0d06caSMauro Carvalho Chehab 	else if (dev->status != STATUS_IDLE)
2650c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
2660c0d06caSMauro Carvalho Chehab 
2670c0d06caSMauro Carvalho Chehab 	vidinf = get_video_info(dev);
2680c0d06caSMauro Carvalho Chehab 
2690c0d06caSMauro Carvalho Chehab 	if (vidinf) {
2700c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
2710c0d06caSMauro Carvalho Chehab 			 "video signal: %dx%d@%dhz\n", vidinf->width,
2720c0d06caSMauro Carvalho Chehab 			 vidinf->height, vidinf->fps);
2730c0d06caSMauro Carvalho Chehab 		kfree(vidinf);
2740c0d06caSMauro Carvalho Chehab 
2750c0d06caSMauro Carvalho Chehab 		/* start streaming 2 request */
2760c0d06caSMauro Carvalho Chehab 		ret = usb_control_msg(dev->udev,
2770c0d06caSMauro Carvalho Chehab 				      usb_sndctrlpipe(dev->udev, 0),
2780c0d06caSMauro Carvalho Chehab 				      0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
2790c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
2800c0d06caSMauro Carvalho Chehab 			 "encoder start control request returned %d\n", ret);
2810c0d06caSMauro Carvalho Chehab 
2820c0d06caSMauro Carvalho Chehab 		hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
2830c0d06caSMauro Carvalho Chehab 
2840c0d06caSMauro Carvalho Chehab 		dev->status = STATUS_STREAMING;
2850c0d06caSMauro Carvalho Chehab 
2860c0d06caSMauro Carvalho Chehab 		INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
2870c0d06caSMauro Carvalho Chehab 		queue_work(dev->workqueue, &dev->worker);
2880c0d06caSMauro Carvalho Chehab 
2890c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
2900c0d06caSMauro Carvalho Chehab 			 "streaming started\n");
2910c0d06caSMauro Carvalho Chehab 
2920c0d06caSMauro Carvalho Chehab 		return 0;
2930c0d06caSMauro Carvalho Chehab 	}
2940c0d06caSMauro Carvalho Chehab 	msleep(250);
2950c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2960c0d06caSMauro Carvalho Chehab 		 "no video signal at input %d\n", dev->options.video_input);
2970c0d06caSMauro Carvalho Chehab 	return -EAGAIN;
2980c0d06caSMauro Carvalho Chehab }
2990c0d06caSMauro Carvalho Chehab 
3000c0d06caSMauro Carvalho Chehab 
3010c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
3020c0d06caSMauro Carvalho Chehab static int hdpvr_stop_streaming(struct hdpvr_device *dev)
3030c0d06caSMauro Carvalho Chehab {
3040c0d06caSMauro Carvalho Chehab 	int actual_length;
3050c0d06caSMauro Carvalho Chehab 	uint c = 0;
3060c0d06caSMauro Carvalho Chehab 	u8 *buf;
3070c0d06caSMauro Carvalho Chehab 
3080c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE)
3090c0d06caSMauro Carvalho Chehab 		return 0;
3100c0d06caSMauro Carvalho Chehab 	else if (dev->status != STATUS_STREAMING)
3110c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
3120c0d06caSMauro Carvalho Chehab 
3130c0d06caSMauro Carvalho Chehab 	buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
3140c0d06caSMauro Carvalho Chehab 	if (!buf)
3150c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer "
3160c0d06caSMauro Carvalho Chehab 			 "for emptying the internal device buffer. "
3170c0d06caSMauro Carvalho Chehab 			 "Next capture start will be slow\n");
3180c0d06caSMauro Carvalho Chehab 
3190c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_SHUTTING_DOWN;
3200c0d06caSMauro Carvalho Chehab 	hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
3210c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3220c0d06caSMauro Carvalho Chehab 
3230c0d06caSMauro Carvalho Chehab 	wake_up_interruptible(&dev->wait_buffer);
3240c0d06caSMauro Carvalho Chehab 	msleep(50);
3250c0d06caSMauro Carvalho Chehab 
3260c0d06caSMauro Carvalho Chehab 	flush_workqueue(dev->workqueue);
3270c0d06caSMauro Carvalho Chehab 
3280c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
3290c0d06caSMauro Carvalho Chehab 	/* kill the still outstanding urbs */
3300c0d06caSMauro Carvalho Chehab 	hdpvr_cancel_queue(dev);
3310c0d06caSMauro Carvalho Chehab 
3320c0d06caSMauro Carvalho Chehab 	/* emptying the device buffer beforeshutting it down */
3330c0d06caSMauro Carvalho Chehab 	while (buf && ++c < 500 &&
3340c0d06caSMauro Carvalho Chehab 	       !usb_bulk_msg(dev->udev,
3350c0d06caSMauro Carvalho Chehab 			     usb_rcvbulkpipe(dev->udev,
3360c0d06caSMauro Carvalho Chehab 					     dev->bulk_in_endpointAddr),
3370c0d06caSMauro Carvalho Chehab 			     buf, dev->bulk_in_size, &actual_length,
3380c0d06caSMauro Carvalho Chehab 			     BULK_URB_TIMEOUT)) {
3390c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3400c0d06caSMauro Carvalho Chehab 			 "%2d: got %d bytes\n", c, actual_length);
3410c0d06caSMauro Carvalho Chehab 	}
3420c0d06caSMauro Carvalho Chehab 	kfree(buf);
3430c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3440c0d06caSMauro Carvalho Chehab 		 "used %d urbs to empty device buffers\n", c-1);
3450c0d06caSMauro Carvalho Chehab 	msleep(10);
3460c0d06caSMauro Carvalho Chehab 
3470c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_IDLE;
3480c0d06caSMauro Carvalho Chehab 
3490c0d06caSMauro Carvalho Chehab 	return 0;
3500c0d06caSMauro Carvalho Chehab }
3510c0d06caSMauro Carvalho Chehab 
3520c0d06caSMauro Carvalho Chehab 
3530c0d06caSMauro Carvalho Chehab /*=======================================================================*/
3540c0d06caSMauro Carvalho Chehab /*
3550c0d06caSMauro Carvalho Chehab  * video 4 linux 2 file operations
3560c0d06caSMauro Carvalho Chehab  */
3570c0d06caSMauro Carvalho Chehab 
3580c0d06caSMauro Carvalho Chehab static int hdpvr_release(struct file *file)
3590c0d06caSMauro Carvalho Chehab {
360ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
3610c0d06caSMauro Carvalho Chehab 
3620c0d06caSMauro Carvalho Chehab 	if (!dev)
3630c0d06caSMauro Carvalho Chehab 		return -ENODEV;
3640c0d06caSMauro Carvalho Chehab 
3650c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
366ede197aaSHans Verkuil 	if (file->private_data == dev->owner) {
3670c0d06caSMauro Carvalho Chehab 		hdpvr_stop_streaming(dev);
368ede197aaSHans Verkuil 		dev->owner = NULL;
369ede197aaSHans Verkuil 	}
3700c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3710c0d06caSMauro Carvalho Chehab 
372ede197aaSHans Verkuil 	return v4l2_fh_release(file);
3730c0d06caSMauro Carvalho Chehab }
3740c0d06caSMauro Carvalho Chehab 
3750c0d06caSMauro Carvalho Chehab /*
3760c0d06caSMauro Carvalho Chehab  * hdpvr_v4l2_read()
3770c0d06caSMauro Carvalho Chehab  * will allocate buffers when called for the first time
3780c0d06caSMauro Carvalho Chehab  */
3790c0d06caSMauro Carvalho Chehab static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
3800c0d06caSMauro Carvalho Chehab 			  loff_t *pos)
3810c0d06caSMauro Carvalho Chehab {
382ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
3830c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
3840c0d06caSMauro Carvalho Chehab 	struct urb *urb;
3850c0d06caSMauro Carvalho Chehab 	unsigned int ret = 0;
3860c0d06caSMauro Carvalho Chehab 	int rem, cnt;
3870c0d06caSMauro Carvalho Chehab 
3880c0d06caSMauro Carvalho Chehab 	if (*pos)
3890c0d06caSMauro Carvalho Chehab 		return -ESPIPE;
3900c0d06caSMauro Carvalho Chehab 
3910c0d06caSMauro Carvalho Chehab 	if (!dev)
3920c0d06caSMauro Carvalho Chehab 		return -ENODEV;
3930c0d06caSMauro Carvalho Chehab 
3940c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
3950c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
3960c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
3970c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
3980c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
3990c0d06caSMauro Carvalho Chehab 			ret = -EIO;
4000c0d06caSMauro Carvalho Chehab 			msleep(200);
4010c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
4020c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
4030c0d06caSMauro Carvalho Chehab 			goto err;
4040c0d06caSMauro Carvalho Chehab 		}
405ede197aaSHans Verkuil 		dev->owner = file->private_data;
4060c0d06caSMauro Carvalho Chehab 		print_buffer_status();
4070c0d06caSMauro Carvalho Chehab 	}
4080c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
4090c0d06caSMauro Carvalho Chehab 
4100c0d06caSMauro Carvalho Chehab 	/* wait for the first buffer */
4110c0d06caSMauro Carvalho Chehab 	if (!(file->f_flags & O_NONBLOCK)) {
4120c0d06caSMauro Carvalho Chehab 		if (wait_event_interruptible(dev->wait_data,
4130c0d06caSMauro Carvalho Chehab 					     hdpvr_get_next_buffer(dev)))
4140c0d06caSMauro Carvalho Chehab 			return -ERESTARTSYS;
4150c0d06caSMauro Carvalho Chehab 	}
4160c0d06caSMauro Carvalho Chehab 
4170c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
4180c0d06caSMauro Carvalho Chehab 
4190c0d06caSMauro Carvalho Chehab 	while (count > 0 && buf) {
4200c0d06caSMauro Carvalho Chehab 
4210c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY &&
4220c0d06caSMauro Carvalho Chehab 		    dev->status != STATUS_DISCONNECTED) {
4230c0d06caSMauro Carvalho Chehab 			/* return nonblocking */
4240c0d06caSMauro Carvalho Chehab 			if (file->f_flags & O_NONBLOCK) {
4250c0d06caSMauro Carvalho Chehab 				if (!ret)
4260c0d06caSMauro Carvalho Chehab 					ret = -EAGAIN;
4270c0d06caSMauro Carvalho Chehab 				goto err;
4280c0d06caSMauro Carvalho Chehab 			}
4290c0d06caSMauro Carvalho Chehab 
4300c0d06caSMauro Carvalho Chehab 			if (wait_event_interruptible(dev->wait_data,
4310c0d06caSMauro Carvalho Chehab 					      buf->status == BUFSTAT_READY)) {
4320c0d06caSMauro Carvalho Chehab 				ret = -ERESTARTSYS;
4330c0d06caSMauro Carvalho Chehab 				goto err;
4340c0d06caSMauro Carvalho Chehab 			}
4350c0d06caSMauro Carvalho Chehab 		}
4360c0d06caSMauro Carvalho Chehab 
4370c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY)
4380c0d06caSMauro Carvalho Chehab 			break;
4390c0d06caSMauro Carvalho Chehab 
4400c0d06caSMauro Carvalho Chehab 		/* set remaining bytes to copy */
4410c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
4420c0d06caSMauro Carvalho Chehab 		rem = urb->actual_length - buf->pos;
4430c0d06caSMauro Carvalho Chehab 		cnt = rem > count ? count : rem;
4440c0d06caSMauro Carvalho Chehab 
4450c0d06caSMauro Carvalho Chehab 		if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
4460c0d06caSMauro Carvalho Chehab 				 cnt)) {
4470c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
4480c0d06caSMauro Carvalho Chehab 			if (!ret)
4490c0d06caSMauro Carvalho Chehab 				ret = -EFAULT;
4500c0d06caSMauro Carvalho Chehab 			goto err;
4510c0d06caSMauro Carvalho Chehab 		}
4520c0d06caSMauro Carvalho Chehab 
4530c0d06caSMauro Carvalho Chehab 		buf->pos += cnt;
4540c0d06caSMauro Carvalho Chehab 		count -= cnt;
4550c0d06caSMauro Carvalho Chehab 		buffer += cnt;
4560c0d06caSMauro Carvalho Chehab 		ret += cnt;
4570c0d06caSMauro Carvalho Chehab 
4580c0d06caSMauro Carvalho Chehab 		/* finished, take next buffer */
4590c0d06caSMauro Carvalho Chehab 		if (buf->pos == urb->actual_length) {
4600c0d06caSMauro Carvalho Chehab 			mutex_lock(&dev->io_mutex);
4610c0d06caSMauro Carvalho Chehab 			buf->pos = 0;
4620c0d06caSMauro Carvalho Chehab 			buf->status = BUFSTAT_AVAILABLE;
4630c0d06caSMauro Carvalho Chehab 
4640c0d06caSMauro Carvalho Chehab 			list_move_tail(&buf->buff_list, &dev->free_buff_list);
4650c0d06caSMauro Carvalho Chehab 
4660c0d06caSMauro Carvalho Chehab 			print_buffer_status();
4670c0d06caSMauro Carvalho Chehab 
4680c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
4690c0d06caSMauro Carvalho Chehab 
4700c0d06caSMauro Carvalho Chehab 			wake_up_interruptible(&dev->wait_buffer);
4710c0d06caSMauro Carvalho Chehab 
4720c0d06caSMauro Carvalho Chehab 			buf = hdpvr_get_next_buffer(dev);
4730c0d06caSMauro Carvalho Chehab 		}
4740c0d06caSMauro Carvalho Chehab 	}
4750c0d06caSMauro Carvalho Chehab err:
4760c0d06caSMauro Carvalho Chehab 	if (!ret && !buf)
4770c0d06caSMauro Carvalho Chehab 		ret = -EAGAIN;
4780c0d06caSMauro Carvalho Chehab 	return ret;
4790c0d06caSMauro Carvalho Chehab }
4800c0d06caSMauro Carvalho Chehab 
4810c0d06caSMauro Carvalho Chehab static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
4820c0d06caSMauro Carvalho Chehab {
48365fe42d6SHans Verkuil 	unsigned long req_events = poll_requested_events(wait);
4840c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
485ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(filp);
48665fe42d6SHans Verkuil 	unsigned int mask = v4l2_ctrl_poll(filp, wait);
48765fe42d6SHans Verkuil 
48865fe42d6SHans Verkuil 	if (!(req_events & (POLLIN | POLLRDNORM)))
48965fe42d6SHans Verkuil 		return mask;
4900c0d06caSMauro Carvalho Chehab 
4910c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
4920c0d06caSMauro Carvalho Chehab 
4930c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
4940c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
4950c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
4960c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
4970c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
498ede197aaSHans Verkuil 		} else {
499ede197aaSHans Verkuil 			dev->owner = filp->private_data;
5000c0d06caSMauro Carvalho Chehab 		}
5010c0d06caSMauro Carvalho Chehab 
5020c0d06caSMauro Carvalho Chehab 		print_buffer_status();
5030c0d06caSMauro Carvalho Chehab 	}
5040c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
5050c0d06caSMauro Carvalho Chehab 
5060c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
5070c0d06caSMauro Carvalho Chehab 	/* only wait if no data is available */
5080c0d06caSMauro Carvalho Chehab 	if (!buf || buf->status != BUFSTAT_READY) {
5090c0d06caSMauro Carvalho Chehab 		poll_wait(filp, &dev->wait_data, wait);
5100c0d06caSMauro Carvalho Chehab 		buf = hdpvr_get_next_buffer(dev);
5110c0d06caSMauro Carvalho Chehab 	}
5120c0d06caSMauro Carvalho Chehab 	if (buf && buf->status == BUFSTAT_READY)
5130c0d06caSMauro Carvalho Chehab 		mask |= POLLIN | POLLRDNORM;
5140c0d06caSMauro Carvalho Chehab 
5150c0d06caSMauro Carvalho Chehab 	return mask;
5160c0d06caSMauro Carvalho Chehab }
5170c0d06caSMauro Carvalho Chehab 
5180c0d06caSMauro Carvalho Chehab 
5190c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations hdpvr_fops = {
5200c0d06caSMauro Carvalho Chehab 	.owner		= THIS_MODULE,
521ede197aaSHans Verkuil 	.open		= v4l2_fh_open,
5220c0d06caSMauro Carvalho Chehab 	.release	= hdpvr_release,
5230c0d06caSMauro Carvalho Chehab 	.read		= hdpvr_read,
5240c0d06caSMauro Carvalho Chehab 	.poll		= hdpvr_poll,
5250c0d06caSMauro Carvalho Chehab 	.unlocked_ioctl	= video_ioctl2,
5260c0d06caSMauro Carvalho Chehab };
5270c0d06caSMauro Carvalho Chehab 
5280c0d06caSMauro Carvalho Chehab /*=======================================================================*/
5290c0d06caSMauro Carvalho Chehab /*
5300c0d06caSMauro Carvalho Chehab  * V4L2 ioctl handling
5310c0d06caSMauro Carvalho Chehab  */
5320c0d06caSMauro Carvalho Chehab 
5330c0d06caSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void  *priv,
5340c0d06caSMauro Carvalho Chehab 			   struct v4l2_capability *cap)
5350c0d06caSMauro Carvalho Chehab {
5360c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_drvdata(file);
5370c0d06caSMauro Carvalho Chehab 
5380c0d06caSMauro Carvalho Chehab 	strcpy(cap->driver, "hdpvr");
5390c0d06caSMauro Carvalho Chehab 	strcpy(cap->card, "Hauppauge HD PVR");
5400c0d06caSMauro Carvalho Chehab 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
54141022fcbSHans Verkuil 	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
5420c0d06caSMauro Carvalho Chehab 			    V4L2_CAP_READWRITE;
54341022fcbSHans Verkuil 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
5440c0d06caSMauro Carvalho Chehab 	return 0;
5450c0d06caSMauro Carvalho Chehab }
5460c0d06caSMauro Carvalho Chehab 
5470c0d06caSMauro Carvalho Chehab static int vidioc_s_std(struct file *file, void *private_data,
548314527acSHans Verkuil 			v4l2_std_id std)
5490c0d06caSMauro Carvalho Chehab {
550ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
5510c0d06caSMauro Carvalho Chehab 	u8 std_type = 1;
5520c0d06caSMauro Carvalho Chehab 
553314527acSHans Verkuil 	if (std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
5540c0d06caSMauro Carvalho Chehab 		std_type = 0;
5550c0d06caSMauro Carvalho Chehab 
5560c0d06caSMauro Carvalho Chehab 	return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
5570c0d06caSMauro Carvalho Chehab }
5580c0d06caSMauro Carvalho Chehab 
5590c0d06caSMauro Carvalho Chehab static const char *iname[] = {
5600c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPONENT] = "Component",
5610c0d06caSMauro Carvalho Chehab 	[HDPVR_SVIDEO]    = "S-Video",
5620c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPOSITE] = "Composite",
5630c0d06caSMauro Carvalho Chehab };
5640c0d06caSMauro Carvalho Chehab 
5650c0d06caSMauro Carvalho Chehab static int vidioc_enum_input(struct file *file, void *priv,
5660c0d06caSMauro Carvalho Chehab 				struct v4l2_input *i)
5670c0d06caSMauro Carvalho Chehab {
568ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
5690c0d06caSMauro Carvalho Chehab 	unsigned int n;
5700c0d06caSMauro Carvalho Chehab 
5710c0d06caSMauro Carvalho Chehab 	n = i->index;
5720c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_VIDEO_INPUTS)
5730c0d06caSMauro Carvalho Chehab 		return -EINVAL;
5740c0d06caSMauro Carvalho Chehab 
5750c0d06caSMauro Carvalho Chehab 	i->type = V4L2_INPUT_TYPE_CAMERA;
5760c0d06caSMauro Carvalho Chehab 
5770c0d06caSMauro Carvalho Chehab 	strncpy(i->name, iname[n], sizeof(i->name) - 1);
5780c0d06caSMauro Carvalho Chehab 	i->name[sizeof(i->name) - 1] = '\0';
5790c0d06caSMauro Carvalho Chehab 
5800c0d06caSMauro Carvalho Chehab 	i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
5810c0d06caSMauro Carvalho Chehab 
5820c0d06caSMauro Carvalho Chehab 	i->std = dev->video_dev->tvnorms;
5830c0d06caSMauro Carvalho Chehab 
5840c0d06caSMauro Carvalho Chehab 	return 0;
5850c0d06caSMauro Carvalho Chehab }
5860c0d06caSMauro Carvalho Chehab 
5870c0d06caSMauro Carvalho Chehab static int vidioc_s_input(struct file *file, void *private_data,
5880c0d06caSMauro Carvalho Chehab 			  unsigned int index)
5890c0d06caSMauro Carvalho Chehab {
590ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
5910c0d06caSMauro Carvalho Chehab 	int retval;
5920c0d06caSMauro Carvalho Chehab 
5930c0d06caSMauro Carvalho Chehab 	if (index >= HDPVR_VIDEO_INPUTS)
5940c0d06caSMauro Carvalho Chehab 		return -EINVAL;
5950c0d06caSMauro Carvalho Chehab 
5960c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
5970c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
5980c0d06caSMauro Carvalho Chehab 
5990c0d06caSMauro Carvalho Chehab 	retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
6000c0d06caSMauro Carvalho Chehab 	if (!retval)
6010c0d06caSMauro Carvalho Chehab 		dev->options.video_input = index;
6020c0d06caSMauro Carvalho Chehab 
6030c0d06caSMauro Carvalho Chehab 	return retval;
6040c0d06caSMauro Carvalho Chehab }
6050c0d06caSMauro Carvalho Chehab 
6060c0d06caSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *private_data,
6070c0d06caSMauro Carvalho Chehab 			  unsigned int *index)
6080c0d06caSMauro Carvalho Chehab {
609ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6100c0d06caSMauro Carvalho Chehab 
6110c0d06caSMauro Carvalho Chehab 	*index = dev->options.video_input;
6120c0d06caSMauro Carvalho Chehab 	return 0;
6130c0d06caSMauro Carvalho Chehab }
6140c0d06caSMauro Carvalho Chehab 
6150c0d06caSMauro Carvalho Chehab 
6160c0d06caSMauro Carvalho Chehab static const char *audio_iname[] = {
6170c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_FRONT] = "RCA front",
6180c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_BACK]  = "RCA back",
6190c0d06caSMauro Carvalho Chehab 	[HDPVR_SPDIF]     = "SPDIF",
6200c0d06caSMauro Carvalho Chehab };
6210c0d06caSMauro Carvalho Chehab 
6220c0d06caSMauro Carvalho Chehab static int vidioc_enumaudio(struct file *file, void *priv,
6230c0d06caSMauro Carvalho Chehab 				struct v4l2_audio *audio)
6240c0d06caSMauro Carvalho Chehab {
6250c0d06caSMauro Carvalho Chehab 	unsigned int n;
6260c0d06caSMauro Carvalho Chehab 
6270c0d06caSMauro Carvalho Chehab 	n = audio->index;
6280c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_AUDIO_INPUTS)
6290c0d06caSMauro Carvalho Chehab 		return -EINVAL;
6300c0d06caSMauro Carvalho Chehab 
6310c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
6320c0d06caSMauro Carvalho Chehab 
6330c0d06caSMauro Carvalho Chehab 	strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1);
6340c0d06caSMauro Carvalho Chehab 	audio->name[sizeof(audio->name) - 1] = '\0';
6350c0d06caSMauro Carvalho Chehab 
6360c0d06caSMauro Carvalho Chehab 	return 0;
6370c0d06caSMauro Carvalho Chehab }
6380c0d06caSMauro Carvalho Chehab 
6390c0d06caSMauro Carvalho Chehab static int vidioc_s_audio(struct file *file, void *private_data,
6400e8025b9SHans Verkuil 			  const struct v4l2_audio *audio)
6410c0d06caSMauro Carvalho Chehab {
642ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6430c0d06caSMauro Carvalho Chehab 	int retval;
6440c0d06caSMauro Carvalho Chehab 
6450c0d06caSMauro Carvalho Chehab 	if (audio->index >= HDPVR_AUDIO_INPUTS)
6460c0d06caSMauro Carvalho Chehab 		return -EINVAL;
6470c0d06caSMauro Carvalho Chehab 
6480c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
6490c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
6500c0d06caSMauro Carvalho Chehab 
6510c0d06caSMauro Carvalho Chehab 	retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
6520c0d06caSMauro Carvalho Chehab 	if (!retval)
6530c0d06caSMauro Carvalho Chehab 		dev->options.audio_input = audio->index;
6540c0d06caSMauro Carvalho Chehab 
6550c0d06caSMauro Carvalho Chehab 	return retval;
6560c0d06caSMauro Carvalho Chehab }
6570c0d06caSMauro Carvalho Chehab 
6580c0d06caSMauro Carvalho Chehab static int vidioc_g_audio(struct file *file, void *private_data,
6590c0d06caSMauro Carvalho Chehab 			  struct v4l2_audio *audio)
6600c0d06caSMauro Carvalho Chehab {
661ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
6620c0d06caSMauro Carvalho Chehab 
6630c0d06caSMauro Carvalho Chehab 	audio->index = dev->options.audio_input;
6640c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
6650c0d06caSMauro Carvalho Chehab 	strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
6660c0d06caSMauro Carvalho Chehab 	audio->name[sizeof(audio->name) - 1] = '\0';
6670c0d06caSMauro Carvalho Chehab 	return 0;
6680c0d06caSMauro Carvalho Chehab }
6690c0d06caSMauro Carvalho Chehab 
67099c77aa4SHans Verkuil static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl)
6710c0d06caSMauro Carvalho Chehab {
67299c77aa4SHans Verkuil 	struct hdpvr_device *dev =
67399c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
6740c0d06caSMauro Carvalho Chehab 
6750c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
67699c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
67799c77aa4SHans Verkuil 		if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
67899c77aa4SHans Verkuil 		    dev->video_bitrate->val >= dev->video_bitrate_peak->val)
67999c77aa4SHans Verkuil 			dev->video_bitrate_peak->val =
68099c77aa4SHans Verkuil 					dev->video_bitrate->val + 100000;
6810c0d06caSMauro Carvalho Chehab 		break;
6820c0d06caSMauro Carvalho Chehab 	}
6830c0d06caSMauro Carvalho Chehab 	return 0;
6840c0d06caSMauro Carvalho Chehab }
6850c0d06caSMauro Carvalho Chehab 
68699c77aa4SHans Verkuil static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
6870c0d06caSMauro Carvalho Chehab {
68899c77aa4SHans Verkuil 	struct hdpvr_device *dev =
68999c77aa4SHans Verkuil 		container_of(ctrl->handler, struct hdpvr_device, hdl);
69099c77aa4SHans Verkuil 	struct hdpvr_options *opt = &dev->options;
6910c0d06caSMauro Carvalho Chehab 	int ret = -EINVAL;
6920c0d06caSMauro Carvalho Chehab 
6930c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
69499c77aa4SHans Verkuil 	case V4L2_CID_BRIGHTNESS:
69599c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val);
69699c77aa4SHans Verkuil 		if (ret)
6970c0d06caSMauro Carvalho Chehab 			break;
69899c77aa4SHans Verkuil 		dev->options.brightness = ctrl->val;
69999c77aa4SHans Verkuil 		return 0;
70099c77aa4SHans Verkuil 	case V4L2_CID_CONTRAST:
70199c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val);
70299c77aa4SHans Verkuil 		if (ret)
7030c0d06caSMauro Carvalho Chehab 			break;
70499c77aa4SHans Verkuil 		dev->options.contrast = ctrl->val;
70599c77aa4SHans Verkuil 		return 0;
70699c77aa4SHans Verkuil 	case V4L2_CID_SATURATION:
70799c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val);
70899c77aa4SHans Verkuil 		if (ret)
7090c0d06caSMauro Carvalho Chehab 			break;
71099c77aa4SHans Verkuil 		dev->options.saturation = ctrl->val;
71199c77aa4SHans Verkuil 		return 0;
71299c77aa4SHans Verkuil 	case V4L2_CID_HUE:
71399c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val);
71499c77aa4SHans Verkuil 		if (ret)
7150c0d06caSMauro Carvalho Chehab 			break;
71699c77aa4SHans Verkuil 		dev->options.hue = ctrl->val;
71799c77aa4SHans Verkuil 		return 0;
71899c77aa4SHans Verkuil 	case V4L2_CID_SHARPNESS:
71999c77aa4SHans Verkuil 		ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val);
72099c77aa4SHans Verkuil 		if (ret)
7210c0d06caSMauro Carvalho Chehab 			break;
72299c77aa4SHans Verkuil 		dev->options.sharpness = ctrl->val;
72399c77aa4SHans Verkuil 		return 0;
7240c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
7250c0d06caSMauro Carvalho Chehab 		if (dev->flags & HDPVR_FLAG_AC3_CAP) {
72699c77aa4SHans Verkuil 			opt->audio_codec = ctrl->val;
72799c77aa4SHans Verkuil 			return hdpvr_set_audio(dev, opt->audio_input,
7280c0d06caSMauro Carvalho Chehab 					      opt->audio_codec);
7290c0d06caSMauro Carvalho Chehab 		}
73099c77aa4SHans Verkuil 		return 0;
7310c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
73299c77aa4SHans Verkuil 		return 0;
7330c0d06caSMauro Carvalho Chehab /* 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
7340c0d06caSMauro Carvalho Chehab /* 		if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
7350c0d06caSMauro Carvalho Chehab /* 			opt->gop_mode |= 0x2; */
7360c0d06caSMauro Carvalho Chehab /* 			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
7370c0d06caSMauro Carvalho Chehab /* 					  opt->gop_mode); */
7380c0d06caSMauro Carvalho Chehab /* 		} */
7390c0d06caSMauro Carvalho Chehab /* 		if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
7400c0d06caSMauro Carvalho Chehab /* 			opt->gop_mode &= ~0x2; */
7410c0d06caSMauro Carvalho Chehab /* 			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
7420c0d06caSMauro Carvalho Chehab /* 					  opt->gop_mode); */
7430c0d06caSMauro Carvalho Chehab /* 		} */
7440c0d06caSMauro Carvalho Chehab /* 		break; */
74599c77aa4SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
74699c77aa4SHans Verkuil 		uint peak_bitrate = dev->video_bitrate_peak->val / 100000;
74799c77aa4SHans Verkuil 		uint bitrate = dev->video_bitrate->val / 100000;
74899c77aa4SHans Verkuil 
74999c77aa4SHans Verkuil 		if (ctrl->is_new) {
75099c77aa4SHans Verkuil 			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
7510c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_CONSTANT;
75299c77aa4SHans Verkuil 			else
7530c0d06caSMauro Carvalho Chehab 				opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
7540c0d06caSMauro Carvalho Chehab 			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
7550c0d06caSMauro Carvalho Chehab 					  opt->bitrate_mode);
75699c77aa4SHans Verkuil 			v4l2_ctrl_activate(dev->video_bitrate_peak,
75799c77aa4SHans Verkuil 				ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
7580c0d06caSMauro Carvalho Chehab 		}
7590c0d06caSMauro Carvalho Chehab 
76099c77aa4SHans Verkuil 		if (dev->video_bitrate_peak->is_new ||
76199c77aa4SHans Verkuil 		    dev->video_bitrate->is_new) {
7620c0d06caSMauro Carvalho Chehab 			opt->bitrate = bitrate;
7630c0d06caSMauro Carvalho Chehab 			opt->peak_bitrate = peak_bitrate;
7640c0d06caSMauro Carvalho Chehab 			hdpvr_set_bitrate(dev);
76599c77aa4SHans Verkuil 		}
76699c77aa4SHans Verkuil 		return 0;
7670c0d06caSMauro Carvalho Chehab 	}
7680c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_STREAM_TYPE:
76999c77aa4SHans Verkuil 		return 0;
7700c0d06caSMauro Carvalho Chehab 	default:
77199c77aa4SHans Verkuil 		break;
7720c0d06caSMauro Carvalho Chehab 	}
7730c0d06caSMauro Carvalho Chehab 	return ret;
7740c0d06caSMauro Carvalho Chehab }
7750c0d06caSMauro Carvalho Chehab 
7760c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
7770c0d06caSMauro Carvalho Chehab 				    struct v4l2_fmtdesc *f)
7780c0d06caSMauro Carvalho Chehab {
7790c0d06caSMauro Carvalho Chehab 
7800c0d06caSMauro Carvalho Chehab 	if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
7810c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7820c0d06caSMauro Carvalho Chehab 
7830c0d06caSMauro Carvalho Chehab 	f->flags = V4L2_FMT_FLAG_COMPRESSED;
7840c0d06caSMauro Carvalho Chehab 	strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32);
7850c0d06caSMauro Carvalho Chehab 	f->pixelformat = V4L2_PIX_FMT_MPEG;
7860c0d06caSMauro Carvalho Chehab 
7870c0d06caSMauro Carvalho Chehab 	return 0;
7880c0d06caSMauro Carvalho Chehab }
7890c0d06caSMauro Carvalho Chehab 
7900c0d06caSMauro Carvalho Chehab static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
7910c0d06caSMauro Carvalho Chehab 				struct v4l2_format *f)
7920c0d06caSMauro Carvalho Chehab {
793ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(file);
7940c0d06caSMauro Carvalho Chehab 	struct hdpvr_video_info *vid_info;
7950c0d06caSMauro Carvalho Chehab 
7960c0d06caSMauro Carvalho Chehab 	if (!dev)
7970c0d06caSMauro Carvalho Chehab 		return -ENODEV;
7980c0d06caSMauro Carvalho Chehab 
7990c0d06caSMauro Carvalho Chehab 	vid_info = get_video_info(dev);
8000c0d06caSMauro Carvalho Chehab 	if (!vid_info)
8010c0d06caSMauro Carvalho Chehab 		return -EFAULT;
8020c0d06caSMauro Carvalho Chehab 
8030c0d06caSMauro Carvalho Chehab 	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
8040c0d06caSMauro Carvalho Chehab 	f->fmt.pix.pixelformat	= V4L2_PIX_FMT_MPEG;
8050c0d06caSMauro Carvalho Chehab 	f->fmt.pix.width	= vid_info->width;
8060c0d06caSMauro Carvalho Chehab 	f->fmt.pix.height	= vid_info->height;
8070c0d06caSMauro Carvalho Chehab 	f->fmt.pix.sizeimage	= dev->bulk_in_size;
8080c0d06caSMauro Carvalho Chehab 	f->fmt.pix.colorspace	= 0;
8090c0d06caSMauro Carvalho Chehab 	f->fmt.pix.bytesperline	= 0;
8100c0d06caSMauro Carvalho Chehab 	f->fmt.pix.field	= V4L2_FIELD_ANY;
8110c0d06caSMauro Carvalho Chehab 
8120c0d06caSMauro Carvalho Chehab 	kfree(vid_info);
8130c0d06caSMauro Carvalho Chehab 	return 0;
8140c0d06caSMauro Carvalho Chehab }
8150c0d06caSMauro Carvalho Chehab 
8160c0d06caSMauro Carvalho Chehab static int vidioc_encoder_cmd(struct file *filp, void *priv,
8170c0d06caSMauro Carvalho Chehab 			       struct v4l2_encoder_cmd *a)
8180c0d06caSMauro Carvalho Chehab {
819ede197aaSHans Verkuil 	struct hdpvr_device *dev = video_drvdata(filp);
820ede197aaSHans Verkuil 	int res = 0;
8210c0d06caSMauro Carvalho Chehab 
8220c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
823ede197aaSHans Verkuil 	a->flags = 0;
8240c0d06caSMauro Carvalho Chehab 
8250c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
8260c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
827ede197aaSHans Verkuil 		if (dev->owner && filp->private_data != dev->owner) {
828ede197aaSHans Verkuil 			res = -EBUSY;
829ede197aaSHans Verkuil 			break;
830ede197aaSHans Verkuil 		}
831ede197aaSHans Verkuil 		if (dev->status == STATUS_STREAMING)
832ede197aaSHans Verkuil 			break;
8330c0d06caSMauro Carvalho Chehab 		res = hdpvr_start_streaming(dev);
834ede197aaSHans Verkuil 		if (!res)
835ede197aaSHans Verkuil 			dev->owner = filp->private_data;
836ede197aaSHans Verkuil 		else
837ede197aaSHans Verkuil 			dev->status = STATUS_IDLE;
8380c0d06caSMauro Carvalho Chehab 		break;
8390c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
840ede197aaSHans Verkuil 		if (dev->owner && filp->private_data != dev->owner) {
841ede197aaSHans Verkuil 			res = -EBUSY;
842ede197aaSHans Verkuil 			break;
843ede197aaSHans Verkuil 		}
844ede197aaSHans Verkuil 		if (dev->status == STATUS_IDLE)
845ede197aaSHans Verkuil 			break;
8460c0d06caSMauro Carvalho Chehab 		res = hdpvr_stop_streaming(dev);
847ede197aaSHans Verkuil 		if (!res)
848ede197aaSHans Verkuil 			dev->owner = NULL;
8490c0d06caSMauro Carvalho Chehab 		break;
8500c0d06caSMauro Carvalho Chehab 	default:
8510c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
8520c0d06caSMauro Carvalho Chehab 			 "Unsupported encoder cmd %d\n", a->cmd);
8530c0d06caSMauro Carvalho Chehab 		res = -EINVAL;
854ede197aaSHans Verkuil 		break;
8550c0d06caSMauro Carvalho Chehab 	}
856ede197aaSHans Verkuil 
8570c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
8580c0d06caSMauro Carvalho Chehab 	return res;
8590c0d06caSMauro Carvalho Chehab }
8600c0d06caSMauro Carvalho Chehab 
8610c0d06caSMauro Carvalho Chehab static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
8620c0d06caSMauro Carvalho Chehab 					struct v4l2_encoder_cmd *a)
8630c0d06caSMauro Carvalho Chehab {
864ede197aaSHans Verkuil 	a->flags = 0;
8650c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
8660c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
8670c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
8680c0d06caSMauro Carvalho Chehab 		return 0;
8690c0d06caSMauro Carvalho Chehab 	default:
8700c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8710c0d06caSMauro Carvalho Chehab 	}
8720c0d06caSMauro Carvalho Chehab }
8730c0d06caSMauro Carvalho Chehab 
8740c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
8750c0d06caSMauro Carvalho Chehab 	.vidioc_querycap	= vidioc_querycap,
8760c0d06caSMauro Carvalho Chehab 	.vidioc_s_std		= vidioc_s_std,
8770c0d06caSMauro Carvalho Chehab 	.vidioc_enum_input	= vidioc_enum_input,
8780c0d06caSMauro Carvalho Chehab 	.vidioc_g_input		= vidioc_g_input,
8790c0d06caSMauro Carvalho Chehab 	.vidioc_s_input		= vidioc_s_input,
8800c0d06caSMauro Carvalho Chehab 	.vidioc_enumaudio	= vidioc_enumaudio,
8810c0d06caSMauro Carvalho Chehab 	.vidioc_g_audio		= vidioc_g_audio,
8820c0d06caSMauro Carvalho Chehab 	.vidioc_s_audio		= vidioc_s_audio,
8830c0d06caSMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap,
8840c0d06caSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
8850c0d06caSMauro Carvalho Chehab 	.vidioc_encoder_cmd	= vidioc_encoder_cmd,
8860c0d06caSMauro Carvalho Chehab 	.vidioc_try_encoder_cmd	= vidioc_try_encoder_cmd,
88765fe42d6SHans Verkuil 	.vidioc_log_status	= v4l2_ctrl_log_status,
88865fe42d6SHans Verkuil 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
88965fe42d6SHans Verkuil 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
8900c0d06caSMauro Carvalho Chehab };
8910c0d06caSMauro Carvalho Chehab 
8920c0d06caSMauro Carvalho Chehab static void hdpvr_device_release(struct video_device *vdev)
8930c0d06caSMauro Carvalho Chehab {
8940c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_get_drvdata(vdev);
8950c0d06caSMauro Carvalho Chehab 
8960c0d06caSMauro Carvalho Chehab 	hdpvr_delete(dev);
8970c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
8980c0d06caSMauro Carvalho Chehab 	destroy_workqueue(dev->workqueue);
8990c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
9000c0d06caSMauro Carvalho Chehab 
9010c0d06caSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
90299c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(&dev->hdl);
9030c0d06caSMauro Carvalho Chehab 
9040c0d06caSMauro Carvalho Chehab 	/* deregister I2C adapter */
90554d80904SMauro Carvalho Chehab #if IS_ENABLED(CONFIG_I2C)
9060c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->i2c_mutex);
9070c0d06caSMauro Carvalho Chehab 	i2c_del_adapter(&dev->i2c_adapter);
9080c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->i2c_mutex);
9090c0d06caSMauro Carvalho Chehab #endif /* CONFIG_I2C */
9100c0d06caSMauro Carvalho Chehab 
9110c0d06caSMauro Carvalho Chehab 	kfree(dev->usbc_buf);
9120c0d06caSMauro Carvalho Chehab 	kfree(dev);
9130c0d06caSMauro Carvalho Chehab }
9140c0d06caSMauro Carvalho Chehab 
9150c0d06caSMauro Carvalho Chehab static const struct video_device hdpvr_video_template = {
9160c0d06caSMauro Carvalho Chehab 	.fops			= &hdpvr_fops,
9170c0d06caSMauro Carvalho Chehab 	.release		= hdpvr_device_release,
9180c0d06caSMauro Carvalho Chehab 	.ioctl_ops 		= &hdpvr_ioctl_ops,
9190c0d06caSMauro Carvalho Chehab 	.tvnorms 		=
9200c0d06caSMauro Carvalho Chehab 		V4L2_STD_NTSC  | V4L2_STD_SECAM | V4L2_STD_PAL_B |
9210c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
9220c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
9230c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_60,
9240c0d06caSMauro Carvalho Chehab 	.current_norm 		= V4L2_STD_NTSC | V4L2_STD_PAL_M |
9250c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_60,
9260c0d06caSMauro Carvalho Chehab };
9270c0d06caSMauro Carvalho Chehab 
92899c77aa4SHans Verkuil static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
92999c77aa4SHans Verkuil 	.try_ctrl = hdpvr_try_ctrl,
93099c77aa4SHans Verkuil 	.s_ctrl = hdpvr_s_ctrl,
93199c77aa4SHans Verkuil };
93299c77aa4SHans Verkuil 
9330c0d06caSMauro Carvalho Chehab int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
9340c0d06caSMauro Carvalho Chehab 			    int devnum)
9350c0d06caSMauro Carvalho Chehab {
93699c77aa4SHans Verkuil 	struct v4l2_ctrl_handler *hdl = &dev->hdl;
93799c77aa4SHans Verkuil 	bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
93899c77aa4SHans Verkuil 	int res;
93999c77aa4SHans Verkuil 
94099c77aa4SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 11);
94199c77aa4SHans Verkuil 	if (dev->fw_ver > 0x15) {
94299c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
94399c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80);
94499c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
94599c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40);
94699c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
94799c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40);
94899c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
94999c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf);
95099c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
95199c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
95299c77aa4SHans Verkuil 	} else {
95399c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
95499c77aa4SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86);
95599c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
95699c77aa4SHans Verkuil 			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80);
95799c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
95899c77aa4SHans Verkuil 			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80);
95999c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
96099c77aa4SHans Verkuil 			V4L2_CID_HUE, 0x0, 0xff, 1, 0x80);
96199c77aa4SHans Verkuil 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
96299c77aa4SHans Verkuil 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
96399c77aa4SHans Verkuil 	}
96499c77aa4SHans Verkuil 
96599c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
96699c77aa4SHans Verkuil 		V4L2_CID_MPEG_STREAM_TYPE,
96799c77aa4SHans Verkuil 		V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
96899c77aa4SHans Verkuil 		0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
96999c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
97099c77aa4SHans Verkuil 		V4L2_CID_MPEG_AUDIO_ENCODING,
97199c77aa4SHans Verkuil 		ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
97299c77aa4SHans Verkuil 		0x7, V4L2_MPEG_AUDIO_ENCODING_AAC);
97399c77aa4SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
97499c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_ENCODING,
97599c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
97699c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
97799c77aa4SHans Verkuil 
97899c77aa4SHans Verkuil 	dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
97999c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
98099c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
98199c77aa4SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
98299c77aa4SHans Verkuil 
98399c77aa4SHans Verkuil 	dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
98499c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE,
98599c77aa4SHans Verkuil 		1000000, 13500000, 100000, 6500000);
98699c77aa4SHans Verkuil 	dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
98799c77aa4SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
98899c77aa4SHans Verkuil 		1100000, 20200000, 100000, 9000000);
98999c77aa4SHans Verkuil 	dev->v4l2_dev.ctrl_handler = hdl;
99099c77aa4SHans Verkuil 	if (hdl->error) {
99199c77aa4SHans Verkuil 		res = hdl->error;
99299c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not register controls\n");
99399c77aa4SHans Verkuil 		goto error;
99499c77aa4SHans Verkuil 	}
99599c77aa4SHans Verkuil 	v4l2_ctrl_cluster(3, &dev->video_mode);
99699c77aa4SHans Verkuil 	res = v4l2_ctrl_handler_setup(hdl);
99799c77aa4SHans Verkuil 	if (res < 0) {
99899c77aa4SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Could not setup controls\n");
99999c77aa4SHans Verkuil 		goto error;
100099c77aa4SHans Verkuil 	}
100199c77aa4SHans Verkuil 
10020c0d06caSMauro Carvalho Chehab 	/* setup and register video device */
10030c0d06caSMauro Carvalho Chehab 	dev->video_dev = video_device_alloc();
10040c0d06caSMauro Carvalho Chehab 	if (!dev->video_dev) {
10050c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
100699c77aa4SHans Verkuil 		res = -ENOMEM;
10070c0d06caSMauro Carvalho Chehab 		goto error;
10080c0d06caSMauro Carvalho Chehab 	}
10090c0d06caSMauro Carvalho Chehab 
1010ede197aaSHans Verkuil 	*dev->video_dev = hdpvr_video_template;
10110c0d06caSMauro Carvalho Chehab 	strcpy(dev->video_dev->name, "Hauppauge HD PVR");
1012ede197aaSHans Verkuil 	dev->video_dev->v4l2_dev = &dev->v4l2_dev;
10130c0d06caSMauro Carvalho Chehab 	video_set_drvdata(dev->video_dev, dev);
101465fe42d6SHans Verkuil 	set_bit(V4L2_FL_USE_FH_PRIO, &dev->video_dev->flags);
10150c0d06caSMauro Carvalho Chehab 
101699c77aa4SHans Verkuil 	res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum);
101799c77aa4SHans Verkuil 	if (res < 0) {
10180c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
10190c0d06caSMauro Carvalho Chehab 		goto error;
10200c0d06caSMauro Carvalho Chehab 	}
10210c0d06caSMauro Carvalho Chehab 
10220c0d06caSMauro Carvalho Chehab 	return 0;
10230c0d06caSMauro Carvalho Chehab error:
102499c77aa4SHans Verkuil 	v4l2_ctrl_handler_free(hdl);
102599c77aa4SHans Verkuil 	return res;
10260c0d06caSMauro Carvalho Chehab }
1027