Path: blob/master/drivers/media/video/et61x251/et61x251_core.c
17687 views
/***************************************************************************1* V4L2 driver for ET61X[12]51 PC Camera Controllers *2* *3* Copyright (C) 2006-2007 by Luca Risolia <[email protected]> *4* *5* This program is free software; you can redistribute it and/or modify *6* it under the terms of the GNU General Public License as published by *7* the Free Software Foundation; either version 2 of the License, or *8* (at your option) any later version. *9* *10* This program is distributed in the hope that it will be useful, *11* but WITHOUT ANY WARRANTY; without even the implied warranty of *12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *13* GNU General Public License for more details. *14* *15* You should have received a copy of the GNU General Public License *16* along with this program; if not, write to the Free Software *17* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *18***************************************************************************/1920#include <linux/module.h>21#include <linux/init.h>22#include <linux/kernel.h>23#include <linux/param.h>24#include <linux/errno.h>25#include <linux/slab.h>26#include <linux/device.h>27#include <linux/fs.h>28#include <linux/delay.h>29#include <linux/compiler.h>30#include <linux/ioctl.h>31#include <linux/poll.h>32#include <linux/stat.h>33#include <linux/mm.h>34#include <linux/vmalloc.h>35#include <linux/page-flags.h>36#include <media/v4l2-ioctl.h>37#include <asm/byteorder.h>38#include <asm/page.h>39#include <asm/uaccess.h>4041#include "et61x251.h"4243/*****************************************************************************/4445#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \46"PC Camera Controllers"47#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"48#define ET61X251_AUTHOR_EMAIL "<[email protected]>"49#define ET61X251_MODULE_LICENSE "GPL"50#define ET61X251_MODULE_VERSION "1:1.09"51#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9)5253/*****************************************************************************/5455MODULE_DEVICE_TABLE(usb, et61x251_id_table);5657MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);58MODULE_DESCRIPTION(ET61X251_MODULE_NAME);59MODULE_VERSION(ET61X251_MODULE_VERSION);60MODULE_LICENSE(ET61X251_MODULE_LICENSE);6162static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};63module_param_array(video_nr, short, NULL, 0444);64MODULE_PARM_DESC(video_nr,65"\n<-1|n[,...]> Specify V4L2 minor mode number."66"\n -1 = use next available (default)"67"\n n = use minor number n (integer >= 0)"68"\nYou can specify up to "69__MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."70"\nFor example:"71"\nvideo_nr=-1,2,-1 would assign minor number 2 to"72"\nthe second registered camera and use auto for the first"73"\none and for every other camera."74"\n");7576static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =77ET61X251_FORCE_MUNMAP};78module_param_array(force_munmap, bool, NULL, 0444);79MODULE_PARM_DESC(force_munmap,80"\n<0|1[,...]> Force the application to unmap previously"81"\nmapped buffer memory before calling any VIDIOC_S_CROP or"82"\nVIDIOC_S_FMT ioctl's. Not all the applications support"83"\nthis feature. This parameter is specific for each"84"\ndetected camera."85"\n 0 = do not force memory unmapping"86"\n 1 = force memory unmapping (save memory)"87"\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"."88"\n");8990static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =91ET61X251_FRAME_TIMEOUT};92module_param_array(frame_timeout, uint, NULL, 0644);93MODULE_PARM_DESC(frame_timeout,94"\n<n[,...]> Timeout for a video frame in seconds."95"\nThis parameter is specific for each detected camera."96"\nDefault value is "97__MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."98"\n");99100#ifdef ET61X251_DEBUG101static unsigned short debug = ET61X251_DEBUG_LEVEL;102module_param(debug, ushort, 0644);103MODULE_PARM_DESC(debug,104"\n<n> Debugging information level, from 0 to 3:"105"\n0 = none (use carefully)"106"\n1 = critical errors"107"\n2 = significant informations"108"\n3 = more verbose messages"109"\nLevel 3 is useful for testing only, when only "110"one device is used."111"\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."112"\n");113#endif114115/*****************************************************************************/116117static u32118et61x251_request_buffers(struct et61x251_device* cam, u32 count,119enum et61x251_io_method io)120{121struct v4l2_pix_format* p = &(cam->sensor.pix_format);122struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);123const size_t imagesize = cam->module_param.force_munmap ||124io == IO_READ ?125(p->width * p->height * p->priv) / 8 :126(r->width * r->height * p->priv) / 8;127void* buff = NULL;128u32 i;129130if (count > ET61X251_MAX_FRAMES)131count = ET61X251_MAX_FRAMES;132133cam->nbuffers = count;134while (cam->nbuffers > 0) {135if ((buff = vmalloc_32_user(cam->nbuffers *136PAGE_ALIGN(imagesize))))137break;138cam->nbuffers--;139}140141for (i = 0; i < cam->nbuffers; i++) {142cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);143cam->frame[i].buf.index = i;144cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);145cam->frame[i].buf.length = imagesize;146cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;147cam->frame[i].buf.sequence = 0;148cam->frame[i].buf.field = V4L2_FIELD_NONE;149cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;150cam->frame[i].buf.flags = 0;151}152153return cam->nbuffers;154}155156157static void et61x251_release_buffers(struct et61x251_device* cam)158{159if (cam->nbuffers) {160vfree(cam->frame[0].bufmem);161cam->nbuffers = 0;162}163cam->frame_current = NULL;164}165166167static void et61x251_empty_framequeues(struct et61x251_device* cam)168{169u32 i;170171INIT_LIST_HEAD(&cam->inqueue);172INIT_LIST_HEAD(&cam->outqueue);173174for (i = 0; i < ET61X251_MAX_FRAMES; i++) {175cam->frame[i].state = F_UNUSED;176cam->frame[i].buf.bytesused = 0;177}178}179180181static void et61x251_requeue_outqueue(struct et61x251_device* cam)182{183struct et61x251_frame_t *i;184185list_for_each_entry(i, &cam->outqueue, frame) {186i->state = F_QUEUED;187list_add(&i->frame, &cam->inqueue);188}189190INIT_LIST_HEAD(&cam->outqueue);191}192193194static void et61x251_queue_unusedframes(struct et61x251_device* cam)195{196unsigned long lock_flags;197u32 i;198199for (i = 0; i < cam->nbuffers; i++)200if (cam->frame[i].state == F_UNUSED) {201cam->frame[i].state = F_QUEUED;202spin_lock_irqsave(&cam->queue_lock, lock_flags);203list_add_tail(&cam->frame[i].frame, &cam->inqueue);204spin_unlock_irqrestore(&cam->queue_lock, lock_flags);205}206}207208/*****************************************************************************/209210int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)211{212struct usb_device* udev = cam->usbdev;213u8* buff = cam->control_buffer;214int res;215216*buff = value;217218res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,2190, index, buff, 1, ET61X251_CTRL_TIMEOUT);220if (res < 0) {221DBG(3, "Failed to write a register (value 0x%02X, index "222"0x%02X, error %d)", value, index, res);223return -1;224}225226return 0;227}228229230static int et61x251_read_reg(struct et61x251_device* cam, u16 index)231{232struct usb_device* udev = cam->usbdev;233u8* buff = cam->control_buffer;234int res;235236res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,2370, index, buff, 1, ET61X251_CTRL_TIMEOUT);238if (res < 0)239DBG(3, "Failed to read a register (index 0x%02X, error %d)",240index, res);241242return (res >= 0) ? (int)(*buff) : -1;243}244245246static int247et61x251_i2c_wait(struct et61x251_device* cam,248const struct et61x251_sensor* sensor)249{250int i, r;251252for (i = 1; i <= 8; i++) {253if (sensor->interface == ET61X251_I2C_3WIRES) {254r = et61x251_read_reg(cam, 0x8e);255if (!(r & 0x02) && (r >= 0))256return 0;257} else {258r = et61x251_read_reg(cam, 0x8b);259if (!(r & 0x01) && (r >= 0))260return 0;261}262if (r < 0)263return -EIO;264udelay(8*8); /* minimum for sensors at 400kHz */265}266267return -EBUSY;268}269270271int272et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,273u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,274u8 data8, u8 address)275{276struct usb_device* udev = cam->usbdev;277u8* data = cam->control_buffer;278int err = 0, res;279280data[0] = data2;281data[1] = data3;282data[2] = data4;283data[3] = data5;284data[4] = data6;285data[5] = data7;286data[6] = data8;287res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,2880, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);289if (res < 0)290err += res;291292data[0] = address;293data[1] = cam->sensor.i2c_slave_id;294data[2] = cam->sensor.rsta | 0x02 | (n << 4);295res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,2960, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);297if (res < 0)298err += res;299300/* Start writing through the serial interface */301data[0] = data1;302res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,3030, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);304if (res < 0)305err += res;306307err += et61x251_i2c_wait(cam, &cam->sensor);308309if (err)310DBG(3, "I2C raw write failed for %s image sensor",311cam->sensor.name);312313PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "314"data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"315" data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,316data1, data2, data3, data4, data5, data6, data7, data8);317318return err ? -1 : 0;319320}321322323/*****************************************************************************/324325static void et61x251_urb_complete(struct urb *urb)326{327struct et61x251_device* cam = urb->context;328struct et61x251_frame_t** f;329size_t imagesize;330u8 i;331int err = 0;332333if (urb->status == -ENOENT)334return;335336f = &cam->frame_current;337338if (cam->stream == STREAM_INTERRUPT) {339cam->stream = STREAM_OFF;340if ((*f))341(*f)->state = F_QUEUED;342DBG(3, "Stream interrupted");343wake_up(&cam->wait_stream);344}345346if (cam->state & DEV_DISCONNECTED)347return;348349if (cam->state & DEV_MISCONFIGURED) {350wake_up_interruptible(&cam->wait_frame);351return;352}353354if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))355goto resubmit_urb;356357if (!(*f))358(*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,359frame);360361imagesize = (cam->sensor.pix_format.width *362cam->sensor.pix_format.height *363cam->sensor.pix_format.priv) / 8;364365for (i = 0; i < urb->number_of_packets; i++) {366unsigned int len, status;367void *pos;368u8* b1, * b2, sof;369const u8 VOID_BYTES = 6;370size_t imglen;371372len = urb->iso_frame_desc[i].actual_length;373status = urb->iso_frame_desc[i].status;374pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;375376if (status) {377DBG(3, "Error in isochronous frame");378(*f)->state = F_ERROR;379continue;380}381382b1 = pos++;383b2 = pos++;384sof = ((*b1 & 0x3f) == 63);385imglen = ((*b1 & 0xc0) << 2) | *b2;386387PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",388len, i, imglen);389390if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)391start_of_frame:392if (sof) {393(*f)->state = F_GRABBING;394(*f)->buf.bytesused = 0;395do_gettimeofday(&(*f)->buf.timestamp);396pos += 22;397DBG(3, "SOF detected: new video frame");398}399400if ((*f)->state == F_GRABBING) {401if (sof && (*f)->buf.bytesused) {402if (cam->sensor.pix_format.pixelformat ==403V4L2_PIX_FMT_ET61X251)404goto end_of_frame;405else {406DBG(3, "Not expected SOF detected "407"after %lu bytes",408(unsigned long)(*f)->buf.bytesused);409(*f)->state = F_ERROR;410continue;411}412}413414if ((*f)->buf.bytesused + imglen > imagesize) {415DBG(3, "Video frame size exceeded");416(*f)->state = F_ERROR;417continue;418}419420pos += VOID_BYTES;421422memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);423(*f)->buf.bytesused += imglen;424425if ((*f)->buf.bytesused == imagesize) {426u32 b;427end_of_frame:428b = (*f)->buf.bytesused;429(*f)->state = F_DONE;430(*f)->buf.sequence= ++cam->frame_count;431spin_lock(&cam->queue_lock);432list_move_tail(&(*f)->frame, &cam->outqueue);433if (!list_empty(&cam->inqueue))434(*f) = list_entry(cam->inqueue.next,435struct et61x251_frame_t,436frame);437else438(*f) = NULL;439spin_unlock(&cam->queue_lock);440DBG(3, "Video frame captured: : %lu bytes",441(unsigned long)(b));442443if (!(*f))444goto resubmit_urb;445446if (sof &&447cam->sensor.pix_format.pixelformat ==448V4L2_PIX_FMT_ET61X251)449goto start_of_frame;450}451}452}453454resubmit_urb:455urb->dev = cam->usbdev;456err = usb_submit_urb(urb, GFP_ATOMIC);457if (err < 0 && err != -EPERM) {458cam->state |= DEV_MISCONFIGURED;459DBG(1, "usb_submit_urb() failed");460}461462wake_up_interruptible(&cam->wait_frame);463}464465466static int et61x251_start_transfer(struct et61x251_device* cam)467{468struct usb_device *udev = cam->usbdev;469struct urb* urb;470struct usb_host_interface* altsetting = usb_altnum_to_altsetting(471usb_ifnum_to_if(udev, 0),472ET61X251_ALTERNATE_SETTING);473const unsigned int psz = le16_to_cpu(altsetting->474endpoint[0].desc.wMaxPacketSize);475s8 i, j;476int err = 0;477478for (i = 0; i < ET61X251_URBS; i++) {479cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,480GFP_KERNEL);481if (!cam->transfer_buffer[i]) {482err = -ENOMEM;483DBG(1, "Not enough memory");484goto free_buffers;485}486}487488for (i = 0; i < ET61X251_URBS; i++) {489urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);490cam->urb[i] = urb;491if (!urb) {492err = -ENOMEM;493DBG(1, "usb_alloc_urb() failed");494goto free_urbs;495}496urb->dev = udev;497urb->context = cam;498urb->pipe = usb_rcvisocpipe(udev, 1);499urb->transfer_flags = URB_ISO_ASAP;500urb->number_of_packets = ET61X251_ISO_PACKETS;501urb->complete = et61x251_urb_complete;502urb->transfer_buffer = cam->transfer_buffer[i];503urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;504urb->interval = 1;505for (j = 0; j < ET61X251_ISO_PACKETS; j++) {506urb->iso_frame_desc[j].offset = psz * j;507urb->iso_frame_desc[j].length = psz;508}509}510511err = et61x251_write_reg(cam, 0x01, 0x03);512err = et61x251_write_reg(cam, 0x00, 0x03);513err = et61x251_write_reg(cam, 0x08, 0x03);514if (err) {515err = -EIO;516DBG(1, "I/O hardware error");517goto free_urbs;518}519520err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);521if (err) {522DBG(1, "usb_set_interface() failed");523goto free_urbs;524}525526cam->frame_current = NULL;527528for (i = 0; i < ET61X251_URBS; i++) {529err = usb_submit_urb(cam->urb[i], GFP_KERNEL);530if (err) {531for (j = i-1; j >= 0; j--)532usb_kill_urb(cam->urb[j]);533DBG(1, "usb_submit_urb() failed, error %d", err);534goto free_urbs;535}536}537538return 0;539540free_urbs:541for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)542usb_free_urb(cam->urb[i]);543544free_buffers:545for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)546kfree(cam->transfer_buffer[i]);547548return err;549}550551552static int et61x251_stop_transfer(struct et61x251_device* cam)553{554struct usb_device *udev = cam->usbdev;555s8 i;556int err = 0;557558if (cam->state & DEV_DISCONNECTED)559return 0;560561for (i = ET61X251_URBS-1; i >= 0; i--) {562usb_kill_urb(cam->urb[i]);563usb_free_urb(cam->urb[i]);564kfree(cam->transfer_buffer[i]);565}566567err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */568if (err)569DBG(3, "usb_set_interface() failed");570571return err;572}573574575static int et61x251_stream_interrupt(struct et61x251_device* cam)576{577long timeout;578579cam->stream = STREAM_INTERRUPT;580timeout = wait_event_timeout(cam->wait_stream,581(cam->stream == STREAM_OFF) ||582(cam->state & DEV_DISCONNECTED),583ET61X251_URB_TIMEOUT);584if (cam->state & DEV_DISCONNECTED)585return -ENODEV;586else if (cam->stream != STREAM_OFF) {587cam->state |= DEV_MISCONFIGURED;588DBG(1, "URB timeout reached. The camera is misconfigured. To "589"use it, close and open %s again.",590video_device_node_name(cam->v4ldev));591return -EIO;592}593594return 0;595}596597/*****************************************************************************/598599#ifdef CONFIG_VIDEO_ADV_DEBUG600601static int et61x251_i2c_try_read(struct et61x251_device* cam,602const struct et61x251_sensor* sensor,603u8 address)604{605struct usb_device* udev = cam->usbdev;606u8* data = cam->control_buffer;607int err = 0, res;608609data[0] = address;610data[1] = cam->sensor.i2c_slave_id;611data[2] = cam->sensor.rsta | 0x10;612data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);613res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,6140, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);615if (res < 0)616err += res;617618err += et61x251_i2c_wait(cam, sensor);619620res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,6210, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);622if (res < 0)623err += res;624625if (err)626DBG(3, "I2C read failed for %s image sensor", sensor->name);627628PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);629630return err ? -1 : (int)data[0];631}632633634static int et61x251_i2c_try_write(struct et61x251_device* cam,635const struct et61x251_sensor* sensor,636u8 address, u8 value)637{638struct usb_device* udev = cam->usbdev;639u8* data = cam->control_buffer;640int err = 0, res;641642data[0] = address;643data[1] = cam->sensor.i2c_slave_id;644data[2] = cam->sensor.rsta | 0x12;645res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,6460, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);647if (res < 0)648err += res;649650data[0] = value;651res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,6520, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);653if (res < 0)654err += res;655656err += et61x251_i2c_wait(cam, sensor);657658if (err)659DBG(3, "I2C write failed for %s image sensor", sensor->name);660661PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);662663return err ? -1 : 0;664}665666static int et61x251_i2c_read(struct et61x251_device* cam, u8 address)667{668return et61x251_i2c_try_read(cam, &cam->sensor, address);669}670671static int et61x251_i2c_write(struct et61x251_device* cam,672u8 address, u8 value)673{674return et61x251_i2c_try_write(cam, &cam->sensor, address, value);675}676677static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)678{679char str[5];680char* endp;681unsigned long val;682683if (len < 4) {684strncpy(str, buff, len);685str[len] = '\0';686} else {687strncpy(str, buff, 4);688str[4] = '\0';689}690691val = simple_strtoul(str, &endp, 0);692693*count = 0;694if (val <= 0xff)695*count = (ssize_t)(endp - str);696if ((*count) && (len == *count+1) && (buff[*count] == '\n'))697*count += 1;698699return (u8)val;700}701702/*703NOTE 1: being inside one of the following methods implies that the v4l704device exists for sure (see kobjects and reference counters)705NOTE 2: buffers are PAGE_SIZE long706*/707708static ssize_t et61x251_show_reg(struct device* cd,709struct device_attribute *attr, char* buf)710{711struct et61x251_device* cam;712ssize_t count;713714if (mutex_lock_interruptible(&et61x251_sysfs_lock))715return -ERESTARTSYS;716717cam = video_get_drvdata(to_video_device(cd));718if (!cam) {719mutex_unlock(&et61x251_sysfs_lock);720return -ENODEV;721}722723count = sprintf(buf, "%u\n", cam->sysfs.reg);724725mutex_unlock(&et61x251_sysfs_lock);726727return count;728}729730731static ssize_t732et61x251_store_reg(struct device* cd,733struct device_attribute *attr, const char* buf, size_t len)734{735struct et61x251_device* cam;736u8 index;737ssize_t count;738739if (mutex_lock_interruptible(&et61x251_sysfs_lock))740return -ERESTARTSYS;741742cam = video_get_drvdata(to_video_device(cd));743if (!cam) {744mutex_unlock(&et61x251_sysfs_lock);745return -ENODEV;746}747748index = et61x251_strtou8(buf, len, &count);749if (index > 0x8e || !count) {750mutex_unlock(&et61x251_sysfs_lock);751return -EINVAL;752}753754cam->sysfs.reg = index;755756DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);757DBG(3, "Written bytes: %zd", count);758759mutex_unlock(&et61x251_sysfs_lock);760761return count;762}763764765static ssize_t et61x251_show_val(struct device* cd,766struct device_attribute *attr, char* buf)767{768struct et61x251_device* cam;769ssize_t count;770int val;771772if (mutex_lock_interruptible(&et61x251_sysfs_lock))773return -ERESTARTSYS;774775cam = video_get_drvdata(to_video_device(cd));776if (!cam) {777mutex_unlock(&et61x251_sysfs_lock);778return -ENODEV;779}780781if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {782mutex_unlock(&et61x251_sysfs_lock);783return -EIO;784}785786count = sprintf(buf, "%d\n", val);787788DBG(3, "Read bytes: %zd", count);789790mutex_unlock(&et61x251_sysfs_lock);791792return count;793}794795796static ssize_t797et61x251_store_val(struct device* cd, struct device_attribute *attr,798const char* buf, size_t len)799{800struct et61x251_device* cam;801u8 value;802ssize_t count;803int err;804805if (mutex_lock_interruptible(&et61x251_sysfs_lock))806return -ERESTARTSYS;807808cam = video_get_drvdata(to_video_device(cd));809if (!cam) {810mutex_unlock(&et61x251_sysfs_lock);811return -ENODEV;812}813814value = et61x251_strtou8(buf, len, &count);815if (!count) {816mutex_unlock(&et61x251_sysfs_lock);817return -EINVAL;818}819820err = et61x251_write_reg(cam, value, cam->sysfs.reg);821if (err) {822mutex_unlock(&et61x251_sysfs_lock);823return -EIO;824}825826DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",827cam->sysfs.reg, value);828DBG(3, "Written bytes: %zd", count);829830mutex_unlock(&et61x251_sysfs_lock);831832return count;833}834835836static ssize_t et61x251_show_i2c_reg(struct device* cd,837struct device_attribute *attr, char* buf)838{839struct et61x251_device* cam;840ssize_t count;841842if (mutex_lock_interruptible(&et61x251_sysfs_lock))843return -ERESTARTSYS;844845cam = video_get_drvdata(to_video_device(cd));846if (!cam) {847mutex_unlock(&et61x251_sysfs_lock);848return -ENODEV;849}850851count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);852853DBG(3, "Read bytes: %zd", count);854855mutex_unlock(&et61x251_sysfs_lock);856857return count;858}859860861static ssize_t862et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr,863const char* buf, size_t len)864{865struct et61x251_device* cam;866u8 index;867ssize_t count;868869if (mutex_lock_interruptible(&et61x251_sysfs_lock))870return -ERESTARTSYS;871872cam = video_get_drvdata(to_video_device(cd));873if (!cam) {874mutex_unlock(&et61x251_sysfs_lock);875return -ENODEV;876}877878index = et61x251_strtou8(buf, len, &count);879if (!count) {880mutex_unlock(&et61x251_sysfs_lock);881return -EINVAL;882}883884cam->sysfs.i2c_reg = index;885886DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);887DBG(3, "Written bytes: %zd", count);888889mutex_unlock(&et61x251_sysfs_lock);890891return count;892}893894895static ssize_t et61x251_show_i2c_val(struct device* cd,896struct device_attribute *attr, char* buf)897{898struct et61x251_device* cam;899ssize_t count;900int val;901902if (mutex_lock_interruptible(&et61x251_sysfs_lock))903return -ERESTARTSYS;904905cam = video_get_drvdata(to_video_device(cd));906if (!cam) {907mutex_unlock(&et61x251_sysfs_lock);908return -ENODEV;909}910911if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {912mutex_unlock(&et61x251_sysfs_lock);913return -ENOSYS;914}915916if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {917mutex_unlock(&et61x251_sysfs_lock);918return -EIO;919}920921count = sprintf(buf, "%d\n", val);922923DBG(3, "Read bytes: %zd", count);924925mutex_unlock(&et61x251_sysfs_lock);926927return count;928}929930931static ssize_t932et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr,933const char* buf, size_t len)934{935struct et61x251_device* cam;936u8 value;937ssize_t count;938int err;939940if (mutex_lock_interruptible(&et61x251_sysfs_lock))941return -ERESTARTSYS;942943cam = video_get_drvdata(to_video_device(cd));944if (!cam) {945mutex_unlock(&et61x251_sysfs_lock);946return -ENODEV;947}948949if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {950mutex_unlock(&et61x251_sysfs_lock);951return -ENOSYS;952}953954value = et61x251_strtou8(buf, len, &count);955if (!count) {956mutex_unlock(&et61x251_sysfs_lock);957return -EINVAL;958}959960err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);961if (err) {962mutex_unlock(&et61x251_sysfs_lock);963return -EIO;964}965966DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",967cam->sysfs.i2c_reg, value);968DBG(3, "Written bytes: %zd", count);969970mutex_unlock(&et61x251_sysfs_lock);971972return count;973}974975976static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,977et61x251_show_reg, et61x251_store_reg);978static DEVICE_ATTR(val, S_IRUGO | S_IWUSR,979et61x251_show_val, et61x251_store_val);980static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,981et61x251_show_i2c_reg, et61x251_store_i2c_reg);982static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,983et61x251_show_i2c_val, et61x251_store_i2c_val);984985986static int et61x251_create_sysfs(struct et61x251_device* cam)987{988struct device *classdev = &(cam->v4ldev->dev);989int err = 0;990991if ((err = device_create_file(classdev, &dev_attr_reg)))992goto err_out;993if ((err = device_create_file(classdev, &dev_attr_val)))994goto err_reg;995996if (cam->sensor.sysfs_ops) {997if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))998goto err_val;999if ((err = device_create_file(classdev, &dev_attr_i2c_val)))1000goto err_i2c_reg;1001}10021003err_i2c_reg:1004if (cam->sensor.sysfs_ops)1005device_remove_file(classdev, &dev_attr_i2c_reg);1006err_val:1007device_remove_file(classdev, &dev_attr_val);1008err_reg:1009device_remove_file(classdev, &dev_attr_reg);1010err_out:1011return err;1012}1013#endif /* CONFIG_VIDEO_ADV_DEBUG */10141015/*****************************************************************************/10161017static int1018et61x251_set_pix_format(struct et61x251_device* cam,1019struct v4l2_pix_format* pix)1020{1021int r, err = 0;10221023if ((r = et61x251_read_reg(cam, 0x12)) < 0)1024err += r;1025if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)1026err += et61x251_write_reg(cam, r & 0xfd, 0x12);1027else1028err += et61x251_write_reg(cam, r | 0x02, 0x12);10291030return err ? -EIO : 0;1031}103210331034static int1035et61x251_set_compression(struct et61x251_device* cam,1036struct v4l2_jpegcompression* compression)1037{1038int r, err = 0;10391040if ((r = et61x251_read_reg(cam, 0x12)) < 0)1041err += r;1042if (compression->quality == 0)1043err += et61x251_write_reg(cam, r & 0xfb, 0x12);1044else1045err += et61x251_write_reg(cam, r | 0x04, 0x12);10461047return err ? -EIO : 0;1048}104910501051static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)1052{1053int r = 0, err = 0;10541055r = et61x251_read_reg(cam, 0x12);1056if (r < 0)1057err += r;10581059if (scale == 1)1060err += et61x251_write_reg(cam, r & ~0x01, 0x12);1061else if (scale == 2)1062err += et61x251_write_reg(cam, r | 0x01, 0x12);10631064if (err)1065return -EIO;10661067PDBGG("Scaling factor: %u", scale);10681069return 0;1070}107110721073static int1074et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)1075{1076struct et61x251_sensor* s = &cam->sensor;1077u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +1078s->active_pixel.left),1079fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +1080s->active_pixel.top),1081fmw_length = (u16)(rect->width),1082fmw_height = (u16)(rect->height);1083int err = 0;10841085err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);1086err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);1087err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);1088err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);1089err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)1090| ((fmw_length & 0x300) >> 4)1091| ((fmw_height & 0x300) >> 2), 0x6d);1092if (err)1093return -EIO;10941095PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",1096fmw_sx, fmw_sy, fmw_length, fmw_height);10971098return 0;1099}110011011102static int et61x251_init(struct et61x251_device* cam)1103{1104struct et61x251_sensor* s = &cam->sensor;1105struct v4l2_control ctrl;1106struct v4l2_queryctrl *qctrl;1107struct v4l2_rect* rect;1108u8 i = 0;1109int err = 0;11101111if (!(cam->state & DEV_INITIALIZED)) {1112mutex_init(&cam->open_mutex);1113init_waitqueue_head(&cam->wait_open);1114qctrl = s->qctrl;1115rect = &(s->cropcap.defrect);1116cam->compression.quality = ET61X251_COMPRESSION_QUALITY;1117} else { /* use current values */1118qctrl = s->_qctrl;1119rect = &(s->_rect);1120}11211122err += et61x251_set_scale(cam, rect->width / s->pix_format.width);1123err += et61x251_set_crop(cam, rect);1124if (err)1125return err;11261127if (s->init) {1128err = s->init(cam);1129if (err) {1130DBG(3, "Sensor initialization failed");1131return err;1132}1133}11341135err += et61x251_set_compression(cam, &cam->compression);1136err += et61x251_set_pix_format(cam, &s->pix_format);1137if (s->set_pix_format)1138err += s->set_pix_format(cam, &s->pix_format);1139if (err)1140return err;11411142if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)1143DBG(3, "Compressed video format is active, quality %d",1144cam->compression.quality);1145else1146DBG(3, "Uncompressed video format is active");11471148if (s->set_crop)1149if ((err = s->set_crop(cam, rect))) {1150DBG(3, "set_crop() failed");1151return err;1152}11531154if (s->set_ctrl) {1155for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)1156if (s->qctrl[i].id != 0 &&1157!(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {1158ctrl.id = s->qctrl[i].id;1159ctrl.value = qctrl[i].default_value;1160err = s->set_ctrl(cam, &ctrl);1161if (err) {1162DBG(3, "Set %s control failed",1163s->qctrl[i].name);1164return err;1165}1166DBG(3, "Image sensor supports '%s' control",1167s->qctrl[i].name);1168}1169}11701171if (!(cam->state & DEV_INITIALIZED)) {1172mutex_init(&cam->fileop_mutex);1173spin_lock_init(&cam->queue_lock);1174init_waitqueue_head(&cam->wait_frame);1175init_waitqueue_head(&cam->wait_stream);1176cam->nreadbuffers = 2;1177memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));1178memcpy(&(s->_rect), &(s->cropcap.defrect),1179sizeof(struct v4l2_rect));1180cam->state |= DEV_INITIALIZED;1181}11821183DBG(2, "Initialization succeeded");1184return 0;1185}11861187/*****************************************************************************/11881189static void et61x251_release_resources(struct kref *kref)1190{1191struct et61x251_device *cam;11921193mutex_lock(&et61x251_sysfs_lock);11941195cam = container_of(kref, struct et61x251_device, kref);11961197DBG(2, "V4L2 device %s deregistered",1198video_device_node_name(cam->v4ldev));1199video_set_drvdata(cam->v4ldev, NULL);1200video_unregister_device(cam->v4ldev);1201usb_put_dev(cam->usbdev);1202kfree(cam->control_buffer);1203kfree(cam);12041205mutex_unlock(&et61x251_sysfs_lock);1206}120712081209static int et61x251_open(struct file *filp)1210{1211struct et61x251_device* cam;1212int err = 0;12131214if (!down_read_trylock(&et61x251_dev_lock))1215return -ERESTARTSYS;12161217cam = video_drvdata(filp);12181219if (wait_for_completion_interruptible(&cam->probe)) {1220up_read(&et61x251_dev_lock);1221return -ERESTARTSYS;1222}12231224kref_get(&cam->kref);12251226if (mutex_lock_interruptible(&cam->open_mutex)) {1227kref_put(&cam->kref, et61x251_release_resources);1228up_read(&et61x251_dev_lock);1229return -ERESTARTSYS;1230}12311232if (cam->state & DEV_DISCONNECTED) {1233DBG(1, "Device not present");1234err = -ENODEV;1235goto out;1236}12371238if (cam->users) {1239DBG(2, "Device %s is already in use",1240video_device_node_name(cam->v4ldev));1241DBG(3, "Simultaneous opens are not supported");1242if ((filp->f_flags & O_NONBLOCK) ||1243(filp->f_flags & O_NDELAY)) {1244err = -EWOULDBLOCK;1245goto out;1246}1247DBG(2, "A blocking open() has been requested. Wait for the "1248"device to be released...");1249up_read(&et61x251_dev_lock);1250err = wait_event_interruptible_exclusive(cam->wait_open,1251(cam->state & DEV_DISCONNECTED)1252|| !cam->users);1253down_read(&et61x251_dev_lock);1254if (err)1255goto out;1256if (cam->state & DEV_DISCONNECTED) {1257err = -ENODEV;1258goto out;1259}1260}12611262if (cam->state & DEV_MISCONFIGURED) {1263err = et61x251_init(cam);1264if (err) {1265DBG(1, "Initialization failed again. "1266"I will retry on next open().");1267goto out;1268}1269cam->state &= ~DEV_MISCONFIGURED;1270}12711272if ((err = et61x251_start_transfer(cam)))1273goto out;12741275filp->private_data = cam;1276cam->users++;1277cam->io = IO_NONE;1278cam->stream = STREAM_OFF;1279cam->nbuffers = 0;1280cam->frame_count = 0;1281et61x251_empty_framequeues(cam);12821283DBG(3, "Video device %s is open",1284video_device_node_name(cam->v4ldev));12851286out:1287mutex_unlock(&cam->open_mutex);1288if (err)1289kref_put(&cam->kref, et61x251_release_resources);1290up_read(&et61x251_dev_lock);1291return err;1292}129312941295static int et61x251_release(struct file *filp)1296{1297struct et61x251_device* cam;12981299down_write(&et61x251_dev_lock);13001301cam = video_drvdata(filp);13021303et61x251_stop_transfer(cam);1304et61x251_release_buffers(cam);1305cam->users--;1306wake_up_interruptible_nr(&cam->wait_open, 1);13071308DBG(3, "Video device %s closed",1309video_device_node_name(cam->v4ldev));13101311kref_put(&cam->kref, et61x251_release_resources);13121313up_write(&et61x251_dev_lock);13141315return 0;1316}131713181319static ssize_t1320et61x251_read(struct file* filp, char __user * buf,1321size_t count, loff_t* f_pos)1322{1323struct et61x251_device *cam = video_drvdata(filp);1324struct et61x251_frame_t* f, * i;1325unsigned long lock_flags;1326long timeout;1327int err = 0;13281329if (mutex_lock_interruptible(&cam->fileop_mutex))1330return -ERESTARTSYS;13311332if (cam->state & DEV_DISCONNECTED) {1333DBG(1, "Device not present");1334mutex_unlock(&cam->fileop_mutex);1335return -ENODEV;1336}13371338if (cam->state & DEV_MISCONFIGURED) {1339DBG(1, "The camera is misconfigured. Close and open it "1340"again.");1341mutex_unlock(&cam->fileop_mutex);1342return -EIO;1343}13441345if (cam->io == IO_MMAP) {1346DBG(3, "Close and open the device again to choose the read "1347"method");1348mutex_unlock(&cam->fileop_mutex);1349return -EBUSY;1350}13511352if (cam->io == IO_NONE) {1353if (!et61x251_request_buffers(cam, cam->nreadbuffers,1354IO_READ)) {1355DBG(1, "read() failed, not enough memory");1356mutex_unlock(&cam->fileop_mutex);1357return -ENOMEM;1358}1359cam->io = IO_READ;1360cam->stream = STREAM_ON;1361}13621363if (list_empty(&cam->inqueue)) {1364if (!list_empty(&cam->outqueue))1365et61x251_empty_framequeues(cam);1366et61x251_queue_unusedframes(cam);1367}13681369if (!count) {1370mutex_unlock(&cam->fileop_mutex);1371return 0;1372}13731374if (list_empty(&cam->outqueue)) {1375if (filp->f_flags & O_NONBLOCK) {1376mutex_unlock(&cam->fileop_mutex);1377return -EAGAIN;1378}1379timeout = wait_event_interruptible_timeout1380( cam->wait_frame,1381(!list_empty(&cam->outqueue)) ||1382(cam->state & DEV_DISCONNECTED) ||1383(cam->state & DEV_MISCONFIGURED),1384msecs_to_jiffies(1385cam->module_param.frame_timeout * 10001386)1387);1388if (timeout < 0) {1389mutex_unlock(&cam->fileop_mutex);1390return timeout;1391}1392if (cam->state & DEV_DISCONNECTED) {1393mutex_unlock(&cam->fileop_mutex);1394return -ENODEV;1395}1396if (!timeout || (cam->state & DEV_MISCONFIGURED)) {1397mutex_unlock(&cam->fileop_mutex);1398return -EIO;1399}1400}14011402f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);14031404if (count > f->buf.bytesused)1405count = f->buf.bytesused;14061407if (copy_to_user(buf, f->bufmem, count)) {1408err = -EFAULT;1409goto exit;1410}1411*f_pos += count;14121413exit:1414spin_lock_irqsave(&cam->queue_lock, lock_flags);1415list_for_each_entry(i, &cam->outqueue, frame)1416i->state = F_UNUSED;1417INIT_LIST_HEAD(&cam->outqueue);1418spin_unlock_irqrestore(&cam->queue_lock, lock_flags);14191420et61x251_queue_unusedframes(cam);14211422PDBGG("Frame #%lu, bytes read: %zu",1423(unsigned long)f->buf.index, count);14241425mutex_unlock(&cam->fileop_mutex);14261427return err ? err : count;1428}142914301431static unsigned int et61x251_poll(struct file *filp, poll_table *wait)1432{1433struct et61x251_device *cam = video_drvdata(filp);1434struct et61x251_frame_t* f;1435unsigned long lock_flags;1436unsigned int mask = 0;14371438if (mutex_lock_interruptible(&cam->fileop_mutex))1439return POLLERR;14401441if (cam->state & DEV_DISCONNECTED) {1442DBG(1, "Device not present");1443goto error;1444}14451446if (cam->state & DEV_MISCONFIGURED) {1447DBG(1, "The camera is misconfigured. Close and open it "1448"again.");1449goto error;1450}14511452if (cam->io == IO_NONE) {1453if (!et61x251_request_buffers(cam, cam->nreadbuffers,1454IO_READ)) {1455DBG(1, "poll() failed, not enough memory");1456goto error;1457}1458cam->io = IO_READ;1459cam->stream = STREAM_ON;1460}14611462if (cam->io == IO_READ) {1463spin_lock_irqsave(&cam->queue_lock, lock_flags);1464list_for_each_entry(f, &cam->outqueue, frame)1465f->state = F_UNUSED;1466INIT_LIST_HEAD(&cam->outqueue);1467spin_unlock_irqrestore(&cam->queue_lock, lock_flags);1468et61x251_queue_unusedframes(cam);1469}14701471poll_wait(filp, &cam->wait_frame, wait);14721473if (!list_empty(&cam->outqueue))1474mask |= POLLIN | POLLRDNORM;14751476mutex_unlock(&cam->fileop_mutex);14771478return mask;14791480error:1481mutex_unlock(&cam->fileop_mutex);1482return POLLERR;1483}148414851486static void et61x251_vm_open(struct vm_area_struct* vma)1487{1488struct et61x251_frame_t* f = vma->vm_private_data;1489f->vma_use_count++;1490}149114921493static void et61x251_vm_close(struct vm_area_struct* vma)1494{1495/* NOTE: buffers are not freed here */1496struct et61x251_frame_t* f = vma->vm_private_data;1497f->vma_use_count--;1498}149915001501static const struct vm_operations_struct et61x251_vm_ops = {1502.open = et61x251_vm_open,1503.close = et61x251_vm_close,1504};150515061507static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)1508{1509struct et61x251_device *cam = video_drvdata(filp);1510unsigned long size = vma->vm_end - vma->vm_start,1511start = vma->vm_start;1512void *pos;1513u32 i;15141515if (mutex_lock_interruptible(&cam->fileop_mutex))1516return -ERESTARTSYS;15171518if (cam->state & DEV_DISCONNECTED) {1519DBG(1, "Device not present");1520mutex_unlock(&cam->fileop_mutex);1521return -ENODEV;1522}15231524if (cam->state & DEV_MISCONFIGURED) {1525DBG(1, "The camera is misconfigured. Close and open it "1526"again.");1527mutex_unlock(&cam->fileop_mutex);1528return -EIO;1529}15301531if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {1532mutex_unlock(&cam->fileop_mutex);1533return -EACCES;1534}15351536if (cam->io != IO_MMAP ||1537size != PAGE_ALIGN(cam->frame[0].buf.length)) {1538mutex_unlock(&cam->fileop_mutex);1539return -EINVAL;1540}15411542for (i = 0; i < cam->nbuffers; i++) {1543if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)1544break;1545}1546if (i == cam->nbuffers) {1547mutex_unlock(&cam->fileop_mutex);1548return -EINVAL;1549}15501551vma->vm_flags |= VM_IO;1552vma->vm_flags |= VM_RESERVED;15531554pos = cam->frame[i].bufmem;1555while (size > 0) { /* size is page-aligned */1556if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {1557mutex_unlock(&cam->fileop_mutex);1558return -EAGAIN;1559}1560start += PAGE_SIZE;1561pos += PAGE_SIZE;1562size -= PAGE_SIZE;1563}15641565vma->vm_ops = &et61x251_vm_ops;1566vma->vm_private_data = &cam->frame[i];1567et61x251_vm_open(vma);15681569mutex_unlock(&cam->fileop_mutex);15701571return 0;1572}15731574/*****************************************************************************/15751576static int1577et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)1578{1579struct v4l2_capability cap = {1580.driver = "et61x251",1581.version = ET61X251_MODULE_VERSION_CODE,1582.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |1583V4L2_CAP_STREAMING,1584};15851586strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));1587if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)1588strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),1589sizeof(cap.bus_info));15901591if (copy_to_user(arg, &cap, sizeof(cap)))1592return -EFAULT;15931594return 0;1595}159615971598static int1599et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)1600{1601struct v4l2_input i;16021603if (copy_from_user(&i, arg, sizeof(i)))1604return -EFAULT;16051606if (i.index)1607return -EINVAL;16081609memset(&i, 0, sizeof(i));1610strcpy(i.name, "Camera");1611i.type = V4L2_INPUT_TYPE_CAMERA;1612i.capabilities = V4L2_IN_CAP_STD;16131614if (copy_to_user(arg, &i, sizeof(i)))1615return -EFAULT;16161617return 0;1618}161916201621static int1622et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)1623{1624int index = 0;16251626if (copy_to_user(arg, &index, sizeof(index)))1627return -EFAULT;16281629return 0;1630}163116321633static int1634et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)1635{1636int index;16371638if (copy_from_user(&index, arg, sizeof(index)))1639return -EFAULT;16401641if (index != 0)1642return -EINVAL;16431644return 0;1645}164616471648static int1649et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)1650{1651struct et61x251_sensor* s = &cam->sensor;1652struct v4l2_queryctrl qc;1653u8 i;16541655if (copy_from_user(&qc, arg, sizeof(qc)))1656return -EFAULT;16571658for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)1659if (qc.id && qc.id == s->qctrl[i].id) {1660memcpy(&qc, &(s->qctrl[i]), sizeof(qc));1661if (copy_to_user(arg, &qc, sizeof(qc)))1662return -EFAULT;1663return 0;1664}16651666return -EINVAL;1667}166816691670static int1671et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)1672{1673struct et61x251_sensor* s = &cam->sensor;1674struct v4l2_control ctrl;1675int err = 0;1676u8 i;16771678if (!s->get_ctrl && !s->set_ctrl)1679return -EINVAL;16801681if (copy_from_user(&ctrl, arg, sizeof(ctrl)))1682return -EFAULT;16831684if (!s->get_ctrl) {1685for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)1686if (ctrl.id == s->qctrl[i].id) {1687ctrl.value = s->_qctrl[i].default_value;1688goto exit;1689}1690return -EINVAL;1691} else1692err = s->get_ctrl(cam, &ctrl);16931694exit:1695if (copy_to_user(arg, &ctrl, sizeof(ctrl)))1696return -EFAULT;16971698return err;1699}170017011702static int1703et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)1704{1705struct et61x251_sensor* s = &cam->sensor;1706struct v4l2_control ctrl;1707u8 i;1708int err = 0;17091710if (!s->set_ctrl)1711return -EINVAL;17121713if (copy_from_user(&ctrl, arg, sizeof(ctrl)))1714return -EFAULT;17151716for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {1717if (ctrl.id == s->qctrl[i].id) {1718if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)1719return -EINVAL;1720if (ctrl.value < s->qctrl[i].minimum ||1721ctrl.value > s->qctrl[i].maximum)1722return -ERANGE;1723ctrl.value -= ctrl.value % s->qctrl[i].step;1724break;1725}1726}1727if (i == ARRAY_SIZE(s->qctrl))1728return -EINVAL;1729if ((err = s->set_ctrl(cam, &ctrl)))1730return err;17311732s->_qctrl[i].default_value = ctrl.value;17331734return 0;1735}173617371738static int1739et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)1740{1741struct v4l2_cropcap* cc = &(cam->sensor.cropcap);17421743cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;1744cc->pixelaspect.numerator = 1;1745cc->pixelaspect.denominator = 1;17461747if (copy_to_user(arg, cc, sizeof(*cc)))1748return -EFAULT;17491750return 0;1751}175217531754static int1755et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)1756{1757struct et61x251_sensor* s = &cam->sensor;1758struct v4l2_crop crop = {1759.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,1760};17611762memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));17631764if (copy_to_user(arg, &crop, sizeof(crop)))1765return -EFAULT;17661767return 0;1768}176917701771static int1772et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)1773{1774struct et61x251_sensor* s = &cam->sensor;1775struct v4l2_crop crop;1776struct v4l2_rect* rect;1777struct v4l2_rect* bounds = &(s->cropcap.bounds);1778struct v4l2_pix_format* pix_format = &(s->pix_format);1779u8 scale;1780const enum et61x251_stream_state stream = cam->stream;1781const u32 nbuffers = cam->nbuffers;1782u32 i;1783int err = 0;17841785if (copy_from_user(&crop, arg, sizeof(crop)))1786return -EFAULT;17871788rect = &(crop.c);17891790if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1791return -EINVAL;17921793if (cam->module_param.force_munmap)1794for (i = 0; i < cam->nbuffers; i++)1795if (cam->frame[i].vma_use_count) {1796DBG(3, "VIDIOC_S_CROP failed. "1797"Unmap the buffers first.");1798return -EBUSY;1799}18001801/* Preserve R,G or B origin */1802rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;1803rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;18041805if (rect->width < 16)1806rect->width = 16;1807if (rect->height < 16)1808rect->height = 16;1809if (rect->width > bounds->width)1810rect->width = bounds->width;1811if (rect->height > bounds->height)1812rect->height = bounds->height;1813if (rect->left < bounds->left)1814rect->left = bounds->left;1815if (rect->top < bounds->top)1816rect->top = bounds->top;1817if (rect->left + rect->width > bounds->left + bounds->width)1818rect->left = bounds->left+bounds->width - rect->width;1819if (rect->top + rect->height > bounds->top + bounds->height)1820rect->top = bounds->top+bounds->height - rect->height;18211822rect->width &= ~15L;1823rect->height &= ~15L;18241825if (ET61X251_PRESERVE_IMGSCALE) {1826/* Calculate the actual scaling factor */1827u32 a, b;1828a = rect->width * rect->height;1829b = pix_format->width * pix_format->height;1830scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;1831} else1832scale = 1;18331834if (cam->stream == STREAM_ON)1835if ((err = et61x251_stream_interrupt(cam)))1836return err;18371838if (copy_to_user(arg, &crop, sizeof(crop))) {1839cam->stream = stream;1840return -EFAULT;1841}18421843if (cam->module_param.force_munmap || cam->io == IO_READ)1844et61x251_release_buffers(cam);18451846err = et61x251_set_crop(cam, rect);1847if (s->set_crop)1848err += s->set_crop(cam, rect);1849err += et61x251_set_scale(cam, scale);18501851if (err) { /* atomic, no rollback in ioctl() */1852cam->state |= DEV_MISCONFIGURED;1853DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "1854"use the camera, close and open %s again.",1855video_device_node_name(cam->v4ldev));1856return -EIO;1857}18581859s->pix_format.width = rect->width/scale;1860s->pix_format.height = rect->height/scale;1861memcpy(&(s->_rect), rect, sizeof(*rect));18621863if ((cam->module_param.force_munmap || cam->io == IO_READ) &&1864nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {1865cam->state |= DEV_MISCONFIGURED;1866DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "1867"use the camera, close and open %s again.",1868video_device_node_name(cam->v4ldev));1869return -ENOMEM;1870}18711872if (cam->io == IO_READ)1873et61x251_empty_framequeues(cam);1874else if (cam->module_param.force_munmap)1875et61x251_requeue_outqueue(cam);18761877cam->stream = stream;18781879return 0;1880}188118821883static int1884et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg)1885{1886struct v4l2_frmsizeenum frmsize;18871888if (copy_from_user(&frmsize, arg, sizeof(frmsize)))1889return -EFAULT;18901891if (frmsize.index != 0)1892return -EINVAL;18931894if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 &&1895frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)1896return -EINVAL;18971898frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;1899frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;1900frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;1901frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;1902frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;1903memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));19041905if (copy_to_user(arg, &frmsize, sizeof(frmsize)))1906return -EFAULT;19071908return 0;1909}191019111912static int1913et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)1914{1915struct v4l2_fmtdesc fmtd;19161917if (copy_from_user(&fmtd, arg, sizeof(fmtd)))1918return -EFAULT;19191920if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1921return -EINVAL;19221923if (fmtd.index == 0) {1924strcpy(fmtd.description, "bayer rgb");1925fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;1926} else if (fmtd.index == 1) {1927strcpy(fmtd.description, "compressed");1928fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;1929fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;1930} else1931return -EINVAL;19321933fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;1934memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));19351936if (copy_to_user(arg, &fmtd, sizeof(fmtd)))1937return -EFAULT;19381939return 0;1940}194119421943static int1944et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)1945{1946struct v4l2_format format;1947struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);19481949if (copy_from_user(&format, arg, sizeof(format)))1950return -EFAULT;19511952if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1953return -EINVAL;19541955pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?19560 : V4L2_COLORSPACE_SRGB;1957pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)1958? 0 : (pfmt->width * pfmt->priv) / 8;1959pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);1960pfmt->field = V4L2_FIELD_NONE;1961memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));19621963if (copy_to_user(arg, &format, sizeof(format)))1964return -EFAULT;19651966return 0;1967}196819691970static int1971et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,1972void __user * arg)1973{1974struct et61x251_sensor* s = &cam->sensor;1975struct v4l2_format format;1976struct v4l2_pix_format* pix;1977struct v4l2_pix_format* pfmt = &(s->pix_format);1978struct v4l2_rect* bounds = &(s->cropcap.bounds);1979struct v4l2_rect rect;1980u8 scale;1981const enum et61x251_stream_state stream = cam->stream;1982const u32 nbuffers = cam->nbuffers;1983u32 i;1984int err = 0;19851986if (copy_from_user(&format, arg, sizeof(format)))1987return -EFAULT;19881989pix = &(format.fmt.pix);19901991if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1992return -EINVAL;19931994memcpy(&rect, &(s->_rect), sizeof(rect));19951996{ /* calculate the actual scaling factor */1997u32 a, b;1998a = rect.width * rect.height;1999b = pix->width * pix->height;2000scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;2001}20022003rect.width = scale * pix->width;2004rect.height = scale * pix->height;20052006if (rect.width < 16)2007rect.width = 16;2008if (rect.height < 16)2009rect.height = 16;2010if (rect.width > bounds->left + bounds->width - rect.left)2011rect.width = bounds->left + bounds->width - rect.left;2012if (rect.height > bounds->top + bounds->height - rect.top)2013rect.height = bounds->top + bounds->height - rect.top;20142015rect.width &= ~15L;2016rect.height &= ~15L;20172018{ /* adjust the scaling factor */2019u32 a, b;2020a = rect.width * rect.height;2021b = pix->width * pix->height;2022scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;2023}20242025pix->width = rect.width / scale;2026pix->height = rect.height / scale;20272028if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&2029pix->pixelformat != V4L2_PIX_FMT_SBGGR8)2030pix->pixelformat = pfmt->pixelformat;2031pix->priv = pfmt->priv; /* bpp */2032pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?20330 : V4L2_COLORSPACE_SRGB;2034pix->colorspace = pfmt->colorspace;2035pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)2036? 0 : (pix->width * pix->priv) / 8;2037pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);2038pix->field = V4L2_FIELD_NONE;20392040if (cmd == VIDIOC_TRY_FMT) {2041if (copy_to_user(arg, &format, sizeof(format)))2042return -EFAULT;2043return 0;2044}20452046if (cam->module_param.force_munmap)2047for (i = 0; i < cam->nbuffers; i++)2048if (cam->frame[i].vma_use_count) {2049DBG(3, "VIDIOC_S_FMT failed. "2050"Unmap the buffers first.");2051return -EBUSY;2052}20532054if (cam->stream == STREAM_ON)2055if ((err = et61x251_stream_interrupt(cam)))2056return err;20572058if (copy_to_user(arg, &format, sizeof(format))) {2059cam->stream = stream;2060return -EFAULT;2061}20622063if (cam->module_param.force_munmap || cam->io == IO_READ)2064et61x251_release_buffers(cam);20652066err += et61x251_set_pix_format(cam, pix);2067err += et61x251_set_crop(cam, &rect);2068if (s->set_pix_format)2069err += s->set_pix_format(cam, pix);2070if (s->set_crop)2071err += s->set_crop(cam, &rect);2072err += et61x251_set_scale(cam, scale);20732074if (err) { /* atomic, no rollback in ioctl() */2075cam->state |= DEV_MISCONFIGURED;2076DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "2077"use the camera, close and open %s again.",2078video_device_node_name(cam->v4ldev));2079return -EIO;2080}20812082memcpy(pfmt, pix, sizeof(*pix));2083memcpy(&(s->_rect), &rect, sizeof(rect));20842085if ((cam->module_param.force_munmap || cam->io == IO_READ) &&2086nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {2087cam->state |= DEV_MISCONFIGURED;2088DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "2089"use the camera, close and open %s again.",2090video_device_node_name(cam->v4ldev));2091return -ENOMEM;2092}20932094if (cam->io == IO_READ)2095et61x251_empty_framequeues(cam);2096else if (cam->module_param.force_munmap)2097et61x251_requeue_outqueue(cam);20982099cam->stream = stream;21002101return 0;2102}210321042105static int2106et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)2107{2108if (copy_to_user(arg, &cam->compression,2109sizeof(cam->compression)))2110return -EFAULT;21112112return 0;2113}211421152116static int2117et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)2118{2119struct v4l2_jpegcompression jc;2120const enum et61x251_stream_state stream = cam->stream;2121int err = 0;21222123if (copy_from_user(&jc, arg, sizeof(jc)))2124return -EFAULT;21252126if (jc.quality != 0 && jc.quality != 1)2127return -EINVAL;21282129if (cam->stream == STREAM_ON)2130if ((err = et61x251_stream_interrupt(cam)))2131return err;21322133err += et61x251_set_compression(cam, &jc);2134if (err) { /* atomic, no rollback in ioctl() */2135cam->state |= DEV_MISCONFIGURED;2136DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "2137"problems. To use the camera, close and open "2138"%s again.", video_device_node_name(cam->v4ldev));2139return -EIO;2140}21412142cam->compression.quality = jc.quality;21432144cam->stream = stream;21452146return 0;2147}214821492150static int2151et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)2152{2153struct v4l2_requestbuffers rb;2154u32 i;2155int err;21562157if (copy_from_user(&rb, arg, sizeof(rb)))2158return -EFAULT;21592160if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||2161rb.memory != V4L2_MEMORY_MMAP)2162return -EINVAL;21632164if (cam->io == IO_READ) {2165DBG(3, "Close and open the device again to choose the mmap "2166"I/O method");2167return -EBUSY;2168}21692170for (i = 0; i < cam->nbuffers; i++)2171if (cam->frame[i].vma_use_count) {2172DBG(3, "VIDIOC_REQBUFS failed. "2173"Previous buffers are still mapped.");2174return -EBUSY;2175}21762177if (cam->stream == STREAM_ON)2178if ((err = et61x251_stream_interrupt(cam)))2179return err;21802181et61x251_empty_framequeues(cam);21822183et61x251_release_buffers(cam);2184if (rb.count)2185rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);21862187if (copy_to_user(arg, &rb, sizeof(rb))) {2188et61x251_release_buffers(cam);2189cam->io = IO_NONE;2190return -EFAULT;2191}21922193cam->io = rb.count ? IO_MMAP : IO_NONE;21942195return 0;2196}219721982199static int2200et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)2201{2202struct v4l2_buffer b;22032204if (copy_from_user(&b, arg, sizeof(b)))2205return -EFAULT;22062207if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||2208b.index >= cam->nbuffers || cam->io != IO_MMAP)2209return -EINVAL;22102211memcpy(&b, &cam->frame[b.index].buf, sizeof(b));22122213if (cam->frame[b.index].vma_use_count)2214b.flags |= V4L2_BUF_FLAG_MAPPED;22152216if (cam->frame[b.index].state == F_DONE)2217b.flags |= V4L2_BUF_FLAG_DONE;2218else if (cam->frame[b.index].state != F_UNUSED)2219b.flags |= V4L2_BUF_FLAG_QUEUED;22202221if (copy_to_user(arg, &b, sizeof(b)))2222return -EFAULT;22232224return 0;2225}222622272228static int2229et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)2230{2231struct v4l2_buffer b;2232unsigned long lock_flags;22332234if (copy_from_user(&b, arg, sizeof(b)))2235return -EFAULT;22362237if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||2238b.index >= cam->nbuffers || cam->io != IO_MMAP)2239return -EINVAL;22402241if (cam->frame[b.index].state != F_UNUSED)2242return -EINVAL;22432244cam->frame[b.index].state = F_QUEUED;22452246spin_lock_irqsave(&cam->queue_lock, lock_flags);2247list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);2248spin_unlock_irqrestore(&cam->queue_lock, lock_flags);22492250PDBGG("Frame #%lu queued", (unsigned long)b.index);22512252return 0;2253}225422552256static int2257et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,2258void __user * arg)2259{2260struct v4l2_buffer b;2261struct et61x251_frame_t *f;2262unsigned long lock_flags;2263long timeout;22642265if (copy_from_user(&b, arg, sizeof(b)))2266return -EFAULT;22672268if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)2269return -EINVAL;22702271if (list_empty(&cam->outqueue)) {2272if (cam->stream == STREAM_OFF)2273return -EINVAL;2274if (filp->f_flags & O_NONBLOCK)2275return -EAGAIN;2276timeout = wait_event_interruptible_timeout2277( cam->wait_frame,2278(!list_empty(&cam->outqueue)) ||2279(cam->state & DEV_DISCONNECTED) ||2280(cam->state & DEV_MISCONFIGURED),2281cam->module_param.frame_timeout *22821000 * msecs_to_jiffies(1) );2283if (timeout < 0)2284return timeout;2285if (cam->state & DEV_DISCONNECTED)2286return -ENODEV;2287if (!timeout || (cam->state & DEV_MISCONFIGURED))2288return -EIO;2289}22902291spin_lock_irqsave(&cam->queue_lock, lock_flags);2292f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);2293list_del(cam->outqueue.next);2294spin_unlock_irqrestore(&cam->queue_lock, lock_flags);22952296f->state = F_UNUSED;22972298memcpy(&b, &f->buf, sizeof(b));2299if (f->vma_use_count)2300b.flags |= V4L2_BUF_FLAG_MAPPED;23012302if (copy_to_user(arg, &b, sizeof(b)))2303return -EFAULT;23042305PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);23062307return 0;2308}230923102311static int2312et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)2313{2314int type;23152316if (copy_from_user(&type, arg, sizeof(type)))2317return -EFAULT;23182319if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)2320return -EINVAL;23212322cam->stream = STREAM_ON;23232324DBG(3, "Stream on");23252326return 0;2327}232823292330static int2331et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)2332{2333int type, err;23342335if (copy_from_user(&type, arg, sizeof(type)))2336return -EFAULT;23372338if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)2339return -EINVAL;23402341if (cam->stream == STREAM_ON)2342if ((err = et61x251_stream_interrupt(cam)))2343return err;23442345et61x251_empty_framequeues(cam);23462347DBG(3, "Stream off");23482349return 0;2350}235123522353static int2354et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)2355{2356struct v4l2_streamparm sp;23572358if (copy_from_user(&sp, arg, sizeof(sp)))2359return -EFAULT;23602361if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)2362return -EINVAL;23632364sp.parm.capture.extendedmode = 0;2365sp.parm.capture.readbuffers = cam->nreadbuffers;23662367if (copy_to_user(arg, &sp, sizeof(sp)))2368return -EFAULT;23692370return 0;2371}237223732374static int2375et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)2376{2377struct v4l2_streamparm sp;23782379if (copy_from_user(&sp, arg, sizeof(sp)))2380return -EFAULT;23812382if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)2383return -EINVAL;23842385sp.parm.capture.extendedmode = 0;23862387if (sp.parm.capture.readbuffers == 0)2388sp.parm.capture.readbuffers = cam->nreadbuffers;23892390if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)2391sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;23922393if (copy_to_user(arg, &sp, sizeof(sp)))2394return -EFAULT;23952396cam->nreadbuffers = sp.parm.capture.readbuffers;23972398return 0;2399}240024012402static long et61x251_ioctl_v4l2(struct file *filp,2403unsigned int cmd, void __user *arg)2404{2405struct et61x251_device *cam = video_drvdata(filp);24062407switch (cmd) {24082409case VIDIOC_QUERYCAP:2410return et61x251_vidioc_querycap(cam, arg);24112412case VIDIOC_ENUMINPUT:2413return et61x251_vidioc_enuminput(cam, arg);24142415case VIDIOC_G_INPUT:2416return et61x251_vidioc_g_input(cam, arg);24172418case VIDIOC_S_INPUT:2419return et61x251_vidioc_s_input(cam, arg);24202421case VIDIOC_QUERYCTRL:2422return et61x251_vidioc_query_ctrl(cam, arg);24232424case VIDIOC_G_CTRL:2425return et61x251_vidioc_g_ctrl(cam, arg);24262427case VIDIOC_S_CTRL:2428return et61x251_vidioc_s_ctrl(cam, arg);24292430case VIDIOC_CROPCAP:2431return et61x251_vidioc_cropcap(cam, arg);24322433case VIDIOC_G_CROP:2434return et61x251_vidioc_g_crop(cam, arg);24352436case VIDIOC_S_CROP:2437return et61x251_vidioc_s_crop(cam, arg);24382439case VIDIOC_ENUM_FMT:2440return et61x251_vidioc_enum_fmt(cam, arg);24412442case VIDIOC_G_FMT:2443return et61x251_vidioc_g_fmt(cam, arg);24442445case VIDIOC_TRY_FMT:2446case VIDIOC_S_FMT:2447return et61x251_vidioc_try_s_fmt(cam, cmd, arg);24482449case VIDIOC_ENUM_FRAMESIZES:2450return et61x251_vidioc_enum_framesizes(cam, arg);24512452case VIDIOC_G_JPEGCOMP:2453return et61x251_vidioc_g_jpegcomp(cam, arg);24542455case VIDIOC_S_JPEGCOMP:2456return et61x251_vidioc_s_jpegcomp(cam, arg);24572458case VIDIOC_REQBUFS:2459return et61x251_vidioc_reqbufs(cam, arg);24602461case VIDIOC_QUERYBUF:2462return et61x251_vidioc_querybuf(cam, arg);24632464case VIDIOC_QBUF:2465return et61x251_vidioc_qbuf(cam, arg);24662467case VIDIOC_DQBUF:2468return et61x251_vidioc_dqbuf(cam, filp, arg);24692470case VIDIOC_STREAMON:2471return et61x251_vidioc_streamon(cam, arg);24722473case VIDIOC_STREAMOFF:2474return et61x251_vidioc_streamoff(cam, arg);24752476case VIDIOC_G_PARM:2477return et61x251_vidioc_g_parm(cam, arg);24782479case VIDIOC_S_PARM:2480return et61x251_vidioc_s_parm(cam, arg);24812482case VIDIOC_G_STD:2483case VIDIOC_S_STD:2484case VIDIOC_QUERYSTD:2485case VIDIOC_ENUMSTD:2486case VIDIOC_QUERYMENU:2487case VIDIOC_ENUM_FRAMEINTERVALS:2488return -EINVAL;24892490default:2491return -EINVAL;24922493}2494}249524962497static long et61x251_ioctl(struct file *filp,2498unsigned int cmd, unsigned long arg)2499{2500struct et61x251_device *cam = video_drvdata(filp);2501long err = 0;25022503if (mutex_lock_interruptible(&cam->fileop_mutex))2504return -ERESTARTSYS;25052506if (cam->state & DEV_DISCONNECTED) {2507DBG(1, "Device not present");2508mutex_unlock(&cam->fileop_mutex);2509return -ENODEV;2510}25112512if (cam->state & DEV_MISCONFIGURED) {2513DBG(1, "The camera is misconfigured. Close and open it "2514"again.");2515mutex_unlock(&cam->fileop_mutex);2516return -EIO;2517}25182519V4LDBG(3, "et61x251", cmd);25202521err = et61x251_ioctl_v4l2(filp, cmd, (void __user *)arg);25222523mutex_unlock(&cam->fileop_mutex);25242525return err;2526}252725282529static const struct v4l2_file_operations et61x251_fops = {2530.owner = THIS_MODULE,2531.open = et61x251_open,2532.release = et61x251_release,2533.unlocked_ioctl = et61x251_ioctl,2534.read = et61x251_read,2535.poll = et61x251_poll,2536.mmap = et61x251_mmap,2537};25382539/*****************************************************************************/25402541/* It exists a single interface only. We do not need to validate anything. */2542static int2543et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)2544{2545struct usb_device *udev = interface_to_usbdev(intf);2546struct et61x251_device* cam;2547static unsigned int dev_nr;2548unsigned int i;2549int err = 0;25502551if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))2552return -ENOMEM;25532554cam->usbdev = udev;25552556if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {2557DBG(1, "kmalloc() failed");2558err = -ENOMEM;2559goto fail;2560}25612562if (!(cam->v4ldev = video_device_alloc())) {2563DBG(1, "video_device_alloc() failed");2564err = -ENOMEM;2565goto fail;2566}25672568DBG(2, "ET61X[12]51 PC Camera Controller detected "2569"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);25702571for (i = 0; et61x251_sensor_table[i]; i++) {2572err = et61x251_sensor_table[i](cam);2573if (!err)2574break;2575}25762577if (!err)2578DBG(2, "%s image sensor detected", cam->sensor.name);2579else {2580DBG(1, "No supported image sensor detected");2581err = -ENODEV;2582goto fail;2583}25842585if (et61x251_init(cam)) {2586DBG(1, "Initialization failed. I will retry on open().");2587cam->state |= DEV_MISCONFIGURED;2588}25892590strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");2591cam->v4ldev->fops = &et61x251_fops;2592cam->v4ldev->release = video_device_release;2593cam->v4ldev->parent = &udev->dev;2594video_set_drvdata(cam->v4ldev, cam);25952596init_completion(&cam->probe);25972598err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,2599video_nr[dev_nr]);2600if (err) {2601DBG(1, "V4L2 device registration failed");2602if (err == -ENFILE && video_nr[dev_nr] == -1)2603DBG(1, "Free /dev/videoX node not found");2604video_nr[dev_nr] = -1;2605dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;2606complete_all(&cam->probe);2607goto fail;2608}26092610DBG(2, "V4L2 device registered as %s",2611video_device_node_name(cam->v4ldev));26122613cam->module_param.force_munmap = force_munmap[dev_nr];2614cam->module_param.frame_timeout = frame_timeout[dev_nr];26152616dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;26172618#ifdef CONFIG_VIDEO_ADV_DEBUG2619err = et61x251_create_sysfs(cam);2620if (!err)2621DBG(2, "Optional device control through 'sysfs' "2622"interface ready");2623else2624DBG(2, "Failed to create 'sysfs' interface for optional "2625"device controlling. Error #%d", err);2626#else2627DBG(2, "Optional device control through 'sysfs' interface disabled");2628DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "2629"configuration option to enable it.");2630#endif26312632usb_set_intfdata(intf, cam);2633kref_init(&cam->kref);2634usb_get_dev(cam->usbdev);26352636complete_all(&cam->probe);26372638return 0;26392640fail:2641if (cam) {2642kfree(cam->control_buffer);2643if (cam->v4ldev)2644video_device_release(cam->v4ldev);2645kfree(cam);2646}2647return err;2648}264926502651static void et61x251_usb_disconnect(struct usb_interface* intf)2652{2653struct et61x251_device* cam;26542655down_write(&et61x251_dev_lock);26562657cam = usb_get_intfdata(intf);26582659DBG(2, "Disconnecting %s...", cam->v4ldev->name);26602661if (cam->users) {2662DBG(2, "Device %s is open! Deregistration and memory "2663"deallocation are deferred.",2664video_device_node_name(cam->v4ldev));2665cam->state |= DEV_MISCONFIGURED;2666et61x251_stop_transfer(cam);2667cam->state |= DEV_DISCONNECTED;2668wake_up_interruptible(&cam->wait_frame);2669wake_up(&cam->wait_stream);2670} else2671cam->state |= DEV_DISCONNECTED;26722673wake_up_interruptible_all(&cam->wait_open);26742675kref_put(&cam->kref, et61x251_release_resources);26762677up_write(&et61x251_dev_lock);2678}267926802681static struct usb_driver et61x251_usb_driver = {2682.name = "et61x251",2683.id_table = et61x251_id_table,2684.probe = et61x251_usb_probe,2685.disconnect = et61x251_usb_disconnect,2686};26872688/*****************************************************************************/26892690static int __init et61x251_module_init(void)2691{2692int err = 0;26932694KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION);2695KDBG(3, ET61X251_MODULE_AUTHOR);26962697if ((err = usb_register(&et61x251_usb_driver)))2698KDBG(1, "usb_register() failed");26992700return err;2701}270227032704static void __exit et61x251_module_exit(void)2705{2706usb_deregister(&et61x251_usb_driver);2707}270827092710module_init(et61x251_module_init);2711module_exit(et61x251_module_exit);271227132714