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

📄 saa5249.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Cleaned up to use existing videodev interface and allow the idea *	of multiple teletext decoders on the video4linux iface. Changed i2c *	to cover addressing clashes on device busses. It's also rebuilt so *	you can add arbitary multiple teletext devices to Linux video4linux *	now (well 32 anyway). * *	Alan Cox <Alan.Cox@linux.org> * *	The original driver was heavily modified to match the i2c interface *	It was truncated to use the WinTV boards, too. * *	Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de> * * $Id: saa5249.c,v 1.1 1998/03/30 22:23:23 alan Exp $ * *	Derived From * * vtx.c: * This is a loadable character-device-driver for videotext-interfaces * (aka teletext). Please check the Makefile/README for a list of supported * interfaces. * * Copyright (c) 1994-97 Martin Buck  <martin-2.buck@student.uni-ulm.de> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <asm/io.h>#include <asm/uaccess.h>#include <stdarg.h>#include <linux/i2c.h>#include <linux/videotext.h>#include <linux/videodev.h>#define VTX_VER_MAJ 1#define VTX_VER_MIN 7#define NUM_DAUS 4#define NUM_BUFS 8#define IF_NAME "SAA5249"static const int disp_modes[8][3] = {	{ 0x46, 0x03, 0x03 },	/* DISPOFF */	{ 0x46, 0xcc, 0xcc },	/* DISPNORM */	{ 0x44, 0x0f, 0x0f },	/* DISPTRANS */	{ 0x46, 0xcc, 0x46 },	/* DISPINS */	{ 0x44, 0x03, 0x03 },	/* DISPOFF, interlaced */	{ 0x44, 0xcc, 0xcc },	/* DISPNORM, interlaced */	{ 0x44, 0x0f, 0x0f },	/* DISPTRANS, interlaced */	{ 0x44, 0xcc, 0x46 }	/* DISPINS, interlaced */};#define PAGE_WAIT 30				/* Time in jiffies between requesting page and */						/* checking status bits */#define PGBUF_EXPIRE 1500			/* Time in jiffies to wait before retransmitting */						/* page regardless of infobits */typedef struct {	u8 pgbuf[VTX_VIRTUALSIZE];		/* Page-buffer */	u8 laststat[10];			/* Last value of infobits for DAU */	u8 sregs[7];				/* Page-request registers */	unsigned long expire;			/* Time when page will be expired */	unsigned clrfound : 1;			/* VTXIOCCLRFOUND has been called */	unsigned stopped : 1;			/* VTXIOCSTOPDAU has been called */} vdau_t;struct saa5249_device{	vdau_t vdau[NUM_DAUS];			/* Data for virtual DAUs (the 5249 only has one */						/* real DAU, so we have to simulate some more) */	int vtx_use_count;	int is_searching[NUM_DAUS];	int disp_mode;	int virtual_mode;	struct i2c_bus *bus;};#define CCTWR 34		/* I睠 write/read-address of vtx-chip */#define CCTRD 35#define NOACK_REPEAT 10		/* Retry access this many times on failure */#define CLEAR_DELAY 5		/* Time in jiffies required to clear a page */#define I2C_TIMEOUT 300		/* open/close/SDA-check timeout in jiffies */#define READY_TIMEOUT 3		/* Time in jiffies to wait for ready signal of I睠-bus interface */#define INIT_DELAY 500		/* Time in usec to wait at initialization of CEA interface */#define START_DELAY 10		/* Time in usec to wait before starting write-cycle (CEA) */#define VTX_DEV_MINOR 0/* General defines and debugging support */#ifndef FALSE#define FALSE 0#define TRUE 1#endif#ifndef MIN#define MIN(a, b) ((a) < (b) ? (a) : (b))#define MAX(a, b) ((a) > (b) ? (a) : (b))#endif#define RESCHED \        do { \          if (current->need_resched) \            schedule(); \        } while (0)static struct video_device saa_template;	/* Declared near bottom *//* *	We do most of the hard work when we become a device on the i2c. */ static int saa5249_attach(struct i2c_device *device){	int pgbuf;	int err;	struct video_device *vd;	struct saa5249_device *t;	/* Only attach these chips to the BT848 bus for now */		if(device->bus->id!=I2C_BUSID_BT848)		return -EINVAL;		strcpy(device->name, IF_NAME);		/*	 *	Now create a video4linux device	 */	 	vd=(struct video_device *)kmalloc(sizeof(struct video_device), GFP_KERNEL);	if(vd==NULL)		return -ENOMEM;		memcpy(vd, &saa_template, sizeof(*vd));		/*	 *	Attach an saa5249 device	 */		t=(struct saa5249_device *)kmalloc(sizeof(struct saa5249_device), GFP_KERNEL);	if(t==NULL)	{		kfree(vd);		return -ENOMEM;	}		memset(t, 0, sizeof(*t));		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;	}	vd->priv=t;		 	device->data=vd;		/*	 *	Register it	 */	if((err=video_register_device(vd, VFL_TYPE_VTX))<0)	{		kfree(t);		kfree(vd);		return err;	}	t->bus = device->bus;	return 0;}static int saa5249_detach(struct i2c_device *device){	struct video_device *vd=device->data;	video_unregister_device(vd);	kfree(vd->priv);	kfree(vd);	return 0;}static int saa5249_command(struct i2c_device *device,			     unsigned int cmd, void *arg){	return -EINVAL;}/* new I2C driver support */static struct i2c_driver i2c_driver_videotext = {	IF_NAME,		/* name */	I2C_DRIVERID_VIDEOTEXT, /* in i2c.h */	34, 35,			/* Addr range */	saa5249_attach,	saa5249_detach,	saa5249_command};/* *	Wait the given number of jiffies (10ms). This calls the scheduler, so the actual *	delay may be longer. */static void jdelay(unsigned long delay) {	sigset_t oldblocked = current->blocked;	spin_lock_irq(&current->sigmask_lock);	sigfillset(&current->blocked);	recalc_sigpending(current);	spin_unlock_irq(&current->sigmask_lock);	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(delay);	spin_lock_irq(&current->sigmask_lock);	current->blocked = oldblocked;	recalc_sigpending(current);	spin_unlock_irq(&current->sigmask_lock);}/* Send arbitrary number of bytes to I睠-bus. Start & stop handshaking is done by this routine. * adr should be address of I睠-device, varargs-list of values to send must be terminated by -1 * Returns -1 if I睠-device didn't send acknowledge, 0 otherwise */static int i2c_senddata(struct saa5249_device *t, int adr, ...) {	int val, loop;	va_list argp;	for (loop = 0; loop <= NOACK_REPEAT; loop++) 	{		i2c_start(t->bus);		if (i2c_sendbyte(t->bus, adr, 0) != 0)			goto loopend;		va_start(argp, adr);		while ((val = va_arg(argp, int)) != -1) 		{			if (val < 0 || val > 255) 			{				printk(KERN_ERR "vtx: internal error in i2c_senddata\n");				break;			}			if (i2c_sendbyte(t->bus, val, 0) != 0)				goto loopend;		}		va_end(argp);		i2c_stop(t->bus);		return 0;loopend:		i2c_stop(t->bus);	}	va_end(argp);	return -1;}/* Send count number of bytes from buffer buf to I睠-device adr. Start & stop handshaking is * done by this routine. If uaccess is TRUE, data is read from user-space with get_user. * Returns -1 if I睠-device didn't send acknowledge, 0 otherwise */static int i2c_sendbuf(struct saa5249_device *t, int adr, int reg, int count, u8 *buf, int uaccess) {	int pos, loop;	u8 val;	for (loop = 0; loop <= NOACK_REPEAT; loop++) 	{		i2c_start(t->bus);		if (i2c_sendbyte(t->bus, adr, 0) != 0 || i2c_sendbyte(t->bus, reg, 0) != 0)			goto loopend;		for (pos = 0; pos < count; pos++) 		{			/* FIXME: FAULT WITH CLI/SPINLOCK ?? */			if (uaccess)				get_user(val, buf + pos);			else				val = buf[pos];			if (i2c_sendbyte(t->bus, val, 0) != 0)				goto loopend;			RESCHED;		}		i2c_stop(t->bus);		return 0;loopend:		i2c_stop(t->bus);	}	return -1;}/* Get count number of bytes from I睠-device at address adr, store them in buf. Start & stop * handshaking is done by this routine, ack will be sent after the last byte to inhibit further * sending of data. If uaccess is TRUE, data is written to user-space with put_user. * Returns -1 if I睠-device didn't send acknowledge, 0 otherwise */static int i2c_getdata(struct saa5249_device *t, int adr, int count, u8 *buf, int uaccess) {	int pos, loop, val;	for (loop = 0; loop <= NOACK_REPEAT; loop++) 	{		i2c_start(t->bus);		if (i2c_sendbyte(t->bus, adr, 1) != 0)			goto loopend;		for (pos = 0; pos < count; pos++) 		{			val = i2c_readbyte(t->bus, (pos==count-1) ? 1 : 0);			if (uaccess) 				put_user(val, buf + pos);			else				buf[pos] = val;			RESCHED;		}		i2c_stop(t->bus);		return 0;loopend:		i2c_stop(t->bus);	}	return -1;}

⌨️ 快捷键说明

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