当前位置:网站首页>Device interface analysis of the adapter of I2C subsystem (I2C dev.c file analysis)
Device interface analysis of the adapter of I2C subsystem (I2C dev.c file analysis)
2022-07-04 17:43:00 【Snail taking off】
1、 The principle of driving implementation
(1) Ideas for driving implementation : take I2C The operation method of the controller is directly provided to the application , The driver itself only implements the simplest I2C The method of bus sending and receiving data , Specifically I2C The operation sequence of the interface hardware is controlled by the application ;
(2) The driver only does the most basic operation of sending and receiving data , The difficulty of driver code development is reduced , But the difficulty of application development has increased , And applications need to be aware of hardware differences , But most of us need to shield the hardware differences of applications when writing programs , So this driver framework is not commonly used ;
2、 The effect of driving
(1) stay /dev Create under directory "i2c-n(n=0,1,2······)" Device node , Each device node represents Soc One of the I2C controller ;
(2) Application passed open、read、write、ioctl Such as function , Go to mount in corresponding I2C On the bus I2C Equipment communication ;
Add : One I2C The controller is equivalent to a I2C Bus ;I2C The controller is in I2C It is also called adapter in subsystem ;
3、 Driver loading :i2c_dev_init( )
// Operation method of equipment node
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
//I2C drive
static struct i2c_driver i2cdev_driver = {
.driver = {
.name = "dev_driver",
},
.attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
};
#define I2C_MAJOR 89 /* Device major number */
static int __init i2c_dev_init(void)
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
// The registered device number is 89, The range of secondary equipment number is 0-255、 The set of file operations is i2cdev_fops Character devices
res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
if (res)
goto out;
// The registered name is i2c-dev The device class of
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
if (IS_ERR(i2c_dev_class)) {
res = PTR_ERR(i2c_dev_class);
goto out_unreg_chrdev;
}
// register i2c Adapter device driver i2cdev_driver
res = i2c_add_driver(&i2cdev_driver);
if (res)
goto out_unreg_class;
return 0;
out_unreg_class:
class_destroy(i2c_dev_class);
out_unreg_chrdev:
unregister_chrdev(I2C_MAJOR, "i2c");
out:
printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
return res;
}
(1) The registered device number is 89, The range of secondary equipment number is 0-255、 The set of file operations is i2cdev_fops Character devices ;
(2) The registered name is i2c-dev The device class of ;
(3) register i2c Adapter device driver i2cdev_driver, Every future kernel registration I2C Adapters will be exposed to applications by the driver in the form of device nodes ;
summary :I2C All drivers belong to i2c-dev Equipment class , Common main equipment number 89; In the future "/sys/class/i2c-dev" You can see the registered I2C drive ;
4、 Open the device node
4.1、i2cdev_open() function
static int i2cdev_open(struct inode *inode, struct file *file)
{
// adopt inode Get the secondary device number
unsigned int minor = iminor(inode);
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
// From the linked list according to the secondary equipment number i2c_dev_list Get the corresponding i2c_dev object
i2c_dev = i2c_dev_get_by_minor(minor);
if (!i2c_dev)
return -ENODEV;
// get ID by i2c_dev->adap->nr The adapter object for
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. */
// Create a i2c_client Object and initialize
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->driver = &i2cdev_driver;
client->adapter = adap;
// Save to struct file Private data of structure , I will use
file->private_data = client;
return 0;
}
(1) from inode Get secondary device number from , Then from the linked list according to the secondary equipment number i2c_dev_list Get the corresponding i2c_dev object ;
(2) get ID by i2c_dev->adap->nr The adapter object for , Adapter objects are used in the kernel to represent I2C Controller ;
(3) Create a i2c_client Object and initialize , take adap、i2cdev_driver、 The names are saved to client in ;
(4) The final will be i2c_client Object as file Private data for subsequent operations ;
5、 from I2C The device reads data
5.1、 Function call
i2cdev_read()
i2c_master_recv()
i2c_transfer()
adap->algo->master_xfer() //adap How the adapter sends and receives data
copy_to_user()
5.2、i2cdev_read() function
static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
loff_t *offset)
{
char *tmp;
int ret;
// Analysis Division open Built when struct i2c_client Structure
struct i2c_client *client = file->private_data;
if (count > 8192)
count = 8192;
tmp = kmalloc(count, GFP_KERNEL);
if (tmp == NULL)
return -ENOMEM;
pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
iminor(file->f_path.dentry->d_inode), count);
// receive data , Then copy the data to the user space cache
ret = i2c_master_recv(client, tmp, count);
if (ret >= 0)
ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
kfree(tmp);
return ret;
}
(1) Analysis Division open Built when struct i2c_client Structure ;
(2) call i2c_master_recv() Function to receive data , Then copy the data to the user space cache ;
5.3、i2c_master_recv() function
int i2c_master_recv(struct i2c_client *client, char *buf, int count)
{
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msg;
int ret;
// stay open() There is no right in the method client->addr assignment , Therefore, you cannot call directly after opening the device read() Method
msg.addr = client->addr; // From the device in I2C Address on the bus
msg.flags = client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = buf;
//i2c_transfer() By calling the adapter communication method master_xfer Send a message
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;
}
(1)i2c_master_recv() By filling i2c_msg Structure , And then call i2c_transfer() Function to realize transmission ;
(2)i2c_transfer() Then call the adapter communication method master_xfer() Send a message ;
Add : In filling msg The slave device is assigned at I2C Address on the bus , But in open Time is not right addr Assign a value , So we can't open Directly after read Operation of the , You need to call ioctl Function to set the slave device address addr, Indicates to operate I2C Which device on the bus ;
6、 Go to I2C Device write data
6.1、 Function call relationship
i2cdev_write()
copy_from_user()
i2c_master_send()
i2c_transfer()
adap->algo->master_xfer()
6.2、i2cdev_write() function
static ssize_t i2cdev_write(struct file *file, const char __user *buf,
size_t count, loff_t *offset)
{
int ret;
char *tmp;
struct i2c_client *client = file->private_data;
if (count > 8192)
count = 8192;
tmp = kmalloc(count, GFP_KERNEL);
if (tmp == NULL)
return -ENOMEM;
// Copy the data to be sent from user space to kernel space
if (copy_from_user(tmp, buf, count)) {
kfree(tmp);
return -EFAULT;
}
pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_send(client, tmp, count);
kfree(tmp);
return ret;
}
(1) Analysis Division open Built when struct i2c_client Structure ;
(2) call i2c_master_send() Function to send data , Ultimately, the adapter communication method is called master_xfer(), It is basically the same as the process of reading data ;
7、ioctl function :i2cdev_ioctl()
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
// Analysis Division open() Created when client
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: // Assign slave device address , If the address has been assigned , Then return to EBUSY error
case I2C_SLAVE_FORCE: // Whether assigned or not , Force this address
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
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: // Set up I2C_M_TEN identification . Enable 10bit Address mode
if (arg)
client->flags |= I2C_M_TEN;
else
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC: // start-up SMBus Package error checking
if (arg)
client->flags |= I2C_CLIENT_PEC;
else
client->flags &= ~I2C_CLIENT_PEC;
return 0;
case I2C_FUNCS: // Read the functions supported by the adapter
funcs = i2c_get_functionality(client->adapter);
return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR: // Read 、 write in I2C news
return i2cdev_ioctl_rdrw(client, arg);
case I2C_SMBUS: // Handle SMBus Message transmission
return i2cdev_ioctl_smbus(client, arg);
case I2C_RETRIES: // Set number of retries
client->adapter->retries = arg;
break;
case I2C_TIMEOUT: // Set timeout
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
default:
return -ENOTTY;
}
return 0;
}
8、 When is the device node created
8.1、 Function call relationship
i2c_dev_init()
i2c_add_driver()
i2c_register_driver()
bus_for_each_dev()
__process_new_driver()
driver->attach_adapter()
i2cdev_attach_adapter()
device_create()
device_create_file()
8.2、i2cdev_attach_adapter() function
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
int res;
// Allocate one i2c_dev object , To add to i2c_dev_list In the list
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
/* Create a device object and create it in sysfs Register in , stay /dev The equipment number created under the directory is MKDEV(I2C_MAJOR, adap->nr), The name is "i2c-%d" Character device node */
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
MKDEV(I2C_MAJOR, adap->nr), NULL,
"i2c-%d", adap->nr);
if (IS_ERR(i2c_dev->dev)) {
res = PTR_ERR(i2c_dev->dev);
goto error;
}
// establish "/sys/class/i2c-dev/"i2c-%d"/name" file
res = device_create_file(i2c_dev->dev, &dev_attr_name);
if (res)
goto error_destroy;
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
adap->name, adap->nr);
return 0;
error_destroy:
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
return_i2c_dev(i2c_dev);
return res;
}
边栏推荐
- Dynamic programming stock problem comparison
- 7 RSA密码体制
- 利用win10计划任务程序定时自动运行jar包
- 图像检索(image retrieval)
- RecastNavigation 之 Recast
- Internet addiction changes brain structure: language function is affected, making people unable to speak neatly
- CocosCreator事件派發使用
- 超标量处理器设计 姚永斌 第7章 寄存器重命名 摘录
- VB cannot access database stocks
- Display opencv drawn pictures on MFC picture control control
猜你喜欢

