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

📄 i2c-core.c

📁 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östi Mälkki <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> */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/init.h>#include <linux/idr.h>#include <linux/seq_file.h>#include <linux/platform_device.h>#include <linux/mutex.h>#include <linux/completion.h>#include <asm/uaccess.h>#include "i2c-core.h"static LIST_HEAD(adapters);static LIST_HEAD(drivers);static DEFINE_MUTEX(core_lists);static DEFINE_IDR(i2c_adapter_idr);#define is_newstyle_driver(d) ((d)->probe || (d)->remove)/* ------------------------------------------------------------------------- */static int i2c_device_match(struct device *dev, struct device_driver *drv){	struct i2c_client	*client = to_i2c_client(dev);	struct i2c_driver	*driver = to_i2c_driver(drv);	/* make legacy i2c drivers bypass driver model probing entirely;	 * such drivers scan each i2c adapter/bus themselves.	 */	if (!is_newstyle_driver(driver))		return 0;	/* new style drivers use the same kind of driver matching policy	 * as platform devices or SPI:  compare device and driver IDs.	 */	return strcmp(client->driver_name, drv->name) == 0;}#ifdef	CONFIG_HOTPLUG/* uevent helps with hotplug: modprobe -q $(MODALIAS) */static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env){	struct i2c_client	*client = to_i2c_client(dev);	/* by definition, legacy drivers can't hotplug */	if (dev->driver || !client->driver_name)		return 0;	if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))		return -ENOMEM;	dev_dbg(dev, "uevent\n");	return 0;}#else#define i2c_device_uevent	NULL#endif	/* CONFIG_HOTPLUG */static int i2c_device_probe(struct device *dev){	struct i2c_client	*client = to_i2c_client(dev);	struct i2c_driver	*driver = to_i2c_driver(dev->driver);	if (!driver->probe)		return -ENODEV;	client->driver = driver;	dev_dbg(dev, "probe\n");	return driver->probe(client);}static int i2c_device_remove(struct device *dev){	struct i2c_client	*client = to_i2c_client(dev);	struct i2c_driver	*driver;	int			status;	if (!dev->driver)		return 0;	driver = to_i2c_driver(dev->driver);	if (driver->remove) {		dev_dbg(dev, "remove\n");		status = driver->remove(client);	} else {		dev->driver = NULL;		status = 0;	}	if (status == 0)		client->driver = NULL;	return status;}static void i2c_device_shutdown(struct device *dev){	struct i2c_driver *driver;	if (!dev->driver)		return;	driver = to_i2c_driver(dev->driver);	if (driver->shutdown)		driver->shutdown(to_i2c_client(dev));}static int i2c_device_suspend(struct device * dev, pm_message_t mesg){	struct i2c_driver *driver;	if (!dev->driver)		return 0;	driver = to_i2c_driver(dev->driver);	if (!driver->suspend)		return 0;	return driver->suspend(to_i2c_client(dev), mesg);}static int i2c_device_resume(struct device * dev){	struct i2c_driver *driver;	if (!dev->driver)		return 0;	driver = to_i2c_driver(dev->driver);	if (!driver->resume)		return 0;	return driver->resume(to_i2c_client(dev));}static void i2c_client_release(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	complete(&client->released);}static void i2c_client_dev_release(struct device *dev){	kfree(to_i2c_client(dev));}static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf){	struct i2c_client *client = to_i2c_client(dev);	return sprintf(buf, "%s\n", client->name);}static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf){	struct i2c_client *client = to_i2c_client(dev);	return client->driver_name		? sprintf(buf, "%s\n", client->driver_name)		: 0;}static struct device_attribute i2c_dev_attrs[] = {	__ATTR(name, S_IRUGO, show_client_name, NULL),	/* modalias helps coldplug:  modprobe $(cat .../modalias) */	__ATTR(modalias, S_IRUGO, show_modalias, NULL),	{ },};static struct bus_type i2c_bus_type = {	.name		= "i2c",	.dev_attrs	= i2c_dev_attrs,	.match		= i2c_device_match,	.uevent		= i2c_device_uevent,	.probe		= i2c_device_probe,	.remove		= i2c_device_remove,	.shutdown	= i2c_device_shutdown,	.suspend	= i2c_device_suspend,	.resume		= i2c_device_resume,};/** * i2c_new_device - instantiate an i2c device for use with a new style driver * @adap: the adapter managing the device * @info: describes one I2C device; bus_num is ignored * Context: can sleep * * Create a device to work with a new style i2c driver, where binding is * handled through driver model probe()/remove() methods.  This call is not * appropriate for use by mainboad initialization logic, which usually runs * during an arch_initcall() long before any i2c_adapter could exist. * * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. */struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info){	struct i2c_client	*client;	int			status;	client = kzalloc(sizeof *client, GFP_KERNEL);	if (!client)		return NULL;	client->adapter = adap;	client->dev.platform_data = info->platform_data;	device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);	client->flags = info->flags & ~I2C_CLIENT_WAKE;	client->addr = info->addr;	client->irq = info->irq;	strlcpy(client->driver_name, info->driver_name,		sizeof(client->driver_name));	strlcpy(client->name, info->type, sizeof(client->name));	/* a new style driver may be bound to this device when we	 * return from this function, or any later moment (e.g. maybe	 * hotplugging will load the driver module).  and the device	 * refcount model is the standard driver model one.	 */	status = i2c_attach_client(client);	if (status < 0) {		kfree(client);		client = NULL;	}	return client;}EXPORT_SYMBOL_GPL(i2c_new_device);/** * i2c_unregister_device - reverse effect of i2c_new_device() * @client: value returned from i2c_new_device() * Context: can sleep */void i2c_unregister_device(struct i2c_client *client){	struct i2c_adapter	*adapter = client->adapter;	struct i2c_driver	*driver = client->driver;	if (driver && !is_newstyle_driver(driver)) {		dev_err(&client->dev, "can't unregister devices "			"with legacy drivers\n");		WARN_ON(1);		return;	}	mutex_lock(&adapter->clist_lock);	list_del(&client->list);	mutex_unlock(&adapter->clist_lock);	device_unregister(&client->dev);}EXPORT_SYMBOL_GPL(i2c_unregister_device);/* ------------------------------------------------------------------------- *//* I2C bus adapters -- one roots each I2C or SMBUS segment */static void i2c_adapter_dev_release(struct device *dev){	struct i2c_adapter *adap = to_i2c_adapter(dev);	complete(&adap->dev_released);}static ssize_tshow_adapter_name(struct device *dev, struct device_attribute *attr, char *buf){	struct i2c_adapter *adap = to_i2c_adapter(dev);	return sprintf(buf, "%s\n", adap->name);}static struct device_attribute i2c_adapter_attrs[] = {	__ATTR(name, S_IRUGO, show_adapter_name, NULL),	{ },};static struct class i2c_adapter_class = {	.owner			= THIS_MODULE,	.name			= "i2c-adapter",	.dev_attrs		= i2c_adapter_attrs,};static void i2c_scan_static_board_info(struct i2c_adapter *adapter){	struct i2c_devinfo	*devinfo;	mutex_lock(&__i2c_board_lock);	list_for_each_entry(devinfo, &__i2c_board_list, list) {		if (devinfo->busnum == adapter->nr				&& !i2c_new_device(adapter,						&devinfo->board_info))			printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",				i2c_adapter_id(adapter),				devinfo->board_info.addr);	}	mutex_unlock(&__i2c_board_lock);}static int i2c_register_adapter(struct i2c_adapter *adap){	int res = 0;	struct list_head   *item;	struct i2c_driver  *driver;	mutex_init(&adap->bus_lock);	mutex_init(&adap->clist_lock);	INIT_LIST_HEAD(&adap->clients);	mutex_lock(&core_lists);	list_add_tail(&adap->list, &adapters);	/* Add the adapter to the driver core.	 * If the parent pointer is not set up,	 * we add this adapter to the host bus.	 */	if (adap->dev.parent == NULL) {		adap->dev.parent = &platform_bus;		pr_debug("I2C adapter driver [%s] forgot to specify "			 "physical device\n", adap->name);	}	sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);	adap->dev.release = &i2c_adapter_dev_release;	adap->dev.class = &i2c_adapter_class;	res = device_register(&adap->dev);	if (res)		goto out_list;	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);	/* create pre-declared device nodes for new-style drivers */	if (adap->nr < __i2c_first_dynamic_bus_num)		i2c_scan_static_board_info(adap);	/* let legacy drivers scan this bus for matching devices */	list_for_each(item,&drivers) {		driver = list_entry(item, struct i2c_driver, list);		if (driver->attach_adapter)			/* We ignore the return code; if it fails, too bad */			driver->attach_adapter(adap);	}out_unlock:	mutex_unlock(&core_lists);	return res;out_list:	list_del(&adap->list);	idr_remove(&i2c_adapter_idr, adap->nr);	goto out_unlock;}/** * i2c_add_adapter - declare i2c adapter, use dynamic bus number * @adapter: the adapter to add * Context: can sleep * * This routine is used to declare an I2C adapter when its bus number * doesn't matter.  Examples: for I2C adapters dynamically added by * USB links or PCI plugin cards. * * When this returns zero, a new bus number was allocated and stored * in adap->nr, and the specified adapter became available for clients. * Otherwise, a negative errno value is returned. */int i2c_add_adapter(struct i2c_adapter *adapter){	int	id, res = 0;retry:	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)		return -ENOMEM;	mutex_lock(&core_lists);	/* "above" here means "above or equal to", sigh */	res = idr_get_new_above(&i2c_adapter_idr, adapter,				__i2c_first_dynamic_bus_num, &id);	mutex_unlock(&core_lists);	if (res < 0) {		if (res == -EAGAIN)			goto retry;		return res;	}	adapter->nr = id;	return i2c_register_adapter(adapter);}EXPORT_SYMBOL(i2c_add_adapter);/** * i2c_add_numbered_adapter - declare i2c adapter, use static bus number * @adap: the adapter to register (with adap->nr initialized) * Context: can sleep * * This routine is used to declare an I2C adapter when its bus number * matters.  Example: for I2C adapters from system-on-chip CPUs, or * otherwise built in to the system's mainboard, and where i2c_board_info * is used to properly configure I2C devices. * * If no devices have pre-been declared for this bus, then be sure to * register the adapter before any dynamically allocated ones.  Otherwise * the required bus ID may not be available. * * When this returns zero, the specified adapter became available for * clients using the bus number provided in adap->nr.  Also, the table * of I2C devices pre-declared using i2c_register_board_info() is scanned, * and the appropriate driver model device nodes are created.  Otherwise, a * negative errno value is returned. */int i2c_add_numbered_adapter(struct i2c_adapter *adap){	int	id;	int	status;	if (adap->nr & ~MAX_ID_MASK)		return -EINVAL;retry:	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)		return -ENOMEM;	mutex_lock(&core_lists);	/* "above" here means "above or equal to", sigh;	 * we need the "equal to" result to force the result	 */	status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);	if (status == 0 && id != adap->nr) {		status = -EBUSY;		idr_remove(&i2c_adapter_idr, id);	}	mutex_unlock(&core_lists);	if (status == -EAGAIN)		goto retry;	if (status == 0)		status = i2c_register_adapter(adap);	return status;}EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);/** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered * Context: can sleep * * This unregisters an I2C adapter which was previously registered * by @i2c_add_adapter or @i2c_add_numbered_adapter. */int i2c_del_adapter(struct i2c_adapter *adap){	struct list_head  *item, *_n;	struct i2c_adapter *adap_from_list;	struct i2c_driver *driver;	struct i2c_client *client;	int res = 0;	mutex_lock(&core_lists);	/* First make sure that this adapter was ever added */	list_for_each_entry(adap_from_list, &adapters, list) {		if (adap_from_list == adap)			break;	}	if (adap_from_list != adap) {		pr_debug("i2c-core: attempting to delete unregistered "			 "adapter [%s]\n", adap->name);		res = -EINVAL;		goto out_unlock;	}	list_for_each(item,&drivers) {		driver = list_entry(item, struct i2c_driver, list);		if (driver->detach_adapter)			if ((res = driver->detach_adapter(adap))) {				dev_err(&adap->dev, "detach_adapter failed "					"for driver [%s]\n",					driver->driver.name);				goto out_unlock;			}	}	/* detach any active clients. This must be done first, because	 * it can fail; in which case we give up. */	list_for_each_safe(item, _n, &adap->clients) {		struct i2c_driver	*driver;		client = list_entry(item, struct i2c_client, list);		driver = client->driver;		/* new style, follow standard driver model */		if (!driver || is_newstyle_driver(driver)) {			i2c_unregister_device(client);			continue;		}

⌨️ 快捷键说明

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