Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2151515
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2013-08-05 14:28:35

一. RTC中的文件
rtc中既在/proc又在/sys目录下存在可以修改属性的文件
/sys/class/rtc/rtc0/
  1. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# tree
  2. .
  3. |-- date
  4. |-- dev
  5. |-- device -> ../../../s3c64xx-rtc
  6. |-- hctosys
  7. |-- max_user_freq
  8. |-- name
  9. |-- since_epoch
  10. |-- subsystem -> ../../../../../class/rtc
  11. |-- time
  12. |-- uevent
  13. `-- wakealarm

  14. 2 directories, 9 files

  15. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat date
  16. 2001-11-05
  17. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat dev
  18. 254:0
  19. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat hctosys
  20. 1
  21. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat max_user_freq
  22. 32768
  23. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat name
  24. s3c
  25. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat since_epoch
  26. 1004971702
  27. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat time
  28. 14:48:26
  29. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat uevent
  30. MAJOR=254
  31. MINOR=0
  32. DEVNAME=rtc0
  33. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0# cat wakealarm
  34. root@OK6410:/sys/devices/platform/s3c64xx-rtc/rtc/rtc0#
/proc
  1. root@OK6410:~# cat /proc/driver/rtc
  2. rtc_time : 14:43:19
  3. rtc_date : 2001-11-05
  4. alrm_time : 20:41:27
  5. alrm_date : 2001-11-03
  6. alarm_IRQ : no
  7. alrm_pending : no
  8. update IRQ enabled : no
  9. periodic IRQ enabled : no
  10. periodic IRQ frequency : 1
  11. max user IRQ frequency : 32768
  12. 24hr : yes
  13. periodic_IRQ : no
二. proc文件系统
s3c_rtc_probe
rtc_device_register    
   --> rtc_proc_add_device
  1. static const struct file_operations rtc_proc_fops = {
  2.     .open        = rtc_proc_open,
  3.     .read        = seq_read,
  4.     .llseek        = seq_lseek,
  5.     .release    = rtc_proc_release,
  6. };

  7. void rtc_proc_add_device(struct rtc_device *rtc)
  8. {
  9.     if (rtc->id == 0)
  10.         proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);  //在/proc目录下创建 driver/rtc文件,文件操作是rtc_proc_fops
  11. }

2. 打开读取/proc/driver/rtc 文件
s3c_rtc_probe
rtc_device_register    
   --> rtc_proc_add_device
        --> rtc_proc_open
            --> rtc_proc_show
  1. static int rtc_proc_show(struct seq_file *seq, void *offset)
  2. {
  3.     int err;
  4.     struct rtc_device *rtc = seq->private;
  5.     const struct rtc_class_ops *ops = rtc->ops;
  6.     struct rtc_wkalrm alrm;
  7.     struct rtc_time tm;

  8.     err = rtc_read_time(rtc, &tm);
  9.     if (err == 0) {
  10.         seq_printf(seq, "rtc_time\t: %02d:%02d:%02d\n" "rtc_date\t: %04d-%02d-%02d\n",
  11.             tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
  12.     }

  13.     err = rtc_read_alarm(rtc, &alrm);
  14.     if (err == 0) {
  15.         seq_printf(seq, "alrm_time\t: ");
  16.         if ((unsigned int)alrm.time.tm_hour <= 24)
  17.             seq_printf(seq, "%02d:", alrm.time.tm_hour);
  18.         else
  19.             seq_printf(seq, "**:");
  20.         if ((unsigned int)alrm.time.tm_min <= 59)
  21.             seq_printf(seq, "%02d:", alrm.time.tm_min);
  22.         else
  23.             seq_printf(seq, "**:");
  24.         if ((unsigned int)alrm.time.tm_sec <= 59)
  25.             seq_printf(seq, "%02d\n", alrm.time.tm_sec);
  26.         else
  27.             seq_printf(seq, "**\n");

  28.         seq_printf(seq, "alrm_date\t: ");
  29.         if ((unsigned int)alrm.time.tm_year <= 200)
  30.             seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
  31.         else
  32.             seq_printf(seq, "****-");
  33.         if ((unsigned int)alrm.time.tm_mon <= 11)
  34.             seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
  35.         else
  36.             seq_printf(seq, "**-");
  37.         if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
  38.             seq_printf(seq, "%02d\n", alrm.time.tm_mday);
  39.         else
  40.             seq_printf(seq, "**\n");
  41.         seq_printf(seq, "alarm_IRQ\t: %s\n", alrm.enabled ? "yes" : "no");
  42.         seq_printf(seq, "alrm_pending\t: %s\n", alrm.pending ? "yes" : "no");
  43.         seq_printf(seq, "update IRQ enabled\t: %s\n", (rtc->uie_rtctimer.enabled) ? "yes" : "no");
  44.         seq_printf(seq, "periodic IRQ enabled\t: %s\n"(rtc->pie_enabled) ? "yes" : "no");
  45.         seq_printf(seq, "periodic IRQ frequency\t: %d\n", rtc->irq_freq);
  46.         seq_printf(seq, "max user IRQ frequency\t: %d\n", rtc->max_user_freq);
  47.     }

  48.     seq_printf(seq, "24hr\t\t: yes\n");

  49.     if (ops->proc)
  50.         ops->proc(rtc->dev.parent, seq);

  51.     return 0;
  52. }

  53. static int rtc_proc_open(struct inode *inode, struct file *file)
  54. {
  55.     int ret;
  56.     struct rtc_device *rtc = PDE(inode)->data;

  57.     if (!try_module_get(THIS_MODULE))
  58.         return -ENODEV;
  59.     //single_open不太明白,网上说是打开和释放只有一条记录的文件,不知道这儿的一条是怎么算的
  60.     ret = single_open(file, rtc_proc_show, rtc);    //调用rtc_proc_show显示
  61.     if (ret)
  62.         module_put(THIS_MODULE);
  63.     return ret;
  64. }

三. sys文件系统
主要包括rtc与alarm
  1. rtc_init
  2.     --> rtc_sysfs_init
  3.     --> rtc_attrs
  4.         --> rtc_sysfs_show_name
  5.             rtc_sysfs_show_date
  6.             rtc_sysfs_show_time
  7.             rtc_sysfs_show_since_epoch
  8.             rtc_sysfs_show_max_user_freq
  9.             rtc_sysfs_set_max_user_freq
  10.             rtc_sysfs_show_hctosys
  11. s3c_rtc_probe
  12.     rtc_device_register
  13.     rtc_sysfs_add_device
  14.     --> device_create_file(&rtc->dev, &dev_attr_wakealarm);
  15.         --> rtc_sysfs_show_wakealarm
  16.         --> rtc_sysfs_set_wakealarm
1. class初始化过程
driver/rtc/class.c
  1. static int __init rtc_init(void) //完成申请设备号和初始化class结构体
  2. {
  3.     rtc_class = class_create(THIS_MODULE, "rtc");
  4.     rtc_class->suspend = rtc_suspend;
  5.     rtc_class->resume = rtc_resume;
  6.     rtc_sysfs_init(rtc_class);     //set rtc_class->dev_attrs
  7.     return 0;
  8. }
2. 设备注册并在/sys/class下生成文件
s3c_rtc_probe
--> rtc_device_register 中
  1. struct rtc_device *rtc_device_register()
  2. {
  3.     rtc->dev.class = rtc_class;         //设置s3c-rtc驱动的class是在driver/rtc/class.c中初始化好后的全局变量rtc_class
  4.     err = device_register(&rtc->dev);   //注册设备   
  5.     rtc_sysfs_add_device(rtc);          //调用device_create_file在sys/class/下产生文件
  6. }
  7. s3c_rtc_probe
    --> rtc_device_register
  8.     -->  rtc_sysfs_add_device 
  9. void rtc_sysfs_add_device(struct rtc_device *rtc)
  10. {
  11.     err = device_create_file(&rtc->dev, &dev_attr_wakealarm); //这个函数可以在/sys/class下创建相应的属性文件
  12. }

3. class创建的文件: 一个是属性创建,一个是通过device_create_file创建
通过rtc_class属性创建的文件是: name, data, time, since_epoch, max_user_freq, hctosys文件
  1. static struct device_attribute rtc_attrs[] = {
  2.     __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
  3.     __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
  4.     __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
  5.     __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
  6.     __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, rtc_sysfs_set_max_user_freq),
  7.     __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
  8.     { },
  9. };

  10. void __init rtc_sysfs_init(struct class *rtc_class)
  11. {
  12.     rtc_class->dev_attrs = rtc_attrs;
  13. }
通过device_create_file创建的文件是: wakealarm
  1. static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);

四. 一个sys的测试程序
  1. #include <linux/module.h>        /* For module specific items */
  2. #include <linux/moduleparam.h>        /* For new moduleparam's */
  3. #include <linux/types.h>        /* For standard types (like size_t) */
  4. #include <linux/errno.h>        /* For the -ENODEV/... values */
  5. #include <linux/kernel.h>        /* For printk/panic/... */
  6. #include <linux/fs.h>            /* For file operations */
  7. #include <linux/ioport.h>        /* For io-port access */
  8. #include <linux/platform_device.h>    /* For platform_driver framework */
  9. #include <linux/init.h>            /* For __init/__exit/... */
  10. #include <linux/uaccess.h>        /* For copy_to_user/put_user/... */
  11. #include <linux/io.h>            /* For inb/outb/... */
  12. #include <linux/device.h>    
  13. #include <linux/sysfs.h>

  14. static struct class *class_test;
  15. static struct device dev_test;
  16. static void dev_test_release(struct device *dev)
  17. {  //避免卸载时的warning
  18. }
  19. static ssize_t rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr, char *buf)
  20. {
  21.     return sprintf(buf, "%s\n", "rtc_sys_show_name");
  22. }
  23. static ssize_t rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr, char *buf)
  24. {  //因为函数是空的,所以在read时为read error
  25. }
  26. static ssize_t rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, char *buf)
  27. {
  28.     return sprintf(buf, "%s\n", "show_wakealarm");
  29. }

  30. static ssize_t rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attrconst char *buf, size_t n)
  31. {
  32. }

  33. static struct device_attribute test_attrs[] =
  34. {
  35.     __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
  36.     __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
  37.     {},
  38. };
  39. static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);

  40. int hello_init(void)
  41. {
  42.     class_test = class_create(THIS_MODULE, "class_test");   //创建一个class
  43.     class_test->dev_attrs = test_attrs;                     //设置class的属性,如果只想创建device文件这步可以省略

  44.     dev_test.class = class_test;                            //设置dev的class
  45.     dev_test.release = dev_test_release;                  //加上这个要不在卸载时会有个warning   
  46.     dev_set_name(&dev_test, "dev_test_%d", 2);              //给dev取个名     
  47.     device_register(&dev_test);                             //注册dev

  48.     device_create_file(&dev_test, &dev_attr_wakealarm);     //为dev创建file

  49.     return 0;
  50. }

  51. void hello_exit(void)
  52. {
  53.     device_unregister(&dev_test);
  54.     device_remove_file(&dev_test, &dev_attr_wakealarm);
  55.     class_destroy(class_test);
  56. }
  57. module_init(hello_init);
  58. module_exit(hello_exit);

  59. MODULE_AUTHOR("test");
  60. MODULE_LICENSE("GPL");
结果如下:
  1. root@OK6410:/work/hello# insmod ./hello.ko
  2. root@OK6410:/work/hello# ls /sys/class/class_test/dev_test_2/    //uevent与subsystem是自动生成的
  3.     date name subsystem uevent wakealarm                    //创建了date name wakealarm三个文件
  4. root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/date
  5.     cat: read error
  6. root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/name
  7.     rtc_sys_show_name
  8. root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/uevent
  9. root@OK6410:/work/hello# cat /sys/class/class_test/dev_test_2/wakealarm
  10.     show_wakealarm

阅读(2092) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~