/* * Copyright (c) 2013,2016 Lubomir Rintel * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Fushicai USBTV007 Audio-Video Grabber Driver * * Product web site: * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html * * Following LWN articles were very useful in construction of this driver: * Video4Linux2 API series: http://lwn.net/Articles/203924/ * videobuf2 API explanation: http://lwn.net/Articles/447435/ * Thanks go to Jonathan Corbet for providing this quality documentation. * He is awesome. * * No physical hardware was harmed running Windows during the * reverse-engineering activity */ #include <media/v4l2-ioctl.h> #include <media/videobuf2-v4l2.h> #include "usbtv.h" static const struct usbtv_norm_params norm_params[] = …; static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) { … } static int usbtv_select_input(struct usbtv *usbtv, int input) { … } static uint16_t usbtv_norm_to_16f_reg(v4l2_std_id norm) { … } static int usbtv_select_norm(struct usbtv *usbtv, v4l2_std_id norm) { … } static int usbtv_setup_capture(struct usbtv *usbtv) { … } /* Copy data from chunk into a frame buffer, deinterlacing the data * into every second line. Unfortunately, they don't align nicely into * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels. * Therefore, we break down the chunk into two halves before copying, * so that we can interleave a line if needed. * * Each "chunk" is 240 words; a word in this context equals 4 bytes. * Image format is YUYV/YUV 4:2:2, consisting of Y Cr Y Cb, defining two * pixels, the Cr and Cb shared between the two pixels, but each having * separate Y values. Thus, the 240 words equal 480 pixels. It therefore, * takes 1.5 chunks to make a 720 pixel-wide line for the frame. * The image is interlaced, so there is a "scan" of odd lines, followed * by "scan" of even numbered lines. * * Following code is writing the chunks in correct sequence, skipping * the rows based on "odd" value. * line 1: chunk[0][ 0..479] chunk[0][480..959] chunk[1][ 0..479] * line 3: chunk[1][480..959] chunk[2][ 0..479] chunk[2][480..959] * ...etc. */ static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd) { … } /* Called for each 256-byte image chunk. * First word identifies the chunk, followed by 240 words of image * data and padding. */ static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk) { … } /* Got image data. Each packet contains a number of 256-word chunks we * compose the image from. */ static void usbtv_iso_cb(struct urb *ip) { … } static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv) { … } static void usbtv_stop(struct usbtv *usbtv) { … } static int usbtv_start(struct usbtv *usbtv) { … } static int usbtv_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { … } static int usbtv_enum_input(struct file *file, void *priv, struct v4l2_input *i) { … } static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { … } static int usbtv_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { … } static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm) { … } static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm) { … } static int usbtv_g_input(struct file *file, void *priv, unsigned int *i) { … } static int usbtv_s_input(struct file *file, void *priv, unsigned int i) { … } static const struct v4l2_ioctl_ops usbtv_ioctl_ops = …; static const struct v4l2_file_operations usbtv_fops = …; static int usbtv_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { … } static void usbtv_buf_queue(struct vb2_buffer *vb) { … } static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count) { … } static void usbtv_stop_streaming(struct vb2_queue *vq) { … } static const struct vb2_ops usbtv_vb2_ops = …; static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) { … } static const struct v4l2_ctrl_ops usbtv_ctrl_ops = …; static void usbtv_release(struct v4l2_device *v4l2_dev) { … } int usbtv_video_init(struct usbtv *usbtv) { … } void usbtv_video_free(struct usbtv *usbtv) { … }