http://blog.csdn.net/angle_birds/article/details/17302297

Alarm就是一个硬件时钟,前面我们已经知道它提供了一个定时器,用于把设备从睡眠状态唤醒,同时它也提供了一个在设备睡眠时仍然会运行的时钟基准。在应用层上,有关时间的应用都需要Alarm的支持,源代码位于“drivers/rtc/alarm.c”。

  Alarm的设备名为“/dev/alarm”。该设备的实现非常简单,我们首先打开源码,可以看到include,其中定义了一些Alarm的相关信息。Alarm的类型枚举如下:

enum android_alarm_type {
    ANDROID_ALARM_RTC_WAKEUP,
    ANDROID_ALARM_RTC,
    ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
    ANDROID_ALARM_ELAPSED_REALTIME,
    ANDROID_ALARM_SYSTEMTIME,
    ANDROID_ALARM_TYPE_COUNT,
};

  主要包括了5种类型的Alarm,_WAKEUP类型表示在触发Alarm时需要唤醒设备,反之则不需要唤醒设备;ANDROID_ALARM_RTC类型表示在指定的某一时刻出发Alarm;ANDROID_ALARM_ELAPSED_REALTIME表示在设备启动后,流逝的时间达到总时间之后触发Alarm;ANDROID_ALARM_SYSTEMTIME类型则表示系统时间;ANDROID_ALARM_ TYPE_COUNT则是Alram类型的计数。

  注意 流逝的时间也包括设备睡眠的时间,流逝时间的计算点从它最后一次启动算起。

  Alarm返回标记的枚举类型如下:

enum android_alarm_return_flags {
    ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
    ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
    ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
                1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
    ANDROID_ALARM_ELAPSED_REALTIME_MASK =
                1U << ANDROID_ALARM_ELAPSED_REALTIME,
    ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
    ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
};

  Alarm返回标记会随着Alarm的类型而改变。最后还定义了一些宏,主要包括禁用Alarm、Alarm等待、设置Alarm等。下面我们来分析Alarm驱动的具体实现。

  首先,Alarm的初始化及退出由以下三个函数来完成:

  late_initcall(alarm_late_init);

  module_init(alarm_init);

  module_exit(alarm_exit);

  其中alarm_init函数对Alarm执行初始化操作,alarm_late_init需要在初始化完成之后进行调用,最后退出时需要调用alarm_exit来销毁和卸载Alarm接口及驱动。

1.alarm_init

  在初始化过程中,首先需要初始化系统时间,通过platform_driver_register函数来注册Alarm驱动的相关参数,具体如下所示:

static struct platform_driver alarm_driver = {
    .suspend = alarm_suspend,
    .resume = alarm_resume,
    .driver = {
        .name = "alarm"
    }
};

  该参数主要指定了当系统挂起(suspend)和唤醒(Desume)所需要实现的分别为alarm_suspend和alarm_resume,同时将Alarm设备驱动的名称设置为了“alarm”。

  如果设置正确,那么继续通过如下代码来初始化SUSPEND lock,因为在使用它们之前必须执行初始化操作。

  wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");

  wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");

  紧接着通过class_interface_register函数来注册Alarm接口信息,主要包括设备的添加和移除操作,内容如下:

static struct class_interface rtc_alarm_interface = {
    .add_dev = &rtc_alarm_add_device,
    .remove_dev = &rtc_alarm_remove_device,
};

  如果在此过程中出现错误,那么需要销毁已经注册的SUSPEND lock,并且卸载Alarm驱动,代码如下:

  wake_lock_destroy(&alarm_rtc_wake_lock);

  wake_lock_destroy(&alarm_wake_lock);

  platform_driver_unregister(&alarm_driver);

  注意 wake lock是一种锁机制,只要有用户持有该锁,系统就无法进入休眠状态,该锁可以被用户态程序和内核获得。这个锁可以是超时的或者是没有超时的,超时的锁会在时间过期以后自动解锁。如果没有锁或者超时了,内核就会启动休眠机制进入休眠状态,后面在讲电源管理时还会进一步讲解该机制。

 2.alarm_late_init

  当Alarm启动之后,我们需要读取当前的RCT和系统时间,由于需要确保在这个操作过程中不被中断,或者在中断之后能告诉其他进程该过程没有读取完成,不能被请求,因此这里需要通过spin_lock_irqsave和spin_unlock_irqrestore来对其执行锁定和解锁操作。实现代码如下:

