本文以Linux自带的驱动DS1337为例,对IIC驱动进行分析。
DS1337所在的位置为Linux\drivers\i2c\chips\ds1337.c。
IIC通信协议,对于我们这些MCU出身的人来说,应该已经很熟悉了,这里就不再介绍。而DS1337为一个时钟IC,具体的规格书可以随便BAIDU到中文版本,这里我们就先不多花时间来复习这些前期的准备知识了。
当然,如果读者还不清楚这两个知识点的话,在读本文前建议先花点时间了解一下这些基本知识。
驱动的入口一般都是module_init,不过我们在进入这个入口之前,我们还是先看看一些变量的定义,以及宏的申明:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/*
* Functions declaration
*/
//这个是IIC设备的器件地址,至于是怎么用到的,我们后面会分析到
static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1(ds1337);
//平白无故的冒出这么一个东西,第一反应是这个东西是一个宏
//于是我们在include\linux\i2c.h中找到了他的申明:
#define I2C_CLIENT_INSMOD_1(chip1) \
enum chips { any_chip, chip1 }; \
I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
"boldly assume to be present"); \
I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
static unsigned short *forces[] = { force, force_##chip1, NULL }; \
I2C_CLIENT_INSMOD_COMMON
我们先不管其他的宏,先把这里给套入参数:
enum chips {any_chip, ds1337};
I2C_CLIENT_MODULE_PARM(….)
I2C_CLIENT_MODULE_PARM_FORCE(ds1337);
static unsigned short *forces[] = {force, force_ds1337, NULL};
I2C_CLIENT_INSMOD_COMMON
*forces[]里面的东西从哪来的?
呵呵,先别着急,我们先把前面两个宏展开来:
%%%%%%%%%%%%%%%%%%%%
#define I2C_CLIENT_MODULE_PARM(var, desc) \
static unsigned short var[I2C_CLIENT_MAX_OPTS] = I2C_CLIENT_DEFAULTS; \
I2C_CLIENT_MAX_OPTS = 48
I2C_CLIENT_DEFAULTS = I2C_CLIENT_END,也就是0xfffeU
所以这里很容易理解:定义一个变量数组force[48],并将值全部初始化为0xfffeU
static unsigned int var##_num; \
定义变量force_num
module_param_array(var, short, &var##_num, 0); \
在include\linux\Moduleparam.h中,我们找到如下定义:
#define module_param_array(name, type, nump, perm) \
module_param_array_named(name, name, type, nump, perm)
这个宏再挖下去话题就远了,我们只要知道这个宏的作用就行了:
force(var) – 模块参数名(就像一个变量名一样)
short – 参数类型
*force_num – 保存元素个数
0 – 权限
MODULE_PARM_DESC(var,desc)
这里只是一个字符串信息描述
可见,这个宏目前可见的作用是声明了一个变量数组force[48],并将该数组全部初始为为I2C_CLIENT_END
%%%%%%%%%%%%%%%%%%%%
#define I2C_CLIENT_MODULE_PARM_FORCE(name) \
I2C_CLIENT_MODULE_PARM(force_##name, \
"List of adapter,address pairs which are " \
"unquestionably assumed to contain a `" \
# name "' chip")
展开一下就是:
IC2_CLIENT_MODULE_PARM(force_ds1337,
“….” ds1337 “chip”)
这个宏刚刚分析过,也就是在这里又建立了一个数组:
force_ds1337[48] = {…}
%%%%%%%%%%%%%%%%%%%%
看完上面两个宏的分析,以下这行代码就容易理解了:
static unsigned short *forces[] = {force, force_ds1337, NULL};
指针数组 ^_^
最后,才是I2C_CLIENT_INSMOD_1(ds1337)的核心部分:
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_COMMON \
I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan " \
"additionally"); \
这里定义了probe[]数组
I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to " \
"scan");
这里定义了ignore[]数组 \
static struct i2c_client_address_data addr_data = { \
.normal_i2c = normal_i2c, \
.probe = probe, \
.ignore = ignore, \
.forces = forces, \
}
对一下结构体原型:
struct i2c_client_address_data {
unsigned short *normal_i2c;
unsigned short *probe;
unsigned short *ignore;
unsigned short **forces;
};
应该没什么疑问了吧。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/*
* Driver data (common to all clients)
*/
//I2C的结构体,很大,这里只初始化了需要用到的部分
static struct i2c_driver ds1337_driver = {
.driver = {
.name = "ds1337",
},
.attach_adapter = ds1337_attach_adapter,
.detach_client = ds1337_detach_client,
.command = ds1337_command,
};
/*
* Client data (each client gets its own)
*/
//指定设备的结构体,不同的设备按自己的需要有不同的定义
struct ds1337_data {
struct i2c_client client;
struct list_head list;
};
/*
* Internal variables
*/
static LIST_HEAD(ds1337_clients); //声明一个空链表ds1337_clients
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
准备工作做完,我们该看代码了,先从入口看起
module_init(ds1337_init);
static int __init ds1337_init(void)
{
return i2c_add_driver(&ds1337_driver);
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
在I2C.h中
static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
然后进入I2C_core.c
这里传近来的*driver = ds1337_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* new style driver methods can't mix with legacy ones */
#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
//从ds1337_driver结构体定义中可以看到,probe和remove均未定义,所以这个if不成立。
//简单的看一眼这个if的实现代码可发现,这个if实际是说明了,i2c_driver中,probe+remove和attach_adapter等函数是互斥的,应该是两种扫描方法(或则说是两种I2C驱动架构),只能选择一种来描述。
if (is_newstyle_driver(driver)) {
if (driver->attach_adapter || driver->detach_adapter || driver->detach_client) {
printk(KERN_WARNING
"i2c-core: driver [%s] is confused\n",
driver->driver.name);
return -EINVAL;
}
}
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner; //模块所有者
driver->driver.bus = &i2c_bus_type; //挂上总线类型,他的定义在i2c_core.c中
static struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
.match = i2c_device_match,
.uevent = i2c_device_uevent,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
};
/* for new style drivers, when registration returns the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver); //注册设备到内核中
if (res)
return res;
mutex_lock(&core_lists); //互斥锁
//将driver->list加进drivers链表中(这条代码在2.6.25中失踪了)
list_add_tail(&driver->list,&drivers);
//打印信息
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* legacy drivers scan i2c busses directly */
//如果attach_adapter定义,则执行if。
//我们在ds1337_driver的声明中已经将该成员赋值为ds1337_attach_adapter
if (driver->attach_adapter) {
struct i2c_adapter *adapter; //定义一个I2C的适配器
// list_for_each_entry:第一个参数为传入的遍历指针,指向宿主数据结构,第二个参数为链表头,为list_head结构,第三个参数为list_head结构在宿主结构中的成员名。
//这里遍历了整个适配器,并调用adapter函数,要注意的是,设备注册进函数是在系统初始化或者模块加载的时候完成的。
list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter);
}
}
mutex_unlock(&core_lists); //解锁
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
接着我们看探测函数:driver->attach_adapter(adapter);
//这个函数除去一些保护检查代码外,就是最后一个循环的最后一个函数调用是实际起作用的:i2c_probe_address
static int ds1337_attach_adapter(struct i2c_adapter *adapter)
{
//注意这里的addr_data就是一开始我们分析参数的时候,宏
// I2C_CLIENT_INSMOD_1所声明的数组
return i2c_probe(adapter, &addr_data, ds1337_detect);
}
同样在i2c-core.c中找到他的实现:
int i2c_probe(
struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int))
{
int i, err;
int adap_id = i2c_adapter_id(adapter); //获取adapter->nr
//forces存在,所以这个if执行
if (address_data->forces) {
unsigned short **forces = address_data->forces;
int kind;
for (kind = 0; forces[kind]; kind++) {
//由于用I2C_CLIENT_MODULE_PARM定义时,forces全给定义成了I2C_CLIENT_END,所以这个for实际没用
for (i = 0; forces[kind][i] != I2C_CLIENT_END; i += 2) {
if (forces[kind][i] == adap_id
|| forces[kind][i] == ANY_I2C_BUS) {
dev_dbg(&adapter->dev, "found force "
"parameter for adapter %d, "
"addr 0x%02x, kind %d\n",
adap_id, forces[kind][i + 1],
kind);
err = i2c_probe_address(adapter,
forces[kind][i + 1],
kind, found_proc);
if (err)
return err;
}
}
}
}
/* Stop here if we can't use SMBUS_QUICK */
//又是一段检查用的代码
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
if (address_data->probe[0] == I2C_CLIENT_END
&& address_data->normal_i2c[0] == I2C_CLIENT_END)
return 0;
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
"can't probe for chips\n");
return -1;
}
//同上,probe都是I2C_CLIENT_END所以这里的代码都无意义
for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
if (address_data->probe[i] == adap_id
|| address_data->probe[i] == ANY_I2C_BUS) {
dev_dbg(&adapter->dev, "found probe parameter for "
"adapter %d, addr 0x%02x\n", adap_id,
address_data->probe[i + 1]);
err = i2c_probe_address(adapter,
address_data->probe[i + 1],
-1, found_proc);
if (err)
return err;
}
}
//由于normal_i2d有定义器件地址,所以这个循环执行
for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
int j, ignore;
ignore = 0;
//同样,这个循环也是不执行的
for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; j += 2) {
if ((address_data->ignore[j] == adap_id ||
address_data->ignore[j] == ANY_I2C_BUS)
&& address_data->ignore[j + 1]
== address_data->normal_i2c[i]) {
dev_dbg(&adapter->dev, "found ignore "
"parameter for adapter %d, "
"addr 0x%02x\n", adap_id,
address_data->ignore[j + 1]);
ignore = 1;
break;
}
}
if (ignore)
continue;
//打印信息
dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
"addr 0x%02x\n", adap_id,
address_data->normal_i2c[i]);
//调用探测地址函数
//可以说这个函数分析完了,也就这句代码是实际起作用的
err = i2c_probe_address(adapter, address_data->normal_i2c[i],
-1, found_proc);
if (err)
return err;
}
return 0;
}
EXPORT_SYMBOL(i2c_probe);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
static int i2c_probe_address(
struct i2c_adapter *adapter,
int addr, //设备地址
int kind, //-1
int (*found_proc) (struct i2c_adapter *, int, int))
{
int err;
/* Make sure the address is valid */
//检查地址是否合法
if (addr < 0x03 || addr > 0x77) {
dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
addr);
return -EINVAL;
}
/* Skip if already in use */
//检查适配器上是否已经有该地址(地址冲突)
if (i2c_check_addr(adapter, addr))
return 0;
/* Make sure there is something at this address, unless forced */
//i2c_smbus_xfer函数挖得有点深,这里先放一放
if (kind < 0) {
if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
I2C_SMBUS_QUICK, NULL) < 0)
return 0;
/* prevent 24RF08 corruption */
if ((addr & ~0x0f) == 0x50)
i2c_smbus_xfer(adapter, addr, 0, 0, 0,
I2C_SMBUS_QUICK, NULL);
}
/* Finally call the custom detection function */
err = found_proc(adapter, addr, kind); //回调传入的函数
//返回错误处理
if (err == -ENODEV)
err = 0;
if (err)
dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
addr, err);
return err;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
探测绕了一个弯,又绕回来了…
static int ds1337_detect(
struct i2c_adapter *adapter,
int address, //设备地址
int kind) //-1
{
struct i2c_client *new_client;
struct ds1337_data *data;
int err = 0;
const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_I2C))
goto exit;
//申请一块内存来保存设备自己的结构体
if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
INIT_LIST_HEAD(&data->list); //初始化设备链表
/* The common I2C client data is placed right before the
* DS1337-specific data.
*/
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &ds1337_driver;
new_client->flags = 0;
/* Default to an DS1337 if forced */
//将类型设置为ds1337, 之前传进来的类型kind = -1
if (kind == 0)
kind = ds1337;
if (kind < 0) { /* detection and identification */
u8 data;
/* Check that status register bits 6-2 are zero */
if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
(data & 0x7c))
goto exit_free;
//此处删除了一些代码,都是用ds1337_read读数据的
kind = ds1337;
}
if (kind == ds1337)
name = "ds1337";
/* We can fill in the remaining client fields */
strlcpy(new_client->name, name, I2C_NAME_SIZE);
/* Tell the I2C layer a new client has arrived */
//调用这个函数探测一个新的IIC设备
//由于我们现在只是分析应用,所以先不挖这个函数。
if ((err = i2c_attach_client(new_client)))
goto exit_free;
/* Initialize the DS1337 chip */
//初始化DS1337设备
ds1337_init_client(new_client);
/* Add client to local list */
list_add(&data->list, &ds1337_clients);
return 0;
exit_free:
kfree(data); //释放刚申请的内存
exit:
return err;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//初始化指定的设备
//这个函数主要展示了IIC读/写的函数调用
static void ds1337_init_client(struct i2c_client *client)
{
u8 status, control;
//读指定寄存器的值
status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
if ((status & 0x80) || (control & 0x80)) {
/* RTC not running */
……
i2c_transfer(client->adapter, msg, 1);
} else {
/* Running: ensure that device is set in 24-hour mode */
s32 val;
val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
if ((val >= 0) && (val & (1 << 6)))
i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
val & 0x3f);
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
卸载函数
static void __exit ds1337_exit(void)
{
i2c_del_driver(&ds1337_driver);
}
void i2c_del_driver(struct i2c_driver *driver)
{
struct list_head *item1, *item2, *_n;
struct i2c_client *client;
struct i2c_adapter *adap;
mutex_lock(&core_lists); //上锁
/* new-style driver? */
//如果是新的风格,则直接跳到卸载部分
if (is_newstyle_driver(driver))
goto unregister;
//旧的风格
list_for_each(item1, &adapters) { //遍历适配器
adap = list_entry(item1, struct i2c_adapter, list);
//调用自定义的释放函数
if (driver->detach_adapter) {
if (driver->detach_adapter(adap)) {
dev_err(&adap->dev, "detach_adapter failed "
"for driver [%s]\n",
driver->driver.name);
}
} else {
list_for_each_safe(item2, _n, &adap->clients) {
client = list_entry(item2, struct i2c_client, list);
if (client->driver != driver)
continue;
dev_dbg(&adap->dev, "detaching client [%s] "
"at 0x%02x\n", client->name,
client->addr);
if (driver->detach_client(client)) {
dev_err(&adap->dev, "detach_client "
"failed for client [%s] at "
"0x%02x\n", client->name,
client->addr);
}
}
}
}
//如果是新的风格,直接运行到这里
unregister:
driver_unregister(&driver->driver); //注销设备
list_del(&driver->list); //从链表中删除本选项
pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
mutex_unlock(&core_lists); //解锁
}
EXPORT_SYMBOL(i2c_del_driver);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
在卸载函数中调用
static int ds1337_detach_client(struct i2c_client *client)
{
int err;
struct ds1337_data *data = i2c_get_clientdata(client);
if ((err = i2c_detach_client(client)))
return err;
list_del(&data->list); //从链表中删除
kfree(data); //释放内存
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
OK,我们回头按顺序看看其他一些函数:
//从函数名我们就知道,这个是读函数
static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
{
//从寄存器中读数据
s32 tmp = i2c_smbus_read_byte_data(client, reg);
if (tmp < 0)
return -EIO; //出错
*value = tmp;
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//这两个函数是DS1337特有的命令函数,所以这里略过(实际要分析,也无非是按规格书上的方法从一些寄存器中读取数据)
static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//这个函数最大的问题就是,如何在用户层调用…..
static int ds1337_command(
struct i2c_client *client,
unsigned int cmd,
void *arg)
{
dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
switch (cmd) {
case DS1337_GET_DATE:
return ds1337_get_datetime(client, arg);
case DS1337_SET_DATE:
return ds1337_set_datetime(client, arg);
default:
return -EINVAL;
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int ds1337_do_command(int bus, int cmd, void *arg)
{
struct list_head *walk;
struct list_head *tmp;
struct ds1337_data *data;
list_for_each_safe(walk, tmp, &ds1337_clients) {
data = list_entry(walk, struct ds1337_data, list);
if (data->client.adapter->nr == bus)
return ds1337_command(&data->client, cmd, arg);
}
return -ENODEV;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
结束语:
经过对DS1337代码的初步分析,虽然还有很多地方不是很清楚,但是我们基本已经知道了该如何修改类似的驱动了:
1、 static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
改为具体设备对应的IIC地址
2、 I2C_CLIENT_INSMOD_1(ds1337);
将ds1337改为具体设备的名字,后面的ds1337也做对应的修改
3、 修改ds1337_command中响应的命令,类似于IOCTL
4、 修改ds1337_detect,探测IIC设备时的调用函数,去掉多余的东西,然后修改ds1337_init_client,写上对应的初始化寄存器代码。
OK,没了,简单吧?
不过还有一个大问题没解决,就是ds1337_command在用户层该如何调用,本来是想先改好一个程序在挖的,现在看来,只有提前挖了,不然真不知道这个命令该在哪调用。