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>
130c0d06caSMauro Carvalho Chehab #include <linux/errno.h>
140c0d06caSMauro Carvalho Chehab #include <linux/init.h>
150c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
160c0d06caSMauro Carvalho Chehab #include <linux/module.h>
170c0d06caSMauro Carvalho Chehab #include <linux/uaccess.h>
180c0d06caSMauro Carvalho Chehab #include <linux/usb.h>
190c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
200c0d06caSMauro Carvalho Chehab #include <linux/workqueue.h>
210c0d06caSMauro Carvalho Chehab 
220c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h>
230c0d06caSMauro Carvalho Chehab #include <media/v4l2-dev.h>
240c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
250c0d06caSMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
260c0d06caSMauro Carvalho Chehab #include "hdpvr.h"
270c0d06caSMauro Carvalho Chehab 
280c0d06caSMauro Carvalho Chehab #define BULK_URB_TIMEOUT   90 /* 0.09 seconds */
290c0d06caSMauro Carvalho Chehab 
300c0d06caSMauro Carvalho Chehab #define print_buffer_status() { \
310c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,	\
320c0d06caSMauro Carvalho Chehab 			 "%s:%d buffer stat: %d free, %d proc\n",	\
330c0d06caSMauro Carvalho Chehab 			 __func__, __LINE__,				\
340c0d06caSMauro Carvalho Chehab 			 list_size(&dev->free_buff_list),		\
350c0d06caSMauro Carvalho Chehab 			 list_size(&dev->rec_buff_list)); }
360c0d06caSMauro Carvalho Chehab 
370c0d06caSMauro Carvalho Chehab struct hdpvr_fh {
380c0d06caSMauro Carvalho Chehab 	struct hdpvr_device	*dev;
390c0d06caSMauro Carvalho Chehab };
400c0d06caSMauro Carvalho Chehab 
410c0d06caSMauro Carvalho Chehab static uint list_size(struct list_head *list)
420c0d06caSMauro Carvalho Chehab {
430c0d06caSMauro Carvalho Chehab 	struct list_head *tmp;
440c0d06caSMauro Carvalho Chehab 	uint count = 0;
450c0d06caSMauro Carvalho Chehab 
460c0d06caSMauro Carvalho Chehab 	list_for_each(tmp, list) {
470c0d06caSMauro Carvalho Chehab 		count++;
480c0d06caSMauro Carvalho Chehab 	}
490c0d06caSMauro Carvalho Chehab 
500c0d06caSMauro Carvalho Chehab 	return count;
510c0d06caSMauro Carvalho Chehab }
520c0d06caSMauro Carvalho Chehab 
530c0d06caSMauro Carvalho Chehab /*=========================================================================*/
540c0d06caSMauro Carvalho Chehab /* urb callback */
550c0d06caSMauro Carvalho Chehab static void hdpvr_read_bulk_callback(struct urb *urb)
560c0d06caSMauro Carvalho Chehab {
570c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
580c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = buf->dev;
590c0d06caSMauro Carvalho Chehab 
600c0d06caSMauro Carvalho Chehab 	/* marking buffer as received and wake waiting */
610c0d06caSMauro Carvalho Chehab 	buf->status = BUFSTAT_READY;
620c0d06caSMauro Carvalho Chehab 	wake_up_interruptible(&dev->wait_data);
630c0d06caSMauro Carvalho Chehab }
640c0d06caSMauro Carvalho Chehab 
650c0d06caSMauro Carvalho Chehab /*=========================================================================*/
660c0d06caSMauro Carvalho Chehab /* bufffer bits */
670c0d06caSMauro Carvalho Chehab 
680c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
690c0d06caSMauro Carvalho Chehab int hdpvr_cancel_queue(struct hdpvr_device *dev)
700c0d06caSMauro Carvalho Chehab {
710c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
720c0d06caSMauro Carvalho Chehab 
730c0d06caSMauro Carvalho Chehab 	list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
740c0d06caSMauro Carvalho Chehab 		usb_kill_urb(buf->urb);
750c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_AVAILABLE;
760c0d06caSMauro Carvalho Chehab 	}
770c0d06caSMauro Carvalho Chehab 
780c0d06caSMauro Carvalho Chehab 	list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
790c0d06caSMauro Carvalho Chehab 
800c0d06caSMauro Carvalho Chehab 	return 0;
810c0d06caSMauro Carvalho Chehab }
820c0d06caSMauro Carvalho Chehab 
830c0d06caSMauro Carvalho Chehab static int hdpvr_free_queue(struct list_head *q)
840c0d06caSMauro Carvalho Chehab {
850c0d06caSMauro Carvalho Chehab 	struct list_head *tmp;
860c0d06caSMauro Carvalho Chehab 	struct list_head *p;
870c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
880c0d06caSMauro Carvalho Chehab 	struct urb *urb;
890c0d06caSMauro Carvalho Chehab 
900c0d06caSMauro Carvalho Chehab 	for (p = q->next; p != q;) {
910c0d06caSMauro Carvalho Chehab 		buf = list_entry(p, struct hdpvr_buffer, buff_list);
920c0d06caSMauro Carvalho Chehab 
930c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
940c0d06caSMauro Carvalho Chehab 		usb_free_coherent(urb->dev, urb->transfer_buffer_length,
950c0d06caSMauro Carvalho Chehab 				  urb->transfer_buffer, urb->transfer_dma);
960c0d06caSMauro Carvalho Chehab 		usb_free_urb(urb);
970c0d06caSMauro Carvalho Chehab 		tmp = p->next;
980c0d06caSMauro Carvalho Chehab 		list_del(p);
990c0d06caSMauro Carvalho Chehab 		kfree(buf);
1000c0d06caSMauro Carvalho Chehab 		p = tmp;
1010c0d06caSMauro Carvalho Chehab 	}
1020c0d06caSMauro Carvalho Chehab 
1030c0d06caSMauro Carvalho Chehab 	return 0;
1040c0d06caSMauro Carvalho Chehab }
1050c0d06caSMauro Carvalho Chehab 
1060c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
1070c0d06caSMauro Carvalho Chehab int hdpvr_free_buffers(struct hdpvr_device *dev)
1080c0d06caSMauro Carvalho Chehab {
1090c0d06caSMauro Carvalho Chehab 	hdpvr_cancel_queue(dev);
1100c0d06caSMauro Carvalho Chehab 
1110c0d06caSMauro Carvalho Chehab 	hdpvr_free_queue(&dev->free_buff_list);
1120c0d06caSMauro Carvalho Chehab 	hdpvr_free_queue(&dev->rec_buff_list);
1130c0d06caSMauro Carvalho Chehab 
1140c0d06caSMauro Carvalho Chehab 	return 0;
1150c0d06caSMauro Carvalho Chehab }
1160c0d06caSMauro Carvalho Chehab 
1170c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
1180c0d06caSMauro Carvalho Chehab int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
1190c0d06caSMauro Carvalho Chehab {
1200c0d06caSMauro Carvalho Chehab 	uint i;
1210c0d06caSMauro Carvalho Chehab 	int retval = -ENOMEM;
1220c0d06caSMauro Carvalho Chehab 	u8 *mem;
1230c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
1240c0d06caSMauro Carvalho Chehab 	struct urb *urb;
1250c0d06caSMauro Carvalho Chehab 
1260c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
1270c0d06caSMauro Carvalho Chehab 		 "allocating %u buffers\n", count);
1280c0d06caSMauro Carvalho Chehab 
1290c0d06caSMauro Carvalho Chehab 	for (i = 0; i < count; i++) {
1300c0d06caSMauro Carvalho Chehab 
1310c0d06caSMauro Carvalho Chehab 		buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
1320c0d06caSMauro Carvalho Chehab 		if (!buf) {
1330c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n");
1340c0d06caSMauro Carvalho Chehab 			goto exit;
1350c0d06caSMauro Carvalho Chehab 		}
1360c0d06caSMauro Carvalho Chehab 		buf->dev = dev;
1370c0d06caSMauro Carvalho Chehab 
1380c0d06caSMauro Carvalho Chehab 		urb = usb_alloc_urb(0, GFP_KERNEL);
1390c0d06caSMauro Carvalho Chehab 		if (!urb) {
1400c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n");
1410c0d06caSMauro Carvalho Chehab 			goto exit_urb;
1420c0d06caSMauro Carvalho Chehab 		}
1430c0d06caSMauro Carvalho Chehab 		buf->urb = urb;
1440c0d06caSMauro Carvalho Chehab 
1450c0d06caSMauro Carvalho Chehab 		mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL,
1460c0d06caSMauro Carvalho Chehab 					 &urb->transfer_dma);
1470c0d06caSMauro Carvalho Chehab 		if (!mem) {
1480c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
1490c0d06caSMauro Carvalho Chehab 				 "cannot allocate usb transfer buffer\n");
1500c0d06caSMauro Carvalho Chehab 			goto exit_urb_buffer;
1510c0d06caSMauro Carvalho Chehab 		}
1520c0d06caSMauro Carvalho Chehab 
1530c0d06caSMauro Carvalho Chehab 		usb_fill_bulk_urb(buf->urb, dev->udev,
1540c0d06caSMauro Carvalho Chehab 				  usb_rcvbulkpipe(dev->udev,
1550c0d06caSMauro Carvalho Chehab 						  dev->bulk_in_endpointAddr),
1560c0d06caSMauro Carvalho Chehab 				  mem, dev->bulk_in_size,
1570c0d06caSMauro Carvalho Chehab 				  hdpvr_read_bulk_callback, buf);
1580c0d06caSMauro Carvalho Chehab 
1590c0d06caSMauro Carvalho Chehab 		buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1600c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_AVAILABLE;
1610c0d06caSMauro Carvalho Chehab 		list_add_tail(&buf->buff_list, &dev->free_buff_list);
1620c0d06caSMauro Carvalho Chehab 	}
1630c0d06caSMauro Carvalho Chehab 	return 0;
1640c0d06caSMauro Carvalho Chehab exit_urb_buffer:
1650c0d06caSMauro Carvalho Chehab 	usb_free_urb(urb);
1660c0d06caSMauro Carvalho Chehab exit_urb:
1670c0d06caSMauro Carvalho Chehab 	kfree(buf);
1680c0d06caSMauro Carvalho Chehab exit:
1690c0d06caSMauro Carvalho Chehab 	hdpvr_free_buffers(dev);
1700c0d06caSMauro Carvalho Chehab 	return retval;
1710c0d06caSMauro Carvalho Chehab }
1720c0d06caSMauro Carvalho Chehab 
1730c0d06caSMauro Carvalho Chehab static int hdpvr_submit_buffers(struct hdpvr_device *dev)
1740c0d06caSMauro Carvalho Chehab {
1750c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
1760c0d06caSMauro Carvalho Chehab 	struct urb *urb;
1770c0d06caSMauro Carvalho Chehab 	int ret = 0, err_count = 0;
1780c0d06caSMauro Carvalho Chehab 
1790c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
1800c0d06caSMauro Carvalho Chehab 
1810c0d06caSMauro Carvalho Chehab 	while (dev->status == STATUS_STREAMING &&
1820c0d06caSMauro Carvalho Chehab 	       !list_empty(&dev->free_buff_list)) {
1830c0d06caSMauro Carvalho Chehab 
1840c0d06caSMauro Carvalho Chehab 		buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
1850c0d06caSMauro Carvalho Chehab 				 buff_list);
1860c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_AVAILABLE) {
1870c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
1880c0d06caSMauro Carvalho Chehab 				 "buffer not marked as available\n");
1890c0d06caSMauro Carvalho Chehab 			ret = -EFAULT;
1900c0d06caSMauro Carvalho Chehab 			goto err;
1910c0d06caSMauro Carvalho Chehab 		}
1920c0d06caSMauro Carvalho Chehab 
1930c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
1940c0d06caSMauro Carvalho Chehab 		urb->status = 0;
1950c0d06caSMauro Carvalho Chehab 		urb->actual_length = 0;
1960c0d06caSMauro Carvalho Chehab 		ret = usb_submit_urb(urb, GFP_KERNEL);
1970c0d06caSMauro Carvalho Chehab 		if (ret) {
1980c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
1990c0d06caSMauro Carvalho Chehab 				 "usb_submit_urb in %s returned %d\n",
2000c0d06caSMauro Carvalho Chehab 				 __func__, ret);
2010c0d06caSMauro Carvalho Chehab 			if (++err_count > 2)
2020c0d06caSMauro Carvalho Chehab 				break;
2030c0d06caSMauro Carvalho Chehab 			continue;
2040c0d06caSMauro Carvalho Chehab 		}
2050c0d06caSMauro Carvalho Chehab 		buf->status = BUFSTAT_INPROGRESS;
2060c0d06caSMauro Carvalho Chehab 		list_move_tail(&buf->buff_list, &dev->rec_buff_list);
2070c0d06caSMauro Carvalho Chehab 	}
2080c0d06caSMauro Carvalho Chehab err:
2090c0d06caSMauro Carvalho Chehab 	print_buffer_status();
2100c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
2110c0d06caSMauro Carvalho Chehab 	return ret;
2120c0d06caSMauro Carvalho Chehab }
2130c0d06caSMauro Carvalho Chehab 
2140c0d06caSMauro Carvalho Chehab static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev)
2150c0d06caSMauro Carvalho Chehab {
2160c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf;
2170c0d06caSMauro Carvalho Chehab 
2180c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
2190c0d06caSMauro Carvalho Chehab 
2200c0d06caSMauro Carvalho Chehab 	if (list_empty(&dev->rec_buff_list)) {
2210c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->io_mutex);
2220c0d06caSMauro Carvalho Chehab 		return NULL;
2230c0d06caSMauro Carvalho Chehab 	}
2240c0d06caSMauro Carvalho Chehab 
2250c0d06caSMauro Carvalho Chehab 	buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer,
2260c0d06caSMauro Carvalho Chehab 			 buff_list);
2270c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
2280c0d06caSMauro Carvalho Chehab 
2290c0d06caSMauro Carvalho Chehab 	return buf;
2300c0d06caSMauro Carvalho Chehab }
2310c0d06caSMauro Carvalho Chehab 
2320c0d06caSMauro Carvalho Chehab static void hdpvr_transmit_buffers(struct work_struct *work)
2330c0d06caSMauro Carvalho Chehab {
2340c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = container_of(work, struct hdpvr_device,
2350c0d06caSMauro Carvalho Chehab 						worker);
2360c0d06caSMauro Carvalho Chehab 
2370c0d06caSMauro Carvalho Chehab 	while (dev->status == STATUS_STREAMING) {
2380c0d06caSMauro Carvalho Chehab 
2390c0d06caSMauro Carvalho Chehab 		if (hdpvr_submit_buffers(dev)) {
2400c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n");
2410c0d06caSMauro Carvalho Chehab 			goto error;
2420c0d06caSMauro Carvalho Chehab 		}
2430c0d06caSMauro Carvalho Chehab 		if (wait_event_interruptible(dev->wait_buffer,
2440c0d06caSMauro Carvalho Chehab 				!list_empty(&dev->free_buff_list) ||
2450c0d06caSMauro Carvalho Chehab 					     dev->status != STATUS_STREAMING))
2460c0d06caSMauro Carvalho Chehab 			goto error;
2470c0d06caSMauro Carvalho Chehab 	}
2480c0d06caSMauro Carvalho Chehab 
2490c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2500c0d06caSMauro Carvalho Chehab 		 "transmit worker exited\n");
2510c0d06caSMauro Carvalho Chehab 	return;
2520c0d06caSMauro Carvalho Chehab error:
2530c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2540c0d06caSMauro Carvalho Chehab 		 "transmit buffers errored\n");
2550c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_ERROR;
2560c0d06caSMauro Carvalho Chehab }
2570c0d06caSMauro Carvalho Chehab 
2580c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
2590c0d06caSMauro Carvalho Chehab static int hdpvr_start_streaming(struct hdpvr_device *dev)
2600c0d06caSMauro Carvalho Chehab {
2610c0d06caSMauro Carvalho Chehab 	int ret;
2620c0d06caSMauro Carvalho Chehab 	struct hdpvr_video_info *vidinf;
2630c0d06caSMauro Carvalho Chehab 
2640c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_STREAMING)
2650c0d06caSMauro Carvalho Chehab 		return 0;
2660c0d06caSMauro Carvalho Chehab 	else if (dev->status != STATUS_IDLE)
2670c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
2680c0d06caSMauro Carvalho Chehab 
2690c0d06caSMauro Carvalho Chehab 	vidinf = get_video_info(dev);
2700c0d06caSMauro Carvalho Chehab 
2710c0d06caSMauro Carvalho Chehab 	if (vidinf) {
2720c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
2730c0d06caSMauro Carvalho Chehab 			 "video signal: %dx%d@%dhz\n", vidinf->width,
2740c0d06caSMauro Carvalho Chehab 			 vidinf->height, vidinf->fps);
2750c0d06caSMauro Carvalho Chehab 		kfree(vidinf);
2760c0d06caSMauro Carvalho Chehab 
2770c0d06caSMauro Carvalho Chehab 		/* start streaming 2 request */
2780c0d06caSMauro Carvalho Chehab 		ret = usb_control_msg(dev->udev,
2790c0d06caSMauro Carvalho Chehab 				      usb_sndctrlpipe(dev->udev, 0),
2800c0d06caSMauro Carvalho Chehab 				      0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
2810c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
2820c0d06caSMauro Carvalho Chehab 			 "encoder start control request returned %d\n", ret);
2830c0d06caSMauro Carvalho Chehab 
2840c0d06caSMauro Carvalho Chehab 		hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
2850c0d06caSMauro Carvalho Chehab 
2860c0d06caSMauro Carvalho Chehab 		dev->status = STATUS_STREAMING;
2870c0d06caSMauro Carvalho Chehab 
2880c0d06caSMauro Carvalho Chehab 		INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
2890c0d06caSMauro Carvalho Chehab 		queue_work(dev->workqueue, &dev->worker);
2900c0d06caSMauro Carvalho Chehab 
2910c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
2920c0d06caSMauro Carvalho Chehab 			 "streaming started\n");
2930c0d06caSMauro Carvalho Chehab 
2940c0d06caSMauro Carvalho Chehab 		return 0;
2950c0d06caSMauro Carvalho Chehab 	}
2960c0d06caSMauro Carvalho Chehab 	msleep(250);
2970c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
2980c0d06caSMauro Carvalho Chehab 		 "no video signal at input %d\n", dev->options.video_input);
2990c0d06caSMauro Carvalho Chehab 	return -EAGAIN;
3000c0d06caSMauro Carvalho Chehab }
3010c0d06caSMauro Carvalho Chehab 
3020c0d06caSMauro Carvalho Chehab 
3030c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */
3040c0d06caSMauro Carvalho Chehab static int hdpvr_stop_streaming(struct hdpvr_device *dev)
3050c0d06caSMauro Carvalho Chehab {
3060c0d06caSMauro Carvalho Chehab 	int actual_length;
3070c0d06caSMauro Carvalho Chehab 	uint c = 0;
3080c0d06caSMauro Carvalho Chehab 	u8 *buf;
3090c0d06caSMauro Carvalho Chehab 
3100c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE)
3110c0d06caSMauro Carvalho Chehab 		return 0;
3120c0d06caSMauro Carvalho Chehab 	else if (dev->status != STATUS_STREAMING)
3130c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
3140c0d06caSMauro Carvalho Chehab 
3150c0d06caSMauro Carvalho Chehab 	buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
3160c0d06caSMauro Carvalho Chehab 	if (!buf)
3170c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer "
3180c0d06caSMauro Carvalho Chehab 			 "for emptying the internal device buffer. "
3190c0d06caSMauro Carvalho Chehab 			 "Next capture start will be slow\n");
3200c0d06caSMauro Carvalho Chehab 
3210c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_SHUTTING_DOWN;
3220c0d06caSMauro Carvalho Chehab 	hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
3230c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3240c0d06caSMauro Carvalho Chehab 
3250c0d06caSMauro Carvalho Chehab 	wake_up_interruptible(&dev->wait_buffer);
3260c0d06caSMauro Carvalho Chehab 	msleep(50);
3270c0d06caSMauro Carvalho Chehab 
3280c0d06caSMauro Carvalho Chehab 	flush_workqueue(dev->workqueue);
3290c0d06caSMauro Carvalho Chehab 
3300c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
3310c0d06caSMauro Carvalho Chehab 	/* kill the still outstanding urbs */
3320c0d06caSMauro Carvalho Chehab 	hdpvr_cancel_queue(dev);
3330c0d06caSMauro Carvalho Chehab 
3340c0d06caSMauro Carvalho Chehab 	/* emptying the device buffer beforeshutting it down */
3350c0d06caSMauro Carvalho Chehab 	while (buf && ++c < 500 &&
3360c0d06caSMauro Carvalho Chehab 	       !usb_bulk_msg(dev->udev,
3370c0d06caSMauro Carvalho Chehab 			     usb_rcvbulkpipe(dev->udev,
3380c0d06caSMauro Carvalho Chehab 					     dev->bulk_in_endpointAddr),
3390c0d06caSMauro Carvalho Chehab 			     buf, dev->bulk_in_size, &actual_length,
3400c0d06caSMauro Carvalho Chehab 			     BULK_URB_TIMEOUT)) {
3410c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3420c0d06caSMauro Carvalho Chehab 			 "%2d: got %d bytes\n", c, actual_length);
3430c0d06caSMauro Carvalho Chehab 	}
3440c0d06caSMauro Carvalho Chehab 	kfree(buf);
3450c0d06caSMauro Carvalho Chehab 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
3460c0d06caSMauro Carvalho Chehab 		 "used %d urbs to empty device buffers\n", c-1);
3470c0d06caSMauro Carvalho Chehab 	msleep(10);
3480c0d06caSMauro Carvalho Chehab 
3490c0d06caSMauro Carvalho Chehab 	dev->status = STATUS_IDLE;
3500c0d06caSMauro Carvalho Chehab 
3510c0d06caSMauro Carvalho Chehab 	return 0;
3520c0d06caSMauro Carvalho Chehab }
3530c0d06caSMauro Carvalho Chehab 
3540c0d06caSMauro Carvalho Chehab 
3550c0d06caSMauro Carvalho Chehab /*=======================================================================*/
3560c0d06caSMauro Carvalho Chehab /*
3570c0d06caSMauro Carvalho Chehab  * video 4 linux 2 file operations
3580c0d06caSMauro Carvalho Chehab  */
3590c0d06caSMauro Carvalho Chehab 
3600c0d06caSMauro Carvalho Chehab static int hdpvr_open(struct file *file)
3610c0d06caSMauro Carvalho Chehab {
3620c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev;
3630c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh;
3640c0d06caSMauro Carvalho Chehab 	int retval = -ENOMEM;
3650c0d06caSMauro Carvalho Chehab 
3660c0d06caSMauro Carvalho Chehab 	dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
3670c0d06caSMauro Carvalho Chehab 	if (!dev) {
3680c0d06caSMauro Carvalho Chehab 		pr_err("open failing with with ENODEV\n");
3690c0d06caSMauro Carvalho Chehab 		retval = -ENODEV;
3700c0d06caSMauro Carvalho Chehab 		goto err;
3710c0d06caSMauro Carvalho Chehab 	}
3720c0d06caSMauro Carvalho Chehab 
3730c0d06caSMauro Carvalho Chehab 	fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
3740c0d06caSMauro Carvalho Chehab 	if (!fh) {
3750c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "Out of memory\n");
3760c0d06caSMauro Carvalho Chehab 		goto err;
3770c0d06caSMauro Carvalho Chehab 	}
3780c0d06caSMauro Carvalho Chehab 	/* lock the device to allow correctly handling errors
3790c0d06caSMauro Carvalho Chehab 	 * in resumption */
3800c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
3810c0d06caSMauro Carvalho Chehab 	dev->open_count++;
3820c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
3830c0d06caSMauro Carvalho Chehab 
3840c0d06caSMauro Carvalho Chehab 	fh->dev = dev;
3850c0d06caSMauro Carvalho Chehab 
3860c0d06caSMauro Carvalho Chehab 	/* save our object in the file's private structure */
3870c0d06caSMauro Carvalho Chehab 	file->private_data = fh;
3880c0d06caSMauro Carvalho Chehab 
3890c0d06caSMauro Carvalho Chehab 	retval = 0;
3900c0d06caSMauro Carvalho Chehab err:
3910c0d06caSMauro Carvalho Chehab 	return retval;
3920c0d06caSMauro Carvalho Chehab }
3930c0d06caSMauro Carvalho Chehab 
3940c0d06caSMauro Carvalho Chehab static int hdpvr_release(struct file *file)
3950c0d06caSMauro Carvalho Chehab {
3960c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh		*fh  = file->private_data;
3970c0d06caSMauro Carvalho Chehab 	struct hdpvr_device	*dev = fh->dev;
3980c0d06caSMauro Carvalho Chehab 
3990c0d06caSMauro Carvalho Chehab 	if (!dev)
4000c0d06caSMauro Carvalho Chehab 		return -ENODEV;
4010c0d06caSMauro Carvalho Chehab 
4020c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
4030c0d06caSMauro Carvalho Chehab 	if (!(--dev->open_count) && dev->status == STATUS_STREAMING)
4040c0d06caSMauro Carvalho Chehab 		hdpvr_stop_streaming(dev);
4050c0d06caSMauro Carvalho Chehab 
4060c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
4070c0d06caSMauro Carvalho Chehab 
4080c0d06caSMauro Carvalho Chehab 	return 0;
4090c0d06caSMauro Carvalho Chehab }
4100c0d06caSMauro Carvalho Chehab 
4110c0d06caSMauro Carvalho Chehab /*
4120c0d06caSMauro Carvalho Chehab  * hdpvr_v4l2_read()
4130c0d06caSMauro Carvalho Chehab  * will allocate buffers when called for the first time
4140c0d06caSMauro Carvalho Chehab  */
4150c0d06caSMauro Carvalho Chehab static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
4160c0d06caSMauro Carvalho Chehab 			  loff_t *pos)
4170c0d06caSMauro Carvalho Chehab {
4180c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
4190c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
4200c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
4210c0d06caSMauro Carvalho Chehab 	struct urb *urb;
4220c0d06caSMauro Carvalho Chehab 	unsigned int ret = 0;
4230c0d06caSMauro Carvalho Chehab 	int rem, cnt;
4240c0d06caSMauro Carvalho Chehab 
4250c0d06caSMauro Carvalho Chehab 	if (*pos)
4260c0d06caSMauro Carvalho Chehab 		return -ESPIPE;
4270c0d06caSMauro Carvalho Chehab 
4280c0d06caSMauro Carvalho Chehab 	if (!dev)
4290c0d06caSMauro Carvalho Chehab 		return -ENODEV;
4300c0d06caSMauro Carvalho Chehab 
4310c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
4320c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
4330c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
4340c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
4350c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
4360c0d06caSMauro Carvalho Chehab 			ret = -EIO;
4370c0d06caSMauro Carvalho Chehab 			msleep(200);
4380c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
4390c0d06caSMauro Carvalho Chehab 			mutex_unlock(&dev->io_mutex);
4400c0d06caSMauro Carvalho Chehab 			goto err;
4410c0d06caSMauro Carvalho Chehab 		}
4420c0d06caSMauro Carvalho Chehab 		print_buffer_status();
4430c0d06caSMauro Carvalho Chehab 	}
4440c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
4450c0d06caSMauro Carvalho Chehab 
4460c0d06caSMauro Carvalho Chehab 	/* wait for the first buffer */
4470c0d06caSMauro Carvalho Chehab 	if (!(file->f_flags & O_NONBLOCK)) {
4480c0d06caSMauro Carvalho Chehab 		if (wait_event_interruptible(dev->wait_data,
4490c0d06caSMauro Carvalho Chehab 					     hdpvr_get_next_buffer(dev)))
4500c0d06caSMauro Carvalho Chehab 			return -ERESTARTSYS;
4510c0d06caSMauro Carvalho Chehab 	}
4520c0d06caSMauro Carvalho Chehab 
4530c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
4540c0d06caSMauro Carvalho Chehab 
4550c0d06caSMauro Carvalho Chehab 	while (count > 0 && buf) {
4560c0d06caSMauro Carvalho Chehab 
4570c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY &&
4580c0d06caSMauro Carvalho Chehab 		    dev->status != STATUS_DISCONNECTED) {
4590c0d06caSMauro Carvalho Chehab 			/* return nonblocking */
4600c0d06caSMauro Carvalho Chehab 			if (file->f_flags & O_NONBLOCK) {
4610c0d06caSMauro Carvalho Chehab 				if (!ret)
4620c0d06caSMauro Carvalho Chehab 					ret = -EAGAIN;
4630c0d06caSMauro Carvalho Chehab 				goto err;
4640c0d06caSMauro Carvalho Chehab 			}
4650c0d06caSMauro Carvalho Chehab 
4660c0d06caSMauro Carvalho Chehab 			if (wait_event_interruptible(dev->wait_data,
4670c0d06caSMauro Carvalho Chehab 					      buf->status == BUFSTAT_READY)) {
4680c0d06caSMauro Carvalho Chehab 				ret = -ERESTARTSYS;
4690c0d06caSMauro Carvalho Chehab 				goto err;
4700c0d06caSMauro Carvalho Chehab 			}
4710c0d06caSMauro Carvalho Chehab 		}
4720c0d06caSMauro Carvalho Chehab 
4730c0d06caSMauro Carvalho Chehab 		if (buf->status != BUFSTAT_READY)
4740c0d06caSMauro Carvalho Chehab 			break;
4750c0d06caSMauro Carvalho Chehab 
4760c0d06caSMauro Carvalho Chehab 		/* set remaining bytes to copy */
4770c0d06caSMauro Carvalho Chehab 		urb = buf->urb;
4780c0d06caSMauro Carvalho Chehab 		rem = urb->actual_length - buf->pos;
4790c0d06caSMauro Carvalho Chehab 		cnt = rem > count ? count : rem;
4800c0d06caSMauro Carvalho Chehab 
4810c0d06caSMauro Carvalho Chehab 		if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
4820c0d06caSMauro Carvalho Chehab 				 cnt)) {
4830c0d06caSMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
4840c0d06caSMauro Carvalho Chehab 			if (!ret)
4850c0d06caSMauro Carvalho Chehab 				ret = -EFAULT;
4860c0d06caSMauro Carvalho Chehab 			goto err;
4870c0d06caSMauro Carvalho Chehab 		}
4880c0d06caSMauro Carvalho Chehab 
4890c0d06caSMauro Carvalho Chehab 		buf->pos += cnt;
4900c0d06caSMauro Carvalho Chehab 		count -= cnt;
4910c0d06caSMauro Carvalho Chehab 		buffer += cnt;
4920c0d06caSMauro Carvalho Chehab 		ret += cnt;
4930c0d06caSMauro Carvalho Chehab 
4940c0d06caSMauro Carvalho Chehab 		/* finished, take next buffer */
4950c0d06caSMauro Carvalho Chehab 		if (buf->pos == urb->actual_length) {
4960c0d06caSMauro Carvalho Chehab 			mutex_lock(&dev->io_mutex);
4970c0d06caSMauro Carvalho Chehab 			buf->pos = 0;
4980c0d06caSMauro Carvalho Chehab 			buf->status = BUFSTAT_AVAILABLE;
4990c0d06caSMauro Carvalho Chehab 
5000c0d06caSMauro Carvalho Chehab 			list_move_tail(&buf->buff_list, &dev->free_buff_list);
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 			wake_up_interruptible(&dev->wait_buffer);
5070c0d06caSMauro Carvalho Chehab 
5080c0d06caSMauro Carvalho Chehab 			buf = hdpvr_get_next_buffer(dev);
5090c0d06caSMauro Carvalho Chehab 		}
5100c0d06caSMauro Carvalho Chehab 	}
5110c0d06caSMauro Carvalho Chehab err:
5120c0d06caSMauro Carvalho Chehab 	if (!ret && !buf)
5130c0d06caSMauro Carvalho Chehab 		ret = -EAGAIN;
5140c0d06caSMauro Carvalho Chehab 	return ret;
5150c0d06caSMauro Carvalho Chehab }
5160c0d06caSMauro Carvalho Chehab 
5170c0d06caSMauro Carvalho Chehab static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
5180c0d06caSMauro Carvalho Chehab {
5190c0d06caSMauro Carvalho Chehab 	struct hdpvr_buffer *buf = NULL;
5200c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = filp->private_data;
5210c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
5220c0d06caSMauro Carvalho Chehab 	unsigned int mask = 0;
5230c0d06caSMauro Carvalho Chehab 
5240c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
5250c0d06caSMauro Carvalho Chehab 
5260c0d06caSMauro Carvalho Chehab 	if (!video_is_registered(dev->video_dev)) {
5270c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->io_mutex);
5280c0d06caSMauro Carvalho Chehab 		return -EIO;
5290c0d06caSMauro Carvalho Chehab 	}
5300c0d06caSMauro Carvalho Chehab 
5310c0d06caSMauro Carvalho Chehab 	if (dev->status == STATUS_IDLE) {
5320c0d06caSMauro Carvalho Chehab 		if (hdpvr_start_streaming(dev)) {
5330c0d06caSMauro Carvalho Chehab 			v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
5340c0d06caSMauro Carvalho Chehab 				 "start_streaming failed\n");
5350c0d06caSMauro Carvalho Chehab 			dev->status = STATUS_IDLE;
5360c0d06caSMauro Carvalho Chehab 		}
5370c0d06caSMauro Carvalho Chehab 
5380c0d06caSMauro Carvalho Chehab 		print_buffer_status();
5390c0d06caSMauro Carvalho Chehab 	}
5400c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
5410c0d06caSMauro Carvalho Chehab 
5420c0d06caSMauro Carvalho Chehab 	buf = hdpvr_get_next_buffer(dev);
5430c0d06caSMauro Carvalho Chehab 	/* only wait if no data is available */
5440c0d06caSMauro Carvalho Chehab 	if (!buf || buf->status != BUFSTAT_READY) {
5450c0d06caSMauro Carvalho Chehab 		poll_wait(filp, &dev->wait_data, wait);
5460c0d06caSMauro Carvalho Chehab 		buf = hdpvr_get_next_buffer(dev);
5470c0d06caSMauro Carvalho Chehab 	}
5480c0d06caSMauro Carvalho Chehab 	if (buf && buf->status == BUFSTAT_READY)
5490c0d06caSMauro Carvalho Chehab 		mask |= POLLIN | POLLRDNORM;
5500c0d06caSMauro Carvalho Chehab 
5510c0d06caSMauro Carvalho Chehab 	return mask;
5520c0d06caSMauro Carvalho Chehab }
5530c0d06caSMauro Carvalho Chehab 
5540c0d06caSMauro Carvalho Chehab 
5550c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations hdpvr_fops = {
5560c0d06caSMauro Carvalho Chehab 	.owner		= THIS_MODULE,
5570c0d06caSMauro Carvalho Chehab 	.open		= hdpvr_open,
5580c0d06caSMauro Carvalho Chehab 	.release	= hdpvr_release,
5590c0d06caSMauro Carvalho Chehab 	.read		= hdpvr_read,
5600c0d06caSMauro Carvalho Chehab 	.poll		= hdpvr_poll,
5610c0d06caSMauro Carvalho Chehab 	.unlocked_ioctl	= video_ioctl2,
5620c0d06caSMauro Carvalho Chehab };
5630c0d06caSMauro Carvalho Chehab 
5640c0d06caSMauro Carvalho Chehab /*=======================================================================*/
5650c0d06caSMauro Carvalho Chehab /*
5660c0d06caSMauro Carvalho Chehab  * V4L2 ioctl handling
5670c0d06caSMauro Carvalho Chehab  */
5680c0d06caSMauro Carvalho Chehab 
5690c0d06caSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void  *priv,
5700c0d06caSMauro Carvalho Chehab 			   struct v4l2_capability *cap)
5710c0d06caSMauro Carvalho Chehab {
5720c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_drvdata(file);
5730c0d06caSMauro Carvalho Chehab 
5740c0d06caSMauro Carvalho Chehab 	strcpy(cap->driver, "hdpvr");
5750c0d06caSMauro Carvalho Chehab 	strcpy(cap->card, "Hauppauge HD PVR");
5760c0d06caSMauro Carvalho Chehab 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
5770c0d06caSMauro Carvalho Chehab 	cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
5780c0d06caSMauro Carvalho Chehab 				V4L2_CAP_AUDIO         |
5790c0d06caSMauro Carvalho Chehab 				V4L2_CAP_READWRITE;
5800c0d06caSMauro Carvalho Chehab 	return 0;
5810c0d06caSMauro Carvalho Chehab }
5820c0d06caSMauro Carvalho Chehab 
5830c0d06caSMauro Carvalho Chehab static int vidioc_s_std(struct file *file, void *private_data,
5840c0d06caSMauro Carvalho Chehab 			v4l2_std_id *std)
5850c0d06caSMauro Carvalho Chehab {
5860c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
5870c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
5880c0d06caSMauro Carvalho Chehab 	u8 std_type = 1;
5890c0d06caSMauro Carvalho Chehab 
5900c0d06caSMauro Carvalho Chehab 	if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
5910c0d06caSMauro Carvalho Chehab 		std_type = 0;
5920c0d06caSMauro Carvalho Chehab 
5930c0d06caSMauro Carvalho Chehab 	return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
5940c0d06caSMauro Carvalho Chehab }
5950c0d06caSMauro Carvalho Chehab 
5960c0d06caSMauro Carvalho Chehab static const char *iname[] = {
5970c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPONENT] = "Component",
5980c0d06caSMauro Carvalho Chehab 	[HDPVR_SVIDEO]    = "S-Video",
5990c0d06caSMauro Carvalho Chehab 	[HDPVR_COMPOSITE] = "Composite",
6000c0d06caSMauro Carvalho Chehab };
6010c0d06caSMauro Carvalho Chehab 
6020c0d06caSMauro Carvalho Chehab static int vidioc_enum_input(struct file *file, void *priv,
6030c0d06caSMauro Carvalho Chehab 				struct v4l2_input *i)
6040c0d06caSMauro Carvalho Chehab {
6050c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
6060c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
6070c0d06caSMauro Carvalho Chehab 	unsigned int n;
6080c0d06caSMauro Carvalho Chehab 
6090c0d06caSMauro Carvalho Chehab 	n = i->index;
6100c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_VIDEO_INPUTS)
6110c0d06caSMauro Carvalho Chehab 		return -EINVAL;
6120c0d06caSMauro Carvalho Chehab 
6130c0d06caSMauro Carvalho Chehab 	i->type = V4L2_INPUT_TYPE_CAMERA;
6140c0d06caSMauro Carvalho Chehab 
6150c0d06caSMauro Carvalho Chehab 	strncpy(i->name, iname[n], sizeof(i->name) - 1);
6160c0d06caSMauro Carvalho Chehab 	i->name[sizeof(i->name) - 1] = '\0';
6170c0d06caSMauro Carvalho Chehab 
6180c0d06caSMauro Carvalho Chehab 	i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
6190c0d06caSMauro Carvalho Chehab 
6200c0d06caSMauro Carvalho Chehab 	i->std = dev->video_dev->tvnorms;
6210c0d06caSMauro Carvalho Chehab 
6220c0d06caSMauro Carvalho Chehab 	return 0;
6230c0d06caSMauro Carvalho Chehab }
6240c0d06caSMauro Carvalho Chehab 
6250c0d06caSMauro Carvalho Chehab static int vidioc_s_input(struct file *file, void *private_data,
6260c0d06caSMauro Carvalho Chehab 			  unsigned int index)
6270c0d06caSMauro Carvalho Chehab {
6280c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
6290c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
6300c0d06caSMauro Carvalho Chehab 	int retval;
6310c0d06caSMauro Carvalho Chehab 
6320c0d06caSMauro Carvalho Chehab 	if (index >= HDPVR_VIDEO_INPUTS)
6330c0d06caSMauro Carvalho Chehab 		return -EINVAL;
6340c0d06caSMauro Carvalho Chehab 
6350c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
6360c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
6370c0d06caSMauro Carvalho Chehab 
6380c0d06caSMauro Carvalho Chehab 	retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
6390c0d06caSMauro Carvalho Chehab 	if (!retval)
6400c0d06caSMauro Carvalho Chehab 		dev->options.video_input = index;
6410c0d06caSMauro Carvalho Chehab 
6420c0d06caSMauro Carvalho Chehab 	return retval;
6430c0d06caSMauro Carvalho Chehab }
6440c0d06caSMauro Carvalho Chehab 
6450c0d06caSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *private_data,
6460c0d06caSMauro Carvalho Chehab 			  unsigned int *index)
6470c0d06caSMauro Carvalho Chehab {
6480c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
6490c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
6500c0d06caSMauro Carvalho Chehab 
6510c0d06caSMauro Carvalho Chehab 	*index = dev->options.video_input;
6520c0d06caSMauro Carvalho Chehab 	return 0;
6530c0d06caSMauro Carvalho Chehab }
6540c0d06caSMauro Carvalho Chehab 
6550c0d06caSMauro Carvalho Chehab 
6560c0d06caSMauro Carvalho Chehab static const char *audio_iname[] = {
6570c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_FRONT] = "RCA front",
6580c0d06caSMauro Carvalho Chehab 	[HDPVR_RCA_BACK]  = "RCA back",
6590c0d06caSMauro Carvalho Chehab 	[HDPVR_SPDIF]     = "SPDIF",
6600c0d06caSMauro Carvalho Chehab };
6610c0d06caSMauro Carvalho Chehab 
6620c0d06caSMauro Carvalho Chehab static int vidioc_enumaudio(struct file *file, void *priv,
6630c0d06caSMauro Carvalho Chehab 				struct v4l2_audio *audio)
6640c0d06caSMauro Carvalho Chehab {
6650c0d06caSMauro Carvalho Chehab 	unsigned int n;
6660c0d06caSMauro Carvalho Chehab 
6670c0d06caSMauro Carvalho Chehab 	n = audio->index;
6680c0d06caSMauro Carvalho Chehab 	if (n >= HDPVR_AUDIO_INPUTS)
6690c0d06caSMauro Carvalho Chehab 		return -EINVAL;
6700c0d06caSMauro Carvalho Chehab 
6710c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
6720c0d06caSMauro Carvalho Chehab 
6730c0d06caSMauro Carvalho Chehab 	strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1);
6740c0d06caSMauro Carvalho Chehab 	audio->name[sizeof(audio->name) - 1] = '\0';
6750c0d06caSMauro Carvalho Chehab 
6760c0d06caSMauro Carvalho Chehab 	return 0;
6770c0d06caSMauro Carvalho Chehab }
6780c0d06caSMauro Carvalho Chehab 
6790c0d06caSMauro Carvalho Chehab static int vidioc_s_audio(struct file *file, void *private_data,
6800e8025b9SHans Verkuil 			  const struct v4l2_audio *audio)
6810c0d06caSMauro Carvalho Chehab {
6820c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
6830c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
6840c0d06caSMauro Carvalho Chehab 	int retval;
6850c0d06caSMauro Carvalho Chehab 
6860c0d06caSMauro Carvalho Chehab 	if (audio->index >= HDPVR_AUDIO_INPUTS)
6870c0d06caSMauro Carvalho Chehab 		return -EINVAL;
6880c0d06caSMauro Carvalho Chehab 
6890c0d06caSMauro Carvalho Chehab 	if (dev->status != STATUS_IDLE)
6900c0d06caSMauro Carvalho Chehab 		return -EAGAIN;
6910c0d06caSMauro Carvalho Chehab 
6920c0d06caSMauro Carvalho Chehab 	retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
6930c0d06caSMauro Carvalho Chehab 	if (!retval)
6940c0d06caSMauro Carvalho Chehab 		dev->options.audio_input = audio->index;
6950c0d06caSMauro Carvalho Chehab 
6960c0d06caSMauro Carvalho Chehab 	return retval;
6970c0d06caSMauro Carvalho Chehab }
6980c0d06caSMauro Carvalho Chehab 
6990c0d06caSMauro Carvalho Chehab static int vidioc_g_audio(struct file *file, void *private_data,
7000c0d06caSMauro Carvalho Chehab 			  struct v4l2_audio *audio)
7010c0d06caSMauro Carvalho Chehab {
7020c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
7030c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
7040c0d06caSMauro Carvalho Chehab 
7050c0d06caSMauro Carvalho Chehab 	audio->index = dev->options.audio_input;
7060c0d06caSMauro Carvalho Chehab 	audio->capability = V4L2_AUDCAP_STEREO;
7070c0d06caSMauro Carvalho Chehab 	strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
7080c0d06caSMauro Carvalho Chehab 	audio->name[sizeof(audio->name) - 1] = '\0';
7090c0d06caSMauro Carvalho Chehab 	return 0;
7100c0d06caSMauro Carvalho Chehab }
7110c0d06caSMauro Carvalho Chehab 
7120c0d06caSMauro Carvalho Chehab static const s32 supported_v4l2_ctrls[] = {
7130c0d06caSMauro Carvalho Chehab 	V4L2_CID_BRIGHTNESS,
7140c0d06caSMauro Carvalho Chehab 	V4L2_CID_CONTRAST,
7150c0d06caSMauro Carvalho Chehab 	V4L2_CID_SATURATION,
7160c0d06caSMauro Carvalho Chehab 	V4L2_CID_HUE,
7170c0d06caSMauro Carvalho Chehab 	V4L2_CID_SHARPNESS,
7180c0d06caSMauro Carvalho Chehab 	V4L2_CID_MPEG_AUDIO_ENCODING,
7190c0d06caSMauro Carvalho Chehab 	V4L2_CID_MPEG_VIDEO_ENCODING,
7200c0d06caSMauro Carvalho Chehab 	V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
7210c0d06caSMauro Carvalho Chehab 	V4L2_CID_MPEG_VIDEO_BITRATE,
7220c0d06caSMauro Carvalho Chehab 	V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
7230c0d06caSMauro Carvalho Chehab };
7240c0d06caSMauro Carvalho Chehab 
7250c0d06caSMauro Carvalho Chehab static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
7260c0d06caSMauro Carvalho Chehab 			  int ac3, int fw_ver)
7270c0d06caSMauro Carvalho Chehab {
7280c0d06caSMauro Carvalho Chehab 	int err;
7290c0d06caSMauro Carvalho Chehab 
7300c0d06caSMauro Carvalho Chehab 	if (fw_ver > 0x15) {
7310c0d06caSMauro Carvalho Chehab 		switch (qc->id) {
7320c0d06caSMauro Carvalho Chehab 		case V4L2_CID_BRIGHTNESS:
7330c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
7340c0d06caSMauro Carvalho Chehab 		case V4L2_CID_CONTRAST:
7350c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
7360c0d06caSMauro Carvalho Chehab 		case V4L2_CID_SATURATION:
7370c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
7380c0d06caSMauro Carvalho Chehab 		case V4L2_CID_HUE:
7390c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0x1e, 1, 0xf);
7400c0d06caSMauro Carvalho Chehab 		case V4L2_CID_SHARPNESS:
7410c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
7420c0d06caSMauro Carvalho Chehab 		}
7430c0d06caSMauro Carvalho Chehab 	} else {
7440c0d06caSMauro Carvalho Chehab 		switch (qc->id) {
7450c0d06caSMauro Carvalho Chehab 		case V4L2_CID_BRIGHTNESS:
7460c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
7470c0d06caSMauro Carvalho Chehab 		case V4L2_CID_CONTRAST:
7480c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
7490c0d06caSMauro Carvalho Chehab 		case V4L2_CID_SATURATION:
7500c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
7510c0d06caSMauro Carvalho Chehab 		case V4L2_CID_HUE:
7520c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
7530c0d06caSMauro Carvalho Chehab 		case V4L2_CID_SHARPNESS:
7540c0d06caSMauro Carvalho Chehab 			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
7550c0d06caSMauro Carvalho Chehab 		}
7560c0d06caSMauro Carvalho Chehab 	}
7570c0d06caSMauro Carvalho Chehab 
7580c0d06caSMauro Carvalho Chehab 	switch (qc->id) {
7590c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
7600c0d06caSMauro Carvalho Chehab 		return v4l2_ctrl_query_fill(
7610c0d06caSMauro Carvalho Chehab 			qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
7620c0d06caSMauro Carvalho Chehab 			ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
7630c0d06caSMauro Carvalho Chehab 			: V4L2_MPEG_AUDIO_ENCODING_AAC,
7640c0d06caSMauro Carvalho Chehab 			1, V4L2_MPEG_AUDIO_ENCODING_AAC);
7650c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
7660c0d06caSMauro Carvalho Chehab 		return v4l2_ctrl_query_fill(
7670c0d06caSMauro Carvalho Chehab 			qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
7680c0d06caSMauro Carvalho Chehab 			V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
7690c0d06caSMauro Carvalho Chehab 			V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
7700c0d06caSMauro Carvalho Chehab 
7710c0d06caSMauro Carvalho Chehab /* 	case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
7720c0d06caSMauro Carvalho Chehab /* 		return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
7730c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
7740c0d06caSMauro Carvalho Chehab 		return v4l2_ctrl_query_fill(
7750c0d06caSMauro Carvalho Chehab 			qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
7760c0d06caSMauro Carvalho Chehab 			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
7770c0d06caSMauro Carvalho Chehab 			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
7780c0d06caSMauro Carvalho Chehab 
7790c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE:
7800c0d06caSMauro Carvalho Chehab 		return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
7810c0d06caSMauro Carvalho Chehab 					    6500000);
7820c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
7830c0d06caSMauro Carvalho Chehab 		err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
7840c0d06caSMauro Carvalho Chehab 					   9000000);
7850c0d06caSMauro Carvalho Chehab 		if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
7860c0d06caSMauro Carvalho Chehab 			qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
7870c0d06caSMauro Carvalho Chehab 		return err;
7880c0d06caSMauro Carvalho Chehab 	default:
7890c0d06caSMauro Carvalho Chehab 		return -EINVAL;
7900c0d06caSMauro Carvalho Chehab 	}
7910c0d06caSMauro Carvalho Chehab }
7920c0d06caSMauro Carvalho Chehab 
7930c0d06caSMauro Carvalho Chehab static int vidioc_queryctrl(struct file *file, void *private_data,
7940c0d06caSMauro Carvalho Chehab 			    struct v4l2_queryctrl *qc)
7950c0d06caSMauro Carvalho Chehab {
7960c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
7970c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
7980c0d06caSMauro Carvalho Chehab 	int i, next;
7990c0d06caSMauro Carvalho Chehab 	u32 id = qc->id;
8000c0d06caSMauro Carvalho Chehab 
8010c0d06caSMauro Carvalho Chehab 	memset(qc, 0, sizeof(*qc));
8020c0d06caSMauro Carvalho Chehab 
8030c0d06caSMauro Carvalho Chehab 	next = !!(id &  V4L2_CTRL_FLAG_NEXT_CTRL);
8040c0d06caSMauro Carvalho Chehab 	qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
8050c0d06caSMauro Carvalho Chehab 
8060c0d06caSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
8070c0d06caSMauro Carvalho Chehab 		if (next) {
8080c0d06caSMauro Carvalho Chehab 			if (qc->id < supported_v4l2_ctrls[i])
8090c0d06caSMauro Carvalho Chehab 				qc->id = supported_v4l2_ctrls[i];
8100c0d06caSMauro Carvalho Chehab 			else
8110c0d06caSMauro Carvalho Chehab 				continue;
8120c0d06caSMauro Carvalho Chehab 		}
8130c0d06caSMauro Carvalho Chehab 
8140c0d06caSMauro Carvalho Chehab 		if (qc->id == supported_v4l2_ctrls[i])
8150c0d06caSMauro Carvalho Chehab 			return fill_queryctrl(&dev->options, qc,
8160c0d06caSMauro Carvalho Chehab 					      dev->flags & HDPVR_FLAG_AC3_CAP,
8170c0d06caSMauro Carvalho Chehab 					      dev->fw_ver);
8180c0d06caSMauro Carvalho Chehab 
8190c0d06caSMauro Carvalho Chehab 		if (qc->id < supported_v4l2_ctrls[i])
8200c0d06caSMauro Carvalho Chehab 			break;
8210c0d06caSMauro Carvalho Chehab 	}
8220c0d06caSMauro Carvalho Chehab 
8230c0d06caSMauro Carvalho Chehab 	return -EINVAL;
8240c0d06caSMauro Carvalho Chehab }
8250c0d06caSMauro Carvalho Chehab 
8260c0d06caSMauro Carvalho Chehab static int vidioc_g_ctrl(struct file *file, void *private_data,
8270c0d06caSMauro Carvalho Chehab 			 struct v4l2_control *ctrl)
8280c0d06caSMauro Carvalho Chehab {
8290c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
8300c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
8310c0d06caSMauro Carvalho Chehab 
8320c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
8330c0d06caSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
8340c0d06caSMauro Carvalho Chehab 		ctrl->value = dev->options.brightness;
8350c0d06caSMauro Carvalho Chehab 		break;
8360c0d06caSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
8370c0d06caSMauro Carvalho Chehab 		ctrl->value = dev->options.contrast;
8380c0d06caSMauro Carvalho Chehab 		break;
8390c0d06caSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
8400c0d06caSMauro Carvalho Chehab 		ctrl->value = dev->options.saturation;
8410c0d06caSMauro Carvalho Chehab 		break;
8420c0d06caSMauro Carvalho Chehab 	case V4L2_CID_HUE:
8430c0d06caSMauro Carvalho Chehab 		ctrl->value = dev->options.hue;
8440c0d06caSMauro Carvalho Chehab 		break;
8450c0d06caSMauro Carvalho Chehab 	case V4L2_CID_SHARPNESS:
8460c0d06caSMauro Carvalho Chehab 		ctrl->value = dev->options.sharpness;
8470c0d06caSMauro Carvalho Chehab 		break;
8480c0d06caSMauro Carvalho Chehab 	default:
8490c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8500c0d06caSMauro Carvalho Chehab 	}
8510c0d06caSMauro Carvalho Chehab 	return 0;
8520c0d06caSMauro Carvalho Chehab }
8530c0d06caSMauro Carvalho Chehab 
8540c0d06caSMauro Carvalho Chehab static int vidioc_s_ctrl(struct file *file, void *private_data,
8550c0d06caSMauro Carvalho Chehab 			 struct v4l2_control *ctrl)
8560c0d06caSMauro Carvalho Chehab {
8570c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
8580c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
8590c0d06caSMauro Carvalho Chehab 	int retval;
8600c0d06caSMauro Carvalho Chehab 
8610c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
8620c0d06caSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
8630c0d06caSMauro Carvalho Chehab 		retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
8640c0d06caSMauro Carvalho Chehab 		if (!retval)
8650c0d06caSMauro Carvalho Chehab 			dev->options.brightness = ctrl->value;
8660c0d06caSMauro Carvalho Chehab 		break;
8670c0d06caSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
8680c0d06caSMauro Carvalho Chehab 		retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
8690c0d06caSMauro Carvalho Chehab 		if (!retval)
8700c0d06caSMauro Carvalho Chehab 			dev->options.contrast = ctrl->value;
8710c0d06caSMauro Carvalho Chehab 		break;
8720c0d06caSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
8730c0d06caSMauro Carvalho Chehab 		retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
8740c0d06caSMauro Carvalho Chehab 		if (!retval)
8750c0d06caSMauro Carvalho Chehab 			dev->options.saturation = ctrl->value;
8760c0d06caSMauro Carvalho Chehab 		break;
8770c0d06caSMauro Carvalho Chehab 	case V4L2_CID_HUE:
8780c0d06caSMauro Carvalho Chehab 		retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
8790c0d06caSMauro Carvalho Chehab 		if (!retval)
8800c0d06caSMauro Carvalho Chehab 			dev->options.hue = ctrl->value;
8810c0d06caSMauro Carvalho Chehab 		break;
8820c0d06caSMauro Carvalho Chehab 	case V4L2_CID_SHARPNESS:
8830c0d06caSMauro Carvalho Chehab 		retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
8840c0d06caSMauro Carvalho Chehab 		if (!retval)
8850c0d06caSMauro Carvalho Chehab 			dev->options.sharpness = ctrl->value;
8860c0d06caSMauro Carvalho Chehab 		break;
8870c0d06caSMauro Carvalho Chehab 	default:
8880c0d06caSMauro Carvalho Chehab 		return -EINVAL;
8890c0d06caSMauro Carvalho Chehab 	}
8900c0d06caSMauro Carvalho Chehab 
8910c0d06caSMauro Carvalho Chehab 	return retval;
8920c0d06caSMauro Carvalho Chehab }
8930c0d06caSMauro Carvalho Chehab 
8940c0d06caSMauro Carvalho Chehab 
8950c0d06caSMauro Carvalho Chehab static int hdpvr_get_ctrl(struct hdpvr_options *opt,
8960c0d06caSMauro Carvalho Chehab 			  struct v4l2_ext_control *ctrl)
8970c0d06caSMauro Carvalho Chehab {
8980c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
8990c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
9000c0d06caSMauro Carvalho Chehab 		ctrl->value = opt->audio_codec;
9010c0d06caSMauro Carvalho Chehab 		break;
9020c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
9030c0d06caSMauro Carvalho Chehab 		ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
9040c0d06caSMauro Carvalho Chehab 		break;
9050c0d06caSMauro Carvalho Chehab /* 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
9060c0d06caSMauro Carvalho Chehab /* 		ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
9070c0d06caSMauro Carvalho Chehab /* 		break; */
9080c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
9090c0d06caSMauro Carvalho Chehab 		ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
9100c0d06caSMauro Carvalho Chehab 			? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
9110c0d06caSMauro Carvalho Chehab 			: V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
9120c0d06caSMauro Carvalho Chehab 		break;
9130c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE:
9140c0d06caSMauro Carvalho Chehab 		ctrl->value = opt->bitrate * 100000;
9150c0d06caSMauro Carvalho Chehab 		break;
9160c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
9170c0d06caSMauro Carvalho Chehab 		ctrl->value = opt->peak_bitrate * 100000;
9180c0d06caSMauro Carvalho Chehab 		break;
9190c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_STREAM_TYPE:
9200c0d06caSMauro Carvalho Chehab 		ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
9210c0d06caSMauro Carvalho Chehab 		break;
9220c0d06caSMauro Carvalho Chehab 	default:
9230c0d06caSMauro Carvalho Chehab 		return -EINVAL;
9240c0d06caSMauro Carvalho Chehab 	}
9250c0d06caSMauro Carvalho Chehab 	return 0;
9260c0d06caSMauro Carvalho Chehab }
9270c0d06caSMauro Carvalho Chehab 
9280c0d06caSMauro Carvalho Chehab static int vidioc_g_ext_ctrls(struct file *file, void *priv,
9290c0d06caSMauro Carvalho Chehab 			      struct v4l2_ext_controls *ctrls)
9300c0d06caSMauro Carvalho Chehab {
9310c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
9320c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
9330c0d06caSMauro Carvalho Chehab 	int i, err = 0;
9340c0d06caSMauro Carvalho Chehab 
9350c0d06caSMauro Carvalho Chehab 	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
9360c0d06caSMauro Carvalho Chehab 		for (i = 0; i < ctrls->count; i++) {
9370c0d06caSMauro Carvalho Chehab 			struct v4l2_ext_control *ctrl = ctrls->controls + i;
9380c0d06caSMauro Carvalho Chehab 
9390c0d06caSMauro Carvalho Chehab 			err = hdpvr_get_ctrl(&dev->options, ctrl);
9400c0d06caSMauro Carvalho Chehab 			if (err) {
9410c0d06caSMauro Carvalho Chehab 				ctrls->error_idx = i;
9420c0d06caSMauro Carvalho Chehab 				break;
9430c0d06caSMauro Carvalho Chehab 			}
9440c0d06caSMauro Carvalho Chehab 		}
9450c0d06caSMauro Carvalho Chehab 		return err;
9460c0d06caSMauro Carvalho Chehab 
9470c0d06caSMauro Carvalho Chehab 	}
9480c0d06caSMauro Carvalho Chehab 
9490c0d06caSMauro Carvalho Chehab 	return -EINVAL;
9500c0d06caSMauro Carvalho Chehab }
9510c0d06caSMauro Carvalho Chehab 
9520c0d06caSMauro Carvalho Chehab 
9530c0d06caSMauro Carvalho Chehab static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
9540c0d06caSMauro Carvalho Chehab {
9550c0d06caSMauro Carvalho Chehab 	int ret = -EINVAL;
9560c0d06caSMauro Carvalho Chehab 
9570c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
9580c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
9590c0d06caSMauro Carvalho Chehab 		if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
9600c0d06caSMauro Carvalho Chehab 		    (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
9610c0d06caSMauro Carvalho Chehab 			ret = 0;
9620c0d06caSMauro Carvalho Chehab 		break;
9630c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
9640c0d06caSMauro Carvalho Chehab 		if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
9650c0d06caSMauro Carvalho Chehab 			ret = 0;
9660c0d06caSMauro Carvalho Chehab 		break;
9670c0d06caSMauro Carvalho Chehab /* 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
9680c0d06caSMauro Carvalho Chehab /* 		if (ctrl->value == 0 || ctrl->value == 128) */
9690c0d06caSMauro Carvalho Chehab /* 			ret = 0; */
9700c0d06caSMauro Carvalho Chehab /* 		break; */
9710c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
9720c0d06caSMauro Carvalho Chehab 		if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
9730c0d06caSMauro Carvalho Chehab 		    ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
9740c0d06caSMauro Carvalho Chehab 			ret = 0;
9750c0d06caSMauro Carvalho Chehab 		break;
9760c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE:
9770c0d06caSMauro Carvalho Chehab 	{
9780c0d06caSMauro Carvalho Chehab 		uint bitrate = ctrl->value / 100000;
9790c0d06caSMauro Carvalho Chehab 		if (bitrate >= 10 && bitrate <= 135)
9800c0d06caSMauro Carvalho Chehab 			ret = 0;
9810c0d06caSMauro Carvalho Chehab 		break;
9820c0d06caSMauro Carvalho Chehab 	}
9830c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
9840c0d06caSMauro Carvalho Chehab 	{
9850c0d06caSMauro Carvalho Chehab 		uint peak_bitrate = ctrl->value / 100000;
9860c0d06caSMauro Carvalho Chehab 		if (peak_bitrate >= 10 && peak_bitrate <= 202)
9870c0d06caSMauro Carvalho Chehab 			ret = 0;
9880c0d06caSMauro Carvalho Chehab 		break;
9890c0d06caSMauro Carvalho Chehab 	}
9900c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_STREAM_TYPE:
9910c0d06caSMauro Carvalho Chehab 		if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
9920c0d06caSMauro Carvalho Chehab 			ret = 0;
9930c0d06caSMauro Carvalho Chehab 		break;
9940c0d06caSMauro Carvalho Chehab 	default:
9950c0d06caSMauro Carvalho Chehab 		return -EINVAL;
9960c0d06caSMauro Carvalho Chehab 	}
9970c0d06caSMauro Carvalho Chehab 	return ret;
9980c0d06caSMauro Carvalho Chehab }
9990c0d06caSMauro Carvalho Chehab 
10000c0d06caSMauro Carvalho Chehab static int vidioc_try_ext_ctrls(struct file *file, void *priv,
10010c0d06caSMauro Carvalho Chehab 				struct v4l2_ext_controls *ctrls)
10020c0d06caSMauro Carvalho Chehab {
10030c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
10040c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
10050c0d06caSMauro Carvalho Chehab 	int i, err = 0;
10060c0d06caSMauro Carvalho Chehab 
10070c0d06caSMauro Carvalho Chehab 	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
10080c0d06caSMauro Carvalho Chehab 		for (i = 0; i < ctrls->count; i++) {
10090c0d06caSMauro Carvalho Chehab 			struct v4l2_ext_control *ctrl = ctrls->controls + i;
10100c0d06caSMauro Carvalho Chehab 
10110c0d06caSMauro Carvalho Chehab 			err = hdpvr_try_ctrl(ctrl,
10120c0d06caSMauro Carvalho Chehab 					     dev->flags & HDPVR_FLAG_AC3_CAP);
10130c0d06caSMauro Carvalho Chehab 			if (err) {
10140c0d06caSMauro Carvalho Chehab 				ctrls->error_idx = i;
10150c0d06caSMauro Carvalho Chehab 				break;
10160c0d06caSMauro Carvalho Chehab 			}
10170c0d06caSMauro Carvalho Chehab 		}
10180c0d06caSMauro Carvalho Chehab 		return err;
10190c0d06caSMauro Carvalho Chehab 	}
10200c0d06caSMauro Carvalho Chehab 
10210c0d06caSMauro Carvalho Chehab 	return -EINVAL;
10220c0d06caSMauro Carvalho Chehab }
10230c0d06caSMauro Carvalho Chehab 
10240c0d06caSMauro Carvalho Chehab 
10250c0d06caSMauro Carvalho Chehab static int hdpvr_set_ctrl(struct hdpvr_device *dev,
10260c0d06caSMauro Carvalho Chehab 			  struct v4l2_ext_control *ctrl)
10270c0d06caSMauro Carvalho Chehab {
10280c0d06caSMauro Carvalho Chehab 	struct hdpvr_options *opt = &dev->options;
10290c0d06caSMauro Carvalho Chehab 	int ret = 0;
10300c0d06caSMauro Carvalho Chehab 
10310c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
10320c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_AUDIO_ENCODING:
10330c0d06caSMauro Carvalho Chehab 		if (dev->flags & HDPVR_FLAG_AC3_CAP) {
10340c0d06caSMauro Carvalho Chehab 			opt->audio_codec = ctrl->value;
10350c0d06caSMauro Carvalho Chehab 			ret = hdpvr_set_audio(dev, opt->audio_input,
10360c0d06caSMauro Carvalho Chehab 					      opt->audio_codec);
10370c0d06caSMauro Carvalho Chehab 		}
10380c0d06caSMauro Carvalho Chehab 		break;
10390c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_ENCODING:
10400c0d06caSMauro Carvalho Chehab 		break;
10410c0d06caSMauro Carvalho Chehab /* 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
10420c0d06caSMauro Carvalho Chehab /* 		if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
10430c0d06caSMauro Carvalho Chehab /* 			opt->gop_mode |= 0x2; */
10440c0d06caSMauro Carvalho Chehab /* 			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
10450c0d06caSMauro Carvalho Chehab /* 					  opt->gop_mode); */
10460c0d06caSMauro Carvalho Chehab /* 		} */
10470c0d06caSMauro Carvalho Chehab /* 		if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
10480c0d06caSMauro Carvalho Chehab /* 			opt->gop_mode &= ~0x2; */
10490c0d06caSMauro Carvalho Chehab /* 			hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
10500c0d06caSMauro Carvalho Chehab /* 					  opt->gop_mode); */
10510c0d06caSMauro Carvalho Chehab /* 		} */
10520c0d06caSMauro Carvalho Chehab /* 		break; */
10530c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
10540c0d06caSMauro Carvalho Chehab 		if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
10550c0d06caSMauro Carvalho Chehab 		    opt->bitrate_mode != HDPVR_CONSTANT) {
10560c0d06caSMauro Carvalho Chehab 			opt->bitrate_mode = HDPVR_CONSTANT;
10570c0d06caSMauro Carvalho Chehab 			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
10580c0d06caSMauro Carvalho Chehab 					  opt->bitrate_mode);
10590c0d06caSMauro Carvalho Chehab 		}
10600c0d06caSMauro Carvalho Chehab 		if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
10610c0d06caSMauro Carvalho Chehab 		    opt->bitrate_mode == HDPVR_CONSTANT) {
10620c0d06caSMauro Carvalho Chehab 			opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
10630c0d06caSMauro Carvalho Chehab 			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
10640c0d06caSMauro Carvalho Chehab 					  opt->bitrate_mode);
10650c0d06caSMauro Carvalho Chehab 		}
10660c0d06caSMauro Carvalho Chehab 		break;
10670c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE: {
10680c0d06caSMauro Carvalho Chehab 		uint bitrate = ctrl->value / 100000;
10690c0d06caSMauro Carvalho Chehab 
10700c0d06caSMauro Carvalho Chehab 		opt->bitrate = bitrate;
10710c0d06caSMauro Carvalho Chehab 		if (bitrate >= opt->peak_bitrate)
10720c0d06caSMauro Carvalho Chehab 			opt->peak_bitrate = bitrate+1;
10730c0d06caSMauro Carvalho Chehab 
10740c0d06caSMauro Carvalho Chehab 		hdpvr_set_bitrate(dev);
10750c0d06caSMauro Carvalho Chehab 		break;
10760c0d06caSMauro Carvalho Chehab 	}
10770c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
10780c0d06caSMauro Carvalho Chehab 		uint peak_bitrate = ctrl->value / 100000;
10790c0d06caSMauro Carvalho Chehab 
10800c0d06caSMauro Carvalho Chehab 		if (opt->bitrate_mode == HDPVR_CONSTANT)
10810c0d06caSMauro Carvalho Chehab 			break;
10820c0d06caSMauro Carvalho Chehab 
10830c0d06caSMauro Carvalho Chehab 		if (opt->bitrate < peak_bitrate) {
10840c0d06caSMauro Carvalho Chehab 			opt->peak_bitrate = peak_bitrate;
10850c0d06caSMauro Carvalho Chehab 			hdpvr_set_bitrate(dev);
10860c0d06caSMauro Carvalho Chehab 		} else
10870c0d06caSMauro Carvalho Chehab 			ret = -EINVAL;
10880c0d06caSMauro Carvalho Chehab 		break;
10890c0d06caSMauro Carvalho Chehab 	}
10900c0d06caSMauro Carvalho Chehab 	case V4L2_CID_MPEG_STREAM_TYPE:
10910c0d06caSMauro Carvalho Chehab 		break;
10920c0d06caSMauro Carvalho Chehab 	default:
10930c0d06caSMauro Carvalho Chehab 		return -EINVAL;
10940c0d06caSMauro Carvalho Chehab 	}
10950c0d06caSMauro Carvalho Chehab 	return ret;
10960c0d06caSMauro Carvalho Chehab }
10970c0d06caSMauro Carvalho Chehab 
10980c0d06caSMauro Carvalho Chehab static int vidioc_s_ext_ctrls(struct file *file, void *priv,
10990c0d06caSMauro Carvalho Chehab 			      struct v4l2_ext_controls *ctrls)
11000c0d06caSMauro Carvalho Chehab {
11010c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
11020c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
11030c0d06caSMauro Carvalho Chehab 	int i, err = 0;
11040c0d06caSMauro Carvalho Chehab 
11050c0d06caSMauro Carvalho Chehab 	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
11060c0d06caSMauro Carvalho Chehab 		for (i = 0; i < ctrls->count; i++) {
11070c0d06caSMauro Carvalho Chehab 			struct v4l2_ext_control *ctrl = ctrls->controls + i;
11080c0d06caSMauro Carvalho Chehab 
11090c0d06caSMauro Carvalho Chehab 			err = hdpvr_try_ctrl(ctrl,
11100c0d06caSMauro Carvalho Chehab 					     dev->flags & HDPVR_FLAG_AC3_CAP);
11110c0d06caSMauro Carvalho Chehab 			if (err) {
11120c0d06caSMauro Carvalho Chehab 				ctrls->error_idx = i;
11130c0d06caSMauro Carvalho Chehab 				break;
11140c0d06caSMauro Carvalho Chehab 			}
11150c0d06caSMauro Carvalho Chehab 			err = hdpvr_set_ctrl(dev, ctrl);
11160c0d06caSMauro Carvalho Chehab 			if (err) {
11170c0d06caSMauro Carvalho Chehab 				ctrls->error_idx = i;
11180c0d06caSMauro Carvalho Chehab 				break;
11190c0d06caSMauro Carvalho Chehab 			}
11200c0d06caSMauro Carvalho Chehab 		}
11210c0d06caSMauro Carvalho Chehab 		return err;
11220c0d06caSMauro Carvalho Chehab 
11230c0d06caSMauro Carvalho Chehab 	}
11240c0d06caSMauro Carvalho Chehab 
11250c0d06caSMauro Carvalho Chehab 	return -EINVAL;
11260c0d06caSMauro Carvalho Chehab }
11270c0d06caSMauro Carvalho Chehab 
11280c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
11290c0d06caSMauro Carvalho Chehab 				    struct v4l2_fmtdesc *f)
11300c0d06caSMauro Carvalho Chehab {
11310c0d06caSMauro Carvalho Chehab 
11320c0d06caSMauro Carvalho Chehab 	if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
11330c0d06caSMauro Carvalho Chehab 		return -EINVAL;
11340c0d06caSMauro Carvalho Chehab 
11350c0d06caSMauro Carvalho Chehab 	f->flags = V4L2_FMT_FLAG_COMPRESSED;
11360c0d06caSMauro Carvalho Chehab 	strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32);
11370c0d06caSMauro Carvalho Chehab 	f->pixelformat = V4L2_PIX_FMT_MPEG;
11380c0d06caSMauro Carvalho Chehab 
11390c0d06caSMauro Carvalho Chehab 	return 0;
11400c0d06caSMauro Carvalho Chehab }
11410c0d06caSMauro Carvalho Chehab 
11420c0d06caSMauro Carvalho Chehab static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
11430c0d06caSMauro Carvalho Chehab 				struct v4l2_format *f)
11440c0d06caSMauro Carvalho Chehab {
11450c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = file->private_data;
11460c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
11470c0d06caSMauro Carvalho Chehab 	struct hdpvr_video_info *vid_info;
11480c0d06caSMauro Carvalho Chehab 
11490c0d06caSMauro Carvalho Chehab 	if (!dev)
11500c0d06caSMauro Carvalho Chehab 		return -ENODEV;
11510c0d06caSMauro Carvalho Chehab 
11520c0d06caSMauro Carvalho Chehab 	vid_info = get_video_info(dev);
11530c0d06caSMauro Carvalho Chehab 	if (!vid_info)
11540c0d06caSMauro Carvalho Chehab 		return -EFAULT;
11550c0d06caSMauro Carvalho Chehab 
11560c0d06caSMauro Carvalho Chehab 	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
11570c0d06caSMauro Carvalho Chehab 	f->fmt.pix.pixelformat	= V4L2_PIX_FMT_MPEG;
11580c0d06caSMauro Carvalho Chehab 	f->fmt.pix.width	= vid_info->width;
11590c0d06caSMauro Carvalho Chehab 	f->fmt.pix.height	= vid_info->height;
11600c0d06caSMauro Carvalho Chehab 	f->fmt.pix.sizeimage	= dev->bulk_in_size;
11610c0d06caSMauro Carvalho Chehab 	f->fmt.pix.colorspace	= 0;
11620c0d06caSMauro Carvalho Chehab 	f->fmt.pix.bytesperline	= 0;
11630c0d06caSMauro Carvalho Chehab 	f->fmt.pix.field	= V4L2_FIELD_ANY;
11640c0d06caSMauro Carvalho Chehab 
11650c0d06caSMauro Carvalho Chehab 	kfree(vid_info);
11660c0d06caSMauro Carvalho Chehab 	return 0;
11670c0d06caSMauro Carvalho Chehab }
11680c0d06caSMauro Carvalho Chehab 
11690c0d06caSMauro Carvalho Chehab static int vidioc_encoder_cmd(struct file *filp, void *priv,
11700c0d06caSMauro Carvalho Chehab 			       struct v4l2_encoder_cmd *a)
11710c0d06caSMauro Carvalho Chehab {
11720c0d06caSMauro Carvalho Chehab 	struct hdpvr_fh *fh = filp->private_data;
11730c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = fh->dev;
11740c0d06caSMauro Carvalho Chehab 	int res;
11750c0d06caSMauro Carvalho Chehab 
11760c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
11770c0d06caSMauro Carvalho Chehab 
11780c0d06caSMauro Carvalho Chehab 	memset(&a->raw, 0, sizeof(a->raw));
11790c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
11800c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
11810c0d06caSMauro Carvalho Chehab 		a->flags = 0;
11820c0d06caSMauro Carvalho Chehab 		res = hdpvr_start_streaming(dev);
11830c0d06caSMauro Carvalho Chehab 		break;
11840c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
11850c0d06caSMauro Carvalho Chehab 		res = hdpvr_stop_streaming(dev);
11860c0d06caSMauro Carvalho Chehab 		break;
11870c0d06caSMauro Carvalho Chehab 	default:
11880c0d06caSMauro Carvalho Chehab 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
11890c0d06caSMauro Carvalho Chehab 			 "Unsupported encoder cmd %d\n", a->cmd);
11900c0d06caSMauro Carvalho Chehab 		res = -EINVAL;
11910c0d06caSMauro Carvalho Chehab 	}
11920c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
11930c0d06caSMauro Carvalho Chehab 	return res;
11940c0d06caSMauro Carvalho Chehab }
11950c0d06caSMauro Carvalho Chehab 
11960c0d06caSMauro Carvalho Chehab static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
11970c0d06caSMauro Carvalho Chehab 					struct v4l2_encoder_cmd *a)
11980c0d06caSMauro Carvalho Chehab {
11990c0d06caSMauro Carvalho Chehab 	switch (a->cmd) {
12000c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_START:
12010c0d06caSMauro Carvalho Chehab 	case V4L2_ENC_CMD_STOP:
12020c0d06caSMauro Carvalho Chehab 		return 0;
12030c0d06caSMauro Carvalho Chehab 	default:
12040c0d06caSMauro Carvalho Chehab 		return -EINVAL;
12050c0d06caSMauro Carvalho Chehab 	}
12060c0d06caSMauro Carvalho Chehab }
12070c0d06caSMauro Carvalho Chehab 
12080c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
12090c0d06caSMauro Carvalho Chehab 	.vidioc_querycap	= vidioc_querycap,
12100c0d06caSMauro Carvalho Chehab 	.vidioc_s_std		= vidioc_s_std,
12110c0d06caSMauro Carvalho Chehab 	.vidioc_enum_input	= vidioc_enum_input,
12120c0d06caSMauro Carvalho Chehab 	.vidioc_g_input		= vidioc_g_input,
12130c0d06caSMauro Carvalho Chehab 	.vidioc_s_input		= vidioc_s_input,
12140c0d06caSMauro Carvalho Chehab 	.vidioc_enumaudio	= vidioc_enumaudio,
12150c0d06caSMauro Carvalho Chehab 	.vidioc_g_audio		= vidioc_g_audio,
12160c0d06caSMauro Carvalho Chehab 	.vidioc_s_audio		= vidioc_s_audio,
12170c0d06caSMauro Carvalho Chehab 	.vidioc_queryctrl	= vidioc_queryctrl,
12180c0d06caSMauro Carvalho Chehab 	.vidioc_g_ctrl		= vidioc_g_ctrl,
12190c0d06caSMauro Carvalho Chehab 	.vidioc_s_ctrl		= vidioc_s_ctrl,
12200c0d06caSMauro Carvalho Chehab 	.vidioc_g_ext_ctrls	= vidioc_g_ext_ctrls,
12210c0d06caSMauro Carvalho Chehab 	.vidioc_s_ext_ctrls	= vidioc_s_ext_ctrls,
12220c0d06caSMauro Carvalho Chehab 	.vidioc_try_ext_ctrls	= vidioc_try_ext_ctrls,
12230c0d06caSMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
12240c0d06caSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt_vid_cap,
12250c0d06caSMauro Carvalho Chehab 	.vidioc_encoder_cmd	= vidioc_encoder_cmd,
12260c0d06caSMauro Carvalho Chehab 	.vidioc_try_encoder_cmd	= vidioc_try_encoder_cmd,
12270c0d06caSMauro Carvalho Chehab };
12280c0d06caSMauro Carvalho Chehab 
12290c0d06caSMauro Carvalho Chehab static void hdpvr_device_release(struct video_device *vdev)
12300c0d06caSMauro Carvalho Chehab {
12310c0d06caSMauro Carvalho Chehab 	struct hdpvr_device *dev = video_get_drvdata(vdev);
12320c0d06caSMauro Carvalho Chehab 
12330c0d06caSMauro Carvalho Chehab 	hdpvr_delete(dev);
12340c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->io_mutex);
12350c0d06caSMauro Carvalho Chehab 	destroy_workqueue(dev->workqueue);
12360c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->io_mutex);
12370c0d06caSMauro Carvalho Chehab 
12380c0d06caSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
12390c0d06caSMauro Carvalho Chehab 
12400c0d06caSMauro Carvalho Chehab 	/* deregister I2C adapter */
12410c0d06caSMauro Carvalho Chehab #if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE)
12420c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->i2c_mutex);
12430c0d06caSMauro Carvalho Chehab 	i2c_del_adapter(&dev->i2c_adapter);
12440c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->i2c_mutex);
12450c0d06caSMauro Carvalho Chehab #endif /* CONFIG_I2C */
12460c0d06caSMauro Carvalho Chehab 
12470c0d06caSMauro Carvalho Chehab 	kfree(dev->usbc_buf);
12480c0d06caSMauro Carvalho Chehab 	kfree(dev);
12490c0d06caSMauro Carvalho Chehab }
12500c0d06caSMauro Carvalho Chehab 
12510c0d06caSMauro Carvalho Chehab static const struct video_device hdpvr_video_template = {
12520c0d06caSMauro Carvalho Chehab /* 	.type			= VFL_TYPE_GRABBER, */
12530c0d06caSMauro Carvalho Chehab /* 	.type2			= VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */
12540c0d06caSMauro Carvalho Chehab 	.fops			= &hdpvr_fops,
12550c0d06caSMauro Carvalho Chehab 	.release		= hdpvr_device_release,
12560c0d06caSMauro Carvalho Chehab 	.ioctl_ops 		= &hdpvr_ioctl_ops,
12570c0d06caSMauro Carvalho Chehab 	.tvnorms 		=
12580c0d06caSMauro Carvalho Chehab 		V4L2_STD_NTSC  | V4L2_STD_SECAM | V4L2_STD_PAL_B |
12590c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
12600c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
12610c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_60,
12620c0d06caSMauro Carvalho Chehab 	.current_norm 		= V4L2_STD_NTSC | V4L2_STD_PAL_M |
12630c0d06caSMauro Carvalho Chehab 		V4L2_STD_PAL_60,
12640c0d06caSMauro Carvalho Chehab };
12650c0d06caSMauro Carvalho Chehab 
12660c0d06caSMauro Carvalho Chehab int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
12670c0d06caSMauro Carvalho Chehab 			    int devnum)
12680c0d06caSMauro Carvalho Chehab {
12690c0d06caSMauro Carvalho Chehab 	/* setup and register video device */
12700c0d06caSMauro Carvalho Chehab 	dev->video_dev = video_device_alloc();
12710c0d06caSMauro Carvalho Chehab 	if (!dev->video_dev) {
12720c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
12730c0d06caSMauro Carvalho Chehab 		goto error;
12740c0d06caSMauro Carvalho Chehab 	}
12750c0d06caSMauro Carvalho Chehab 
12760c0d06caSMauro Carvalho Chehab 	*(dev->video_dev) = hdpvr_video_template;
12770c0d06caSMauro Carvalho Chehab 	strcpy(dev->video_dev->name, "Hauppauge HD PVR");
12780c0d06caSMauro Carvalho Chehab 	dev->video_dev->parent = parent;
12790c0d06caSMauro Carvalho Chehab 	video_set_drvdata(dev->video_dev, dev);
12800c0d06caSMauro Carvalho Chehab 
12810c0d06caSMauro Carvalho Chehab 	if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
12820c0d06caSMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
12830c0d06caSMauro Carvalho Chehab 		goto error;
12840c0d06caSMauro Carvalho Chehab 	}
12850c0d06caSMauro Carvalho Chehab 
12860c0d06caSMauro Carvalho Chehab 	return 0;
12870c0d06caSMauro Carvalho Chehab error:
12880c0d06caSMauro Carvalho Chehab 	return -ENOMEM;
12890c0d06caSMauro Carvalho Chehab }
1290