免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
Linux RTC驅(qū)動(dòng)分析(三)
         rtc-sysfs.c這個(gè)部分主要是有關(guān)sysfs的操作。在rtc_device_register函數(shù)中,rtc_sysfs_add_device(rtc);完成sys的操作。
void rtc_sysfs_add_device(struct rtc_device *rtc)
{
    int err;
    /* not all RTCs support both alarms and wakeup */
    if (!rtc_does_wakealarm(rtc))
        return;
    err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
    if (err)
        dev_err(rtc->dev.parent,
            "failed to create alarm attribute, %d\n", err);
}
        rtc_init函數(shù)中初始化sys。
void __init rtc_sysfs_init(struct class *rtc_class)
{
    rtc_class->dev_attrs = rtc_attrs;
}
        rtc_attrs設(shè)備屬性組如下:
static struct device_attribute rtc_attrs[] = {
    __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
    __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
    __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
    __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
    __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
            rtc_sysfs_set_max_user_freq),
    __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
    { },
};
        這個(gè)屬性組是在class.c的模塊初始化函數(shù)中,由rtc_sysfs_init函數(shù)賦值給rtc_class->dev_attrs的,以后屬于這個(gè)類的設(shè)備都會(huì)有這些屬性。但是我們知道要想一個(gè)設(shè)備結(jié)構(gòu)擁有一種屬性,必須調(diào)用device_create_file,這樣才會(huì)使這個(gè)屬性出現(xiàn)在sysfs相關(guān)設(shè)備目錄里。但是在這里的代碼中只是給這個(gè)類的dev_attrs域賦值了這個(gè)屬性組指針,而沒(méi)有調(diào)用device_create_file。我原來(lái)以為是在rtc_device_resgister函數(shù)中由rtc_sysfs_add_device完成這個(gè)工作,但是這個(gè)函數(shù)只是給設(shè)備添加了鬧鐘屬性,并沒(méi)有處理這個(gè)屬性組。最后發(fā)現(xiàn)這個(gè)工作是由device_register來(lái)完成的:

        device_register調(diào)用device_add

        device_add調(diào)用device_add_attrs

        device_add_attrs調(diào)用device_add_attributes

        device_add_attributes調(diào)用device_create_file來(lái)完成設(shè)備的屬性設(shè)置。

        設(shè)置完屬性后,在/sys/class/rtc/rtc(n)的目錄下就會(huì)出現(xiàn)name、date、time、since_epoch、max_user_freq和hctosys等文件,用戶讀這些文件的時(shí)候就會(huì)調(diào)用相應(yīng)的函數(shù)。如讀取name文件,就會(huì)調(diào)用rtc_sysfs_show_name函數(shù),這個(gè)函數(shù)也是在rtc-sysfs.c中實(shí)現(xiàn)的,作用是讀取并顯示時(shí)間。

/*
 * NOTE:  RTC times displayed in sysfs use the RTC's timezone.  That's
 * ideally UTC.  However, PCs that also boot to MS-Windows normally use
 * the local time and change to match daylight savings time.  That affects
 * attributes including date, time, since_epoch, and wakealarm.
 */
static ssize_t
rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
        char *buf)
{
    return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
}
static ssize_t
rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
        char *buf)
{
    ssize_t retval;
    struct rtc_time tm;
    retval = rtc_read_time(to_rtc_device(dev), &tm);
    if (retval == 0) {
        retval = sprintf(buf, "%04d-%02d-%02d\n",
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
    }
    return retval;
}
static ssize_t
rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
        char *buf)
{
    ssize_t retval;
    struct rtc_time tm;
    retval = rtc_read_time(to_rtc_device(dev), &tm);
    if (retval == 0) {
        retval = sprintf(buf, "%02d:%02d:%02d\n",
            tm.tm_hour, tm.tm_min, tm.tm_sec);
    }
    return retval;
}
static ssize_t
rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
        char *buf)
{
    ssize_t retval;
    struct rtc_time tm;
    retval = rtc_read_time(to_rtc_device(dev), &tm);
    if (retval == 0) {
        unsigned long time;
        rtc_tm_to_time(&tm, &time);
        retval = sprintf(buf, "%lu\n", time);
    }
    return retval;
}
static ssize_t
rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
        char *buf)
{
    return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
}
static ssize_t
rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
        const char *buf, size_t n)
{
    struct rtc_device *rtc = to_rtc_device(dev);
    unsigned long val = simple_strtoul(buf, NULL, 0);
    if (val >= 4096 || val == 0)
        return -EINVAL;
    rtc->max_user_freq = (int)val;
    return n;
}
static ssize_t
rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
        char *buf)
{
#ifdef CONFIG_RTC_HCTOSYS_DEVICE
    if (rtc_hctosys_ret == 0 &&
            strcmp(dev_name(&to_rtc_device(dev)->dev),
                CONFIG_RTC_HCTOSYS_DEVICE) == 0)
        return sprintf(buf, "1\n");
    else
#endif
        return sprintf(buf, "0\n");
}
        rtc-proc.c這個(gè)文件提供RTC的proc文件系統(tǒng)接口。proc文件系統(tǒng)是軟件創(chuàng)建的文件系統(tǒng),內(nèi)核通過(guò)他向外界導(dǎo)出信息。
        在第一份部分的rtc_device_register函數(shù)中調(diào)用rtc_proc_add_device(rtc);,函數(shù)主要功能就是增加proc文件系統(tǒng)的內(nèi)容,該函數(shù)具體內(nèi)容如下:
