原文: http://blog.chinaunix.net/uid-22609852-id-3506488.html
不管怎样,先列出在linux2.6.32.2下最简短的i2c程序,因为在跟踪内核代码的过程中你会关注到它。
一、最简驱动
/*
at24c08.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
static int at24c08_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
{
printk("at24c08_probe\n");
return 0;
}
static int at24c08_remove(struct i2c_client *client)
{
printk("at24c08_remove\n");
return 0;
}
static int at24c08_detect(struct i2c_client *client, int kind, struct i2c_board_info *bd_info)
{
strcpy(bd_info->type, "at24c08"); //这个必须设置
//Point3
printk("at24c08_detect\n");
return 0;
}
static const struct i2c_device_id at24c08_id[] = {
{"at24c08", 0},
{}
};
static unsigned short ignore[] = { I2C_CLIENT_END };
static const unsigned short normal_i2c[] = {0x50, I2C_CLIENT_END};
static const struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
.probe = ignore,
.ignore = ignore,
//.forces Point1
};
static struct i2c_driver at24c08_driver= {
.probe = at24c08_probe,
.remove = at24c08_remove,
.driver = {
.name = "at24c08",
},
.id_table = at24c08_id,
.detect = at24c08_detect,
.address_data = &addr_data,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD, //Point2
};
static int at24c08_init(void)
{
i2c_add_driver(&at24c08_driver);
return 0;
}
static void at24c08_exit(void)
{
i2c_del_driver(&at24c08_driver);
return ;
}
module_init(at24c08_init);
module_exit(at24c08_exit);
MODULE_LICENSE("GPL");
二、代码分析
适写驱动之前我们先从i2c-s3c2410.c开始分析
系统启动初始化运行i2c_adap_s3c_init
i2c_adap_s3c_init(i2c-s3c2410.c)
platform_driver_register (platform.c)
drv->driver.bus = &platform_bus_type; //设置驱动总线的类型为平台总线
driver_register(&drv->driver) (driver.c)
bus_add_driver(drv) (bus.c)
driver_attach(drv) (db.c)
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)(bus.c)
fn(dev, data) (bus.c)
<=>__driver_attach (db.c)
driver_match_device(drv, dev) (base.h)//调用驱动所属总线的match函数即:platform_match
driver_probe_device(drv, dev) (db.c)
really_probe(dev, drv) (db.c)
if (dev->bus->probe) { //不存在
ret = dev->bus->probe(dev);
...
} else if (drv->probe) { //或者调用驱动的probe函数即:s3c24xx_i2c_probe
ret = drv->probe(dev);
..
}
接上
drv->probe(dev)(db.c)
一、最简驱动
/*
at24c08.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
static int at24c08_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
{
printk("at24c08_probe\n");
return 0;
}
static int at24c08_remove(struct i2c_client *client)
{
printk("at24c08_remove\n");
return 0;
}
static int at24c08_detect(struct i2c_client *client, int kind, struct i2c_board_info *bd_info)
{
strcpy(bd_info->type, "at24c08"); //这个必须设置
//Point3
printk("at24c08_detect\n");
return 0;
}
static const struct i2c_device_id at24c08_id[] = {
{"at24c08", 0},
{}
};
static unsigned short ignore[] = { I2C_CLIENT_END };
static const unsigned short normal_i2c[] = {0x50, I2C_CLIENT_END};
static const struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
.probe = ignore,
.ignore = ignore,
//.forces Point1
};
static struct i2c_driver at24c08_driver= {
.probe = at24c08_probe,
.remove = at24c08_remove,
.driver = {
.name = "at24c08",
},
.id_table = at24c08_id,
.detect = at24c08_detect,
.address_data = &addr_data,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD, //Point2
};
static int at24c08_init(void)
{
i2c_add_driver(&at24c08_driver);
return 0;
}
static void at24c08_exit(void)
{
i2c_del_driver(&at24c08_driver);
return ;
}
module_init(at24c08_init);
module_exit(at24c08_exit);
MODULE_LICENSE("GPL");
二、代码分析
适写驱动之前我们先从i2c-s3c2410.c开始分析
系统启动初始化运行i2c_adap_s3c_init
i2c_adap_s3c_init(i2c-s3c2410.c)
platform_driver_register (platform.c)
drv->driver.bus = &platform_bus_type; //设置驱动总线的类型为平台总线
driver_register(&drv->driver) (driver.c)
bus_add_driver(drv) (bus.c)
driver_attach(drv) (db.c)
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)(bus.c)
fn(dev, data) (bus.c)
<=>__driver_attach (db.c)
driver_match_device(drv, dev) (base.h)//调用驱动所属总线的match函数即:platform_match
driver_probe_device(drv, dev) (db.c)
really_probe(dev, drv) (db.c)
if (dev->bus->probe) { //不存在
ret = dev->bus->probe(dev);
...
} else if (drv->probe) { //或者调用驱动的probe函数即:s3c24xx_i2c_probe
ret = drv->probe(dev);
..
}
接上
drv->probe(dev)(db.c)