18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Hauppauge HD PVR USB driver - video 4 linux 2 interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Janne Grunau (j@jannau.net) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 148c2ecf20Sopenharmony_ci#include <linux/usb.h> 158c2ecf20Sopenharmony_ci#include <linux/mutex.h> 168c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 198c2ecf20Sopenharmony_ci#include <linux/v4l2-dv-timings.h> 208c2ecf20Sopenharmony_ci#include <media/v4l2-dev.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-dv-timings.h> 238c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 248c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 258c2ecf20Sopenharmony_ci#include "hdpvr.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define BULK_URB_TIMEOUT 90 /* 0.09 seconds */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define print_buffer_status() { \ 308c2ecf20Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \ 318c2ecf20Sopenharmony_ci "%s:%d buffer stat: %d free, %d proc\n", \ 328c2ecf20Sopenharmony_ci __func__, __LINE__, \ 338c2ecf20Sopenharmony_ci list_size(&dev->free_buff_list), \ 348c2ecf20Sopenharmony_ci list_size(&dev->rec_buff_list)); } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic const struct v4l2_dv_timings hdpvr_dv_timings[] = { 378c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_720X480I59_94, 388c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_720X576I50, 398c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_720X480P59_94, 408c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_720X576P50, 418c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_1280X720P50, 428c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_1280X720P60, 438c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_1920X1080I50, 448c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_1920X1080I60, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Use 480i59 as the default timings */ 488c2ecf20Sopenharmony_ci#define HDPVR_DEF_DV_TIMINGS_IDX (0) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct hdpvr_fh { 518c2ecf20Sopenharmony_ci struct v4l2_fh fh; 528c2ecf20Sopenharmony_ci bool legacy_mode; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic uint list_size(struct list_head *list) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct list_head *tmp; 588c2ecf20Sopenharmony_ci uint count = 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci list_for_each(tmp, list) { 618c2ecf20Sopenharmony_ci count++; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return count; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/*=========================================================================*/ 688c2ecf20Sopenharmony_ci/* urb callback */ 698c2ecf20Sopenharmony_cistatic void hdpvr_read_bulk_callback(struct urb *urb) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context; 728c2ecf20Sopenharmony_ci struct hdpvr_device *dev = buf->dev; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* marking buffer as received and wake waiting */ 758c2ecf20Sopenharmony_ci buf->status = BUFSTAT_READY; 768c2ecf20Sopenharmony_ci wake_up_interruptible(&dev->wait_data); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/*=========================================================================*/ 808c2ecf20Sopenharmony_ci/* buffer bits */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 838c2ecf20Sopenharmony_ciint hdpvr_cancel_queue(struct hdpvr_device *dev) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci list_for_each_entry(buf, &dev->rec_buff_list, buff_list) { 888c2ecf20Sopenharmony_ci usb_kill_urb(buf->urb); 898c2ecf20Sopenharmony_ci buf->status = BUFSTAT_AVAILABLE; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int hdpvr_free_queue(struct list_head *q) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct list_head *tmp; 1008c2ecf20Sopenharmony_ci struct list_head *p; 1018c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf; 1028c2ecf20Sopenharmony_ci struct urb *urb; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci for (p = q->next; p != q;) { 1058c2ecf20Sopenharmony_ci buf = list_entry(p, struct hdpvr_buffer, buff_list); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci urb = buf->urb; 1088c2ecf20Sopenharmony_ci usb_free_coherent(urb->dev, urb->transfer_buffer_length, 1098c2ecf20Sopenharmony_ci urb->transfer_buffer, urb->transfer_dma); 1108c2ecf20Sopenharmony_ci usb_free_urb(urb); 1118c2ecf20Sopenharmony_ci tmp = p->next; 1128c2ecf20Sopenharmony_ci list_del(p); 1138c2ecf20Sopenharmony_ci kfree(buf); 1148c2ecf20Sopenharmony_ci p = tmp; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 1218c2ecf20Sopenharmony_ciint hdpvr_free_buffers(struct hdpvr_device *dev) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci hdpvr_cancel_queue(dev); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci hdpvr_free_queue(&dev->free_buff_list); 1268c2ecf20Sopenharmony_ci hdpvr_free_queue(&dev->rec_buff_list); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 1328c2ecf20Sopenharmony_ciint hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci uint i; 1358c2ecf20Sopenharmony_ci int retval = -ENOMEM; 1368c2ecf20Sopenharmony_ci u8 *mem; 1378c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf; 1388c2ecf20Sopenharmony_ci struct urb *urb; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 1418c2ecf20Sopenharmony_ci "allocating %u buffers\n", count); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL); 1468c2ecf20Sopenharmony_ci if (!buf) { 1478c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n"); 1488c2ecf20Sopenharmony_ci goto exit; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci buf->dev = dev; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 1538c2ecf20Sopenharmony_ci if (!urb) 1548c2ecf20Sopenharmony_ci goto exit_urb; 1558c2ecf20Sopenharmony_ci buf->urb = urb; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL, 1588c2ecf20Sopenharmony_ci &urb->transfer_dma); 1598c2ecf20Sopenharmony_ci if (!mem) { 1608c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 1618c2ecf20Sopenharmony_ci "cannot allocate usb transfer buffer\n"); 1628c2ecf20Sopenharmony_ci goto exit_urb_buffer; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci usb_fill_bulk_urb(buf->urb, dev->udev, 1668c2ecf20Sopenharmony_ci usb_rcvbulkpipe(dev->udev, 1678c2ecf20Sopenharmony_ci dev->bulk_in_endpointAddr), 1688c2ecf20Sopenharmony_ci mem, dev->bulk_in_size, 1698c2ecf20Sopenharmony_ci hdpvr_read_bulk_callback, buf); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1728c2ecf20Sopenharmony_ci buf->status = BUFSTAT_AVAILABLE; 1738c2ecf20Sopenharmony_ci list_add_tail(&buf->buff_list, &dev->free_buff_list); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ciexit_urb_buffer: 1778c2ecf20Sopenharmony_ci usb_free_urb(urb); 1788c2ecf20Sopenharmony_ciexit_urb: 1798c2ecf20Sopenharmony_ci kfree(buf); 1808c2ecf20Sopenharmony_ciexit: 1818c2ecf20Sopenharmony_ci hdpvr_free_buffers(dev); 1828c2ecf20Sopenharmony_ci return retval; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int hdpvr_submit_buffers(struct hdpvr_device *dev) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf; 1888c2ecf20Sopenharmony_ci struct urb *urb; 1898c2ecf20Sopenharmony_ci int ret = 0, err_count = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci while (dev->status == STATUS_STREAMING && 1948c2ecf20Sopenharmony_ci !list_empty(&dev->free_buff_list)) { 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer, 1978c2ecf20Sopenharmony_ci buff_list); 1988c2ecf20Sopenharmony_ci if (buf->status != BUFSTAT_AVAILABLE) { 1998c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 2008c2ecf20Sopenharmony_ci "buffer not marked as available\n"); 2018c2ecf20Sopenharmony_ci ret = -EFAULT; 2028c2ecf20Sopenharmony_ci goto err; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci urb = buf->urb; 2068c2ecf20Sopenharmony_ci urb->status = 0; 2078c2ecf20Sopenharmony_ci urb->actual_length = 0; 2088c2ecf20Sopenharmony_ci ret = usb_submit_urb(urb, GFP_KERNEL); 2098c2ecf20Sopenharmony_ci if (ret) { 2108c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 2118c2ecf20Sopenharmony_ci "usb_submit_urb in %s returned %d\n", 2128c2ecf20Sopenharmony_ci __func__, ret); 2138c2ecf20Sopenharmony_ci if (++err_count > 2) 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci continue; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci buf->status = BUFSTAT_INPROGRESS; 2188c2ecf20Sopenharmony_ci list_move_tail(&buf->buff_list, &dev->rec_buff_list); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_cierr: 2218c2ecf20Sopenharmony_ci print_buffer_status(); 2228c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (list_empty(&dev->rec_buff_list)) { 2338c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 2348c2ecf20Sopenharmony_ci return NULL; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer, 2388c2ecf20Sopenharmony_ci buff_list); 2398c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return buf; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void hdpvr_transmit_buffers(struct work_struct *work) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct hdpvr_device *dev = container_of(work, struct hdpvr_device, 2478c2ecf20Sopenharmony_ci worker); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci while (dev->status == STATUS_STREAMING) { 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (hdpvr_submit_buffers(dev)) { 2528c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n"); 2538c2ecf20Sopenharmony_ci goto error; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci if (wait_event_interruptible(dev->wait_buffer, 2568c2ecf20Sopenharmony_ci !list_empty(&dev->free_buff_list) || 2578c2ecf20Sopenharmony_ci dev->status != STATUS_STREAMING)) 2588c2ecf20Sopenharmony_ci goto error; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 2628c2ecf20Sopenharmony_ci "transmit worker exited\n"); 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_cierror: 2658c2ecf20Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 2668c2ecf20Sopenharmony_ci "transmit buffers errored\n"); 2678c2ecf20Sopenharmony_ci dev->status = STATUS_ERROR; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 2718c2ecf20Sopenharmony_cistatic int hdpvr_start_streaming(struct hdpvr_device *dev) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int ret; 2748c2ecf20Sopenharmony_ci struct hdpvr_video_info vidinf; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (dev->status == STATUS_STREAMING) 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci if (dev->status != STATUS_IDLE) 2798c2ecf20Sopenharmony_ci return -EAGAIN; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ret = get_video_info(dev, &vidinf); 2828c2ecf20Sopenharmony_ci if (ret < 0) 2838c2ecf20Sopenharmony_ci return ret; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (!vidinf.valid) { 2868c2ecf20Sopenharmony_ci msleep(250); 2878c2ecf20Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 2888c2ecf20Sopenharmony_ci "no video signal at input %d\n", dev->options.video_input); 2898c2ecf20Sopenharmony_ci return -EAGAIN; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 2938c2ecf20Sopenharmony_ci "video signal: %dx%d@%dhz\n", vidinf.width, 2948c2ecf20Sopenharmony_ci vidinf.height, vidinf.fps); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* start streaming 2 request */ 2978c2ecf20Sopenharmony_ci ret = usb_control_msg(dev->udev, 2988c2ecf20Sopenharmony_ci usb_sndctrlpipe(dev->udev, 0), 2998c2ecf20Sopenharmony_ci 0xb8, 0x38, 0x1, 0, NULL, 0, 8000); 3008c2ecf20Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3018c2ecf20Sopenharmony_ci "encoder start control request returned %d\n", ret); 3028c2ecf20Sopenharmony_ci if (ret < 0) 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00); 3068c2ecf20Sopenharmony_ci if (ret) 3078c2ecf20Sopenharmony_ci return ret; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci dev->status = STATUS_STREAMING; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci schedule_work(&dev->worker); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3148c2ecf20Sopenharmony_ci "streaming started\n"); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 3218c2ecf20Sopenharmony_cistatic int hdpvr_stop_streaming(struct hdpvr_device *dev) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int actual_length; 3248c2ecf20Sopenharmony_ci uint c = 0; 3258c2ecf20Sopenharmony_ci u8 *buf; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (dev->status == STATUS_IDLE) 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci else if (dev->status != STATUS_STREAMING) 3308c2ecf20Sopenharmony_ci return -EAGAIN; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci buf = kmalloc(dev->bulk_in_size, GFP_KERNEL); 3338c2ecf20Sopenharmony_ci if (!buf) 3348c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer for emptying the internal device buffer. Next capture start will be slow\n"); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci dev->status = STATUS_SHUTTING_DOWN; 3378c2ecf20Sopenharmony_ci hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00); 3388c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci wake_up_interruptible(&dev->wait_buffer); 3418c2ecf20Sopenharmony_ci msleep(50); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci flush_work(&dev->worker); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 3468c2ecf20Sopenharmony_ci /* kill the still outstanding urbs */ 3478c2ecf20Sopenharmony_ci hdpvr_cancel_queue(dev); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* emptying the device buffer beforeshutting it down */ 3508c2ecf20Sopenharmony_ci while (buf && ++c < 500 && 3518c2ecf20Sopenharmony_ci !usb_bulk_msg(dev->udev, 3528c2ecf20Sopenharmony_ci usb_rcvbulkpipe(dev->udev, 3538c2ecf20Sopenharmony_ci dev->bulk_in_endpointAddr), 3548c2ecf20Sopenharmony_ci buf, dev->bulk_in_size, &actual_length, 3558c2ecf20Sopenharmony_ci BULK_URB_TIMEOUT)) { 3568c2ecf20Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3578c2ecf20Sopenharmony_ci "%2d: got %d bytes\n", c, actual_length); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci kfree(buf); 3608c2ecf20Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 3618c2ecf20Sopenharmony_ci "used %d urbs to empty device buffers\n", c-1); 3628c2ecf20Sopenharmony_ci msleep(10); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci dev->status = STATUS_IDLE; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/*=======================================================================*/ 3718c2ecf20Sopenharmony_ci/* 3728c2ecf20Sopenharmony_ci * video 4 linux 2 file operations 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int hdpvr_open(struct file *file) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (fh == NULL) 3808c2ecf20Sopenharmony_ci return -ENOMEM; 3818c2ecf20Sopenharmony_ci fh->legacy_mode = true; 3828c2ecf20Sopenharmony_ci v4l2_fh_init(&fh->fh, video_devdata(file)); 3838c2ecf20Sopenharmony_ci v4l2_fh_add(&fh->fh); 3848c2ecf20Sopenharmony_ci file->private_data = fh; 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int hdpvr_release(struct file *file) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 3938c2ecf20Sopenharmony_ci if (file->private_data == dev->owner) { 3948c2ecf20Sopenharmony_ci hdpvr_stop_streaming(dev); 3958c2ecf20Sopenharmony_ci dev->owner = NULL; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return v4l2_fh_release(file); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci/* 4038c2ecf20Sopenharmony_ci * hdpvr_v4l2_read() 4048c2ecf20Sopenharmony_ci * will allocate buffers when called for the first time 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_cistatic ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, 4078c2ecf20Sopenharmony_ci loff_t *pos) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 4108c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf = NULL; 4118c2ecf20Sopenharmony_ci struct urb *urb; 4128c2ecf20Sopenharmony_ci int ret = 0; 4138c2ecf20Sopenharmony_ci int rem, cnt; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (*pos) 4168c2ecf20Sopenharmony_ci return -ESPIPE; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 4198c2ecf20Sopenharmony_ci if (dev->status == STATUS_IDLE) { 4208c2ecf20Sopenharmony_ci if (hdpvr_start_streaming(dev)) { 4218c2ecf20Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 4228c2ecf20Sopenharmony_ci "start_streaming failed\n"); 4238c2ecf20Sopenharmony_ci ret = -EIO; 4248c2ecf20Sopenharmony_ci msleep(200); 4258c2ecf20Sopenharmony_ci dev->status = STATUS_IDLE; 4268c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 4278c2ecf20Sopenharmony_ci goto err; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci dev->owner = file->private_data; 4308c2ecf20Sopenharmony_ci print_buffer_status(); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* wait for the first buffer */ 4358c2ecf20Sopenharmony_ci if (!(file->f_flags & O_NONBLOCK)) { 4368c2ecf20Sopenharmony_ci if (wait_event_interruptible(dev->wait_data, 4378c2ecf20Sopenharmony_ci !list_empty_careful(&dev->rec_buff_list))) 4388c2ecf20Sopenharmony_ci return -ERESTARTSYS; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci while (count > 0 && buf) { 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (buf->status != BUFSTAT_READY && 4468c2ecf20Sopenharmony_ci dev->status != STATUS_DISCONNECTED) { 4478c2ecf20Sopenharmony_ci int err; 4488c2ecf20Sopenharmony_ci /* return nonblocking */ 4498c2ecf20Sopenharmony_ci if (file->f_flags & O_NONBLOCK) { 4508c2ecf20Sopenharmony_ci if (!ret) 4518c2ecf20Sopenharmony_ci ret = -EAGAIN; 4528c2ecf20Sopenharmony_ci goto err; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci err = wait_event_interruptible_timeout(dev->wait_data, 4568c2ecf20Sopenharmony_ci buf->status == BUFSTAT_READY, 4578c2ecf20Sopenharmony_ci msecs_to_jiffies(1000)); 4588c2ecf20Sopenharmony_ci if (err < 0) { 4598c2ecf20Sopenharmony_ci ret = err; 4608c2ecf20Sopenharmony_ci goto err; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci if (!err) { 4638c2ecf20Sopenharmony_ci v4l2_info(&dev->v4l2_dev, 4648c2ecf20Sopenharmony_ci "timeout: restart streaming\n"); 4658c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 4668c2ecf20Sopenharmony_ci hdpvr_stop_streaming(dev); 4678c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 4688c2ecf20Sopenharmony_ci /* 4698c2ecf20Sopenharmony_ci * The FW needs about 4 seconds after streaming 4708c2ecf20Sopenharmony_ci * stopped before it is ready to restart 4718c2ecf20Sopenharmony_ci * streaming. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci msleep(4000); 4748c2ecf20Sopenharmony_ci err = hdpvr_start_streaming(dev); 4758c2ecf20Sopenharmony_ci if (err) { 4768c2ecf20Sopenharmony_ci ret = err; 4778c2ecf20Sopenharmony_ci goto err; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (buf->status != BUFSTAT_READY) 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* set remaining bytes to copy */ 4868c2ecf20Sopenharmony_ci urb = buf->urb; 4878c2ecf20Sopenharmony_ci rem = urb->actual_length - buf->pos; 4888c2ecf20Sopenharmony_ci cnt = rem > count ? count : rem; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (copy_to_user(buffer, urb->transfer_buffer + buf->pos, 4918c2ecf20Sopenharmony_ci cnt)) { 4928c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n"); 4938c2ecf20Sopenharmony_ci if (!ret) 4948c2ecf20Sopenharmony_ci ret = -EFAULT; 4958c2ecf20Sopenharmony_ci goto err; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci buf->pos += cnt; 4998c2ecf20Sopenharmony_ci count -= cnt; 5008c2ecf20Sopenharmony_ci buffer += cnt; 5018c2ecf20Sopenharmony_ci ret += cnt; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* finished, take next buffer */ 5048c2ecf20Sopenharmony_ci if (buf->pos == urb->actual_length) { 5058c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 5068c2ecf20Sopenharmony_ci buf->pos = 0; 5078c2ecf20Sopenharmony_ci buf->status = BUFSTAT_AVAILABLE; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci list_move_tail(&buf->buff_list, &dev->free_buff_list); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci print_buffer_status(); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci wake_up_interruptible(&dev->wait_buffer); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_cierr: 5218c2ecf20Sopenharmony_ci if (!ret && !buf) 5228c2ecf20Sopenharmony_ci ret = -EAGAIN; 5238c2ecf20Sopenharmony_ci return ret; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic __poll_t hdpvr_poll(struct file *filp, poll_table *wait) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci __poll_t req_events = poll_requested_events(wait); 5298c2ecf20Sopenharmony_ci struct hdpvr_buffer *buf = NULL; 5308c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(filp); 5318c2ecf20Sopenharmony_ci __poll_t mask = v4l2_ctrl_poll(filp, wait); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (!(req_events & (EPOLLIN | EPOLLRDNORM))) 5348c2ecf20Sopenharmony_ci return mask; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (dev->status == STATUS_IDLE) { 5398c2ecf20Sopenharmony_ci if (hdpvr_start_streaming(dev)) { 5408c2ecf20Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 5418c2ecf20Sopenharmony_ci "start_streaming failed\n"); 5428c2ecf20Sopenharmony_ci dev->status = STATUS_IDLE; 5438c2ecf20Sopenharmony_ci } else { 5448c2ecf20Sopenharmony_ci dev->owner = filp->private_data; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci print_buffer_status(); 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 5528c2ecf20Sopenharmony_ci /* only wait if no data is available */ 5538c2ecf20Sopenharmony_ci if (!buf || buf->status != BUFSTAT_READY) { 5548c2ecf20Sopenharmony_ci poll_wait(filp, &dev->wait_data, wait); 5558c2ecf20Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci if (buf && buf->status == BUFSTAT_READY) 5588c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return mask; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations hdpvr_fops = { 5658c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5668c2ecf20Sopenharmony_ci .open = hdpvr_open, 5678c2ecf20Sopenharmony_ci .release = hdpvr_release, 5688c2ecf20Sopenharmony_ci .read = hdpvr_read, 5698c2ecf20Sopenharmony_ci .poll = hdpvr_poll, 5708c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 5718c2ecf20Sopenharmony_ci}; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci/*=======================================================================*/ 5748c2ecf20Sopenharmony_ci/* 5758c2ecf20Sopenharmony_ci * V4L2 ioctl handling 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic int vidioc_querycap(struct file *file, void *priv, 5798c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci strscpy(cap->driver, "hdpvr", sizeof(cap->driver)); 5848c2ecf20Sopenharmony_ci strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card)); 5858c2ecf20Sopenharmony_ci usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *_fh, 5908c2ecf20Sopenharmony_ci v4l2_std_id std) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 5938c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 5948c2ecf20Sopenharmony_ci u8 std_type = 1; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) 5978c2ecf20Sopenharmony_ci return -ENODATA; 5988c2ecf20Sopenharmony_ci if (dev->status != STATUS_IDLE) 5998c2ecf20Sopenharmony_ci return -EBUSY; 6008c2ecf20Sopenharmony_ci if (std & V4L2_STD_525_60) 6018c2ecf20Sopenharmony_ci std_type = 0; 6028c2ecf20Sopenharmony_ci dev->cur_std = std; 6038c2ecf20Sopenharmony_ci dev->width = 720; 6048c2ecf20Sopenharmony_ci dev->height = std_type ? 576 : 480; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *_fh, 6108c2ecf20Sopenharmony_ci v4l2_std_id *std) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 6138c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) 6168c2ecf20Sopenharmony_ci return -ENODATA; 6178c2ecf20Sopenharmony_ci *std = dev->cur_std; 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 6248c2ecf20Sopenharmony_ci struct hdpvr_video_info vid_info; 6258c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 6268c2ecf20Sopenharmony_ci int ret; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci *a = V4L2_STD_UNKNOWN; 6298c2ecf20Sopenharmony_ci if (dev->options.video_input == HDPVR_COMPONENT) 6308c2ecf20Sopenharmony_ci return fh->legacy_mode ? 0 : -ENODATA; 6318c2ecf20Sopenharmony_ci ret = get_video_info(dev, &vid_info); 6328c2ecf20Sopenharmony_ci if (vid_info.valid && vid_info.width == 720 && 6338c2ecf20Sopenharmony_ci (vid_info.height == 480 || vid_info.height == 576)) { 6348c2ecf20Sopenharmony_ci *a = (vid_info.height == 480) ? 6358c2ecf20Sopenharmony_ci V4L2_STD_525_60 : V4L2_STD_625_50; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci return ret; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic int vidioc_s_dv_timings(struct file *file, void *_fh, 6418c2ecf20Sopenharmony_ci struct v4l2_dv_timings *timings) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 6448c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 6458c2ecf20Sopenharmony_ci int i; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci fh->legacy_mode = false; 6488c2ecf20Sopenharmony_ci if (dev->options.video_input) 6498c2ecf20Sopenharmony_ci return -ENODATA; 6508c2ecf20Sopenharmony_ci if (dev->status != STATUS_IDLE) 6518c2ecf20Sopenharmony_ci return -EBUSY; 6528c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) 6538c2ecf20Sopenharmony_ci if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false)) 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(hdpvr_dv_timings)) 6568c2ecf20Sopenharmony_ci return -EINVAL; 6578c2ecf20Sopenharmony_ci dev->cur_dv_timings = hdpvr_dv_timings[i]; 6588c2ecf20Sopenharmony_ci dev->width = hdpvr_dv_timings[i].bt.width; 6598c2ecf20Sopenharmony_ci dev->height = hdpvr_dv_timings[i].bt.height; 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int vidioc_g_dv_timings(struct file *file, void *_fh, 6648c2ecf20Sopenharmony_ci struct v4l2_dv_timings *timings) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 6678c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci fh->legacy_mode = false; 6708c2ecf20Sopenharmony_ci if (dev->options.video_input) 6718c2ecf20Sopenharmony_ci return -ENODATA; 6728c2ecf20Sopenharmony_ci *timings = dev->cur_dv_timings; 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int vidioc_query_dv_timings(struct file *file, void *_fh, 6778c2ecf20Sopenharmony_ci struct v4l2_dv_timings *timings) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 6808c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 6818c2ecf20Sopenharmony_ci struct hdpvr_video_info vid_info; 6828c2ecf20Sopenharmony_ci bool interlaced; 6838c2ecf20Sopenharmony_ci int ret = 0; 6848c2ecf20Sopenharmony_ci int i; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci fh->legacy_mode = false; 6878c2ecf20Sopenharmony_ci if (dev->options.video_input) 6888c2ecf20Sopenharmony_ci return -ENODATA; 6898c2ecf20Sopenharmony_ci ret = get_video_info(dev, &vid_info); 6908c2ecf20Sopenharmony_ci if (ret) 6918c2ecf20Sopenharmony_ci return ret; 6928c2ecf20Sopenharmony_ci if (!vid_info.valid) 6938c2ecf20Sopenharmony_ci return -ENOLCK; 6948c2ecf20Sopenharmony_ci interlaced = vid_info.fps <= 30; 6958c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) { 6968c2ecf20Sopenharmony_ci const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt; 6978c2ecf20Sopenharmony_ci unsigned hsize; 6988c2ecf20Sopenharmony_ci unsigned vsize; 6998c2ecf20Sopenharmony_ci unsigned fps; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci hsize = V4L2_DV_BT_FRAME_WIDTH(bt); 7028c2ecf20Sopenharmony_ci vsize = V4L2_DV_BT_FRAME_HEIGHT(bt); 7038c2ecf20Sopenharmony_ci fps = (unsigned)bt->pixelclock / (hsize * vsize); 7048c2ecf20Sopenharmony_ci if (bt->width != vid_info.width || 7058c2ecf20Sopenharmony_ci bt->height != vid_info.height || 7068c2ecf20Sopenharmony_ci bt->interlaced != interlaced || 7078c2ecf20Sopenharmony_ci (fps != vid_info.fps && fps + 1 != vid_info.fps)) 7088c2ecf20Sopenharmony_ci continue; 7098c2ecf20Sopenharmony_ci *timings = hdpvr_dv_timings[i]; 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(hdpvr_dv_timings)) 7138c2ecf20Sopenharmony_ci ret = -ERANGE; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return ret; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int vidioc_enum_dv_timings(struct file *file, void *_fh, 7198c2ecf20Sopenharmony_ci struct v4l2_enum_dv_timings *timings) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 7228c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci fh->legacy_mode = false; 7258c2ecf20Sopenharmony_ci memset(timings->reserved, 0, sizeof(timings->reserved)); 7268c2ecf20Sopenharmony_ci if (dev->options.video_input) 7278c2ecf20Sopenharmony_ci return -ENODATA; 7288c2ecf20Sopenharmony_ci if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings)) 7298c2ecf20Sopenharmony_ci return -EINVAL; 7308c2ecf20Sopenharmony_ci timings->timings = hdpvr_dv_timings[timings->index]; 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic int vidioc_dv_timings_cap(struct file *file, void *_fh, 7358c2ecf20Sopenharmony_ci struct v4l2_dv_timings_cap *cap) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 7388c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci fh->legacy_mode = false; 7418c2ecf20Sopenharmony_ci if (dev->options.video_input) 7428c2ecf20Sopenharmony_ci return -ENODATA; 7438c2ecf20Sopenharmony_ci cap->type = V4L2_DV_BT_656_1120; 7448c2ecf20Sopenharmony_ci cap->bt.min_width = 720; 7458c2ecf20Sopenharmony_ci cap->bt.max_width = 1920; 7468c2ecf20Sopenharmony_ci cap->bt.min_height = 480; 7478c2ecf20Sopenharmony_ci cap->bt.max_height = 1080; 7488c2ecf20Sopenharmony_ci cap->bt.min_pixelclock = 27000000; 7498c2ecf20Sopenharmony_ci cap->bt.max_pixelclock = 74250000; 7508c2ecf20Sopenharmony_ci cap->bt.standards = V4L2_DV_BT_STD_CEA861; 7518c2ecf20Sopenharmony_ci cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE; 7528c2ecf20Sopenharmony_ci return 0; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic const char *iname[] = { 7568c2ecf20Sopenharmony_ci [HDPVR_COMPONENT] = "Component", 7578c2ecf20Sopenharmony_ci [HDPVR_SVIDEO] = "S-Video", 7588c2ecf20Sopenharmony_ci [HDPVR_COMPOSITE] = "Composite", 7598c2ecf20Sopenharmony_ci}; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci unsigned int n; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci n = i->index; 7668c2ecf20Sopenharmony_ci if (n >= HDPVR_VIDEO_INPUTS) 7678c2ecf20Sopenharmony_ci return -EINVAL; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci i->type = V4L2_INPUT_TYPE_CAMERA; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci strscpy(i->name, iname[n], sizeof(i->name)); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS; 7768c2ecf20Sopenharmony_ci i->std = n ? V4L2_STD_ALL : 0; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int vidioc_s_input(struct file *file, void *_fh, 7828c2ecf20Sopenharmony_ci unsigned int index) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 7858c2ecf20Sopenharmony_ci int retval; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (index >= HDPVR_VIDEO_INPUTS) 7888c2ecf20Sopenharmony_ci return -EINVAL; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (dev->status != STATUS_IDLE) 7918c2ecf20Sopenharmony_ci return -EBUSY; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); 7948c2ecf20Sopenharmony_ci if (!retval) { 7958c2ecf20Sopenharmony_ci dev->options.video_input = index; 7968c2ecf20Sopenharmony_ci /* 7978c2ecf20Sopenharmony_ci * Unfortunately gstreamer calls ENUMSTD and bails out if it 7988c2ecf20Sopenharmony_ci * won't find any formats, even though component input is 7998c2ecf20Sopenharmony_ci * selected. This means that we have to leave tvnorms at 8008c2ecf20Sopenharmony_ci * V4L2_STD_ALL. We cannot use the 'legacy' trick since 8018c2ecf20Sopenharmony_ci * tvnorms is set at the device node level and not at the 8028c2ecf20Sopenharmony_ci * filehandle level. 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * Comment this out for now, but if the legacy mode can be 8058c2ecf20Sopenharmony_ci * removed in the future, then this code should be enabled 8068c2ecf20Sopenharmony_ci * again. 8078c2ecf20Sopenharmony_ci dev->video_dev.tvnorms = 8088c2ecf20Sopenharmony_ci (index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0; 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return retval; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int vidioc_g_input(struct file *file, void *private_data, 8168c2ecf20Sopenharmony_ci unsigned int *index) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci *index = dev->options.video_input; 8218c2ecf20Sopenharmony_ci return 0; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic const char *audio_iname[] = { 8268c2ecf20Sopenharmony_ci [HDPVR_RCA_FRONT] = "RCA front", 8278c2ecf20Sopenharmony_ci [HDPVR_RCA_BACK] = "RCA back", 8288c2ecf20Sopenharmony_ci [HDPVR_SPDIF] = "SPDIF", 8298c2ecf20Sopenharmony_ci}; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic int vidioc_enumaudio(struct file *file, void *priv, 8328c2ecf20Sopenharmony_ci struct v4l2_audio *audio) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci unsigned int n; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci n = audio->index; 8378c2ecf20Sopenharmony_ci if (n >= HDPVR_AUDIO_INPUTS) 8388c2ecf20Sopenharmony_ci return -EINVAL; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci audio->capability = V4L2_AUDCAP_STEREO; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci strscpy(audio->name, audio_iname[n], sizeof(audio->name)); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return 0; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic int vidioc_s_audio(struct file *file, void *private_data, 8488c2ecf20Sopenharmony_ci const struct v4l2_audio *audio) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 8518c2ecf20Sopenharmony_ci int retval; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (audio->index >= HDPVR_AUDIO_INPUTS) 8548c2ecf20Sopenharmony_ci return -EINVAL; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (dev->status != STATUS_IDLE) 8578c2ecf20Sopenharmony_ci return -EBUSY; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec); 8608c2ecf20Sopenharmony_ci if (!retval) 8618c2ecf20Sopenharmony_ci dev->options.audio_input = audio->index; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci return retval; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic int vidioc_g_audio(struct file *file, void *private_data, 8678c2ecf20Sopenharmony_ci struct v4l2_audio *audio) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci audio->index = dev->options.audio_input; 8728c2ecf20Sopenharmony_ci audio->capability = V4L2_AUDCAP_STEREO; 8738c2ecf20Sopenharmony_ci strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name)); 8748c2ecf20Sopenharmony_ci return 0; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci struct hdpvr_device *dev = 8808c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct hdpvr_device, hdl); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci switch (ctrl->id) { 8838c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: 8848c2ecf20Sopenharmony_ci if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && 8858c2ecf20Sopenharmony_ci dev->video_bitrate->val >= dev->video_bitrate_peak->val) 8868c2ecf20Sopenharmony_ci dev->video_bitrate_peak->val = 8878c2ecf20Sopenharmony_ci dev->video_bitrate->val + 100000; 8888c2ecf20Sopenharmony_ci break; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct hdpvr_device *dev = 8968c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct hdpvr_device, hdl); 8978c2ecf20Sopenharmony_ci struct hdpvr_options *opt = &dev->options; 8988c2ecf20Sopenharmony_ci int ret = -EINVAL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci switch (ctrl->id) { 9018c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 9028c2ecf20Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val); 9038c2ecf20Sopenharmony_ci if (ret) 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci dev->options.brightness = ctrl->val; 9068c2ecf20Sopenharmony_ci return 0; 9078c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 9088c2ecf20Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val); 9098c2ecf20Sopenharmony_ci if (ret) 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci dev->options.contrast = ctrl->val; 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 9148c2ecf20Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val); 9158c2ecf20Sopenharmony_ci if (ret) 9168c2ecf20Sopenharmony_ci break; 9178c2ecf20Sopenharmony_ci dev->options.saturation = ctrl->val; 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 9208c2ecf20Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val); 9218c2ecf20Sopenharmony_ci if (ret) 9228c2ecf20Sopenharmony_ci break; 9238c2ecf20Sopenharmony_ci dev->options.hue = ctrl->val; 9248c2ecf20Sopenharmony_ci return 0; 9258c2ecf20Sopenharmony_ci case V4L2_CID_SHARPNESS: 9268c2ecf20Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val); 9278c2ecf20Sopenharmony_ci if (ret) 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci dev->options.sharpness = ctrl->val; 9308c2ecf20Sopenharmony_ci return 0; 9318c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_AUDIO_ENCODING: 9328c2ecf20Sopenharmony_ci if (dev->flags & HDPVR_FLAG_AC3_CAP) { 9338c2ecf20Sopenharmony_ci opt->audio_codec = ctrl->val; 9348c2ecf20Sopenharmony_ci return hdpvr_set_audio(dev, opt->audio_input + 1, 9358c2ecf20Sopenharmony_ci opt->audio_codec); 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci return 0; 9388c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_ENCODING: 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ 9418c2ecf20Sopenharmony_ci/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */ 9428c2ecf20Sopenharmony_ci/* opt->gop_mode |= 0x2; */ 9438c2ecf20Sopenharmony_ci/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ 9448c2ecf20Sopenharmony_ci/* opt->gop_mode); */ 9458c2ecf20Sopenharmony_ci/* } */ 9468c2ecf20Sopenharmony_ci/* if (ctrl->value == 128 && opt->gop_mode & 0x2) { */ 9478c2ecf20Sopenharmony_ci/* opt->gop_mode &= ~0x2; */ 9488c2ecf20Sopenharmony_ci/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ 9498c2ecf20Sopenharmony_ci/* opt->gop_mode); */ 9508c2ecf20Sopenharmony_ci/* } */ 9518c2ecf20Sopenharmony_ci/* break; */ 9528c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { 9538c2ecf20Sopenharmony_ci uint peak_bitrate = dev->video_bitrate_peak->val / 100000; 9548c2ecf20Sopenharmony_ci uint bitrate = dev->video_bitrate->val / 100000; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (ctrl->is_new) { 9578c2ecf20Sopenharmony_ci if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) 9588c2ecf20Sopenharmony_ci opt->bitrate_mode = HDPVR_CONSTANT; 9598c2ecf20Sopenharmony_ci else 9608c2ecf20Sopenharmony_ci opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE; 9618c2ecf20Sopenharmony_ci hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, 9628c2ecf20Sopenharmony_ci opt->bitrate_mode); 9638c2ecf20Sopenharmony_ci v4l2_ctrl_activate(dev->video_bitrate_peak, 9648c2ecf20Sopenharmony_ci ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (dev->video_bitrate_peak->is_new || 9688c2ecf20Sopenharmony_ci dev->video_bitrate->is_new) { 9698c2ecf20Sopenharmony_ci opt->bitrate = bitrate; 9708c2ecf20Sopenharmony_ci opt->peak_bitrate = peak_bitrate; 9718c2ecf20Sopenharmony_ci hdpvr_set_bitrate(dev); 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci return 0; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_STREAM_TYPE: 9768c2ecf20Sopenharmony_ci return 0; 9778c2ecf20Sopenharmony_ci default: 9788c2ecf20Sopenharmony_ci break; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci return ret; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, 9848c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *f) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci if (f->index != 0) 9878c2ecf20Sopenharmony_ci return -EINVAL; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_MPEG; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci return 0; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, 9958c2ecf20Sopenharmony_ci struct v4l2_format *f) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 9988c2ecf20Sopenharmony_ci struct hdpvr_fh *fh = _fh; 9998c2ecf20Sopenharmony_ci int ret; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* 10028c2ecf20Sopenharmony_ci * The original driver would always returns the current detected 10038c2ecf20Sopenharmony_ci * resolution as the format (and EFAULT if it couldn't be detected). 10048c2ecf20Sopenharmony_ci * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a 10058c2ecf20Sopenharmony_ci * better way of doing this, but to stay compatible with existing 10068c2ecf20Sopenharmony_ci * applications we assume legacy mode every time an application opens 10078c2ecf20Sopenharmony_ci * the device. Only if one of the new DV_TIMINGS ioctls is called 10088c2ecf20Sopenharmony_ci * will the filehandle go into 'normal' mode where g_fmt returns the 10098c2ecf20Sopenharmony_ci * last set format. 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_ci if (fh->legacy_mode) { 10128c2ecf20Sopenharmony_ci struct hdpvr_video_info vid_info; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci ret = get_video_info(dev, &vid_info); 10158c2ecf20Sopenharmony_ci if (ret < 0) 10168c2ecf20Sopenharmony_ci return ret; 10178c2ecf20Sopenharmony_ci if (!vid_info.valid) 10188c2ecf20Sopenharmony_ci return -EFAULT; 10198c2ecf20Sopenharmony_ci f->fmt.pix.width = vid_info.width; 10208c2ecf20Sopenharmony_ci f->fmt.pix.height = vid_info.height; 10218c2ecf20Sopenharmony_ci } else { 10228c2ecf20Sopenharmony_ci f->fmt.pix.width = dev->width; 10238c2ecf20Sopenharmony_ci f->fmt.pix.height = dev->height; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 10268c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = dev->bulk_in_size; 10278c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = 0; 10288c2ecf20Sopenharmony_ci if (f->fmt.pix.width == 720) { 10298c2ecf20Sopenharmony_ci /* SDTV formats */ 10308c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 10318c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_INTERLACED; 10328c2ecf20Sopenharmony_ci } else { 10338c2ecf20Sopenharmony_ci /* HDTV formats */ 10348c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; 10358c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_NONE; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci return 0; 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int vidioc_encoder_cmd(struct file *filp, void *priv, 10418c2ecf20Sopenharmony_ci struct v4l2_encoder_cmd *a) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(filp); 10448c2ecf20Sopenharmony_ci int res = 0; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci mutex_lock(&dev->io_mutex); 10478c2ecf20Sopenharmony_ci a->flags = 0; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci switch (a->cmd) { 10508c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_START: 10518c2ecf20Sopenharmony_ci if (dev->owner && filp->private_data != dev->owner) { 10528c2ecf20Sopenharmony_ci res = -EBUSY; 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci if (dev->status == STATUS_STREAMING) 10568c2ecf20Sopenharmony_ci break; 10578c2ecf20Sopenharmony_ci res = hdpvr_start_streaming(dev); 10588c2ecf20Sopenharmony_ci if (!res) 10598c2ecf20Sopenharmony_ci dev->owner = filp->private_data; 10608c2ecf20Sopenharmony_ci else 10618c2ecf20Sopenharmony_ci dev->status = STATUS_IDLE; 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_STOP: 10648c2ecf20Sopenharmony_ci if (dev->owner && filp->private_data != dev->owner) { 10658c2ecf20Sopenharmony_ci res = -EBUSY; 10668c2ecf20Sopenharmony_ci break; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci if (dev->status == STATUS_IDLE) 10698c2ecf20Sopenharmony_ci break; 10708c2ecf20Sopenharmony_ci res = hdpvr_stop_streaming(dev); 10718c2ecf20Sopenharmony_ci if (!res) 10728c2ecf20Sopenharmony_ci dev->owner = NULL; 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci default: 10758c2ecf20Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 10768c2ecf20Sopenharmony_ci "Unsupported encoder cmd %d\n", a->cmd); 10778c2ecf20Sopenharmony_ci res = -EINVAL; 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci mutex_unlock(&dev->io_mutex); 10828c2ecf20Sopenharmony_ci return res; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic int vidioc_try_encoder_cmd(struct file *filp, void *priv, 10868c2ecf20Sopenharmony_ci struct v4l2_encoder_cmd *a) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci a->flags = 0; 10898c2ecf20Sopenharmony_ci switch (a->cmd) { 10908c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_START: 10918c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_STOP: 10928c2ecf20Sopenharmony_ci return 0; 10938c2ecf20Sopenharmony_ci default: 10948c2ecf20Sopenharmony_ci return -EINVAL; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { 10998c2ecf20Sopenharmony_ci .vidioc_querycap = vidioc_querycap, 11008c2ecf20Sopenharmony_ci .vidioc_s_std = vidioc_s_std, 11018c2ecf20Sopenharmony_ci .vidioc_g_std = vidioc_g_std, 11028c2ecf20Sopenharmony_ci .vidioc_querystd = vidioc_querystd, 11038c2ecf20Sopenharmony_ci .vidioc_s_dv_timings = vidioc_s_dv_timings, 11048c2ecf20Sopenharmony_ci .vidioc_g_dv_timings = vidioc_g_dv_timings, 11058c2ecf20Sopenharmony_ci .vidioc_query_dv_timings= vidioc_query_dv_timings, 11068c2ecf20Sopenharmony_ci .vidioc_enum_dv_timings = vidioc_enum_dv_timings, 11078c2ecf20Sopenharmony_ci .vidioc_dv_timings_cap = vidioc_dv_timings_cap, 11088c2ecf20Sopenharmony_ci .vidioc_enum_input = vidioc_enum_input, 11098c2ecf20Sopenharmony_ci .vidioc_g_input = vidioc_g_input, 11108c2ecf20Sopenharmony_ci .vidioc_s_input = vidioc_s_input, 11118c2ecf20Sopenharmony_ci .vidioc_enumaudio = vidioc_enumaudio, 11128c2ecf20Sopenharmony_ci .vidioc_g_audio = vidioc_g_audio, 11138c2ecf20Sopenharmony_ci .vidioc_s_audio = vidioc_s_audio, 11148c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap, 11158c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 11168c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = vidioc_g_fmt_vid_cap, 11178c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = vidioc_g_fmt_vid_cap, 11188c2ecf20Sopenharmony_ci .vidioc_encoder_cmd = vidioc_encoder_cmd, 11198c2ecf20Sopenharmony_ci .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, 11208c2ecf20Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 11218c2ecf20Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 11228c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 11238c2ecf20Sopenharmony_ci}; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic void hdpvr_device_release(struct video_device *vdev) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct hdpvr_device *dev = video_get_drvdata(vdev); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci hdpvr_delete(dev); 11308c2ecf20Sopenharmony_ci flush_work(&dev->worker); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci v4l2_device_unregister(&dev->v4l2_dev); 11338c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&dev->hdl); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* deregister I2C adapter */ 11368c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C) 11378c2ecf20Sopenharmony_ci mutex_lock(&dev->i2c_mutex); 11388c2ecf20Sopenharmony_ci i2c_del_adapter(&dev->i2c_adapter); 11398c2ecf20Sopenharmony_ci mutex_unlock(&dev->i2c_mutex); 11408c2ecf20Sopenharmony_ci#endif /* CONFIG_I2C */ 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci kfree(dev->usbc_buf); 11438c2ecf20Sopenharmony_ci kfree(dev); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic const struct video_device hdpvr_video_template = { 11478c2ecf20Sopenharmony_ci .fops = &hdpvr_fops, 11488c2ecf20Sopenharmony_ci .release = hdpvr_device_release, 11498c2ecf20Sopenharmony_ci .ioctl_ops = &hdpvr_ioctl_ops, 11508c2ecf20Sopenharmony_ci .tvnorms = V4L2_STD_ALL, 11518c2ecf20Sopenharmony_ci .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | 11528c2ecf20Sopenharmony_ci V4L2_CAP_READWRITE, 11538c2ecf20Sopenharmony_ci}; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { 11568c2ecf20Sopenharmony_ci .try_ctrl = hdpvr_try_ctrl, 11578c2ecf20Sopenharmony_ci .s_ctrl = hdpvr_s_ctrl, 11588c2ecf20Sopenharmony_ci}; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ciint hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, 11618c2ecf20Sopenharmony_ci int devnum) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &dev->hdl; 11648c2ecf20Sopenharmony_ci bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP; 11658c2ecf20Sopenharmony_ci int res; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci // initialize dev->worker 11688c2ecf20Sopenharmony_ci INIT_WORK(&dev->worker, hdpvr_transmit_buffers); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci dev->cur_std = V4L2_STD_525_60; 11718c2ecf20Sopenharmony_ci dev->width = 720; 11728c2ecf20Sopenharmony_ci dev->height = 480; 11738c2ecf20Sopenharmony_ci dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX]; 11748c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 11); 11758c2ecf20Sopenharmony_ci if (dev->fw_ver > 0x15) { 11768c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11778c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80); 11788c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11798c2ecf20Sopenharmony_ci V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40); 11808c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11818c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40); 11828c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11838c2ecf20Sopenharmony_ci V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf); 11848c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11858c2ecf20Sopenharmony_ci V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); 11868c2ecf20Sopenharmony_ci } else { 11878c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11888c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86); 11898c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11908c2ecf20Sopenharmony_ci V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80); 11918c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11928c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80); 11938c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11948c2ecf20Sopenharmony_ci V4L2_CID_HUE, 0x0, 0xff, 1, 0x80); 11958c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 11968c2ecf20Sopenharmony_ci V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 12008c2ecf20Sopenharmony_ci V4L2_CID_MPEG_STREAM_TYPE, 12018c2ecf20Sopenharmony_ci V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 12028c2ecf20Sopenharmony_ci 0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS); 12038c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 12048c2ecf20Sopenharmony_ci V4L2_CID_MPEG_AUDIO_ENCODING, 12058c2ecf20Sopenharmony_ci ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC, 12068c2ecf20Sopenharmony_ci 0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC); 12078c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 12088c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_ENCODING, 12098c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3, 12108c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 12138c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE_MODE, 12148c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, 12158c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 12188c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE, 12198c2ecf20Sopenharmony_ci 1000000, 13500000, 100000, 6500000); 12208c2ecf20Sopenharmony_ci dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 12218c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, 12228c2ecf20Sopenharmony_ci 1100000, 20200000, 100000, 9000000); 12238c2ecf20Sopenharmony_ci dev->v4l2_dev.ctrl_handler = hdl; 12248c2ecf20Sopenharmony_ci if (hdl->error) { 12258c2ecf20Sopenharmony_ci res = hdl->error; 12268c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "Could not register controls\n"); 12278c2ecf20Sopenharmony_ci goto error; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci v4l2_ctrl_cluster(3, &dev->video_mode); 12308c2ecf20Sopenharmony_ci res = v4l2_ctrl_handler_setup(hdl); 12318c2ecf20Sopenharmony_ci if (res < 0) { 12328c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "Could not setup controls\n"); 12338c2ecf20Sopenharmony_ci goto error; 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci /* setup and register video device */ 12378c2ecf20Sopenharmony_ci dev->video_dev = hdpvr_video_template; 12388c2ecf20Sopenharmony_ci strscpy(dev->video_dev.name, "Hauppauge HD PVR", 12398c2ecf20Sopenharmony_ci sizeof(dev->video_dev.name)); 12408c2ecf20Sopenharmony_ci dev->video_dev.v4l2_dev = &dev->v4l2_dev; 12418c2ecf20Sopenharmony_ci video_set_drvdata(&dev->video_dev, dev); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci res = video_register_device(&dev->video_dev, VFL_TYPE_VIDEO, devnum); 12448c2ecf20Sopenharmony_ci if (res < 0) { 12458c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); 12468c2ecf20Sopenharmony_ci goto error; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci return 0; 12508c2ecf20Sopenharmony_cierror: 12518c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 12528c2ecf20Sopenharmony_ci return res; 12538c2ecf20Sopenharmony_ci} 1254