Linux RTC设备驱动

本文深入解析了Linux2.6.29内核中RTC设备的驱动实现,详细介绍了RTC平台设备的注册流程,包括平台设备定义、资源分配、探针函数s3c_rtc_probe()的内部工作原理,以及rtc_device_register()函数如何创建和注册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\n",
            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\n",
            rtc->name, MAJOR(rtc_devt), rtc->id);
    else
        pr_debug("%s: dev (%d:%d)\n", 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.\n",
        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;
}

 

转载于:https://www.cnblogs.com/wulei0630/p/10840516.html

在车辆工程中,悬架系统的性能评估和优化一直是研究的热点。悬架不仅关乎车辆的乘坐舒适性,还直接影响到车辆的操控性和稳定性。为了深入理解悬架的动态行为,研究人员经常使用“二自由度悬架模型”来简化分析,并运用“传递函数”这一数学工具来描述悬架系统的动态特性。 二自由度悬架模型将复杂的车辆系统简化为两个独立的部分:车轮和车身。这种简化模型能够较准确地模拟出车辆在垂直方向上的运动行为,同时忽略了侧向和纵向的动态影响,这使得工程师能够更加专注于分析与优化与垂直动态相关的性能指标。 传递函数作为控制系统理论中的一种工具,能够描述系统输入和输出之间的关系。在悬架系统中,传递函数特别重要,因为它能够反映出路面不平度如何被悬架系统转化为车内乘员感受到的振动。通过传递函数,我们可以得到一个频率域上的表达式,从中分析出悬架系统的关键动态特性,如系统的振幅衰减特性和共振频率等。 在实际应用中,工程师通过使用MATLAB这类数学软件,建立双质量悬架的数学模型。模型中的参数包括车轮质量、车身质量、弹簧刚度以及阻尼系数等。通过编程求解,工程师可以得到悬架系统的传递函数,并据此绘制出传递函数曲线。这为评估悬架性能提供了一个直观的工具,使工程师能够了解悬架在不同频率激励下的响应情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值