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

📄 i2c-core.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* legacy drivers create and remove clients themselves */		if ((res = driver->detach_client(client))) {			dev_err(&adap->dev, "detach_client failed for client "				"[%s] at address 0x%02x\n", client->name,				client->addr);			goto out_unlock;		}	}	/* clean up the sysfs representation */	init_completion(&adap->dev_released);	device_unregister(&adap->dev);	list_del(&adap->list);	/* wait for sysfs to drop all references */	wait_for_completion(&adap->dev_released);	/* free bus id */	idr_remove(&i2c_adapter_idr, adap->nr);	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); out_unlock:	mutex_unlock(&core_lists);	return res;}EXPORT_SYMBOL(i2c_del_adapter);/* ------------------------------------------------------------------------- *//* * An i2c_driver is used with one or more i2c_client (device) nodes to access * i2c slave chips, on a bus instance associated with some i2c_adapter.  There * are two models for binding the driver to its device:  "new style" drivers * follow the standard Linux driver model and just respond to probe() calls * issued if the driver core sees they match(); "legacy" drivers create device * nodes themselves. */int i2c_register_driver(struct module *owner, struct i2c_driver *driver){	int res;	/* new style driver methods can't mix with legacy ones */	if (is_newstyle_driver(driver)) {		if (driver->attach_adapter || driver->detach_adapter				|| driver->detach_client) {			printk(KERN_WARNING					"i2c-core: driver [%s] is confused\n",					driver->driver.name);			return -EINVAL;		}	}	/* add the driver to the list of i2c drivers in the driver core */	driver->driver.owner = owner;	driver->driver.bus = &i2c_bus_type;	/* for new style drivers, when registration returns the driver core	 * will have called probe() for all matching-but-unbound devices.	 */	res = driver_register(&driver->driver);	if (res)		return res;	mutex_lock(&core_lists);	list_add_tail(&driver->list,&drivers);	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);	/* legacy drivers scan i2c busses directly */	if (driver->attach_adapter) {		struct i2c_adapter *adapter;		list_for_each_entry(adapter, &adapters, list) {			driver->attach_adapter(adapter);		}	}	mutex_unlock(&core_lists);	return 0;}EXPORT_SYMBOL(i2c_register_driver);/** * i2c_del_driver - unregister I2C driver * @driver: the driver being unregistered * Context: can sleep */void i2c_del_driver(struct i2c_driver *driver){	struct list_head   *item1, *item2, *_n;	struct i2c_client  *client;	struct i2c_adapter *adap;	mutex_lock(&core_lists);	/* new-style driver? */	if (is_newstyle_driver(driver))		goto unregister;	/* 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.	 */	list_for_each(item1,&adapters) {		adap = list_entry(item1, struct i2c_adapter, list);		if (driver->detach_adapter) {			if (driver->detach_adapter(adap)) {				dev_err(&adap->dev, "detach_adapter failed "					"for driver [%s]\n",					driver->driver.name);			}		} else {			list_for_each_safe(item2, _n, &adap->clients) {				client = list_entry(item2, struct i2c_client, list);				if (client->driver != driver)					continue;				dev_dbg(&adap->dev, "detaching client [%s] "					"at 0x%02x\n", client->name,					client->addr);				if (driver->detach_client(client)) {					dev_err(&adap->dev, "detach_client "						"failed for client [%s] at "						"0x%02x\n", client->name,						client->addr);				}			}		}	} unregister:	driver_unregister(&driver->driver);	list_del(&driver->list);	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);	mutex_unlock(&core_lists);}EXPORT_SYMBOL(i2c_del_driver);/* ------------------------------------------------------------------------- */static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr){	struct list_head   *item;	struct i2c_client  *client;	list_for_each(item,&adapter->clients) {		client = list_entry(item, struct i2c_client, list);		if (client->addr == addr)			return -EBUSY;	}	return 0;}static int i2c_check_addr(struct i2c_adapter *adapter, int addr){	int rval;	mutex_lock(&adapter->clist_lock);	rval = __i2c_check_addr(adapter, addr);	mutex_unlock(&adapter->clist_lock);	return rval;}int i2c_attach_client(struct i2c_client *client){	struct i2c_adapter *adapter = client->adapter;	int res = 0;	mutex_lock(&adapter->clist_lock);	if (__i2c_check_addr(client->adapter, client->addr)) {		res = -EBUSY;		goto out_unlock;	}	list_add_tail(&client->list,&adapter->clients);	client->usage_count = 0;	client->dev.parent = &client->adapter->dev;	client->dev.bus = &i2c_bus_type;	if (client->driver)		client->dev.driver = &client->driver->driver;	if (client->driver && !is_newstyle_driver(client->driver)) {		client->dev.release = i2c_client_release;		client->dev.uevent_suppress = 1;	} else		client->dev.release = i2c_client_dev_release;	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),		"%d-%04x", i2c_adapter_id(adapter), client->addr);	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",		client->name, client->dev.bus_id);	res = device_register(&client->dev);	if (res)		goto out_list;	mutex_unlock(&adapter->clist_lock);	if (adapter->client_register)  {		if (adapter->client_register(client)) {			dev_dbg(&adapter->dev, "client_register "				"failed for client [%s] at 0x%02x\n",				client->name, client->addr);		}	}	return 0;out_list:	list_del(&client->list);	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "		"(%d)\n", client->name, client->addr, res);out_unlock:	mutex_unlock(&adapter->clist_lock);	return res;}EXPORT_SYMBOL(i2c_attach_client);int i2c_detach_client(struct i2c_client *client){	struct i2c_adapter *adapter = client->adapter;	int res = 0;	if (client->usage_count > 0) {		dev_warn(&client->dev, "Client [%s] still busy, "			 "can't detach\n", client->name);		return -EBUSY;	}	if (adapter->client_unregister)  {		res = adapter->client_unregister(client);		if (res) {			dev_err(&client->dev,				"client_unregister [%s] failed, "				"client not detached\n", client->name);			goto out;		}	}	mutex_lock(&adapter->clist_lock);	list_del(&client->list);	init_completion(&client->released);	device_unregister(&client->dev);	mutex_unlock(&adapter->clist_lock);	wait_for_completion(&client->released); out:	return res;}EXPORT_SYMBOL(i2c_detach_client);static int i2c_inc_use_client(struct i2c_client *client){	if (!try_module_get(client->driver->driver.owner))		return -ENODEV;	if (!try_module_get(client->adapter->owner)) {		module_put(client->driver->driver.owner);		return -ENODEV;	}	return 0;}static void i2c_dec_use_client(struct i2c_client *client){	module_put(client->driver->driver.owner);	module_put(client->adapter->owner);}int i2c_use_client(struct i2c_client *client){	int ret;	ret = i2c_inc_use_client(client);	if (ret)		return ret;	client->usage_count++;	return 0;}EXPORT_SYMBOL(i2c_use_client);int i2c_release_client(struct i2c_client *client){	if (!client->usage_count) {		pr_debug("i2c-core: %s used one too many times\n",			 __FUNCTION__);		return -EPERM;	}	client->usage_count--;	i2c_dec_use_client(client);	return 0;}EXPORT_SYMBOL(i2c_release_client);void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg){	struct list_head  *item;	struct i2c_client *client;	mutex_lock(&adap->clist_lock);	list_for_each(item,&adap->clients) {		client = list_entry(item, struct i2c_client, list);		if (!try_module_get(client->driver->driver.owner))			continue;		if (NULL != client->driver->command) {			mutex_unlock(&adap->clist_lock);			client->driver->command(client,cmd,arg);			mutex_lock(&adap->clist_lock);		}		module_put(client->driver->driver.owner);       }       mutex_unlock(&adap->clist_lock);}EXPORT_SYMBOL(i2c_clients_command);static int __init i2c_init(void){	int retval;	retval = bus_register(&i2c_bus_type);	if (retval)		return retval;	return class_register(&i2c_adapter_class);}static void __exit i2c_exit(void){	class_unregister(&i2c_adapter_class);	bus_unregister(&i2c_bus_type);}subsys_initcall(i2c_init);module_exit(i2c_exit);/* ---------------------------------------------------- * the functional interface to the i2c busses. * ---------------------------------------------------- */int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num){	int ret;	if (adap->algo->master_xfer) {#ifdef DEBUG		for (ret = 0; ret < num; ret++) {			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");		}#endif		mutex_lock_nested(&adap->bus_lock, adap->level);		ret = adap->algo->master_xfer(adap,msgs,num);		mutex_unlock(&adap->bus_lock);		return ret;	} else {		dev_dbg(&adap->dev, "I2C level transfers not supported\n");		return -ENOSYS;	}}EXPORT_SYMBOL(i2c_transfer);int i2c_master_send(struct i2c_client *client,const char *buf ,int count){	int ret;	struct i2c_adapter *adap=client->adapter;	struct i2c_msg msg;	msg.addr = client->addr;	msg.flags = client->flags & I2C_M_TEN;	msg.len = count;	msg.buf = (char *)buf;	ret = i2c_transfer(adap, &msg, 1);	/* If everything went ok (i.e. 1 msg transmitted), return #bytes	   transmitted, else error code. */	return (ret == 1) ? count : ret;}EXPORT_SYMBOL(i2c_master_send);int i2c_master_recv(struct i2c_client *client, char *buf ,int count){	struct i2c_adapter *adap=client->adapter;	struct i2c_msg msg;	int ret;	msg.addr = client->addr;	msg.flags = client->flags & I2C_M_TEN;	msg.flags |= I2C_M_RD;	msg.len = count;	msg.buf = buf;	ret = i2c_transfer(adap, &msg, 1);	/* If everything went ok (i.e. 1 msg transmitted), return #bytes	   transmitted, else error code. */	return (ret == 1) ? count : ret;}EXPORT_SYMBOL(i2c_master_recv);/* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! * ---------------------------------------------------- */static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,			     int (*found_proc) (struct i2c_adapter *, int, int)){	int err;	/* Make sure the address is valid */	if (addr < 0x03 || addr > 0x77) {		dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",			 addr);		return -EINVAL;	}	/* Skip if already in use */	if (i2c_check_addr(adapter, addr))		return 0;	/* Make sure there is something at this address, unless forced */	if (kind < 0) {		if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,				   I2C_SMBUS_QUICK, NULL) < 0)			return 0;		/* prevent 24RF08 corruption */		if ((addr & ~0x0f) == 0x50)			i2c_smbus_xfer(adapter, addr, 0, 0, 0,				       I2C_SMBUS_QUICK, NULL);	}	/* Finally call the custom detection function */	err = found_proc(adapter, addr, kind);	/* -ENODEV can be returned if there is a chip at the given address	   but it isn't supported by this chip driver. We catch it here as	   this isn't an error. */	if (err == -ENODEV)		err = 0;	if (err)		dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",			 addr, err);	return err;}int i2c_probe(struct i2c_adapter *adapter,	      struct i2c_client_address_data *address_data,	      int (*found_proc) (struct i2c_adapter *, int, int)){	int i, err;	int adap_id = i2c_adapter_id(adapter);	/* Force entries are done first, and are not affected by ignore	   entries */	if (address_data->forces) {		unsigned short **forces = address_data->forces;		int kind;		for (kind = 0; forces[kind]; kind++) {			for (i = 0; forces[kind][i] != I2C_CLIENT_END;			     i += 2) {				if (forces[kind][i] == adap_id				 || forces[kind][i] == ANY_I2C_BUS) {					dev_dbg(&adapter->dev, "found force "						"parameter for adapter %d, "						"addr 0x%02x, kind %d\n",						adap_id, forces[kind][i + 1],						kind);					err = i2c_probe_address(adapter,						forces[kind][i + 1],						kind, found_proc);					if (err)						return err;				}			}		}	}	/* Stop here if we can't use SMBUS_QUICK */	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {		if (address_data->probe[0] == I2C_CLIENT_END		 && address_data->normal_i2c[0] == I2C_CLIENT_END)			return 0;		dev_warn(&adapter->dev, "SMBus Quick command not supported, "			 "can't probe for chips\n");		return -1;	}	/* Probe entries are done second, and are not affected by ignore	   entries either */	for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {		if (address_data->probe[i] == adap_id		 || address_data->probe[i] == ANY_I2C_BUS) {			dev_dbg(&adapter->dev, "found probe parameter for "				"adapter %d, addr 0x%02x\n", adap_id,				address_data->probe[i + 1]);			err = i2c_probe_address(adapter,						address_data->probe[i + 1],						-1, found_proc);			if (err)				return err;		}	}

⌨️ 快捷键说明

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