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

📄 i2c-core.c

📁 I2C总线LINUX驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* i2c-core.c - a device driver for the iic-bus interface		     *//* ------------------------------------------------------------------------- *//*   Copyright (C) 1995-99 Simon G. Vogl    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., 675 Mass Ave, Cambridge, MA 02139, USA.		     *//* ------------------------------------------------------------------------- *//* With some changes from Ky鰏ti M鋖kki <kmalkki@cc.hut.fi>.   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>   SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and   Jean Delvare <khali@linux-fr.org> *//* $Id: i2c-core.c,v 1.115 2005/11/05 21:00:58 khali Exp $ */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/init.h>#include "i2c.h"#include <asm/uaccess.h>/* ----- global defines ---------------------------------------------------- */#if I2C_LINUX_2_4_BINARY_COMPATIBILITY#define I2C_LOCK_LIST(adap) down(&adap->bus)#define I2C_UNLOCK_LIST(adap) up(&adap->bus)#else#define I2C_LOCK_LIST(adap) down(&adap->list)#define I2C_UNLOCK_LIST(adap) up(&adap->list)#endif#define DEB(x) if (i2c_debug>=1) x;#define DEB2(x) if (i2c_debug>=2) x;/* ----- global variables -------------------------------------------------- */DECLARE_MUTEX(core_lists);static struct i2c_adapter *adapters[I2C_ADAP_MAX];static struct i2c_driver *drivers[I2C_DRIVER_MAX];/**** debug level */static int i2c_debug;/* --------------------------------------------------- * /proc entry declarations *---------------------------------------------------- */#ifdef CONFIG_PROC_FSstatic ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,                                 loff_t *ppos);static int read_bus_i2c(char *buf, char **start, off_t offset, int len,                           int *eof , void *private);/* To implement the dynamic /proc/bus/i2c-? files, we need our own    implementation of the read hook */static struct file_operations i2cproc_operations = {	.read		= i2cproc_bus_read,};static int i2cproc_register(struct i2c_adapter *adap, int bus);static void i2cproc_remove(int bus);#endif /* CONFIG_PROC_FS *//* --------------------------------------------------- * registering functions  * ---------------------------------------------------  *//* ----- * i2c_add_adapter is called from within the algorithm layer, * when a new hw adapter registers. A new device is register to be * available for clients. */int i2c_add_adapter(struct i2c_adapter *adap){	int i,j,res = 0;	down(&core_lists);	for (i = 0; i < I2C_ADAP_MAX; i++)		if (NULL == adapters[i])			break;	if (I2C_ADAP_MAX == i) {		printk(KERN_WARNING 		       " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n",			adap->name);		res = -ENOMEM;		goto ERROR0;	}	#ifdef CONFIG_PROC_FS	res = i2cproc_register(adap, i);	if (res<0)	    goto ERROR0;#endif /* def CONFIG_PROC_FS */	adapters[i] = adap;		/* init data types */	init_MUTEX(&adap->bus);#if !I2C_LINUX_2_4_BINARY_COMPATIBILITY	init_MUTEX(&adap->list);#endif	/* inform drivers of new adapters */	for (j=0;j<I2C_DRIVER_MAX;j++)		if (drivers[j]!=NULL && 		    (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY)))			/* We ignore the return code; if it fails, too bad */			drivers[j]->attach_adapter(adap);		DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n",	           adap->name,i));ERROR0:	up(&core_lists);	return res;}int i2c_del_adapter(struct i2c_adapter *adap){	int i,j,res = 0;	down(&core_lists);	for (i = 0; i < I2C_ADAP_MAX; i++)		if (adap == adapters[i])			break;	if (I2C_ADAP_MAX == i) {		printk(KERN_WARNING "i2c-core.o: unregister_adapter adap [%s] not found.\n",			adap->name);		res = -ENODEV;		goto ERROR0;	}	/* DUMMY drivers do not register their clients, so we have to	 * use a trick here: we call driver->attach_adapter to	 * *detach* it! Of course, each dummy driver should know about	 * this or hell will break loose...	 */	for (j = 0; j < I2C_DRIVER_MAX; j++) 		if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))			if ((res = drivers[j]->attach_adapter(adap))) {				printk(KERN_WARNING "i2c-core.o: can't detach adapter %s "				       "while detaching driver %s: driver not "				       "detached!\n", adap->name, drivers[j]->name);				goto ERROR0;			}	/* detach any active clients. This must be done first, because	 * it can fail; in which case we give up. */	for (j=0;j<I2C_CLIENT_MAX;j++) {		struct i2c_client *client = adap->clients[j];		if (client!=NULL)		    /* detaching devices is unconditional of the set notify		     * flag, as _all_ clients that reside on the adapter		     * must be deleted, as this would cause invalid states.		     */			if ((res=client->driver->detach_client(client))) {				printk(KERN_ERR "i2c-core.o: adapter %s not "					"unregistered, because client at "					"address %02x can't be detached\n",					adap->name, client->addr);				goto ERROR0;			}	}#ifdef CONFIG_PROC_FS	i2cproc_remove(i);#endif /* def CONFIG_PROC_FS */	adapters[i] = NULL;	DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name));ERROR0:	up(&core_lists);	return res;}/* ----- * What follows is the "upwards" interface: commands for talking to clients, * which implement the functions to access the physical information of the * chips. */int i2c_add_driver(struct i2c_driver *driver){	int i;	down(&core_lists);	for (i = 0; i < I2C_DRIVER_MAX; i++)		if (NULL == drivers[i])			break;	if (I2C_DRIVER_MAX == i) {		printk(KERN_WARNING 		       " i2c-core.o: register_driver(%s) "		       "- enlarge I2C_DRIVER_MAX.\n",			driver->name);		up(&core_lists);		return -ENOMEM;	}	drivers[i] = driver;	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));		/* now look for instances of driver on our adapters	 */	if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) {		for (i=0;i<I2C_ADAP_MAX;i++)			if (adapters[i]!=NULL)				/* Ignore errors */				driver->attach_adapter(adapters[i]);	}	up(&core_lists);	return 0;}int i2c_del_driver(struct i2c_driver *driver){	int i,j,k,res = 0;	down(&core_lists);	for (i = 0; i < I2C_DRIVER_MAX; i++)		if (driver == drivers[i])			break;	if (I2C_DRIVER_MAX == i) {		printk(KERN_WARNING " i2c-core.o: unregister_driver: "				    "[%s] not found\n",			driver->name);		up(&core_lists);		return -ENODEV;	}	/* Have a look at each adapter, if clients of this driver are still	 * attached. If so, detach them to be able to kill the driver 	 * afterwards.	 */	DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n"));	/* removing clients does not depend on the notify flag, else 	 * invalid operation might (will!) result, when using stale client	 * pointers.	 */	for (k=0;k<I2C_ADAP_MAX;k++) {		struct i2c_adapter *adap = adapters[k];		if (adap == NULL) /* skip empty entries. */			continue;		DEB2(printk(KERN_DEBUG "i2c-core.o: examining adapter %s:\n",			    adap->name));		if (driver->flags & I2C_DF_DUMMY) {		/* DUMMY drivers do not register their clients, so we have to		 * use a trick here: we call driver->attach_adapter to		 * *detach* it! Of course, each dummy driver should know about		 * this or hell will break loose...  		 */			if ((res = driver->attach_adapter(adap))) {				printk(KERN_WARNING "i2c-core.o: while unregistering "				       "dummy driver %s, adapter %s could "				       "not be detached properly; driver "				       "not unloaded!\n", driver->name,				       adap->name);				goto ERROR0;			}		} else {			for (j=0;j<I2C_CLIENT_MAX;j++) { 				struct i2c_client *client = adap->clients[j];				if (client != NULL && 				    client->driver == driver) {					DEB2(printk(KERN_DEBUG "i2c-core.o: "						    "detaching client %s:\n",					            client->name));					if ((res = driver->							detach_client(client)))					{						printk(KERN_ERR "i2c-core.o: while "						       "unregistering driver "						       "`%s', the client at "						       "address %02x of "						       "adapter `%s' could not "						       "be detached; driver "						       "not unloaded!\n",						       driver->name,						       client->addr,						       adap->name);						goto ERROR0;					}				}			}		}	}	drivers[i] = NULL;	DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));ERROR0:	up(&core_lists);	return res;}static int __i2c_check_addr (struct i2c_adapter *adapter, int addr){	int i;	for (i = 0; i < I2C_CLIENT_MAX ; i++) 		if (adapter->clients[i] && (adapter->clients[i]->addr == addr))			return -EBUSY;	return 0;}int i2c_check_addr (struct i2c_adapter *adapter, int addr){	int rval;	I2C_LOCK_LIST(adapter);	rval = __i2c_check_addr(adapter, addr);	I2C_UNLOCK_LIST(adapter);	return rval;}int i2c_attach_client(struct i2c_client *client){	struct i2c_adapter *adapter = client->adapter;	int i;	if (i2c_check_addr(client->adapter,client->addr))		return -EBUSY;	I2C_LOCK_LIST(adapter);	for (i = 0; i < I2C_CLIENT_MAX; i++)		if (NULL == adapter->clients[i])			break;	if (I2C_CLIENT_MAX == i) {		printk(KERN_WARNING 		       " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",			client->name);		I2C_UNLOCK_LIST(adapter);		return -ENOMEM;	}	adapter->clients[i] = client;	I2C_UNLOCK_LIST(adapter);		if (adapter->client_register) 		if (adapter->client_register(client)) 			printk(KERN_DEBUG "i2c-core.o: warning: client_register seems "			       "to have failed for client %02x at adapter %s\n",			       client->addr,adapter->name);	DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n",		client->name, adapter->name,i));	if(client->flags & I2C_CLIENT_ALLOW_USE)		client->usage_count = 0;		return 0;}int i2c_detach_client(struct i2c_client *client){	struct i2c_adapter *adapter = client->adapter;	int i,res;	if( (client->flags & I2C_CLIENT_ALLOW_USE) && 	    (client->usage_count>0))		return -EBUSY;		if (adapter->client_unregister != NULL) 		if ((res = adapter->client_unregister(client))) {			printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, "			       "client not detached\n", client->name);			return res;		}	I2C_LOCK_LIST(adapter);	for (i = 0; i < I2C_CLIENT_MAX; i++)		if (client == adapter->clients[i])			break;	if (I2C_CLIENT_MAX == i) {		printk(KERN_WARNING " i2c-core.o: unregister_client "				    "[%s] not found\n",			client->name);		I2C_UNLOCK_LIST(adapter);		return -ENODEV;	}	adapter->clients[i] = NULL;	I2C_UNLOCK_LIST(adapter);	DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name));	return 0;}static void i2c_inc_use_client(struct i2c_client *client){	if (client->driver->inc_use != NULL)		client->driver->inc_use(client);	if (client->adapter->inc_use != NULL)		client->adapter->inc_use(client->adapter);}static void i2c_dec_use_client(struct i2c_client *client){	if (client->driver->dec_use != NULL)		client->driver->dec_use(client);	if (client->adapter->dec_use != NULL)		client->adapter->dec_use(client->adapter);}struct i2c_client *i2c_get_client(int driver_id, int adapter_id, 					struct i2c_client *prev){	int i,j;		/* Will iterate through the list of clients in each adapter of adapters-list	   in search for a client that matches the search criteria. driver_id or 	   adapter_id are ignored if set to 0. If both are ignored this returns 	   first client found. */		i = j = 0;  		/* set starting point */ 	if(prev)	{		if(!(prev->adapter))			return (struct i2c_client *) -EINVAL;				for(j=0; j < I2C_ADAP_MAX; j++)			if(prev->adapter == adapters[j])				break;				/* invalid starting point? */		if (I2C_ADAP_MAX == j) {			printk(KERN_WARNING " i2c-core.o: get_client adapter for client:[%s] not found\n",				prev->name);			return (struct i2c_client *) -ENODEV;		}					for(i=0; i < I2C_CLIENT_MAX; i++)			if(prev == adapters[j]->clients[i])				break;				/* invalid starting point? */		if (I2C_CLIENT_MAX == i) {			printk(KERN_WARNING " i2c-core.o: get_client client:[%s] not found\n",				prev->name);			return (struct i2c_client *) -ENODEV;		}					i++; /* start from one after prev */	}		for(; j < I2C_ADAP_MAX; j++)	{		if(!adapters[j])			continue;					if(adapter_id && (adapters[j]->id != adapter_id))			continue;				for(; i < I2C_CLIENT_MAX; i++)		{			if(!adapters[j]->clients[i])				continue;							if(driver_id && (adapters[j]->clients[i]->driver->id != driver_id))				continue;			if(adapters[j]->clients[i]->flags & I2C_CLIENT_ALLOW_USE)					return adapters[j]->clients[i];		}		i = 0;	}	return 0;}int i2c_use_client(struct i2c_client *client)

⌨️ 快捷键说明

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