162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Hauppauge HD PVR USB driver - video 4 linux 2 interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 Janne Grunau (j@jannau.net) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/uaccess.h> 1462306a36Sopenharmony_ci#include <linux/usb.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci#include <linux/workqueue.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/videodev2.h> 1962306a36Sopenharmony_ci#include <linux/v4l2-dv-timings.h> 2062306a36Sopenharmony_ci#include <media/v4l2-dev.h> 2162306a36Sopenharmony_ci#include <media/v4l2-common.h> 2262306a36Sopenharmony_ci#include <media/v4l2-dv-timings.h> 2362306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 2462306a36Sopenharmony_ci#include <media/v4l2-event.h> 2562306a36Sopenharmony_ci#include "hdpvr.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define BULK_URB_TIMEOUT 90 /* 0.09 seconds */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define print_buffer_status() { \ 3062306a36Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \ 3162306a36Sopenharmony_ci "%s:%d buffer stat: %d free, %d proc\n", \ 3262306a36Sopenharmony_ci __func__, __LINE__, \ 3362306a36Sopenharmony_ci list_size(&dev->free_buff_list), \ 3462306a36Sopenharmony_ci list_size(&dev->rec_buff_list)); } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const struct v4l2_dv_timings hdpvr_dv_timings[] = { 3762306a36Sopenharmony_ci V4L2_DV_BT_CEA_720X480I59_94, 3862306a36Sopenharmony_ci V4L2_DV_BT_CEA_720X576I50, 3962306a36Sopenharmony_ci V4L2_DV_BT_CEA_720X480P59_94, 4062306a36Sopenharmony_ci V4L2_DV_BT_CEA_720X576P50, 4162306a36Sopenharmony_ci V4L2_DV_BT_CEA_1280X720P50, 4262306a36Sopenharmony_ci V4L2_DV_BT_CEA_1280X720P60, 4362306a36Sopenharmony_ci V4L2_DV_BT_CEA_1920X1080I50, 4462306a36Sopenharmony_ci V4L2_DV_BT_CEA_1920X1080I60, 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* Use 480i59 as the default timings */ 4862306a36Sopenharmony_ci#define HDPVR_DEF_DV_TIMINGS_IDX (0) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct hdpvr_fh { 5162306a36Sopenharmony_ci struct v4l2_fh fh; 5262306a36Sopenharmony_ci bool legacy_mode; 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic uint list_size(struct list_head *list) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct list_head *tmp; 5862306a36Sopenharmony_ci uint count = 0; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci list_for_each(tmp, list) { 6162306a36Sopenharmony_ci count++; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return count; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/*=========================================================================*/ 6862306a36Sopenharmony_ci/* urb callback */ 6962306a36Sopenharmony_cistatic void hdpvr_read_bulk_callback(struct urb *urb) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context; 7262306a36Sopenharmony_ci struct hdpvr_device *dev = buf->dev; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* marking buffer as received and wake waiting */ 7562306a36Sopenharmony_ci buf->status = BUFSTAT_READY; 7662306a36Sopenharmony_ci wake_up_interruptible(&dev->wait_data); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/*=========================================================================*/ 8062306a36Sopenharmony_ci/* buffer bits */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 8362306a36Sopenharmony_ciint hdpvr_cancel_queue(struct hdpvr_device *dev) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct hdpvr_buffer *buf; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci list_for_each_entry(buf, &dev->rec_buff_list, buff_list) { 8862306a36Sopenharmony_ci usb_kill_urb(buf->urb); 8962306a36Sopenharmony_ci buf->status = BUFSTAT_AVAILABLE; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int hdpvr_free_queue(struct list_head *q) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct list_head *tmp; 10062306a36Sopenharmony_ci struct list_head *p; 10162306a36Sopenharmony_ci struct hdpvr_buffer *buf; 10262306a36Sopenharmony_ci struct urb *urb; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci for (p = q->next; p != q;) { 10562306a36Sopenharmony_ci buf = list_entry(p, struct hdpvr_buffer, buff_list); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci urb = buf->urb; 10862306a36Sopenharmony_ci usb_free_coherent(urb->dev, urb->transfer_buffer_length, 10962306a36Sopenharmony_ci urb->transfer_buffer, urb->transfer_dma); 11062306a36Sopenharmony_ci usb_free_urb(urb); 11162306a36Sopenharmony_ci tmp = p->next; 11262306a36Sopenharmony_ci list_del(p); 11362306a36Sopenharmony_ci kfree(buf); 11462306a36Sopenharmony_ci p = tmp; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 12162306a36Sopenharmony_ciint hdpvr_free_buffers(struct hdpvr_device *dev) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci hdpvr_cancel_queue(dev); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci hdpvr_free_queue(&dev->free_buff_list); 12662306a36Sopenharmony_ci hdpvr_free_queue(&dev->rec_buff_list); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 13262306a36Sopenharmony_ciint hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci uint i; 13562306a36Sopenharmony_ci int retval = -ENOMEM; 13662306a36Sopenharmony_ci u8 *mem; 13762306a36Sopenharmony_ci struct hdpvr_buffer *buf; 13862306a36Sopenharmony_ci struct urb *urb; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 14162306a36Sopenharmony_ci "allocating %u buffers\n", count); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL); 14662306a36Sopenharmony_ci if (!buf) { 14762306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n"); 14862306a36Sopenharmony_ci goto exit; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci buf->dev = dev; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 15362306a36Sopenharmony_ci if (!urb) 15462306a36Sopenharmony_ci goto exit_urb; 15562306a36Sopenharmony_ci buf->urb = urb; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL, 15862306a36Sopenharmony_ci &urb->transfer_dma); 15962306a36Sopenharmony_ci if (!mem) { 16062306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 16162306a36Sopenharmony_ci "cannot allocate usb transfer buffer\n"); 16262306a36Sopenharmony_ci goto exit_urb_buffer; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci usb_fill_bulk_urb(buf->urb, dev->udev, 16662306a36Sopenharmony_ci usb_rcvbulkpipe(dev->udev, 16762306a36Sopenharmony_ci dev->bulk_in_endpointAddr), 16862306a36Sopenharmony_ci mem, dev->bulk_in_size, 16962306a36Sopenharmony_ci hdpvr_read_bulk_callback, buf); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 17262306a36Sopenharmony_ci buf->status = BUFSTAT_AVAILABLE; 17362306a36Sopenharmony_ci list_add_tail(&buf->buff_list, &dev->free_buff_list); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ciexit_urb_buffer: 17762306a36Sopenharmony_ci usb_free_urb(urb); 17862306a36Sopenharmony_ciexit_urb: 17962306a36Sopenharmony_ci kfree(buf); 18062306a36Sopenharmony_ciexit: 18162306a36Sopenharmony_ci hdpvr_free_buffers(dev); 18262306a36Sopenharmony_ci return retval; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int hdpvr_submit_buffers(struct hdpvr_device *dev) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct hdpvr_buffer *buf; 18862306a36Sopenharmony_ci struct urb *urb; 18962306a36Sopenharmony_ci int ret = 0, err_count = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci while (dev->status == STATUS_STREAMING && 19462306a36Sopenharmony_ci !list_empty(&dev->free_buff_list)) { 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer, 19762306a36Sopenharmony_ci buff_list); 19862306a36Sopenharmony_ci if (buf->status != BUFSTAT_AVAILABLE) { 19962306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 20062306a36Sopenharmony_ci "buffer not marked as available\n"); 20162306a36Sopenharmony_ci ret = -EFAULT; 20262306a36Sopenharmony_ci goto err; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci urb = buf->urb; 20662306a36Sopenharmony_ci urb->status = 0; 20762306a36Sopenharmony_ci urb->actual_length = 0; 20862306a36Sopenharmony_ci ret = usb_submit_urb(urb, GFP_KERNEL); 20962306a36Sopenharmony_ci if (ret) { 21062306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 21162306a36Sopenharmony_ci "usb_submit_urb in %s returned %d\n", 21262306a36Sopenharmony_ci __func__, ret); 21362306a36Sopenharmony_ci if (++err_count > 2) 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci continue; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci buf->status = BUFSTAT_INPROGRESS; 21862306a36Sopenharmony_ci list_move_tail(&buf->buff_list, &dev->rec_buff_list); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_cierr: 22162306a36Sopenharmony_ci print_buffer_status(); 22262306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 22362306a36Sopenharmony_ci return ret; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct hdpvr_buffer *buf; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (list_empty(&dev->rec_buff_list)) { 23362306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 23462306a36Sopenharmony_ci return NULL; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer, 23862306a36Sopenharmony_ci buff_list); 23962306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return buf; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void hdpvr_transmit_buffers(struct work_struct *work) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct hdpvr_device *dev = container_of(work, struct hdpvr_device, 24762306a36Sopenharmony_ci worker); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci while (dev->status == STATUS_STREAMING) { 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (hdpvr_submit_buffers(dev)) { 25262306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n"); 25362306a36Sopenharmony_ci goto error; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci if (wait_event_interruptible(dev->wait_buffer, 25662306a36Sopenharmony_ci !list_empty(&dev->free_buff_list) || 25762306a36Sopenharmony_ci dev->status != STATUS_STREAMING)) 25862306a36Sopenharmony_ci goto error; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 26262306a36Sopenharmony_ci "transmit worker exited\n"); 26362306a36Sopenharmony_ci return; 26462306a36Sopenharmony_cierror: 26562306a36Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 26662306a36Sopenharmony_ci "transmit buffers errored\n"); 26762306a36Sopenharmony_ci dev->status = STATUS_ERROR; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 27162306a36Sopenharmony_cistatic int hdpvr_start_streaming(struct hdpvr_device *dev) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci int ret; 27462306a36Sopenharmony_ci struct hdpvr_video_info vidinf; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (dev->status == STATUS_STREAMING) 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci if (dev->status != STATUS_IDLE) 27962306a36Sopenharmony_ci return -EAGAIN; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ret = get_video_info(dev, &vidinf); 28262306a36Sopenharmony_ci if (ret < 0) 28362306a36Sopenharmony_ci return ret; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!vidinf.valid) { 28662306a36Sopenharmony_ci msleep(250); 28762306a36Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 28862306a36Sopenharmony_ci "no video signal at input %d\n", dev->options.video_input); 28962306a36Sopenharmony_ci return -EAGAIN; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 29362306a36Sopenharmony_ci "video signal: %dx%d@%dhz\n", vidinf.width, 29462306a36Sopenharmony_ci vidinf.height, vidinf.fps); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* start streaming 2 request */ 29762306a36Sopenharmony_ci ret = usb_control_msg(dev->udev, 29862306a36Sopenharmony_ci usb_sndctrlpipe(dev->udev, 0), 29962306a36Sopenharmony_ci 0xb8, 0x38, 0x1, 0, NULL, 0, 8000); 30062306a36Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 30162306a36Sopenharmony_ci "encoder start control request returned %d\n", ret); 30262306a36Sopenharmony_ci if (ret < 0) 30362306a36Sopenharmony_ci return ret; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00); 30662306a36Sopenharmony_ci if (ret) 30762306a36Sopenharmony_ci return ret; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci dev->status = STATUS_STREAMING; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci schedule_work(&dev->worker); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 31462306a36Sopenharmony_ci "streaming started\n"); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* function expects dev->io_mutex to be hold by caller */ 32162306a36Sopenharmony_cistatic int hdpvr_stop_streaming(struct hdpvr_device *dev) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci int actual_length; 32462306a36Sopenharmony_ci uint c = 0; 32562306a36Sopenharmony_ci u8 *buf; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (dev->status == STATUS_IDLE) 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci else if (dev->status != STATUS_STREAMING) 33062306a36Sopenharmony_ci return -EAGAIN; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci buf = kmalloc(dev->bulk_in_size, GFP_KERNEL); 33362306a36Sopenharmony_ci if (!buf) 33462306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer for emptying the internal device buffer. Next capture start will be slow\n"); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci dev->status = STATUS_SHUTTING_DOWN; 33762306a36Sopenharmony_ci hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00); 33862306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci wake_up_interruptible(&dev->wait_buffer); 34162306a36Sopenharmony_ci msleep(50); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci flush_work(&dev->worker); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 34662306a36Sopenharmony_ci /* kill the still outstanding urbs */ 34762306a36Sopenharmony_ci hdpvr_cancel_queue(dev); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* emptying the device buffer beforeshutting it down */ 35062306a36Sopenharmony_ci while (buf && ++c < 500 && 35162306a36Sopenharmony_ci !usb_bulk_msg(dev->udev, 35262306a36Sopenharmony_ci usb_rcvbulkpipe(dev->udev, 35362306a36Sopenharmony_ci dev->bulk_in_endpointAddr), 35462306a36Sopenharmony_ci buf, dev->bulk_in_size, &actual_length, 35562306a36Sopenharmony_ci BULK_URB_TIMEOUT)) { 35662306a36Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 35762306a36Sopenharmony_ci "%2d: got %d bytes\n", c, actual_length); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci kfree(buf); 36062306a36Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 36162306a36Sopenharmony_ci "used %d urbs to empty device buffers\n", c-1); 36262306a36Sopenharmony_ci msleep(10); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci dev->status = STATUS_IDLE; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/*=======================================================================*/ 37162306a36Sopenharmony_ci/* 37262306a36Sopenharmony_ci * video 4 linux 2 file operations 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic int hdpvr_open(struct file *file) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (fh == NULL) 38062306a36Sopenharmony_ci return -ENOMEM; 38162306a36Sopenharmony_ci fh->legacy_mode = true; 38262306a36Sopenharmony_ci v4l2_fh_init(&fh->fh, video_devdata(file)); 38362306a36Sopenharmony_ci v4l2_fh_add(&fh->fh); 38462306a36Sopenharmony_ci file->private_data = fh; 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int hdpvr_release(struct file *file) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 39362306a36Sopenharmony_ci if (file->private_data == dev->owner) { 39462306a36Sopenharmony_ci hdpvr_stop_streaming(dev); 39562306a36Sopenharmony_ci dev->owner = NULL; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return v4l2_fh_release(file); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* 40362306a36Sopenharmony_ci * hdpvr_v4l2_read() 40462306a36Sopenharmony_ci * will allocate buffers when called for the first time 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_cistatic ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, 40762306a36Sopenharmony_ci loff_t *pos) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 41062306a36Sopenharmony_ci struct hdpvr_buffer *buf = NULL; 41162306a36Sopenharmony_ci struct urb *urb; 41262306a36Sopenharmony_ci int ret = 0; 41362306a36Sopenharmony_ci int rem, cnt; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (*pos) 41662306a36Sopenharmony_ci return -ESPIPE; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 41962306a36Sopenharmony_ci if (dev->status == STATUS_IDLE) { 42062306a36Sopenharmony_ci if (hdpvr_start_streaming(dev)) { 42162306a36Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 42262306a36Sopenharmony_ci "start_streaming failed\n"); 42362306a36Sopenharmony_ci ret = -EIO; 42462306a36Sopenharmony_ci msleep(200); 42562306a36Sopenharmony_ci dev->status = STATUS_IDLE; 42662306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 42762306a36Sopenharmony_ci goto err; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci dev->owner = file->private_data; 43062306a36Sopenharmony_ci print_buffer_status(); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* wait for the first buffer */ 43562306a36Sopenharmony_ci if (!(file->f_flags & O_NONBLOCK)) { 43662306a36Sopenharmony_ci if (wait_event_interruptible(dev->wait_data, 43762306a36Sopenharmony_ci !list_empty_careful(&dev->rec_buff_list))) 43862306a36Sopenharmony_ci return -ERESTARTSYS; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci while (count > 0 && buf) { 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (buf->status != BUFSTAT_READY && 44662306a36Sopenharmony_ci dev->status != STATUS_DISCONNECTED) { 44762306a36Sopenharmony_ci int err; 44862306a36Sopenharmony_ci /* return nonblocking */ 44962306a36Sopenharmony_ci if (file->f_flags & O_NONBLOCK) { 45062306a36Sopenharmony_ci if (!ret) 45162306a36Sopenharmony_ci ret = -EAGAIN; 45262306a36Sopenharmony_ci goto err; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci err = wait_event_interruptible_timeout(dev->wait_data, 45662306a36Sopenharmony_ci buf->status == BUFSTAT_READY, 45762306a36Sopenharmony_ci msecs_to_jiffies(1000)); 45862306a36Sopenharmony_ci if (err < 0) { 45962306a36Sopenharmony_ci ret = err; 46062306a36Sopenharmony_ci goto err; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci if (!err) { 46362306a36Sopenharmony_ci v4l2_info(&dev->v4l2_dev, 46462306a36Sopenharmony_ci "timeout: restart streaming\n"); 46562306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 46662306a36Sopenharmony_ci hdpvr_stop_streaming(dev); 46762306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * The FW needs about 4 seconds after streaming 47062306a36Sopenharmony_ci * stopped before it is ready to restart 47162306a36Sopenharmony_ci * streaming. 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci msleep(4000); 47462306a36Sopenharmony_ci err = hdpvr_start_streaming(dev); 47562306a36Sopenharmony_ci if (err) { 47662306a36Sopenharmony_ci ret = err; 47762306a36Sopenharmony_ci goto err; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (buf->status != BUFSTAT_READY) 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* set remaining bytes to copy */ 48662306a36Sopenharmony_ci urb = buf->urb; 48762306a36Sopenharmony_ci rem = urb->actual_length - buf->pos; 48862306a36Sopenharmony_ci cnt = rem > count ? count : rem; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (copy_to_user(buffer, urb->transfer_buffer + buf->pos, 49162306a36Sopenharmony_ci cnt)) { 49262306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n"); 49362306a36Sopenharmony_ci if (!ret) 49462306a36Sopenharmony_ci ret = -EFAULT; 49562306a36Sopenharmony_ci goto err; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci buf->pos += cnt; 49962306a36Sopenharmony_ci count -= cnt; 50062306a36Sopenharmony_ci buffer += cnt; 50162306a36Sopenharmony_ci ret += cnt; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* finished, take next buffer */ 50462306a36Sopenharmony_ci if (buf->pos == urb->actual_length) { 50562306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 50662306a36Sopenharmony_ci buf->pos = 0; 50762306a36Sopenharmony_ci buf->status = BUFSTAT_AVAILABLE; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci list_move_tail(&buf->buff_list, &dev->free_buff_list); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci print_buffer_status(); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci wake_up_interruptible(&dev->wait_buffer); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_cierr: 52162306a36Sopenharmony_ci if (!ret && !buf) 52262306a36Sopenharmony_ci ret = -EAGAIN; 52362306a36Sopenharmony_ci return ret; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic __poll_t hdpvr_poll(struct file *filp, poll_table *wait) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci __poll_t req_events = poll_requested_events(wait); 52962306a36Sopenharmony_ci struct hdpvr_buffer *buf = NULL; 53062306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(filp); 53162306a36Sopenharmony_ci __poll_t mask = v4l2_ctrl_poll(filp, wait); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (!(req_events & (EPOLLIN | EPOLLRDNORM))) 53462306a36Sopenharmony_ci return mask; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (dev->status == STATUS_IDLE) { 53962306a36Sopenharmony_ci if (hdpvr_start_streaming(dev)) { 54062306a36Sopenharmony_ci v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, 54162306a36Sopenharmony_ci "start_streaming failed\n"); 54262306a36Sopenharmony_ci dev->status = STATUS_IDLE; 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci dev->owner = filp->private_data; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci print_buffer_status(); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 55262306a36Sopenharmony_ci /* only wait if no data is available */ 55362306a36Sopenharmony_ci if (!buf || buf->status != BUFSTAT_READY) { 55462306a36Sopenharmony_ci poll_wait(filp, &dev->wait_data, wait); 55562306a36Sopenharmony_ci buf = hdpvr_get_next_buffer(dev); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci if (buf && buf->status == BUFSTAT_READY) 55862306a36Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return mask; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic const struct v4l2_file_operations hdpvr_fops = { 56562306a36Sopenharmony_ci .owner = THIS_MODULE, 56662306a36Sopenharmony_ci .open = hdpvr_open, 56762306a36Sopenharmony_ci .release = hdpvr_release, 56862306a36Sopenharmony_ci .read = hdpvr_read, 56962306a36Sopenharmony_ci .poll = hdpvr_poll, 57062306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 57162306a36Sopenharmony_ci}; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/*=======================================================================*/ 57462306a36Sopenharmony_ci/* 57562306a36Sopenharmony_ci * V4L2 ioctl handling 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int vidioc_querycap(struct file *file, void *priv, 57962306a36Sopenharmony_ci struct v4l2_capability *cap) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci strscpy(cap->driver, "hdpvr", sizeof(cap->driver)); 58462306a36Sopenharmony_ci strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card)); 58562306a36Sopenharmony_ci usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); 58662306a36Sopenharmony_ci return 0; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *_fh, 59062306a36Sopenharmony_ci v4l2_std_id std) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 59362306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 59462306a36Sopenharmony_ci u8 std_type = 1; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) 59762306a36Sopenharmony_ci return -ENODATA; 59862306a36Sopenharmony_ci if (dev->status != STATUS_IDLE) 59962306a36Sopenharmony_ci return -EBUSY; 60062306a36Sopenharmony_ci if (std & V4L2_STD_525_60) 60162306a36Sopenharmony_ci std_type = 0; 60262306a36Sopenharmony_ci dev->cur_std = std; 60362306a36Sopenharmony_ci dev->width = 720; 60462306a36Sopenharmony_ci dev->height = std_type ? 576 : 480; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *_fh, 61062306a36Sopenharmony_ci v4l2_std_id *std) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 61362306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) 61662306a36Sopenharmony_ci return -ENODATA; 61762306a36Sopenharmony_ci *std = dev->cur_std; 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 62462306a36Sopenharmony_ci struct hdpvr_video_info vid_info; 62562306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 62662306a36Sopenharmony_ci int ret; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci *a = V4L2_STD_UNKNOWN; 62962306a36Sopenharmony_ci if (dev->options.video_input == HDPVR_COMPONENT) 63062306a36Sopenharmony_ci return fh->legacy_mode ? 0 : -ENODATA; 63162306a36Sopenharmony_ci ret = get_video_info(dev, &vid_info); 63262306a36Sopenharmony_ci if (vid_info.valid && vid_info.width == 720 && 63362306a36Sopenharmony_ci (vid_info.height == 480 || vid_info.height == 576)) { 63462306a36Sopenharmony_ci *a = (vid_info.height == 480) ? 63562306a36Sopenharmony_ci V4L2_STD_525_60 : V4L2_STD_625_50; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci return ret; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int vidioc_s_dv_timings(struct file *file, void *_fh, 64162306a36Sopenharmony_ci struct v4l2_dv_timings *timings) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 64462306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 64562306a36Sopenharmony_ci int i; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci fh->legacy_mode = false; 64862306a36Sopenharmony_ci if (dev->options.video_input) 64962306a36Sopenharmony_ci return -ENODATA; 65062306a36Sopenharmony_ci if (dev->status != STATUS_IDLE) 65162306a36Sopenharmony_ci return -EBUSY; 65262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) 65362306a36Sopenharmony_ci if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false)) 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci if (i == ARRAY_SIZE(hdpvr_dv_timings)) 65662306a36Sopenharmony_ci return -EINVAL; 65762306a36Sopenharmony_ci dev->cur_dv_timings = hdpvr_dv_timings[i]; 65862306a36Sopenharmony_ci dev->width = hdpvr_dv_timings[i].bt.width; 65962306a36Sopenharmony_ci dev->height = hdpvr_dv_timings[i].bt.height; 66062306a36Sopenharmony_ci return 0; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic int vidioc_g_dv_timings(struct file *file, void *_fh, 66462306a36Sopenharmony_ci struct v4l2_dv_timings *timings) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 66762306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci fh->legacy_mode = false; 67062306a36Sopenharmony_ci if (dev->options.video_input) 67162306a36Sopenharmony_ci return -ENODATA; 67262306a36Sopenharmony_ci *timings = dev->cur_dv_timings; 67362306a36Sopenharmony_ci return 0; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic int vidioc_query_dv_timings(struct file *file, void *_fh, 67762306a36Sopenharmony_ci struct v4l2_dv_timings *timings) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 68062306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 68162306a36Sopenharmony_ci struct hdpvr_video_info vid_info; 68262306a36Sopenharmony_ci bool interlaced; 68362306a36Sopenharmony_ci int ret = 0; 68462306a36Sopenharmony_ci int i; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci fh->legacy_mode = false; 68762306a36Sopenharmony_ci if (dev->options.video_input) 68862306a36Sopenharmony_ci return -ENODATA; 68962306a36Sopenharmony_ci ret = get_video_info(dev, &vid_info); 69062306a36Sopenharmony_ci if (ret) 69162306a36Sopenharmony_ci return ret; 69262306a36Sopenharmony_ci if (!vid_info.valid) 69362306a36Sopenharmony_ci return -ENOLCK; 69462306a36Sopenharmony_ci interlaced = vid_info.fps <= 30; 69562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) { 69662306a36Sopenharmony_ci const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt; 69762306a36Sopenharmony_ci unsigned hsize; 69862306a36Sopenharmony_ci unsigned vsize; 69962306a36Sopenharmony_ci unsigned fps; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci hsize = V4L2_DV_BT_FRAME_WIDTH(bt); 70262306a36Sopenharmony_ci vsize = V4L2_DV_BT_FRAME_HEIGHT(bt); 70362306a36Sopenharmony_ci fps = (unsigned)bt->pixelclock / (hsize * vsize); 70462306a36Sopenharmony_ci if (bt->width != vid_info.width || 70562306a36Sopenharmony_ci bt->height != vid_info.height || 70662306a36Sopenharmony_ci bt->interlaced != interlaced || 70762306a36Sopenharmony_ci (fps != vid_info.fps && fps + 1 != vid_info.fps)) 70862306a36Sopenharmony_ci continue; 70962306a36Sopenharmony_ci *timings = hdpvr_dv_timings[i]; 71062306a36Sopenharmony_ci break; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci if (i == ARRAY_SIZE(hdpvr_dv_timings)) 71362306a36Sopenharmony_ci ret = -ERANGE; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci return ret; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic int vidioc_enum_dv_timings(struct file *file, void *_fh, 71962306a36Sopenharmony_ci struct v4l2_enum_dv_timings *timings) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 72262306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci fh->legacy_mode = false; 72562306a36Sopenharmony_ci memset(timings->reserved, 0, sizeof(timings->reserved)); 72662306a36Sopenharmony_ci if (dev->options.video_input) 72762306a36Sopenharmony_ci return -ENODATA; 72862306a36Sopenharmony_ci if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings)) 72962306a36Sopenharmony_ci return -EINVAL; 73062306a36Sopenharmony_ci timings->timings = hdpvr_dv_timings[timings->index]; 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic int vidioc_dv_timings_cap(struct file *file, void *_fh, 73562306a36Sopenharmony_ci struct v4l2_dv_timings_cap *cap) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 73862306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci fh->legacy_mode = false; 74162306a36Sopenharmony_ci if (dev->options.video_input) 74262306a36Sopenharmony_ci return -ENODATA; 74362306a36Sopenharmony_ci cap->type = V4L2_DV_BT_656_1120; 74462306a36Sopenharmony_ci cap->bt.min_width = 720; 74562306a36Sopenharmony_ci cap->bt.max_width = 1920; 74662306a36Sopenharmony_ci cap->bt.min_height = 480; 74762306a36Sopenharmony_ci cap->bt.max_height = 1080; 74862306a36Sopenharmony_ci cap->bt.min_pixelclock = 27000000; 74962306a36Sopenharmony_ci cap->bt.max_pixelclock = 74250000; 75062306a36Sopenharmony_ci cap->bt.standards = V4L2_DV_BT_STD_CEA861; 75162306a36Sopenharmony_ci cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE; 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic const char *iname[] = { 75662306a36Sopenharmony_ci [HDPVR_COMPONENT] = "Component", 75762306a36Sopenharmony_ci [HDPVR_SVIDEO] = "S-Video", 75862306a36Sopenharmony_ci [HDPVR_COMPOSITE] = "Composite", 75962306a36Sopenharmony_ci}; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci unsigned int n; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci n = i->index; 76662306a36Sopenharmony_ci if (n >= HDPVR_VIDEO_INPUTS) 76762306a36Sopenharmony_ci return -EINVAL; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci i->type = V4L2_INPUT_TYPE_CAMERA; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci strscpy(i->name, iname[n], sizeof(i->name)); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS; 77662306a36Sopenharmony_ci i->std = n ? V4L2_STD_ALL : 0; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic int vidioc_s_input(struct file *file, void *_fh, 78262306a36Sopenharmony_ci unsigned int index) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 78562306a36Sopenharmony_ci int retval; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (index >= HDPVR_VIDEO_INPUTS) 78862306a36Sopenharmony_ci return -EINVAL; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (dev->status != STATUS_IDLE) 79162306a36Sopenharmony_ci return -EBUSY; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); 79462306a36Sopenharmony_ci if (!retval) { 79562306a36Sopenharmony_ci dev->options.video_input = index; 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * Unfortunately gstreamer calls ENUMSTD and bails out if it 79862306a36Sopenharmony_ci * won't find any formats, even though component input is 79962306a36Sopenharmony_ci * selected. This means that we have to leave tvnorms at 80062306a36Sopenharmony_ci * V4L2_STD_ALL. We cannot use the 'legacy' trick since 80162306a36Sopenharmony_ci * tvnorms is set at the device node level and not at the 80262306a36Sopenharmony_ci * filehandle level. 80362306a36Sopenharmony_ci * 80462306a36Sopenharmony_ci * Comment this out for now, but if the legacy mode can be 80562306a36Sopenharmony_ci * removed in the future, then this code should be enabled 80662306a36Sopenharmony_ci * again. 80762306a36Sopenharmony_ci dev->video_dev.tvnorms = 80862306a36Sopenharmony_ci (index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0; 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return retval; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int vidioc_g_input(struct file *file, void *private_data, 81662306a36Sopenharmony_ci unsigned int *index) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci *index = dev->options.video_input; 82162306a36Sopenharmony_ci return 0; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic const char *audio_iname[] = { 82662306a36Sopenharmony_ci [HDPVR_RCA_FRONT] = "RCA front", 82762306a36Sopenharmony_ci [HDPVR_RCA_BACK] = "RCA back", 82862306a36Sopenharmony_ci [HDPVR_SPDIF] = "SPDIF", 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic int vidioc_enumaudio(struct file *file, void *priv, 83262306a36Sopenharmony_ci struct v4l2_audio *audio) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci unsigned int n; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci n = audio->index; 83762306a36Sopenharmony_ci if (n >= HDPVR_AUDIO_INPUTS) 83862306a36Sopenharmony_ci return -EINVAL; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci audio->capability = V4L2_AUDCAP_STEREO; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci strscpy(audio->name, audio_iname[n], sizeof(audio->name)); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int vidioc_s_audio(struct file *file, void *private_data, 84862306a36Sopenharmony_ci const struct v4l2_audio *audio) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 85162306a36Sopenharmony_ci int retval; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (audio->index >= HDPVR_AUDIO_INPUTS) 85462306a36Sopenharmony_ci return -EINVAL; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (dev->status != STATUS_IDLE) 85762306a36Sopenharmony_ci return -EBUSY; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec); 86062306a36Sopenharmony_ci if (!retval) 86162306a36Sopenharmony_ci dev->options.audio_input = audio->index; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return retval; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic int vidioc_g_audio(struct file *file, void *private_data, 86762306a36Sopenharmony_ci struct v4l2_audio *audio) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci audio->index = dev->options.audio_input; 87262306a36Sopenharmony_ci audio->capability = V4L2_AUDCAP_STEREO; 87362306a36Sopenharmony_ci strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name)); 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct hdpvr_device *dev = 88062306a36Sopenharmony_ci container_of(ctrl->handler, struct hdpvr_device, hdl); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci switch (ctrl->id) { 88362306a36Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: 88462306a36Sopenharmony_ci if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && 88562306a36Sopenharmony_ci dev->video_bitrate->val >= dev->video_bitrate_peak->val) 88662306a36Sopenharmony_ci dev->video_bitrate_peak->val = 88762306a36Sopenharmony_ci dev->video_bitrate->val + 100000; 88862306a36Sopenharmony_ci break; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci return 0; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct hdpvr_device *dev = 89662306a36Sopenharmony_ci container_of(ctrl->handler, struct hdpvr_device, hdl); 89762306a36Sopenharmony_ci struct hdpvr_options *opt = &dev->options; 89862306a36Sopenharmony_ci int ret = -EINVAL; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci switch (ctrl->id) { 90162306a36Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 90262306a36Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val); 90362306a36Sopenharmony_ci if (ret) 90462306a36Sopenharmony_ci break; 90562306a36Sopenharmony_ci dev->options.brightness = ctrl->val; 90662306a36Sopenharmony_ci return 0; 90762306a36Sopenharmony_ci case V4L2_CID_CONTRAST: 90862306a36Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val); 90962306a36Sopenharmony_ci if (ret) 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci dev->options.contrast = ctrl->val; 91262306a36Sopenharmony_ci return 0; 91362306a36Sopenharmony_ci case V4L2_CID_SATURATION: 91462306a36Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val); 91562306a36Sopenharmony_ci if (ret) 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci dev->options.saturation = ctrl->val; 91862306a36Sopenharmony_ci return 0; 91962306a36Sopenharmony_ci case V4L2_CID_HUE: 92062306a36Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val); 92162306a36Sopenharmony_ci if (ret) 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci dev->options.hue = ctrl->val; 92462306a36Sopenharmony_ci return 0; 92562306a36Sopenharmony_ci case V4L2_CID_SHARPNESS: 92662306a36Sopenharmony_ci ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val); 92762306a36Sopenharmony_ci if (ret) 92862306a36Sopenharmony_ci break; 92962306a36Sopenharmony_ci dev->options.sharpness = ctrl->val; 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_ci case V4L2_CID_MPEG_AUDIO_ENCODING: 93262306a36Sopenharmony_ci if (dev->flags & HDPVR_FLAG_AC3_CAP) { 93362306a36Sopenharmony_ci opt->audio_codec = ctrl->val; 93462306a36Sopenharmony_ci return hdpvr_set_audio(dev, opt->audio_input + 1, 93562306a36Sopenharmony_ci opt->audio_codec); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci return 0; 93862306a36Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_ENCODING: 93962306a36Sopenharmony_ci return 0; 94062306a36Sopenharmony_ci/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ 94162306a36Sopenharmony_ci/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */ 94262306a36Sopenharmony_ci/* opt->gop_mode |= 0x2; */ 94362306a36Sopenharmony_ci/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ 94462306a36Sopenharmony_ci/* opt->gop_mode); */ 94562306a36Sopenharmony_ci/* } */ 94662306a36Sopenharmony_ci/* if (ctrl->value == 128 && opt->gop_mode & 0x2) { */ 94762306a36Sopenharmony_ci/* opt->gop_mode &= ~0x2; */ 94862306a36Sopenharmony_ci/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ 94962306a36Sopenharmony_ci/* opt->gop_mode); */ 95062306a36Sopenharmony_ci/* } */ 95162306a36Sopenharmony_ci/* break; */ 95262306a36Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { 95362306a36Sopenharmony_ci uint peak_bitrate = dev->video_bitrate_peak->val / 100000; 95462306a36Sopenharmony_ci uint bitrate = dev->video_bitrate->val / 100000; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (ctrl->is_new) { 95762306a36Sopenharmony_ci if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) 95862306a36Sopenharmony_ci opt->bitrate_mode = HDPVR_CONSTANT; 95962306a36Sopenharmony_ci else 96062306a36Sopenharmony_ci opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE; 96162306a36Sopenharmony_ci hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, 96262306a36Sopenharmony_ci opt->bitrate_mode); 96362306a36Sopenharmony_ci v4l2_ctrl_activate(dev->video_bitrate_peak, 96462306a36Sopenharmony_ci ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci if (dev->video_bitrate_peak->is_new || 96862306a36Sopenharmony_ci dev->video_bitrate->is_new) { 96962306a36Sopenharmony_ci opt->bitrate = bitrate; 97062306a36Sopenharmony_ci opt->peak_bitrate = peak_bitrate; 97162306a36Sopenharmony_ci hdpvr_set_bitrate(dev); 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci return 0; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci case V4L2_CID_MPEG_STREAM_TYPE: 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci default: 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci return ret; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, 98462306a36Sopenharmony_ci struct v4l2_fmtdesc *f) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci if (f->index != 0) 98762306a36Sopenharmony_ci return -EINVAL; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_MPEG; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, 99562306a36Sopenharmony_ci struct v4l2_format *f) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(file); 99862306a36Sopenharmony_ci struct hdpvr_fh *fh = _fh; 99962306a36Sopenharmony_ci int ret; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci /* 100262306a36Sopenharmony_ci * The original driver would always returns the current detected 100362306a36Sopenharmony_ci * resolution as the format (and EFAULT if it couldn't be detected). 100462306a36Sopenharmony_ci * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a 100562306a36Sopenharmony_ci * better way of doing this, but to stay compatible with existing 100662306a36Sopenharmony_ci * applications we assume legacy mode every time an application opens 100762306a36Sopenharmony_ci * the device. Only if one of the new DV_TIMINGS ioctls is called 100862306a36Sopenharmony_ci * will the filehandle go into 'normal' mode where g_fmt returns the 100962306a36Sopenharmony_ci * last set format. 101062306a36Sopenharmony_ci */ 101162306a36Sopenharmony_ci if (fh->legacy_mode) { 101262306a36Sopenharmony_ci struct hdpvr_video_info vid_info; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ret = get_video_info(dev, &vid_info); 101562306a36Sopenharmony_ci if (ret < 0) 101662306a36Sopenharmony_ci return ret; 101762306a36Sopenharmony_ci if (!vid_info.valid) 101862306a36Sopenharmony_ci return -EFAULT; 101962306a36Sopenharmony_ci f->fmt.pix.width = vid_info.width; 102062306a36Sopenharmony_ci f->fmt.pix.height = vid_info.height; 102162306a36Sopenharmony_ci } else { 102262306a36Sopenharmony_ci f->fmt.pix.width = dev->width; 102362306a36Sopenharmony_ci f->fmt.pix.height = dev->height; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 102662306a36Sopenharmony_ci f->fmt.pix.sizeimage = dev->bulk_in_size; 102762306a36Sopenharmony_ci f->fmt.pix.bytesperline = 0; 102862306a36Sopenharmony_ci if (f->fmt.pix.width == 720) { 102962306a36Sopenharmony_ci /* SDTV formats */ 103062306a36Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 103162306a36Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_INTERLACED; 103262306a36Sopenharmony_ci } else { 103362306a36Sopenharmony_ci /* HDTV formats */ 103462306a36Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; 103562306a36Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_NONE; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic int vidioc_encoder_cmd(struct file *filp, void *priv, 104162306a36Sopenharmony_ci struct v4l2_encoder_cmd *a) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct hdpvr_device *dev = video_drvdata(filp); 104462306a36Sopenharmony_ci int res = 0; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci mutex_lock(&dev->io_mutex); 104762306a36Sopenharmony_ci a->flags = 0; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci switch (a->cmd) { 105062306a36Sopenharmony_ci case V4L2_ENC_CMD_START: 105162306a36Sopenharmony_ci if (dev->owner && filp->private_data != dev->owner) { 105262306a36Sopenharmony_ci res = -EBUSY; 105362306a36Sopenharmony_ci break; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci if (dev->status == STATUS_STREAMING) 105662306a36Sopenharmony_ci break; 105762306a36Sopenharmony_ci res = hdpvr_start_streaming(dev); 105862306a36Sopenharmony_ci if (!res) 105962306a36Sopenharmony_ci dev->owner = filp->private_data; 106062306a36Sopenharmony_ci else 106162306a36Sopenharmony_ci dev->status = STATUS_IDLE; 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci case V4L2_ENC_CMD_STOP: 106462306a36Sopenharmony_ci if (dev->owner && filp->private_data != dev->owner) { 106562306a36Sopenharmony_ci res = -EBUSY; 106662306a36Sopenharmony_ci break; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci if (dev->status == STATUS_IDLE) 106962306a36Sopenharmony_ci break; 107062306a36Sopenharmony_ci res = hdpvr_stop_streaming(dev); 107162306a36Sopenharmony_ci if (!res) 107262306a36Sopenharmony_ci dev->owner = NULL; 107362306a36Sopenharmony_ci break; 107462306a36Sopenharmony_ci default: 107562306a36Sopenharmony_ci v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, 107662306a36Sopenharmony_ci "Unsupported encoder cmd %d\n", a->cmd); 107762306a36Sopenharmony_ci res = -EINVAL; 107862306a36Sopenharmony_ci break; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci mutex_unlock(&dev->io_mutex); 108262306a36Sopenharmony_ci return res; 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic int vidioc_try_encoder_cmd(struct file *filp, void *priv, 108662306a36Sopenharmony_ci struct v4l2_encoder_cmd *a) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci a->flags = 0; 108962306a36Sopenharmony_ci switch (a->cmd) { 109062306a36Sopenharmony_ci case V4L2_ENC_CMD_START: 109162306a36Sopenharmony_ci case V4L2_ENC_CMD_STOP: 109262306a36Sopenharmony_ci return 0; 109362306a36Sopenharmony_ci default: 109462306a36Sopenharmony_ci return -EINVAL; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { 109962306a36Sopenharmony_ci .vidioc_querycap = vidioc_querycap, 110062306a36Sopenharmony_ci .vidioc_s_std = vidioc_s_std, 110162306a36Sopenharmony_ci .vidioc_g_std = vidioc_g_std, 110262306a36Sopenharmony_ci .vidioc_querystd = vidioc_querystd, 110362306a36Sopenharmony_ci .vidioc_s_dv_timings = vidioc_s_dv_timings, 110462306a36Sopenharmony_ci .vidioc_g_dv_timings = vidioc_g_dv_timings, 110562306a36Sopenharmony_ci .vidioc_query_dv_timings= vidioc_query_dv_timings, 110662306a36Sopenharmony_ci .vidioc_enum_dv_timings = vidioc_enum_dv_timings, 110762306a36Sopenharmony_ci .vidioc_dv_timings_cap = vidioc_dv_timings_cap, 110862306a36Sopenharmony_ci .vidioc_enum_input = vidioc_enum_input, 110962306a36Sopenharmony_ci .vidioc_g_input = vidioc_g_input, 111062306a36Sopenharmony_ci .vidioc_s_input = vidioc_s_input, 111162306a36Sopenharmony_ci .vidioc_enumaudio = vidioc_enumaudio, 111262306a36Sopenharmony_ci .vidioc_g_audio = vidioc_g_audio, 111362306a36Sopenharmony_ci .vidioc_s_audio = vidioc_s_audio, 111462306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap, 111562306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 111662306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap = vidioc_g_fmt_vid_cap, 111762306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap = vidioc_g_fmt_vid_cap, 111862306a36Sopenharmony_ci .vidioc_encoder_cmd = vidioc_encoder_cmd, 111962306a36Sopenharmony_ci .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, 112062306a36Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 112162306a36Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 112262306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 112362306a36Sopenharmony_ci}; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic void hdpvr_device_release(struct video_device *vdev) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci struct hdpvr_device *dev = video_get_drvdata(vdev); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci hdpvr_delete(dev); 113062306a36Sopenharmony_ci flush_work(&dev->worker); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci v4l2_device_unregister(&dev->v4l2_dev); 113362306a36Sopenharmony_ci v4l2_ctrl_handler_free(&dev->hdl); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* deregister I2C adapter */ 113662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C) 113762306a36Sopenharmony_ci mutex_lock(&dev->i2c_mutex); 113862306a36Sopenharmony_ci i2c_del_adapter(&dev->i2c_adapter); 113962306a36Sopenharmony_ci mutex_unlock(&dev->i2c_mutex); 114062306a36Sopenharmony_ci#endif /* CONFIG_I2C */ 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci kfree(dev->usbc_buf); 114362306a36Sopenharmony_ci kfree(dev); 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic const struct video_device hdpvr_video_template = { 114762306a36Sopenharmony_ci .fops = &hdpvr_fops, 114862306a36Sopenharmony_ci .release = hdpvr_device_release, 114962306a36Sopenharmony_ci .ioctl_ops = &hdpvr_ioctl_ops, 115062306a36Sopenharmony_ci .tvnorms = V4L2_STD_ALL, 115162306a36Sopenharmony_ci .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | 115262306a36Sopenharmony_ci V4L2_CAP_READWRITE, 115362306a36Sopenharmony_ci}; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { 115662306a36Sopenharmony_ci .try_ctrl = hdpvr_try_ctrl, 115762306a36Sopenharmony_ci .s_ctrl = hdpvr_s_ctrl, 115862306a36Sopenharmony_ci}; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ciint hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, 116162306a36Sopenharmony_ci int devnum) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &dev->hdl; 116462306a36Sopenharmony_ci bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP; 116562306a36Sopenharmony_ci int res; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci // initialize dev->worker 116862306a36Sopenharmony_ci INIT_WORK(&dev->worker, hdpvr_transmit_buffers); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci dev->cur_std = V4L2_STD_525_60; 117162306a36Sopenharmony_ci dev->width = 720; 117262306a36Sopenharmony_ci dev->height = 480; 117362306a36Sopenharmony_ci dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX]; 117462306a36Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 11); 117562306a36Sopenharmony_ci if (dev->fw_ver > 0x15) { 117662306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 117762306a36Sopenharmony_ci V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80); 117862306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 117962306a36Sopenharmony_ci V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40); 118062306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118162306a36Sopenharmony_ci V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40); 118262306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118362306a36Sopenharmony_ci V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf); 118462306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118562306a36Sopenharmony_ci V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); 118662306a36Sopenharmony_ci } else { 118762306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 118862306a36Sopenharmony_ci V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86); 118962306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119062306a36Sopenharmony_ci V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80); 119162306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119262306a36Sopenharmony_ci V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80); 119362306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119462306a36Sopenharmony_ci V4L2_CID_HUE, 0x0, 0xff, 1, 0x80); 119562306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 119662306a36Sopenharmony_ci V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 120062306a36Sopenharmony_ci V4L2_CID_MPEG_STREAM_TYPE, 120162306a36Sopenharmony_ci V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 120262306a36Sopenharmony_ci 0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS); 120362306a36Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 120462306a36Sopenharmony_ci V4L2_CID_MPEG_AUDIO_ENCODING, 120562306a36Sopenharmony_ci ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC, 120662306a36Sopenharmony_ci 0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC); 120762306a36Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 120862306a36Sopenharmony_ci V4L2_CID_MPEG_VIDEO_ENCODING, 120962306a36Sopenharmony_ci V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3, 121062306a36Sopenharmony_ci V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, 121362306a36Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE_MODE, 121462306a36Sopenharmony_ci V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, 121562306a36Sopenharmony_ci V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 121862306a36Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE, 121962306a36Sopenharmony_ci 1000000, 13500000, 100000, 6500000); 122062306a36Sopenharmony_ci dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, 122162306a36Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, 122262306a36Sopenharmony_ci 1100000, 20200000, 100000, 9000000); 122362306a36Sopenharmony_ci dev->v4l2_dev.ctrl_handler = hdl; 122462306a36Sopenharmony_ci if (hdl->error) { 122562306a36Sopenharmony_ci res = hdl->error; 122662306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "Could not register controls\n"); 122762306a36Sopenharmony_ci goto error; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci v4l2_ctrl_cluster(3, &dev->video_mode); 123062306a36Sopenharmony_ci res = v4l2_ctrl_handler_setup(hdl); 123162306a36Sopenharmony_ci if (res < 0) { 123262306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "Could not setup controls\n"); 123362306a36Sopenharmony_ci goto error; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* setup and register video device */ 123762306a36Sopenharmony_ci dev->video_dev = hdpvr_video_template; 123862306a36Sopenharmony_ci strscpy(dev->video_dev.name, "Hauppauge HD PVR", 123962306a36Sopenharmony_ci sizeof(dev->video_dev.name)); 124062306a36Sopenharmony_ci dev->video_dev.v4l2_dev = &dev->v4l2_dev; 124162306a36Sopenharmony_ci video_set_drvdata(&dev->video_dev, dev); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci res = video_register_device(&dev->video_dev, VFL_TYPE_VIDEO, devnum); 124462306a36Sopenharmony_ci if (res < 0) { 124562306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); 124662306a36Sopenharmony_ci goto error; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_cierror: 125162306a36Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 125262306a36Sopenharmony_ci return res; 125362306a36Sopenharmony_ci} 1254