Linux内核学习:I2C_SLAVE_FORCE

转载地址:https://blog.csdn.net/tomxue0126/article/details/8245226

在Linux内核源代码include/linux/i2c-dev.h文件内,有如下定义:

#define I2C_SLAVE	0x0703	/* Use this slave address */
#define I2C_SLAVE_FORCE	0x0706	/* Use this slave address, even if it
				   is already in use by a driver! */

看注释,意思就是当某个i2c设备地址已经关联了某个内核driver时,再用I2C_SLAVE作为ioctl的flag就无法取得该设备的控制权了。这时,应该使用I2C_SLAVE_FORCE。


再次搜索,找到drivers/i2c/i2c-dev.c文件:

static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct i2c_client *client = file->private_data;
	unsigned long funcs;
dev_dbg(&amp;client-&gt;adapter-&gt;dev, <span class="hljs-string">"ioctl, cmd=0x%02x, arg=0x%02lx\n"</span>,
	cmd, arg);

<span class="hljs-keyword">switch</span> (cmd) {
<span class="hljs-keyword">case</span> I2C_SLAVE:
<span class="hljs-keyword">case</span> I2C_SLAVE_FORCE:
	<span class="hljs-comment">/* <span class="hljs-doctag">NOTE:</span>  devices set up to work with "new style" drivers
	 * can't use I2C_SLAVE, even when the device node is not
	 * bound to a driver.  Only I2C_SLAVE_FORCE will work.
	 *
	 * Setting the PEC flag here won't affect kernel drivers,
	 * which will be using the i2c_client node registered with
	 * the driver model core.  Likewise, when that client has
	 * the PEC flag already set, the i2c-dev driver won't see
	 * (or use) this setting.
	 */</span>
	<span class="hljs-keyword">if</span> ((arg &gt; <span class="hljs-number">0x3ff</span>) ||  <span class="hljs-comment">// 如果地址不只10位</span>
	    (((client-&gt;flags &amp; I2C_M_TEN) == <span class="hljs-number">0</span>) &amp;&amp; arg &gt; <span class="hljs-number">0x7f</span>))  <span class="hljs-comment">// 如果地址设置为7位但实际却超过7位</span>
		<span class="hljs-keyword">return</span> -EINVAL;
	<span class="hljs-keyword">if</span> (cmd == I2C_SLAVE &amp;&amp; i2cdev_check_addr(client-&gt;adapter, arg))
		<span class="hljs-keyword">return</span> -EBUSY;
	<span class="hljs-comment">/* REVISIT: address could become busy later */</span>
	client-&gt;addr = arg;
	<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
<span class="hljs-keyword">case</span> I2C_TENBIT:

上面的第一个参数file,举个例子,它可以是/dev/i2c-2,那么由此得到的client应该是挂在这个i2c-2总线上的所有i2c设备吧,这是我的理解。

这里case I2C_SLAVE后面是空的,实际上应该是转移到下一条分支case I2C_SLAVE_FORCE去了,也就是说这两种情况的后续处理放在了一起。

如果cmd == I2C_SLAVE并且总线上挂的设备中已经有地址为arg的设备在用了,则给出-EBUSY,这其实就是说你往相同的i2c总线上挂两个i2c地址一样的设备,肯定有潜在的问题,Linux不建议你这样干。

这个也是我之前遇到过的情况。解决办法就是设置flag为I2C_SLAVE_FORCE,这样,就可以跳过这个检测条件,将我想要使用的设备地址arg强行传递给该总线,而不理可能导致的问题,这就叫FORCE,后果自负!

client->addr = arg;

另外一个问题:client为什么是通过file->private_data传递的?这就要看下面的代码了。

它描述的大概流程是这样的:inode -> minor -> i2c_dev -> adap -> client,即通过inode一步步生成了client,最后把client传递进file->private_data,和i2cdev_ioctl()中的传递方向正好相反。而且这个i2cdev_open()发生在上面的i2cdev_ioctl()之前。

static int i2cdev_open(struct inode *inode, struct file *file)
{
	unsigned int minor = iminor(inode);
	struct i2c_client *client;
	struct i2c_adapter *adap;
	struct i2c_dev *i2c_dev;
i2c_dev = i2c_dev_get_by_minor(minor);
<span class="hljs-keyword">if</span> (!i2c_dev)
	<span class="hljs-keyword">return</span> -ENODEV;

adap = i2c_get_adapter(i2c_dev-&gt;adap-&gt;nr);
<span class="hljs-keyword">if</span> (!adap)
	<span class="hljs-keyword">return</span> -ENODEV;

<span class="hljs-comment">/* This creates an anonymous i2c_client, which may later be
 * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
 *
 * This client is ** NEVER REGISTERED ** with the driver model
 * or I2C core code!!  It just holds private copies of addressing
 * information and maybe a PEC flag.
 */</span>
client = kzalloc(<span class="hljs-keyword">sizeof</span>(*client), GFP_KERNEL);
<span class="hljs-keyword">if</span> (!client) {
	i2c_put_adapter(adap);
	<span class="hljs-keyword">return</span> -ENOMEM;
}
<span class="hljs-built_in">snprintf</span>(client-&gt;name, I2C_NAME_SIZE, <span class="hljs-string">"i2c-dev %d"</span>, adap-&gt;nr);

client-&gt;adapter = adap;
file-&gt;private_data = client;

<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

}

注意到上面的注释中的一段话,意思是它只创建一个匿名的i2c_client,这个i2c_client以后可以通过I2C_SLAVE或I2C_SLAVE_FORCE flag指向某些i2c设备地址。而且这个i2c_client绝对不会注册到driver model或者I2C core代码中。它只是用于暂时的hold住地址信息的私有拷贝(and maybe a PEC flag,这句话暂时不理吧).


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值