方法 | 问题描述 |
---|---|
Linux 3.X.X版本之后,设备树+驱动 | 此方法是比较符合linux驱动的写法的。当对于不熟悉设备树的小伙伴,写起来比较棘手 |
使用 i2c-tools,并通过脚本或者应用程序编写设备驱动(简单粗暴) | 此方法是将设备驱动丢到用户态中,对于一些的设备除了I2C通信还有一些引脚也要控制的,此方法写起来将非常痛苦 |
直接操作i2c总线驱动。(简单粗暴) | 此方法是将设备驱动丢到用户态中,对于一些的设备除了I2C通信还有一些引脚也要控制的,此方法写起来将非常痛苦。他将会操作多个文件 |
I2C总线驱动的代码在linux的源码中--i2c-dev.c中。
在代码中可以看到他提供一套文件操作接口,open,read,write,close接口。实际在上面描述的直接操作i2c总线驱动的方法,最终就是调用到这里。
通过整个源码的分析,我们主要看看open和ioctl接口。其中:
open接口,代码分析:通过inode获取设备子设备号,根据子设备号获取I2C适配器。然后申请一个从设备对象。并将I2C适配器句柄映射到从设备对象中。
static int i2cdev_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct i2c_client *client;
struct i2c_adapter *adap;
adap = i2c_get_adapter(minor);
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;
}
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = file->private_data;
unsigned long funcs;
......
switch (cmd) {
.....
case I2C_RDWR:
return i2cdev_ioctl_rdwr(client, arg);
......
}
return 0;
}
static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
unsigned long arg)
{
struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_msg *rdwr_pa;
u8 __user **data_ptrs;
int i, res;
if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg)))
return -EFAULT;
......
res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
while (i-- > 0) {
if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
rdwr_pa[i].len))
res = -EFAULT;
}
kfree(rdwr_pa[i].buf);
}
......
return res;
}
#include "rice_i2c.h"
#define CLASS_NAME "rice_i2c"
#define DEVICE_NAME "rice_i2c"
typedef struct {
int major_number;
struct device *device;
struct class *class;
struct i2c_client *client;
} Rice_Driver;
Rice_Driver rice_drv;
static int i2c_test(void)
{
struct i2c_msg i2c_msg[2] = {0};
uint8_t reg_addr = 0x75;
uint8_t buff[2] = {0};
i2c_msg[0].addr = 0x69;
i2c_msg[0].flags = 0;
i2c_msg[0].len = 1;
i2c_msg[0].buf = (uint8_t *)®_addr;
i2c_msg[1].addr = 0x69;
i2c_msg[1].flags = I2C_M_RD;
i2c_msg[1].len = 1;
i2c_msg[1].buf = buff;
i2c_transfer(rice_drv.client->adapter, i2c_msg, 2);
printk(KERN_ALERT "i2c read data: 0x%02x!!\n", buff[0]);
}
static int __init rice_i2c_init(void) {
struct i2c_client *client;
struct i2c_adapter *adap;
rice_drv.major_number = register_chrdev(0, DEVICE_NAME, NULL);
if (rice_drv.major_number < 0) {
printk(KERN_ALERT "Register fail!!\n");
return rice_drv.major_number;
}
printk(KERN_ALERT "Registe success, major number is %d\n", rice_drv.major_number);
rice_drv.class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(rice_drv.class)) {
unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
return PTR_ERR(rice_drv.class);
}
rice_drv.device = device_create(rice_drv.class, NULL, MKDEV(rice_drv.major_number, 0), NULL, DEVICE_NAME);
if (IS_ERR(rice_drv.device)) {
class_destroy(rice_drv.class);
unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
return PTR_ERR(rice_drv.device);
}
// 1 为设备挂在的i2c总线的子设备号
adap = i2c_get_adapter(1);
if (!adap)
return -ENODEV;
rice_drv.client = kzalloc(sizeof(*rice_drv.client), GFP_KERNEL);
if (!rice_drv.client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(rice_drv.client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
rice_drv.client->adapter = adap;
i2c_test();
printk(KERN_ALERT "rice i2c ko init!!\n");
return 0;
}
static void __exit rice_i2c_exit(void) {
device_destroy(rice_drv.class, MKDEV(rice_drv.major_number, 0));
class_unregister(rice_drv.class);
class_destroy(rice_drv.class);
unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
i2c_put_adapter(rice_drv.client->adap);
printk(KERN_ALERT "rice i2c ko exit!!\n");
}
module_init(rice_i2c_init);
module_exit(rice_i2c_exit);
MODULE_AUTHOR("RieChen");
MODULE_LICENSE("GPL");
Registe success, major number is 240
i2c read data: 0x67!!
rice i2c ko init!!
审核编辑 黄昊宇
全部0条评论
快来发表一下你的评论吧 !