当前位置:嗨网首页>书籍在线阅读

08-实例_S3C6410实时钟中断

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

10.3.4 实例:S3C6410实时钟中断

S3C6410处理器内部集成了实时钟(RTC)模块,该模块能够在系统断电的情况下由后备电池供电继续工作,其主要功能相对于一个时钟,记录年、月、日、时、分、秒等。S3C6410的RTC可产生两种中断:周期节拍(tick)中断和报警(alarm)中断,前者相当于一个周期性的定时器,后者相当于一个“闹钟”,它在预先设定的时间到来时产生中断。

S3C6410实时钟设备驱动(drivers/rtc/rtc-s3c.c,为S3C2410、S3C64XX、S5PC1XX、S5P64XX多种CPU共享)的open()函数中,会申请它将要使用的中断,如代码清单10.4所示。

代码清单10.4 S3C6410实时钟驱动open()函数

1 static int s3c_rtc_open(struct device *dev)

2 {

3 struct platform_device *pdev = to_platform_device(dev);

4 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);

5 int ret;

6 /申请alarm中断/

7 ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,

8 IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev);

9

10 if (ret) {

11 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);

12 return ret;

13 }

14

15 /申请tick中断/

16 ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,

17 IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev);

18

19 if (ret) {

20 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);

21 goto tick_err;

22 }

23

24 return ret;

25

26 tick_err:

27 free_irq(s3c_rtc_alarmno, rtc_dev);

28 return ret;

29 }

S3C6410实时钟设备驱动的release()函数中,会释放它将要使用的中断,如代码清单10.5所示。

代码清单10.5 S3C6410实时钟驱动release()函数

1 static void s3c_rtc_release(struct device *dev)

2 {

3 struct platform_device *pdev = to_platform_device(dev);

4 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);

5

6 s3c_rtc_setpie(dev, 0);

7 /释放中断/

8 free_irq(s3c_rtc_alarmno, rtc_dev);

9 free_irq(s3c_rtc_tickno, rtc_dev);

10 }

S3C6410实时钟驱动的中断处理比较简单,没有明确地分为上下两个半部,而只存在顶半部,如代码清单10.6所示。

代码清单10.6 S3C6410实时钟驱动中断处理程序

1 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)

2 {

3 struct rtc_device *rdev = id;

4

5 rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);

6

7 s3c_rtc_set_bit_byte(s3c_rtc_base,S3C2410_INTP,S3C2410_INTP_ALM);

8

9 return IRQ_HANDLED;

10 }

11

12 static irqreturn_t s3c_rtc_tickirq(int irq, void *id)

13 {

14 struct rtc_device *rdev = id;

15

16 rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);

17

18 s3c_rtc_set_bit_byte(s3c_rtc_base,S3C2410_INTP,S3C2410_INTP_TIC);

19

20 return IRQ_HANDLED;

21 }

上述代码中调用的rtc_update_irq()函数定义于drivers/rtc/interface.c文件中,被各种实时钟驱动共享,如代码清单10.7所示。

代码清单10.7 实时钟更新rtc_update_irq()函数

1 void rtc_update_irq(struct rtc_device *rtc,

2 unsigned long num, unsigned long events)

3 {

4 spin_lock(&rtc->irq_lock);

5 rtc->irq_data = (rtc->irq_data + (num << 8)) | events;

6 spin_unlock(&rtc->irq_lock);

7

8 spin_lock(&rtc->irq_task_lock);

9 if (rtc->irq_task)

10 rtc->irq_task->func(rtc->irq_task->private_data);

11 spin_unlock(&rtc->irq_task_lock);

12

13 wake_up_interruptible(&rtc->irq_queue);

14 kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);

15 }

上述中断处理程序并没有底半部(或者说没有严格意义上的tasklet、工作队列或软中断底半部),实际上,它只是唤醒一个等待队列rtc->irq_queue并发出一个SIGIO信号,而这个等待队列的唤醒也将导致一个阻塞的进程被执行(这个阻塞的进程可看作底半部)。现在我们看到,等待队列可以作为中断处理程序顶半部和进程同步的一种良好机制。但是,任何情况下,都不能在顶半部等待一个等待队列,而只能唤醒。