Linux时间子系统之(十七):ARM Generic Timer驱动代码分析
谈谈为 Linux 内核写驱动的编码规范

谈谈为 Linux 内核写驱动的编码规范最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离Linux内核的coding style要求还是差很多。
当初自己对内核文档里的CodingStyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周。
不过,在不遵守规则的程序员队伍里,我并不是孤独的。
如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的coding style,而且在很多驱动程序的TODO文件里,都会把"checkpatch.pl fixes"作为自己的目标之一(checkpatch.pl是用来检查代码是否符合coding style的脚本)。
不可否认,coding style是仁者见仁、智者见智的事情。
比如Microsoft所推崇的匈牙利命名法,在Linus看来就是及其脑残(brain damaged)的做法。
也许您并不赞成Linus制定的coding style,但在提交内核驱动这件事上,最好还是以大局为重。
对于这么一个庞大的集市式的开发来说,随意书写代码必将带来严重的可维护性的灾难。
(题图来自:mota.ru)一些辅助工具当代码量达到一定程度时,手动去检查和修改coding style是非常繁琐的工作,幸好,我们还有一些工具可以使用。
scripts/checkpatch.pl这是一个检查代码是否符合内核编码规范的的脚本。
顾名思义,checkpatch是用来检查patch的,默认的调用也确实如此。
如果用来检查原文件,需要加上“-f”的选项。
我们来看一段无聊的代码(文件名为print_msg.c):1.void print_msg(int a)2.{3. switch (a) {4. case 1:5. printf("a == 1\n");6. break;7.8. case 2:9. printf("a == 2\n");10. break;11. }12.}这段代码的coding style是否有问题呢?用checkpatch.pl来检查一下:1.scripts/checkpatch.pl -f print_msg.c检查的结果是:1.ERROR: switch and case should be at the same indent2.#3: FILE: switch.c:3:3.+ switch (a) {4.+ case 1:5.[...]6.+ case 2:7.8.total: 1 errors, 0 warnings, 12 lines checked9.10.switch.c has style problems, please review. If any of theseerrors11.are false positives report them to the maintainer, see12.CHECKPATCH in MAINTAINERS.在Linux内核的coding style里,switch和case要求有相同的缩进。
linux定时器编程

