Path: blob/master/drivers/media/video/davinci/vpif_capture.c
17658 views
/*1* Copyright (C) 2009 Texas Instruments Inc2*3* This program is free software; you can redistribute it and/or modify4* it under the terms of the GNU General Public License as published by5* the Free Software Foundation; either version 2 of the License, or6* (at your option) any later version.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*13* You should have received a copy of the GNU General Public License14* along with this program; if not, write to the Free Software15* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA16*17* TODO : add support for VBI & HBI data service18* add static buffer allocation19*/20#include <linux/kernel.h>21#include <linux/init.h>22#include <linux/module.h>23#include <linux/errno.h>24#include <linux/fs.h>25#include <linux/mm.h>26#include <linux/interrupt.h>27#include <linux/workqueue.h>28#include <linux/string.h>29#include <linux/videodev2.h>30#include <linux/wait.h>31#include <linux/time.h>32#include <linux/i2c.h>33#include <linux/platform_device.h>34#include <linux/io.h>35#include <linux/version.h>36#include <linux/slab.h>37#include <media/v4l2-device.h>38#include <media/v4l2-ioctl.h>39#include <media/v4l2-chip-ident.h>4041#include "vpif_capture.h"42#include "vpif.h"4344MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");45MODULE_LICENSE("GPL");4647#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)48#define vpif_dbg(level, debug, fmt, arg...) \49v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)5051static int debug = 1;52static u32 ch0_numbuffers = 3;53static u32 ch1_numbuffers = 3;54static u32 ch0_bufsize = 1920 * 1080 * 2;55static u32 ch1_bufsize = 720 * 576 * 2;5657module_param(debug, int, 0644);58module_param(ch0_numbuffers, uint, S_IRUGO);59module_param(ch1_numbuffers, uint, S_IRUGO);60module_param(ch0_bufsize, uint, S_IRUGO);61module_param(ch1_bufsize, uint, S_IRUGO);6263MODULE_PARM_DESC(debug, "Debug level 0-1");64MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)");65MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)");66MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)");67MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)");6869static struct vpif_config_params config_params = {70.min_numbuffers = 3,71.numbuffers[0] = 3,72.numbuffers[1] = 3,73.min_bufsize[0] = 720 * 480 * 2,74.min_bufsize[1] = 720 * 480 * 2,75.channel_bufsize[0] = 1920 * 1080 * 2,76.channel_bufsize[1] = 720 * 576 * 2,77};7879/* global variables */80static struct vpif_device vpif_obj = { {NULL} };81static struct device *vpif_dev;8283/**84* vpif_uservirt_to_phys : translate user/virtual address to phy address85* @virtp: user/virtual address86*87* This inline function is used to convert user space virtual address to88* physical address.89*/90static inline u32 vpif_uservirt_to_phys(u32 virtp)91{92unsigned long physp = 0;93struct mm_struct *mm = current->mm;94struct vm_area_struct *vma;9596vma = find_vma(mm, virtp);9798/* For kernel direct-mapped memory, take the easy way */99if (virtp >= PAGE_OFFSET)100physp = virt_to_phys((void *)virtp);101else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff))102/**103* this will catch, kernel-allocated, mmaped-to-usermode104* addresses105*/106physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);107else {108/* otherwise, use get_user_pages() for general userland pages */109int res, nr_pages = 1;110struct page *pages;111112down_read(¤t->mm->mmap_sem);113114res = get_user_pages(current, current->mm,115virtp, nr_pages, 1, 0, &pages, NULL);116up_read(¤t->mm->mmap_sem);117118if (res == nr_pages)119physp = __pa(page_address(&pages[0]) +120(virtp & ~PAGE_MASK));121else {122vpif_err("get_user_pages failed\n");123return 0;124}125}126return physp;127}128129/**130* buffer_prepare : callback function for buffer prepare131* @q : buffer queue ptr132* @vb: ptr to video buffer133* @field: field info134*135* This is the callback function for buffer prepare when videobuf_qbuf()136* function is called. The buffer is prepared and user space virtual address137* or user address is converted into physical address138*/139static int vpif_buffer_prepare(struct videobuf_queue *q,140struct videobuf_buffer *vb,141enum v4l2_field field)142{143/* Get the file handle object and channel object */144struct vpif_fh *fh = q->priv_data;145struct channel_obj *ch = fh->channel;146struct common_obj *common;147unsigned long addr;148149150vpif_dbg(2, debug, "vpif_buffer_prepare\n");151152common = &ch->common[VPIF_VIDEO_INDEX];153154/* If buffer is not initialized, initialize it */155if (VIDEOBUF_NEEDS_INIT == vb->state) {156vb->width = common->width;157vb->height = common->height;158vb->size = vb->width * vb->height;159vb->field = field;160}161vb->state = VIDEOBUF_PREPARED;162/**163* if user pointer memory mechanism is used, get the physical164* address of the buffer165*/166if (V4L2_MEMORY_USERPTR == common->memory) {167if (0 == vb->baddr) {168vpif_dbg(1, debug, "buffer address is 0\n");169return -EINVAL;170171}172vb->boff = vpif_uservirt_to_phys(vb->baddr);173if (!IS_ALIGNED(vb->boff, 8))174goto exit;175}176177addr = vb->boff;178if (q->streaming) {179if (!IS_ALIGNED((addr + common->ytop_off), 8) ||180!IS_ALIGNED((addr + common->ybtm_off), 8) ||181!IS_ALIGNED((addr + common->ctop_off), 8) ||182!IS_ALIGNED((addr + common->cbtm_off), 8))183goto exit;184}185return 0;186exit:187vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n");188return -EINVAL;189}190191/**192* vpif_buffer_setup : Callback function for buffer setup.193* @q: buffer queue ptr194* @count: number of buffers195* @size: size of the buffer196*197* This callback function is called when reqbuf() is called to adjust198* the buffer count and buffer size199*/200static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count,201unsigned int *size)202{203/* Get the file handle object and channel object */204struct vpif_fh *fh = q->priv_data;205struct channel_obj *ch = fh->channel;206struct common_obj *common;207208common = &ch->common[VPIF_VIDEO_INDEX];209210vpif_dbg(2, debug, "vpif_buffer_setup\n");211212/* If memory type is not mmap, return */213if (V4L2_MEMORY_MMAP != common->memory)214return 0;215216/* Calculate the size of the buffer */217*size = config_params.channel_bufsize[ch->channel_id];218219if (*count < config_params.min_numbuffers)220*count = config_params.min_numbuffers;221return 0;222}223224/**225* vpif_buffer_queue : Callback function to add buffer to DMA queue226* @q: ptr to videobuf_queue227* @vb: ptr to videobuf_buffer228*/229static void vpif_buffer_queue(struct videobuf_queue *q,230struct videobuf_buffer *vb)231{232/* Get the file handle object and channel object */233struct vpif_fh *fh = q->priv_data;234struct channel_obj *ch = fh->channel;235struct common_obj *common;236237common = &ch->common[VPIF_VIDEO_INDEX];238239vpif_dbg(2, debug, "vpif_buffer_queue\n");240241/* add the buffer to the DMA queue */242list_add_tail(&vb->queue, &common->dma_queue);243/* Change state of the buffer */244vb->state = VIDEOBUF_QUEUED;245}246247/**248* vpif_buffer_release : Callback function to free buffer249* @q: buffer queue ptr250* @vb: ptr to video buffer251*252* This function is called from the videobuf layer to free memory253* allocated to the buffers254*/255static void vpif_buffer_release(struct videobuf_queue *q,256struct videobuf_buffer *vb)257{258/* Get the file handle object and channel object */259struct vpif_fh *fh = q->priv_data;260struct channel_obj *ch = fh->channel;261struct common_obj *common;262263common = &ch->common[VPIF_VIDEO_INDEX];264265videobuf_dma_contig_free(q, vb);266vb->state = VIDEOBUF_NEEDS_INIT;267}268269static struct videobuf_queue_ops video_qops = {270.buf_setup = vpif_buffer_setup,271.buf_prepare = vpif_buffer_prepare,272.buf_queue = vpif_buffer_queue,273.buf_release = vpif_buffer_release,274};275276static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] =277{ {1, 1} };278279/**280* vpif_process_buffer_complete: process a completed buffer281* @common: ptr to common channel object282*283* This function time stamp the buffer and mark it as DONE. It also284* wake up any process waiting on the QUEUE and set the next buffer285* as current286*/287static void vpif_process_buffer_complete(struct common_obj *common)288{289do_gettimeofday(&common->cur_frm->ts);290common->cur_frm->state = VIDEOBUF_DONE;291wake_up_interruptible(&common->cur_frm->done);292/* Make curFrm pointing to nextFrm */293common->cur_frm = common->next_frm;294}295296/**297* vpif_schedule_next_buffer: set next buffer address for capture298* @common : ptr to common channel object299*300* This function will get next buffer from the dma queue and301* set the buffer address in the vpif register for capture.302* the buffer is marked active303*/304static void vpif_schedule_next_buffer(struct common_obj *common)305{306unsigned long addr = 0;307308common->next_frm = list_entry(common->dma_queue.next,309struct videobuf_buffer, queue);310/* Remove that buffer from the buffer queue */311list_del(&common->next_frm->queue);312common->next_frm->state = VIDEOBUF_ACTIVE;313if (V4L2_MEMORY_USERPTR == common->memory)314addr = common->next_frm->boff;315else316addr = videobuf_to_dma_contig(common->next_frm);317318/* Set top and bottom field addresses in VPIF registers */319common->set_addr(addr + common->ytop_off,320addr + common->ybtm_off,321addr + common->ctop_off,322addr + common->cbtm_off);323}324325/**326* vpif_channel_isr : ISR handler for vpif capture327* @irq: irq number328* @dev_id: dev_id ptr329*330* It changes status of the captured buffer, takes next buffer from the queue331* and sets its address in VPIF registers332*/333static irqreturn_t vpif_channel_isr(int irq, void *dev_id)334{335struct vpif_device *dev = &vpif_obj;336struct common_obj *common;337struct channel_obj *ch;338enum v4l2_field field;339int channel_id = 0;340int fid = -1, i;341342channel_id = *(int *)(dev_id);343ch = dev->dev[channel_id];344345field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;346347for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {348common = &ch->common[i];349/* skip If streaming is not started in this channel */350if (0 == common->started)351continue;352353/* Check the field format */354if (1 == ch->vpifparams.std_info.frm_fmt) {355/* Progressive mode */356if (list_empty(&common->dma_queue))357continue;358359if (!channel_first_int[i][channel_id])360vpif_process_buffer_complete(common);361362channel_first_int[i][channel_id] = 0;363364vpif_schedule_next_buffer(common);365366367channel_first_int[i][channel_id] = 0;368} else {369/**370* Interlaced mode. If it is first interrupt, ignore371* it372*/373if (channel_first_int[i][channel_id]) {374channel_first_int[i][channel_id] = 0;375continue;376}377if (0 == i) {378ch->field_id ^= 1;379/* Get field id from VPIF registers */380fid = vpif_channel_getfid(ch->channel_id);381if (fid != ch->field_id) {382/**383* If field id does not match stored384* field id, make them in sync385*/386if (0 == fid)387ch->field_id = fid;388return IRQ_HANDLED;389}390}391/* device field id and local field id are in sync */392if (0 == fid) {393/* this is even field */394if (common->cur_frm == common->next_frm)395continue;396397/* mark the current buffer as done */398vpif_process_buffer_complete(common);399} else if (1 == fid) {400/* odd field */401if (list_empty(&common->dma_queue) ||402(common->cur_frm != common->next_frm))403continue;404405vpif_schedule_next_buffer(common);406}407}408}409return IRQ_HANDLED;410}411412/**413* vpif_update_std_info() - update standard related info414* @ch: ptr to channel object415*416* For a given standard selected by application, update values417* in the device data structures418*/419static int vpif_update_std_info(struct channel_obj *ch)420{421struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];422struct vpif_params *vpifparams = &ch->vpifparams;423const struct vpif_channel_config_params *config;424struct vpif_channel_config_params *std_info = &vpifparams->std_info;425struct video_obj *vid_ch = &ch->video;426int index;427428vpif_dbg(2, debug, "vpif_update_std_info\n");429430for (index = 0; index < vpif_ch_params_count; index++) {431config = &ch_params[index];432if (config->hd_sd == 0) {433vpif_dbg(2, debug, "SD format\n");434if (config->stdid & vid_ch->stdid) {435memcpy(std_info, config, sizeof(*config));436break;437}438} else {439vpif_dbg(2, debug, "HD format\n");440if (config->dv_preset == vid_ch->dv_preset) {441memcpy(std_info, config, sizeof(*config));442break;443}444}445}446447/* standard not found */448if (index == vpif_ch_params_count)449return -EINVAL;450451common->fmt.fmt.pix.width = std_info->width;452common->width = std_info->width;453common->fmt.fmt.pix.height = std_info->height;454common->height = std_info->height;455common->fmt.fmt.pix.bytesperline = std_info->width;456vpifparams->video_params.hpitch = std_info->width;457vpifparams->video_params.storage_mode = std_info->frm_fmt;458459return 0;460}461462/**463* vpif_calculate_offsets : This function calculates buffers offsets464* @ch : ptr to channel object465*466* This function calculates buffer offsets for Y and C in the top and467* bottom field468*/469static void vpif_calculate_offsets(struct channel_obj *ch)470{471unsigned int hpitch, vpitch, sizeimage;472struct video_obj *vid_ch = &(ch->video);473struct vpif_params *vpifparams = &ch->vpifparams;474struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];475enum v4l2_field field = common->fmt.fmt.pix.field;476477vpif_dbg(2, debug, "vpif_calculate_offsets\n");478479if (V4L2_FIELD_ANY == field) {480if (vpifparams->std_info.frm_fmt)481vid_ch->buf_field = V4L2_FIELD_NONE;482else483vid_ch->buf_field = V4L2_FIELD_INTERLACED;484} else485vid_ch->buf_field = common->fmt.fmt.pix.field;486487if (V4L2_MEMORY_USERPTR == common->memory)488sizeimage = common->fmt.fmt.pix.sizeimage;489else490sizeimage = config_params.channel_bufsize[ch->channel_id];491492hpitch = common->fmt.fmt.pix.bytesperline;493vpitch = sizeimage / (hpitch * 2);494495if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||496(V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {497/* Calculate offsets for Y top, Y Bottom, C top and C Bottom */498common->ytop_off = 0;499common->ybtm_off = hpitch;500common->ctop_off = sizeimage / 2;501common->cbtm_off = sizeimage / 2 + hpitch;502} else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {503/* Calculate offsets for Y top, Y Bottom, C top and C Bottom */504common->ytop_off = 0;505common->ybtm_off = sizeimage / 4;506common->ctop_off = sizeimage / 2;507common->cbtm_off = common->ctop_off + sizeimage / 4;508} else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {509/* Calculate offsets for Y top, Y Bottom, C top and C Bottom */510common->ybtm_off = 0;511common->ytop_off = sizeimage / 4;512common->cbtm_off = sizeimage / 2;513common->ctop_off = common->cbtm_off + sizeimage / 4;514}515if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||516(V4L2_FIELD_INTERLACED == vid_ch->buf_field))517vpifparams->video_params.storage_mode = 1;518else519vpifparams->video_params.storage_mode = 0;520521if (1 == vpifparams->std_info.frm_fmt)522vpifparams->video_params.hpitch =523common->fmt.fmt.pix.bytesperline;524else {525if ((field == V4L2_FIELD_ANY)526|| (field == V4L2_FIELD_INTERLACED))527vpifparams->video_params.hpitch =528common->fmt.fmt.pix.bytesperline * 2;529else530vpifparams->video_params.hpitch =531common->fmt.fmt.pix.bytesperline;532}533534ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid;535}536537/**538* vpif_config_format: configure default frame format in the device539* ch : ptr to channel object540*/541static void vpif_config_format(struct channel_obj *ch)542{543struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];544545vpif_dbg(2, debug, "vpif_config_format\n");546547common->fmt.fmt.pix.field = V4L2_FIELD_ANY;548if (config_params.numbuffers[ch->channel_id] == 0)549common->memory = V4L2_MEMORY_USERPTR;550else551common->memory = V4L2_MEMORY_MMAP;552553common->fmt.fmt.pix.sizeimage554= config_params.channel_bufsize[ch->channel_id];555556if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER)557common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;558else559common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;560common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;561}562563/**564* vpif_get_default_field() - Get default field type based on interface565* @vpif_params - ptr to vpif params566*/567static inline enum v4l2_field vpif_get_default_field(568struct vpif_interface *iface)569{570return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE :571V4L2_FIELD_INTERLACED;572}573574/**575* vpif_check_format() - check given pixel format for compatibility576* @ch - channel ptr577* @pixfmt - Given pixel format578* @update - update the values as per hardware requirement579*580* Check the application pixel format for S_FMT and update the input581* values as per hardware limits for TRY_FMT. The default pixel and582* field format is selected based on interface type.583*/584static int vpif_check_format(struct channel_obj *ch,585struct v4l2_pix_format *pixfmt,586int update)587{588struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);589struct vpif_params *vpif_params = &ch->vpifparams;590enum v4l2_field field = pixfmt->field;591u32 sizeimage, hpitch, vpitch;592int ret = -EINVAL;593594vpif_dbg(2, debug, "vpif_check_format\n");595/**596* first check for the pixel format. If if_type is Raw bayer,597* only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only598* V4L2_PIX_FMT_YUV422P is supported599*/600if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) {601if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) {602if (!update) {603vpif_dbg(2, debug, "invalid pix format\n");604goto exit;605}606pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8;607}608} else {609if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) {610if (!update) {611vpif_dbg(2, debug, "invalid pixel format\n");612goto exit;613}614pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P;615}616}617618if (!(VPIF_VALID_FIELD(field))) {619if (!update) {620vpif_dbg(2, debug, "invalid field format\n");621goto exit;622}623/**624* By default use FIELD_NONE for RAW Bayer capture625* and FIELD_INTERLACED for other interfaces626*/627field = vpif_get_default_field(&vpif_params->iface);628} else if (field == V4L2_FIELD_ANY)629/* unsupported field. Use default */630field = vpif_get_default_field(&vpif_params->iface);631632/* validate the hpitch */633hpitch = pixfmt->bytesperline;634if (hpitch < vpif_params->std_info.width) {635if (!update) {636vpif_dbg(2, debug, "invalid hpitch\n");637goto exit;638}639hpitch = vpif_params->std_info.width;640}641642if (V4L2_MEMORY_USERPTR == common->memory)643sizeimage = pixfmt->sizeimage;644else645sizeimage = config_params.channel_bufsize[ch->channel_id];646647vpitch = sizeimage / (hpitch * 2);648649/* validate the vpitch */650if (vpitch < vpif_params->std_info.height) {651if (!update) {652vpif_dbg(2, debug, "Invalid vpitch\n");653goto exit;654}655vpitch = vpif_params->std_info.height;656}657658/* Check for 8 byte alignment */659if (!ALIGN(hpitch, 8)) {660if (!update) {661vpif_dbg(2, debug, "invalid pitch alignment\n");662goto exit;663}664/* adjust to next 8 byte boundary */665hpitch = (((hpitch + 7) / 8) * 8);666}667/* if update is set, modify the bytesperline and sizeimage */668if (update) {669pixfmt->bytesperline = hpitch;670pixfmt->sizeimage = hpitch * vpitch * 2;671}672/**673* Image width and height is always based on current standard width and674* height675*/676pixfmt->width = common->fmt.fmt.pix.width;677pixfmt->height = common->fmt.fmt.pix.height;678return 0;679exit:680return ret;681}682683/**684* vpif_config_addr() - function to configure buffer address in vpif685* @ch - channel ptr686* @muxmode - channel mux mode687*/688static void vpif_config_addr(struct channel_obj *ch, int muxmode)689{690struct common_obj *common;691692vpif_dbg(2, debug, "vpif_config_addr\n");693694common = &(ch->common[VPIF_VIDEO_INDEX]);695696if (VPIF_CHANNEL1_VIDEO == ch->channel_id)697common->set_addr = ch1_set_videobuf_addr;698else if (2 == muxmode)699common->set_addr = ch0_set_videobuf_addr_yc_nmux;700else701common->set_addr = ch0_set_videobuf_addr;702}703704/**705* vpfe_mmap : It is used to map kernel space buffers into user spaces706* @filep: file pointer707* @vma: ptr to vm_area_struct708*/709static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)710{711/* Get the channel object and file handle object */712struct vpif_fh *fh = filep->private_data;713struct channel_obj *ch = fh->channel;714struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);715716vpif_dbg(2, debug, "vpif_mmap\n");717718return videobuf_mmap_mapper(&common->buffer_queue, vma);719}720721/**722* vpif_poll: It is used for select/poll system call723* @filep: file pointer724* @wait: poll table to wait725*/726static unsigned int vpif_poll(struct file *filep, poll_table * wait)727{728struct vpif_fh *fh = filep->private_data;729struct channel_obj *channel = fh->channel;730struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);731732vpif_dbg(2, debug, "vpif_poll\n");733734if (common->started)735return videobuf_poll_stream(filep, &common->buffer_queue, wait);736return 0;737}738739/**740* vpif_open : vpif open handler741* @filep: file ptr742*743* It creates object of file handle structure and stores it in private_data744* member of filepointer745*/746static int vpif_open(struct file *filep)747{748struct vpif_capture_config *config = vpif_dev->platform_data;749struct video_device *vdev = video_devdata(filep);750struct common_obj *common;751struct video_obj *vid_ch;752struct channel_obj *ch;753struct vpif_fh *fh;754int i;755756vpif_dbg(2, debug, "vpif_open\n");757758ch = video_get_drvdata(vdev);759760vid_ch = &ch->video;761common = &ch->common[VPIF_VIDEO_INDEX];762763if (NULL == ch->curr_subdev_info) {764/**765* search through the sub device to see a registered766* sub device and make it as current sub device767*/768for (i = 0; i < config->subdev_count; i++) {769if (vpif_obj.sd[i]) {770/* the sub device is registered */771ch->curr_subdev_info = &config->subdev_info[i];772/* make first input as the current input */773vid_ch->input_idx = 0;774break;775}776}777if (i == config->subdev_count) {778vpif_err("No sub device registered\n");779return -ENOENT;780}781}782783/* Allocate memory for the file handle object */784fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);785if (NULL == fh) {786vpif_err("unable to allocate memory for file handle object\n");787return -ENOMEM;788}789790/* store pointer to fh in private_data member of filep */791filep->private_data = fh;792fh->channel = ch;793fh->initialized = 0;794/* If decoder is not initialized. initialize it */795if (!ch->initialized) {796fh->initialized = 1;797ch->initialized = 1;798memset(&(ch->vpifparams), 0, sizeof(struct vpif_params));799}800/* Increment channel usrs counter */801ch->usrs++;802/* Set io_allowed member to false */803fh->io_allowed[VPIF_VIDEO_INDEX] = 0;804/* Initialize priority of this instance to default priority */805fh->prio = V4L2_PRIORITY_UNSET;806v4l2_prio_open(&ch->prio, &fh->prio);807return 0;808}809810/**811* vpif_release : function to clean up file close812* @filep: file pointer813*814* This function deletes buffer queue, frees the buffers and the vpfe file815* handle816*/817static int vpif_release(struct file *filep)818{819struct vpif_fh *fh = filep->private_data;820struct channel_obj *ch = fh->channel;821struct common_obj *common;822823vpif_dbg(2, debug, "vpif_release\n");824825common = &ch->common[VPIF_VIDEO_INDEX];826827/* if this instance is doing IO */828if (fh->io_allowed[VPIF_VIDEO_INDEX]) {829/* Reset io_usrs member of channel object */830common->io_usrs = 0;831/* Disable channel as per its device type and channel id */832if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {833enable_channel0(0);834channel0_intr_enable(0);835}836if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||837(2 == common->started)) {838enable_channel1(0);839channel1_intr_enable(0);840}841common->started = 0;842/* Free buffers allocated */843videobuf_queue_cancel(&common->buffer_queue);844videobuf_mmap_free(&common->buffer_queue);845}846847/* Decrement channel usrs counter */848ch->usrs--;849850/* Close the priority */851v4l2_prio_close(&ch->prio, fh->prio);852853if (fh->initialized)854ch->initialized = 0;855856filep->private_data = NULL;857kfree(fh);858return 0;859}860861/**862* vpif_reqbufs() - request buffer handler863* @file: file ptr864* @priv: file handle865* @reqbuf: request buffer structure ptr866*/867static int vpif_reqbufs(struct file *file, void *priv,868struct v4l2_requestbuffers *reqbuf)869{870struct vpif_fh *fh = priv;871struct channel_obj *ch = fh->channel;872struct common_obj *common;873u8 index = 0;874875vpif_dbg(2, debug, "vpif_reqbufs\n");876877/**878* This file handle has not initialized the channel,879* It is not allowed to do settings880*/881if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)882|| (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {883if (!fh->initialized) {884vpif_dbg(1, debug, "Channel Busy\n");885return -EBUSY;886}887}888889if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type)890return -EINVAL;891892index = VPIF_VIDEO_INDEX;893894common = &ch->common[index];895896if (0 != common->io_usrs)897return -EBUSY;898899/* Initialize videobuf queue as per the buffer type */900videobuf_queue_dma_contig_init(&common->buffer_queue,901&video_qops, NULL,902&common->irqlock,903reqbuf->type,904common->fmt.fmt.pix.field,905sizeof(struct videobuf_buffer), fh,906&common->lock);907908/* Set io allowed member of file handle to TRUE */909fh->io_allowed[index] = 1;910/* Increment io usrs member of channel object to 1 */911common->io_usrs = 1;912/* Store type of memory requested in channel object */913common->memory = reqbuf->memory;914INIT_LIST_HEAD(&common->dma_queue);915916/* Allocate buffers */917return videobuf_reqbufs(&common->buffer_queue, reqbuf);918}919920/**921* vpif_querybuf() - query buffer handler922* @file: file ptr923* @priv: file handle924* @buf: v4l2 buffer structure ptr925*/926static int vpif_querybuf(struct file *file, void *priv,927struct v4l2_buffer *buf)928{929struct vpif_fh *fh = priv;930struct channel_obj *ch = fh->channel;931struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];932933vpif_dbg(2, debug, "vpif_querybuf\n");934935if (common->fmt.type != buf->type)936return -EINVAL;937938if (common->memory != V4L2_MEMORY_MMAP) {939vpif_dbg(1, debug, "Invalid memory\n");940return -EINVAL;941}942943return videobuf_querybuf(&common->buffer_queue, buf);944}945946/**947* vpif_qbuf() - query buffer handler948* @file: file ptr949* @priv: file handle950* @buf: v4l2 buffer structure ptr951*/952static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)953{954955struct vpif_fh *fh = priv;956struct channel_obj *ch = fh->channel;957struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];958struct v4l2_buffer tbuf = *buf;959struct videobuf_buffer *buf1;960unsigned long addr = 0;961unsigned long flags;962int ret = 0;963964vpif_dbg(2, debug, "vpif_qbuf\n");965966if (common->fmt.type != tbuf.type) {967vpif_err("invalid buffer type\n");968return -EINVAL;969}970971if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {972vpif_err("fh io not allowed \n");973return -EACCES;974}975976if (!(list_empty(&common->dma_queue)) ||977(common->cur_frm != common->next_frm) ||978!common->started ||979(common->started && (0 == ch->field_id)))980return videobuf_qbuf(&common->buffer_queue, buf);981982/* bufferqueue is empty store buffer address in VPIF registers */983mutex_lock(&common->buffer_queue.vb_lock);984buf1 = common->buffer_queue.bufs[tbuf.index];985986if ((buf1->state == VIDEOBUF_QUEUED) ||987(buf1->state == VIDEOBUF_ACTIVE)) {988vpif_err("invalid state\n");989goto qbuf_exit;990}991992switch (buf1->memory) {993case V4L2_MEMORY_MMAP:994if (buf1->baddr == 0)995goto qbuf_exit;996break;997998case V4L2_MEMORY_USERPTR:999if (tbuf.length < buf1->bsize)1000goto qbuf_exit;10011002if ((VIDEOBUF_NEEDS_INIT != buf1->state)1003&& (buf1->baddr != tbuf.m.userptr)) {1004vpif_buffer_release(&common->buffer_queue, buf1);1005buf1->baddr = tbuf.m.userptr;1006}1007break;10081009default:1010goto qbuf_exit;1011}10121013local_irq_save(flags);1014ret = vpif_buffer_prepare(&common->buffer_queue, buf1,1015common->buffer_queue.field);1016if (ret < 0) {1017local_irq_restore(flags);1018goto qbuf_exit;1019}10201021buf1->state = VIDEOBUF_ACTIVE;10221023if (V4L2_MEMORY_USERPTR == common->memory)1024addr = buf1->boff;1025else1026addr = videobuf_to_dma_contig(buf1);10271028common->next_frm = buf1;1029common->set_addr(addr + common->ytop_off,1030addr + common->ybtm_off,1031addr + common->ctop_off,1032addr + common->cbtm_off);10331034local_irq_restore(flags);1035list_add_tail(&buf1->stream, &common->buffer_queue.stream);1036mutex_unlock(&common->buffer_queue.vb_lock);1037return 0;10381039qbuf_exit:1040mutex_unlock(&common->buffer_queue.vb_lock);1041return -EINVAL;1042}10431044/**1045* vpif_dqbuf() - query buffer handler1046* @file: file ptr1047* @priv: file handle1048* @buf: v4l2 buffer structure ptr1049*/1050static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)1051{1052struct vpif_fh *fh = priv;1053struct channel_obj *ch = fh->channel;1054struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];10551056vpif_dbg(2, debug, "vpif_dqbuf\n");10571058return videobuf_dqbuf(&common->buffer_queue, buf,1059file->f_flags & O_NONBLOCK);1060}10611062/**1063* vpif_streamon() - streamon handler1064* @file: file ptr1065* @priv: file handle1066* @buftype: v4l2 buffer type1067*/1068static int vpif_streamon(struct file *file, void *priv,1069enum v4l2_buf_type buftype)1070{10711072struct vpif_capture_config *config = vpif_dev->platform_data;1073struct vpif_fh *fh = priv;1074struct channel_obj *ch = fh->channel;1075struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1076struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];1077struct vpif_params *vpif;1078unsigned long addr = 0;1079int ret = 0;10801081vpif_dbg(2, debug, "vpif_streamon\n");10821083vpif = &ch->vpifparams;10841085if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {1086vpif_dbg(1, debug, "buffer type not supported\n");1087return -EINVAL;1088}10891090/* If file handle is not allowed IO, return error */1091if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {1092vpif_dbg(1, debug, "io not allowed\n");1093return -EACCES;1094}10951096/* If Streaming is already started, return error */1097if (common->started) {1098vpif_dbg(1, debug, "channel->started\n");1099return -EBUSY;1100}11011102if ((ch->channel_id == VPIF_CHANNEL0_VIDEO &&1103oth_ch->common[VPIF_VIDEO_INDEX].started &&1104vpif->std_info.ycmux_mode == 0) ||1105((ch->channel_id == VPIF_CHANNEL1_VIDEO) &&1106(2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {1107vpif_dbg(1, debug, "other channel is being used\n");1108return -EBUSY;1109}11101111ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0);1112if (ret)1113return ret;11141115/* Enable streamon on the sub device */1116ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,1117s_stream, 1);11181119if (ret && (ret != -ENOIOCTLCMD)) {1120vpif_dbg(1, debug, "stream on failed in subdev\n");1121return ret;1122}11231124/* Call videobuf_streamon to start streaming in videobuf */1125ret = videobuf_streamon(&common->buffer_queue);1126if (ret) {1127vpif_dbg(1, debug, "videobuf_streamon\n");1128return ret;1129}11301131/* If buffer queue is empty, return error */1132if (list_empty(&common->dma_queue)) {1133vpif_dbg(1, debug, "buffer queue is empty\n");1134ret = -EIO;1135goto exit;1136}11371138/* Get the next frame from the buffer queue */1139common->cur_frm = list_entry(common->dma_queue.next,1140struct videobuf_buffer, queue);1141common->next_frm = common->cur_frm;11421143/* Remove buffer from the buffer queue */1144list_del(&common->cur_frm->queue);1145/* Mark state of the current frame to active */1146common->cur_frm->state = VIDEOBUF_ACTIVE;1147/* Initialize field_id and started member */1148ch->field_id = 0;1149common->started = 1;11501151if (V4L2_MEMORY_USERPTR == common->memory)1152addr = common->cur_frm->boff;1153else1154addr = videobuf_to_dma_contig(common->cur_frm);11551156/* Calculate the offset for Y and C data in the buffer */1157vpif_calculate_offsets(ch);11581159if ((vpif->std_info.frm_fmt &&1160((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) &&1161(common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) ||1162(!vpif->std_info.frm_fmt &&1163(common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {1164vpif_dbg(1, debug, "conflict in field format and std format\n");1165ret = -EINVAL;1166goto exit;1167}11681169/* configure 1 or 2 channel mode */1170ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode);11711172if (ret < 0) {1173vpif_dbg(1, debug, "can't set vpif channel mode\n");1174goto exit;1175}11761177/* Call vpif_set_params function to set the parameters and addresses */1178ret = vpif_set_video_params(vpif, ch->channel_id);11791180if (ret < 0) {1181vpif_dbg(1, debug, "can't set video params\n");1182goto exit;1183}11841185common->started = ret;1186vpif_config_addr(ch, ret);11871188common->set_addr(addr + common->ytop_off,1189addr + common->ybtm_off,1190addr + common->ctop_off,1191addr + common->cbtm_off);11921193/**1194* Set interrupt for both the fields in VPIF Register enable channel in1195* VPIF register1196*/1197if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) {1198channel0_intr_assert();1199channel0_intr_enable(1);1200enable_channel0(1);1201}1202if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||1203(common->started == 2)) {1204channel1_intr_assert();1205channel1_intr_enable(1);1206enable_channel1(1);1207}1208channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;1209return ret;12101211exit:1212videobuf_streamoff(&common->buffer_queue);1213return ret;1214}12151216/**1217* vpif_streamoff() - streamoff handler1218* @file: file ptr1219* @priv: file handle1220* @buftype: v4l2 buffer type1221*/1222static int vpif_streamoff(struct file *file, void *priv,1223enum v4l2_buf_type buftype)1224{12251226struct vpif_fh *fh = priv;1227struct channel_obj *ch = fh->channel;1228struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1229int ret;12301231vpif_dbg(2, debug, "vpif_streamoff\n");12321233if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {1234vpif_dbg(1, debug, "buffer type not supported\n");1235return -EINVAL;1236}12371238/* If io is allowed for this file handle, return error */1239if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {1240vpif_dbg(1, debug, "io not allowed\n");1241return -EACCES;1242}12431244/* If streaming is not started, return error */1245if (!common->started) {1246vpif_dbg(1, debug, "channel->started\n");1247return -EINVAL;1248}12491250/* disable channel */1251if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {1252enable_channel0(0);1253channel0_intr_enable(0);1254} else {1255enable_channel1(0);1256channel1_intr_enable(0);1257}12581259common->started = 0;12601261ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,1262s_stream, 0);12631264if (ret && (ret != -ENOIOCTLCMD))1265vpif_dbg(1, debug, "stream off failed in subdev\n");12661267return videobuf_streamoff(&common->buffer_queue);1268}12691270/**1271* vpif_map_sub_device_to_input() - Maps sub device to input1272* @ch - ptr to channel1273* @config - ptr to capture configuration1274* @input_index - Given input index from application1275* @sub_device_index - index into sd table1276*1277* lookup the sub device information for a given input index.1278* we report all the inputs to application. inputs table also1279* has sub device name for the each input1280*/1281static struct vpif_subdev_info *vpif_map_sub_device_to_input(1282struct channel_obj *ch,1283struct vpif_capture_config *vpif_cfg,1284int input_index,1285int *sub_device_index)1286{1287struct vpif_capture_chan_config *chan_cfg;1288struct vpif_subdev_info *subdev_info = NULL;1289const char *subdev_name = NULL;1290int i;12911292vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n");12931294chan_cfg = &vpif_cfg->chan_config[ch->channel_id];12951296/**1297* search through the inputs to find the sub device supporting1298* the input1299*/1300for (i = 0; i < chan_cfg->input_count; i++) {1301/* For each sub device, loop through input */1302if (i == input_index) {1303subdev_name = chan_cfg->inputs[i].subdev_name;1304break;1305}1306}13071308/* if reached maximum. return null */1309if (i == chan_cfg->input_count || (NULL == subdev_name))1310return subdev_info;13111312/* loop through the sub device list to get the sub device info */1313for (i = 0; i < vpif_cfg->subdev_count; i++) {1314subdev_info = &vpif_cfg->subdev_info[i];1315if (!strcmp(subdev_info->name, subdev_name))1316break;1317}13181319if (i == vpif_cfg->subdev_count)1320return subdev_info;13211322/* check if the sub device is registered */1323if (NULL == vpif_obj.sd[i])1324return NULL;13251326*sub_device_index = i;1327return subdev_info;1328}13291330/**1331* vpif_querystd() - querystd handler1332* @file: file ptr1333* @priv: file handle1334* @std_id: ptr to std id1335*1336* This function is called to detect standard at the selected input1337*/1338static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)1339{1340struct vpif_fh *fh = priv;1341struct channel_obj *ch = fh->channel;1342int ret = 0;13431344vpif_dbg(2, debug, "vpif_querystd\n");13451346/* Call querystd function of decoder device */1347ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,1348querystd, std_id);1349if (ret < 0)1350vpif_dbg(1, debug, "Failed to set standard for sub devices\n");13511352return ret;1353}13541355/**1356* vpif_g_std() - get STD handler1357* @file: file ptr1358* @priv: file handle1359* @std_id: ptr to std id1360*/1361static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)1362{1363struct vpif_fh *fh = priv;1364struct channel_obj *ch = fh->channel;13651366vpif_dbg(2, debug, "vpif_g_std\n");13671368*std = ch->video.stdid;1369return 0;1370}13711372/**1373* vpif_s_std() - set STD handler1374* @file: file ptr1375* @priv: file handle1376* @std_id: ptr to std id1377*/1378static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)1379{1380struct vpif_fh *fh = priv;1381struct channel_obj *ch = fh->channel;1382struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1383int ret = 0;13841385vpif_dbg(2, debug, "vpif_s_std\n");13861387if (common->started) {1388vpif_err("streaming in progress\n");1389return -EBUSY;1390}13911392if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||1393(VPIF_CHANNEL1_VIDEO == ch->channel_id)) {1394if (!fh->initialized) {1395vpif_dbg(1, debug, "Channel Busy\n");1396return -EBUSY;1397}1398}13991400ret = v4l2_prio_check(&ch->prio, fh->prio);1401if (0 != ret)1402return ret;14031404fh->initialized = 1;14051406/* Call encoder subdevice function to set the standard */1407ch->video.stdid = *std_id;1408ch->video.dv_preset = V4L2_DV_INVALID;1409memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));14101411/* Get the information about the standard */1412if (vpif_update_std_info(ch)) {1413vpif_err("Error getting the standard info\n");1414return -EINVAL;1415}14161417/* Configure the default format information */1418vpif_config_format(ch);14191420/* set standard in the sub device */1421ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,1422s_std, *std_id);1423if (ret < 0)1424vpif_dbg(1, debug, "Failed to set standard for sub devices\n");1425return ret;1426}14271428/**1429* vpif_enum_input() - ENUMINPUT handler1430* @file: file ptr1431* @priv: file handle1432* @input: ptr to input structure1433*/1434static int vpif_enum_input(struct file *file, void *priv,1435struct v4l2_input *input)1436{14371438struct vpif_capture_config *config = vpif_dev->platform_data;1439struct vpif_capture_chan_config *chan_cfg;1440struct vpif_fh *fh = priv;1441struct channel_obj *ch = fh->channel;14421443chan_cfg = &config->chan_config[ch->channel_id];14441445if (input->index >= chan_cfg->input_count) {1446vpif_dbg(1, debug, "Invalid input index\n");1447return -EINVAL;1448}14491450memcpy(input, &chan_cfg->inputs[input->index].input,1451sizeof(*input));1452return 0;1453}14541455/**1456* vpif_g_input() - Get INPUT handler1457* @file: file ptr1458* @priv: file handle1459* @index: ptr to input index1460*/1461static int vpif_g_input(struct file *file, void *priv, unsigned int *index)1462{1463struct vpif_fh *fh = priv;1464struct channel_obj *ch = fh->channel;1465struct video_obj *vid_ch = &ch->video;14661467*index = vid_ch->input_idx;14681469return 0;1470}14711472/**1473* vpif_s_input() - Set INPUT handler1474* @file: file ptr1475* @priv: file handle1476* @index: input index1477*/1478static int vpif_s_input(struct file *file, void *priv, unsigned int index)1479{1480struct vpif_capture_config *config = vpif_dev->platform_data;1481struct vpif_capture_chan_config *chan_cfg;1482struct vpif_fh *fh = priv;1483struct channel_obj *ch = fh->channel;1484struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1485struct video_obj *vid_ch = &ch->video;1486struct vpif_subdev_info *subdev_info;1487int ret = 0, sd_index = 0;1488u32 input = 0, output = 0;14891490chan_cfg = &config->chan_config[ch->channel_id];14911492if (common->started) {1493vpif_err("Streaming in progress\n");1494return -EBUSY;1495}14961497if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||1498(VPIF_CHANNEL1_VIDEO == ch->channel_id)) {1499if (!fh->initialized) {1500vpif_dbg(1, debug, "Channel Busy\n");1501return -EBUSY;1502}1503}15041505ret = v4l2_prio_check(&ch->prio, fh->prio);1506if (0 != ret)1507return ret;15081509fh->initialized = 1;1510subdev_info = vpif_map_sub_device_to_input(ch, config, index,1511&sd_index);1512if (NULL == subdev_info) {1513vpif_dbg(1, debug,1514"couldn't lookup sub device for the input index\n");1515return -EINVAL;1516}15171518/* first setup input path from sub device to vpif */1519if (config->setup_input_path) {1520ret = config->setup_input_path(ch->channel_id,1521subdev_info->name);1522if (ret < 0) {1523vpif_dbg(1, debug, "couldn't setup input path for the"1524" sub device %s, for input index %d\n",1525subdev_info->name, index);1526return ret;1527}1528}15291530if (subdev_info->can_route) {1531input = subdev_info->input;1532output = subdev_info->output;1533ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing,1534input, output, 0);1535if (ret < 0) {1536vpif_dbg(1, debug, "Failed to set input\n");1537return ret;1538}1539}1540vid_ch->input_idx = index;1541ch->curr_subdev_info = subdev_info;1542ch->curr_sd_index = sd_index;1543/* copy interface parameters to vpif */1544ch->vpifparams.iface = subdev_info->vpif_if;15451546/* update tvnorms from the sub device input info */1547ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;1548return ret;1549}15501551/**1552* vpif_enum_fmt_vid_cap() - ENUM_FMT handler1553* @file: file ptr1554* @priv: file handle1555* @index: input index1556*/1557static int vpif_enum_fmt_vid_cap(struct file *file, void *priv,1558struct v4l2_fmtdesc *fmt)1559{1560struct vpif_fh *fh = priv;1561struct channel_obj *ch = fh->channel;15621563if (fmt->index != 0) {1564vpif_dbg(1, debug, "Invalid format index\n");1565return -EINVAL;1566}15671568/* Fill in the information about format */1569if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) {1570fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;1571strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb");1572fmt->pixelformat = V4L2_PIX_FMT_SBGGR8;1573} else {1574fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;1575strcpy(fmt->description, "YCbCr4:2:2 YC Planar");1576fmt->pixelformat = V4L2_PIX_FMT_YUV422P;1577}1578return 0;1579}15801581/**1582* vpif_try_fmt_vid_cap() - TRY_FMT handler1583* @file: file ptr1584* @priv: file handle1585* @fmt: ptr to v4l2 format structure1586*/1587static int vpif_try_fmt_vid_cap(struct file *file, void *priv,1588struct v4l2_format *fmt)1589{1590struct vpif_fh *fh = priv;1591struct channel_obj *ch = fh->channel;1592struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;15931594return vpif_check_format(ch, pixfmt, 1);1595}159615971598/**1599* vpif_g_fmt_vid_cap() - Set INPUT handler1600* @file: file ptr1601* @priv: file handle1602* @fmt: ptr to v4l2 format structure1603*/1604static int vpif_g_fmt_vid_cap(struct file *file, void *priv,1605struct v4l2_format *fmt)1606{1607struct vpif_fh *fh = priv;1608struct channel_obj *ch = fh->channel;1609struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];16101611/* Check the validity of the buffer type */1612if (common->fmt.type != fmt->type)1613return -EINVAL;16141615/* Fill in the information about format */1616*fmt = common->fmt;1617return 0;1618}16191620/**1621* vpif_s_fmt_vid_cap() - Set FMT handler1622* @file: file ptr1623* @priv: file handle1624* @fmt: ptr to v4l2 format structure1625*/1626static int vpif_s_fmt_vid_cap(struct file *file, void *priv,1627struct v4l2_format *fmt)1628{1629struct vpif_fh *fh = priv;1630struct channel_obj *ch = fh->channel;1631struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1632struct v4l2_pix_format *pixfmt;1633int ret = 0;16341635vpif_dbg(2, debug, "%s\n", __func__);16361637/* If streaming is started, return error */1638if (common->started) {1639vpif_dbg(1, debug, "Streaming is started\n");1640return -EBUSY;1641}16421643if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||1644(VPIF_CHANNEL1_VIDEO == ch->channel_id)) {1645if (!fh->initialized) {1646vpif_dbg(1, debug, "Channel Busy\n");1647return -EBUSY;1648}1649}16501651ret = v4l2_prio_check(&ch->prio, fh->prio);1652if (0 != ret)1653return ret;16541655fh->initialized = 1;16561657pixfmt = &fmt->fmt.pix;1658/* Check for valid field format */1659ret = vpif_check_format(ch, pixfmt, 0);16601661if (ret)1662return ret;1663/* store the format in the channel object */1664common->fmt = *fmt;1665return 0;1666}16671668/**1669* vpif_querycap() - QUERYCAP handler1670* @file: file ptr1671* @priv: file handle1672* @cap: ptr to v4l2_capability structure1673*/1674static int vpif_querycap(struct file *file, void *priv,1675struct v4l2_capability *cap)1676{1677struct vpif_capture_config *config = vpif_dev->platform_data;16781679cap->version = VPIF_CAPTURE_VERSION_CODE;1680cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;1681strlcpy(cap->driver, "vpif capture", sizeof(cap->driver));1682strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info));1683strlcpy(cap->card, config->card_name, sizeof(cap->card));16841685return 0;1686}16871688/**1689* vpif_g_priority() - get priority handler1690* @file: file ptr1691* @priv: file handle1692* @prio: ptr to v4l2_priority structure1693*/1694static int vpif_g_priority(struct file *file, void *priv,1695enum v4l2_priority *prio)1696{1697struct vpif_fh *fh = priv;1698struct channel_obj *ch = fh->channel;16991700*prio = v4l2_prio_max(&ch->prio);17011702return 0;1703}17041705/**1706* vpif_s_priority() - set priority handler1707* @file: file ptr1708* @priv: file handle1709* @prio: ptr to v4l2_priority structure1710*/1711static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)1712{1713struct vpif_fh *fh = priv;1714struct channel_obj *ch = fh->channel;17151716return v4l2_prio_change(&ch->prio, &fh->prio, p);1717}17181719/**1720* vpif_cropcap() - cropcap handler1721* @file: file ptr1722* @priv: file handle1723* @crop: ptr to v4l2_cropcap structure1724*/1725static int vpif_cropcap(struct file *file, void *priv,1726struct v4l2_cropcap *crop)1727{1728struct vpif_fh *fh = priv;1729struct channel_obj *ch = fh->channel;1730struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];17311732if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type)1733return -EINVAL;17341735crop->bounds.left = 0;1736crop->bounds.top = 0;1737crop->bounds.height = common->height;1738crop->bounds.width = common->width;1739crop->defrect = crop->bounds;1740return 0;1741}17421743/**1744* vpif_enum_dv_presets() - ENUM_DV_PRESETS handler1745* @file: file ptr1746* @priv: file handle1747* @preset: input preset1748*/1749static int vpif_enum_dv_presets(struct file *file, void *priv,1750struct v4l2_dv_enum_preset *preset)1751{1752struct vpif_fh *fh = priv;1753struct channel_obj *ch = fh->channel;17541755return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],1756video, enum_dv_presets, preset);1757}17581759/**1760* vpif_query_dv_presets() - QUERY_DV_PRESET handler1761* @file: file ptr1762* @priv: file handle1763* @preset: input preset1764*/1765static int vpif_query_dv_preset(struct file *file, void *priv,1766struct v4l2_dv_preset *preset)1767{1768struct vpif_fh *fh = priv;1769struct channel_obj *ch = fh->channel;17701771return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],1772video, query_dv_preset, preset);1773}1774/**1775* vpif_s_dv_presets() - S_DV_PRESETS handler1776* @file: file ptr1777* @priv: file handle1778* @preset: input preset1779*/1780static int vpif_s_dv_preset(struct file *file, void *priv,1781struct v4l2_dv_preset *preset)1782{1783struct vpif_fh *fh = priv;1784struct channel_obj *ch = fh->channel;1785struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1786int ret = 0;17871788if (common->started) {1789vpif_dbg(1, debug, "streaming in progress\n");1790return -EBUSY;1791}17921793if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||1794(VPIF_CHANNEL1_VIDEO == ch->channel_id)) {1795if (!fh->initialized) {1796vpif_dbg(1, debug, "Channel Busy\n");1797return -EBUSY;1798}1799}18001801ret = v4l2_prio_check(&ch->prio, fh->prio);1802if (ret)1803return ret;18041805fh->initialized = 1;18061807/* Call encoder subdevice function to set the standard */1808if (mutex_lock_interruptible(&common->lock))1809return -ERESTARTSYS;18101811ch->video.dv_preset = preset->preset;1812ch->video.stdid = V4L2_STD_UNKNOWN;1813memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));18141815/* Get the information about the standard */1816if (vpif_update_std_info(ch)) {1817vpif_dbg(1, debug, "Error getting the standard info\n");1818ret = -EINVAL;1819} else {1820/* Configure the default format information */1821vpif_config_format(ch);18221823ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],1824video, s_dv_preset, preset);1825}18261827mutex_unlock(&common->lock);18281829return ret;1830}1831/**1832* vpif_g_dv_presets() - G_DV_PRESETS handler1833* @file: file ptr1834* @priv: file handle1835* @preset: input preset1836*/1837static int vpif_g_dv_preset(struct file *file, void *priv,1838struct v4l2_dv_preset *preset)1839{1840struct vpif_fh *fh = priv;1841struct channel_obj *ch = fh->channel;18421843preset->preset = ch->video.dv_preset;18441845return 0;1846}18471848/**1849* vpif_s_dv_timings() - S_DV_TIMINGS handler1850* @file: file ptr1851* @priv: file handle1852* @timings: digital video timings1853*/1854static int vpif_s_dv_timings(struct file *file, void *priv,1855struct v4l2_dv_timings *timings)1856{1857struct vpif_fh *fh = priv;1858struct channel_obj *ch = fh->channel;1859struct vpif_params *vpifparams = &ch->vpifparams;1860struct vpif_channel_config_params *std_info = &vpifparams->std_info;1861struct video_obj *vid_ch = &ch->video;1862struct v4l2_bt_timings *bt = &vid_ch->bt_timings;1863int ret;18641865if (timings->type != V4L2_DV_BT_656_1120) {1866vpif_dbg(2, debug, "Timing type not defined\n");1867return -EINVAL;1868}18691870/* Configure subdevice timings, if any */1871ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],1872video, s_dv_timings, timings);1873if (ret == -ENOIOCTLCMD) {1874vpif_dbg(2, debug, "Custom DV timings not supported by "1875"subdevice\n");1876return -EINVAL;1877}1878if (ret < 0) {1879vpif_dbg(2, debug, "Error setting custom DV timings\n");1880return ret;1881}18821883if (!(timings->bt.width && timings->bt.height &&1884(timings->bt.hbackporch ||1885timings->bt.hfrontporch ||1886timings->bt.hsync) &&1887timings->bt.vfrontporch &&1888(timings->bt.vbackporch ||1889timings->bt.vsync))) {1890vpif_dbg(2, debug, "Timings for width, height, "1891"horizontal back porch, horizontal sync, "1892"horizontal front porch, vertical back porch, "1893"vertical sync and vertical back porch "1894"must be defined\n");1895return -EINVAL;1896}18971898*bt = timings->bt;18991900/* Configure video port timings */19011902std_info->eav2sav = bt->hbackporch + bt->hfrontporch +1903bt->hsync - 8;1904std_info->sav2eav = bt->width;19051906std_info->l1 = 1;1907std_info->l3 = bt->vsync + bt->vbackporch + 1;19081909if (bt->interlaced) {1910if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {1911std_info->vsize = bt->height * 2 +1912bt->vfrontporch + bt->vsync + bt->vbackporch +1913bt->il_vfrontporch + bt->il_vsync +1914bt->il_vbackporch;1915std_info->l5 = std_info->vsize/2 -1916(bt->vfrontporch - 1);1917std_info->l7 = std_info->vsize/2 + 1;1918std_info->l9 = std_info->l7 + bt->il_vsync +1919bt->il_vbackporch + 1;1920std_info->l11 = std_info->vsize -1921(bt->il_vfrontporch - 1);1922} else {1923vpif_dbg(2, debug, "Required timing values for "1924"interlaced BT format missing\n");1925return -EINVAL;1926}1927} else {1928std_info->vsize = bt->height + bt->vfrontporch +1929bt->vsync + bt->vbackporch;1930std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);1931}1932strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);1933std_info->width = bt->width;1934std_info->height = bt->height;1935std_info->frm_fmt = bt->interlaced ? 0 : 1;1936std_info->ycmux_mode = 0;1937std_info->capture_format = 0;1938std_info->vbi_supported = 0;1939std_info->hd_sd = 1;1940std_info->stdid = 0;1941std_info->dv_preset = V4L2_DV_INVALID;19421943vid_ch->stdid = 0;1944vid_ch->dv_preset = V4L2_DV_INVALID;1945return 0;1946}19471948/**1949* vpif_g_dv_timings() - G_DV_TIMINGS handler1950* @file: file ptr1951* @priv: file handle1952* @timings: digital video timings1953*/1954static int vpif_g_dv_timings(struct file *file, void *priv,1955struct v4l2_dv_timings *timings)1956{1957struct vpif_fh *fh = priv;1958struct channel_obj *ch = fh->channel;1959struct video_obj *vid_ch = &ch->video;1960struct v4l2_bt_timings *bt = &vid_ch->bt_timings;19611962timings->bt = *bt;19631964return 0;1965}19661967/*1968* vpif_g_chip_ident() - Identify the chip1969* @file: file ptr1970* @priv: file handle1971* @chip: chip identity1972*1973* Returns zero or -EINVAL if read operations fails.1974*/1975static int vpif_g_chip_ident(struct file *file, void *priv,1976struct v4l2_dbg_chip_ident *chip)1977{1978chip->ident = V4L2_IDENT_NONE;1979chip->revision = 0;1980if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&1981chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {1982vpif_dbg(2, debug, "match_type is invalid.\n");1983return -EINVAL;1984}19851986return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,1987g_chip_ident, chip);1988}19891990#ifdef CONFIG_VIDEO_ADV_DEBUG1991/*1992* vpif_dbg_g_register() - Read register1993* @file: file ptr1994* @priv: file handle1995* @reg: register to be read1996*1997* Debugging only1998* Returns zero or -EINVAL if read operations fails.1999*/2000static int vpif_dbg_g_register(struct file *file, void *priv,2001struct v4l2_dbg_register *reg){2002struct vpif_fh *fh = priv;2003struct channel_obj *ch = fh->channel;20042005return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,2006g_register, reg);2007}20082009/*2010* vpif_dbg_s_register() - Write to register2011* @file: file ptr2012* @priv: file handle2013* @reg: register to be modified2014*2015* Debugging only2016* Returns zero or -EINVAL if write operations fails.2017*/2018static int vpif_dbg_s_register(struct file *file, void *priv,2019struct v4l2_dbg_register *reg){2020struct vpif_fh *fh = priv;2021struct channel_obj *ch = fh->channel;20222023return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,2024s_register, reg);2025}2026#endif20272028/*2029* vpif_log_status() - Status information2030* @file: file ptr2031* @priv: file handle2032*2033* Returns zero.2034*/2035static int vpif_log_status(struct file *filep, void *priv)2036{2037/* status for sub devices */2038v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);20392040return 0;2041}20422043/* vpif capture ioctl operations */2044static const struct v4l2_ioctl_ops vpif_ioctl_ops = {2045.vidioc_querycap = vpif_querycap,2046.vidioc_g_priority = vpif_g_priority,2047.vidioc_s_priority = vpif_s_priority,2048.vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap,2049.vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap,2050.vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap,2051.vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap,2052.vidioc_enum_input = vpif_enum_input,2053.vidioc_s_input = vpif_s_input,2054.vidioc_g_input = vpif_g_input,2055.vidioc_reqbufs = vpif_reqbufs,2056.vidioc_querybuf = vpif_querybuf,2057.vidioc_querystd = vpif_querystd,2058.vidioc_s_std = vpif_s_std,2059.vidioc_g_std = vpif_g_std,2060.vidioc_qbuf = vpif_qbuf,2061.vidioc_dqbuf = vpif_dqbuf,2062.vidioc_streamon = vpif_streamon,2063.vidioc_streamoff = vpif_streamoff,2064.vidioc_cropcap = vpif_cropcap,2065.vidioc_enum_dv_presets = vpif_enum_dv_presets,2066.vidioc_s_dv_preset = vpif_s_dv_preset,2067.vidioc_g_dv_preset = vpif_g_dv_preset,2068.vidioc_query_dv_preset = vpif_query_dv_preset,2069.vidioc_s_dv_timings = vpif_s_dv_timings,2070.vidioc_g_dv_timings = vpif_g_dv_timings,2071.vidioc_g_chip_ident = vpif_g_chip_ident,2072#ifdef CONFIG_VIDEO_ADV_DEBUG2073.vidioc_g_register = vpif_dbg_g_register,2074.vidioc_s_register = vpif_dbg_s_register,2075#endif2076.vidioc_log_status = vpif_log_status,2077};20782079/* vpif file operations */2080static struct v4l2_file_operations vpif_fops = {2081.owner = THIS_MODULE,2082.open = vpif_open,2083.release = vpif_release,2084.unlocked_ioctl = video_ioctl2,2085.mmap = vpif_mmap,2086.poll = vpif_poll2087};20882089/* vpif video template */2090static struct video_device vpif_video_template = {2091.name = "vpif",2092.fops = &vpif_fops,2093.minor = -1,2094.ioctl_ops = &vpif_ioctl_ops,2095};20962097/**2098* initialize_vpif() - Initialize vpif data structures2099*2100* Allocate memory for data structures and initialize them2101*/2102static int initialize_vpif(void)2103{2104int err = 0, i, j;2105int free_channel_objects_index;21062107/* Default number of buffers should be 3 */2108if ((ch0_numbuffers > 0) &&2109(ch0_numbuffers < config_params.min_numbuffers))2110ch0_numbuffers = config_params.min_numbuffers;2111if ((ch1_numbuffers > 0) &&2112(ch1_numbuffers < config_params.min_numbuffers))2113ch1_numbuffers = config_params.min_numbuffers;21142115/* Set buffer size to min buffers size if it is invalid */2116if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO])2117ch0_bufsize =2118config_params.min_bufsize[VPIF_CHANNEL0_VIDEO];2119if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO])2120ch1_bufsize =2121config_params.min_bufsize[VPIF_CHANNEL1_VIDEO];21222123config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers;2124config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers;2125if (ch0_numbuffers) {2126config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO]2127= ch0_bufsize;2128}2129if (ch1_numbuffers) {2130config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO]2131= ch1_bufsize;2132}21332134/* Allocate memory for six channel objects */2135for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {2136vpif_obj.dev[i] =2137kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL);2138/* If memory allocation fails, return error */2139if (!vpif_obj.dev[i]) {2140free_channel_objects_index = i;2141err = -ENOMEM;2142goto vpif_init_free_channel_objects;2143}2144}2145return 0;21462147vpif_init_free_channel_objects:2148for (j = 0; j < free_channel_objects_index; j++)2149kfree(vpif_obj.dev[j]);2150return err;2151}21522153/**2154* vpif_probe : This function probes the vpif capture driver2155* @pdev: platform device pointer2156*2157* This creates device entries by register itself to the V4L2 driver and2158* initializes fields of each channel objects2159*/2160static __init int vpif_probe(struct platform_device *pdev)2161{2162struct vpif_subdev_info *subdevdata;2163struct vpif_capture_config *config;2164int i, j, k, m, q, err;2165struct i2c_adapter *i2c_adap;2166struct channel_obj *ch;2167struct common_obj *common;2168struct video_device *vfd;2169struct resource *res;2170int subdev_count;21712172vpif_dev = &pdev->dev;21732174err = initialize_vpif();2175if (err) {2176v4l2_err(vpif_dev->driver, "Error initializing vpif\n");2177return err;2178}21792180k = 0;2181while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {2182for (i = res->start; i <= res->end; i++) {2183if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,2184"DM646x_Capture",2185(void *)(&vpif_obj.dev[k]->channel_id))) {2186err = -EBUSY;2187i--;2188goto vpif_int_err;2189}2190}2191k++;2192}21932194for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {2195/* Get the pointer to the channel object */2196ch = vpif_obj.dev[i];2197/* Allocate memory for video device */2198vfd = video_device_alloc();2199if (NULL == vfd) {2200for (j = 0; j < i; j++) {2201ch = vpif_obj.dev[j];2202video_device_release(ch->video_dev);2203}2204err = -ENOMEM;2205goto vpif_dev_alloc_err;2206}22072208/* Initialize field of video device */2209*vfd = vpif_video_template;2210vfd->v4l2_dev = &vpif_obj.v4l2_dev;2211vfd->release = video_device_release;2212snprintf(vfd->name, sizeof(vfd->name),2213"DM646x_VPIFCapture_DRIVER_V%d.%d.%d",2214(VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff,2215(VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff,2216(VPIF_CAPTURE_VERSION_CODE) & 0xff);2217/* Set video_dev to the video device */2218ch->video_dev = vfd;2219}22202221for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {2222ch = vpif_obj.dev[j];2223ch->channel_id = j;2224common = &(ch->common[VPIF_VIDEO_INDEX]);2225spin_lock_init(&common->irqlock);2226mutex_init(&common->lock);2227ch->video_dev->lock = &common->lock;2228/* Initialize prio member of channel object */2229v4l2_prio_init(&ch->prio);2230err = video_register_device(ch->video_dev,2231VFL_TYPE_GRABBER, (j ? 1 : 0));2232if (err)2233goto probe_out;22342235video_set_drvdata(ch->video_dev, ch);22362237}22382239i2c_adap = i2c_get_adapter(1);2240config = pdev->dev.platform_data;22412242subdev_count = config->subdev_count;2243vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,2244GFP_KERNEL);2245if (vpif_obj.sd == NULL) {2246vpif_err("unable to allocate memory for subdevice pointers\n");2247err = -ENOMEM;2248goto probe_out;2249}22502251err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);2252if (err) {2253v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");2254goto probe_subdev_out;2255}22562257for (i = 0; i < subdev_count; i++) {2258subdevdata = &config->subdev_info[i];2259vpif_obj.sd[i] =2260v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,2261i2c_adap,2262&subdevdata->board_info,2263NULL);22642265if (!vpif_obj.sd[i]) {2266vpif_err("Error registering v4l2 subdevice\n");2267goto probe_subdev_out;2268}2269v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",2270subdevdata->name);22712272if (vpif_obj.sd[i])2273vpif_obj.sd[i]->grp_id = 1 << i;2274}22752276v4l2_info(&vpif_obj.v4l2_dev,2277"DM646x VPIF capture driver initialized\n");2278return 0;22792280probe_subdev_out:2281/* free sub devices memory */2282kfree(vpif_obj.sd);22832284j = VPIF_CAPTURE_MAX_DEVICES;2285probe_out:2286v4l2_device_unregister(&vpif_obj.v4l2_dev);2287for (k = 0; k < j; k++) {2288/* Get the pointer to the channel object */2289ch = vpif_obj.dev[k];2290/* Unregister video device */2291video_unregister_device(ch->video_dev);2292}22932294vpif_dev_alloc_err:2295k = VPIF_CAPTURE_MAX_DEVICES-1;2296res = platform_get_resource(pdev, IORESOURCE_IRQ, k);2297i = res->end;22982299vpif_int_err:2300for (q = k; q >= 0; q--) {2301for (m = i; m >= (int)res->start; m--)2302free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id));23032304res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1);2305if (res)2306i = res->end;2307}2308return err;2309}23102311/**2312* vpif_remove() - driver remove handler2313* @device: ptr to platform device structure2314*2315* The vidoe device is unregistered2316*/2317static int vpif_remove(struct platform_device *device)2318{2319int i;2320struct channel_obj *ch;23212322v4l2_device_unregister(&vpif_obj.v4l2_dev);23232324/* un-register device */2325for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {2326/* Get the pointer to the channel object */2327ch = vpif_obj.dev[i];2328/* Unregister video device */2329video_unregister_device(ch->video_dev);2330}2331return 0;2332}23332334/**2335* vpif_suspend: vpif device suspend2336*2337* TODO: Add suspend code here2338*/2339static int2340vpif_suspend(struct device *dev)2341{2342return -1;2343}23442345/**2346* vpif_resume: vpif device suspend2347*2348* TODO: Add resume code here2349*/2350static int2351vpif_resume(struct device *dev)2352{2353return -1;2354}23552356static const struct dev_pm_ops vpif_dev_pm_ops = {2357.suspend = vpif_suspend,2358.resume = vpif_resume,2359};23602361static __refdata struct platform_driver vpif_driver = {2362.driver = {2363.name = "vpif_capture",2364.owner = THIS_MODULE,2365.pm = &vpif_dev_pm_ops,2366},2367.probe = vpif_probe,2368.remove = vpif_remove,2369};23702371/**2372* vpif_init: initialize the vpif driver2373*2374* This function registers device and driver to the kernel, requests irq2375* handler and allocates memory2376* for channel objects2377*/2378static __init int vpif_init(void)2379{2380return platform_driver_register(&vpif_driver);2381}23822383/**2384* vpif_cleanup : This function clean up the vpif capture resources2385*2386* This will un-registers device and driver to the kernel, frees2387* requested irq handler and de-allocates memory allocated for channel2388* objects.2389*/2390static void vpif_cleanup(void)2391{2392struct platform_device *pdev;2393struct resource *res;2394int irq_num;2395int i = 0;23962397pdev = container_of(vpif_dev, struct platform_device, dev);2398while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {2399for (irq_num = res->start; irq_num <= res->end; irq_num++)2400free_irq(irq_num,2401(void *)(&vpif_obj.dev[i]->channel_id));2402i++;2403}24042405platform_driver_unregister(&vpif_driver);24062407kfree(vpif_obj.sd);2408for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++)2409kfree(vpif_obj.dev[i]);2410}24112412/* Function for module initialization and cleanup */2413module_init(vpif_init);2414module_exit(vpif_cleanup);241524162417