08 - debugfs

---- 整理自 王利涛老师 课程
实验环境:宅学部落 www.zhaixue.cc

文章目录

  • 0. 什么是 debugfs
  • 1. debugfs 配置编译和注册运行
  • 2. 第一个 debugfs 编程示例
  • 3. 通过 debugfs 导出整型数据
  • 4. 通过 debugfs 导出 16 进制数据
  • 5. 通过 debugfs 到处数组
  • 6. 通过 debugfs 导出内存数据块
  • 7. 通过 debugfs 导出自定义格式数据
  • 8. 在 debugfs 下使用 seq_file 接口
  • 9. 使用 seq_file 接口访问数组
  • 10. 使用 seq_file 接口访问链表
  • 11. 通过 debugfs 导出寄存器列表
  • 12. 通过 debugfs 修改 RTC 寄存器
  • 13. 通过 debugfs 导出 RTC 调试接口

0. 什么是 debugfs

  • 天生为调试内核而开发,一个基于内存的文件系统,它是基于 libfs,主要调试功能
  • 相比 procfs、sysfs 的优势
    • procfs:调试内核、修改寄存器,进程的信息导出到用户空间
      proc:需要实现它对应的底层的 read、write 接口,需要添加很多的调试代码
    • sysfs:设备模型导出到用户空间
    • debugfs:简化了导出的接口,一行代码,就可以将内核变量、数组、链表、内存中数据、寄存器导出导出到用户空间,方便调试

1. debugfs 配置编译和注册运行

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 第一个 debugfs 编程示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>static unsigned int hello_value;
static struct dentry *hello_root;static int __init hello_debugfs_init(void)
{hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_u32("hello_reg", 0644, hello_root, &hello_value);return 0;
}static void __exit hello_debugfs_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}//debugfs_remove();
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
EXTRA_CFLAGS += -DDEBUG 
KDIR:=/home/code_folder/uboot_linux_rootfs/kernel/linux-5.10.4
ARCH_ARGS := ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
all:make $(ARCH_ARGS) -C $(KDIR) M=$(PWD) modules
clean:make $(ARCH_ARGS) -C $(KDIR) M=$(PWD) modules clean
endif

在这里插入图片描述
在这里插入图片描述

3. 通过 debugfs 导出整型数据

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>static unsigned int hello_value;
static struct dentry *hello_root;static u8 u8_a;
static u16 u16_a;
static u64 u64_a;
static size_t size_t_a;
static unsigned long ulong_a;
static bool bool_a;static int __init hello_debugfs_init(void)
{hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_u32("hello_reg", 0644, hello_root, &hello_value);debugfs_create_u8("u8_reg", 0644, hello_root, &u8_a);debugfs_create_u16("u16_reg", 0644, hello_root, &u16_a);debugfs_create_u64("u64_reg", 0644, hello_root, &u64_a);debugfs_create_size_t("size_t_reg", 0644, hello_root, &size_t_a);debugfs_create_ulong("ulong_reg", 0644, hello_root, &ulong_a);debugfs_create_bool("bool_reg", 0644, hello_root, &bool_a);return 0;
}static void __exit hello_debugfs_exit(void)
{if (hello_root)debugfs_remove_recursive(hello_root);
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
EXTRA_CFLAGS += -DDEBUG 
KDIR:=/home/code_folder/uboot_linux_rootfs/kernel/linux-5.10.4
ARCH_ARGS := ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
all:make $(ARCH_ARGS) -C $(KDIR) M=$(PWD) modules
clean:make $(ARCH_ARGS) -C $(KDIR) M=$(PWD) modules clean
endif

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 通过 debugfs 导出 16 进制数据

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>static unsigned int hello_value;
static struct dentry *hello_root;static u8 u8_a;
static u16 u16_a;
static u64 u64_a;static int __init hello_debugfs_init(void)
{hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_x32("hello_reg", 0644, hello_root, &hello_value);debugfs_create_x8("u8_reg", 0644, hello_root, &u8_a);debugfs_create_x16("u16_reg", 0644, hello_root, &u16_a);debugfs_create_x64("u64_reg", 0644, hello_root, &u64_a);return 0;
}static void __exit hello_debugfs_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
EXTRA_CFLAGS += -DDEBUG 
KDIR:=/home/code_folder/uboot_linux_rootfs/kernel/linux-5.10.4
ARCH_ARGS := ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
all:make $(ARCH_ARGS) -C $(KDIR) M=$(PWD) modules
clean:make $(ARCH_ARGS) -C $(KDIR) M=$(PWD) modules clean
endif

在这里插入图片描述

5. 通过 debugfs 到处数组

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>static struct dentry *hello_root;
static u32 hello_array[8] = {1,2,3,4,5,6,7,8};static struct debugfs_u32_array array_info = {.array = hello_array,.n_elements = 8,
};static int __init hello_debugfs_init(void)
{int ret = 0;hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_u32_array("hello_array", S_IWUGO, hello_root, &array_info);return ret;
}static void __exit hello_debugfs_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

6. 通过 debugfs 导出内存数据块

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/slab.h>static struct dentry *hello_root;
static u32 hello_array[8] ={ 65, 66, 67, 68, 69, 70, 70, 71 };
static char *mem_block_p = NULL;static struct debugfs_u32_array array_info = {.array = hello_array,.n_elements = 8,
};static struct debugfs_blob_wrapper hello_blob = {.data = hello_array,.size = 8 * sizeof(u32),
};static struct debugfs_blob_wrapper hello_mem;static int __init hello_debugfs_init(void)
{int ret = 0;mem_block_p = kmalloc(32, GFP_ATOMIC);if (!mem_block_p) {pr_err("%s: kmalloc memory failed\n", __func__);return -ENOMEM;}memcpy(mem_block_p, "hello zhaixue.cc\n", 20);hello_mem.data = mem_block_p;hello_mem.size = 32;hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_u32_array("hello_array", S_IWUGO, hello_root, &array_info);debugfs_create_blob("hello_blob", S_IWUGO, hello_root, &hello_blob);debugfs_create_blob("hello_mem", S_IWUGO, hello_root, &hello_mem);return ret;
}static void __exit hello_debugfs_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}kfree(mem_block_p);
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

