| 在上一篇中我们在中分析了RTC驱动的注册和注销,重点讲了平台设备驱动的probe函数,最后引出了这篇我们要讲解的内容,那就是下面这个结构体中的一些函数。 static const struct rtc_class_ops s3c_rtcops = { .open= s3c_rtc_open,.release  = s3c_rtc_release,
 .ioctl  = s3c_rtc_ioctl,
 .read_time  = s3c_rtc_gettime,
 .set_time  = s3c_rtc_settime,
 .read_alarm  = s3c_rtc_getalarm,
 .set_alarm  = s3c_rtc_setalarm,
 .irq_set_freq  = s3c_rtc_setfreq,
 .irq_set_state= s3c_rtc_setpie,
 .proc         = s3c_rtc_proc,
 };
 
 1、先来看open函数,此函数用来打开一个设备,再该函数中可以对设备进行初始化。s3c_rtc_open的主要作用就是申请了两个中断,函数源码如下: static int s3c_rtc_open(struct device *dev){
 struct platform_device *pdev = to_platform_device(dev);从device结构体得到平台设备platform_device
 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);从pdev->dev的私有数据中得到rtc_device
 int ret;
 
 ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
 IRQF_DISABLED,  "s3c2410-rtc alarm", rtc_dev);申请一个报警中断,将中断函数设为s3c_rtc_alarmirq,并传递rtc_dev作为参数。对于request_irq函数大家应该很熟悉,如下所示:
 /*** request_irq - allocate an interrupt line
 * @irq: Interrupt line to allocate
 * @handler: Function to be called when the IRQ occurs
 * @irqflags: Interrupt type flags
 * @devname: An ascii name for the claiming device
 * @dev_id: A cookie passed back to the handler function
 *  Flags:
 *
 * IRQF_SHAREDInterrupt is shared
 * IRQF_DISABLEDDisable local interrupts while processing
 * IRQF_SAMPLE_RANDOMThe interrupt can be used for entropy
 * IRQF_TRIGGER_*Specify active edge(s) or level
 *
 *int request_irq(unsigned int irq, irq_handler_t handler,
 unsigned long irqflags, const char *devname, void *dev_id)
 
 if (ret) {
 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
 return ret;
 }
 
 
 ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
 IRQF_DISABLED,  "s3c2410-rtc tick", rtc_dev);和上面一样,申请一个TICK中断,将中断函数设为 s3c_rtc_tickirq,并传递rtc_dev作为参数。
 
 if (ret) {
 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
 goto tick_err;
 }
 return ret;
 tick_err:
 free_irq(s3c_rtc_alarmno, rtc_dev);
 return ret;
 }
 
 2、接着看release函数,用户空间调用close时调用。s3c_rtc_release函数主要是释放两个中断,源码如下: static void s3c_rtc_release(struct device *dev){
 struct platform_device *pdev = to_platform_device(dev);
 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
 
 /* do not clear AIE here, it may be needed for wake */
 s3c_rtc_setpie(dev, 0);此函数用来设置是否允许TICK中断,第二个参数enabled等于1,表示允许,等于0,表示不允许。源码如下:
 static int s3c_rtc_setpie(struct device *dev, int enabled){
 pr_debug("%s: pie=%d\n", __func__, enabled);
 spin_lock_irq(&s3c_rtc_pie_lock);
 s3c_rtc_set_pie(s3c_rtc_base,enabled);
 void s3c_rtc_set_pie(void __iomem *base, uint to){
 unsigned int tmp;
 tmp = readw(base + S3C2410_RTCCON) & ~S3C_RTCCON_TICEN;先读出RTCCON寄存器。
 if (to)根据to的值,决定回写时的值。看下图:
 tmp |= S3C_RTCCON_TICEN;
 writew(tmp, base + S3C2410_RTCCON);
 ![]() }
 spin_unlock_irq(&s3c_rtc_pie_lock);
 return 0;
 }
 
 free_irq(s3c_rtc_alarmno, rtc_dev);释放中断s3c_rtc_alarmno
 free_irq(s3c_rtc_tickno, rtc_dev);
 /*** free_irq - free an interrupt
 * @irq: Interrupt line to free
 * @dev_id: Device identity to free
 
   void free_irq(unsigned int irq, void *dev_id) }
 3、接着看s3c_rtc_gettime函数,这里牵扯到一个结构体,如下所示: /** The struct used to pass data via the following ioctl. Similar to the
 * struct tm in <time.h>, but it needs to be here so that the kernel
 * source is self contained, allowing cross-compiles, etc. etc.
 */
 struct rtc_time {
 int tm_sec;秒
 int tm_min;
 int tm_hour;
 int tm_mday;
 int tm_mon;
 int tm_year;
 int tm_wday;RTC实时时钟中没用
 int tm_yday;同上
 int tm_isdst;同上
 };
 
 源码如下: /* Time read/write */static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 {
 unsigned int have_retried = 0;定义了一个重试变量,如果该变量为0,表示可能重新读取寄存器的值
 void __iomem *base = s3c_rtc_base;
 
 retry_get_time:
 rtc_tm->tm_min  = readb(base + S3C2410_RTCMIN);
 rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
 rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);
 rtc_tm->tm_mon  = readb(base + S3C2410_RTCMON);
 rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);
 rtc_tm->tm_sec  = readb(base + S3C2410_RTCSEC);
 
 /* the only way to work out wether the system was mid-update
 * when we read it is to check the second counter, and ifit
 * is zero, then we re-try the entire read这句在前面s3c6410硬件RTC(实时时钟)这篇博客中有讲述,可以回头去查看。如果秒寄存器为0,要重读。
 */
 if (rtc_tm->tm_sec == 0 && !have_retried) {
 have_retried = 1;
 goto retry_get_time;
 }
 
 pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
 
 rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
 rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
 rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
 rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
 rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
 rtc_tm->tm_year =bcd2bin(rtc_tm->tm_year);
 这个函数进行BCD到二进制的转化 unsigned bcd2bin(unsigned char val){
 return (val & 0x0f) + (val >> 4) * 10;
 }
 EXPORT_SYMBOL(bcd2bin);
 对应的二进制转化成BCDunsigned char bin2bcd(unsigned val)
 {
 return ((val / 10) << 4) + val % 10;
 }
 EXPORT_SYMBOL(bin2bcd);
 
 rtc_tm->tm_year += 100;
 rtc_tm->tm_mon -= 1;
 return 0;
 }
 
 注:存储器中存放的是从1900年开始的时间。 4、像s3c_rtc_getalarm和s3c_rtc_setalarm都和上面很类似,就不再所说了。下面这几个函数前两个也说过了,就剩最后一个了。 .irq_set_freq= s3c_rtc_setfreq,.irq_set_state = s3c_rtc_setpie,
 .proc        = s3c_rtc_proc,
 
 现在就来说s3c_rtc_proc函数。大家都知道,在proc文件系统中,可以读取proc文件来判断RTC实时时钟是否支持TICK中断。在读取proc文件中,会调用此函数。源码如下:
 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq){
 unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
 
 seq_printf(seq, "periodic_IRQ\t: %s\n",
 (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
 return 0;
 }
 
 看出什么问题了吗?问题出在S3C2410_TICNT和S3C2410_TICNT_ENABLE上。看一下数据手册就能马上明白,这个问题留给你? 
 |