void rtc_proc_add_device(struct rtc_device *rtc)
{
    if (rtc->id == 0)
        proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);    //rtc_proc_fops在下面講述
}
        他主要調(diào)用了proc_create_data。proc_create_data完成創(chuàng)建文件節(jié)點(diǎn)的作用,并將文件的操作函數(shù)與節(jié)點(diǎn)聯(lián)系起來(lái)。調(diào)用這個(gè)函數(shù)后,在/proc/driver目錄下就會(huì)有一個(gè)文件rtc,應(yīng)用程序打開(kāi)這個(gè)文件就會(huì)調(diào)用rtc_proc_open函數(shù)。
//以下函數(shù)在rtc_device_unregister()中調(diào)用
void rtc_proc_del_device(struct rtc_device *rtc)
{
    if (rtc->id == 0)
        remove_proc_entry("driver/rtc", NULL);
}
        下面的每一個(gè)文件都綁定一個(gè)函數(shù),當(dāng)用戶讀取這個(gè)文件的時(shí)候,這些函數(shù)會(huì)向文件寫(xiě)入信息:
static const struct file_operations rtc_proc_fops = {
    .open        = rtc_proc_open,
    .read        = seq_read,
    .llseek        = seq_lseek,
    .release    = rtc_proc_release,
};
static int rtc_proc_open(struct inode *inode, struct file *file)
{
    int ret;
    struct rtc_device *rtc = PDE(inode)->data;
    if (!try_module_get(THIS_MODULE))
        return -ENODEV;
    ret = single_open(file, rtc_proc_show, rtc);    //rtc_proc_show接下來(lái)講述
    if (ret)
        module_put(THIS_MODULE);
    return ret;
}
        我們知道一個(gè)proc的文件必須與一個(gè)操作函數(shù)組成一個(gè)proc入口項(xiàng),這個(gè)文件才能正常工作。這個(gè)函數(shù)最主要作用就是調(diào)用single_open,創(chuàng)建一個(gè)proc文件入口項(xiàng),使其操作函數(shù)是rtc_proc_show,并初始化seq_file接口。rtc_proc_show函數(shù)如下定義:
static int rtc_proc_show(struct seq_file *seq, void *offset)
{
    int err;
    struct rtc_device *rtc = seq->private;
    const struct rtc_class_ops *ops = rtc->ops;
    struct rtc_wkalrm alrm;
    struct rtc_time tm;
    err = rtc_read_time(rtc, &tm);
    if (err == 0) {
        seq_printf(seq,
            "rtc_time\t: %02d:%02d:%02d\n"
            "rtc_date\t: %04d-%02d-%02d\n",
            tm.tm_hour, tm.tm_min, tm.tm_sec,
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
    }
    err = rtc_read_alarm(rtc, &alrm);
    if (err == 0) {
        seq_printf(seq, "alrm_time\t: ");
        if ((unsigned int)alrm.time.tm_hour <= 24)
            seq_printf(seq, "%02d:", alrm.time.tm_hour);
        else
            seq_printf(seq, "**:");
        if ((unsigned int)alrm.time.tm_min <= 59)
            seq_printf(seq, "%02d:", alrm.time.tm_min);
        else
            seq_printf(seq, "**:");
        if ((unsigned int)alrm.time.tm_sec <= 59)
            seq_printf(seq, "%02d\n", alrm.time.tm_sec);
        else
            seq_printf(seq, "**\n");
        seq_printf(seq, "alrm_date\t: ");
        if ((unsigned int)alrm.time.tm_year <= 200)
            seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
        else
            seq_printf(seq, "****-");
        if ((unsigned int)alrm.time.tm_mon <= 11)
            seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
        else
            seq_printf(seq, "**-");
        if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
            seq_printf(seq, "%02d\n", alrm.time.tm_mday);
        else
            seq_printf(seq, "**\n");
        seq_printf(seq, "alarm_IRQ\t: %s\n",
                alrm.enabled ? "yes" : "no");
        seq_printf(seq, "alrm_pending\t: %s\n",
                alrm.pending ? "yes" : "no");
        seq_printf(seq, "update IRQ enabled\t: %s\n",
            (rtc->uie_rtctimer.enabled) ? "yes" : "no");
        seq_printf(seq, "periodic IRQ enabled\t: %s\n",
            (rtc->pie_enabled) ? "yes" : "no");
        seq_printf(seq, "periodic IRQ frequency\t: %d\n",
            rtc->irq_freq);
        seq_printf(seq, "max user IRQ frequency\t: %d\n",
            rtc->max_user_freq);
    }
    seq_printf(seq, "24hr\t\t: yes\n");
    if (ops->proc)
        ops->proc(rtc->dev.parent, seq);
    return 0;
}
        這個(gè)函數(shù)就是最后給用戶顯示信息的函數(shù)了,可以看出他通過(guò)調(diào)用rtc_deivce中的操作函數(shù)讀取時(shí)間、日期和一些其他的信息顯示給用戶。

        RTC核心使底層硬件對(duì)用戶來(lái)說(shuō)是透明的,并且減少了編寫(xiě)驅(qū)動(dòng)程序的工作量。RTC新的驅(qū)動(dòng)接口提供了更多的功能,使系統(tǒng)可以同時(shí)存在多個(gè)RTC。/dev,sysfs,proc這三種機(jī)制的實(shí)現(xiàn)使得應(yīng)用程序能靈活的使用RTC。RTC核心代碼的組織方式值得學(xué)習(xí),不同功能的代碼放在不同的文件中,簡(jiǎn)單明了。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux驅(qū)動(dòng) | Linux內(nèi)核 RTC時(shí)間架構(gòu)
Linux時(shí)間系統(tǒng)之RTC時(shí)間
DEVICE
使用 /sys 文件系統(tǒng)訪問(wèn) Linux 內(nèi)核
致驅(qū)動(dòng)工程師的一封信
Linux驅(qū)動(dòng)程序開(kāi)發(fā) - 設(shè)備驅(qū)動(dòng)模型初探
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服