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

📄 iic.c

📁 嵌入式linux的IIC驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
		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);
		return -ENODEV;
	}
	
	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("i2c-core.o: client_unregister [%s] failed, "
			       "client not detached",client->name);
			return res;
		}

	adapter->clients[i] = NULL;
	adapter->client_count--;

	DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name));
	return 0;
}

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);
}

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)
{
	if(client->flags & I2C_CLIENT_ALLOW_USE) {
		if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) 
			client->usage_count++;
		else {
			if(client->usage_count > 0) 
				return -EBUSY;
			 else 
				client->usage_count++;
		}
	}

	i2c_inc_use_client(client);

	return 0;
}

int i2c_release_client(struct i2c_client *client)
{
	if(client->flags & I2C_CLIENT_ALLOW_USE) {
		if(client->usage_count>0)
			client->usage_count--;
		else
		{
			printk(KERN_WARNING " i2c-core.o: dec_use_client used one too many times\n");
			return -EPERM;
		}
	}
	
	i2c_dec_use_client(client);
	
	return 0;
}

/* ----------------------------------------------------
 * The /proc functions
 * ----------------------------------------------------
 */

#ifdef CONFIG_PROC_FS

#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible
   if some process still uses it or some file in it */
void monitor_bus_i2c(struct inode *inode, int fill)
{
	if (fill)
		MOD_INC_USE_COUNT;
	else
		MOD_DEC_USE_COUNT;
}
#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,37)) */

/* This function generates the output for /proc/bus/i2c */
int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, 
                 void *private)
{
	int i;
	int nr = 0;
	/* Note that it is safe to write a `little' beyond len. Yes, really. */
	for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++)
		if (adapters[i]) {
			nr += sprintf(buf+nr, "i2c-%d\t", i);
			if (adapters[i]->algo->smbus_xfer) {
				if (adapters[i]->algo->master_xfer)
					nr += sprintf(buf+nr,"smbus/i2c");
				else
					nr += sprintf(buf+nr,"smbus    ");
			} else if (adapters[i]->algo->master_xfer)
				nr += sprintf(buf+nr,"i2c       ");
			else
				nr += sprintf(buf+nr,"dummy     ");
			nr += sprintf(buf+nr,"\t%-32s\t%-32s\n",
			              adapters[i]->name,
			              adapters[i]->algo->name);
		}
	return nr;
}

/* This function generates the output for /proc/bus/i2c-? */
ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
                         loff_t *ppos)
{
	struct inode * inode = file->f_dentry->d_inode;
	char *kbuf;
	struct i2c_client *client;
	int i,j,k,order_nr,len=0,len_total;
	int order[I2C_CLIENT_MAX];

	if (count > 4000)
		return -EINVAL; 
	len_total = file->f_pos + count;
	/* Too bad if this gets longer (unlikely) */
	if (len_total > 4000)
		len_total = 4000;
	for (i = 0; i < I2C_ADAP_MAX; i++)
		if (adapters[i]->inode == inode->i_ino) {
		/* We need a bit of slack in the kernel buffer; this makes the
		   sprintf safe. */
			if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
				return -ENOMEM;
			/* Order will hold the indexes of the clients
			   sorted by address */
			order_nr=0;
			for (j = 0; j < I2C_CLIENT_MAX; j++) {
				if ((client = adapters[i]->clients[j]) && 
				    (client->driver->id != I2C_DRIVERID_I2CDEV))  {
					for(k = order_nr; 
					    (k > 0) && 
					    adapters[i]->clients[order[k-1]]->
					             addr > client->addr; 
					    k--)
						order[k] = order[k-1];
					order[k] = j;
					order_nr++;
				}
			}


			for (j = 0; (j < order_nr) && (len < len_total); j++) {
				client = adapters[i]->clients[order[j]];
				len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
				              client->addr,
				              client->name,
				              client->driver->name);
			}
			len = len - file->f_pos;
			if (len > count)
				len = count;
			if (len < 0) 
				len = 0;
			if (copy_to_user (buf,kbuf+file->f_pos, len)) {
				kfree(kbuf);
				return -EFAULT;
			}
			file->f_pos += len;
			kfree(kbuf);
			return len;
		}
	return -ENOENT;
}

int i2cproc_init(void)
{

	struct proc_dir_entry *proc_bus_i2c;

	i2cproc_initialized = 0;

	if (! proc_bus) {
		printk("i2c-core.o: /proc/bus/ does not exist");
		i2cproc_cleanup();
		return -ENOENT;
 	} 
	proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
	if (!proc_bus_i2c) {
		printk("i2c-core.o: Could not create /proc/bus/i2c");
		i2cproc_cleanup();
		return -ENOENT;
 	}
	proc_bus_i2c->read_proc = &read_bus_i2c;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
	proc_bus_i2c->owner = THIS_MODULE;
#else
	proc_bus_i2c->fill_inode = &monitor_bus_i2c;
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */
	i2cproc_initialized += 2;
	return 0;
}

static void i2cproc_cleanup(void)
{

	if (i2cproc_initialized >= 1) {
		remove_proc_entry("i2c",proc_bus);
		i2cproc_initialized -= 2;
	}
}


#endif /* def CONFIG_PROC_FS */

/* ----------------------------------------------------
 * 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) {
 	 	DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",
		            adap->name,num));

		I2C_LOCK(adap);
		ret = adap->algo->master_xfer(adap,msgs,num);
		I2C_UNLOCK(adap);

		return ret;
	} else {
		printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
		       adap->id);
		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;
		(const char *)msg.buf = buf;
	
		DEB2(printk("i2c-core.o: master_send: writing %d bytes on %s.\n",
			count,client->adapter->name));
	
		I2C_LOCK(adap);
		ret = adap->algo->master_xfer(adap,&msg,1);
		I2C_UNLOCK(adap);

		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
		 * transmitted, else error code.
		 */
		return (ret == 1 )? count : ret;
	} else {
		printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
		       client->adapter->id);
		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;

		DEB2(printk("i2c-core.o: master_recv: reading %d bytes on %s.\n",
			count,client->adapter->name));
	
		I2C_LOCK(adap);
		ret = adap->algo->master_xfer(adap,&msg,1);
		I2C_UNLOCK(adap);
	
		DEB2(printk("i2c-core.o: 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 {
		printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
		       client->adapter->id);
		return -ENOSYS;
	}
}


int i2c_control(struct i2c_client *client,
	unsigned int cmd, unsigned long arg)
{
	int ret = 0;
	struct i2c_adapter *adap = client->adapter;

	DEB2(printk("i2c-core.o: 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,
                   i2c_client_found_addr_proc *found_proc)
{
	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) {

⌨️ 快捷键说明

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