7. 通过 debugfs 导出自定义格式数据

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>static struct dentry *hello_root;static unsigned int hello_value;
static char hello_buf[100];static ssize_t hello_read(struct file *filp, char __user *buf, size_t count,loff_t *ppos)
{int ret;if (*ppos >= 100)return 0;if (*ppos + count > 100)count = 100 - *ppos;ret = copy_to_user(buf, hello_buf, count);if (ret) {return -EFAULT;}*ppos += count;return count;
}static ssize_t hello_write(struct file *filp, const char __user *buf, size_t count,loff_t *ppos)
{int ret;if (*ppos > 100)return 0;if (*ppos + count > 100)count = 100 - *ppos;ret = copy_from_user(hello_buf, buf, count);if (ret)return -EFAULT;*ppos += count;return count;
}static struct file_operations hello_fops = {.owner = THIS_MODULE,.read = hello_read,.write = hello_write,
};static int __init hello_debugfs_init(void)
{hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_x32("hello_reg", 0644, hello_root, &hello_value);debugfs_create_file("hello_buffer", S_IWUGO, hello_root, NULL, &hello_fops);return 0;
}static void __exit hello_debugfs_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

8. 在 debugfs 下使用 seq_file 接口

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>static struct dentry *hello_root;static char hello_buf[100];static int hello_debugfs_show(struct seq_file *s, void *data)
{char* p = s->private;seq_printf(s, "%s", p);return 0;
}static int hello_open(struct inode* inode, struct file* file)
{return single_open(file, hello_debugfs_show, inode->i_private);
}static ssize_t hello_write(struct file *filp, const char __user *buf, size_t count,loff_t *ppos)
{int ret;if (*ppos > 100)return 0;if (*ppos + count > 100)count = 100 - *ppos;ret = copy_from_user(hello_buf, buf, count);if (ret)return -EFAULT;*ppos += count;return count;
}static struct file_operations hello_fops = {.owner = THIS_MODULE,.open = hello_open,.read = seq_read,.write = hello_write,.llseek = seq_lseek,.release = single_release,
};static int __init hello_debugfs_init(void)
{hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_file("hello_buffer", S_IWUGO, hello_root, hello_buf, &hello_fops);return 0;
}static void __exit hello_debugfs_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

9. 使用 seq_file 接口访问数组

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>struct hello_struct {unsigned int value;unsigned int id;
};static struct dentry *hello_root;
static struct hello_struct hello_array[8];
static char hello_buf[64];
static int index = 0;static void *hello_seq_start(struct seq_file *s, loff_t *pos)
{printk("------start: *pos = %lld\n", *pos);if (*pos == 0) {return &hello_array[0];} else {*pos = 0;return NULL;}
}static void *hello_seq_next(struct seq_file *s, void *v, loff_t *pos)
{struct hello_struct *p_node = NULL;(*pos)++;printk("------next: *pos = %lld\n", *pos);p_node = &hello_array[*pos];if (*pos == 8) {return NULL;}return p_node;
}static void hello_seq_stop(struct seq_file *s, void *v)
{printk("stop\n");
}static int hello_seq_show(struct seq_file *s, void *v)
{struct hello_struct *p = (struct hello_struct *)v;printk("------show: id = %d\n", p->id);if (p->id > 0) {seq_printf(s, "hello_arr[%d].value = 0x%x\n", p->id-1, \hello_array[p->id-1].value);}return 0;
}static struct seq_operations hello_seq_ops = {.start = hello_seq_start,.next  = hello_seq_next,.stop  = hello_seq_stop,.show  = hello_seq_show,
};static int hello_open(struct inode* inode, struct file* file)
{return seq_open(file, &hello_seq_ops);
}static ssize_t hello_write(struct file *filp, const char __user *buf, size_t len,loff_t *ppos)
{int ret;if (len == 0 || len > 64) {ret = -EFAULT;return ret;}ret = copy_from_user(hello_buf, buf, len);if (ret) {return -EFAULT;}printk("hello_write: index = %d\n", index);hello_array[index].id = index + 1;hello_array[index].value = simple_strtoul(hello_buf, NULL, 0);index++;if (index == 8) {index = 0;}return len;
}static struct file_operations hello_fops = {.owner = THIS_MODULE,.open = hello_open,.read = seq_read,.write = hello_write,.llseek = seq_lseek,
};static int __init hello_debugfs_init(void)
{hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_file("hello_buffer", S_IWUGO, hello_root, hello_array, &hello_fops);return 0;
}static void __exit hello_debugfs_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述
在这里插入图片描述

