一. RTC中的文件
rtc中既在/proc又在/sys目录下存在可以修改属性的文件
/sys/class/rtc/rtc0/
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# tree
-
.
-
|-- date
-
|-- dev
-
|-- device -> ../../../s3c64xx-rtc
-
|-- hctosys
-
|-- max_user_freq
-
|-- name
-
|-- since_epoch
-
|-- subsystem -> ../../../../../class/rtc
-
|-- time
-
|-- uevent
-
`-- wakealarm
-
-
2 directories, 9 files
-
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat date
-
2001-11-05
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat dev
-
254:0
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat hctosys
-
1
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat max_user_freq
-
32768
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat name
-
s3c
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat since_epoch
-
1004971702
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat time
-
14:48:26
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat uevent
-
MAJOR=254
-
MINOR=0
-
DEVNAME=rtc0
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat wakealarm
-
root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0#
/proc
-
root@OK6410:~# cat /proc/driver/rtc
-
rtc_time : 14:43:19
-
rtc_date : 2001-11-05
-
alrm_time : 20:41:27
-
alrm_date : 2001-11-03
-
alarm_IRQ : no
-
alrm_pending : no
-
update IRQ enabled : no
-
periodic IRQ enabled : no
-
periodic IRQ frequency : 1
-
max user IRQ frequency : 32768
-
24hr : yes
-
periodic_IRQ : no
二. proc文件系统
s3c_rtc_probe
rtc_device_register
--> rtc_proc_add_device
-
static const struct file_operations rtc_proc_fops = {
-
.open = rtc_proc_open,
-
.read = seq_read,
-
.llseek = seq_lseek,
-
.release = rtc_proc_release,
-
};
-
-
void rtc_proc_add_device(struct rtc_device *rtc)
-
{
-
if (rtc->id == 0)
-
proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); //在/proc目录下创建 driver/rtc文件,文件操作是rtc_proc_fops
-
}
2. 打开读取/proc/driver/rtc 文件
s3c_rtc_probe
rtc_device_register
--> rtc_proc_add_device
--> rtc_proc_open
--> rtc_proc_show
-
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;
-
}
-
-
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;
-
//single_open不太明白,网上说是打开和释放只有一条记录的文件,不知道这儿的一条是怎么算的
-
ret = single_open(file, rtc_proc_show, rtc); //调用rtc_proc_show显示
-
if (ret)
-
module_put(THIS_MODULE);
-
return ret;
-
}
三. sys文件系统
主要包括rtc与alarm
-
rtc_init
-
--> rtc_sysfs_init
-
--> rtc_attrs
-
--> rtc_sysfs_show_name
-
rtc_sysfs_show_date
-
rtc_sysfs_show_time
-
rtc_sysfs_show_since_epoch
-
rtc_sysfs_show_max_user_freq
-
rtc_sysfs_set_max_user_freq
-
rtc_sysfs_show_hctosys
-
s3c_rtc_probe
-
rtc_device_register
-
rtc_sysfs_add_device
-
--> device_create_file(&rtc->dev, &dev_attr_wakealarm);
-
--> rtc_sysfs_show_wakealarm
-
--> rtc_sysfs_set_wakealarm
1. class初始化过程
driver/rtc/class.c
-
static int __init rtc_init(void) //完成申请设备号和初始化class结构体
-
{
-
rtc_class = class_create(THIS_MODULE, "rtc");
-
rtc_class->suspend = rtc_suspend;
-
rtc_class->resume = rtc_resume;
-
rtc_sysfs_init(rtc_class); //set rtc_class->dev_attrs
-
return 0;
-
}
2. 设备注册并在/sys/class下生成文件
s3c_rtc_probe
--> rtc_device_register 中
-
struct rtc_device *rtc_device_register()
-
{
-
rtc->dev.class = rtc_class; //设置s3c-rtc驱动的class是在driver/rtc/class.c中初始化好后的全局变量rtc_class
-
err = device_register(&rtc->dev); //注册设备
-
rtc_sysfs_add_device(rtc); //调用device_create_file在sys/class/下产生文件
-
}
-
s3c_rtc_probe
--> rtc_device_register
-
--> rtc_sysfs_add_device
-
void rtc_sysfs_add_device(struct rtc_device *rtc)
-
{
-
err = device_create_file(&rtc->dev, &dev_attr_wakealarm); //这个函数可以在/sys/class下创建相应的属性文件
-
}
3. class创建的文件: 一个是属性创建,一个是通过device_create_file创建
通过rtc_class属性创建的文件是:
name, data, time, since_epoch, max_user_freq, hctosys文件
-
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),
-
{ },
-
};
-
-
void __init rtc_sysfs_init(struct class *rtc_class)
-
{
-
rtc_class->dev_attrs = rtc_attrs;
-
}
通过device_create_file创建的文件是: wakealarm
-
static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
四. 一个sys的测试程序
-
#include <linux/module.h> /* For module specific items */
-
#include <linux/moduleparam.h> /* For new moduleparam's */
-
#include <linux/types.h> /* For standard types (like size_t) */
-
#include <linux/errno.h> /* For the -ENODEV/... values */
-
#include <linux/kernel.h> /* For printk/panic/... */
-
#include <linux/fs.h> /* For file operations */
-
#include <linux/ioport.h> /* For io-port access */
-
#include <linux/platform_device.h> /* For platform_driver framework */
-
#include <linux/init.h> /* For __init/__exit/... */
-
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
-
#include <linux/io.h> /* For inb/outb/... */
-
#include <linux/device.h>
-
#include <linux/sysfs.h>
-
-
static struct class *class_test;
-
static struct device dev_test;
-
static void dev_test_release(struct device *dev)
-
{ //避免卸载时的warning
-
}
-
static ssize_t rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr, char *buf)
-
{
-
return sprintf(buf, "%s\n", "rtc_sys_show_name");
-
}
-
static ssize_t rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr, char *buf)
-
{ //因为函数是空的,所以在read时为read error
-
}
-
static ssize_t rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, char *buf)
-
{
-
return sprintf(buf, "%s\n", "show_wakealarm");
-
}
-
-
static ssize_t rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
-
{
-
}
-
-
static struct device_attribute test_attrs[] =
-
{
-
__ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
-
__ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
-
{},
-
};
-
static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
-
-
int hello_init(void)
-
{
-
class_test = class_create(THIS_MODULE, "class_test"); //创建一个class
-
class_test->dev_attrs = test_attrs; //设置class的属性,如果只想创建device文件这步可以省略
-
-
dev_test.class = class_test; //设置dev的class
-
dev_test.release = dev_test_release; //加上这个要不在卸载时会有个warning
-
dev_set_name(&dev_test, "dev_test_%d", 2); //给dev取个名
-
device_register(&dev_test); //注册dev
-
-
device_create_file(&dev_test, &dev_attr_wakealarm); //为dev创建file
-
-
return 0;
-
}
-
-
void hello_exit(void)
-
{
-
device_unregister(&dev_test);
-
device_remove_file(&dev_test, &dev_attr_wakealarm);
-
class_destroy(class_test);
-
}
-
module_init(hello_init);
-
module_exit(hello_exit);
-
-
MODULE_AUTHOR("test");
-
MODULE_LICENSE("GPL");
结果如下:
-
root@OK6410:/work/hello# insmod ./hello.ko
-
root@OK6410:/work/hello# ls /sys/class/class_test/dev_test_2/ //uevent与subsystem是自动生成的
-
date name subsystem uevent wakealarm //创建了date name wakealarm三个文件
-
root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/date
-
cat: read error
-
root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/name
-
rtc_sys_show_name
-
root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/uevent
-
root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/wakealarm
-
show_wakealarm
阅读(1542) | 评论(0) | 转发(0) |