RTC设备驱动
问题: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 <a.zummo@towertech.it>"); 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); ; } 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-.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; ; forces[kind]; kind++) { ; forces[kind][i] != I2C_CLIENT_END; i += ) { 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 + ], kind); err = i2c_probe_address(adapter, forces[kind][i + ], 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)) { ] == I2C_CLIENT_END && address_data->normal_i2c[] == I2C_CLIENT_END) ; dev_warn(&adapter->dev, "SMBus Quick command not supported, " "can't probe for chips\n"); ; } /* Probe entries are done second, and are not affected by ignore entries either */ ; address_data->probe[i] != I2C_CLIENT_END; i += ) { 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 + ]); err = i2c_probe_address(adapter, address_data->probe[i + ], -, found_proc); if (err) return err; } } /* Normal entries are done last, unless shadowed by an ignore entry */ //执行这部!通过i2c_probe_address函数来回调你编写的pcf8563_probe加载函数。 ; address_data->normal_i2c[i] != I2C_CLIENT_END; i += ) { int j, ignore; ignore = ; ; address_data->ignore[j] != I2C_CLIENT_END; j += ) { if ((address_data->ignore[j] == adap_id || address_data->ignore[j] == ANY_I2C_BUS) && address_data->ignore[j + ] == 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 + ]); ignore = ; 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], -, found_proc); if (err) return err; } ; } 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)) ; /* Make sure there is something at this address, unless forced */ ) { , , , I2C_SMBUS_QUICK, NULL) < ) ; /* prevent 24RF08 corruption */ if ((addr & ~0x0f) == 0x50) i2c_smbus_xfer(adapter, addr, , , , 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 = ; if (err) dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n", addr, err); return err; }
RTC设备驱动的更多相关文章
- 【Linux-驱动】RTC设备驱动架构
在Linux操作系统中,RTC设备驱动的架构如下图所示: RTC设备驱动涉及的文件:class.c.rtc-dev.c : 建立/dev/rtc0设备,同时注册相应的操作函数.interface.c ...
- Linux RTC设备驱动
1. 在Linux2.6.29内核中,RTC是以平台设备的方式注册进内核的. ① RTC驱动定义于文件:drivers/rtc/rtc-s3c.c static struct platform_dri ...
- linux设备驱动的分层设计思想--input子系统及RTC
转自:linux设备驱动的分层设计思想 宋宝华 http://blog.csdn.net/21cnbao/article/details/5615493 1.1 设备驱动核心层和例化 在面向对象的程序 ...
- Linux设备驱动中的软件架构思想
目录 更新记录 一.Linux驱动的软件架构 1.1 出发点 1.2 分离思想 1.3 分层思想 二.platform设备驱动 2.1 platform设备 2.2 platform驱动 2.3 pl ...
- S3C2440上RTC时钟驱动开发实例讲解(转载)
嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤.一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便.如有错误之处,谢请指正. 共享资源,欢迎转载:http:/ ...
- i2c设备驱动移植笔记(二)
说明:上一篇博客写了我在移植android驱动之TEF6606的苦逼遭遇,即驱动层向应用层提供接口支持,查找了两天的资料,不得不放弃,转而进行IIC下移植RTC设备的实验. 第一步:查找设备的数据手册 ...
- linux设备驱动归纳总结(十):1.udev&misc【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-111839.html linux设备驱动归纳总结(十):1.udev&misc xxxxxxx ...
- linux设备驱动归纳总结(七):1.时间管理与内核延时【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-100005.html linux设备驱动归纳总结(七):1.时间管理与内核延时 xxxxxxxxxxx ...
- linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-59416.html linux设备驱动归纳总结(三):1.字符型设备之设备申请 操作系统:Ubunru ...
随机推荐
- Linux下光盘镜像生成和刻录
mkiosfs命令如在/root/下有文件file1 file2 file3maiosfs -o img.ios file1 file2 file3该命令将file1 file2 file3放入到im ...
- 000 Excel获取数据
1.目标网址 http://data.10jqka.com.cn/funds/ggzjl/field/zjjlr 二:需求一 1.需求 爬单个页面的数据 2.变化网址 http://data.10jq ...
- Java 集合补充
集合大致可以分List,Set,Queue,Map四种体系. 集合和数组不一样,数组元素可以是基本类型的值,也可以是对象(的引用变量),集合里只能保存对象(的引用变量). 访问:如果访问List集合中 ...
- 【基础知识】C#数据库中主键类型的选择
主键在数据库中占有很大的地位,对于表的关联性,和数据的唯一识别性有重要的作用: 1,在C#开发中,Int自增字段和Guid(数据库中是uniqueidentifier类型)可设置为主键: 1>G ...
- [UOJ422]小Z的礼物
设要取的物品集合为$S$,$E=n(m-1)+(n-1)m$,$x_T$为覆盖了$T$中至少一个元素的$1\times2$数量 $$\begin{aligned}\sum\limits_{i=1}^\ ...
- 【扩展欧几里得】codevs1200-同余方程
[题目大意] 求关于 x 同余方程 ax ≡ 1 (mod b)的最小正整数解. [思路] 求解ax+by=1,只要x<0就不断加上 b. #include<iostream> #i ...
- C/C++ 之输入输出
因为C++向下兼容C,所以有多种输入输出的方式,cin/cout十分简洁,但个人觉得不如scanf/printf来的强大,而且在做算法题时,后者运行速度也快些. scanf/printf #inclu ...
- hdu 1208 记忆化搜索
题目大意:只能按照格子上的数字*方向走,从左上走到右下Sample Input42331121312313110Sample Output3 直接记忆化搜索,注意是0的情况 #include<c ...
- Codeforces Round #357 (Div. 2) B. Economy Game 水题
B. Economy Game 题目连接: http://www.codeforces.com/contest/681/problem/B Description Kolya is developin ...
- 网络服务器搭建的那些事(PV QPS Throughput) 转载
一.前言: 从事后台sever开发的同学,代码开发完成之后,上线之前,总会进行各种黑盒白盒测试,压测.正确性测试... 而测试同学,会给开发同学一份测试报告,需要开发同学进行确认...问题来了,里面好 ...