1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 20c0d06caSMauro Carvalho Chehab /* 30c0d06caSMauro Carvalho Chehab * Hauppauge HD PVR USB driver - video 4 linux 2 interface 40c0d06caSMauro Carvalho Chehab * 50c0d06caSMauro Carvalho Chehab * Copyright (C) 2008 Janne Grunau (j@jannau.net) 60c0d06caSMauro Carvalho Chehab */ 70c0d06caSMauro Carvalho Chehab 80c0d06caSMauro Carvalho Chehab #include <linux/kernel.h> 90c0d06caSMauro Carvalho Chehab #include <linux/errno.h> 100c0d06caSMauro Carvalho Chehab #include <linux/init.h> 110c0d06caSMauro Carvalho Chehab #include <linux/slab.h> 120c0d06caSMauro Carvalho Chehab #include <linux/module.h> 130c0d06caSMauro Carvalho Chehab #include <linux/uaccess.h> 140c0d06caSMauro Carvalho Chehab #include <linux/usb.h> 150c0d06caSMauro Carvalho Chehab #include <linux/mutex.h> 160c0d06caSMauro Carvalho Chehab #include <linux/workqueue.h> 170c0d06caSMauro Carvalho Chehab 180c0d06caSMauro Carvalho Chehab #include <linux/videodev2.h> 193315c59aSHans Verkuil #include <linux/v4l2-dv-timings.h> 200c0d06caSMauro Carvalho Chehab #include <media/v4l2-dev.h> 210c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h> 2225764158SHans Verkuil #include <media/v4l2-dv-timings.h> 230c0d06caSMauro Carvalho Chehab #include <media/v4l2-ioctl.h> 2465fe42d6SHans Verkuil #include <media/v4l2-event.h> 250c0d06caSMauro Carvalho Chehab #include "hdpvr.h" 260c0d06caSMauro Carvalho Chehab 270c0d06caSMauro Carvalho Chehab #define BULK_URB_TIMEOUT 90 /* 0.09 seconds */ 280c0d06caSMauro Carvalho Chehab 290c0d06caSMauro Carvalho Chehab #define print_buffer_status() { \ 300c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \ 310c0d06caSMauro Carvalho Chehab "%s:%d buffer stat: %d free, %d proc\n", \ 320c0d06caSMauro Carvalho Chehab __func__, __LINE__, \ 330c0d06caSMauro Carvalho Chehab list_size(&dev->free_buff_list), \ 340c0d06caSMauro Carvalho Chehab list_size(&dev->rec_buff_list)); } 350c0d06caSMauro Carvalho Chehab 363315c59aSHans Verkuil static const struct v4l2_dv_timings hdpvr_dv_timings[] = { 373315c59aSHans Verkuil V4L2_DV_BT_CEA_720X480I59_94, 383315c59aSHans Verkuil V4L2_DV_BT_CEA_720X576I50, 393315c59aSHans Verkuil V4L2_DV_BT_CEA_720X480P59_94, 403315c59aSHans Verkuil V4L2_DV_BT_CEA_720X576P50, 413315c59aSHans Verkuil V4L2_DV_BT_CEA_1280X720P50, 423315c59aSHans Verkuil V4L2_DV_BT_CEA_1280X720P60, 433315c59aSHans Verkuil V4L2_DV_BT_CEA_1920X1080I50, 443315c59aSHans Verkuil V4L2_DV_BT_CEA_1920X1080I60, 453315c59aSHans Verkuil }; 463315c59aSHans Verkuil 473315c59aSHans Verkuil /* Use 480i59 as the default timings */ 483315c59aSHans Verkuil #define HDPVR_DEF_DV_TIMINGS_IDX (0) 493315c59aSHans Verkuil 503315c59aSHans Verkuil struct hdpvr_fh { 513315c59aSHans Verkuil struct v4l2_fh fh; 523315c59aSHans Verkuil bool legacy_mode; 533315c59aSHans Verkuil }; 543315c59aSHans Verkuil 550c0d06caSMauro Carvalho Chehab static uint list_size(struct list_head *list) 560c0d06caSMauro Carvalho Chehab { 570c0d06caSMauro Carvalho Chehab struct list_head *tmp; 580c0d06caSMauro Carvalho Chehab uint count = 0; 590c0d06caSMauro Carvalho Chehab 600c0d06caSMauro Carvalho Chehab list_for_each(tmp, list) { 610c0d06caSMauro Carvalho Chehab count++; 620c0d06caSMauro Carvalho Chehab } 630c0d06caSMauro Carvalho Chehab 640c0d06caSMauro Carvalho Chehab return count; 650c0d06caSMauro Carvalho Chehab } 660c0d06caSMauro Carvalho Chehab 670c0d06caSMauro Carvalho Chehab /*=========================================================================*/ 680c0d06caSMauro Carvalho Chehab /* urb callback */ 690c0d06caSMauro Carvalho Chehab static void hdpvr_read_bulk_callback(struct urb *urb) 700c0d06caSMauro Carvalho Chehab { 710c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context; 720c0d06caSMauro Carvalho Chehab struct hdpvr_device *dev = buf->dev; 730c0d06caSMauro Carvalho Chehab 740c0d06caSMauro Carvalho Chehab /* marking buffer as received and wake waiting */ 750c0d06caSMauro Carvalho Chehab buf->status = BUFSTAT_READY; 760c0d06caSMauro Carvalho Chehab wake_up_interruptible(&dev->wait_data); 770c0d06caSMauro Carvalho Chehab } 780c0d06caSMauro Carvalho Chehab 790c0d06caSMauro Carvalho Chehab /*=========================================================================*/ 803445857bSHans Verkuil /* buffer bits */ 810c0d06caSMauro Carvalho Chehab 820c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */ 830c0d06caSMauro Carvalho Chehab int hdpvr_cancel_queue(struct hdpvr_device *dev) 840c0d06caSMauro Carvalho Chehab { 850c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf; 860c0d06caSMauro Carvalho Chehab 870c0d06caSMauro Carvalho Chehab list_for_each_entry(buf, &dev->rec_buff_list, buff_list) { 880c0d06caSMauro Carvalho Chehab usb_kill_urb(buf->urb); 890c0d06caSMauro Carvalho Chehab buf->status = BUFSTAT_AVAILABLE; 900c0d06caSMauro Carvalho Chehab } 910c0d06caSMauro Carvalho Chehab 920c0d06caSMauro Carvalho Chehab list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev); 930c0d06caSMauro Carvalho Chehab 940c0d06caSMauro Carvalho Chehab return 0; 950c0d06caSMauro Carvalho Chehab } 960c0d06caSMauro Carvalho Chehab 970c0d06caSMauro Carvalho Chehab static int hdpvr_free_queue(struct list_head *q) 980c0d06caSMauro Carvalho Chehab { 990c0d06caSMauro Carvalho Chehab struct list_head *tmp; 1000c0d06caSMauro Carvalho Chehab struct list_head *p; 1010c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf; 1020c0d06caSMauro Carvalho Chehab struct urb *urb; 1030c0d06caSMauro Carvalho Chehab 1040c0d06caSMauro Carvalho Chehab for (p = q->next; p != q;) { 1050c0d06caSMauro Carvalho Chehab buf = list_entry(p, struct hdpvr_buffer, buff_list); 1060c0d06caSMauro Carvalho Chehab 1070c0d06caSMauro Carvalho Chehab urb = buf->urb; 1080c0d06caSMauro Carvalho Chehab usb_free_coherent(urb->dev, urb->transfer_buffer_length, 1090c0d06caSMauro Carvalho Chehab urb->transfer_buffer, urb->transfer_dma); 1100c0d06caSMauro Carvalho Chehab usb_free_urb(urb); 1110c0d06caSMauro Carvalho Chehab tmp = p->next; 1120c0d06caSMauro Carvalho Chehab list_del(p); 1130c0d06caSMauro Carvalho Chehab kfree(buf); 1140c0d06caSMauro Carvalho Chehab p = tmp; 1150c0d06caSMauro Carvalho Chehab } 1160c0d06caSMauro Carvalho Chehab 1170c0d06caSMauro Carvalho Chehab return 0; 1180c0d06caSMauro Carvalho Chehab } 1190c0d06caSMauro Carvalho Chehab 1200c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */ 1210c0d06caSMauro Carvalho Chehab int hdpvr_free_buffers(struct hdpvr_device *dev) 1220c0d06caSMauro Carvalho Chehab { 1230c0d06caSMauro Carvalho Chehab hdpvr_cancel_queue(dev); 1240c0d06caSMauro Carvalho Chehab 1250c0d06caSMauro Carvalho Chehab hdpvr_free_queue(&dev->free_buff_list); 1260c0d06caSMauro Carvalho Chehab hdpvr_free_queue(&dev->rec_buff_list); 1270c0d06caSMauro Carvalho Chehab 1280c0d06caSMauro Carvalho Chehab return 0; 1290c0d06caSMauro Carvalho Chehab } 1300c0d06caSMauro Carvalho Chehab 1310c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */ 1320c0d06caSMauro Carvalho Chehab int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count) 1330c0d06caSMauro Carvalho Chehab { 1340c0d06caSMauro Carvalho Chehab uint i; 1350c0d06caSMauro Carvalho Chehab int retval = -ENOMEM; 1360c0d06caSMauro Carvalho Chehab u8 *mem; 1370c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf; 1380c0d06caSMauro Carvalho Chehab struct urb *urb; 1390c0d06caSMauro Carvalho Chehab 1400c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 1410c0d06caSMauro Carvalho Chehab "allocating %u buffers\n", count); 1420c0d06caSMauro Carvalho Chehab 1430c0d06caSMauro Carvalho Chehab for (i = 0; i < count; i++) { 1440c0d06caSMauro Carvalho Chehab 1450c0d06caSMauro Carvalho Chehab buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL); 1460c0d06caSMauro Carvalho Chehab if (!buf) { 1470c0d06caSMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n"); 1480c0d06caSMauro Carvalho Chehab goto exit; 1490c0d06caSMauro Carvalho Chehab } 1500c0d06caSMauro Carvalho Chehab buf->dev = dev; 1510c0d06caSMauro Carvalho Chehab 1520c0d06caSMauro Carvalho Chehab urb = usb_alloc_urb(0, GFP_KERNEL); 15390831662SWolfram Sang if (!urb) 1540c0d06caSMauro Carvalho Chehab goto exit_urb; 1550c0d06caSMauro Carvalho Chehab buf->urb = urb; 1560c0d06caSMauro Carvalho Chehab 1570c0d06caSMauro Carvalho Chehab mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL, 1580c0d06caSMauro Carvalho Chehab &urb->transfer_dma); 1590c0d06caSMauro Carvalho Chehab if (!mem) { 1600c0d06caSMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 1610c0d06caSMauro Carvalho Chehab "cannot allocate usb transfer buffer\n"); 1620c0d06caSMauro Carvalho Chehab goto exit_urb_buffer; 1630c0d06caSMauro Carvalho Chehab } 1640c0d06caSMauro Carvalho Chehab 1650c0d06caSMauro Carvalho Chehab usb_fill_bulk_urb(buf->urb, dev->udev, 1660c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(dev->udev, 1670c0d06caSMauro Carvalho Chehab dev->bulk_in_endpointAddr), 1680c0d06caSMauro Carvalho Chehab mem, dev->bulk_in_size, 1690c0d06caSMauro Carvalho Chehab hdpvr_read_bulk_callback, buf); 1700c0d06caSMauro Carvalho Chehab 1710c0d06caSMauro Carvalho Chehab buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1720c0d06caSMauro Carvalho Chehab buf->status = BUFSTAT_AVAILABLE; 1730c0d06caSMauro Carvalho Chehab list_add_tail(&buf->buff_list, &dev->free_buff_list); 1740c0d06caSMauro Carvalho Chehab } 1750c0d06caSMauro Carvalho Chehab return 0; 1760c0d06caSMauro Carvalho Chehab exit_urb_buffer: 1770c0d06caSMauro Carvalho Chehab usb_free_urb(urb); 1780c0d06caSMauro Carvalho Chehab exit_urb: 1790c0d06caSMauro Carvalho Chehab kfree(buf); 1800c0d06caSMauro Carvalho Chehab exit: 1810c0d06caSMauro Carvalho Chehab hdpvr_free_buffers(dev); 1820c0d06caSMauro Carvalho Chehab return retval; 1830c0d06caSMauro Carvalho Chehab } 1840c0d06caSMauro Carvalho Chehab 1850c0d06caSMauro Carvalho Chehab static int hdpvr_submit_buffers(struct hdpvr_device *dev) 1860c0d06caSMauro Carvalho Chehab { 1870c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf; 1880c0d06caSMauro Carvalho Chehab struct urb *urb; 1890c0d06caSMauro Carvalho Chehab int ret = 0, err_count = 0; 1900c0d06caSMauro Carvalho Chehab 1910c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 1920c0d06caSMauro Carvalho Chehab 1930c0d06caSMauro Carvalho Chehab while (dev->status == STATUS_STREAMING && 1940c0d06caSMauro Carvalho Chehab !list_empty(&dev->free_buff_list)) { 1950c0d06caSMauro Carvalho Chehab 1960c0d06caSMauro Carvalho Chehab buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer, 1970c0d06caSMauro Carvalho Chehab buff_list); 1980c0d06caSMauro Carvalho Chehab if (buf->status != BUFSTAT_AVAILABLE) { 1990c0d06caSMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 2000c0d06caSMauro Carvalho Chehab "buffer not marked as available\n"); 2010c0d06caSMauro Carvalho Chehab ret = -EFAULT; 2020c0d06caSMauro Carvalho Chehab goto err; 2030c0d06caSMauro Carvalho Chehab } 2040c0d06caSMauro Carvalho Chehab 2050c0d06caSMauro Carvalho Chehab urb = buf->urb; 2060c0d06caSMauro Carvalho Chehab urb->status = 0; 2070c0d06caSMauro Carvalho Chehab urb->actual_length = 0; 2080c0d06caSMauro Carvalho Chehab ret = usb_submit_urb(urb, GFP_KERNEL); 2090c0d06caSMauro Carvalho Chehab if (ret) { 2100c0d06caSMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 2110c0d06caSMauro Carvalho Chehab "usb_submit_urb in %s returned %d\n", 2120c0d06caSMauro Carvalho Chehab __func__, ret); 2130c0d06caSMauro Carvalho Chehab if (++err_count > 2) 2140c0d06caSMauro Carvalho Chehab break; 2150c0d06caSMauro Carvalho Chehab continue; 2160c0d06caSMauro Carvalho Chehab } 2170c0d06caSMauro Carvalho Chehab buf->status = BUFSTAT_INPROGRESS; 2180c0d06caSMauro Carvalho Chehab list_move_tail(&buf->buff_list, &dev->rec_buff_list); 2190c0d06caSMauro Carvalho Chehab } 2200c0d06caSMauro Carvalho Chehab err: 2210c0d06caSMauro Carvalho Chehab print_buffer_status(); 2220c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 2230c0d06caSMauro Carvalho Chehab return ret; 2240c0d06caSMauro Carvalho Chehab } 2250c0d06caSMauro Carvalho Chehab 2260c0d06caSMauro Carvalho Chehab static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev) 2270c0d06caSMauro Carvalho Chehab { 2280c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf; 2290c0d06caSMauro Carvalho Chehab 2300c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 2310c0d06caSMauro Carvalho Chehab 2320c0d06caSMauro Carvalho Chehab if (list_empty(&dev->rec_buff_list)) { 2330c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 2340c0d06caSMauro Carvalho Chehab return NULL; 2350c0d06caSMauro Carvalho Chehab } 2360c0d06caSMauro Carvalho Chehab 2370c0d06caSMauro Carvalho Chehab buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer, 2380c0d06caSMauro Carvalho Chehab buff_list); 2390c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 2400c0d06caSMauro Carvalho Chehab 2410c0d06caSMauro Carvalho Chehab return buf; 2420c0d06caSMauro Carvalho Chehab } 2430c0d06caSMauro Carvalho Chehab 2440c0d06caSMauro Carvalho Chehab static void hdpvr_transmit_buffers(struct work_struct *work) 2450c0d06caSMauro Carvalho Chehab { 2460c0d06caSMauro Carvalho Chehab struct hdpvr_device *dev = container_of(work, struct hdpvr_device, 2470c0d06caSMauro Carvalho Chehab worker); 2480c0d06caSMauro Carvalho Chehab 2490c0d06caSMauro Carvalho Chehab while (dev->status == STATUS_STREAMING) { 2500c0d06caSMauro Carvalho Chehab 2510c0d06caSMauro Carvalho Chehab if (hdpvr_submit_buffers(dev)) { 2520c0d06caSMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n"); 2530c0d06caSMauro Carvalho Chehab goto error; 2540c0d06caSMauro Carvalho Chehab } 2550c0d06caSMauro Carvalho Chehab if (wait_event_interruptible(dev->wait_buffer, 2560c0d06caSMauro Carvalho Chehab !list_empty(&dev->free_buff_list) || 2570c0d06caSMauro Carvalho Chehab dev->status != STATUS_STREAMING)) 2580c0d06caSMauro Carvalho Chehab goto error; 2590c0d06caSMauro Carvalho Chehab } 2600c0d06caSMauro Carvalho Chehab 2610c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 2620c0d06caSMauro Carvalho Chehab "transmit worker exited\n"); 2630c0d06caSMauro Carvalho Chehab return; 2640c0d06caSMauro Carvalho Chehab error: 2650c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 2660c0d06caSMauro Carvalho Chehab "transmit buffers errored\n"); 2670c0d06caSMauro Carvalho Chehab dev->status = STATUS_ERROR; 2680c0d06caSMauro Carvalho Chehab } 2690c0d06caSMauro Carvalho Chehab 2700c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */ 2710c0d06caSMauro Carvalho Chehab static int hdpvr_start_streaming(struct hdpvr_device *dev) 2720c0d06caSMauro Carvalho Chehab { 2730c0d06caSMauro Carvalho Chehab int ret; 2744d601c4cSLeonid Kegulskiy struct hdpvr_video_info vidinf; 2750c0d06caSMauro Carvalho Chehab 2760c0d06caSMauro Carvalho Chehab if (dev->status == STATUS_STREAMING) 2770c0d06caSMauro Carvalho Chehab return 0; 27879f10b62SHans Verkuil if (dev->status != STATUS_IDLE) 2790c0d06caSMauro Carvalho Chehab return -EAGAIN; 2800c0d06caSMauro Carvalho Chehab 2814d601c4cSLeonid Kegulskiy ret = get_video_info(dev, &vidinf); 2825f454d82SHans Verkuil if (ret < 0) 2835f454d82SHans Verkuil return ret; 2845f454d82SHans Verkuil 2855f454d82SHans Verkuil if (!vidinf.valid) { 28679f10b62SHans Verkuil msleep(250); 28779f10b62SHans Verkuil v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 28879f10b62SHans Verkuil "no video signal at input %d\n", dev->options.video_input); 28979f10b62SHans Verkuil return -EAGAIN; 29079f10b62SHans Verkuil } 2910c0d06caSMauro Carvalho Chehab 2920c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 2934d601c4cSLeonid Kegulskiy "video signal: %dx%d@%dhz\n", vidinf.width, 2944d601c4cSLeonid Kegulskiy vidinf.height, vidinf.fps); 2950c0d06caSMauro Carvalho Chehab 2960c0d06caSMauro Carvalho Chehab /* start streaming 2 request */ 2970c0d06caSMauro Carvalho Chehab ret = usb_control_msg(dev->udev, 2980c0d06caSMauro Carvalho Chehab usb_sndctrlpipe(dev->udev, 0), 2990c0d06caSMauro Carvalho Chehab 0xb8, 0x38, 0x1, 0, NULL, 0, 8000); 3000c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3010c0d06caSMauro Carvalho Chehab "encoder start control request returned %d\n", ret); 302f7436876SLeonid Kegulskiy if (ret < 0) 303f7436876SLeonid Kegulskiy return ret; 3040c0d06caSMauro Carvalho Chehab 305f7436876SLeonid Kegulskiy ret = hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00); 306f7436876SLeonid Kegulskiy if (ret) 307f7436876SLeonid Kegulskiy return ret; 3080c0d06caSMauro Carvalho Chehab 3090c0d06caSMauro Carvalho Chehab dev->status = STATUS_STREAMING; 3100c0d06caSMauro Carvalho Chehab 3110c0d06caSMauro Carvalho Chehab INIT_WORK(&dev->worker, hdpvr_transmit_buffers); 3125612e191SBhaktipriya Shridhar schedule_work(&dev->worker); 3130c0d06caSMauro Carvalho Chehab 3140c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3150c0d06caSMauro Carvalho Chehab "streaming started\n"); 3160c0d06caSMauro Carvalho Chehab 3170c0d06caSMauro Carvalho Chehab return 0; 3180c0d06caSMauro Carvalho Chehab } 3190c0d06caSMauro Carvalho Chehab 3200c0d06caSMauro Carvalho Chehab 3210c0d06caSMauro Carvalho Chehab /* function expects dev->io_mutex to be hold by caller */ 3220c0d06caSMauro Carvalho Chehab static int hdpvr_stop_streaming(struct hdpvr_device *dev) 3230c0d06caSMauro Carvalho Chehab { 3240c0d06caSMauro Carvalho Chehab int actual_length; 3250c0d06caSMauro Carvalho Chehab uint c = 0; 3260c0d06caSMauro Carvalho Chehab u8 *buf; 3270c0d06caSMauro Carvalho Chehab 3280c0d06caSMauro Carvalho Chehab if (dev->status == STATUS_IDLE) 3290c0d06caSMauro Carvalho Chehab return 0; 3300c0d06caSMauro Carvalho Chehab else if (dev->status != STATUS_STREAMING) 3310c0d06caSMauro Carvalho Chehab return -EAGAIN; 3320c0d06caSMauro Carvalho Chehab 3330c0d06caSMauro Carvalho Chehab buf = kmalloc(dev->bulk_in_size, GFP_KERNEL); 3340c0d06caSMauro Carvalho Chehab if (!buf) 3354d5ded75SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer for emptying the internal device buffer. Next capture start will be slow\n"); 3360c0d06caSMauro Carvalho Chehab 3370c0d06caSMauro Carvalho Chehab dev->status = STATUS_SHUTTING_DOWN; 3380c0d06caSMauro Carvalho Chehab hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00); 3390c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 3400c0d06caSMauro Carvalho Chehab 3410c0d06caSMauro Carvalho Chehab wake_up_interruptible(&dev->wait_buffer); 3420c0d06caSMauro Carvalho Chehab msleep(50); 3430c0d06caSMauro Carvalho Chehab 3445612e191SBhaktipriya Shridhar flush_work(&dev->worker); 3450c0d06caSMauro Carvalho Chehab 3460c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 3470c0d06caSMauro Carvalho Chehab /* kill the still outstanding urbs */ 3480c0d06caSMauro Carvalho Chehab hdpvr_cancel_queue(dev); 3490c0d06caSMauro Carvalho Chehab 3500c0d06caSMauro Carvalho Chehab /* emptying the device buffer beforeshutting it down */ 3510c0d06caSMauro Carvalho Chehab while (buf && ++c < 500 && 3520c0d06caSMauro Carvalho Chehab !usb_bulk_msg(dev->udev, 3530c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(dev->udev, 3540c0d06caSMauro Carvalho Chehab dev->bulk_in_endpointAddr), 3550c0d06caSMauro Carvalho Chehab buf, dev->bulk_in_size, &actual_length, 3560c0d06caSMauro Carvalho Chehab BULK_URB_TIMEOUT)) { 3570c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3580c0d06caSMauro Carvalho Chehab "%2d: got %d bytes\n", c, actual_length); 3590c0d06caSMauro Carvalho Chehab } 3600c0d06caSMauro Carvalho Chehab kfree(buf); 3610c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3620c0d06caSMauro Carvalho Chehab "used %d urbs to empty device buffers\n", c-1); 3630c0d06caSMauro Carvalho Chehab msleep(10); 3640c0d06caSMauro Carvalho Chehab 3650c0d06caSMauro Carvalho Chehab dev->status = STATUS_IDLE; 3660c0d06caSMauro Carvalho Chehab 3670c0d06caSMauro Carvalho Chehab return 0; 3680c0d06caSMauro Carvalho Chehab } 3690c0d06caSMauro Carvalho Chehab 3700c0d06caSMauro Carvalho Chehab 3710c0d06caSMauro Carvalho Chehab /*=======================================================================*/ 3720c0d06caSMauro Carvalho Chehab /* 3730c0d06caSMauro Carvalho Chehab * video 4 linux 2 file operations 3740c0d06caSMauro Carvalho Chehab */ 3750c0d06caSMauro Carvalho Chehab 3763315c59aSHans Verkuil static int hdpvr_open(struct file *file) 3773315c59aSHans Verkuil { 3783315c59aSHans Verkuil struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); 3793315c59aSHans Verkuil 3803315c59aSHans Verkuil if (fh == NULL) 3813315c59aSHans Verkuil return -ENOMEM; 3823315c59aSHans Verkuil fh->legacy_mode = true; 3833315c59aSHans Verkuil v4l2_fh_init(&fh->fh, video_devdata(file)); 3843315c59aSHans Verkuil v4l2_fh_add(&fh->fh); 3853315c59aSHans Verkuil file->private_data = fh; 3863315c59aSHans Verkuil return 0; 3873315c59aSHans Verkuil } 3883315c59aSHans Verkuil 3890c0d06caSMauro Carvalho Chehab static int hdpvr_release(struct file *file) 3900c0d06caSMauro Carvalho Chehab { 391ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 3920c0d06caSMauro Carvalho Chehab 3930c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 394ede197aaSHans Verkuil if (file->private_data == dev->owner) { 3950c0d06caSMauro Carvalho Chehab hdpvr_stop_streaming(dev); 396ede197aaSHans Verkuil dev->owner = NULL; 397ede197aaSHans Verkuil } 3980c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 3990c0d06caSMauro Carvalho Chehab 400ede197aaSHans Verkuil return v4l2_fh_release(file); 4010c0d06caSMauro Carvalho Chehab } 4020c0d06caSMauro Carvalho Chehab 4030c0d06caSMauro Carvalho Chehab /* 4040c0d06caSMauro Carvalho Chehab * hdpvr_v4l2_read() 4050c0d06caSMauro Carvalho Chehab * will allocate buffers when called for the first time 4060c0d06caSMauro Carvalho Chehab */ 4070c0d06caSMauro Carvalho Chehab static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, 4080c0d06caSMauro Carvalho Chehab loff_t *pos) 4090c0d06caSMauro Carvalho Chehab { 410ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 4110c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf = NULL; 4120c0d06caSMauro Carvalho Chehab struct urb *urb; 4130c0d06caSMauro Carvalho Chehab unsigned int ret = 0; 4140c0d06caSMauro Carvalho Chehab int rem, cnt; 4150c0d06caSMauro Carvalho Chehab 4160c0d06caSMauro Carvalho Chehab if (*pos) 4170c0d06caSMauro Carvalho Chehab return -ESPIPE; 4180c0d06caSMauro Carvalho Chehab 4190c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 4200c0d06caSMauro Carvalho Chehab if (dev->status == STATUS_IDLE) { 4210c0d06caSMauro Carvalho Chehab if (hdpvr_start_streaming(dev)) { 4220c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 4230c0d06caSMauro Carvalho Chehab "start_streaming failed\n"); 4240c0d06caSMauro Carvalho Chehab ret = -EIO; 4250c0d06caSMauro Carvalho Chehab msleep(200); 4260c0d06caSMauro Carvalho Chehab dev->status = STATUS_IDLE; 4270c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 4280c0d06caSMauro Carvalho Chehab goto err; 4290c0d06caSMauro Carvalho Chehab } 430ede197aaSHans Verkuil dev->owner = file->private_data; 4310c0d06caSMauro Carvalho Chehab print_buffer_status(); 4320c0d06caSMauro Carvalho Chehab } 4330c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 4340c0d06caSMauro Carvalho Chehab 4350c0d06caSMauro Carvalho Chehab /* wait for the first buffer */ 4360c0d06caSMauro Carvalho Chehab if (!(file->f_flags & O_NONBLOCK)) { 4370c0d06caSMauro Carvalho Chehab if (wait_event_interruptible(dev->wait_data, 4386bc5a4a1SHans Verkuil !list_empty_careful(&dev->rec_buff_list))) 4390c0d06caSMauro Carvalho Chehab return -ERESTARTSYS; 4400c0d06caSMauro Carvalho Chehab } 4410c0d06caSMauro Carvalho Chehab 4420c0d06caSMauro Carvalho Chehab buf = hdpvr_get_next_buffer(dev); 4430c0d06caSMauro Carvalho Chehab 4440c0d06caSMauro Carvalho Chehab while (count > 0 && buf) { 4450c0d06caSMauro Carvalho Chehab 4460c0d06caSMauro Carvalho Chehab if (buf->status != BUFSTAT_READY && 4470c0d06caSMauro Carvalho Chehab dev->status != STATUS_DISCONNECTED) { 448a503ff81SJonathan Sims int err; 4490c0d06caSMauro Carvalho Chehab /* return nonblocking */ 4500c0d06caSMauro Carvalho Chehab if (file->f_flags & O_NONBLOCK) { 4510c0d06caSMauro Carvalho Chehab if (!ret) 4520c0d06caSMauro Carvalho Chehab ret = -EAGAIN; 4530c0d06caSMauro Carvalho Chehab goto err; 4540c0d06caSMauro Carvalho Chehab } 4550c0d06caSMauro Carvalho Chehab 456a503ff81SJonathan Sims err = wait_event_interruptible_timeout(dev->wait_data, 457a503ff81SJonathan Sims buf->status == BUFSTAT_READY, 458a503ff81SJonathan Sims msecs_to_jiffies(1000)); 459a503ff81SJonathan Sims if (err < 0) { 460a503ff81SJonathan Sims ret = err; 461a503ff81SJonathan Sims goto err; 462a503ff81SJonathan Sims } 463a503ff81SJonathan Sims if (!err) { 4646bc5a4a1SHans Verkuil v4l2_info(&dev->v4l2_dev, 465a503ff81SJonathan Sims "timeout: restart streaming\n"); 4666bc5a4a1SHans Verkuil mutex_lock(&dev->io_mutex); 467a503ff81SJonathan Sims hdpvr_stop_streaming(dev); 4686bc5a4a1SHans Verkuil mutex_unlock(&dev->io_mutex); 4696bc5a4a1SHans Verkuil /* 4706bc5a4a1SHans Verkuil * The FW needs about 4 seconds after streaming 4716bc5a4a1SHans Verkuil * stopped before it is ready to restart 4726bc5a4a1SHans Verkuil * streaming. 4736bc5a4a1SHans Verkuil */ 4746bc5a4a1SHans Verkuil msleep(4000); 475a503ff81SJonathan Sims err = hdpvr_start_streaming(dev); 476a503ff81SJonathan Sims if (err) { 477a503ff81SJonathan Sims ret = err; 478a503ff81SJonathan Sims goto err; 479a503ff81SJonathan Sims } 480a503ff81SJonathan Sims } 4810c0d06caSMauro Carvalho Chehab } 4820c0d06caSMauro Carvalho Chehab 4830c0d06caSMauro Carvalho Chehab if (buf->status != BUFSTAT_READY) 4840c0d06caSMauro Carvalho Chehab break; 4850c0d06caSMauro Carvalho Chehab 4860c0d06caSMauro Carvalho Chehab /* set remaining bytes to copy */ 4870c0d06caSMauro Carvalho Chehab urb = buf->urb; 4880c0d06caSMauro Carvalho Chehab rem = urb->actual_length - buf->pos; 4890c0d06caSMauro Carvalho Chehab cnt = rem > count ? count : rem; 4900c0d06caSMauro Carvalho Chehab 4910c0d06caSMauro Carvalho Chehab if (copy_to_user(buffer, urb->transfer_buffer + buf->pos, 4920c0d06caSMauro Carvalho Chehab cnt)) { 4930c0d06caSMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n"); 4940c0d06caSMauro Carvalho Chehab if (!ret) 4950c0d06caSMauro Carvalho Chehab ret = -EFAULT; 4960c0d06caSMauro Carvalho Chehab goto err; 4970c0d06caSMauro Carvalho Chehab } 4980c0d06caSMauro Carvalho Chehab 4990c0d06caSMauro Carvalho Chehab buf->pos += cnt; 5000c0d06caSMauro Carvalho Chehab count -= cnt; 5010c0d06caSMauro Carvalho Chehab buffer += cnt; 5020c0d06caSMauro Carvalho Chehab ret += cnt; 5030c0d06caSMauro Carvalho Chehab 5040c0d06caSMauro Carvalho Chehab /* finished, take next buffer */ 5050c0d06caSMauro Carvalho Chehab if (buf->pos == urb->actual_length) { 5060c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 5070c0d06caSMauro Carvalho Chehab buf->pos = 0; 5080c0d06caSMauro Carvalho Chehab buf->status = BUFSTAT_AVAILABLE; 5090c0d06caSMauro Carvalho Chehab 5100c0d06caSMauro Carvalho Chehab list_move_tail(&buf->buff_list, &dev->free_buff_list); 5110c0d06caSMauro Carvalho Chehab 5120c0d06caSMauro Carvalho Chehab print_buffer_status(); 5130c0d06caSMauro Carvalho Chehab 5140c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 5150c0d06caSMauro Carvalho Chehab 5160c0d06caSMauro Carvalho Chehab wake_up_interruptible(&dev->wait_buffer); 5170c0d06caSMauro Carvalho Chehab 5180c0d06caSMauro Carvalho Chehab buf = hdpvr_get_next_buffer(dev); 5190c0d06caSMauro Carvalho Chehab } 5200c0d06caSMauro Carvalho Chehab } 5210c0d06caSMauro Carvalho Chehab err: 5220c0d06caSMauro Carvalho Chehab if (!ret && !buf) 5230c0d06caSMauro Carvalho Chehab ret = -EAGAIN; 5240c0d06caSMauro Carvalho Chehab return ret; 5250c0d06caSMauro Carvalho Chehab } 5260c0d06caSMauro Carvalho Chehab 527c23e0cb8SAl Viro static __poll_t hdpvr_poll(struct file *filp, poll_table *wait) 5280c0d06caSMauro Carvalho Chehab { 52901699437SAl Viro __poll_t req_events = poll_requested_events(wait); 5300c0d06caSMauro Carvalho Chehab struct hdpvr_buffer *buf = NULL; 531ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(filp); 532c23e0cb8SAl Viro __poll_t mask = v4l2_ctrl_poll(filp, wait); 53365fe42d6SHans Verkuil 534a9a08845SLinus Torvalds if (!(req_events & (EPOLLIN | EPOLLRDNORM))) 53565fe42d6SHans Verkuil return mask; 5360c0d06caSMauro Carvalho Chehab 5370c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 5380c0d06caSMauro Carvalho Chehab 5390c0d06caSMauro Carvalho Chehab if (dev->status == STATUS_IDLE) { 5400c0d06caSMauro Carvalho Chehab if (hdpvr_start_streaming(dev)) { 5410c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 5420c0d06caSMauro Carvalho Chehab "start_streaming failed\n"); 5430c0d06caSMauro Carvalho Chehab dev->status = STATUS_IDLE; 544ede197aaSHans Verkuil } else { 545ede197aaSHans Verkuil dev->owner = filp->private_data; 5460c0d06caSMauro Carvalho Chehab } 5470c0d06caSMauro Carvalho Chehab 5480c0d06caSMauro Carvalho Chehab print_buffer_status(); 5490c0d06caSMauro Carvalho Chehab } 5500c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 5510c0d06caSMauro Carvalho Chehab 5520c0d06caSMauro Carvalho Chehab buf = hdpvr_get_next_buffer(dev); 5530c0d06caSMauro Carvalho Chehab /* only wait if no data is available */ 5540c0d06caSMauro Carvalho Chehab if (!buf || buf->status != BUFSTAT_READY) { 5550c0d06caSMauro Carvalho Chehab poll_wait(filp, &dev->wait_data, wait); 5560c0d06caSMauro Carvalho Chehab buf = hdpvr_get_next_buffer(dev); 5570c0d06caSMauro Carvalho Chehab } 5580c0d06caSMauro Carvalho Chehab if (buf && buf->status == BUFSTAT_READY) 559a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 5600c0d06caSMauro Carvalho Chehab 5610c0d06caSMauro Carvalho Chehab return mask; 5620c0d06caSMauro Carvalho Chehab } 5630c0d06caSMauro Carvalho Chehab 5640c0d06caSMauro Carvalho Chehab 5650c0d06caSMauro Carvalho Chehab static const struct v4l2_file_operations hdpvr_fops = { 5660c0d06caSMauro Carvalho Chehab .owner = THIS_MODULE, 5673315c59aSHans Verkuil .open = hdpvr_open, 5680c0d06caSMauro Carvalho Chehab .release = hdpvr_release, 5690c0d06caSMauro Carvalho Chehab .read = hdpvr_read, 5700c0d06caSMauro Carvalho Chehab .poll = hdpvr_poll, 5710c0d06caSMauro Carvalho Chehab .unlocked_ioctl = video_ioctl2, 5720c0d06caSMauro Carvalho Chehab }; 5730c0d06caSMauro Carvalho Chehab 5740c0d06caSMauro Carvalho Chehab /*=======================================================================*/ 5750c0d06caSMauro Carvalho Chehab /* 5760c0d06caSMauro Carvalho Chehab * V4L2 ioctl handling 5770c0d06caSMauro Carvalho Chehab */ 5780c0d06caSMauro Carvalho Chehab 5790c0d06caSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void *priv, 5800c0d06caSMauro Carvalho Chehab struct v4l2_capability *cap) 5810c0d06caSMauro Carvalho Chehab { 5820c0d06caSMauro Carvalho Chehab struct hdpvr_device *dev = video_drvdata(file); 5830c0d06caSMauro Carvalho Chehab 584cc1e6315SMauro Carvalho Chehab strscpy(cap->driver, "hdpvr", sizeof(cap->driver)); 585cc1e6315SMauro Carvalho Chehab strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card)); 5860c0d06caSMauro Carvalho Chehab usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); 5870c0d06caSMauro Carvalho Chehab return 0; 5880c0d06caSMauro Carvalho Chehab } 5890c0d06caSMauro Carvalho Chehab 5905854bf88SHans Verkuil static int vidioc_s_std(struct file *file, void *_fh, 591314527acSHans Verkuil v4l2_std_id std) 5920c0d06caSMauro Carvalho Chehab { 593ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 5945854bf88SHans Verkuil struct hdpvr_fh *fh = _fh; 5950c0d06caSMauro Carvalho Chehab u8 std_type = 1; 5960c0d06caSMauro Carvalho Chehab 5975854bf88SHans Verkuil if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) 5988f69da95SHans Verkuil return -ENODATA; 5998f69da95SHans Verkuil if (dev->status != STATUS_IDLE) 6008f69da95SHans Verkuil return -EBUSY; 6018f69da95SHans Verkuil if (std & V4L2_STD_525_60) 6020c0d06caSMauro Carvalho Chehab std_type = 0; 6038f69da95SHans Verkuil dev->cur_std = std; 6048f69da95SHans Verkuil dev->width = 720; 6058f69da95SHans Verkuil dev->height = std_type ? 576 : 480; 6060c0d06caSMauro Carvalho Chehab 6070c0d06caSMauro Carvalho Chehab return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); 6080c0d06caSMauro Carvalho Chehab } 6090c0d06caSMauro Carvalho Chehab 6105854bf88SHans Verkuil static int vidioc_g_std(struct file *file, void *_fh, 6118f69da95SHans Verkuil v4l2_std_id *std) 6128f69da95SHans Verkuil { 6138f69da95SHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 6145854bf88SHans Verkuil struct hdpvr_fh *fh = _fh; 6158f69da95SHans Verkuil 6165854bf88SHans Verkuil if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) 6178f69da95SHans Verkuil return -ENODATA; 6188f69da95SHans Verkuil *std = dev->cur_std; 6198f69da95SHans Verkuil return 0; 6208f69da95SHans Verkuil } 6218f69da95SHans Verkuil 6225854bf88SHans Verkuil static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) 6238f69da95SHans Verkuil { 6248f69da95SHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 6254d601c4cSLeonid Kegulskiy struct hdpvr_video_info vid_info; 6265854bf88SHans Verkuil struct hdpvr_fh *fh = _fh; 6274d601c4cSLeonid Kegulskiy int ret; 6288f69da95SHans Verkuil 629ab6e134aSHans Verkuil *a = V4L2_STD_UNKNOWN; 6305854bf88SHans Verkuil if (dev->options.video_input == HDPVR_COMPONENT) 6315854bf88SHans Verkuil return fh->legacy_mode ? 0 : -ENODATA; 6324d601c4cSLeonid Kegulskiy ret = get_video_info(dev, &vid_info); 6335f454d82SHans Verkuil if (vid_info.valid && vid_info.width == 720 && 6344d601c4cSLeonid Kegulskiy (vid_info.height == 480 || vid_info.height == 576)) { 6354d601c4cSLeonid Kegulskiy *a = (vid_info.height == 480) ? 6368f69da95SHans Verkuil V4L2_STD_525_60 : V4L2_STD_625_50; 6378f69da95SHans Verkuil } 6385f454d82SHans Verkuil return ret; 6398f69da95SHans Verkuil } 6408f69da95SHans Verkuil 6413315c59aSHans Verkuil static int vidioc_s_dv_timings(struct file *file, void *_fh, 6423315c59aSHans Verkuil struct v4l2_dv_timings *timings) 6433315c59aSHans Verkuil { 6443315c59aSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 6453315c59aSHans Verkuil struct hdpvr_fh *fh = _fh; 6463315c59aSHans Verkuil int i; 6473315c59aSHans Verkuil 6483315c59aSHans Verkuil fh->legacy_mode = false; 6493315c59aSHans Verkuil if (dev->options.video_input) 6503315c59aSHans Verkuil return -ENODATA; 6513315c59aSHans Verkuil if (dev->status != STATUS_IDLE) 6523315c59aSHans Verkuil return -EBUSY; 6533315c59aSHans Verkuil for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) 65485f9e06cSHans Verkuil if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false)) 6553315c59aSHans Verkuil break; 6563315c59aSHans Verkuil if (i == ARRAY_SIZE(hdpvr_dv_timings)) 6573315c59aSHans Verkuil return -EINVAL; 6583315c59aSHans Verkuil dev->cur_dv_timings = hdpvr_dv_timings[i]; 6593315c59aSHans Verkuil dev->width = hdpvr_dv_timings[i].bt.width; 6603315c59aSHans Verkuil dev->height = hdpvr_dv_timings[i].bt.height; 6613315c59aSHans Verkuil return 0; 6623315c59aSHans Verkuil } 6633315c59aSHans Verkuil 6643315c59aSHans Verkuil static int vidioc_g_dv_timings(struct file *file, void *_fh, 6653315c59aSHans Verkuil struct v4l2_dv_timings *timings) 6663315c59aSHans Verkuil { 6673315c59aSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 6683315c59aSHans Verkuil struct hdpvr_fh *fh = _fh; 6693315c59aSHans Verkuil 6703315c59aSHans Verkuil fh->legacy_mode = false; 6713315c59aSHans Verkuil if (dev->options.video_input) 6723315c59aSHans Verkuil return -ENODATA; 6733315c59aSHans Verkuil *timings = dev->cur_dv_timings; 6743315c59aSHans Verkuil return 0; 6753315c59aSHans Verkuil } 6763315c59aSHans Verkuil 6773315c59aSHans Verkuil static int vidioc_query_dv_timings(struct file *file, void *_fh, 6783315c59aSHans Verkuil struct v4l2_dv_timings *timings) 6793315c59aSHans Verkuil { 6803315c59aSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 6813315c59aSHans Verkuil struct hdpvr_fh *fh = _fh; 6824d601c4cSLeonid Kegulskiy struct hdpvr_video_info vid_info; 6833315c59aSHans Verkuil bool interlaced; 6843315c59aSHans Verkuil int ret = 0; 6853315c59aSHans Verkuil int i; 6863315c59aSHans Verkuil 6873315c59aSHans Verkuil fh->legacy_mode = false; 6883315c59aSHans Verkuil if (dev->options.video_input) 6893315c59aSHans Verkuil return -ENODATA; 6904d601c4cSLeonid Kegulskiy ret = get_video_info(dev, &vid_info); 6914d601c4cSLeonid Kegulskiy if (ret) 6925f454d82SHans Verkuil return ret; 6935f454d82SHans Verkuil if (!vid_info.valid) 6943315c59aSHans Verkuil return -ENOLCK; 6954d601c4cSLeonid Kegulskiy interlaced = vid_info.fps <= 30; 6963315c59aSHans Verkuil for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) { 6973315c59aSHans Verkuil const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt; 6983315c59aSHans Verkuil unsigned hsize; 6993315c59aSHans Verkuil unsigned vsize; 7003315c59aSHans Verkuil unsigned fps; 7013315c59aSHans Verkuil 702eacf8f9aSHans Verkuil hsize = V4L2_DV_BT_FRAME_WIDTH(bt); 703eacf8f9aSHans Verkuil vsize = V4L2_DV_BT_FRAME_HEIGHT(bt); 7043315c59aSHans Verkuil fps = (unsigned)bt->pixelclock / (hsize * vsize); 7054d601c4cSLeonid Kegulskiy if (bt->width != vid_info.width || 7064d601c4cSLeonid Kegulskiy bt->height != vid_info.height || 7073315c59aSHans Verkuil bt->interlaced != interlaced || 7084d601c4cSLeonid Kegulskiy (fps != vid_info.fps && fps + 1 != vid_info.fps)) 7093315c59aSHans Verkuil continue; 7103315c59aSHans Verkuil *timings = hdpvr_dv_timings[i]; 7113315c59aSHans Verkuil break; 7123315c59aSHans Verkuil } 7133315c59aSHans Verkuil if (i == ARRAY_SIZE(hdpvr_dv_timings)) 7143315c59aSHans Verkuil ret = -ERANGE; 7154d601c4cSLeonid Kegulskiy 7163315c59aSHans Verkuil return ret; 7173315c59aSHans Verkuil } 7183315c59aSHans Verkuil 7193315c59aSHans Verkuil static int vidioc_enum_dv_timings(struct file *file, void *_fh, 7203315c59aSHans Verkuil struct v4l2_enum_dv_timings *timings) 7213315c59aSHans Verkuil { 7223315c59aSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 7233315c59aSHans Verkuil struct hdpvr_fh *fh = _fh; 7243315c59aSHans Verkuil 7253315c59aSHans Verkuil fh->legacy_mode = false; 7263315c59aSHans Verkuil memset(timings->reserved, 0, sizeof(timings->reserved)); 7273315c59aSHans Verkuil if (dev->options.video_input) 7283315c59aSHans Verkuil return -ENODATA; 7293315c59aSHans Verkuil if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings)) 7303315c59aSHans Verkuil return -EINVAL; 7313315c59aSHans Verkuil timings->timings = hdpvr_dv_timings[timings->index]; 7323315c59aSHans Verkuil return 0; 7333315c59aSHans Verkuil } 7343315c59aSHans Verkuil 7353315c59aSHans Verkuil static int vidioc_dv_timings_cap(struct file *file, void *_fh, 7363315c59aSHans Verkuil struct v4l2_dv_timings_cap *cap) 7373315c59aSHans Verkuil { 7383315c59aSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 7393315c59aSHans Verkuil struct hdpvr_fh *fh = _fh; 7403315c59aSHans Verkuil 7413315c59aSHans Verkuil fh->legacy_mode = false; 7423315c59aSHans Verkuil if (dev->options.video_input) 7433315c59aSHans Verkuil return -ENODATA; 7443315c59aSHans Verkuil cap->type = V4L2_DV_BT_656_1120; 7453315c59aSHans Verkuil cap->bt.min_width = 720; 7463315c59aSHans Verkuil cap->bt.max_width = 1920; 7473315c59aSHans Verkuil cap->bt.min_height = 480; 7483315c59aSHans Verkuil cap->bt.max_height = 1080; 7493315c59aSHans Verkuil cap->bt.min_pixelclock = 27000000; 7503315c59aSHans Verkuil cap->bt.max_pixelclock = 74250000; 7513315c59aSHans Verkuil cap->bt.standards = V4L2_DV_BT_STD_CEA861; 7523315c59aSHans Verkuil cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE; 7533315c59aSHans Verkuil return 0; 7543315c59aSHans Verkuil } 7553315c59aSHans Verkuil 7560c0d06caSMauro Carvalho Chehab static const char *iname[] = { 7570c0d06caSMauro Carvalho Chehab [HDPVR_COMPONENT] = "Component", 7580c0d06caSMauro Carvalho Chehab [HDPVR_SVIDEO] = "S-Video", 7590c0d06caSMauro Carvalho Chehab [HDPVR_COMPOSITE] = "Composite", 7600c0d06caSMauro Carvalho Chehab }; 7610c0d06caSMauro Carvalho Chehab 7625854bf88SHans Verkuil static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) 7630c0d06caSMauro Carvalho Chehab { 7640c0d06caSMauro Carvalho Chehab unsigned int n; 7650c0d06caSMauro Carvalho Chehab 7660c0d06caSMauro Carvalho Chehab n = i->index; 7670c0d06caSMauro Carvalho Chehab if (n >= HDPVR_VIDEO_INPUTS) 7680c0d06caSMauro Carvalho Chehab return -EINVAL; 7690c0d06caSMauro Carvalho Chehab 7700c0d06caSMauro Carvalho Chehab i->type = V4L2_INPUT_TYPE_CAMERA; 7710c0d06caSMauro Carvalho Chehab 77285709cbfSMauro Carvalho Chehab strscpy(i->name, iname[n], sizeof(i->name)); 7730c0d06caSMauro Carvalho Chehab 7740c0d06caSMauro Carvalho Chehab i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF; 7750c0d06caSMauro Carvalho Chehab 7768f69da95SHans Verkuil i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS; 7778f69da95SHans Verkuil i->std = n ? V4L2_STD_ALL : 0; 7780c0d06caSMauro Carvalho Chehab 7790c0d06caSMauro Carvalho Chehab return 0; 7800c0d06caSMauro Carvalho Chehab } 7810c0d06caSMauro Carvalho Chehab 7825854bf88SHans Verkuil static int vidioc_s_input(struct file *file, void *_fh, 7830c0d06caSMauro Carvalho Chehab unsigned int index) 7840c0d06caSMauro Carvalho Chehab { 785ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 7860c0d06caSMauro Carvalho Chehab int retval; 7870c0d06caSMauro Carvalho Chehab 7880c0d06caSMauro Carvalho Chehab if (index >= HDPVR_VIDEO_INPUTS) 7890c0d06caSMauro Carvalho Chehab return -EINVAL; 7900c0d06caSMauro Carvalho Chehab 7910c0d06caSMauro Carvalho Chehab if (dev->status != STATUS_IDLE) 79297caa318SHans Verkuil return -EBUSY; 7930c0d06caSMauro Carvalho Chehab 7940c0d06caSMauro Carvalho Chehab retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); 7958f69da95SHans Verkuil if (!retval) { 7960c0d06caSMauro Carvalho Chehab dev->options.video_input = index; 7975854bf88SHans Verkuil /* 7985854bf88SHans Verkuil * Unfortunately gstreamer calls ENUMSTD and bails out if it 7995854bf88SHans Verkuil * won't find any formats, even though component input is 8005854bf88SHans Verkuil * selected. This means that we have to leave tvnorms at 8015854bf88SHans Verkuil * V4L2_STD_ALL. We cannot use the 'legacy' trick since 8025854bf88SHans Verkuil * tvnorms is set at the device node level and not at the 8035854bf88SHans Verkuil * filehandle level. 8045854bf88SHans Verkuil * 8055854bf88SHans Verkuil * Comment this out for now, but if the legacy mode can be 8065854bf88SHans Verkuil * removed in the future, then this code should be enabled 8075854bf88SHans Verkuil * again. 8084b30409bSHans Verkuil dev->video_dev.tvnorms = 8095854bf88SHans Verkuil (index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0; 8105854bf88SHans Verkuil */ 8118f69da95SHans Verkuil } 8120c0d06caSMauro Carvalho Chehab 8130c0d06caSMauro Carvalho Chehab return retval; 8140c0d06caSMauro Carvalho Chehab } 8150c0d06caSMauro Carvalho Chehab 8160c0d06caSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *private_data, 8170c0d06caSMauro Carvalho Chehab unsigned int *index) 8180c0d06caSMauro Carvalho Chehab { 819ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 8200c0d06caSMauro Carvalho Chehab 8210c0d06caSMauro Carvalho Chehab *index = dev->options.video_input; 8220c0d06caSMauro Carvalho Chehab return 0; 8230c0d06caSMauro Carvalho Chehab } 8240c0d06caSMauro Carvalho Chehab 8250c0d06caSMauro Carvalho Chehab 8260c0d06caSMauro Carvalho Chehab static const char *audio_iname[] = { 8270c0d06caSMauro Carvalho Chehab [HDPVR_RCA_FRONT] = "RCA front", 8280c0d06caSMauro Carvalho Chehab [HDPVR_RCA_BACK] = "RCA back", 8290c0d06caSMauro Carvalho Chehab [HDPVR_SPDIF] = "SPDIF", 8300c0d06caSMauro Carvalho Chehab }; 8310c0d06caSMauro Carvalho Chehab 8320c0d06caSMauro Carvalho Chehab static int vidioc_enumaudio(struct file *file, void *priv, 8330c0d06caSMauro Carvalho Chehab struct v4l2_audio *audio) 8340c0d06caSMauro Carvalho Chehab { 8350c0d06caSMauro Carvalho Chehab unsigned int n; 8360c0d06caSMauro Carvalho Chehab 8370c0d06caSMauro Carvalho Chehab n = audio->index; 8380c0d06caSMauro Carvalho Chehab if (n >= HDPVR_AUDIO_INPUTS) 8390c0d06caSMauro Carvalho Chehab return -EINVAL; 8400c0d06caSMauro Carvalho Chehab 8410c0d06caSMauro Carvalho Chehab audio->capability = V4L2_AUDCAP_STEREO; 8420c0d06caSMauro Carvalho Chehab 84385709cbfSMauro Carvalho Chehab strscpy(audio->name, audio_iname[n], sizeof(audio->name)); 8440c0d06caSMauro Carvalho Chehab 8450c0d06caSMauro Carvalho Chehab return 0; 8460c0d06caSMauro Carvalho Chehab } 8470c0d06caSMauro Carvalho Chehab 8480c0d06caSMauro Carvalho Chehab static int vidioc_s_audio(struct file *file, void *private_data, 8490e8025b9SHans Verkuil const struct v4l2_audio *audio) 8500c0d06caSMauro Carvalho Chehab { 851ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 8520c0d06caSMauro Carvalho Chehab int retval; 8530c0d06caSMauro Carvalho Chehab 8540c0d06caSMauro Carvalho Chehab if (audio->index >= HDPVR_AUDIO_INPUTS) 8550c0d06caSMauro Carvalho Chehab return -EINVAL; 8560c0d06caSMauro Carvalho Chehab 8570c0d06caSMauro Carvalho Chehab if (dev->status != STATUS_IDLE) 85897caa318SHans Verkuil return -EBUSY; 8590c0d06caSMauro Carvalho Chehab 8600c0d06caSMauro Carvalho Chehab retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec); 8610c0d06caSMauro Carvalho Chehab if (!retval) 8620c0d06caSMauro Carvalho Chehab dev->options.audio_input = audio->index; 8630c0d06caSMauro Carvalho Chehab 8640c0d06caSMauro Carvalho Chehab return retval; 8650c0d06caSMauro Carvalho Chehab } 8660c0d06caSMauro Carvalho Chehab 8670c0d06caSMauro Carvalho Chehab static int vidioc_g_audio(struct file *file, void *private_data, 8680c0d06caSMauro Carvalho Chehab struct v4l2_audio *audio) 8690c0d06caSMauro Carvalho Chehab { 870ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 8710c0d06caSMauro Carvalho Chehab 8720c0d06caSMauro Carvalho Chehab audio->index = dev->options.audio_input; 8730c0d06caSMauro Carvalho Chehab audio->capability = V4L2_AUDCAP_STEREO; 874c0decac1SMauro Carvalho Chehab strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name)); 8750c0d06caSMauro Carvalho Chehab return 0; 8760c0d06caSMauro Carvalho Chehab } 8770c0d06caSMauro Carvalho Chehab 87899c77aa4SHans Verkuil static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl) 8790c0d06caSMauro Carvalho Chehab { 88099c77aa4SHans Verkuil struct hdpvr_device *dev = 88199c77aa4SHans Verkuil container_of(ctrl->handler, struct hdpvr_device, hdl); 8820c0d06caSMauro Carvalho Chehab 8830c0d06caSMauro Carvalho Chehab switch (ctrl->id) { 88499c77aa4SHans Verkuil case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: 88599c77aa4SHans Verkuil if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && 88699c77aa4SHans Verkuil dev->video_bitrate->val >= dev->video_bitrate_peak->val) 88799c77aa4SHans Verkuil dev->video_bitrate_peak->val = 88899c77aa4SHans Verkuil dev->video_bitrate->val + 100000; 8890c0d06caSMauro Carvalho Chehab break; 8900c0d06caSMauro Carvalho Chehab } 8910c0d06caSMauro Carvalho Chehab return 0; 8920c0d06caSMauro Carvalho Chehab } 8930c0d06caSMauro Carvalho Chehab 89499c77aa4SHans Verkuil static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) 8950c0d06caSMauro Carvalho Chehab { 89699c77aa4SHans Verkuil struct hdpvr_device *dev = 89799c77aa4SHans Verkuil container_of(ctrl->handler, struct hdpvr_device, hdl); 89899c77aa4SHans Verkuil struct hdpvr_options *opt = &dev->options; 8990c0d06caSMauro Carvalho Chehab int ret = -EINVAL; 9000c0d06caSMauro Carvalho Chehab 9010c0d06caSMauro Carvalho Chehab switch (ctrl->id) { 90299c77aa4SHans Verkuil case V4L2_CID_BRIGHTNESS: 90399c77aa4SHans Verkuil ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val); 90499c77aa4SHans Verkuil if (ret) 9050c0d06caSMauro Carvalho Chehab break; 90699c77aa4SHans Verkuil dev->options.brightness = ctrl->val; 90799c77aa4SHans Verkuil return 0; 90899c77aa4SHans Verkuil case V4L2_CID_CONTRAST: 90999c77aa4SHans Verkuil ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val); 91099c77aa4SHans Verkuil if (ret) 9110c0d06caSMauro Carvalho Chehab break; 91299c77aa4SHans Verkuil dev->options.contrast = ctrl->val; 91399c77aa4SHans Verkuil return 0; 91499c77aa4SHans Verkuil case V4L2_CID_SATURATION: 91599c77aa4SHans Verkuil ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val); 91699c77aa4SHans Verkuil if (ret) 9170c0d06caSMauro Carvalho Chehab break; 91899c77aa4SHans Verkuil dev->options.saturation = ctrl->val; 91999c77aa4SHans Verkuil return 0; 92099c77aa4SHans Verkuil case V4L2_CID_HUE: 92199c77aa4SHans Verkuil ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val); 92299c77aa4SHans Verkuil if (ret) 9230c0d06caSMauro Carvalho Chehab break; 92499c77aa4SHans Verkuil dev->options.hue = ctrl->val; 92599c77aa4SHans Verkuil return 0; 92699c77aa4SHans Verkuil case V4L2_CID_SHARPNESS: 92799c77aa4SHans Verkuil ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val); 92899c77aa4SHans Verkuil if (ret) 9290c0d06caSMauro Carvalho Chehab break; 93099c77aa4SHans Verkuil dev->options.sharpness = ctrl->val; 93199c77aa4SHans Verkuil return 0; 9320c0d06caSMauro Carvalho Chehab case V4L2_CID_MPEG_AUDIO_ENCODING: 9330c0d06caSMauro Carvalho Chehab if (dev->flags & HDPVR_FLAG_AC3_CAP) { 93499c77aa4SHans Verkuil opt->audio_codec = ctrl->val; 9353445857bSHans Verkuil return hdpvr_set_audio(dev, opt->audio_input + 1, 9360c0d06caSMauro Carvalho Chehab opt->audio_codec); 9370c0d06caSMauro Carvalho Chehab } 93899c77aa4SHans Verkuil return 0; 9390c0d06caSMauro Carvalho Chehab case V4L2_CID_MPEG_VIDEO_ENCODING: 94099c77aa4SHans Verkuil return 0; 9410c0d06caSMauro Carvalho Chehab /* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ 9420c0d06caSMauro Carvalho Chehab /* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */ 9430c0d06caSMauro Carvalho Chehab /* opt->gop_mode |= 0x2; */ 9440c0d06caSMauro Carvalho Chehab /* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ 9450c0d06caSMauro Carvalho Chehab /* opt->gop_mode); */ 9460c0d06caSMauro Carvalho Chehab /* } */ 9470c0d06caSMauro Carvalho Chehab /* if (ctrl->value == 128 && opt->gop_mode & 0x2) { */ 9480c0d06caSMauro Carvalho Chehab /* opt->gop_mode &= ~0x2; */ 9490c0d06caSMauro Carvalho Chehab /* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ 9500c0d06caSMauro Carvalho Chehab /* opt->gop_mode); */ 9510c0d06caSMauro Carvalho Chehab /* } */ 9520c0d06caSMauro Carvalho Chehab /* break; */ 95399c77aa4SHans Verkuil case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { 95499c77aa4SHans Verkuil uint peak_bitrate = dev->video_bitrate_peak->val / 100000; 95599c77aa4SHans Verkuil uint bitrate = dev->video_bitrate->val / 100000; 95699c77aa4SHans Verkuil 95799c77aa4SHans Verkuil if (ctrl->is_new) { 95899c77aa4SHans Verkuil if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) 9590c0d06caSMauro Carvalho Chehab opt->bitrate_mode = HDPVR_CONSTANT; 96099c77aa4SHans Verkuil else 9610c0d06caSMauro Carvalho Chehab opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE; 9620c0d06caSMauro Carvalho Chehab hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, 9630c0d06caSMauro Carvalho Chehab opt->bitrate_mode); 96499c77aa4SHans Verkuil v4l2_ctrl_activate(dev->video_bitrate_peak, 96599c77aa4SHans Verkuil ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); 9660c0d06caSMauro Carvalho Chehab } 9670c0d06caSMauro Carvalho Chehab 96899c77aa4SHans Verkuil if (dev->video_bitrate_peak->is_new || 96999c77aa4SHans Verkuil dev->video_bitrate->is_new) { 9700c0d06caSMauro Carvalho Chehab opt->bitrate = bitrate; 9710c0d06caSMauro Carvalho Chehab opt->peak_bitrate = peak_bitrate; 9720c0d06caSMauro Carvalho Chehab hdpvr_set_bitrate(dev); 97399c77aa4SHans Verkuil } 97499c77aa4SHans Verkuil return 0; 9750c0d06caSMauro Carvalho Chehab } 9760c0d06caSMauro Carvalho Chehab case V4L2_CID_MPEG_STREAM_TYPE: 97799c77aa4SHans Verkuil return 0; 9780c0d06caSMauro Carvalho Chehab default: 97999c77aa4SHans Verkuil break; 9800c0d06caSMauro Carvalho Chehab } 9810c0d06caSMauro Carvalho Chehab return ret; 9820c0d06caSMauro Carvalho Chehab } 9830c0d06caSMauro Carvalho Chehab 9840c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, 9850c0d06caSMauro Carvalho Chehab struct v4l2_fmtdesc *f) 9860c0d06caSMauro Carvalho Chehab { 98797caa318SHans Verkuil if (f->index != 0) 9880c0d06caSMauro Carvalho Chehab return -EINVAL; 9890c0d06caSMauro Carvalho Chehab 9900c0d06caSMauro Carvalho Chehab f->flags = V4L2_FMT_FLAG_COMPRESSED; 99185709cbfSMauro Carvalho Chehab strscpy(f->description, "MPEG2-TS with AVC/AAC streams", 99285709cbfSMauro Carvalho Chehab sizeof(f->description)); 9930c0d06caSMauro Carvalho Chehab f->pixelformat = V4L2_PIX_FMT_MPEG; 9940c0d06caSMauro Carvalho Chehab 9950c0d06caSMauro Carvalho Chehab return 0; 9960c0d06caSMauro Carvalho Chehab } 9970c0d06caSMauro Carvalho Chehab 9983315c59aSHans Verkuil static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, 9990c0d06caSMauro Carvalho Chehab struct v4l2_format *f) 10000c0d06caSMauro Carvalho Chehab { 1001ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(file); 10023315c59aSHans Verkuil struct hdpvr_fh *fh = _fh; 10034d601c4cSLeonid Kegulskiy int ret; 10040c0d06caSMauro Carvalho Chehab 10053315c59aSHans Verkuil /* 10063315c59aSHans Verkuil * The original driver would always returns the current detected 10073315c59aSHans Verkuil * resolution as the format (and EFAULT if it couldn't be detected). 10083315c59aSHans Verkuil * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a 10093315c59aSHans Verkuil * better way of doing this, but to stay compatible with existing 10103315c59aSHans Verkuil * applications we assume legacy mode every time an application opens 10113315c59aSHans Verkuil * the device. Only if one of the new DV_TIMINGS ioctls is called 10123315c59aSHans Verkuil * will the filehandle go into 'normal' mode where g_fmt returns the 10133315c59aSHans Verkuil * last set format. 10143315c59aSHans Verkuil */ 10153315c59aSHans Verkuil if (fh->legacy_mode) { 10164d601c4cSLeonid Kegulskiy struct hdpvr_video_info vid_info; 10170c0d06caSMauro Carvalho Chehab 10184d601c4cSLeonid Kegulskiy ret = get_video_info(dev, &vid_info); 10195f454d82SHans Verkuil if (ret < 0) 10205f454d82SHans Verkuil return ret; 10215f454d82SHans Verkuil if (!vid_info.valid) 10220c0d06caSMauro Carvalho Chehab return -EFAULT; 10234d601c4cSLeonid Kegulskiy f->fmt.pix.width = vid_info.width; 10244d601c4cSLeonid Kegulskiy f->fmt.pix.height = vid_info.height; 10253315c59aSHans Verkuil } else { 10263315c59aSHans Verkuil f->fmt.pix.width = dev->width; 10273315c59aSHans Verkuil f->fmt.pix.height = dev->height; 10283315c59aSHans Verkuil } 10293315c59aSHans Verkuil f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 10303315c59aSHans Verkuil f->fmt.pix.sizeimage = dev->bulk_in_size; 10313315c59aSHans Verkuil f->fmt.pix.bytesperline = 0; 10323315c59aSHans Verkuil if (f->fmt.pix.width == 720) { 10333315c59aSHans Verkuil /* SDTV formats */ 10343315c59aSHans Verkuil f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 10353315c59aSHans Verkuil f->fmt.pix.field = V4L2_FIELD_INTERLACED; 10363315c59aSHans Verkuil } else { 10373315c59aSHans Verkuil /* HDTV formats */ 103893e6a855SHans Verkuil f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; 10393315c59aSHans Verkuil f->fmt.pix.field = V4L2_FIELD_NONE; 10403315c59aSHans Verkuil } 10410c0d06caSMauro Carvalho Chehab return 0; 10420c0d06caSMauro Carvalho Chehab } 10430c0d06caSMauro Carvalho Chehab 10440c0d06caSMauro Carvalho Chehab static int vidioc_encoder_cmd(struct file *filp, void *priv, 10450c0d06caSMauro Carvalho Chehab struct v4l2_encoder_cmd *a) 10460c0d06caSMauro Carvalho Chehab { 1047ede197aaSHans Verkuil struct hdpvr_device *dev = video_drvdata(filp); 1048ede197aaSHans Verkuil int res = 0; 10490c0d06caSMauro Carvalho Chehab 10500c0d06caSMauro Carvalho Chehab mutex_lock(&dev->io_mutex); 1051ede197aaSHans Verkuil a->flags = 0; 10520c0d06caSMauro Carvalho Chehab 10530c0d06caSMauro Carvalho Chehab switch (a->cmd) { 10540c0d06caSMauro Carvalho Chehab case V4L2_ENC_CMD_START: 1055ede197aaSHans Verkuil if (dev->owner && filp->private_data != dev->owner) { 1056ede197aaSHans Verkuil res = -EBUSY; 1057ede197aaSHans Verkuil break; 1058ede197aaSHans Verkuil } 1059ede197aaSHans Verkuil if (dev->status == STATUS_STREAMING) 1060ede197aaSHans Verkuil break; 10610c0d06caSMauro Carvalho Chehab res = hdpvr_start_streaming(dev); 1062ede197aaSHans Verkuil if (!res) 1063ede197aaSHans Verkuil dev->owner = filp->private_data; 1064ede197aaSHans Verkuil else 1065ede197aaSHans Verkuil dev->status = STATUS_IDLE; 10660c0d06caSMauro Carvalho Chehab break; 10670c0d06caSMauro Carvalho Chehab case V4L2_ENC_CMD_STOP: 1068ede197aaSHans Verkuil if (dev->owner && filp->private_data != dev->owner) { 1069ede197aaSHans Verkuil res = -EBUSY; 1070ede197aaSHans Verkuil break; 1071ede197aaSHans Verkuil } 1072ede197aaSHans Verkuil if (dev->status == STATUS_IDLE) 1073ede197aaSHans Verkuil break; 10740c0d06caSMauro Carvalho Chehab res = hdpvr_stop_streaming(dev); 1075ede197aaSHans Verkuil if (!res) 1076ede197aaSHans Verkuil dev->owner = NULL; 10770c0d06caSMauro Carvalho Chehab break; 10780c0d06caSMauro Carvalho Chehab default: 10790c0d06caSMauro Carvalho Chehab v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 10800c0d06caSMauro Carvalho Chehab "Unsupported encoder cmd %d\n", a->cmd); 10810c0d06caSMauro Carvalho Chehab res = -EINVAL; 1082ede197aaSHans Verkuil break; 10830c0d06caSMauro Carvalho Chehab } 1084ede197aaSHans Verkuil 10850c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->io_mutex); 10860c0d06caSMauro Carvalho Chehab return res; 10870c0d06caSMauro Carvalho Chehab } 10880c0d06caSMauro Carvalho Chehab 10890c0d06caSMauro Carvalho Chehab static int vidioc_try_encoder_cmd(struct file *filp, void *priv, 10900c0d06caSMauro Carvalho Chehab struct v4l2_encoder_cmd *a) 10910c0d06caSMauro Carvalho Chehab { 1092ede197aaSHans Verkuil a->flags = 0; 10930c0d06caSMauro Carvalho Chehab switch (a->cmd) { 10940c0d06caSMauro Carvalho Chehab case V4L2_ENC_CMD_START: 10950c0d06caSMauro Carvalho Chehab case V4L2_ENC_CMD_STOP: 10960c0d06caSMauro Carvalho Chehab return 0; 10970c0d06caSMauro Carvalho Chehab default: 10980c0d06caSMauro Carvalho Chehab return -EINVAL; 10990c0d06caSMauro Carvalho Chehab } 11000c0d06caSMauro Carvalho Chehab } 11010c0d06caSMauro Carvalho Chehab 11020c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { 11030c0d06caSMauro Carvalho Chehab .vidioc_querycap = vidioc_querycap, 11040c0d06caSMauro Carvalho Chehab .vidioc_s_std = vidioc_s_std, 11058f69da95SHans Verkuil .vidioc_g_std = vidioc_g_std, 11068f69da95SHans Verkuil .vidioc_querystd = vidioc_querystd, 11073315c59aSHans Verkuil .vidioc_s_dv_timings = vidioc_s_dv_timings, 11083315c59aSHans Verkuil .vidioc_g_dv_timings = vidioc_g_dv_timings, 11093315c59aSHans Verkuil .vidioc_query_dv_timings= vidioc_query_dv_timings, 11103315c59aSHans Verkuil .vidioc_enum_dv_timings = vidioc_enum_dv_timings, 11113315c59aSHans Verkuil .vidioc_dv_timings_cap = vidioc_dv_timings_cap, 11120c0d06caSMauro Carvalho Chehab .vidioc_enum_input = vidioc_enum_input, 11130c0d06caSMauro Carvalho Chehab .vidioc_g_input = vidioc_g_input, 11140c0d06caSMauro Carvalho Chehab .vidioc_s_input = vidioc_s_input, 11150c0d06caSMauro Carvalho Chehab .vidioc_enumaudio = vidioc_enumaudio, 11160c0d06caSMauro Carvalho Chehab .vidioc_g_audio = vidioc_g_audio, 11170c0d06caSMauro Carvalho Chehab .vidioc_s_audio = vidioc_s_audio, 11180c0d06caSMauro Carvalho Chehab .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap, 11190c0d06caSMauro Carvalho Chehab .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 11203315c59aSHans Verkuil .vidioc_s_fmt_vid_cap = vidioc_g_fmt_vid_cap, 11213315c59aSHans Verkuil .vidioc_try_fmt_vid_cap = vidioc_g_fmt_vid_cap, 11220c0d06caSMauro Carvalho Chehab .vidioc_encoder_cmd = vidioc_encoder_cmd, 11230c0d06caSMauro Carvalho Chehab .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, 112465fe42d6SHans Verkuil .vidioc_log_status = v4l2_ctrl_log_status, 112565fe42d6SHans Verkuil .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 112665fe42d6SHans Verkuil .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 11270c0d06caSMauro Carvalho Chehab }; 11280c0d06caSMauro Carvalho Chehab 11290c0d06caSMauro Carvalho Chehab static void hdpvr_device_release(struct video_device *vdev) 11300c0d06caSMauro Carvalho Chehab { 11310c0d06caSMauro Carvalho Chehab struct hdpvr_device *dev = video_get_drvdata(vdev); 11320c0d06caSMauro Carvalho Chehab 11330c0d06caSMauro Carvalho Chehab hdpvr_delete(dev); 11345612e191SBhaktipriya Shridhar flush_work(&dev->worker); 11350c0d06caSMauro Carvalho Chehab 11360c0d06caSMauro Carvalho Chehab v4l2_device_unregister(&dev->v4l2_dev); 113799c77aa4SHans Verkuil v4l2_ctrl_handler_free(&dev->hdl); 11380c0d06caSMauro Carvalho Chehab 11390c0d06caSMauro Carvalho Chehab /* deregister I2C adapter */ 114054d80904SMauro Carvalho Chehab #if IS_ENABLED(CONFIG_I2C) 11410c0d06caSMauro Carvalho Chehab mutex_lock(&dev->i2c_mutex); 11420c0d06caSMauro Carvalho Chehab i2c_del_adapter(&dev->i2c_adapter); 11430c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->i2c_mutex); 11440c0d06caSMauro Carvalho Chehab #endif /* CONFIG_I2C */ 11450c0d06caSMauro Carvalho Chehab 11460c0d06caSMauro Carvalho Chehab kfree(dev->usbc_buf); 11470c0d06caSMauro Carvalho Chehab kfree(dev); 11480c0d06caSMauro Carvalho Chehab } 11490c0d06caSMauro Carvalho Chehab 11500c0d06caSMauro Carvalho Chehab static const struct video_device hdpvr_video_template = { 11510c0d06caSMauro Carvalho Chehab .fops = &hdpvr_fops, 11520c0d06caSMauro Carvalho Chehab .release = hdpvr_device_release, 11530c0d06caSMauro Carvalho Chehab .ioctl_ops = &hdpvr_ioctl_ops, 11545854bf88SHans Verkuil .tvnorms = V4L2_STD_ALL, 11558c3854d0SHans Verkuil .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | 11568c3854d0SHans Verkuil V4L2_CAP_READWRITE, 11570c0d06caSMauro Carvalho Chehab }; 11580c0d06caSMauro Carvalho Chehab 115999c77aa4SHans Verkuil static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { 116099c77aa4SHans Verkuil .try_ctrl = hdpvr_try_ctrl, 116199c77aa4SHans Verkuil .s_ctrl = hdpvr_s_ctrl, 116299c77aa4SHans Verkuil }; 116399c77aa4SHans Verkuil 11640c0d06caSMauro Carvalho Chehab int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, 11650c0d06caSMauro Carvalho Chehab int devnum) 11660c0d06caSMauro Carvalho Chehab { 116799c77aa4SHans Verkuil struct v4l2_ctrl_handler *hdl = &dev->hdl; 116899c77aa4SHans Verkuil bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP; 116999c77aa4SHans Verkuil int res; 117099c77aa4SHans Verkuil 11718f69da95SHans Verkuil dev->cur_std = V4L2_STD_525_60; 11728f69da95SHans Verkuil dev->width = 720; 11738f69da95SHans Verkuil dev->height = 480; 11743315c59aSHans Verkuil dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX]; 117599c77aa4SHans Verkuil v4l2_ctrl_handler_init(hdl, 11); 117699c77aa4SHans Verkuil if (dev->fw_ver > 0x15) { 117799c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 117899c77aa4SHans Verkuil V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80); 117999c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118099c77aa4SHans Verkuil V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40); 118199c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118299c77aa4SHans Verkuil V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40); 118399c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118499c77aa4SHans Verkuil V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf); 118599c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118699c77aa4SHans Verkuil V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); 118799c77aa4SHans Verkuil } else { 118899c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118999c77aa4SHans Verkuil V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86); 119099c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119199c77aa4SHans Verkuil V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80); 119299c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119399c77aa4SHans Verkuil V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80); 119499c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119599c77aa4SHans Verkuil V4L2_CID_HUE, 0x0, 0xff, 1, 0x80); 119699c77aa4SHans Verkuil v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119799c77aa4SHans Verkuil V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); 119899c77aa4SHans Verkuil } 119999c77aa4SHans Verkuil 120099c77aa4SHans Verkuil v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 120199c77aa4SHans Verkuil V4L2_CID_MPEG_STREAM_TYPE, 120299c77aa4SHans Verkuil V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 120399c77aa4SHans Verkuil 0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS); 120499c77aa4SHans Verkuil v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 120599c77aa4SHans Verkuil V4L2_CID_MPEG_AUDIO_ENCODING, 120699c77aa4SHans Verkuil ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC, 12073445857bSHans Verkuil 0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC); 120899c77aa4SHans Verkuil v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 120999c77aa4SHans Verkuil V4L2_CID_MPEG_VIDEO_ENCODING, 121099c77aa4SHans Verkuil V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3, 121199c77aa4SHans Verkuil V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); 121299c77aa4SHans Verkuil 121399c77aa4SHans Verkuil dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 121499c77aa4SHans Verkuil V4L2_CID_MPEG_VIDEO_BITRATE_MODE, 121599c77aa4SHans Verkuil V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, 121699c77aa4SHans Verkuil V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); 121799c77aa4SHans Verkuil 121899c77aa4SHans Verkuil dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 121999c77aa4SHans Verkuil V4L2_CID_MPEG_VIDEO_BITRATE, 122099c77aa4SHans Verkuil 1000000, 13500000, 100000, 6500000); 122199c77aa4SHans Verkuil dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 122299c77aa4SHans Verkuil V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, 122399c77aa4SHans Verkuil 1100000, 20200000, 100000, 9000000); 122499c77aa4SHans Verkuil dev->v4l2_dev.ctrl_handler = hdl; 122599c77aa4SHans Verkuil if (hdl->error) { 122699c77aa4SHans Verkuil res = hdl->error; 122799c77aa4SHans Verkuil v4l2_err(&dev->v4l2_dev, "Could not register controls\n"); 122899c77aa4SHans Verkuil goto error; 122999c77aa4SHans Verkuil } 123099c77aa4SHans Verkuil v4l2_ctrl_cluster(3, &dev->video_mode); 123199c77aa4SHans Verkuil res = v4l2_ctrl_handler_setup(hdl); 123299c77aa4SHans Verkuil if (res < 0) { 123399c77aa4SHans Verkuil v4l2_err(&dev->v4l2_dev, "Could not setup controls\n"); 123499c77aa4SHans Verkuil goto error; 123599c77aa4SHans Verkuil } 123699c77aa4SHans Verkuil 12370c0d06caSMauro Carvalho Chehab /* setup and register video device */ 12384b30409bSHans Verkuil dev->video_dev = hdpvr_video_template; 1239cc1e6315SMauro Carvalho Chehab strscpy(dev->video_dev.name, "Hauppauge HD PVR", 1240cc1e6315SMauro Carvalho Chehab sizeof(dev->video_dev.name)); 12414b30409bSHans Verkuil dev->video_dev.v4l2_dev = &dev->v4l2_dev; 12424b30409bSHans Verkuil video_set_drvdata(&dev->video_dev, dev); 12430c0d06caSMauro Carvalho Chehab 12444b30409bSHans Verkuil res = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, devnum); 124599c77aa4SHans Verkuil if (res < 0) { 12460c0d06caSMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); 12470c0d06caSMauro Carvalho Chehab goto error; 12480c0d06caSMauro Carvalho Chehab } 12490c0d06caSMauro Carvalho Chehab 12500c0d06caSMauro Carvalho Chehab return 0; 12510c0d06caSMauro Carvalho Chehab error: 125299c77aa4SHans Verkuil v4l2_ctrl_handler_free(hdl); 125399c77aa4SHans Verkuil return res; 12540c0d06caSMauro Carvalho Chehab } 1255