• Linux RTC设备驱动


    1. 在Linux2.6.29内核中,RTC是以平台设备的方式注册进内核的。

    ① RTC驱动定义于文件:drivers/rtc/rtc-s3c.c

    static struct platform_driver s3c2410_rtc_driver = {
        .probe        = s3c_rtc_probe,
        .remove        = __devexit_p(s3c_rtc_remove),
        .suspend    = s3c_rtc_suspend,
        .resume        = s3c_rtc_resume,
        .driver        = {
            .name    = "s3c2410-rtc",
            .owner    = THIS_MODULE,
        },
    };

    ② RTC平台资源定义于:arch/arm/plat-s3c24xx/devs.c

    static struct resource s3c_rtc_resource[] = {
        [0] = {
            .start = S3C24XX_PA_RTC,
            .end   = S3C24XX_PA_RTC + 0xff,
            .flags = IORESOURCE_MEM,
        },
        [1] = {
            .start = IRQ_RTC,
            .end   = IRQ_RTC,
            .flags = IORESOURCE_IRQ,
        },
        [2] = {
            .start = IRQ_TICK,
            .end   = IRQ_TICK,
            .flags = IORESOURCE_IRQ
        }
    };
    
    struct platform_device s3c_device_rtc = {
        .name          = "s3c2410-rtc",
        .id          = -1,
        .num_resources      = ARRAY_SIZE(s3c_rtc_resource),
        .resource      = s3c_rtc_resource,
    };

    ③ 当RTC设备驱动匹配到名字为“s3c2410-rtc”的设备时,会调用probe函数s3c_rtc_probe()

    static int __devinit s3c_rtc_probe(struct platform_device *pdev)
    {
        struct rtc_device *rtc;
        struct resource *res;
        int ret;/* find the IRQs */
        s3c_rtc_tickno = platform_get_irq(pdev, 1);
        s3c_rtc_alarmno = platform_get_irq(pdev, 0);
       /* get the memory region */
        s3c_rtc_mem = request_mem_region(res->start,
                         res->end-res->start+1,
                         pdev->name);
    
        s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);/* check to see if everything is setup correctly */
        
    s3c_rtc_enable(pdev,
    1); s3c_rtc_setfreq(&pdev->dev, 1); device_init_wakeup(&pdev->dev, 1); /* register RTC and exit */ rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops, THIS_MODULE); rtc->max_user_freq = 128; platform_set_drvdata(pdev, rtc); return 0;

    (1) s3c_rtc_probe()函数分析1: 获取平台资源(中断号和IO内存),然后记录中断号,进行IO内存映射。

    (2) s3c_rtc_probe()函数分析2: 调用rtc_device_register()函数,分配RTC的设备描述结构rtc_device,并填充其成员,然后进行设备注册(注册字符设备,注册进proc系统,注册进sys系统)

    (3) s3c_rtc_probe()函数分析3: 保存RTC设备描述结构到平台设备驱动的dev域。

    注: RTC的设备描述结构rtc_device是device结构的扩展,描述一个具体的RTC设备。

    ⑤ rtc_device_register()函数分析:

    struct rtc_device *rtc_device_register(const char *name, struct device *dev,
                        const struct rtc_class_ops *ops,
                        struct module *owner)
    {
        struct rtc_device *rtc;
        int id, err;
    
        if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
            err = -ENOMEM;
            goto exit;
        }
    
        mutex_lock(&idr_lock);
        err = idr_get_new(&rtc_idr, NULL, &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->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;
    
        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);
        dev_set_name(&rtc->dev, "rtc%d", id);
    
        rtc_dev_prepare(rtc);
    
        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
    ",
                rtc->name, dev_name(&rtc->dev));
    
        return rtc;
    
    }

    (1) 为RTC设备描述结构(rtc_device)分配空间,并填充相关成员。

    (2) 通过rtc_dev_prepare()函数填充RTC字符设备的主设备号和操作函数集rtc_dev_fops

    void rtc_dev_prepare(struct rtc_device *rtc)
    {
        rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
    
        cdev_init(&rtc->char_dev, &rtc_dev_fops);
        rtc->char_dev.owner = rtc->owner;
    }

    (3)通过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
    ",
                rtc->name, MAJOR(rtc_devt), rtc->id);
        else
            pr_debug("%s: dev (%d:%d)
    ", rtc->name,
                MAJOR(rtc_devt), rtc->id);
    }

    (4)RTC字符设备操作函数集rtc_dev_fops:用于实现访问RTC设备文件/dev/rtc0的操作方法,包括open、read、ioctl等方法。

    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,
    };

    (5)RTC设备操作函数集s3c_rtcops:用于实现操作RTC设备的基本方法也是rtc_device_register()函数中赋值给rtc(rtc_device结构)的ops成员的

    static const struct rtc_class_ops s3c_rtcops = {
        .open        = s3c_rtc_open,
        .release    = s3c_rtc_release,
        .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,
    };

    注:s3c_rtcops属于RTC的设备描述结构rtc_device的成员,用于实现操作RTC的基本方法;而rtc_dev_fops属于cdev结构的成员,用于实现访问RTC设备文件/dev/rtc0的基本方法。rtc_dev_fops中的成员需要调用s3c_rtcops中的成员来实现其具体功能。

    2. Linux2.6.29内核中,RTC平台驱动已经注册进内核,但RTC平台资源并未注册。我们添加RTC仅需要把RTC的平台资源结构体添加到平台资源初始化列表中即可。

    (1)向smdk2440_devices[]数组中添加s3c_device_rtc

    static struct platform_device *smdk2440_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
        &s3c_device_i2c0,
        &s3c_device_iis,
        &smdk2440_device_eth,
        &s3c_device_rtc,
    };

    (2)重新配置内核,加入RTC的驱动:Device Drivers--->Real Time Clock-->Samsung S3C series Soc RTC

    3. RTC测试

    (1)操作设备文件/dev/rtc0

    (2)通过proc查看:cat /proc/driver/rtc

    (3)通过sys文件系统接口:cat /sys/class/trc/rtc0/date; cat /sys/class/trc/rtc0/time

    #include <stdio.h>
    #include <linux/rtc.h>
    #include <sys/ioctl.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <errno.h>
    
    static const char default_rtc[] = "/dev/rtc0";
    
    int main(int argc, char** argv)
    {
        int fd, retval;
        struct rtc_time rtc_tm;
        const char* rtc = default_rtc;
        
        switch(argc)
        {
            case 2:
                rtc = argv[1];
                break;
            case 1:
                break;
            default:
                fprintf(stderr, "usage: TestRtc [RtcDev]");
                return 1;
        }
        
        fd = open(rtc, O_RDONLY);
        if(fd == -1)
        {
            perror(rtc);
            exit(errno);
        }
        
        retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
        if(retval == -1)
        {
            perror("RTC_RD_TIME ioctl");
            exit(errno);
        }
        
        printf("Current RTC date/time is %d-%d-%d, %02d:%02d:%02d.
    ",
            rtc_tm.tm_year + 1900, rtc_tm.tm_mon + 1, rtc_tm.tm_mday, 
            rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
        
        return 0;
    }
  • 相关阅读:
    python os 用法(转)
    caffe for python
    day20-Python运维开发基础(装饰器 / 类中的方法 / 类的方法变属性)
    day19-Python运维开发基础(类的魔术方法)
    day18-Python运维开发基础(单继承 / 多继承 / 菱形继承、类的多态)
    day17-Python运维开发基础(类的封装 / 对象和类的相关操作、构造方法)
    day16-Python运维开发基础(os / os.path / shutil模块)
    Linux 创建网卡子接口
    day15-Python运维开发基础(json序列化模块、random / time / zipfile / OS模块函数)
    day14-Python运维开发基础(内置函数、pickle序列化模块、math数学模块)
  • 原文地址:https://www.cnblogs.com/wulei0630/p/10840516.html
Copyright © 2020-2023  润新知