当前位置:网站首页>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;
}
边栏推荐
- With an annual income of more than 8 million, he has five full-time jobs. He still has time to play games
- Image retrieval
- Firewall basic transparent mode deployment and dual machine hot standby
- Kunming Third Ring Road Closure project will pass through these places. Is there one near your home?
- 如何进行MDM的产品测试
- 【华为HCIA持续更新】SDN与FVC
- 【Hot100】32. 最长有效括号
- Superscalar processor design yaoyongbin Chapter 7 register rename excerpt
- What is low code development?
- [test development] software testing - Basics
猜你喜欢

The company needs to be monitored. How do ZABBIX and Prometheus choose? That's the right choice!

【HCIA持续更新】WLAN工作流程概述

利用win10计划任务程序定时自动运行jar包

Vscode modification indentation failed, indent four spaces as soon as it is saved

Ble HCI flow control mechanism

CANN算子:利用迭代器高效实现Tensor数据切割分块处理

Ks007 realizes personal blog system based on JSP

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

kaili不能输入中文怎么办???

Firewall basic transparent mode deployment and dual machine hot standby
随机推荐
Firewall basic transparent mode deployment and dual machine hot standby
Cocoscreator event dispatch use
Flask 轻量web框架
The Ministry of human resources and Social Security announced the new construction occupation
To sort out messy header files, I use include what you use
《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(2)-初识Fiddler让你理性认识一下
What is low code development?
Developers, MySQL column finish, help you easily from installation to entry
【Hot100】32. 最长有效括号
Initial experience of domestic database tidb: simple and easy to use, quick to start
S5PV210芯片I2C适配器驱动分析(i2c-s3c2410.c)
第十八届IET交直流输电国际会议(ACDC2022)于线上成功举办
Easy to use map visualization
leetcode:421. The maximum XOR value of two numbers in the array
Superscalar processor design yaoyongbin Chapter 7 register rename excerpt
网页游戏引擎
雨量预警广播自动化数据平台BWII 型广播预警监测仪
The company needs to be monitored. How do ZABBIX and Prometheus choose? That's the right choice!
Mathematical analysis_ Notes_ Chapter 7: differential calculus of multivariate functions
R language plot visualization: plot visualization of multiple variable violin plot in R with plot