⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 et61x251_core.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 5 页
字号:
/*************************************************************************** * V4L2 driver for ET61X[12]51 PC Camera Controllers                       * *                                                                         * * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       * *                                                                         * * This program is free software; you can redistribute it and/or modify    * * it under the terms of the GNU General Public License as published by    * * the Free Software Foundation; either version 2 of the License, or       * * (at your option) any later version.                                     * *                                                                         * * This program is distributed in the hope that it will be useful,         * * but WITHOUT ANY WARRANTY; without even the implied warranty of          * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           * * GNU General Public License for more details.                            * *                                                                         * * You should have received a copy of the GNU General Public License       * * along with this program; if not, write to the Free Software             * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               * ***************************************************************************/#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/param.h>#include <linux/moduleparam.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/device.h>#include <linux/fs.h>#include <linux/delay.h>#include <linux/compiler.h>#include <linux/ioctl.h>#include <linux/poll.h>#include <linux/stat.h>#include <linux/mm.h>#include <linux/vmalloc.h>#include <linux/page-flags.h>#include <linux/byteorder/generic.h>#include <asm/page.h>#include <asm/uaccess.h>#include "et61x251.h"/*****************************************************************************/#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \				"PC Camera Controllers"#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"#define ET61X251_MODULE_LICENSE "GPL"#define ET61X251_MODULE_VERSION "1:1.02"#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)/*****************************************************************************/MODULE_DEVICE_TABLE(usb, et61x251_id_table);MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);MODULE_DESCRIPTION(ET61X251_MODULE_NAME);MODULE_VERSION(ET61X251_MODULE_VERSION);MODULE_LICENSE(ET61X251_MODULE_LICENSE);static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};module_param_array(video_nr, short, NULL, 0444);MODULE_PARM_DESC(video_nr,		 "\n<-1|n[,...]> Specify V4L2 minor mode number."		 "\n -1 = use next available (default)"		 "\n  n = use minor number n (integer >= 0)"		 "\nYou can specify up to "		 __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."		 "\nFor example:"		 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"		 "\nthe second registered camera and use auto for the first"		 "\none and for every other camera."		 "\n");static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =			       ET61X251_FORCE_MUNMAP};module_param_array(force_munmap, bool, NULL, 0444);MODULE_PARM_DESC(force_munmap,		 "\n<0|1[,...]> Force the application to unmap previously"		 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"		 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"		 "\nthis feature. This parameter is specific for each"		 "\ndetected camera."		 "\n 0 = do not force memory unmapping"		 "\n 1 = force memory unmapping (save memory)"		 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."		 "\n");static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =				       ET61X251_FRAME_TIMEOUT};module_param_array(frame_timeout, uint, NULL, 0644);MODULE_PARM_DESC(frame_timeout,		 "\n<n[,...]> Timeout for a video frame in seconds."		 "\nThis parameter is specific for each detected camera."		 "\nDefault value is "		 __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."		 "\n");#ifdef ET61X251_DEBUGstatic unsigned short debug = ET61X251_DEBUG_LEVEL;module_param(debug, ushort, 0644);MODULE_PARM_DESC(debug,		 "\n<n> Debugging information level, from 0 to 3:"		 "\n0 = none (use carefully)"		 "\n1 = critical errors"		 "\n2 = significant informations"		 "\n3 = more verbose messages"		 "\nLevel 3 is useful for testing only, when only "		 "one device is used."		 "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."		 "\n");#endif/*****************************************************************************/static u32et61x251_request_buffers(struct et61x251_device* cam, u32 count,			 enum et61x251_io_method io){	struct v4l2_pix_format* p = &(cam->sensor.pix_format);	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);	const size_t imagesize = cam->module_param.force_munmap ||				 io == IO_READ ?				 (p->width * p->height * p->priv) / 8 :				 (r->width * r->height * p->priv) / 8;	void* buff = NULL;	u32 i;	if (count > ET61X251_MAX_FRAMES)		count = ET61X251_MAX_FRAMES;	cam->nbuffers = count;	while (cam->nbuffers > 0) {		if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))			break;		cam->nbuffers--;	}	for (i = 0; i < cam->nbuffers; i++) {		cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);		cam->frame[i].buf.index = i;		cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);		cam->frame[i].buf.length = imagesize;		cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		cam->frame[i].buf.sequence = 0;		cam->frame[i].buf.field = V4L2_FIELD_NONE;		cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;		cam->frame[i].buf.flags = 0;	}	return cam->nbuffers;}static void et61x251_release_buffers(struct et61x251_device* cam){	if (cam->nbuffers) {		vfree(cam->frame[0].bufmem);		cam->nbuffers = 0;	}	cam->frame_current = NULL;}static void et61x251_empty_framequeues(struct et61x251_device* cam){	u32 i;	INIT_LIST_HEAD(&cam->inqueue);	INIT_LIST_HEAD(&cam->outqueue);	for (i = 0; i < ET61X251_MAX_FRAMES; i++) {		cam->frame[i].state = F_UNUSED;		cam->frame[i].buf.bytesused = 0;	}}static void et61x251_requeue_outqueue(struct et61x251_device* cam){	struct et61x251_frame_t *i;	list_for_each_entry(i, &cam->outqueue, frame) {		i->state = F_QUEUED;		list_add(&i->frame, &cam->inqueue);	}	INIT_LIST_HEAD(&cam->outqueue);}static void et61x251_queue_unusedframes(struct et61x251_device* cam){	unsigned long lock_flags;	u32 i;	for (i = 0; i < cam->nbuffers; i++)		if (cam->frame[i].state == F_UNUSED) {			cam->frame[i].state = F_QUEUED;			spin_lock_irqsave(&cam->queue_lock, lock_flags);			list_add_tail(&cam->frame[i].frame, &cam->inqueue);			spin_unlock_irqrestore(&cam->queue_lock, lock_flags);		}}/*****************************************************************************/int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index){	struct usb_device* udev = cam->usbdev;	u8* buff = cam->control_buffer;	int res;	*buff = value;	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,			      0, index, buff, 1, ET61X251_CTRL_TIMEOUT);	if (res < 0) {		DBG(3, "Failed to write a register (value 0x%02X, index "		       "0x%02X, error %d)", value, index, res);		return -1;	}	return 0;}int et61x251_read_reg(struct et61x251_device* cam, u16 index){	struct usb_device* udev = cam->usbdev;	u8* buff = cam->control_buffer;	int res;	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,			      0, index, buff, 1, ET61X251_CTRL_TIMEOUT);	if (res < 0)		DBG(3, "Failed to read a register (index 0x%02X, error %d)",		    index, res);	return (res >= 0) ? (int)(*buff) : -1;}static intet61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor){	int i, r;	for (i = 1; i <= 8; i++) {		if (sensor->interface == ET61X251_I2C_3WIRES) {			r = et61x251_read_reg(cam, 0x8e);			if (!(r & 0x02) && (r >= 0))				return 0;		} else {			r = et61x251_read_reg(cam, 0x8b);			if (!(r & 0x01) && (r >= 0))				return 0;		}		if (r < 0)			return -EIO;		udelay(8*8); /* minimum for sensors at 400kHz */	}	return -EBUSY;}intet61x251_i2c_try_read(struct et61x251_device* cam,		      struct et61x251_sensor* sensor, u8 address){	struct usb_device* udev = cam->usbdev;	u8* data = cam->control_buffer;	int err = 0, res;	data[0] = address;	data[1] = cam->sensor.i2c_slave_id;	data[2] = cam->sensor.rsta | 0x10;	data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,			      0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);	if (res < 0)		err += res;	err += et61x251_i2c_wait(cam, sensor);	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);	if (res < 0)		err += res;	if (err)		DBG(3, "I2C read failed for %s image sensor", sensor->name);	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);	return err ? -1 : (int)data[0];}intet61x251_i2c_try_write(struct et61x251_device* cam,		       struct et61x251_sensor* sensor, u8 address, u8 value){	struct usb_device* udev = cam->usbdev;	u8* data = cam->control_buffer;	int err = 0, res;	data[0] = address;	data[1] = cam->sensor.i2c_slave_id;	data[2] = cam->sensor.rsta | 0x12;	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);	if (res < 0)		err += res;	data[0] = value;	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);	if (res < 0)		err += res;	err += et61x251_i2c_wait(cam, sensor);	if (err)		DBG(3, "I2C write failed for %s image sensor", sensor->name);	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);	return err ? -1 : 0;}intet61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,		       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,		       u8 data8, u8 address){	struct usb_device* udev = cam->usbdev;	u8* data = cam->control_buffer;	int err = 0, res;	data[0] = data2;	data[1] = data3;	data[2] = data4;	data[3] = data5;	data[4] = data6;	data[5] = data7;	data[6] = data8;	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,			      0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);	if (res < 0)		err += res;	data[0] = address;	data[1] = cam->sensor.i2c_slave_id;	data[2] = cam->sensor.rsta | 0x02 | (n << 4);	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);	if (res < 0)		err += res;	/* Start writing through the serial interface */	data[0] = data1;	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);	if (res < 0)		err += res;	err += et61x251_i2c_wait(cam, &cam->sensor);	if (err)		DBG(3, "I2C raw write failed for %s image sensor",		    cam->sensor.name);	PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "	      "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"	      " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,	      data1, data2, data3, data4, data5, data6, data7, data8);	return err ? -1 : 0;}int et61x251_i2c_read(struct et61x251_device* cam, u8 address){	return et61x251_i2c_try_read(cam, &cam->sensor, address);}int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value){	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);}/*****************************************************************************/static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs){	struct et61x251_device* cam = urb->context;	struct et61x251_frame_t** f;	size_t imagesize;	u8 i;	int err = 0;	if (urb->status == -ENOENT)		return;	f = &cam->frame_current;	if (cam->stream == STREAM_INTERRUPT) {		cam->stream = STREAM_OFF;		if ((*f))			(*f)->state = F_QUEUED;		DBG(3, "Stream interrupted");		wake_up(&cam->wait_stream);	}	if (cam->state & DEV_DISCONNECTED)		return;	if (cam->state & DEV_MISCONFIGURED) {		wake_up_interruptible(&cam->wait_frame);		return;	}	if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))		goto resubmit_urb;	if (!(*f))		(*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,				  frame);	imagesize = (cam->sensor.pix_format.width *		     cam->sensor.pix_format.height *		     cam->sensor.pix_format.priv) / 8;	for (i = 0; i < urb->number_of_packets; i++) {		unsigned int len, status;		void *pos;		u8* b1, * b2, sof;		const u8 VOID_BYTES = 6;		size_t imglen;		len = urb->iso_frame_desc[i].actual_length;		status = urb->iso_frame_desc[i].status;		pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;		if (status) {			DBG(3, "Error in isochronous frame");			(*f)->state = F_ERROR;			continue;		}		b1 = pos++;		b2 = pos++;		sof = ((*b1 & 0x3f) == 63);		imglen = ((*b1 & 0xc0) << 2) | *b2;		PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",		      len, i, imglen);		if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)start_of_frame:			if (sof) {				(*f)->state = F_GRABBING;				(*f)->buf.bytesused = 0;				do_gettimeofday(&(*f)->buf.timestamp);				pos += 22;				DBG(3, "SOF detected: new video frame");			}		if ((*f)->state == F_GRABBING) {			if (sof && (*f)->buf.bytesused) {				if (cam->sensor.pix_format.pixelformat ==							 V4L2_PIX_FMT_ET61X251)					goto end_of_frame;				else {					DBG(3, "Not expected SOF detected "					       "after %lu bytes",					   (unsigned long)(*f)->buf.bytesused);					(*f)->state = F_ERROR;					continue;				}			}			if ((*f)->buf.bytesused + imglen > imagesize) {				DBG(3, "Video frame size exceeded");				(*f)->state = F_ERROR;				continue;			}			pos += VOID_BYTES;			memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);			(*f)->buf.bytesused += imglen;			if ((*f)->buf.bytesused == imagesize) {				u32 b;end_of_frame:				b = (*f)->buf.bytesused;				(*f)->state = F_DONE;				(*f)->buf.sequence= ++cam->frame_count;				spin_lock(&cam->queue_lock);				list_move_tail(&(*f)->frame, &cam->outqueue);				if (!list_empty(&cam->inqueue))					(*f) = list_entry(cam->inqueue.next,						       struct et61x251_frame_t,							  frame);				else					(*f) = NULL;				spin_unlock(&cam->queue_lock);				DBG(3, "Video frame captured: : %lu bytes",				       (unsigned long)(b));				if (!(*f))					goto resubmit_urb;				if (sof &&				    cam->sensor.pix_format.pixelformat ==							 V4L2_PIX_FMT_ET61X251)					goto start_of_frame;			}		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -