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

📄 i2c-core.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
		module_put(client->driver->owner);		return -ENODEV;	}	return 0;}static void i2c_dec_use_client(struct i2c_client *client){	module_put(client->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;	if (client->flags & I2C_CLIENT_ALLOW_USE) {		if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE)			client->usage_count++;		else if (client->usage_count > 0) 			goto busy;		else 			client->usage_count++;	}	return 0; busy:	i2c_dec_use_client(client);	return -EBUSY;}int i2c_release_client(struct i2c_client *client){	if(client->flags & I2C_CLIENT_ALLOW_USE) {		if(client->usage_count>0)			client->usage_count--;		else {			pr_debug("i2c-core: %s used one too many times\n",				__FUNCTION__);			return -EPERM;		}	}		i2c_dec_use_client(client);		return 0;}void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg){	struct list_head  *item;	struct i2c_client *client;	down(&adap->clist_lock);	list_for_each(item,&adap->clients) {		client = list_entry(item, struct i2c_client, list);		if (!try_module_get(client->driver->owner))			continue;		if (NULL != client->driver->command) {			up(&adap->clist_lock);			client->driver->command(client,cmd,arg);			down(&adap->clist_lock);		}		module_put(client->driver->owner);       }       up(&adap->clist_lock);}/* match always succeeds, as we want the probe() to tell if we really accept this match */static int i2c_device_match(struct device *dev, struct device_driver *drv){	return 1;}struct bus_type i2c_bus_type = {	.name =		"i2c",	.match =	i2c_device_match,};static int __init i2c_init(void){	int retval;	retval = bus_register(&i2c_bus_type);	if (retval)		return retval;	retval = driver_register(&i2c_adapter_driver);	if (retval)		return retval;	return class_register(&i2c_adapter_class);}static void __exit i2c_exit(void){	class_unregister(&i2c_adapter_class);	driver_unregister(&i2c_adapter_driver);	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) { 	 	dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num);		down(&adap->bus_lock);		ret = adap->algo->master_xfer(adap,msgs,num);		up(&adap->bus_lock);		return ret;	} else {		dev_dbg(&adap->dev, "I2C level transfers not supported\n");		return -ENOSYS;	}}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;	if (client->adapter->algo->master_xfer) {		msg.addr   = client->addr;		msg.flags = client->flags & I2C_M_TEN;		msg.len = count;		msg.buf = (char *)buf;			dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",			count);			down(&adap->bus_lock);		ret = adap->algo->master_xfer(adap,&msg,1);		up(&adap->bus_lock);		/* if everything went ok (i.e. 1 msg transmitted), return #bytes		 * transmitted, else error code.		 */		return (ret == 1 )? count : ret;	} else {		dev_err(&client->adapter->dev, "I2C level transfers not supported\n");		return -ENOSYS;	}}int i2c_master_recv(struct i2c_client *client, char *buf ,int count){	struct i2c_adapter *adap=client->adapter;	struct i2c_msg msg;	int ret;	if (client->adapter->algo->master_xfer) {		msg.addr   = client->addr;		msg.flags = client->flags & I2C_M_TEN;		msg.flags |= I2C_M_RD;		msg.len = count;		msg.buf = buf;		dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",			count);			down(&adap->bus_lock);		ret = adap->algo->master_xfer(adap,&msg,1);		up(&adap->bus_lock);			dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n",			ret, count, client->addr);			/* if everything went ok (i.e. 1 msg transmitted), return #bytes	 	* transmitted, else error code.	 	*/		return (ret == 1 )? count : ret;	} else {		dev_err(&client->adapter->dev, "I2C level transfers not supported\n");		return -ENOSYS;	}}int i2c_control(struct i2c_client *client,	unsigned int cmd, unsigned long arg){	int ret = 0;	struct i2c_adapter *adap = client->adapter;	dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);	switch (cmd) {		case I2C_RETRIES:			adap->retries = arg;			break;		case I2C_TIMEOUT:			adap->timeout = arg;			break;		default:			if (adap->algo->algo_control!=NULL)				ret = adap->algo->algo_control(adap,cmd,arg);	}	return ret;}/* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! * ---------------------------------------------------- */int i2c_probe(struct i2c_adapter *adapter,	      struct i2c_client_address_data *address_data,	      int (*found_proc) (struct i2c_adapter *, int, int)){	int addr,i,found,err;	int adap_id = i2c_adapter_id(adapter);	/* Forget it if we can't probe using SMBUS_QUICK */	if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))		return -1;	for (addr = 0x00; addr <= 0x7f; addr++) {		/* Skip if already in use */		if (i2c_check_addr(adapter,addr))			continue;		/* If it is in one of the force entries, we don't do any detection		   at all */		found = 0;		for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) {			if (((adap_id == address_data->force[i]) || 			     (address_data->force[i] == ANY_I2C_BUS)) &&			     (addr == address_data->force[i+1])) {				dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n",					adap_id, addr);				if ((err = found_proc(adapter,addr,0)))					return err;				found = 1;			}		}		if (found) 			continue;		/* If this address is in one of the ignores, we can forget about		   it right now */		for (i = 0;		     !found && (address_data->ignore[i] != I2C_CLIENT_END);		     i += 2) {			if (((adap_id == address_data->ignore[i]) || 			    ((address_data->ignore[i] == ANY_I2C_BUS))) &&			    (addr == address_data->ignore[i+1])) {				dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, "					"addr %04x\n", adap_id ,addr);				found = 1;			}		}		for (i = 0;		     !found && (address_data->ignore_range[i] != I2C_CLIENT_END);		     i += 3) {			if (((adap_id == address_data->ignore_range[i]) ||			    ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&			    (addr >= address_data->ignore_range[i+1]) &&			    (addr <= address_data->ignore_range[i+2])) {				dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, "					"addr %04x\n", adap_id,addr);				found = 1;			}		}		if (found) 			continue;		/* Now, we will do a detection, but only if it is in the normal or 		   probe entries */  		for (i = 0;		     !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);		     i += 1) {			if (addr == address_data->normal_i2c[i]) {				found = 1;				dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, "					"addr %02x", adap_id,addr);			}		}		for (i = 0;		     !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);		     i += 2) {			if ((addr >= address_data->normal_i2c_range[i]) &&			    (addr <= address_data->normal_i2c_range[i+1])) {				found = 1;				dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, "					"addr %04x\n", adap_id,addr);			}		}		for (i = 0;		     !found && (address_data->probe[i] != I2C_CLIENT_END);		     i += 2) {			if (((adap_id == address_data->probe[i]) ||			    ((address_data->probe[i] == ANY_I2C_BUS))) &&			    (addr == address_data->probe[i+1])) {				found = 1;				dev_dbg(&adapter->dev, "found probe parameter for adapter %d, "					"addr %04x\n", adap_id,addr);			}		}		for (i = 0;		     !found && (address_data->probe_range[i] != I2C_CLIENT_END);		     i += 3) {			if (((adap_id == address_data->probe_range[i]) ||			   (address_data->probe_range[i] == ANY_I2C_BUS)) &&			   (addr >= address_data->probe_range[i+1]) &&			   (addr <= address_data->probe_range[i+2])) {				found = 1;				dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, "					"addr %04x\n", adap_id,addr);			}		}		if (!found) 			continue;		/* OK, so we really should examine this address. First check		   whether there is some client here at all! */		if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)			if ((err = found_proc(adapter,addr,-1)))				return err;	}	return 0;}/* * return id number for a specific adapter */int i2c_adapter_id(struct i2c_adapter *adap){	return adap->nr;}struct i2c_adapter* i2c_get_adapter(int id){	struct list_head   *item;	struct i2c_adapter *adapter;		down(&core_lists);	list_for_each(item,&adapters) {		adapter = list_entry(item, struct i2c_adapter, list);		if (id == adapter->nr &&		    try_module_get(adapter->owner)) {			up(&core_lists);			return adapter;		}	}	up(&core_lists);	return NULL;}void i2c_put_adapter(struct i2c_adapter *adap){	module_put(adap->owner);}/* The SMBus parts */#define POLY    (0x1070U << 3) static u8crc8(u16 data){	int i;  	for(i = 0; i < 8; i++) {		if (data & 0x8000) 			data = data ^ POLY;		data = data << 1;	}	return (u8)(data >> 8);}/* CRC over count bytes in the first array plus the bytes in the rest   array if it is non-null. rest[0] is the (length of rest) - 1   and is included. */u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest){	int i;	for(i = 0; i < count; i++)		crc = crc8((crc ^ first[i]) << 8);	if(rest != NULL)		for(i = 0; i <= rest[0]; i++)			crc = crc8((crc ^ rest[i]) << 8);	return crc;}u8 i2c_smbus_pec(int count, u8 *first, u8 *rest){	return i2c_smbus_partial_pec(0, count, first, rest);}/* Returns new "size" (transaction type)   Note that we convert byte to byte_data and byte_data to word_data   rather than invent new xxx_PEC transactions. */int i2c_smbus_add_pec(u16 addr, u8 command, int size,                      union i2c_smbus_data *data){	u8 buf[3];	buf[0] = addr << 1;	buf[1] = command;	switch(size) {		case I2C_SMBUS_BYTE:			data->byte = i2c_smbus_pec(2, buf, NULL);			size = I2C_SMBUS_BYTE_DATA;			break;		case I2C_SMBUS_BYTE_DATA:			buf[2] = data->byte;			data->word = buf[2] ||			            (i2c_smbus_pec(3, buf, NULL) << 8);			size = I2C_SMBUS_WORD_DATA;			break;		case I2C_SMBUS_WORD_DATA:			/* unsupported */			break;		case I2C_SMBUS_BLOCK_DATA:			data->block[data->block[0] + 1] =			             i2c_smbus_pec(2, buf, data->block);			size = I2C_SMBUS_BLOCK_DATA_PEC;			break;	}	return size;	}

⌨️ 快捷键说明

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