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

📄 zc0301_core.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/*************************************************************************** * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip      * *                                                                         * * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  * *                                                                         * * Informations about the chip internals needed to enable the I2C protocol * * have been taken from the documentation of the ZC030x Video4Linux1       * * driver written by Andrew Birkett <andy@nobugs.org>                      * *                                                                         * * 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/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 <asm/byteorder.h>#include <asm/page.h>#include <asm/uaccess.h>#include "zc0301.h"/*****************************************************************************/#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \			      "Image Processor and Control Chip"#define ZC0301_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"#define ZC0301_MODULE_LICENSE "GPL"#define ZC0301_MODULE_VERSION "1:1.10"#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 10)/*****************************************************************************/MODULE_DEVICE_TABLE(usb, zc0301_id_table);MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);MODULE_DESCRIPTION(ZC0301_MODULE_NAME);MODULE_VERSION(ZC0301_MODULE_VERSION);MODULE_LICENSE(ZC0301_MODULE_LICENSE);static short video_nr[] = {[0 ... ZC0301_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(ZC0301_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 ... ZC0301_MAX_DEVICES-1] =			       ZC0301_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(ZC0301_FORCE_MUNMAP)"."		 "\n");static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =				       ZC0301_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(ZC0301_FRAME_TIMEOUT)"."		 "\n");#ifdef ZC0301_DEBUGstatic unsigned short debug = ZC0301_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(ZC0301_DEBUG_LEVEL)"."		 "\n");#endif/*****************************************************************************/static u32zc0301_request_buffers(struct zc0301_device* cam, u32 count,		       enum zc0301_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 > ZC0301_MAX_FRAMES)		count = ZC0301_MAX_FRAMES;	cam->nbuffers = count;	while (cam->nbuffers > 0) {		if ((buff = vmalloc_32_user(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 zc0301_release_buffers(struct zc0301_device* cam){	if (cam->nbuffers) {		vfree(cam->frame[0].bufmem);		cam->nbuffers = 0;	}	cam->frame_current = NULL;}static void zc0301_empty_framequeues(struct zc0301_device* cam){	u32 i;	INIT_LIST_HEAD(&cam->inqueue);	INIT_LIST_HEAD(&cam->outqueue);	for (i = 0; i < ZC0301_MAX_FRAMES; i++) {		cam->frame[i].state = F_UNUSED;		cam->frame[i].buf.bytesused = 0;	}}static void zc0301_requeue_outqueue(struct zc0301_device* cam){	struct zc0301_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 zc0301_queue_unusedframes(struct zc0301_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 zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value){	struct usb_device* udev = cam->usbdev;	int res;	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,			      value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);	if (res < 0) {		DBG(3, "Failed to write a register (index 0x%04X, "		       "value 0x%02X, error %d)",index, value, res);		return -1;	}	return 0;}int zc0301_read_reg(struct zc0301_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), 0xa1, 0xc0,			      0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);	if (res < 0)		DBG(3, "Failed to read a register (index 0x%04X, error %d)",		    index, res);	PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));	return (res >= 0) ? (int)(*buff) : -1;}int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length){	int err = 0, res, r0, r1;	err += zc0301_write_reg(cam, 0x0092, address);	err += zc0301_write_reg(cam, 0x0090, 0x02);	msleep(1);	res = zc0301_read_reg(cam, 0x0091);	if (res < 0)		err += res;	r0 = zc0301_read_reg(cam, 0x0095);	if (r0 < 0)		err += r0;	r1 = zc0301_read_reg(cam, 0x0096);	if (r1 < 0)		err += r1;	res = (length <= 1) ? r0 : r0 | (r1 << 8);	if (err)		DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",		    address, res);	PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);	return err ? -1 : res;}int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value){	int err = 0, res;	err += zc0301_write_reg(cam, 0x0092, address);	err += zc0301_write_reg(cam, 0x0093, value & 0xff);	err += zc0301_write_reg(cam, 0x0094, value >> 8);	err += zc0301_write_reg(cam, 0x0090, 0x01);	msleep(1);	res = zc0301_read_reg(cam, 0x0091);	if (res < 0)		err += res;	if (err)		DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",		    address, value);	PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);	return err ? -1 : 0;}/*****************************************************************************/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)#elsestatic void zc0301_urb_complete(struct urb *urb)#endif{	struct zc0301_device* cam = urb->context;	struct zc0301_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 zc0301_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;		u16* soi;		u8 sof;		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;		}		sof = (*(soi = pos) == 0xd8ff);		PDBGG("Isochrnous frame: length %u, #%u i,", len, i);		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);				DBG(3, "SOF detected: new video frame");			}		if ((*f)->state == F_GRABBING) {			if (sof && (*f)->buf.bytesused)					goto end_of_frame;			if ((*f)->buf.bytesused + len > imagesize) {				DBG(3, "Video frame size exceeded");				(*f)->state = F_ERROR;				continue;			}			memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);			(*f)->buf.bytesused += len;			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 zc0301_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)					goto start_of_frame;			}		}	}resubmit_urb:	urb->dev = cam->usbdev;	err = usb_submit_urb(urb, GFP_ATOMIC);	if (err < 0 && err != -EPERM) {		cam->state |= DEV_MISCONFIGURED;		DBG(1, "usb_submit_urb() failed");	}	wake_up_interruptible(&cam->wait_frame);}static int zc0301_start_transfer(struct zc0301_device* cam){	struct usb_device *udev = cam->usbdev;	struct usb_host_interface* altsetting = usb_altnum_to_altsetting(						     usb_ifnum_to_if(udev, 0),						     ZC0301_ALTERNATE_SETTING);	const unsigned int psz = le16_to_cpu(altsetting->					     endpoint[0].desc.wMaxPacketSize);	struct urb* urb;	s8 i, j;	int err = 0;	for (i = 0; i < ZC0301_URBS; i++) {		cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,						  GFP_KERNEL);		if (!cam->transfer_buffer[i]) {			err = -ENOMEM;			DBG(1, "Not enough memory");			goto free_buffers;		}	}	for (i = 0; i < ZC0301_URBS; i++) {		urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);		cam->urb[i] = urb;		if (!urb) {			err = -ENOMEM;			DBG(1, "usb_alloc_urb() failed");			goto free_urbs;		}		urb->dev = udev;		urb->context = cam;		urb->pipe = usb_rcvisocpipe(udev, 1);		urb->transfer_flags = URB_ISO_ASAP;		urb->number_of_packets = ZC0301_ISO_PACKETS;		urb->complete = zc0301_urb_complete;		urb->transfer_buffer = cam->transfer_buffer[i];		urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;		urb->interval = 1;		for (j = 0; j < ZC0301_ISO_PACKETS; j++) {			urb->iso_frame_desc[j].offset = psz * j;			urb->iso_frame_desc[j].length = psz;		}	}	err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);	if (err) {		DBG(1, "usb_set_interface() failed");		goto free_urbs;	}	cam->frame_current = NULL;	for (i = 0; i < ZC0301_URBS; i++) {		err = usb_submit_urb(cam->urb[i], GFP_KERNEL);		if (err) {			for (j = i-1; j >= 0; j--)				usb_kill_urb(cam->urb[j]);			DBG(1, "usb_submit_urb() failed, error %d", err);			goto free_urbs;		}	}	return 0;free_urbs:	for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)		usb_free_urb(cam->urb[i]);free_buffers:	for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)		kfree(cam->transfer_buffer[i]);	return err;}static int zc0301_stop_transfer(struct zc0301_device* cam){	struct usb_device *udev = cam->usbdev;	s8 i;	int err = 0;	if (cam->state & DEV_DISCONNECTED)		return 0;	for (i = ZC0301_URBS-1; i >= 0; i--) {		usb_kill_urb(cam->urb[i]);		usb_free_urb(cam->urb[i]);		kfree(cam->transfer_buffer[i]);	}	err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */	if (err)		DBG(3, "usb_set_interface() failed");

⌨️ 快捷键说明

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