RTC设备驱动
时间:2010-04-07 来源:cao5170
问题:pcf8563 RTC设备驱动不能被正常的加载!问题分析过程。
问题在下午得到解决,虽然解决的办法比较笨,采用的是不断的使用printk来跟踪rtc-8563驱动的加载的过程,以及iic模块的工作过程。
曾经想过将内核的DEBUG打开,打开的方法在/linux2.6.21/include/linux/device.h文件中搜索DEBUG,这样的话,设备的所有的操作的debug信息都会输出,你会受不了,因为输出的无用的信息会掩盖你需要的真正的信息。
所以就改为在i2c-core.c和rtc-8563文件中加入printk调试信息来跟踪系统的信息输出。我们来分析一下rtc驱动的加载过程。
Linux驱动的i2c文件夹下有algos,busses,chips三个文件夹,另外还有i2c-core.c和i2c-dev.c两个文件。其中 i2c-core.c文件实现了I2C core框架,是Linux内核用来维护和管理的I2C的核心部分,其中维护了两个静态的List,分别记录系统中的I2C driver结构和I2C adapter结构。I2C core提供接口函数,允许一个I2C adatper,I2C driver和I2C client初始化时在I2C core中进行注册,以及退出时进行注销。同时还提供了I2C总线读写访问的一般接口,主要应用在I2C设备驱动中。
在rtc-8563文件中:
static int __init pcf8563_init(void)
{
return i2c_add_driver(&pcf8563_driver);
}
static void __exit pcf8563_exit(void)
{
i2c_del_driver(&pcf8563_driver);
}
MODULE_AUTHOR("Alessandro Zummo <[email protected]>");
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(pcf8563_init);
module_exit(pcf8563_exit);
从这里我们可以知道模块加载的初始化函数和卸载函数都是使用的i2c的框架函数i2c_add_driver和i2c_del_driver。
i2c_add_driver被定义在 include/linux/i2c.h文件中。其实质是i2c-core.c文件中的i2c_register_driver函数
该函数的原型如下:
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
struct list_head *item;
struct i2c_adapter *adapter;
int res;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
res = driver_register(&driver->driver);
if (res)
return res;
mutex_lock(&core_lists);
//将该driver的list成员加入到全局的drivers链表尾部,linux中大量存在这种链表的结构体
list_add_tail(&driver->list,&drivers);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* now look for instances of driver on our adapters */
if (driver->attach_adapter) {
//该函数搜索整个adapters链表,item指向每一个链表中的成员,这里实际是一个for循环。
// #define list_for_each(pos, head) \
// for (pos = (head)->next; prefetch(pos->next), pos //!=(head); pos = pos->next)
list_for_each(item,&adapters) {
//获得一个适配器结构体
adapter = list_entry(item, struct i2c_adapter, list);
driver->attach_adapter(adapter);
}
}
mutex_unlock(&core_lists);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
在这个函数中,首先向内核中注册你的驱动,然后锁信号量。。最关键的一步是:
driver->attach_adapter(adapter);
而attach_adapter就是在rtc-pcf8563.c文件中定义的重要的驱动结构体,定义如下。
static struct i2c_driver pcf8563_driver = {
.driver = {
.name = "pcf8563",
},
.id = I2C_DRIVERID_PCF8563,
.attach_adapter = &pcf8563_attach,
.detach_client = &pcf8563_detach,
};
所以也就是说i2c框架函数会回调你写的适配器加载函数,我们的适配器加载函数是pcf8563_attach函数。该函数定义如下:
static int pcf8563_attach(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, pcf8563_probe);
}
调用i2c框架函数i2c_probe来进行适配器的加载。
在下面这个函数中传递参数为
适配器变量:adapter。
i2c_client_address_data结构体原型
static struct i2c_client_address_data addr_data = { \
.normal_i2c = normal_i2c, \
.probe = probe, \
.ignore = ignore, \
.forces = forces, \
}
注意,在我们的rtc-8563.c文件中只定义了normal_i2c数组。
static unsigned short normal_i2c[] = { 0x51,I2C_CLIENT_END };
而出错的地方就在这里,原来的定义没有0x51这个成员,所以根本不去加载pcf8563这个器件。
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);
/* Force entries are done first, and are not affected by ignore
entries */
//为空,不执行
if (address_data->forces) {
unsigned short **forces = address_data->forces;
int kind;
for (kind = 0; forces[kind]; kind++) {
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 entries are done second, and are not affected by ignore
entries either */
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 entries are done last, unless shadowed by an ignore entry */
//执行这部!通过i2c_probe_address函数来回调你编写的pcf8563_probe加载函数。
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_printk(KERN_ERR ,&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;
}
i2c_probe_address的原型存在于i2c-core.c文件中:
static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
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 */
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 */
//这里回调你写的适配器加载函数pcf8563_probe,完成一个iic适配器的加载
err = found_proc(adapter, addr, kind);
/* -ENODEV can be returned if there is a chip at the given address
but it isn't supported by this chip driver. We catch it here as
this isn't an error. */
if (err == -ENODEV)
err = 0;
if (err)
dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
addr, err);
return err;
}
问题在下午得到解决,虽然解决的办法比较笨,采用的是不断的使用printk来跟踪rtc-8563驱动的加载的过程,以及iic模块的工作过程。
曾经想过将内核的DEBUG打开,打开的方法在/linux2.6.21/include/linux/device.h文件中搜索DEBUG,这样的话,设备的所有的操作的debug信息都会输出,你会受不了,因为输出的无用的信息会掩盖你需要的真正的信息。
所以就改为在i2c-core.c和rtc-8563文件中加入printk调试信息来跟踪系统的信息输出。我们来分析一下rtc驱动的加载过程。
Linux驱动的i2c文件夹下有algos,busses,chips三个文件夹,另外还有i2c-core.c和i2c-dev.c两个文件。其中 i2c-core.c文件实现了I2C core框架,是Linux内核用来维护和管理的I2C的核心部分,其中维护了两个静态的List,分别记录系统中的I2C driver结构和I2C adapter结构。I2C core提供接口函数,允许一个I2C adatper,I2C driver和I2C client初始化时在I2C core中进行注册,以及退出时进行注销。同时还提供了I2C总线读写访问的一般接口,主要应用在I2C设备驱动中。
在rtc-8563文件中:
static int __init pcf8563_init(void)
{
return i2c_add_driver(&pcf8563_driver);
}
static void __exit pcf8563_exit(void)
{
i2c_del_driver(&pcf8563_driver);
}
MODULE_AUTHOR("Alessandro Zummo <[email protected]>");
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(pcf8563_init);
module_exit(pcf8563_exit);
从这里我们可以知道模块加载的初始化函数和卸载函数都是使用的i2c的框架函数i2c_add_driver和i2c_del_driver。
i2c_add_driver被定义在 include/linux/i2c.h文件中。其实质是i2c-core.c文件中的i2c_register_driver函数
该函数的原型如下:
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
struct list_head *item;
struct i2c_adapter *adapter;
int res;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
res = driver_register(&driver->driver);
if (res)
return res;
mutex_lock(&core_lists);
//将该driver的list成员加入到全局的drivers链表尾部,linux中大量存在这种链表的结构体
list_add_tail(&driver->list,&drivers);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* now look for instances of driver on our adapters */
if (driver->attach_adapter) {
//该函数搜索整个adapters链表,item指向每一个链表中的成员,这里实际是一个for循环。
// #define list_for_each(pos, head) \
// for (pos = (head)->next; prefetch(pos->next), pos //!=(head); pos = pos->next)
list_for_each(item,&adapters) {
//获得一个适配器结构体
adapter = list_entry(item, struct i2c_adapter, list);
driver->attach_adapter(adapter);
}
}
mutex_unlock(&core_lists);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
在这个函数中,首先向内核中注册你的驱动,然后锁信号量。。最关键的一步是:
driver->attach_adapter(adapter);
而attach_adapter就是在rtc-pcf8563.c文件中定义的重要的驱动结构体,定义如下。
static struct i2c_driver pcf8563_driver = {
.driver = {
.name = "pcf8563",
},
.id = I2C_DRIVERID_PCF8563,
.attach_adapter = &pcf8563_attach,
.detach_client = &pcf8563_detach,
};
所以也就是说i2c框架函数会回调你写的适配器加载函数,我们的适配器加载函数是pcf8563_attach函数。该函数定义如下:
static int pcf8563_attach(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, pcf8563_probe);
}
调用i2c框架函数i2c_probe来进行适配器的加载。
在下面这个函数中传递参数为
适配器变量:adapter。
i2c_client_address_data结构体原型
static struct i2c_client_address_data addr_data = { \
.normal_i2c = normal_i2c, \
.probe = probe, \
.ignore = ignore, \
.forces = forces, \
}
注意,在我们的rtc-8563.c文件中只定义了normal_i2c数组。
static unsigned short normal_i2c[] = { 0x51,I2C_CLIENT_END };
而出错的地方就在这里,原来的定义没有0x51这个成员,所以根本不去加载pcf8563这个器件。
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);
/* Force entries are done first, and are not affected by ignore
entries */
//为空,不执行
if (address_data->forces) {
unsigned short **forces = address_data->forces;
int kind;
for (kind = 0; forces[kind]; kind++) {
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 entries are done second, and are not affected by ignore
entries either */
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 entries are done last, unless shadowed by an ignore entry */
//执行这部!通过i2c_probe_address函数来回调你编写的pcf8563_probe加载函数。
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_printk(KERN_ERR ,&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;
}
i2c_probe_address的原型存在于i2c-core.c文件中:
static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
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 */
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 */
//这里回调你写的适配器加载函数pcf8563_probe,完成一个iic适配器的加载
err = found_proc(adapter, addr, kind);
/* -ENODEV can be returned if there is a chip at the given address
but it isn't supported by this chip driver. We catch it here as
this isn't an error. */
if (err == -ENODEV)
err = 0;
if (err)
dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
addr, err);
return err;
}
相关阅读 更多 +
排行榜 更多 +