| 还记得这句话吗? rtc_dev_prepare终于完了,现在回到rtc_device_register函数中。美好的时光总是短暂的,又到了一篇结束的时刻,就像灰太狼先生说的那样:“我还会回来的!”下篇见。
 现在灰太狼先生回来了。 1、接着回到rtc_device_register函数中,
 err = device_register(&rtc->dev);if (err)
 goto exit_kfree;
 直接看注释,就是把设备注册到设备模型中,即系统中。 /*** device_register - register a device with the system.
 * @dev: pointer to the device structure
 *
 * This happens in two clean steps - initialize the device
 * and add it to the system.
  */
 rtc_dev_add_device(rtc);这个函数在上一篇中提到了一此,对应那两个问题中的一个,还记得吗?如果忘记了,可以会过去查看。列出其源码:
 void rtc_dev_add_device(struct rtc_device *rtc){
 if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))看到这句,应该明白了吧?
 printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
 rtc->name, MAJOR(rtc_devt), rtc->id);
 else
 pr_debug("%s: dev (%d:%d)\n", rtc->name,
 MAJOR(rtc_devt), rtc->id);
 }
 rtc_sysfs_add_device(rtc);
 在Rtc-sysfs.c (linux2.6.28\drivers\rtc)文件中,对sysfs文件系统,我也不太懂,就不说了。rtc_proc_add_device(rtc);
 在Rtc-proc.c (linux2.6.28\drivers\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);
 }rtc_device_register函数到这里也就完了。
 
 回到s3c_rtc_probe函数中,接着看: /* register RTC and exit */rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
 THIS_MODULE);上面刚分析完。
 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;定义用户可以设备的最大频率,和TICK TIME定时器有关。
 
 
 /* check rtc time */检测RTC,基本原理就是,先读出寄存器 S3C2410_RTCSEC  和 寄存器S3C2410_RTCYEAR之间的每个寄存器,然后进行判断(判断条件相应的四位BCD码与9进行比较,因为四位BCD码不可能大于9,如果大于,肯定出错了,就清零。),在对相应的寄存器写0。看下面的图就更清楚了。
 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);这个函数在平台设备中也很常有,以前也有一篇博客讲过,这个函数。看下面:
 #define platform_set_drvdata(_dev,data)dev_set_drvdata(&(_dev)->dev, (data)) static inline void dev_set_drvdata(struct device *dev, void *data){
 dev->driver_data = data;应该明白了吧。
 }
 
 
 return 0;
 
 下面这些与错误处理有关。
 err_nortc:
 s3c_rtc_enable(pdev, 0);
 iounmap(s3c_rtc_base);
 
 
 err_nomap:
 release_resource(s3c_rtc_mem);
 
 
 err_nores:
 return ret;
 }
 
 现在s3c_rtc_probe函数也说完了,但对于RTC设备驱动来说,只是迈出了很小的一步,但不积硅步,无以至千里。 2、这两篇说的都是RTC平台设备的注册和对应的probe函数,相应的平台设备的注销函数和remove函数还没说,那相比于RTC平台设备的注册和对应的probe函数,就简单许多了。直接上源码:
 平台注销函数: static void __exit s3c_rtc_exit(void){
 platform_driver_unregister(&s3c2410_rtc_driver);
 }
 
 module_exit(s3c_rtc_exit);
 /*** platform_driver_unregister
 * @drv: platform driver structure
 */
 void platform_driver_unregister(struct platform_driver *drv)
 {
 driver_unregister(&drv->driver);
 }
 
 void driver_unregister(struct device_driver *drv){
 driver_remove_groups(drv, drv->groups);
 bus_remove_driver(drv);
 }
 
 相应的remove函数: static struct platform_driver s3c2410_rtc_driver = {.probe  = s3c_rtc_probe,
 .remove= s3c_rtc_remove,
 .suspend  = s3c_rtc_suspend,
 .resume  = s3c_rtc_resume,
 .driver  = {
 .name = "s3c2410-rtc",
 .owner  = THIS_MODULE,
 },
 };
 static int s3c_rtc_remove(struct platform_device *dev){
 struct rtc_device *rtc = platform_get_drvdata(dev);
 
 
 platform_set_drvdata(dev, NULL);
 rtc_device_unregister(rtc);
 
 
 s3c_rtc_setpie(&dev->dev, 0);
 s3c_rtc_setaie(0);
 
 
 iounmap(s3c_rtc_base);
 release_resource(s3c_rtc_mem);
 kfree(s3c_rtc_mem);
 
 
 return 0;
 }
 
 看到这些,是否觉得似曾相识?它们就像被分离的双胞胎一样,永远不能相见。各有各的职责,各有各的风采。 3、在讲顶层字符设备的注册时,说过RTC设备的设备好是在rtc_dev_init()函数中申请的,相应的释放也在对应的文件中。 Class.c (linux2.6.28\drivers\rtc)文件:
 subsys_initcall(rtc_init);module_exit(rtc_exit);
 
 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();
 rtc_sysfs_init(rtc_class);
 return 0;
 }
 
 static void __exit rtc_exit(void){
 rtc_dev_exit();
 class_destroy(rtc_class);
 }
 void __exit rtc_dev_exit(void){
 if (rtc_devt)
 unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
 }
 
 看到这应该明白了吧! 4、写到这里,注册和注销都已经讲完了,还是那句话,要走的路还有很长,看下面的结构体: struct rtc_class_ops {int (*open)(struct device *);
 void (*release)(struct device *);
 int (*ioctl)(struct device *, unsigned int, unsigned long);
 int (*read_time)(struct device *, struct rtc_time *);
 int (*set_time)(struct device *, struct rtc_time *);
 int (*read_alarm)(struct device *, struct rtc_wkalrm *);
 int (*set_alarm)(struct device *, struct rtc_wkalrm *);
 int (*proc)(struct device *, struct seq_file *);
 int (*set_mmss)(struct device *, unsigned long secs);
 int (*irq_set_state)(struct device *, int enabled);
 int (*irq_set_freq)(struct device *, int freq);
 int (*read_callback)(struct device *, int data);
 };
 
 这个结构的作用在s3c6410的RTC在linux中的驱动(1)有说明,它是底层与RTC设备模型的接口,它对应的实例是在Rtc-s3c.c (linux2.6.28\drivers\rtc) 文件中 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,
 };
 
 看到这么多函数,你应该明白我说的,我们的路还有很长要走。下篇再说。 
 |