linux内核__force,Linux内核学习:I2C_SLAVE_FORCE
在Linux內核源代碼include/linux/i2c-dev.h文件內,有如下定義:
#define I2C_SLAVE0x0703/* Use this slave address */
#define I2C_SLAVE_FORCE0x0706/* 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(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
cmd, arg);
switch (cmd) {
case I2C_SLAVE:
case I2C_SLAVE_FORCE:
/* NOTE: 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.
*/
if ((arg > 0x3ff) || // 如果地址不只10位
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) // 如果地址設置為7位但實際卻超過7位
return -EINVAL;
if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
return -EBUSY;
/* REVISIT: address could become busy later */
client->addr = arg;
return 0;
case 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);
if (!i2c_dev)
return -ENODEV;
adap = i2c_get_adapter(i2c_dev->adap->nr);
if (!adap)
return -ENODEV;
/* 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.
*/
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->adapter = adap;
file->private_data = client;
return 0;
}
注意到上面的注釋中的一段話,意思是它只創建一個匿名的i2c_client,這個i2c_client以后可以通過I2C_SLAVE或I2C_SLAVE_FORCE flag指向某些i2c設備地址。而且這個i2c_client絕對不會注冊到driver model或者I2C core代碼中。它只是用于暫時的hold住地址信息的私有拷貝(and maybe a PEC flag,這句話暫時不理吧).
總結
以上是生活随笔為你收集整理的linux内核__force,Linux内核学习:I2C_SLAVE_FORCE的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux系统加硬盘容量,Linux系统
- 下一篇: linux如何锁定文件夹,如何在没有加密