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

📄 w9966.c

📁 pxa270下的摄像头mtd91111的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
{	// saa7111 regs 0x00 trough 0x12	const u8 regs[] = {		0x00, // not written		0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, 0x88, 0x10,		cam->brightness,	// 0x0a		cam->contrast,		// 0x0b		cam->color,		// 0x0c		cam->hue,		// 0x0d		0x01, 0x00, 0x48, 0x0c, 0x00,	};	int i;	if (w9966_flag_test(cam, W9966_STATE_DETECTED))		return 1;	// Write regs to saa7111 chip	for (i = 1; i < 0x13; i++)		if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, i, regs[i]))			return 1;	// Read back regs	for (i = 1; i < 0x13; i++)		if (w9966_i2c_rreg(cam, W9966_SAA7111_ID, i) != regs[i])			return 1;	// Fill in model specific data	cam->name = "Lifeview Flycam Supra";	cam->sramsize = 128 << 10;	// 128 kib	cam->sramid = 0x02;		// see w9966.pdf	cam->cmask = 0x18;		// normal polarity	cam->min_x = 16;		// empirically determined	cam->max_x = 705;	cam->min_y = 14;	cam->max_y = 253;	cam->image = &w9966_saa7111_image;	DPRINTF("Found and initialized a saa7111 chip.\n");	w9966_flag_set(cam, W9966_STATE_DETECTED);	return 1;}// Setup image properties (brightness, hue, etc.) for the saa7111 chip// expects a claimed parport// 1 on success, else 0static int w9966_saa7111_image(struct w9966_dev* cam){	if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0a, cam->brightness) ||	    !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0b, cam->contrast) ||	    !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0c, cam->color) ||	    !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0d, cam->hue))		return 0;	return 1;}// Detect and initialize lc99053 ccd-controller chip.// expects a claimed parport// this is currently a hack, no detection is done, we just assume an Eyestar2// 1 on success, else 0static int w9966_lc99053_init(struct w9966_dev* cam){	if (w9966_flag_test(cam, W9966_STATE_DETECTED))		return 1;	// Fill in model specific data	cam->name = "Microtek Eyestar2";	cam->sramsize = 128 << 10;	// 128 kib	cam->sramid = 0x02;		// w9966cf.pdf	cam->cmask = 0x10;		// reverse polarity	cam->min_x = 16;		// empirically determined	cam->max_x = 705;	cam->min_y = 14;	cam->max_y = 253;	cam->image = &w9966_lc99053_image;	DPRINTF("Found and initialized a lc99053 chip.\n");	w9966_flag_set(cam, W9966_STATE_DETECTED);	return 1;}// Setup image properties (brightness, hue, etc.) for the lc99053 chip// expects a claimed parport// 1 on success, else 0static int w9966_lc99053_image(struct w9966_dev* cam){	return 1;}/* *	Ugly and primitive i2c protocol functions */// Sets the data line on the i2c bus.// Expects a claimed pdev.static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state){	if (state)		cam->i2c_state |= W9966_I2C_W_DATA;	else		cam->i2c_state &= ~W9966_I2C_W_DATA;	w9966_wreg(cam, 0x18, cam->i2c_state);	udelay(W9966_I2C_UDELAY);}// Sets the clock line on the i2c bus.// Expects a claimed pdev.// 1 on success, else 0static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state){	if (state)		cam->i2c_state |= W9966_I2C_W_CLOCK;	else		cam->i2c_state &= ~W9966_I2C_W_CLOCK;	w9966_wreg(cam, 0x18, cam->i2c_state);	udelay(W9966_I2C_UDELAY);	// when we go to high, we also expect the peripheral to ack.	if (state) {		const int timeout = jiffies + W9966_I2C_TIMEOUT;		while (!w9966_i2c_getscl(cam)) {			if (time_after(jiffies, timeout))				return 0;		}	}	return 1;}// Get peripheral data line// Expects a claimed pdev.static inline int w9966_i2c_getsda(struct w9966_dev* cam){	const u8 pins = w9966_rreg(cam, 0x18);	return ((pins & W9966_I2C_R_DATA) > 0);}// Get peripheral clock line// Expects a claimed pdev.static inline int w9966_i2c_getscl(struct w9966_dev* cam){	const u8 pins = w9966_rreg(cam, 0x18);	return ((pins & W9966_I2C_R_CLOCK) > 0);}// Write a byte with ack to the i2c bus.// Expects a claimed pdev.// 1 on success, else 0static int w9966_i2c_wbyte(struct w9966_dev* cam, int data){	int i;	for (i = 7; i >= 0; i--) {		w9966_i2c_setsda(cam, (data >> i) & 0x01);		if (!w9966_i2c_setscl(cam, 1) ||		    !w9966_i2c_setscl(cam, 0))			return 0;	}	w9966_i2c_setsda(cam, 1);	if (!w9966_i2c_setscl(cam, 1) ||	    !w9966_i2c_setscl(cam, 0))		return 0;	return 1;}// Read a data byte with ack from the i2c-bus// Expects a claimed pdev. -1 on errorstatic int w9966_i2c_rbyte(struct w9966_dev* cam){	u8 data = 0x00;	int i;	w9966_i2c_setsda(cam, 1);	for (i = 0; i < 8; i++)	{		if (!w9966_i2c_setscl(cam, 1))			return -1;		data = data << 1;		if (w9966_i2c_getsda(cam))			data |= 0x01;		w9966_i2c_setscl(cam, 0);	}	return data;}// Read a register from the i2c device.// Expects claimed pdev. -1 on errorstatic int w9966_i2c_rreg(struct w9966_dev* cam, int device, int reg){	int data;	w9966_i2c_setsda(cam, 0);	w9966_i2c_setscl(cam, 0);	if (!w9966_i2c_wbyte(cam, device << 1) ||	    !w9966_i2c_wbyte(cam, reg))		return -1;	w9966_i2c_setsda(cam, 1);	if (!w9966_i2c_setscl(cam, 1))		return -1;	w9966_i2c_setsda(cam, 0);	w9966_i2c_setscl(cam, 0);	if (!w9966_i2c_wbyte(cam, (device << 1) | 1) ||	    (data = w9966_i2c_rbyte(cam)) == -1)		return -1;	w9966_i2c_setsda(cam, 0);	if (!w9966_i2c_setscl(cam, 1))		return -1;	w9966_i2c_setsda(cam, 1);	return data;}// Write a register to the i2c device.// Expects claimed pdev.// 1 on success, else 0static int w9966_i2c_wreg(struct w9966_dev* cam, int device, int reg, int data){	w9966_i2c_setsda(cam, 0);	w9966_i2c_setscl(cam, 0);	if (!w9966_i2c_wbyte(cam, device << 1) ||	    !w9966_i2c_wbyte(cam, reg) ||	    !w9966_i2c_wbyte(cam, data))		return 0;	w9966_i2c_setsda(cam, 0);	if (!w9966_i2c_setscl(cam, 1))		return 0;	w9966_i2c_setsda(cam, 1);	return 1;}/* *	Video4linux interface */static int w9966_v4l_open(struct video_device *vdev, int flags){	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;	// Claim parport	if (!w9966_pdev_claim(cam)) {		DPRINTF("Unable to claim parport");		return -EFAULT;	}	// Allocate read buffer	cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL);	if (cam->buffer == NULL) {		w9966_pdev_release(cam);		return -ENOMEM;	}	w9966_flag_set(cam, W9966_STATE_BUFFER);	return 0;}static void w9966_v4l_close(struct video_device *vdev){	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;	// Free read buffer	if (w9966_flag_test(cam, W9966_STATE_BUFFER)) {		kfree(cam->buffer);		w9966_flag_clear(cam, W9966_STATE_BUFFER);	}	// release parport	w9966_pdev_release(cam);}// expects a claimed parportstatic int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg){	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;	switch(cmd)	{	case VIDIOCGCAP:	{		struct video_capability vcap = {			W9966_DRIVERNAME,	// name			VID_TYPE_CAPTURE | VID_TYPE_SCALES,	// type			1, 0,			// vid, aud channels			cam->max_x - cam->min_x,			cam->max_y - cam->min_y,			W9966_WND_MIN_W,			W9966_WND_MIN_H		};		if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0)			return -EFAULT;		return 0;	}	case VIDIOCGCHAN:	{		struct video_channel vch;		if(copy_from_user(&vch, arg, sizeof(vch)) != 0)			return -EFAULT;		if(vch.channel != 0)	// We only support one channel (#0)			return -EINVAL;		strcpy(vch.name, "CCD-input");		vch.flags = 0;		// We have no tuner or audio		vch.tuners = 0;		vch.type = VIDEO_TYPE_CAMERA;		vch.norm = 0;		// ???		if(copy_to_user(arg, &vch, sizeof(vch)) != 0)			return -EFAULT;		return 0;	}	case VIDIOCSCHAN:	{		struct video_channel vch;		if(copy_from_user(&vch, arg, sizeof(vch) ) != 0)			return -EFAULT;		if(vch.channel != 0)			return -EINVAL;		return 0;	}	case VIDIOCGTUNER:	{		struct video_tuner vtune;		if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0)			return -EFAULT;		if(vtune.tuner != 0);			return -EINVAL;		strcpy(vtune.name, "no tuner");		vtune.rangelow = 0;		vtune.rangehigh = 0;		vtune.flags = VIDEO_TUNER_NORM;		vtune.mode = VIDEO_MODE_AUTO;		vtune.signal = 0xffff;		if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0)			return -EFAULT;		return 0;	}	case VIDIOCSTUNER:	{		struct video_tuner vtune;		if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0)			return -EFAULT;		if (vtune.tuner != 0)			return -EINVAL;		if (vtune.mode != VIDEO_MODE_AUTO)			return -EINVAL;		return 0;	}	case VIDIOCGPICT:	{		struct video_picture vpic = {			cam->brightness << 8,	// brightness			(cam->hue + 128) << 8,	// hue			cam->color << 9,	// color			cam->contrast << 9,	// contrast			0x8000,			// whiteness			16, VIDEO_PALETTE_YUV422// bpp, palette format		};		if(copy_to_user(arg, &vpic, sizeof(vpic)) != 0)			return -EFAULT;		return 0;	}	case VIDIOCSPICT:	{		struct video_picture vpic;		if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0)			return -EFAULT;		if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422)			return -EINVAL;		cam->brightness = vpic.brightness >> 8;		cam->hue = (vpic.hue >> 8) - 128;		cam->color = vpic.colour >> 9;		cam->contrast = vpic.contrast >> 9;		if (!cam->image(cam))			return -EFAULT;		return 0;	}	case VIDIOCSWIN:	{		struct video_window vwin;		if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0)			return -EFAULT;		if (		  vwin.flags != 0 ||		  vwin.clipcount != 0)			return -EINVAL;		if (vwin.width  > cam->max_x - cam->min_x ||		    vwin.height > cam->max_y - cam->min_y ||		    vwin.width  < W9966_WND_MIN_W ||		    vwin.height < W9966_WND_MIN_H)			return -EINVAL;		// Update camera regs		if (!w9966_window(cam, 0, 0, 1023, 1023, vwin.width, vwin.height))			return -EFAULT;		return 0;	}	case VIDIOCGWIN:	{		struct video_window vwin;		memset(&vwin, 0, sizeof(vwin));		vwin.width = cam->width;		vwin.height = cam->height;		if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0)			return -EFAULT;		return 0;	}	// Unimplemented	case VIDIOCCAPTURE:	case VIDIOCGFBUF:	case VIDIOCSFBUF:	case VIDIOCKEY:	case VIDIOCGFREQ:	case VIDIOCSFREQ:	case VIDIOCGAUDIO:	case VIDIOCSAUDIO:		return -EINVAL;	default:		return -ENOIOCTLCMD;	}	return 0;}// Capture data// expects a claimed parport and allocated read bufferstatic long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count,  int noblock){	struct w9966_dev *cam = (struct w9966_dev *)vdev->priv;	const u8 addr = 0xa0;	// ECP, read, CCD-transfer, 00000	u8* dest = (u8*)buf;	unsigned long dleft = count;	// Why would anyone want more than this??	if (count > cam->width * cam->height * 2)		count = cam->width * cam->height * 2;	w9966_wreg(cam, 0x00, 0x02);	// Reset ECP-FIFO buffer	w9966_wreg(cam, 0x00, 0x00);	// Return to normal operation	w9966_wreg(cam, 0x01, cam->cmask | 0x80);	// Enable capture	// write special capture-addr and negotiate into data transfer	if (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 ||	    parport_write(cam->pport, &addr, 1) != 1 ||	    parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0) {		DPRINTF("Unable to write capture-addr.\n");		return -EFAULT;	}	while(dleft > 0)	{		const size_t tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;		if (parport_read(cam->pport, cam->buffer, tsize) < tsize)			return -EFAULT;		if (copy_to_user(dest, cam->buffer, tsize) != 0)			return -EFAULT;		dest += tsize;		dleft -= tsize;	}	w9966_wreg(cam, 0x01, cam->cmask);	// Disable capture	return count;}// Called once for every parport on initstatic void w9966_attach(struct parport *port){	int i;	for (i = 0; i < W9966_MAXCAMS; i++) {		if (strcmp(pardev[i], "none") == 0 ||	// Skip if 'none' or if		    w9966_cams[i].dev_state != 0)	// cam already assigned			continue;		if (strcmp(pardev[i], "auto") == 0 ||		    strcmp(pardev[i], port->name) == 0) {			if (!w9966_init(&w9966_cams[i], port, video_nr[i]))				w9966_term(&w9966_cams[i]);			break;	// return		}	}}// Called once for every parport on terminationstatic void w9966_detach(struct parport *port){	int i;	for (i = 0; i < W9966_MAXCAMS; i++)	if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)		w9966_term(&w9966_cams[i]);}static struct parport_driver w9966_ppd = {	W9966_DRIVERNAME,	w9966_attach,	w9966_detach,	NULL};// Module entry pointstatic int __init w9966_mod_init(void){	int i, err;	w9966_cams = kmalloc(		sizeof(struct w9966_dev) * W9966_MAXCAMS, GFP_KERNEL);	if (!w9966_cams)		return -ENOMEM;	for (i = 0; i < W9966_MAXCAMS; i++)		w9966_cams[i].dev_state = 0;	// Register parport driver	if ((err = parport_register_driver(&w9966_ppd)) != 0) {		kfree(w9966_cams);		w9966_cams = 0;		return err;	}	return 0;}// Module cleanupstatic void __exit w9966_mod_term(void){	if (w9966_cams)		kfree(w9966_cams);	parport_unregister_driver(&w9966_ppd);}module_init(w9966_mod_init);module_exit(w9966_mod_term);

⌨️ 快捷键说明

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