Linux内核中定义了一个timer_list结构,我们在驱动程序中可以利用之:
struct timer_list {
struct list_head list;
unsigned long expires; //定时器到期时间
unsigned long data; //作为参数被传入定时器处理函数
(4)在定时器到期时,function被执行;
(5)在程序中涉及timer控制的地方适当地调用del_timer、mod_timer删除timer或修改timer的expires。
我们可以参考drivers\char\keyboard.c中键盘的驱动中关于timer的部分:
…
#include <linux/timer.h>
rep = test_and_set_bit(keycode, key_down);
/* If the keyboard autorepeated for us, ignore it.
* We do our own autorepeat processing.
*/
if (rep && !autorepeat)
kbd_repeatkeycode = keycode;
if (vc_kbd_mode(kbd, VC_REPEAT)) {
if (rep)
key_autorepeat_timer.expires = jiffies + kbd_repeatinterval;
else
key_autorepeat_timer.expires = jiffies + kbd_repeattimeout;
return;
浅析Linux中的时间编程和实现原理,第3部分Linux内核的工作

浅析Linux 中的时间编程和实现原理,第 3 部分: Linux 内核的工作引子时间系统的工作需要软硬件以及操作系统的互相协作,在上一部分,我们已经看到大多数时间函数都依赖内核系统调用,GlibC 仅仅做了一次请求的转发。
因此必须深入内核代码以便了解更多的细节。
内核自身的正常运行也依赖于时钟系统。
Linux 是一个典型的分时系统,CPU 时间被分成多个时间片,这是多任务实现的基础。
Linux 内核依赖tick,即时钟中断来进行分时。
为了满足应用和内核自己的需求,内核时间系统必须提供以下三个基本功能:∙提供系统tick 中断(驱动调度器,实现分时)∙维护系统时间∙维护软件定时器目前的Linux 内核版本为 3.8,其时间系统比较复杂,复杂的原因来自几个方面:首先Linux 要支持不同的硬件体系结构和时钟电路,Linux 是一个通用操作系统,支持平台的多样性导致时间系统必须包含各种各样的硬件处理和驱动代码。
其次,早期Linux 的时钟实现采用低精度时钟框架(ms 级别),随着硬件的发展和软件需求的发展,越来越多的呼声是提高时钟精度(ns 级别);经过若干年的努力,人们发现无法在早期低精度时钟体系结构上优雅地扩展高精度时钟。
最终,内核采用了两套独立的代码实现,分别对应于高精度和低精度时钟。
这使得代码复杂度增加。
最后,来自电源管理的需求进一步增加了时间系统的复杂性。
Linux 越来越多地被应用到嵌入式设备,对节电的要求增加了。
当系统idle 时,CPU 进入节电模式,此时一成不变的时钟中断将频繁地打断CPU 的睡眠状态,新的时间系统必须改变以应对这种需求,在系统没有任务执行时,停止时钟中断,直到有任务需要执行时再恢复时钟。
以上几点,造成了内核时间系统的复杂性。
不过Linux 内核并不是从一开始就如此复杂,所以还是让我们从头说起吧。
回页首早期的Linux 时间系统在Linux 2.6.16 之前,内核只支持低精度时钟。
arm_generic_timer

1 关于ARM Generic timerARM通用timer提供一个系统计数器(system counter),测量真实的时间流;同时,也支持虚拟计数器(virtual counter),用于测量虚拟时间流;提供timer,当一段时间流逝后,产生系统事件,这些timer可以工作在自增或自减模式,也可以操作真实时间或虚拟时间。
1.1系统计数器系统计数器具有以下规范:(1)位宽(width),至少56位宽。
以64位方式读该值,返回0扩展后的64位值。
(2)频率,以固有频率增加,频率范围为1-50Mhz。
支持超过一个可选的工作模式,即可以选择在更低频率以更大的值自增;主要是为了功耗考虑。
(3)计数翻转(roll-over),计数翻转时间不少于40年。
(4)精度(accuracy),ARM没有指定一个必须的精度要求;到该计数值不能超过±(10sec/24hour)。
(5)启动(start-up),从零开始工作。
系统计数器必须提供统一的系统时间视图。
更确切地说,下面次序的时间展示的时间倒退是不可能发生的:(1)Device A从系统计数器读时间值;(2)Device A与系统中其他agent通信,Device B;(3)Device B收到Device A地信息后,再读该系统计数器。
另外,系统计数器必须位于不断电的域(always-on power domain)。
为了支持低功耗工作模式,计数器可以在更低频率,以更大数值自增。
比如,10Mhz 的系统计数器可能实现以下两种工作模式:(1)在10Mhz频率下,自增1;(2)在20Khz频率下,自增500;其工作频率下降后,可以降低功耗。
在这种情况下,计数器必须支持在高频率、高精度工作模式和低频率、低精度工作模式之间切换。
切换的过程中,不能影响计数器必要的精度。
软件可以访问CNTFRQ寄存器,读或者修改系统计数器的时钟频率。
系统计数器将计数值分发给其他系统组件的机制,在系统实现时确定。
Linux下时钟时区以及时间同步的命令和配置[整理]
![Linux下时钟时区以及时间同步的命令和配置[整理]](https://img.taocdn.com/s3/m/5efb9752b207e87101f69e3143323968011cf4a0.png)
Linux下时钟时区以及时间同步的命令和配置Linux下时钟时区以及时间同步的命令和配置=================================第一部分:设置时间=================================我们一般使用“date -s”命令来修改系统时间 (这里说的是系统时间,是linux由操作系统维护的。
)。
比如将系统时间设定成1996年6月10日的命令如下。
#date -s 06/10/96将系统时间设定成下午1点12分0秒的命令如下。
#date -s 13:12:00将日期时间设置成1996年6月10日下午1点12分0秒可以用#date -s "06/10/1996 13:12:00"这里的格式是 "MM/DD/YYYY hh:mm:ss"或者#date 061013121996.00这里的格式是MMDDhhmmYYYY.ss (月日时分年.秒)在系统启动时,Linux操作系统将时间从CMOS中读到系统时间变量中,以后修改时间通过修改系统时间实现。
为了保持系统时间与CMOS 时间的一致性, Linux每隔一段时间会将系统时间写入CMOS。
由于该同步是每隔一段时间(大约是11分钟)进行的,在我们执行date -s后,如果马上重起机器,修改时间就有可能没有被写入CMOS,这就是问题的原因。
如果要确保修改生效可以执行如下命令。
#hwclock -w这个命令强制把系统时间写入CMOS,(等同于hwclock --systohc)Linux将时钟分为系统时钟(System Clock)和硬件(Real Time Clock,简称RTC)时钟两种。
系统时间是指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的那个主板硬件时钟,这个时钟可以在BIOS的Standard BIOS Feture”项中进行设置。
在 Linux中,用于时钟查看和设置的命令主要有date、hwclock 和clock。
嵌入式linux arm时间同步方法

嵌入式linux arm时间同步方法嵌入式Linux ARM时间同步方法在嵌入式系统中,时间同步是非常重要的一个功能。
它可以确保系统中各个设备的时间一致,以便于各个模块之间的协同工作。
本文将介绍一些在嵌入式Linux ARM平台上实现时间同步的方法。
一、使用NTP协议进行时间同步NTP(Network Time Protocol)是一种用于同步网络中各个设备时间的协议。
在嵌入式Linux ARM系统中,可以通过安装和配置NTP服务器来实现时间同步。
具体步骤如下:1. 安装NTP服务器软件。
可以通过在终端中执行相应的命令来安装NTP服务器软件,例如在Debian系列系统中可以使用apt-get命令来安装。
2. 配置NTP服务器。
可以通过编辑配置文件/etc/ntp.conf来配置NTP服务器。
在配置文件中,需要指定一些NTP服务器的参数,例如要同步的时间服务器的地址等。
3. 启动NTP服务器。
在配置完成后,可以使用命令启动NTP服务器,例如在Debian系列系统中可以使用service命令来启动。
4. 配置客户端设备。
在每个需要同步时间的客户端设备上,需要配置NTP客户端。
可以通过编辑配置文件/etc/ntp.conf来配置NTP 客户端,指定要同步的时间服务器的地址。
5. 同步时间。
在配置完成后,可以使用命令手动同步时间,或者设置自动同步时间的策略。
一般情况下,NTP客户端会定期向NTP 服务器发送请求,以获取最新的时间信息。
二、使用PPS信号进行时间同步PPS(Pulse Per Second)信号是一种精确的时间信号,可以用于实现高精度的时间同步。
在嵌入式Linux ARM系统中,可以通过配置PPS信号来实现时间同步。
具体步骤如下:1. 配置GPIO引脚。
首先需要选择一个GPIO引脚,将其配置为输入模式,并连接到一个精确的时间源上,例如GPS模块的PPS输出引脚。
2. 配置内核。
在Linux内核中,需要配置相应的驱动程序来接收和处理PPS信号。
linux中timer表达式
linux中timer表达式Linux中的定时器表达式(Timer Expression)是一种用来设定在特定时间点或时间间隔执行任务的方法。
这种表达式在Linux系统中广泛应用于计划任务、调度任务和系统管理等方面。
在本文中,我们将详细解释Linux中的定时器表达式,并逐步回答有关其用法和原理的问题。
第一部分:什么是定时器表达式?定时器表达式是一种特殊的字符串格式,用于指定特定时间点或时间间隔来执行任务。
它可以精确指定年份、月份、日期、时间、周几等,提供了很高的灵活性。
第二部分:定时器表达式的基本格式定时器表达式通常由五个字段组成,分别为分钟、小时、日期、月份和周几。
这些字段用空格或通配符来分隔。
下面是一个定时器表达式的基本格式:[分钟] [小时] [日期] [月份] [周几]其中,每个字段都有自己的取值范围和特定的取值符号。
第三部分:定时器表达式的用法1. 字段取值符号- 通配符*:表示该字段可以取任意值。
- 逗号,:用于指定多个取值,例如"1,2,3" 表示取值为1、2 或3。
- 连字符-:用于指定一个范围内的取值,例如"1-5" 表示取值为1 到5。
- 斜线/:用于指定一个范围内的步长,例如"*/2" 表示每隔两个值取一个。
2. 字段取值范围- 分钟:0-59- 小时:0-23- 日期:1-31- 月份:1-12- 周几:0-7(其中0和7都表示周日)3. 示例下面是一些定时器表达式的示例,以帮助理解其用法:- 每小时的第五分钟执行任务:`5 * * * *`- 每天凌晨两点执行任务:`0 2 * * *`- 每周一的上午十点执行任务:`0 10 * * 1`- 每个月的第一天下午三点执行任务:`0 15 1 * *`以上示例都是使用具体的数值来指定执行任务的时间点,当然也可以使用取值符号来更灵活地设定表达式。
第四部分:定时器表达式的原理在Linux系统中,系统会定期检查当前时间和设定的定时器表达式,以确定是否需要执行相应的任务。
linux时钟综合编程总结
linux时钟综合编程总结Linux系统中的时钟编程是一个重要的主题,它涉及到系统时间的获取、设置以及与硬件的交互。
以下是对Linux时钟编程的综合总结:1.硬件时钟与系统时钟:1.硬件时钟(RTC):这是计算机主板上的石英晶体振荡器,它为计算机提供基本的计时基准。
2.系统时钟:这是运行在操作系统中的时钟,它通常与硬件时钟同步,但也可以独立设置。
2.时间表示:0.时间戳:自1970年1月1日(UTC)以来的秒数。
1.struct tm:表示本地时间,包含年、月、日、时、分、秒等信息。
3.获取当前时间:0.使用time()函数或clock_gettime()函数可以获取当前的时间戳。
1.使用localtime()或gmtime()函数可以将时间戳转换为struct tm格式。
4.设置系统时间:0.使用settimeofday()或clock_settime()函数可以设置系统时间。
这些函数需要root权限才能执行。
5.定时器与闹钟:0.Linux提供了几种定时器机制,如alarm()和setitimer()。
这些可以用来在未来的某个时间点执行某个任务。
6.时间同步:0.NTP(Network Time Protocol)是用于同步计算机系统时钟的标准协议。
Linux提供了ntpd和chronyd等工具来使用NTP进行时间同步。
7.注意事项:0.修改系统时间可能会影响依赖于此时间的服务或应用程序。
在修改系统时间之前,请确保了解潜在的影响。
1.始终从可靠的源获取时间,以避免由于时间漂移而造成的问题。
8.工具与命令:0.date:用于显示或设置系统日期和时间的命令。
1.hwclock:用于读取和设置硬件时钟的命令。
9.高级话题:0.内核时钟:内核内部使用的时钟,与硬件时钟关联,但可以在不与硬件交互的情况下进行操作。
1.实时时钟(RTC)驱动:这是与硬件RTC交互的底层驱动,通常不直接与应用程序开发人员交互,但了解其工作原理对于深入理解系统时间是很有帮助的。
linux timer用法
linuxtimer用法Linux操作系统提供了丰富的定时器功能,通过使用Linux定时器,可以轻松地实现定时任务、周期性执行的操作等。
本文将介绍Linux定时器的用法,包括定时器的类型、创建、使用和销毁等。
一、定时器类型Linux定时器可以分为以下几种类型:1.软定时器:软定时器是一种基于时间的定时器,可以通过系统调用实现定时任务。
软定时器的时间单位可以是秒、毫秒、微秒等,可以根据实际需求选择合适的单位。
2.硬定时器:硬定时器是一种基于内核定时器的定时器,可以通过内核提供的定时器接口实现周期性执行的操作。
硬定时器的精度较高,可以根据实际需求选择合适的精度。
二、创建定时器创建定时器可以通过系统调用来实现,具体方法如下:1.软定时器创建:可以使用`timer_create()`函数创建一个软定时器,该函数需要指定定时器的名称、指向定时器回调函数的指针、定时器的超时时间等信息。
创建成功后,会返回一个定时器的标识符,可以使用该标识符来控制定时器的执行。
2.硬定时器创建:可以使用`timer_create()`函数创建一个硬定时器,该函数需要指定定时器的名称、指向定时器回调函数的指针、定时器的起始时间等信息。
创建成功后,内核会根据指定的精度周期性地执行回调函数。
三、使用定时器创建了定时器后,需要使用该标识符来控制定时器的执行。
可以使用`timer_set_state()`函数来设置定时器的状态为运行或停止。
可以使用`timer_start()`函数来启动定时器,使定时器进入运行状态;可以使用`timer_try_stop()`函数来尝试停止当前运行的定时器。
需要注意的是,硬定时器不能被取消或延迟执行,只能被重新设置起始时间。
四、销毁定时器定时器执行完毕或不再需要时,需要销毁该定时器。
可以使用`timer_delete()`函数来销毁软定时器,使用`timer_delete(timerfd)`函数来销毁硬定时器。
linux定时器原理
linux定时器原理Linux定时器是Linux操作系统中的一种机制,用于实现在指定时间间隔内执行特定任务的功能。
本文将介绍Linux定时器的原理和工作方式。
一、概述在现代操作系统中,定时器是一项重要的功能。
它可以用于定时执行任务,例如周期性地刷新屏幕、定时发送网络数据包等。
Linux 内核提供了多种定时器机制,其中最常用的是基于时钟事件的定时器。
二、基于时钟事件的定时器Linux内核通过时钟事件来触发定时器的执行。
时钟事件是由硬件时钟产生的,它以固定的频率中断处理器的正常执行流程。
Linux 内核会注册一个中断处理函数来处理时钟事件,并在每次时钟中断时调用该函数。
三、内核定时器APILinux内核提供了一组函数和数据结构,用于管理定时器。
其中最重要的是`timer_create()`、`timer_settime()`和`timer_delete()`函数。
`timer_create()`函数用于创建一个新的定时器,`timer_settime()`函数用于设置定时器的参数和启动定时器,`timer_delete()`函数用于删除定时器。
四、定时器的创建和设置要创建一个定时器,首先需要定义一个`timer_t`类型的变量来存储定时器的ID。
然后使用`timer_create()`函数来创建定时器,并将定时器ID保存在该变量中。
接下来,可以使用`timer_settime()`函数来设置定时器的参数,如定时器的初始时间和间隔时间。
五、定时器的工作原理当定时器被设置并启动后,内核会在每次时钟中断时检查定时器是否到期。
如果定时器到期,则会触发定时器的回调函数。
定时器的回调函数是在内核上下文中执行的,因此需要注意避免使用可能会导致死锁或竞争条件的操作。
六、定时器的删除当不再需要定时器时,可以使用`timer_delete()`函数来删除定时器。
删除定时器后,内核会停止触发定时器的回调函数。
七、定时器的应用Linux定时器在很多场景下都有广泛的应用。