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

📄 c-qcam.c

📁 pxa270下的摄像头mtd91111的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Video4Linux Colour QuickCam driver *	Copyright 1997-2000 Philip Blundell <philb@gnu.org> * *    Module parameters: * *	parport=auto      -- probe all parports (default) *	parport=0         -- parport0 becomes qcam1 *	parport=2,0,1     -- parports 2,0,1 are tried in that order * *	probe=0		  -- do no probing, assume camera is present *	probe=1		  -- use IEEE-1284 autoprobe data only (default) *	probe=2		  -- probe aggressively for cameras * *	force_rgb=1       -- force data format to RGB (default is BGR) * * The parport parameter controls which parports will be scanned. * Scanning all parports causes some printers to print a garbage page. *       -- March 14, 1999  Billy Donahue <billy@escape.com>  * * Fixed data format to BGR, added force_rgb parameter. Added missing * parport_unregister_driver() on module removal. *       -- May 28, 2000  Claudio Matsuoka <claudio@conectiva.com> */#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/parport.h>#include <linux/sched.h>#include <linux/version.h>#include <linux/videodev.h>#include <asm/semaphore.h>#include <asm/uaccess.h>struct qcam_device {	struct video_device vdev;	struct pardevice *pdev;	struct parport *pport;	int width, height;	int ccd_width, ccd_height;	int mode;	int contrast, brightness, whitebal;	int top, left;	unsigned int bidirectional;	struct semaphore lock;};/* cameras maximum */#define MAX_CAMS 4/* The three possible QuickCam modes */#define QC_MILLIONS	0x18#define QC_BILLIONS	0x10#define QC_THOUSANDS	0x08	/* with VIDEC compression (not supported) *//* The three possible decimations */#define QC_DECIMATION_1		0#define QC_DECIMATION_2		2#define QC_DECIMATION_4		4#define BANNER "Colour QuickCam for Video4Linux v0.05"static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };static int probe = 2;static int force_rgb = 0;static int video_nr = -1;static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i){	/* note: the QC specs refer to the PCAck pin by voltage, not	   software level.  PC ports have builtin inverters. */	parport_frob_control(qcam->pport, 8, i?8:0);}static inline unsigned int qcam_ready1(struct qcam_device *qcam){	return (parport_read_status(qcam->pport) & 0x8)?1:0;}static inline unsigned int qcam_ready2(struct qcam_device *qcam){	return (parport_read_data(qcam->pport) & 0x1)?1:0;}static unsigned int qcam_await_ready1(struct qcam_device *qcam, 					     int value){	unsigned long oldjiffies = jiffies;	unsigned int i;	for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )		if (qcam_ready1(qcam) == value)			return 0;	/* If the camera didn't respond within 1/25 second, poll slowly 	   for a while. */	for (i = 0; i < 50; i++)	{		if (qcam_ready1(qcam) == value)			return 0;		current->state=TASK_INTERRUPTIBLE;		schedule_timeout(HZ/10);	}	/* Probably somebody pulled the plug out.  Not much we can do. */	printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,	       parport_read_status(qcam->pport),	       parport_read_control(qcam->pport));	return 1;}static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value){	unsigned long oldjiffies = jiffies;	unsigned int i;	for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )		if (qcam_ready2(qcam) == value)			return 0;	/* If the camera didn't respond within 1/25 second, poll slowly 	   for a while. */	for (i = 0; i < 50; i++)	{		if (qcam_ready2(qcam) == value)			return 0;		current->state=TASK_INTERRUPTIBLE;		schedule_timeout(HZ/10);	}	/* Probably somebody pulled the plug out.  Not much we can do. */	printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,	       parport_read_status(qcam->pport),	       parport_read_control(qcam->pport),	       parport_read_data(qcam->pport));	return 1;}static int qcam_read_data(struct qcam_device *qcam){	unsigned int idata;	qcam_set_ack(qcam, 0);	if (qcam_await_ready1(qcam, 1)) return -1;	idata = parport_read_status(qcam->pport) & 0xf0;	qcam_set_ack(qcam, 1);	if (qcam_await_ready1(qcam, 0)) return -1;	idata |= (parport_read_status(qcam->pport) >> 4);	return idata;}static int qcam_write_data(struct qcam_device *qcam, unsigned int data){	unsigned int idata;	parport_write_data(qcam->pport, data);	idata = qcam_read_data(qcam);	if (data != idata) 	{		printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, 		       idata);		return 1;	} 	return 0;}static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data){	if (qcam_write_data(qcam, cmd))		return -1;	if (qcam_write_data(qcam, data))		return -1;	return 0;}static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd){	if (qcam_write_data(qcam, cmd))		return -1;	return qcam_read_data(qcam);}static int qc_detect(struct qcam_device *qcam){	unsigned int stat, ostat, i, count = 0;	/* The probe routine below is not very reliable.  The IEEE-1284	   probe takes precedence. */	/* XXX Currently parport provides no way to distinguish between	   "the IEEE probe was not done" and "the probe was done, but	   no device was found".  Fix this one day. */	if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA	    && qcam->pport->probe_info[0].model	    && !strcmp(qcam->pdev->port->probe_info[0].model, 		       "Color QuickCam 2.0")) {		printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");		return 1;	}		if (probe < 2)		return 0;	parport_write_control(qcam->pport, 0xc);	/* look for a heartbeat */	ostat = stat = parport_read_status(qcam->pport);	for (i=0; i<250; i++) 	{		mdelay(1);		stat = parport_read_status(qcam->pport);		if (ostat != stat) 		{			if (++count >= 3) return 1;			ostat = stat;		}	}	/* Reset the camera and try again */	parport_write_control(qcam->pport, 0xc);	parport_write_control(qcam->pport, 0x8);	mdelay(1);	parport_write_control(qcam->pport, 0xc);	mdelay(1);	count = 0;	ostat = stat = parport_read_status(qcam->pport);	for (i=0; i<250; i++) 	{		mdelay(1);		stat = parport_read_status(qcam->pport);		if (ostat != stat) 		{			if (++count >= 3) return 1;			ostat = stat;		}	}	/* no (or flatline) camera, give up */	return 0;}static void qc_reset(struct qcam_device *qcam){	parport_write_control(qcam->pport, 0xc);	parport_write_control(qcam->pport, 0x8);	mdelay(1);	parport_write_control(qcam->pport, 0xc);	mdelay(1);          }/* Reset the QuickCam and program for brightness, contrast, * white-balance, and resolution. */static void qc_setup(struct qcam_device *q){	qc_reset(q);	/* Set the brightness.  */       	qcam_set(q, 11, q->brightness);	/* Set the height and width.  These refer to the actual	   CCD area *before* applying the selected decimation.  */	qcam_set(q, 17, q->ccd_height);	qcam_set(q, 19, q->ccd_width / 2);	/* Set top and left.  */	qcam_set(q, 0xd, q->top);	qcam_set(q, 0xf, q->left);	/* Set contrast and white balance.  */	qcam_set(q, 0x19, q->contrast);	qcam_set(q, 0x1f, q->whitebal);		/* Set the speed.  */	qcam_set(q, 45, 2);}/* Read some bytes from the camera and put them in the buffer.    nbytes should be a multiple of 3, because bidirectional mode gives   us three bytes at a time.  */static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes){	unsigned int bytes = 0;	qcam_set_ack(q, 0);	if (q->bidirectional)	{		/* It's a bidirectional port */		while (bytes < nbytes)		{			unsigned int lo1, hi1, lo2, hi2;			unsigned char r, g, b;			if (qcam_await_ready2(q, 1)) return bytes;			lo1 = parport_read_data(q->pport) >> 1;			hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;			qcam_set_ack(q, 1);			if (qcam_await_ready2(q, 0)) return bytes;			lo2 = parport_read_data(q->pport) >> 1;			hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;			qcam_set_ack(q, 0);			r = (lo1 | ((hi1 & 1)<<7));			g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);			b = (lo2 | ((hi2 & 1)<<7));			if (force_rgb) {				buf[bytes++] = r;				buf[bytes++] = g;				buf[bytes++] = b;			} else {				buf[bytes++] = b;				buf[bytes++] = g;				buf[bytes++] = r;			}		}	}	else	{		/* It's a unidirectional port */		int i = 0, n = bytes;		unsigned char rgb[3];		while (bytes < nbytes)		{			unsigned int hi, lo;			if (qcam_await_ready1(q, 1)) return bytes;			hi = (parport_read_status(q->pport) & 0xf0);			qcam_set_ack(q, 1);			if (qcam_await_ready1(q, 0)) return bytes;			lo = (parport_read_status(q->pport) & 0xf0);			qcam_set_ack(q, 0);			/* flip some bits */			rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;			if (i >= 2) {get_fragment:				if (force_rgb) {					buf[n++] = rgb[0];					buf[n++] = rgb[1];					buf[n++] = rgb[2];				} else {					buf[n++] = rgb[2];					buf[n++] = rgb[1];					buf[n++] = rgb[0];				}			}		}		if (i) {			i = 0;			goto get_fragment;		}	}	return bytes;}#define BUFSZ	150static long qc_capture(struct qcam_device *q, char *buf, unsigned long len){	unsigned lines, pixelsperline, bitsperxfer;	unsigned int is_bi_dir = q->bidirectional;	size_t wantlen, outptr = 0;	char tmpbuf[BUFSZ];	if (verify_area(VERIFY_WRITE, buf, len))		return -EFAULT;	/* Wait for camera to become ready */	for (;;)	{		int i = qcam_get(q, 41);		if (i == -1) {			qc_setup(q);			return -EIO;		}		if ((i & 0x80) == 0)			break;		else			schedule();	}	if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))		return -EIO;		lines = q->height;	pixelsperline = q->width;	bitsperxfer = (is_bi_dir) ? 24 : 8;	if (is_bi_dir)	{		/* Turn the port around */		parport_data_reverse(q->pport);		mdelay(3);		qcam_set_ack(q, 0);		if (qcam_await_ready1(q, 1)) {			qc_setup(q);			return -EIO;		}		qcam_set_ack(q, 1);		if (qcam_await_ready1(q, 0)) {			qc_setup(q);			return -EIO;		}	}	wantlen = lines * pixelsperline * 24 / 8;	while (wantlen)	{		size_t t, s;		s = (wantlen > BUFSZ)?BUFSZ:wantlen;		t = qcam_read_bytes(q, tmpbuf, s);		if (outptr < len)		{			size_t sz = len - outptr;			if (sz > t) sz = t;			if (__copy_to_user(buf+outptr, tmpbuf, sz))				break;			outptr += sz;		}		wantlen -= t;		if (t < s)			break;		if (current->need_resched)			schedule();	}	len = outptr;	if (wantlen)	{		printk("qcam: short read.\n");		if (is_bi_dir)			parport_data_forward(q->pport);		qc_setup(q);		return len;	}	if (is_bi_dir)	{		int l;		do {

⌨️ 快捷键说明

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