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

📄 zc0301_driver.c

📁 在LINUX下编译的摄像头驱动源码,有MAKE文件
💻 C
字号:
/*	This file in the main file of this driver. * *	This driver is suite for zc0301 control IC and pb0330 sensor IC. * *	The device uses USB1.1 to transfer datas, so speed is not so fast. * *	I bought my camera at 2005.01.xx, it cost me 110 RMB. * * 	It's created by WE.XCC at 2008.05.03
 *
 *	Author's E-mail:84318391@163.com */#include <linux/kernel.h>  /*printk and other*/#include <linux/module.h>  /*module_init(exit)*/#include <linux/types.h>   /*u8 u16 u32 etc*/#include <linux/usb.h>     /*should be contained if the device is an usb device*/#include <linux/fs.h>      /*struct file_operations*/#include "zc0301_struct.h"#include "zc0301_debug.h"#include "zc0301_descriptors.h"#include "zc0301_pb0330.h"#include "zc0301_urb.h"#include "zc0301_v4l2.h"static const struct usb_device_id zc0301_id_table[] =  {	{ USB_DEVICE(0x0ac8, 0x301b) }, /* PB-0330/HV7131 */	{ }};int zc0301_init_pb0330_and_0301(struct zc0301_device *camm){	struct zc0301_device *cam = NULL;	int err = 0;	if (camm == NULL)	{		debug_error("zc0301_init_pb0330_and_0301:camm is null\n");		return -ENODEV;	}	//debug_param("%s\n", __FUNCTION__);	cam = camm;		err = zc0301_pb0330_init(cam);	if (err)	{		debug_error("zc0301_init_pb0330_and_0301:pb0330 init failed\n");		return err;	}	debug_info("zc0301_init_pb0330_and_0301:pb0330 init successed\n");	err = zc0301_set_compression(cam);	if (err)	{		debug_error("zc0301_init_pb0330_and_0301:set compression failed\n");		return err;	}	debug_info("zc0301_init_pb0330_and_0301:set compression successed\n");	init_waitqueue_head(&cam->wait_frame);	spin_lock_init(&cam->queue_lock);	mutex_init(&cam->fop_mutex);	cam->d_state |= INITED;	cam->users = 0;	return 0;}int zc0301_mmap(struct file *filp, struct vm_area_struct *vma){	struct zc0301_device *cam = NULL;	unsigned long size = vma->vm_end - vma->vm_start, start = vma->vm_start;	void *pos = NULL;	u32 i = 0;	if ((filp == NULL) || (vma == NULL))	{		debug_error("zc0301_mmap:filp or vma is null\n");		return -EIO;	}	//debug_param("%s\n", __FUNCTION__);	cam = filp->private_data;		if (mutex_lock_interruptible(&cam->fop_mutex)) /*I don't know why to use interruptible?*/		return -ERESTARTSYS;	if ((cam->d_state & DISCONNECTED) || (cam->d_state & MISCONFIGED))	{		debug_error("zc0301_mmap:state is wrong\n");		mutex_unlock(&cam->fop_mutex);		return cam->d_state & DISCONNECTED ? -ENODEV : -EIO;	}		if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_READ) || size != 307200)	{		debug_error("zc0301_mmap:flag or size is wrong, failed\n");		mutex_unlock(&cam->fop_mutex);		return -EINVAL;	}	for (i = 0; i < cam->nbuffers; i++)	{		if ((cam->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)			break;	}	if (i >= cam->nbuffers)	{		debug_error("zc0301_mmap:i >= nbuffers, failed\n");		mutex_unlock(&cam->fop_mutex);		return -EINVAL;	}	vma->vm_flags |= VM_IO;	vma->vm_flags |= VM_RESERVED;	pos = cam->frame[i].bufmem;	while (size > 0)	{		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) /*I don't know here :(*/		{			debug_error("zc0301_mmap:vm_insert_page failed\n");			return -EAGAIN;		}		pos   += PAGE_SIZE;		start += PAGE_SIZE;			size  -= PAGE_SIZE;	}	vma->vm_private_data = &cam->frame[i];	mutex_unlock(&cam->fop_mutex);	return 0;}int zc0301_open(struct inode *inode, struct file *filp){	struct zc0301_device *cam = NULL;	int err = 0;	u8 i = 0;	if (filp == NULL)	{		debug_error("zc0301_open:filp is null\n");		return -EINVAL;	}	//debug_param("%s\n", __FUNCTION__);	debug_param("process %i(%s) wanna open this driver\n", current->pid, current->comm);	cam = video_get_drvdata(video_devdata(filp));		mutex_lock(&cam->dev_mutex);	if (cam->users)	{		debug_info("the device is busy now.plz visit it later\n");		if (filp->f_flags & O_NONBLOCK)		{			debug_error("zc0301_open:operation is nonblocked\n");			mutex_unlock(&cam->dev_mutex);			return -EWOULDBLOCK;		}		/*if open-operation is blocked, I will add blocked handles here*/		/*But open-operation is non_blocked usually*/	}	/*if this is the first time to open device, driver should make sure whether the device has been configed*/	if (cam->d_state & MISCONFIGED)	{		err = zc0301_init_pb0330_and_0301(cam);		if (err)		{			debug_error("zc0301_open:init pb0330 and 0301 failed\n");			mutex_unlock(&cam->dev_mutex);			return -EFAULT;		}		cam->d_state = INITED;	}	filp->private_data = cam;	INIT_LIST_HEAD(&cam->inqueue);	INIT_LIST_HEAD(&cam->outqueue);	for (i = 0; i < ZC0301_MAX_FRAMES; i++)	{		cam->frame[i].f_state = F_UNUSED;		cam->frame[i].buf.bytesused = 0;	}	cam->users++;	cam->nbuffers = 0;	cam->s_state = STREAM_OFF;		err = zc0301_urb_start(cam);	if (err)	{		debug_error("zc0301_open:urb start transfer failed\n");		mutex_unlock(&cam->dev_mutex);		return err;	}	mutex_unlock(&cam->dev_mutex);	//debug_info("zc0301_open:open successed\n");	return 0;}int zc0301_release(struct inode *inode, struct file *filp){	struct zc0301_device *cam = NULL;	int err = 0;		if (filp == NULL)	{		debug_error("zc0301_release:filp is null\n");		return -EINVAL;	}	//debug_param("%s\n", __FUNCTION__);	cam = filp->private_data;	mutex_lock(&cam->dev_mutex);	err = zc0301_urb_stop(cam);	if (err)	{		debug_error("zc0301_release:urb stop transfer failed\n");		mutex_unlock(&cam->dev_mutex);		return err;	}	/*if driver has alloced some vma, vfree them first*/	if (cam->nbuffers)	{		vfree(cam->frame[0].bufmem);		cam->nbuffers = 0;	}		cam->users--;	mutex_unlock(&cam->dev_mutex);	//debug_info("zc0301_release:close successed\n");	return 0;}int zc0301_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){	struct zc0301_device *cam = NULL;	int err = 0;	if (filp == NULL)	{		debug_error("zc0301_ioctl:filp is null\n");		return -EINVAL;	}	//debug_param("%s\n", __FUNCTION__);	cam = filp->private_data;	if (mutex_lock_interruptible(&cam->fop_mutex)) /*I don't know why to use interruptible here*/		return -ERESTARTSYS;                   /*it works well if I choose mutex_lock*/	if ((cam->d_state & DISCONNECTED) || (cam->d_state & MISCONFIGED))	{		debug_error("zc0301_ioctl:dev state is wrong\n");		//wake_up_interruptible_all(&cam->wait_frame);		mutex_unlock(&cam->fop_mutex);		return cam->d_state & DISCONNECTED ? -ENODEV : -EIO;	}		err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);	mutex_unlock(&cam->fop_mutex);	return err;}static const struct file_operations zc0301_fops = {	.owner        = THIS_MODULE,	.open         = zc0301_open,	.release      = zc0301_release,	.mmap         = zc0301_mmap,	.ioctl        = zc0301_ioctl,	//.compat_ioctl = v4l_compat_ioctl32,};static struct video_device zc0301_video = {	.name    = "zc0301 PC camera",	.owner   = THIS_MODULE,	.type    = VID_TYPE_CAPTURE,	.fops    = &zc0301_fops,	.minor   = -1,	.release = video_device_release,};static int zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id){	struct zc0301_device *cam = NULL;	struct usb_device *udev = NULL;	int err = 0;	u8 flag = 0;	if ((intf == NULL) || (id == NULL))	{		debug_error("zc0301_usb_probe:intf or id is null\n");		return -EIO;	}	debug_param("There are %u alternate settings for this"		    "interface, so you must make sure that your altsetting"		    "number should between 0 to %u\n"		    , intf->num_altsetting, intf->num_altsetting - 1);	udev = interface_to_usbdev(intf);	if (udev == NULL)        {                debug_error("zc0301_usb_probe:udev is null\n");                return -EINVAL;        }	debug_param("This Device has %d configurations\n", (udev->descriptor).bNumConfigurations);	if ((udev->descriptor).bNumConfigurations > 1)	{		debug_error("We Don't Handle MultiConfig Device.....\n");		return -EFAULT;	}	switch (udev->speed)	{		case USB_SPEED_UNKNOWN:			debug_info("UNKNOWN SPEED.\n");			break;		case USB_SPEED_LOW:			debug_info("LOW SPEED DEVICE.\n");			break;		case USB_SPEED_FULL:			debug_info("FULL SPEED DEVICE.\n");			break;		case USB_SPEED_HIGH:			debug_info("HIGH SPEED DEVICE.\n");			break;		case USB_SPEED_VARIABLE:			debug_info("USING FOR WIRELESS DEVICE.\n");			break;	}	debug_info("START PROBE\n");	do	{		if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))		{			debug_error("zc0301_usb_probe:cam alloc failed\n");			flag = 1;			break;		}		if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL)))		{			debug_error("zc0301_usb_probe:control_buffer alloc failed\n");			flag = 1;			break;		}				if (!(cam->v4ldev = video_device_alloc()))		{			debug_error("zc0301_usb_probe:v4ldev alloc failed\n");			flag = 1;			break;		}		debug_info("resources alloc successed\n");		cam->usbdev = udev;		mutex_init(&cam->dev_mutex);		mutex_lock(&cam->dev_mutex);		err = zc0301_pb0330_probe(cam);		if (err)		{			debug_error("zc0301_usb_probe:pb0330 probe failed\n");			flag = 1;			mutex_unlock(&cam->dev_mutex);			break;		}		debug_info("sensor IC:pb0330 probe successed\n");		err = zc0301_init_pb0330_and_0301(cam);		if (err)		{			debug_error("zc0301_usb_probe:pb0330 and 0301 failed\n");			cam->d_state = MISCONFIGED;		}		debug_info("pb0330 && 0301 init successed\n");		memcpy(cam->v4ldev, &zc0301_video, sizeof(struct video_device));		video_set_drvdata(cam->v4ldev, cam);		err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, 0);		if (err)		{			debug_error("zc0301_usb_probe:register video device failed\n");			mutex_unlock(&cam->dev_mutex);			flag = 1;			break;		}		debug_info("register video device successed\n");		usb_set_intfdata(intf, cam);		usb_get_dev(cam->usbdev);		mutex_unlock(&cam->dev_mutex);		debug_info("PROBE SUCCESSED!\n");		/*print descriptors*/        	zc0301_get_device_descriptor(cam);        	zc0301_get_config_descriptor(cam);       	 	zc0301_get_interface_descriptor(cam);        	zc0301_get_endpoint_descriptor(cam);	        zc0301_get_string_descriptor(cam);	} while(0);	if (flag)	{		debug_error("PROBE FAILED!!!!!\n");		if (cam)		{			if (cam->control_buffer)				kfree(cam->control_buffer);			if (cam->v4ldev)				video_device_release(cam->v4ldev);		}		kfree(cam);	}	return err;}static void zc0301_usb_disconnect(struct usb_interface* intf){	struct zc0301_device *cam = NULL;	//u8 i = 0;	if (intf == NULL)	{		debug_error("zc0301_usb_disconnect:intf is null\n");		return;	}	//debug_param("%s\n", __FUNCTION__);	cam = usb_get_intfdata(intf);	if (cam == NULL)	{		debug_error("zc0301_usb_disconnect:cam is null\n");		return;	}		debug_info("DISCONNECT START\n");	mutex_lock(&cam->dev_mutex);	if (cam->users)	{		zc0301_urb_stop(cam);		cam->d_state |= DISCONNECTED;		wake_up_interruptible(&cam->wait_frame);	}	else	{		video_set_drvdata(cam->v4ldev, NULL);        	video_unregister_device(cam->v4ldev);		kfree(cam->control_buffer);		cam->d_state |= DISCONNECTED;	}	usb_put_dev(cam->usbdev);	mutex_unlock(&cam->dev_mutex);	if (cam->users == 0)		kfree(cam);	debug_info("DISCONNECT SUCCESSED!\n");}static struct usb_driver zc0301_module_driver = {	.name =       "webcam",	.id_table =   zc0301_id_table,	.probe =      zc0301_usb_probe,	.disconnect = zc0301_usb_disconnect,};static int __init zc0301_module_insmod(void){	s8 err = 0;	debug_info("MODULE INSMOD START\n");	err = usb_register(&zc0301_module_driver);	if (err)	{		debug_error("register an usb device failed...\n");		return err;	}	return 0;}static void __exit zc0301_module_rmmod(void){	debug_info("MODULE RMMOD START\n");	usb_deregister(&zc0301_module_driver);}module_init(zc0301_module_insmod);module_exit(zc0301_module_rmmod);MODULE_LICENSE("GPL");MODULE_AUTHOR("WE.XCC");MODULE_DESCRIPTION("This is the first driver I programs using for my ZC0301 PC Camera"		   "ZC0301[P] process && control IC and PB0330 sensor IC");MODULE_DEVICE_TABLE(usb, zc0301_id_table);

⌨️ 快捷键说明

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