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

📄 qcamvc_pp.c

📁 VC编写的USB QuickCam驱动程序,实现四种视频格式在linux下的编码,信号来自摄像源
💻 C
📖 第 1 页 / 共 2 页
字号:
		cond_resched();#endif		if ( (read=parport_read(parport, buffer + counter, 1)) != 1 )		{			printk(KERN_ERR "QuickCamVC: qcamvc_stream_read2: failed to read: error %i.\n", read);			break;		}		read_bytes += read;	}		return read_bytes;}/********************************************************************//* qcamvc_read general purpose parport read interface		*//****************************************************************/static size_t qcamvc_read(void *privdata, void *buffer, size_t len){	struct pp_cam_entry *cam = privdata;	if(!cam || !cam->open_count) return 0;		struct parport *parport = cam->port;	size_t ret=0;		if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0)	{		printk(KERN_ERR "QuickCamVC: qcamvc_read: ieee1284 failed negotiation\n");		return -1;	}	parport_read(parport, buffer, len);		return ret = len;}/******************************************************************//* qcamvc_write general purpose parport write interface		*//****************************************************************/static int qcamvc_write(void *privdata, void *buffer, size_t len){	struct pp_cam_entry *cam = privdata;	if(!cam || !cam->open_count) return 0;		struct parport *parport = cam->port;  	int ret=0;		if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0)	{		printk(KERN_ERR "QuickCamVC: qcamvc_write: ieee1284 failed negotiation\n");		return -1;	}	parport_write(parport, buffer, len);		return ret = len;}/********************************************************************************//* qcamvc_set_reg register value set method for the parport version of the QuickCamVC *//********************************************************************************/static int qcamvc_set_reg(void *privdata, unsigned char reg, void *buffer, size_t len){	struct pp_cam_entry *cam = privdata;	if(!cam || !cam->open_count) return 0;		struct parport *parport = cam->port;	int ret=0;		if ( parport_negotiate(parport, IEEE1284_ADDR | ppmode) != 0 )	{		printk(KERN_ERR "QuickCamVC:WCN1 qcamvc_set_reg1: ieee1284 failed negotiation\n");		return -1;	}	if (parport_write(parport, &reg, 1) != 1)		printk(KERN_INFO "QuickCamVC: qcamvc_set_reg: write failed #1\n");		if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0)	{		printk(KERN_ERR "QuickCamVC: qcamvc_set_reg2: ieee1284 failed negotiation\n");		return -1;	}	if (parport_write(parport, buffer, len) != len)		printk(KERN_ERR "QuickCamVC: qcamvc_set_reg: write failed #2\n");		return ret = len;}/********************************************************************************//* qcamvc_get_reg register value retrieval method for the parport version of theQuickCamVC *//*********************************************************************************/static size_t qcamvc_get_reg(void *privdata, unsigned char reg, void *buffer, size_t len){	struct pp_cam_entry *cam = privdata;	if(!cam || !cam->open_count) return 0;		struct parport *parport = cam->port;	int ret=0;		if(parport_negotiate(cam->port, IEEE1284_ADDR | ppmode) != 0)	{		printk(KERN_ERR "QuickCamVC:WCN1 qcamvc_get_reg1: ieee1284 failed negotiation\n");		return -1;	}		ret=parport_write(parport, &reg, 1);		if (len == 0 || buffer == NULL)		return ret;		if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0)	{		printk(KERN_ERR "QuickCamVC: qcamvc_get_reg2: ieee1284 failed negotiation\n");		return -1;	}	parport_read(parport, buffer, len);		return len;}/************************************************************************//* qcamvc_register registers the camera with the V4L driver and the parport driver*//**************************************************************************/static int qcamvc_register(struct parport *port) {	struct pardevice *pdev = NULL;	struct pp_cam_entry *cam;	struct qcamvc_data *qcamvc;		if (!(port->modes & PARPORT_MODE_ECP) &&		!(port->modes & PARPORT_MODE_TRISTATE))	{		printk(KERN_ERR "QuickCam VC(PP): Port is not ECP capable!\n");		return -ENXIO;	}	if (port->modes & PARPORT_MODE_DMA)		printk(KERN_INFO "QuickCam VC(PP): Port is DMA capable.\n");		cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);	if (cam == NULL)	{		printk(KERN_ERR "QuickCam VC(PP): Failed to allocate pp_cam_entry.\n");		return -ENOMEM;	}		memset(cam,0,sizeof(struct pp_cam_entry));	pdev = parport_register_device(port, "Connectix QuickCam VC", NULL, NULL, NULL, 0, cam);  	if (!pdev)	{		//LOG("failed to parport_register_device\n");		printk(KERN_ERR "Failed to parport_register_device.\n");		kfree(cam);		return -ENXIO;	}  	cam->pdev = pdev;	cam->port = port;	if( (qcamvc = qcamvc_register_camera(&qcamvc_pp_ops, cam, "QuickCam VC(PP)")) == NULL )	{		printk(KERN_ERR "Failed to qcamvc_register_camera.\n");		parport_unregister_device(pdev);		kfree(cam);		return -ENXIO;	}	printk(KERN_INFO "QuickCam VC(PP): sucessfully registered.\n");	spin_lock( &cam_list_lock_pp );	list_add( &qcamvc->cam_data_list, &cam_list );	spin_unlock( &cam_list_lock_pp );	return 0;}/*****************************************************************//* qcamvc_pp_detach Used to remove the driver from the kernel *//****************************************************************/static void qcamvc_pp_detach(struct parport *port){	struct list_head *tmp;	struct qcamvc_data *qcamvc = NULL;	struct pp_cam_entry *cam = NULL;	spin_lock( &cam_list_lock_pp );	list_for_each (tmp, &cam_list)	{		qcamvc = list_entry(tmp, struct qcamvc_data, cam_data_list);		cam = (struct pp_cam_entry *) qcamvc->lowlevel_data;		if (cam && cam->port->number == port->number)		{			break;		}		qcamvc = NULL;	}	spin_unlock( &cam_list_lock_pp );	if (!qcamvc || !cam)	{		printk(KERN_ERR "qcamvc_pp_detach failed to find qcamvc in cam_data_list\n");		return;	}	if(cam->open_count > 0) 		qcamvc_close(cam);	parport_unregister_device(cam->pdev);	qcamvc->lowlevel_data = NULL;	kfree(cam);}/*****************************************************************//* qcamvc_pp_attach used to attach the driver to the kernel *//**************************************************************/static void qcamvc_pp_attach(struct parport *port){	unsigned int i;	switch (parport_nr[0])	{		case QCAMVC_PARPORT_UNSPEC:		case QCAMVC_PARPORT_AUTO:		if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||			strncmp(port->probe_info[0].mfr, "Connectix", 9) != 0 ||			strncmp(port->probe_info[0].model, "QuickCam VC", 11) != 0			)		{			printk(KERN_ERR "qcamvc_pp_attach failed.\n");  			return;		}		qcamvc_register(port);     		break;      		default:		for (i = 0; i < PARPORT_MAX; ++i) 		{			if (port->number == parport_nr[i])			{				qcamvc_register(port);				break;			}		}		break;	}}static struct parport_driver qcamvc_pp_driver = {	.name = "Connectix QuickCam VC",	.attach = qcamvc_pp_attach,	.detach = qcamvc_pp_detach,};static int qcamvc_pp_init(void){	if(parport_nr[0] == QCAMVC_PARPORT_OFF)	{		printk("  disabled\n");		return 0;	}	spin_lock_init( &cam_list_lock_pp );			if (parport_register_driver (&qcamvc_pp_driver))	{		printk(KERN_ERR "unable to register with parport\n");		return -EIO;	}		return 0;}#ifdef MODULE/********************************************************************//* qcamvc_pp_init_module used by the wrapper below to insmod (or modprobe) *//*********************************************************************/static int __init qcamvc_pp_init_module (void){	printk("QuickCam VC(PP): (C) 2001 by De Marchi Daniele, <demarchidaniele@libero.it>\n");	printk("QuickCam VC(PP): lowlevel driver version %s registered.\n",QCAMVCVERSION);		if (parport[0])	{		/* The user gave some parameters.  Let's see what they were. */		if (!strncmp(parport[0], "auto", 4))		{			parport_nr[0] = QCAMVC_PARPORT_AUTO;		}		else		{			int n;			for (n = 0; n < PARPORT_MAX && parport[n]; n++)			{				if (!strncmp(parport[n], "none", 4))				{					parport_nr[n] = QCAMVC_PARPORT_NONE;				}				else				{					char *ep;					unsigned long r = simple_strtoul(parport[n], &ep, 0);					if (ep != parport[n])					{						parport_nr[n] = r;					}					else					{						printk("bad port specifier `%s'\n", parport[n]);						return -ENODEV;					}				}			}		}	}#if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE)	if(parport_enumerate() && !parport_enumerate()->probe_info.model)	{		request_module("parport_probe");	}#endif  	return qcamvc_pp_init();}/***************************************************************************//* qcamvc_pp_exit_module used by the wrapper below to rmmod *//**************************************************************************/static void __exit qcamvc_pp_exit_module(void){	parport_unregister_driver(&qcamvc_pp_driver);	/*	finally unregister video.	can't do this in detach() because the call to qcamvc_unregister_camera()	blocks and causes "bad: scheduling while atomic!" when unloading this module.	*/	struct list_head *tmp;	struct qcamvc_data *qcamvc = NULL;	spin_lock( &cam_list_lock_pp );	list_for_each (tmp, &cam_list)	{		qcamvc = list_entry(tmp, struct qcamvc_data, cam_data_list);		/*		lowlevel_data will be NULL if it's the one we want		ie. lowlevel_data=NULL in detach() from call to parport_unregister_driver()		*/		if (!qcamvc->lowlevel_data)		{			list_del(&qcamvc->cam_data_list);			break;		}		qcamvc = NULL;	}	spin_unlock( &cam_list_lock_pp );	if (!qcamvc)		printk("qcamvc_pp_exit_module: failed to find qcamvc in cam_data_list\n");	else			qcamvc_unregister_camera(qcamvc);}/**************************************//* wrappers used by insmod and rmmod to load and unload the driver as a module *//**************************************/module_init(qcamvc_pp_init_module);module_exit(qcamvc_pp_exit_module);#else /*!MODULE*//**************************************************//* used if compiled into the kernel *//*************************************************/static int __init qcamvc_pp_setup(char *str){	if (!strncmp(str, "parport", 7)) {		int n = simple_strtoul(str + 7, NULL, 10);		if (parport_ptr < PARPORT_MAX) {			parport_nr[parport_ptr++] = n;		} else {			LOG("too many ports, %s ignored.\n", str);		}	} else if (!strcmp(str, "auto")) {		parport_nr[0] = QCAMVC_PARPORT_AUTO;	} else if (!strcmp(str, "none")) {		parport_nr[parport_ptr++] = QCAMVC_PARPORT_NONE;	}	return 0;}__setup("qcamvc_pp=", qcamvc_pp_setup);#endif /* MODULE *//* ----------------------------------------*//* Parallel Port DMA Code from CPiA driver *//* ----------------------------------------*/#ifdef QCAMVC_PARPORT_DMA/*-----------------------------------------------------------------------*//* stuff below is static stuff  * copied from parport_pc.c (should be made public) */#define DPRINTK(fmt,args...) do {} while(0)/* ECR modes */#define ECR_SPP 00#define ECR_PS2 01#define ECR_PPF 02#define ECR_ECP 03#define ECR_EPP 04#define ECR_VND 05#define ECR_TST 06#define ECR_CNF 07#define ECR_MODE_MASK 0xe0#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v))#define ECONTROL(p) ((p)->base_hi + 0x2)/* frob_control, but for ECR */static void frob_econtrol (struct parport *pb, unsigned char m,			   unsigned char v){	unsigned char ectr = 0;	if (m != 0xff)		ectr = inb (ECONTROL (pb));	DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",		m, v, ectr, (ectr & ~m) ^ v);	outb ((ectr & ~m) ^ v, ECONTROL (pb));}/* Safely change the mode bits in the ECR    Returns:	    0    : Success	   -EBUSY: Could not drain FIFO in some finite amount of time,		   mode not changed! */static int change_mode(struct parport *p, int m){	const struct parport_pc_private *priv = p->physport->private_data;	unsigned char oecr;	int mode;	DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m);	if (!priv->ecr) {		printk (KERN_DEBUG "change_mode: but there's no ECR!\n");		return 0;	}	/* Bits <7:5> contain the mode. */	oecr = inb (ECONTROL (p));	mode = (oecr >> 5) & 0x7;	if (mode == m) return 0;	if (mode >= 2 && !(priv->ctr & 0x20)) {		/* This mode resets the FIFO, so we may		 * have to wait for it to drain first. */#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))		long expire = jiffies + p->physport->cad->timeout;#else		unsigned long expire = jiffies + p->physport->cad->timeout;#endif		int counter;		switch (mode) {		case ECR_PPF: /* Parallel Port FIFO mode */		case ECR_ECP: /* ECP Parallel Port mode */			/* Busy wait for 200us */			for (counter = 0; counter < 40; counter++) {				if (inb (ECONTROL (p)) & 0x01)					break;				if (signal_pending (current)) break;				udelay (5);			}			/* Poll slowly. */			while (!(inb (ECONTROL (p)) & 0x01)) {				if (time_after_eq (jiffies, expire))					/* The FIFO is stuck. */					return -EBUSY;				__set_current_state (TASK_INTERRUPTIBLE);				schedule_timeout ((HZ + 99) / 100);				if (signal_pending (current))					break;			}		}	}	if (mode >= 2 && m >= 2) {		/* We have to go through mode 001 */		oecr &= ~(7 << 5);		oecr |= ECR_PS2 << 5;		ECR_WRITE (p, oecr);	}	/* Set the mode. */	oecr &= ~(7 << 5);	oecr |= m << 5;	ECR_WRITE (p, oecr);	return 0;}#endif /* QCAMVC_PARPORT_DMA */

⌨️ 快捷键说明

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