Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48975
  • 博文数量: 8
  • 博客积分: 176
  • 博客等级: 入伍新兵
  • 技术积分: 85
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-27 08:58
文章分类

全部博文(8)

文章存档

2016年(1)

2015年(1)

2011年(3)

2009年(3)

我的朋友

分类:

2011-03-22 15:56:27

1.s3c_rtc_probe
  • 从platform_resource中获取中断号:tickno,alarmno
  • 从platform_resource中获取rtc寄存器对应的内存区域,并初始化该区域,通过request_meme_region,ioremap
  • s3c_rtc_enable:
  • s3c_rtc_setfreq:

    s3c2440的datasheet中是这样描述的:

    The count value reaches '0' when the tick time interrupt occurs. Then the period of interrupt is as follows:
— Period = ( n+1 ) / 128 second
— n: Tick time count value (1~127)

    此处n设置为127,所以tick的中断周期是1秒。

  • device_init_wakeup

    用于cpu休眠及唤醒,还没来得及仔细研究。

  • rtc_device_register:对rtc_device进行初始化并注册,后面详细展开
  • platform_set_drvdata:

    platform_device->device->device_private->driver_data = rtc_device

    把platform_device的一个专用指针指向rtc_device。嵌套了很多层,现在先不管他,以后分析platform框架的时候再考虑。

2.rtc_device_register

  • 初始化idr:

    Small id to pointer translation service.就是给某个数据结构分配一个id,通过这个id就能找到这个数据结构的地址。先不管他。

  • 初始化rtc_device的各个结构成员,并使platform_device作为他的父设备。
  • rtc_dev_prepare:更进一步的初始化,稍后讨论。
  • rtc_dev_add_device:添加rtc对应的字符设备,该字符设备已经在rtc_dev_prepare中初始化完毕。

    cdev_add(&rtc->char_dev, rtc->dev.devt, 1)

  • rtc_sysfs_add_device

    这里只涉及了一个属性的添加:dev_attr_wakealarm,没搞明白,稍后还要再看看是怎么回事。@这里涉及到class.c这个文件:

subsys_initcall(rtc_init);

rtc_init负责初试化rtc_class,以及调用rtc_sysfs_init,此处会加载rtc_attrs属性到rtc_class中。

subsys_initcall将rtc_init标记为“初始化段”的一部分,编译器会把他放进该段,而在系统初始化的时候,会调用初始化段里的函数,因此,在rtc的驱动模块之前,rtc_attrs这些通用属性就已经加载完毕了。

  • rtc_proc_add_device

    在proc文件系统中添加driver/rtc文件。

3.rtc_dev_prepare

  • 注册设备号:rtc_device->dev.devt
  • UIE(update interrupt enable)相关初始化

INIT_WORK(&rtc->uie_task, rtc_uie_task);
setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);

uie部分负责及时更新rtc_device->irq_data,每当经过一秒钟,就在irq_data中记录相应的信息,包括经过的秒数、更新类型(UIE、PIE、AIE)。

这主要通过一个工作队列(uie_task)和一个定时器(uie_timer)完成。最开始,task不断调用自己(schedule_work(&rtc->uie_task))进行轮询,从rtc中读取秒数值,与之前保存的rtc_device->oldsecs对比,如果不一样,就说明经过了至少一秒钟,于是task就停止轮询,并启用定时器,将其延时设为一个不到1秒钟的间隔,而定时器负责启用task轮询。这样,在这个时间间隔内,就不需要再进行轮询了。

static void rtc_uie_task(struct work_struct *work)
{
 struct rtc_device *rtc =
  container_of(work, struct rtc_device, uie_task);
 struct rtc_time tm;
 int num = 0;
 int err;

 err = rtc_read_time(rtc, &tm);

 spin_lock_irq(&rtc->irq_lock);
 if (rtc->stop_uie_polling || err) {
  rtc->uie_task_active = 0;
 } else if (rtc->oldsecs != tm.tm_sec) {    //如果经过了至少1秒,则启用定时器

  num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;   //究竟经过了多少秒
  rtc->oldsecs = tm.tm_sec;
  rtc->uie_timer.expires = jiffies + HZ - (HZ/10);   //定时器延时设置为将近1秒钟:jiffies+Hz = 1s
  rtc->uie_timer_active = 1;
  rtc->uie_task_active = 0;
  add_timer(&rtc->uie_timer);
 } else if (schedule_work(&rtc->uie_task) == 0) {    //如果没有到达1秒,就不断轮询
  rtc->uie_task_active = 0;
 }
 spin_unlock_irq(&rtc->irq_lock);
 if (num)
  rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
}
static void rtc_uie_timer(unsigned long data)
{
 struct rtc_device *rtc = (struct rtc_device *)data;
 unsigned long flags;

 spin_lock_irqsave(&rtc->irq_lock, flags);
 rtc->uie_timer_active = 0;
 rtc->uie_task_active = 1;
 if ((schedule_work(&rtc->uie_task) == 0))    //重新启用task进行轮询
  rtc->uie_task_active = 0;
 spin_unlock_irqrestore(&rtc->irq_lock, flags);
}

阅读(1723) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~