static int __init alarm_late_init(void)
{
    unsigned long   flags;
    struct timespec system_time;
    spin_lock_irqsave(&alarm_slock, flags);
    getnstimeofday(&elapsed_rtc_delta);
    ktime_get_ts(&system_time);
    elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta, system_time);
    spin_unlock_irqrestore(&alarm_slock, flags);
    ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
"alarm_late_init: rtc to elapsed realtime delta %ld.%09ld\n",
        elapsed_rtc_delta.tv_sec, elapsed_rtc_delta.tv_nsec);
    return 0;
}

 3.alarm_exit

  当Alarm退出时,就需要通过class_interface_unregister函数来卸载在初始化时注册的Alarm接口,通过wake_lock_destroy函数来销毁SUSPEND lock,以及通过platform_driver_unregister函数来卸载Alarm驱动。实现代码如下:

static void  __exit alarm_exit(void)
{
    class_interface_unregister(&rtc_alarm_interface);
    wake_lock_destroy(&alarm_rtc_wake_lock);
    wake_lock_destroy(&alarm_wake_lock);
    platform_driver_unregister(&alarm_driver);
}

 4.添加和移除设备

  接下来是rtc_alarm_add_device和rtc_alarm_remove_device函数的实现。添加设备时,首先将设备转换成rtc_device类型,然后,通过misc_register函数将自己注册成为一个Misc设备。其包括的主要特性如下面的代码所示:

static struct file_operations alarm_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = alarm_ioctl,
    .open = alarm_open,
    .release = alarm_release,
};
static struct miscdevice alarm_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "alarm",
    .fops = &alarm_fops,
};

  其中alarm_device中的“.name”表示设备文件名称,而alarm_fops则定义了Alarm的常用操作,包括打开、释放和I/O控制。这里还需要通过rtc_irq_register函数注册一个rtc_task,用来处理Alarm触发的方法,其定义如下:

static struct rtc_task alarm_rtc_task = {
    .func = alarm_triggered_func
};

  其中“alarm_triggered_func”则是Alarm需要触发的方法。

  注意 如果在添加设备的过程中出现错误,我们需要对已经执行的操作进行释放、销毁和卸载。但是,移除一个设备时同样需要判断设备是否是Alarm设备,然后再执行卸载等操作。另外,在处理挂起操作时,我们首先就需要对设备进行锁定,然后根据Alarm的类型执行不同的操作,同时要保存时间。

  alarm_open和alarm_release的实现很简单。最后需要说明的是,对于I/O操作而言,主要需要实现:设置时间、设置RTC、获取时间、设置Alarm等待等。

  本小节主要对Android中最简单的设备驱动——Alarm的实现流程进行了分析,大家应该可以自己绘制出一个流程图来了吧。对于Alarm的具体实现,大家可以参考源代码“drivers/rtc/alarm.c”中的实现方式。