Kunming Third Ring Road Closure project will pass through these places. Is there one near your home?

雨量预警广播自动化数据平台BWII 型广播预警监测仪

CocosCreator事件派发使用

超标量处理器设计 姚永斌 第7章 寄存器重命名 摘录

The Block:USDD增长势头强劲

wuzhicms代码审计

VSCode修改缩进不成功,一保存就缩进四个空格

开发者,MySQL专栏完更,助你轻松从安装到入门进阶

RecastNavigation 之 Recast
![[HCIA continuous update] WLAN overview and basic concepts](/img/50/7eef28b7cfb0a72c97f3c50518ad6d.png)
[HCIA continuous update] WLAN overview and basic concepts
随机推荐
设置窗体透明 隐藏任务栏 与全屏显示
解读数据安全治理能力评估框架2.0,第四批DSG评估征集中
Offline and open source version of notation -- comprehensive evaluation of note taking software anytype
regular expression
Datakit -- the real unified observability agent
Interpretation of data security governance capability evaluation framework 2.0, the fourth batch of DSG evaluation collection
一文掌握数仓中auto analyze的使用
Vscode modification indentation failed, indent four spaces as soon as it is saved
Win32 API access route encrypted web pages
动态规划股票问题对比
Superscalar processor design yaoyongbin Chapter 7 register rename excerpt
整理混乱的头文件,我用include what you use
Solution of commercial supply chain coordination system in the mineral industry: build a digital intelligent supply chain platform to ensure the safe supply of mineral resources
Great Wall Securities security does not open a securities account
国产数据库TiDB初体验:简单易用,快速上手
OPPO小布推出预训练大模型OBERT,晋升KgCLUE榜首
将Opencv绘制图片显示在MFC Picture Control控件上
超标量处理器设计 姚永斌 第7章 寄存器重命名 摘录
斑马识别成狗,AI犯错的原因被斯坦福找到了丨开源
Is it safe for CITIC Securities to open an account online? Is the account opening fee charged