saa5249.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 642 行 · 第 1/2 页

C
642
字号
		info.headline = !!(infobits[5] & 4);		info.subtitle = !!(infobits[5] & 8);		info.supp_header = !!(infobits[6] & 1);		info.update = !!(infobits[6] & 2);		info.inter_seq = !!(infobits[6] & 4);		info.dis_disp = !!(infobits[6] & 8);		info.serial = !!(infobits[7] & 1);		info.notfound = !!(infobits[8] & 0x10);		info.pblf = !!(infobits[9] & 0x20);		info.hamming = 0;		for (a = 0; a <= 7; a++) {			if (infobits[a] & 0xf0) {				info.hamming = 1;				break;			}		}		if (t->vdau[req->pgbuf].clrfound)			info.notfound = 1;		if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))			return -EFAULT;		if (!info.hamming && !info.notfound)			t->is_searching[req->pgbuf] = false;		return 0;	}	case VTXIOCGETPAGE:	{		vtx_pagereq_t *req = arg;		int start, end;		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||			req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))			return -EINVAL;		if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))			return -EFAULT;		 /*		  *	Always read the time directly from SAA5249		  */		if (req->start <= 39 && req->end >= 32) {			int len;			char buf[16];			start = max(req->start, 32);			end = min(req->end, 39);			len = end - start + 1;			if (i2c_senddata(t, 8, 0, 0, start, -1) ||				i2c_getdata(t, len, buf))				return -EIO;			if (copy_to_user(req->buffer + start - req->start, buf, len))				return -EFAULT;		}		/* Insert the current header if DAU is still searching for a page */		if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) {			char buf[32];			int len;			start = max(req->start, 7);			end = min(req->end, 31);			len = end - start + 1;			if (i2c_senddata(t, 8, 0, 0, start, -1) ||				i2c_getdata(t, len, buf))				return -EIO;			if (copy_to_user(req->buffer + start - req->start, buf, len))				return -EFAULT;		}		return 0;	}	case VTXIOCSTOPDAU:	{		vtx_pagereq_t *req = arg;		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)			return -EINVAL;		t->vdau[req->pgbuf].stopped = true;		t->is_searching[req->pgbuf] = false;		return 0;	}	case VTXIOCPUTPAGE:	case VTXIOCSETDISP:	case VTXIOCPUTSTAT:		return 0;	case VTXIOCCLRCACHE:	{		if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,			' ', ' ', ' ', ' ', ' ', ' ',			' ', ' ', ' ', ' ', ' ', ' ',			' ', ' ', ' ', ' ', ' ', ' ',			' ', ' ', ' ', ' ', ' ', ' ',			-1))			return -EIO;		if (i2c_senddata(t, 3, 0x20, -1))			return -EIO;		jdelay(10 * CLEAR_DELAY);			/* I have no idea how long we have to wait here */		return 0;	}	case VTXIOCSETVIRT:	{		/* The SAA5249 has virtual-row reception turned on always */		t->virtual_mode = (int)(long)arg;		return 0;	}	}	return -EINVAL;}/* * Translates old vtx IOCTLs to new ones * * This keeps new kernel versions compatible with old userspace programs. */static inline unsigned int vtx_fix_command(unsigned int cmd){	switch (cmd) {	case VTXIOCGETINFO_OLD:		cmd = VTXIOCGETINFO;		break;	case VTXIOCCLRPAGE_OLD:		cmd = VTXIOCCLRPAGE;		break;	case VTXIOCCLRFOUND_OLD:		cmd = VTXIOCCLRFOUND;		break;	case VTXIOCPAGEREQ_OLD:		cmd = VTXIOCPAGEREQ;		break;	case VTXIOCGETSTAT_OLD:		cmd = VTXIOCGETSTAT;		break;	case VTXIOCGETPAGE_OLD:		cmd = VTXIOCGETPAGE;		break;	case VTXIOCSTOPDAU_OLD:		cmd = VTXIOCSTOPDAU;		break;	case VTXIOCPUTPAGE_OLD:		cmd = VTXIOCPUTPAGE;		break;	case VTXIOCSETDISP_OLD:		cmd = VTXIOCSETDISP;		break;	case VTXIOCPUTSTAT_OLD:		cmd = VTXIOCPUTSTAT;		break;	case VTXIOCCLRCACHE_OLD:		cmd = VTXIOCCLRCACHE;		break;	case VTXIOCSETVIRT_OLD:		cmd = VTXIOCSETVIRT;		break;	}	return cmd;}/* *	Handle the locking */static int saa5249_ioctl(struct inode *inode, struct file *file,			 unsigned int cmd, unsigned long arg){	struct saa5249_device *t = video_drvdata(file);	int err;	cmd = vtx_fix_command(cmd);	mutex_lock(&t->lock);	err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);	mutex_unlock(&t->lock);	return err;}static int saa5249_open(struct inode *inode, struct file *file){	struct saa5249_device *t = video_drvdata(file);	int pgbuf;	if (t->client == NULL)		return -ENODEV;	if (test_and_set_bit(0, &t->in_use))		return -EBUSY;	if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */		/* Turn off parity checks (we do this ourselves) */		i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||		/* Display TV-picture, no virtual rows */		i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1))		/* Set display to page 4 */	{		clear_bit(0, &t->in_use);		return -EIO;	}	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));		memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));		memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));		t->vdau[pgbuf].expire = 0;		t->vdau[pgbuf].clrfound = true;		t->vdau[pgbuf].stopped = true;		t->is_searching[pgbuf] = false;	}	t->virtual_mode = false;	return 0;}static int saa5249_release(struct inode *inode, struct file *file){	struct saa5249_device *t = video_drvdata(file);	i2c_senddata(t, 1, 0x20, -1);		/* Turn off CCT */	i2c_senddata(t, 5, 3, 3, -1);		/* Turn off TV-display */	clear_bit(0, &t->in_use);	return 0;}static const struct file_operations saa_fops = {	.owner		= THIS_MODULE,	.open		= saa5249_open,	.release       	= saa5249_release,	.ioctl          = saa5249_ioctl,#ifdef CONFIG_COMPAT	.compat_ioctl	= v4l_compat_ioctl32,#endif	.llseek         = no_llseek,};static struct video_device saa_template ={	.name		= "saa5249",	.fops           = &saa_fops,	.release 	= video_device_release,};/* Addresses to scan */static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };I2C_CLIENT_INSMOD;static int saa5249_probe(struct i2c_client *client,			const struct i2c_device_id *id){	int pgbuf;	int err;	struct video_device *vd;	struct saa5249_device *t;	v4l_info(client, "chip found @ 0x%x (%s)\n",			client->addr << 1, client->adapter->name);	v4l_info(client, "VideoText version %d.%d\n",			VTX_VER_MAJ, VTX_VER_MIN);	t = kzalloc(sizeof(*t), GFP_KERNEL);	if (t == NULL)		return -ENOMEM;	mutex_init(&t->lock);	/* Now create a video4linux device */	vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);	if (vd == NULL) {		kfree(client);		return -ENOMEM;	}	i2c_set_clientdata(client, vd);	memcpy(vd, &saa_template, sizeof(*vd));	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));		memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));		memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));		t->vdau[pgbuf].expire = 0;		t->vdau[pgbuf].clrfound = true;		t->vdau[pgbuf].stopped = true;		t->is_searching[pgbuf] = false;	}	video_set_drvdata(vd, t);	/* Register it */	err = video_register_device(vd, VFL_TYPE_VTX, -1);	if (err < 0) {		kfree(t);		kfree(vd);		return err;	}	t->client = client;	return 0;}static int saa5249_remove(struct i2c_client *client){	struct video_device *vd = i2c_get_clientdata(client);	video_unregister_device(vd);	kfree(video_get_drvdata(vd));	kfree(vd);	return 0;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)static const struct i2c_device_id saa5249_id[] = {	{ "saa5249", 0 },	{ }};MODULE_DEVICE_TABLE(i2c, saa5249_id);#endifstatic struct v4l2_i2c_driver_data v4l2_i2c_data = {	.name = "saa5249",	.driverid = I2C_DRIVERID_SAA5249,	.probe = saa5249_probe,	.remove = saa5249_remove,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)	.id_table = saa5249_id,#endif};

⌨️ 快捷键说明

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