| 上一篇说到了s3c_rtc_probe函数,但由于太长,而没有说完,这一篇接着上一篇的说。 说完了这个函数就可以回到s3c_rtc_probe函数接着说了,下篇再聊。还记的这句话吗?现在接着聊:pr_debug("s3c2410_rtc: RTCCON=%02x\n",
 readb(s3c_rtc_base + S3C2410_RTCCON));调试信息
 
 
 s3c_rtc_setfreq(&pdev->dev, 1);RTC设置频率函数,周期公式为: Then the period of interrupt is as follows:Period = (n+1)/32768 second (n= tick counter value)
 则频率freq=32768/(n+1) 其中n为TICNT寄存器,看下图: ![]() 
 static int s3c_rtc_setfreq(struct device *dev, int freq){
 spin_lock_irq(&s3c_rtc_pie_lock);
 
 s3c_rtc_set_freq_regs(s3c_rtc_base, freq, s3c_rtc_freq);
 void s3c_rtc_set_freq_regs(void __iomem *base, uint freq, uint s3c_freq)这个参数没用到{
 unsigned int tmp;
 tmp = readw(base + S3C2410_RTCCON) & (S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN );
 writew(tmp, base + S3C2410_RTCCON);
 s3c_freq = freq;
 tmp = (32768 / freq)-1;
 writel(tmp, base + S3C2410_TICNT);看上面的图,就是那个寄存器。
 }
 
 spin_unlock_irq(&s3c_rtc_pie_lock);
 return 0;
 }
 在此回到s3c_rtc_probe函数中。
 
 device_init_wakeup(&pdev->dev, 1);
 /* register RTC and exit */
 rtc =rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,THIS_MODULE);
 RTC必须要注册到内核中才能使用,这个是在RTC驱动模型中说过的这个函数的作用,如果不清楚,可以回过去查看。现在具体看下这个函数的源码:
 /*** rtc_device_register - register w/ RTC class
 * @dev: the device to register
 *
 * rtc_device_unregister() must be called when the class device is no
 * longer needed.
 *
 * Returns the pointer to the new struct class device.这个函数的返回值是个struct rtc_device结构的指针。
 */当看到一个新函数,如果不明白,就可以先看它的注释。
 struct rtc_device *rtc_device_register(const char *name, struct device *dev,
 const struct rtc_class_ops *ops,
 struct module *owner)
 {
 先看出传入的参数中的const struct rtc_class_ops结构指针,实参为: 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,
 };在Rtc-s3c.c (linux2.6.28\drivers\rtc)文件中定义,这样RTC设备模型就和具体的RTC设备联系起来了。
 struct rtc_device *rtc;
 int id, err;
 
 if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
 err = -ENOMEM;
 goto exit;
 }分配一个ID号,用来把一个数字与一个指针联系起来
 
 mutex_lock(&idr_lock);
 err = idr_get_new(&rtc_idr, NULL, &id);得到一个ID号,不太懂。
 mutex_unlock(&idr_lock);
 if (err < 0)
 goto exit;
 id = id & MAX_ID_MASK;
 
 
 rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
 if (rtc == NULL) {
 err = -ENOMEM;
 goto exit_idr;
 }分配一个RTC设备结构体struct rtc_device
 
 
 rtc->id = id;
 rtc->ops = ops;
 rtc->owner = owner;
 rtc->max_user_freq = 64;
 rtc->dev.parent = dev;
 rtc->dev.class = rtc_class;
 rtc->dev.release = rtc_device_release;
 初始化struct rtc_device结构体,用户可以设置的最大频率为64,下面是struct rtc_device结构体的原型:
 structrtc_device{
 struct device dev;
 struct module *owner;
 int id;
 char name[RTC_DEVICE_NAME_SIZE];
 const struct rtc_class_ops *ops;
 struct mutex ops_lock;
 struct cdev char_dev;
 unsigned long flags;
 
 unsigned long irq_data;
 spinlock_t irq_lock;
 wait_queue_head_t irq_queue;
 struct fasync_struct *async_queue;
 
 
 struct rtc_task *irq_task;
 spinlock_t irq_task_lock;
 int irq_freq;
 int max_user_freq;
 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
 struct work_struct uie_task;
 struct timer_list uie_timer;
 /* Those fields are protected by rtc->irq_lock */
 unsigned int oldsecs;
 unsigned int irq_active:1;
 unsigned int stop_uie_polling:1;
 unsigned int uie_task_active:1;
 unsigned int uie_timer_active:1;
 #endif
 };
 
 mutex_init(&rtc->ops_lock);
 spin_lock_init(&rtc->irq_lock);
 spin_lock_init(&rtc->irq_task_lock);
 init_waitqueue_head(&rtc->irq_queue);
 strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
 snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id);
 
 
 rtc_dev_prepare(rtc);
 
 /* insertion/removal hooks */void rtc_dev_prepare(struct rtc_device *rtc)
 {
 if (!rtc_devt)
 return;
 
 if (rtc->id >= RTC_DEV_MAX) {
 pr_debug("%s: too many RTC devices\n", rtc->name);
 return;
 }
 
 
 rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
 
 
 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
 INIT_WORK(&rtc->uie_task, rtc_uie_task);
 setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
 #endif
 
 
 cdev_init(&rtc->char_dev, &rtc_dev_fops);看到这个函数应该很熟悉,这个是字符设备驱动中常用的函数,可是你有没有觉得少了点什么?设备号在什么时候申请的?而且没有cdev_add函数?
 现在回答第一个问题——设备号在什么时候申请的? 大家还记得在第一篇中的/drivers/rtc/class.c这个文件吗? 有如下代码: subsys_initcall(rtc_init);
 static int __init rtc_init(void){
 rtc_class = class_create(THIS_MODULE, "rtc");
 if (IS_ERR(rtc_class)) {
 printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
 return PTR_ERR(rtc_class);
 }
 rtc_class->suspend = rtc_suspend;
 rtc_class->resume = rtc_resume;
 rtc_dev_init();重点来了。请关注:
 void __init rtc_dev_init(void){
 int err;
 
 
 err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
 if (err < 0)
 printk(KERN_ERR "%s: failed to allocate char dev region\n",
 __FILE__);
 }看到了吗?设备号在这里申请的。
 rtc_sysfs_init(rtc_class);
 return 0;
 }
 
 而且没有 其中函数实参为,在/drivers/rtc/rtc-dev.c文件中定义。 static const struct file_operations rtc_dev_fops = {.owner  = THIS_MODULE,
 .llseek  = no_llseek,
 .read = rtc_dev_read,
 .poll = rtc_dev_poll,
 .unlocked_ioctl= rtc_dev_ioctl,
 .open = rtc_dev_open,
 .release  = rtc_dev_release,
 .fasync  = rtc_dev_fasync,
 };
 rtc->char_dev.owner = rtc->owner;
 }
 rtc_dev_prepare终于完了,现在回到rtc_device_register函数中。美好的时光总是短暂的,又到了一篇结束的时刻,就像灰太狼先生说的那样:“我还会回来的!”下篇见。
 
 err = device_register(&rtc->dev);
 if (err)
 goto exit_kfree;
 
 
 rtc_dev_add_device(rtc);
 rtc_sysfs_add_device(rtc);
 rtc_proc_add_device(rtc);
 
 
 dev_info(dev, "rtc core: registered %s as %s\n",
 rtc->name, rtc->dev.bus_id);
 
 
 return rtc;
 
 
 exit_kfree:
 kfree(rtc);
 
 
 exit_idr:
 mutex_lock(&idr_lock);
 idr_remove(&rtc_idr, id);
 mutex_unlock(&idr_lock);
 
 
 exit:
 dev_err(dev, "rtc core: unable to register %s, err = %d\n",
 name, err);
 return ERR_PTR(err);
 }
 
 if (IS_ERR(rtc)) {
 dev_err(&pdev->dev, "cannot attach rtc\n");
 ret = PTR_ERR(rtc);
 goto err_nortc;
 }
 
 
 rtc->max_user_freq = S3C_MAX_CNT;
 
 
 /* check rtc time */
 for (bcd_loop = S3C2410_RTCSEC ; bcd_loop <= S3C2410_RTCYEAR ; bcd_loop +=0x4)
 {
 bcd_tmp = readb(s3c_rtc_base + bcd_loop);
 if(((bcd_tmp & 0xf) > 0x9) || ((bcd_tmp & 0xf0) > 0x90))
 writeb(0, s3c_rtc_base + bcd_loop);
 }
 
 
 platform_set_drvdata(pdev, rtc);
 
 
 return 0;
 
 
 err_nortc:
 s3c_rtc_enable(pdev, 0);
 iounmap(s3c_rtc_base);
 
 
 err_nomap:
 release_resource(s3c_rtc_mem);
 
 
 err_nores:
 return ret;
 }
 
 |