您的位置:首页 > 运维架构 > Linux

【Linux高级驱动】I2C驱动框架分析

2014-06-22 15:43 423 查看

1.i2c-dev.c(i2c设备驱动组件层)

功能:1)给用户提供接口

i2c_dev_init //入口函数
/*申请主设备号*/

register_chrdev(I2C_MAJOR(89), "i2c", &i2cdev_fops);
/*创建一个设备类*/
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
/*注册一个i2c驱动*/
i2c_add_driver(&i2cdev_driver);
i2c_register_driver(THIS_MODULE, driver);
/*指定总线类型*/
driver->driver.bus = &i2c_bus_type;
/*驱动注册
*1.将i2c驱动加入i2c总线的驱动链表
*2.搜索设备链表,实现匹配,根据i2c总线的匹配原理:必须要求i2c驱动结构体中实现id_table
* 但是,i2c驱动结构体中并没有实现id_table,所以永远都匹配失败
*/
driver_register(&driver->driver);

/*搜索适配器链表,每搜索一个适配器,都会调用__process_new_driver函数
*在此函数中,又会调用i2c驱动中的,attach_adapter函数
*/
bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
__process_new_driver //此函数可能会被调用多次
i2c_do_add_adapter(data, to_i2c_adapter(dev));
if (driver->attach_adapter) {
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap); //i2cdev_attach_adapter
}

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,
};
static struct i2c_driver i2cdev_driver = {
.driver = {
.name = "dev_driver",
},
.attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
};

2.i2c-core.c(i2c核心层组件)

功能:1)注册一条i2c总线
2)提供基本的接口函数,用来建立上层与下层的连接

i2c_init //入口函数
/*注册I2C总线*/
bus_register(&i2c_bus_type);

struct bus_type i2c_bus_type = { //实际的物理总线,I2C总线
.name = "i2c",
.match = i2c_device_match, //匹配函数
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client)
return 0;
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
while (id->name[0]) {
if (strcmp(client->name, id->name) == 0)
return id;
id++;
}
return 0;
}

涉及的重要结构体:

struct i2c_client { //表示一个i2c设备
unsigned short flags; /* div., see below */
unsigned short addr; /*器件地址*/
char name[I2C_NAME_SIZE]; /*名字*/
struct i2c_adapter *adapter; /*所属适配器,所属控制器*/
struct i2c_driver *driver; /*设备驱动*/
struct device dev; /* the device structure */
int irq; /* irq issued by device */
struct list_head detected;
};
struct i2c_driver { //用来表示i2c驱动
unsigned int class;
/* Notifies the driver that a new bus has appeared or is about to be
* removed. You should avoid using this if you can, it will probably
* be removed in a near future.
*/
int (*attach_adapter)(struct i2c_adapter *);
int (*detach_adapter)(struct i2c_adapter *);
/*probe函数:初始化工作,设备检测,*/
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
struct device_driver driver; //设备驱动
const struct i2c_device_id *id_table; //指定此驱动能为哪些设备服务
...
...
};
struct i2c_adapter { //表示一个i2c适配器/i2c控制器
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
/*操作方法*/
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
int nr; /*适配器的号码*/
...
...
};
struct i2c_msg { //表示一个i2c数据包
__u16 addr; /*设备地址*/
__u16 flags; /*表示:1-表示读包 0-表示写包*/
__u16 len; /*数据包的长度*/
__u8 *buf; /*真正的数据*/
...
...
};

涉及的重要函数接口:

/*注册一个i2c控制器*/
int i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_del_adapter(struct i2c_adapter *adap)
/*注册i2c驱动*/
int i2c_add_driver(struct i2c_driver *driver)
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
int i2c_del_numbered_adapter(struct i2c_adapter *adap)
extern int i2c_del_driver(struct i2c_driver *driver);
/*接收i2c数据包*/
int i2c_master_recv(struct i2c_client *client, char *buf, int count)
/*发送i2c数据包*/
int i2c_master_send(struct i2c_client *client, const char *buf, int count)
/*提交i2c数据包到总线驱动层*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

3.busses目录:i2c总线驱动/i2c控制器驱动/i2c适配器驱动

i2c-s3c2410.c

功能:1)实现对i2c控制器的初始化
2)实现操作方法(实现i2c协议,完成数据的发送)

如何用通用接口驱动来操作i2c设备

open

app: open("/dev/i2c-0", O_RDWR);
=====================================
sys: sys_open
...
...
i2c-dev.c struct file_operations i2cdev_fops
.open = i2cdev_open,
/*构建一个i2c_client*/
struct i2c_client *client;
struct i2c_adapter *adap;
/*获取适配器*/
adap = i2c_get_adapter(i2c_dev->adap->nr);
client = kzalloc(sizeof(*client), GFP_KERNEL);
client->driver = &i2cdev_driver; //指定i2c设备驱动
client->adapter = adap; //指定适配器
file->private_data = client;

ioctl

app: ioctl(fd, I2C_SLAVE, 0x48)
==============================================
sys: sys_ioctl
...
...
i2c-dev.c struct file_operations i2cdev_fops
.unlocked_ioctl = i2cdev_ioctl,
/*获取i2c_client*/
struct i2c_client *client = file->private_data;
switch (cmd) {
case I2C_SLAVE: I2C_M_TEN:是否为10位寻址的设备
if ((arg > 0x3ff) ||(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
client->addr = arg; //0x48
}

write

app: write(fd, wbuf, 1)
===============================================
sys: sys_write
...
...
i2c-dev.c struct file_operations i2cdev_fops
.write = i2cdev_write,
/*获取i2c_client*/
struct i2c_client *client = file->private_data;
char *tmp;
tmp = kmalloc(count, GFP_KERNEL);
copy_from_user(tmp, buf, count)

/*发送数据到核心层*/
i2c-core.c i2c_master_send(client, tmp, count);
struct i2c_msg msg; //表示i2c数据包
/*填充数据包*/
msg.addr = client->addr; //0x48
msg.flags = client->flags & I2C_M_TEN; //写
msg.len = count; //1
msg.buf = (char *)buf; //wbuf 0x0
/*提交数据给总线驱动层*/
i2c_transfer(adap, &msg, 1);
if (adap->algo->master_xfer)
i2c_s3c2410.c adap->algo->master_xfer(adap, msgs, num); //s3c24xx_i2c_xfer
s3c24xx_i2c_xfer

@成鹏致远

[b](blogs:http://lcw.cnblogs.com[/b]

(email[b]:[/b]wwwlllll@126.com)

(qq[b]:[/b]552158509)

From WizNote
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: