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

📄 c-qcam.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Video4Linux Colour QuickCam driver *	Copyright 1997-1998 Philip Blundell <philb@gnu.org> * */#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/malloc.h>#include <linux/mm.h>#include <linux/parport.h>#include <linux/sched.h>#include <linux/version.h>#include <linux/videodev.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;};/* 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		4static 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;	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;		}	}	/* 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;			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);			buf[bytes++] = (lo1 | ((hi1 & 1)<<7));			buf[bytes++] = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);			buf[bytes++] = (lo2 | ((hi2 & 1)<<7));		}	}	else	{		/* It's a unidirectional port */		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 */			buf[bytes++] = (hi | (lo >> 4)) ^ 0x88;		}	}	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_frob_control(q->pport, 0x20, 0x20);		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_frob_control(q->pport, 0x20, 0);		qc_setup(q);		return len;	}	if (is_bi_dir)	{		int l;		do {			l = qcam_read_bytes(q, tmpbuf, 3);			if (current->need_resched)				schedule();		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));		if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)			printk("qcam: bad EOF\n");		qcam_set_ack(q, 0);		if (qcam_await_ready1(q, 1))		{			printk("qcam: no ack after EOF\n");			parport_frob_control(q->pport, 0x20, 0);			qc_setup(q);			return len;		}		parport_frob_control(q->pport, 0x20, 0);		mdelay(3);		qcam_set_ack(q, 1);		if (qcam_await_ready1(q, 0))		{			printk("qcam: no ack to port turnaround\n");			qc_setup(q);			return len;		}	}	else	{		int l;		do {			l = qcam_read_bytes(q, tmpbuf, 1);			if (current->need_resched)				schedule();		} while (l && tmpbuf[0] == 0x7e);		l = qcam_read_bytes(q, tmpbuf+1, 2);		if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)

⌨️ 快捷键说明

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