Alarm(硬件时钟) init的更多相关文章

  1. RTC硬件时钟设置修改【转】

    转自:http://os.chinaunix.net/a2008/0526/981/000000981211.shtml 这两天一直在做i2c设备驱动的理解,所以很少更新文章. 由于对于表计来说,RT ...

  2. Linux 系统时钟(date) 硬件时钟(hwclock)

    /********************************************************************* * Linux 系统时钟(date) 硬件时钟(hwclo ...

  3. Linux命令之hwclock - 查询和设置硬件时钟

    常用参数 -r, --show         读取并打印硬件时钟(read hardware clock and print result ) -s, --hctosys      将硬件时钟同步到 ...

  4. ntp/系统时钟/硬件时钟/双系统下计算机时间读取的问题

    http://blog.chinaunix.net/uid-182041-id-3464524.html       //linux系统时间和硬件时钟问题(date和hwclock) http://j ...

  5. linux系统时钟和硬件时钟不一致

    在做DB2 集群复制的时候要求两台主机时间相互一致. 但是在一台主机上系统时间和硬件时间相差12个小时左右:手动同步后,重启后又相差12个小时左右. 为什么会是这样的,先介绍下系统时钟和硬件时钟的区别 ...

  6. linux系统时间同步,硬件时钟和系统时间同步,时区的设置

           1.时间同步(手动): date -s "2015-07-15 22:13:30" hwclock --systohc   (表示系统时间同步到硬件时钟) hwclo ...

  7. Linux中有硬件时钟与系统时钟

    在Linux中有硬件时钟与系统时钟等两种时钟.硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟.系统时钟则是指kernel中的时钟.当Linux启动时,系统时钟会去读取硬件时钟的设 ...

  8. Linux系统时钟与硬件时钟

    linux系统有两个时钟:一个是由主板电池驱动的硬件时钟(Real Time Clock),也叫做RTC或者叫CMOS时钟.当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的: ...

  9. 使用hwclock同步RTC(硬件时钟)和OS Clock(操作系统时钟)

    Linux下面有个命令叫做hwclock,其主要的功能是用来在RTC和操作系统之间进行时钟同步.既可以将RTC的时钟同步到操作系统,也可以在通过hwclock将当前系统时间.Internet时间.本地 ...

随机推荐

  1. ASP.NET MVC Validation

    CHECKBOX http://stackoverflow.com/questions/4934032/mvc3-make-checkbox-required-via-jquery-validate ...

  2. 审计参数 audit_trail

      audit_trail参数定义了在哪里存放审计记录   默认是DB.如果将其设置为NONE,标准数据库审计功能被取消.audit_trail是静态参数,修改后必须重启数据库.   可以设置的值:- ...

  3. Swift游戏实战-跑酷熊猫 13 二段跳的实现

    这节内容我们来实现熊猫的二段跳. 要点: 二段跳的逻辑: 逻辑一,第一次点击屏幕,status就会变成jump. 逻辑二,第二次点击屏幕,status就会变成jump2. 逻辑三,当status变成j ...

  4. PostgreSQL Replication之第十二章 与Postgres-XC一起工作(3)

    12.3 配置一个简单的集群 在本章中,我们要建立一个由三个数据节点组成的集群.一个协调节点,以及管理集群的全局事务管理节点.对于每个组件,我们必须创建一个目录: hs@vm:~/data$ ls - ...

  5. Lintcode: Rotate String

    Given a string and an offset, rotate string by offset. (rotate from left to right) Example Given &qu ...

  6. SpringMvc:视图和视图解析器

    请求处理方法执行完成后,最终返回一个ModelAndView对象,对于返回String,View或ModelMap等类型的处理方法,SpringMvc也会在内部将它们装配成一个ModelAndView ...

  7. paper 37 : WINCE的BIB文件解析

    WINCE的BIB文件解析 BIB的全称为Binary Image Builder,在Wince编译过程中的最后MakeImage阶段会用到BIB文件,BIB文件的作用是指示构建系统如何构建二进制映像 ...

  8. C#语言基础2016/3/6

    一.  基础知识 输入输出 Console.Write();//输出语句,自动换行 Console.WriteLine();//输出语句 Console.WriteLine();输入语句 Consol ...

  9. zw版【转发·台湾nvp系列Delphi例程】HALCON AffineTransRegion

    zw版[转发·台湾nvp系列Delphi例程]HALCON AffineTransRegion unit Unit1;interfaceuses Windows, Messages, SysUtils ...

  10. JavaScript获取后台C#变量以及调用后台方法

    http://www.educity.cn/develop/495493.html 有时需要在JavaScript中获取后台变量的值,来判断JavaScript的执行逻辑,或者需要调用C#后台方法获取 ...