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