10. 使用 seq_file 接口访问链表

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>static struct dentry *hello_root;static char hello_buf[64];
static struct list_head hello_list_head;struct hello_struct {unsigned int value;struct list_head node;
};static void *hello_seq_start(struct seq_file *s, loff_t *pos)
{return seq_list_start(&hello_list_head, *pos);
}static void *hello_seq_next(struct seq_file *s, void *v, loff_t *pos)
{return seq_list_next(v, &hello_list_head, pos);
}static void hello_seq_stop(struct seq_file *s, void *v)
{// printk("stop\n");
}static int hello_seq_show(struct seq_file *s, void *v)
{struct hello_struct *p_node = list_entry(v, struct hello_struct, node);seq_printf(s, "node = 0x%x\n", p_node->value);return 0;
}static struct seq_operations hello_seq_ops = {.start = hello_seq_start,.next  = hello_seq_next,.stop  = hello_seq_stop,.show  = hello_seq_show,
};static int hello_open(struct inode* inode, struct file* file)
{return seq_open(file, &hello_seq_ops);
}static ssize_t hello_write(struct file *filp, const char __user *buf, size_t len,loff_t *ppos)
{int ret;struct hello_struct *data;if (len == 0 || len > 64) {ret = -EFAULT;return ret;}ret = copy_from_user(hello_buf, buf, len);if (ret) {return -EFAULT;}data = kmalloc(sizeof(struct hello_struct), GFP_KERNEL);if (data != NULL) {data->value = simple_strtoul(hello_buf, NULL, 0);list_add(&data->node, &hello_list_head);}return len;
}static struct file_operations hello_fops = {.open = hello_open,.read = seq_read,.write = hello_write,.llseek = seq_lseek,
};static int __init hello_debugfs_init(void)
{int ret = 0;INIT_LIST_HEAD(&hello_list_head);hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create debugfs dir failed\n", __func__);return PTR_ERR(hello_root);}debugfs_create_file("hello_list", S_IWUGO, hello_root, NULL, &hello_fops);return 0;
}static void __exit hello_debugfs_exit(void)
{struct hello_struct *data;if (hello_root) {debugfs_remove_recursive(hello_root);}while (!list_empty(&hello_list_head)) {data = list_entry(hello_list_head.next, struct hello_struct, node);list_del(&data->node);kfree(data);}
}module_init(hello_debugfs_init);
module_exit(hello_debugfs_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

11. 通过 debugfs 导出寄存器列表

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/debugfs.h>typedef volatile struct {unsigned long  RTCDR;    /* +0x00: data register */unsigned long  RTCMR;    /* +0x04: match register */unsigned long  RTCLR;    /* +0x08: load register */unsigned long  RTCCR;    /* +0x0C: control register */unsigned long  RTCIMSC;  /* +0x10: interrupt mask set and clear register*/unsigned long  RTCRIS;   /* +0x14: raw interrupt status register*/unsigned long  RTCMIS;   /* +0x18: masked interrupt status register */unsigned long  RTCICR;   /* +0x1C: interrupt clear register */
} rtc_reg_t;struct rtc_time {unsigned int year;unsigned int mon;unsigned int day;unsigned int hour;unsigned int min;unsigned int sec;
};#define RTC_BASE 0x10017000static volatile rtc_reg_t *regs = NULL;
static unsigned long cur_time = 0;
static struct rtc_time tm;static dev_t devno;
static struct cdev *rtc_cdev;static void rtc_time_translate(void)
{tm.hour = (cur_time  % 86400) / 3600;tm.min  = (cur_time  % 3600) / 60;tm.sec  = cur_time  % 60;
}static void set_rtc_alarm(void)
{unsigned long tmp = 0;tmp = regs->RTCCR;tmp = tmp & 0xFFFFFFFE;regs->RTCCR = tmp;cur_time = regs->RTCDR;regs->RTCMR = cur_time + 15;regs->RTCICR = 0x1;regs->RTCIMSC = 0x1;tmp = regs->RTCCR;tmp = tmp | 0x1;regs->RTCCR = tmp;
}static irqreturn_t rtc_alarm_handler(int irq, void *dev_id)
{cur_time = regs->RTCDR;rtc_time_translate();printk("\nalarm: beep~ beep~ \n");printk("\n    %d:%d:%d\n", tm.hour, tm.min, tm.sec);regs->RTCICR = 1;set_rtc_alarm();return IRQ_HANDLED;
}static struct file_operations rtc_fops;static const struct debugfs_reg32 rtc_reg_array[] = {{.name   = "RTCDR",.offset = 0x0},{.name   = "RTCMR",.offset = 0x4},{.name   = "RTCLR",.offset = 0x8},{.name   = "RTCCR",.offset = 0xC},{.name   = "RTCIMSC",.offset = 0x10},{.name   = "RTCRIS",.offset = 0x14},{.name   = "RTCMIS",.offset = 0x18},{.name   = "RTCICR",.offset = 0x1C}
};static struct debugfs_regset32 rtc_regset; // <------
static struct dentry *hello_root;static int __init rtc_init(void)
{int ret = 0;regs = (rtc_reg_t *)ioremap(RTC_BASE, sizeof(rtc_reg_t));ret = alloc_chrdev_region(&devno, 0, 1, "rtc-demo");if (ret) {printk("alloc char device number failed!\n");return ret;}printk("RTC devnum:%d minornum:%d\n", MAJOR(devno), MINOR(devno));rtc_cdev = cdev_alloc();cdev_init(rtc_cdev, &rtc_fops);ret = cdev_add(rtc_cdev, devno, 1);if (ret < 0) {printk("cdev_add failed..\n");return -1;} else {printk("Register char module: rtc success!\n");}ret = request_irq(39, rtc_alarm_handler, 0, "rtc-test", NULL);if (ret == -1) {printk("request_irq failed!\n");return -1;}set_rtc_alarm();hello_root = debugfs_create_dir("hello", NULL);if (IS_ERR(hello_root)) {pr_err("%s: create rtc dir failed\n", __func__);return PTR_ERR(hello_root);}rtc_regset.regs  = rtc_reg_array;rtc_regset.nregs = 8;rtc_regset.base  = (void *)regs;debugfs_create_regset32("reglist", 0644, hello_root, &rtc_regset); // <------return 0;
}static void __exit rtc_exit(void)
{if (hello_root) {debugfs_remove_recursive(hello_root);}free_irq(39, NULL);cdev_del(rtc_cdev);unregister_chrdev_region(devno, 1);
}module_init(rtc_init);
module_exit(rtc_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

12. 通过 debugfs 修改 RTC 寄存器

  • 关闭内核自带的 rtc 驱动
  • 打开 debugfs 选项

在这里插入图片描述
在这里插入图片描述

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>typedef volatile struct {unsigned int  RTCDR;    /* +0x00: data register */unsigned int  RTCMR;    /* +0x04: match register */unsigned int  RTCLR;    /* +0x08: load register */unsigned int  RTCCR;    /* +0x0C: control register */unsigned int  RTCIMSC;  /* +0x10: interrupt mask set and clear register*/unsigned int  RTCRIS;   /* +0x14: raw interrupt status register*/unsigned int  RTCMIS;   /* +0x18: masked interrupt status register */unsigned int  RTCICR;   /* +0x1C: interrupt clear register */
}rtc_reg_t;struct rtc_time {unsigned int year;unsigned int mon;unsigned int day;unsigned int hour;unsigned int min;unsigned int sec;
};#define RTC_BASE 0x10017000static volatile rtc_reg_t *regs = NULL;
static unsigned long cur_time = 0;
static struct rtc_time tm;static void rtc_time_translate(void)
{tm.hour = (cur_time  % 86400) / 3600;tm.min  = (cur_time  % 3600) / 60;tm.sec  = cur_time  % 60;
}static void rtc_tm_to_time(void)
{cur_time = tm.hour * 3600 + tm.min * 60 + tm.sec;
}static dev_t devno;
static struct cdev *rtc_cdev;static int rtc_open(struct inode *inode, struct file *fp)
{return 0;
}static int rtc_release(struct inode *inode, struct file *fp)
{return 0;
}static ssize_t rtc_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
{cur_time = regs->RTCDR;rtc_time_translate();if (copy_to_user(buf, &tm, sizeof(struct rtc_time)) != 0){printk("rtc_read error!\n");return -1;}return sizeof(struct rtc_time);
}static ssize_t rtc_write(struct file *fp, const char __user *buf, size_t size, loff_t *pos)
{int len = 0;len = sizeof(struct rtc_time);if (copy_from_user(&tm, buf, len) != 0) {printk("rtc_write error!\n");return -1;}rtc_tm_to_time();regs->RTCLR = cur_time;return len;
}/* standard file I/O system call interface */
static const struct file_operations rtc_fops = {.owner   = THIS_MODULE,.read    = rtc_read,.write   = rtc_write,.open    = rtc_open,.release = rtc_release,
};static void set_rtc_alarm(void)
{unsigned int tmp = 0;tmp = regs->RTCCR;tmp = tmp & 0xFFFFFFFE;regs->RTCCR = tmp;cur_time = regs->RTCDR;regs->RTCMR = cur_time + 25; // <------regs->RTCICR = 1;regs->RTCIMSC = 1; // <------tmp = regs->RTCCR;tmp = tmp | 0x1;regs->RTCCR = tmp;
}static irqreturn_t rtc_alarm_handler(int irq, void *dev_id)
{cur_time = regs->RTCDR;rtc_time_translate();printk("\nalarm: beep~ beep~ \n");printk("\n    %d:%d:%d\n", tm.hour, tm.min, tm.sec);regs->RTCICR = 1;set_rtc_alarm();return IRQ_HANDLED;
}static struct dentry *rtc_root;
static struct dentry *reg_dir;
static u32 *reg_p = NULL;static int __init rtc_init(void)
{int ret = 0;regs = (rtc_reg_t *)ioremap(RTC_BASE, sizeof(rtc_reg_t));printk("rtc_init\n");ret = alloc_chrdev_region(&devno, 0, 1, "rtc-demo");if (ret) {printk("alloc char device number failed!\n");return ret;}printk("RTC devnum:%d minornum:%d\n", MAJOR(devno), MINOR(devno));rtc_cdev = cdev_alloc();cdev_init(rtc_cdev, &rtc_fops);ret = cdev_add(rtc_cdev, devno, 1);if (ret < 0) {printk("cdev_add failed..\n");return -ret;} else {printk("Register char module: rtc success!\n");}ret = request_irq(39, rtc_alarm_handler, 0, "rtc-test", NULL);if (ret == -1) {printk("request_irq failed!\n");return -ret;}rtc_root = debugfs_create_dir("rtc", NULL);if (IS_ERR(rtc_root)) {pr_err("%s: create rtc dir failed\n", __func__);return PTR_ERR(rtc_root);}reg_dir = debugfs_create_dir("reg_list", rtc_root);if (IS_ERR(reg_dir)) {pr_err("%s: create reg dir failed\n", __func__);return PTR_ERR(reg_dir);}reg_p = (u32 *)regs;debugfs_create_x32("RTCDR", 0644, reg_dir, reg_p);debugfs_create_x32("RTCMR", 0644, reg_dir, reg_p + 0x01);debugfs_create_x32("RTCLR", 0644, reg_dir, reg_p + 0x02);debugfs_create_x32("RTCCR", 0644, reg_dir, reg_p + 0x03);debugfs_create_x32("RTCIMSC", 0644, reg_dir, reg_p + 0x04);debugfs_create_x32("RTCRIS", 0644, reg_dir, reg_p + 0x05);debugfs_create_x32("RTCMIS", 0644, reg_dir, reg_p + 0x06);debugfs_create_x32("RTCICR", 0644, reg_dir, reg_p + 0x07);set_rtc_alarm();return 0;
}static void __exit rtc_exit(void)
{if (rtc_root) {debugfs_remove_recursive(rtc_root);}free_irq(39, NULL);cdev_del(rtc_cdev);unregister_chrdev_region(devno, 1);
}module_init(rtc_init);
module_exit(rtc_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

13. 通过 debugfs 导出 RTC 调试接口

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>typedef volatile struct {unsigned int  RTCDR;    /* +0x00: data register */unsigned int  RTCMR;    /* +0x04: match register */unsigned int  RTCLR;    /* +0x08: load register */unsigned int  RTCCR;    /* +0x0C: control register */unsigned int  RTCIMSC;  /* +0x10: interrupt mask set and clear register*/unsigned int  RTCRIS;   /* +0x14: raw interrupt status register*/unsigned int  RTCMIS;   /* +0x18: masked interrupt status register */unsigned int  RTCICR;   /* +0x1C: interrupt clear register */
} rtc_reg_t;struct rtc_time {unsigned int year;unsigned int mon;unsigned int day;unsigned int hour;unsigned int min;unsigned int sec;
};#define RTC_BASE 0x10017000#define CUR_TIME_CMD   1      /* command for set/get current time */
#define ALARM_TIME_CMD 2      /* command for set/get alarm time */static volatile rtc_reg_t *regs = NULL;
static unsigned long cur_time = 0;   /* current time */
static unsigned long alarm_time = 0; /* alarm time  */
static struct rtc_time tm; /* global time */
static char rtc_buf[64]; /* buffer for time string input from user space */static void rtc_time_to_tm(unsigned long time)
{tm.hour = (time % 86400) / 3600;tm.min  = (time % 3600) / 60;tm.sec = time % 60;
}static void rtc_tm_to_time(unsigned long *time)
{*time = tm.hour * 3600 + tm.min * 60 + tm.sec;
}static void rtc_string_to_tm(void)
{tm.hour = (rtc_buf[0] - '0') * 10 + (rtc_buf[1] - '0');tm.min  = (rtc_buf[2] - '0') * 10 + (rtc_buf[3] - '0');tm.sec  = (rtc_buf[4] - '0') * 10 + (rtc_buf[5] - '0');
}static void rtc_tm_to_string(void)
{rtc_buf[0] = tm.hour / 10 + '0';rtc_buf[1] = tm.hour % 10 + '0';rtc_buf[2] = tm.min / 10 + '0';rtc_buf[3] = tm.min % 10 + '0';rtc_buf[4] = tm.sec / 10 + '0';rtc_buf[5] = tm.sec % 10 + '0';rtc_buf[6] = '\n';rtc_buf[7] = '\0';
}static dev_t devno;
static struct cdev *rtc_cdev;static int rtc_open(struct inode *inode, struct file *fp)
{return 0;
}static int rtc_release(struct inode *inode, struct file *fp)
{return 0;
}static ssize_t rtc_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
{cur_time = regs->RTCDR;rtc_time_to_tm(cur_time);if (copy_to_user(buf, &tm, sizeof(struct rtc_time)) != 0){printk("rtc_read error!\n");return -1;}return sizeof(struct rtc_time);
}static ssize_t rtc_write(struct file *fp, const char __user *buf, size_t size, loff_t *pos)
{int len = 0;len = sizeof(struct rtc_time);if (copy_from_user(&tm, buf, len) != 0) {printk("rtc_write error!\n");return -1;}rtc_tm_to_time(&cur_time);regs->RTCLR = cur_time;return len;
}/* standard file I/O system call */
static const struct file_operations rtc_fops = {.owner   = THIS_MODULE,.read    = rtc_read,.write   = rtc_write,.open    = rtc_open,.release = rtc_release,
};static void set_rtc_alarm(void)
{unsigned int tmp = 0;tmp = regs->RTCCR;tmp = tmp & 0xFFFFFFFE;regs->RTCCR = tmp;cur_time = regs->RTCDR;regs->RTCMR = alarm_time;regs->RTCICR = 1;regs->RTCIMSC = 1; // <------tmp = regs->RTCCR;tmp = tmp | 0x1;regs->RTCCR = tmp;
}static irqreturn_t rtc_alarm_handler(int irq, void *dev_id)
{cur_time = regs->RTCDR;rtc_time_to_tm(cur_time);printk("\nalarm: beep~ beep~ \n");printk("\n    %d:%d:%d\n", tm.hour, tm.min, tm.sec);regs->RTCICR = 1;return IRQ_HANDLED;
}static ssize_t rtc_debugfs_read(struct file *filp, char __user *buf,size_t count, loff_t *ppos, int cmd)
{int ret;if (*ppos >= 64)return 0;if (*ppos + count > 64)count = 64 - *ppos;if (cmd == CUR_TIME_CMD) {cur_time = regs->RTCDR;rtc_time_to_tm(cur_time);}if (cmd == ALARM_TIME_CMD) {alarm_time = regs->RTCMR;rtc_time_to_tm(alarm_time);}rtc_tm_to_string();ret = copy_to_user(buf, rtc_buf, count);if (ret)return -EFAULT;*ppos += count;return count;
}static ssize_t rtc_debugfs_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos, int cmd)
{int ret;if (*ppos > 64)return 0;if (*ppos + count > 64)count = 64 - *ppos;ret = copy_from_user(rtc_buf, buf, count);if (ret)return -EFAULT;*ppos += count;rtc_string_to_tm();if (cmd == CUR_TIME_CMD) {rtc_tm_to_time(&cur_time);regs->RTCLR = cur_time;}if (cmd == ALARM_TIME_CMD) {rtc_tm_to_time(&alarm_time);set_rtc_alarm();}return count;
}/* set current time interface */
static ssize_t rtc_cur_time_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{return rtc_debugfs_read(filp, buf, count, ppos, CUR_TIME_CMD);
}static ssize_t rtc_cur_time_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{return rtc_debugfs_write(filp, buf, count, ppos, CUR_TIME_CMD);
}static const struct file_operations rtc_cur_time_fops = {.read    = rtc_cur_time_read,.write   = rtc_cur_time_write,
};/* set alarm time interface */
static ssize_t rtc_alarm_time_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{return rtc_debugfs_read(filp, buf, count, ppos, ALARM_TIME_CMD);
}static ssize_t rtc_alarm_time_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{return rtc_debugfs_write(filp, buf, count, ppos, ALARM_TIME_CMD);
}static const struct file_operations rtc_alarm_time_fops = {.read    = rtc_alarm_time_read,.write   = rtc_alarm_time_write,
};static struct dentry *rtc_root;
static struct dentry *reg_dir;
static u32 *reg_p = NULL;static int __init rtc_init(void)
{int ret = 0;regs = (rtc_reg_t *)ioremap(RTC_BASE, sizeof(rtc_reg_t));printk("rtc_init\n");ret = alloc_chrdev_region(&devno, 0, 1, "rtc-demo");if (ret) {printk("alloc char device number failed!\n");return ret;}printk("RTC devnum:%d minornum:%d\n", MAJOR(devno), MINOR(devno));rtc_cdev = cdev_alloc();cdev_init(rtc_cdev, &rtc_fops);ret = cdev_add(rtc_cdev, devno, 1);if (ret < 0) {printk("cdev_add failed..\n");return -ret;} else {printk("Register char module: rtc success!\n");}ret = request_irq(39, rtc_alarm_handler, 0, "rtc-test", NULL);if (ret == -1) {printk("request_irq failed!\n");return -ret;}rtc_root = debugfs_create_dir("rtc", NULL);if (IS_ERR(rtc_root)) {pr_err("%s: create rtc dir failed\n", __func__);return PTR_ERR(rtc_root);}reg_dir = debugfs_create_dir("reg_list", rtc_root);if (IS_ERR(reg_dir)) {pr_err("%s: create reg dir failed\n", __func__);return PTR_ERR(reg_dir);}reg_p = (u32 *)regs;debugfs_create_x32("RTCDR", 0644, reg_dir, reg_p);debugfs_create_x32("RTCMR", 0644, reg_dir, reg_p + 0x01);debugfs_create_x32("RTCLR", 0644, reg_dir, reg_p + 0x02);debugfs_create_x32("RTCCR", 0644, reg_dir, reg_p + 0x03);debugfs_create_x32("RTCIMSC", 0644, reg_dir, reg_p + 0x04);debugfs_create_x32("RTCRIS", 0644, reg_dir, reg_p + 0x05);debugfs_create_x32("RTCMIS", 0644, reg_dir, reg_p + 0x06);debugfs_create_x32("RTCICR", 0644, reg_dir, reg_p + 0x07);debugfs_create_file("cur_time", 0644, rtc_root, NULL, &rtc_cur_time_fops);debugfs_create_file("alarm_time", 0644, rtc_root, NULL, &rtc_alarm_time_fops);return 0;
}static void __exit rtc_exit(void)
{if (rtc_root) {debugfs_remove_recursive(rtc_root);}free_irq(39, NULL);cdev_del(rtc_cdev);unregister_chrdev_region(devno, 1);
}module_init(rtc_init);
module_exit(rtc_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/411373.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu20.04可以同时安装ROS(Noetic)和ROS2(Humble)

Ubuntu系统确实可以同时安装ROS&#xff08;Robot Operating System&#xff09;和ROS2&#xff0c;但需要注意一些关键步骤和配置以确保两者能够顺利共存并独立运行。以下是在Ubuntu上同时安装ROS和ROS2的详细步骤和注意事项&#xff1a; 安装前准备 检查Ubuntu版本&#xff…

nacos 动态读取nacos配置中心项目配置

实现了项目稳定运行情况下不需要在项目中改配置&#xff0c;直接在nacos中修改更方便。 pom文件&#xff1a; <!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap…

HarmonyOs应用权限申请,system_grant和user_grant区别。本文附头像上传申请user-grant权限代码示例

HarmonyOs应用权限申请&#xff0c;system_grant和user_grant区别。本文附头像上传申请user-grant权限代码示例 system_grant&#xff08;系统授权&#xff09; system_grant指的是系统授权类型&#xff0c;在该类型的权限许可下&#xff0c;应用被允许访问的数据不会涉及到用户…

大数据测试怎么做,数据应用测试、数据平台测试、数据仓库测试

本期内容由中通科技高级质量工程师龙渊在公益讲座中分享&#xff0c;他从大数据测试整体介绍、数据应用测试、数据平台测试以及数据仓库测试等方面&#xff0c;与大家共同探讨了大数据测试的方法实施与落地。 以下是讲座正文&#xff1a; 今天我们分享的内容主要从大数据简介…

二、基于Vue3的开发-环境搭建【Visual Studio Code】扩展组件

Visual Studio Code中的扩展组件 1、安装的扩展工具2、说明2.1 、代码规范性检查EsLint2.2 、代码语法高亮提示工具Vue - Official2.3 、阿里的AI代码开发提示工具 TONGYI Lingma 1、安装的扩展工具 2、说明 2.1 、代码规范性检查EsLint Visual Studio Code 中【设置】-setti…

基于springboot+vue+uniapp的使命召唤游戏助手小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

OSI七层模型中的数据链路层

图片&#xff1a;数据帧的格式 这里面的一个关键点是&#xff0c;数据的源IP和目标IP在哪里&#xff1f; 就在图中的“数据”里面&#xff0c;这个“数据”也就是网络层的数据包&#xff0c;如果是TCP类型的数据包&#xff0c;数据包里面就包含TCP类型的首部信息&#xff0c;…

使用excel把json文件转为表格

json文件格式 [ { "ID": "16", "名称": "测站", "管理ID": "3", "管理名称": "土", "辅助信息": { "百度经度&qu…

linux neo4j 切换知识图谱

neo4j 安装 linux neo4j的安装可以浏览这篇文章&#xff1a; ubuntu sudo apt-get install neo4j 配置安装与设置远程访问 引言 如果你是window用户&#xff0c;直接下载桌面版进行安装与使用即可&#xff1b; 我有一台linux的服务器&#xff0c;想部署在上面&#xff0c;不…

阿里云私有镜像仓库配置及使用

1 登录阿里云 阿里云访问地址&#xff1a;https://www.aliyun.com/ 右上角选择“控制台” 2 创建个人实例 搜索框搜索“容器镜像服务” 新建“个人实例” 选择“创建个人版” 同意协议&#xff0c;点击确定 3 个人实例配置 设置Registry登录密码 密码要求&#xff1…

[Arxiv 2024] Self-Rewarding Language Models

Contents IntroductionMethodExperimentsReferences Introduction 作者提出 Self-Rewarding 训练框架&#xff0c;LLM 在训练过程中同时担任 actor 和 critic&#xff0c;actor 负责合成新数据&#xff0c;critic 负责判断合成数据质量用于组成高质量的偏好数据集用于模型的下…

NoSql数据库Redis集群

一、关系型数据库和 NoSQL 数据库 1.1 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 关系型数据库 &#xff0c;是建立在关系模型基础上的数据库&#xff0c;其借助于集合代数等数学概念和方法来处理数据库中的数据主流的 MySQL 、 Oracle 、 MS SQL Server…

ElasticSearch和Kibana的安全设置以及https设置

&#x1f468;‍&#x1f4bb;本文专栏&#xff1a;ElasticSearch和Kibana的安全设置以及https设置 &#x1f468;‍&#x1f4bb;本文简述&#xff1a;跟着猿灰灰一起学Java&#xff01; &#x1f468;‍&#x1f4bb;上一篇文章&#xff1a; &#x1f468;‍&#x1f4bb;有任…

『功能项目』怪物受击的动画事件【10】

我们打开上一篇09着色器光透魔法球的项目&#xff0c; 本章要做的事情是在场景中创建一个怪物对象&#xff0c;当怪物被主角的魔法球击中后播放受击动画效果&#xff0c;此类技术用到动画事件帧&#xff0c;在动画上创建脚本。 首先打开资源商店选择一个免费资源的怪物模型加载…

apache httpclient速成

目录标题 快速使用连接池参数连接池状态清除闲置连接evictIdleConnections删除过期连接 timeToLive 和evictExpiredConnections 注意释放内存关闭流 http和netty的关系 导入依赖 <dependency><groupId>org.apache.httpcomponents.client5</groupId><artif…

【ceph学习】S3权限认证部分

认证过程简介 认证的过程是一个对用户信息进行解析并且判断前后得到的秘钥是否一致的过程。 auth_regitry的创建 在rgw_main.cc:main()中进行初始化auth_registry对象 /*rgw_main.cc*/ /* Initialize the registry of auth strategies which will coordinate * the dynamic…

浏览器中的开源SQL可视化工具:sqliteviz

sqliteviz&#xff1a; 在浏览器中&#xff0c;即刻开启数据可视化之旅。- 精选真开源&#xff0c;释放新价值。 概览 sqliteviz是一个专为数据可视化而设计的单页离线优先PWA&#xff0c;它利用了现代浏览器技术&#xff0c;让用户无需安装任何软件即可在本地浏览器中进行SQL…

WxPython可视化编辑器

作者&#xff1a;陈炳强 WxPython是python的一个用来写桌面程序的模块,目前只写了小部分功能跟组件, 用Python写中文&#xff0c;非常方便&#xff01; 下载地址&#xff1a;https://pan.quark.cn/s/ba19b2472246

大模型提示词工程技术2-设计有效的提示词技巧、角色与上下文在提示中的应用

大模型提示词工程技术2-设计有效的提示词技巧、角色与上下文在提示中的应用。《大模型提示词工程技术》的作者&#xff1a;微学AI&#xff0c;这是一本专注于提升人工智能大模型性能的著作&#xff0c;它深入浅出地讲解了如何通过优化输入提示词来引导大模型生成高质量、准确的…

19.神经网络 - 线性层及其他层介绍

神经网络 - 线性层及其他层介绍 1.批标准化层–归一化层&#xff08;不难&#xff0c;自学看官方文档&#xff09; Normalization Layers torch.nn — PyTorch 1.10 documentation BatchNorm2d — PyTorch 1.10 documentation 对输入采用Batch Normalization&#xff0c;可…