驱动调试之proc文件系统
2016-09-20 19:18
721 查看
一、思维导读
我们知道在/proc目录下存在一些文件,我们可以使用cat、echo命令来查询和设置一些系统的信息(比如查看内存的信息和cpu的信息等),可见/proc目录下的文件提供给我们和内核交互的功能。那么如果我们的驱动也有对应的proc文件,我们就可以和驱动进行交互,实时读取和修改驱动中变量的值,这样一来驱动调试就非常方便了!本文会给出proc的一些基本概念来加深对proc文件系统的理解,但是主要在于应用,下面会贴出一个简单的例子,若是要用直接复制然后自己进行相应的修改即可!
二、proc文件系统
proc文件系统是一种无存储的文件系统,当读其中的文件时,其内容由文件关联的读函数动态生成,当写文件时,文件所关联的写函数被调用。每个proc文件都关联特定的读写函数,因而它提供了另外的一种和内核通信的机制:内核部件可以通过该文件系统向用户空间提供接口来提供查询信息、修改软件行为,因而它是一种比较重要的特殊文件系统。
由于proc文件系统以文件的形式向用户空间提供了访问接口,这些接口可以用于在运行时获取相关部件的信息或者修改部件的行为,因而它是非常方便的一个接口。内核中大量使用了该文件系统。proc文件系统就是一个文件系统,它可以挂载在目录树的任意位置,不过通常挂载在/proc下。
三、proc数据结构
a、proc文件及目录在内核中用proc_dir_entry来表示。它在proc文件系统内部包含了proc文件的所有信息。其数据结构如下所示
struct proc_dir_entry {
unsigned int low_ino;
umode_t mode;
nlink_t nlink;
kuid_t uid;
kgid_t gid;
loff_t size;
const struct inode_operations *proc_iops;//inode操作
const struct file_operations *proc_fops;//文件操作
struct proc_dir_entry *next, *parent, *subdir;
void *data;
read_proc_t *read_proc;
write_proc_t *write_proc;
atomic_t count;
int pde_users;
struct completion *pde_unload_completion;
struct list_head pde_openers;
spinlock_t pde_unload_lock;
u8 namelen;
char name[];
};
b、内核还提供了一个数据结构proc_inode用于将特定于proc的数据与文件所对应的inode关联起来,其定义如下。借助该数据结构,内核可以方便的在inode和与该inode相关的proc数据之间进行转换。
struct proc_inode {
struct pid *pid;
int fd;
union proc_op op;
struct proc_dir_entry *pde;
struct ctl_table_header *sysctl;
struct ctl_table *sysctl_entry;
void *ns;
const struct proc_ns_operations *ns_ops;
struct inode vfs_inode;
};
四、操作proc文件系统的API
相关的函数在内核代码的头文件<linux/proc_fs.h>声明,主要用到以下三个函数。
1、这个函数用于在proc文件系统中创建一个proc文件。
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent);
2、这个函数用于在proc文件系统中创建一个目录项,大多数时候,当我们期望实现自己的proc文件时,都要先创建一个自己的目录,然后在该目录里创建自己的文件,当然我们也可以直接在已经存在的proc文件系统目录里创建自己的文件
struct proc_dir_entry *proc_mkdir(const char *name,
struct proc_dir_entry *parent);
3、这个函数用于从proc文件系统的指定目录删除指定的proc文件。实际上也可以用来删除目录的。
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
五、例子
驱动源代码:
我们知道在/proc目录下存在一些文件,我们可以使用cat、echo命令来查询和设置一些系统的信息(比如查看内存的信息和cpu的信息等),可见/proc目录下的文件提供给我们和内核交互的功能。那么如果我们的驱动也有对应的proc文件,我们就可以和驱动进行交互,实时读取和修改驱动中变量的值,这样一来驱动调试就非常方便了!本文会给出proc的一些基本概念来加深对proc文件系统的理解,但是主要在于应用,下面会贴出一个简单的例子,若是要用直接复制然后自己进行相应的修改即可!
二、proc文件系统
proc文件系统是一种无存储的文件系统,当读其中的文件时,其内容由文件关联的读函数动态生成,当写文件时,文件所关联的写函数被调用。每个proc文件都关联特定的读写函数,因而它提供了另外的一种和内核通信的机制:内核部件可以通过该文件系统向用户空间提供接口来提供查询信息、修改软件行为,因而它是一种比较重要的特殊文件系统。
由于proc文件系统以文件的形式向用户空间提供了访问接口,这些接口可以用于在运行时获取相关部件的信息或者修改部件的行为,因而它是非常方便的一个接口。内核中大量使用了该文件系统。proc文件系统就是一个文件系统,它可以挂载在目录树的任意位置,不过通常挂载在/proc下。
三、proc数据结构
a、proc文件及目录在内核中用proc_dir_entry来表示。它在proc文件系统内部包含了proc文件的所有信息。其数据结构如下所示
struct proc_dir_entry {
unsigned int low_ino;
umode_t mode;
nlink_t nlink;
kuid_t uid;
kgid_t gid;
loff_t size;
const struct inode_operations *proc_iops;//inode操作
const struct file_operations *proc_fops;//文件操作
struct proc_dir_entry *next, *parent, *subdir;
void *data;
read_proc_t *read_proc;
write_proc_t *write_proc;
atomic_t count;
int pde_users;
struct completion *pde_unload_completion;
struct list_head pde_openers;
spinlock_t pde_unload_lock;
u8 namelen;
char name[];
};
b、内核还提供了一个数据结构proc_inode用于将特定于proc的数据与文件所对应的inode关联起来,其定义如下。借助该数据结构,内核可以方便的在inode和与该inode相关的proc数据之间进行转换。
struct proc_inode {
struct pid *pid;
int fd;
union proc_op op;
struct proc_dir_entry *pde;
struct ctl_table_header *sysctl;
struct ctl_table *sysctl_entry;
void *ns;
const struct proc_ns_operations *ns_ops;
struct inode vfs_inode;
};
四、操作proc文件系统的API
相关的函数在内核代码的头文件<linux/proc_fs.h>声明,主要用到以下三个函数。
1、这个函数用于在proc文件系统中创建一个proc文件。
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent);
2、这个函数用于在proc文件系统中创建一个目录项,大多数时候,当我们期望实现自己的proc文件时,都要先创建一个自己的目录,然后在该目录里创建自己的文件,当然我们也可以直接在已经存在的proc文件系统目录里创建自己的文件
struct proc_dir_entry *proc_mkdir(const char *name,
struct proc_dir_entry *parent);
3、这个函数用于从proc文件系统的指定目录删除指定的proc文件。实际上也可以用来删除目录的。
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
五、例子
驱动源代码:
#include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_gpio.h> #include <linux/of_address.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/types.h> #include <linux/cdev.h> #include <linux/i2c.h> #include <linux/of_gpio.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <asm/uaccess.h> #define PROCFS_MAX_SIZE 128 #define PROC_DIR "dspinfo" /*类型定义*/ struct plat_info { unsigned char cputype[10]; unsigned char cpufreq[10]; unsigned char ramsize[10]; unsigned char attr[10]; }; /*全局变量*/ static char S_procfs_buffer[PROCFS_MAX_SIZE]; static char S_debug = 0; struct plat_info dsp_data[] = { { .cpufreq = "456", .cputype = "C6746", .ramsize = "64M", .attr = "standard", }, { .cpufreq = "456", .cputype = "C6746", .ramsize = "64M", .attr = "standard", }, { .cpufreq = "456", .cputype = "C6746", .ramsize = "64M", .attr = "extended", }, { .cpufreq = "456", .cputype = "C6746", .ramsize = "64M", .attr = "extended", }, { .cpufreq = "456", .cputype = "C6746", .ramsize = "64M", .attr = "extended", }, { .cpufreq = "456", .cputype = "C6746", .ramsize = "64M", .attr = "extended", }, { .cpufreq = "456", .cputype = "C6746", .ramsize = "64M", .attr = "extended", } }; /*函数声明*/ static int dsp_proc_read(struct seq_file *m, void *p); static void *c_start(struct seq_file *m, loff_t *pos) { return *pos < 1 ? (void *)1 : NULL; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { ++*pos; return NULL; } static void c_stop(struct seq_file *m, void *v) { /*nothing to do*/ } static int c_show(struct seq_file *m, void *p) { /*调用自己实现的proc读函数*/ dsp_proc_read(m, p); return 0; } static struct seq_operations proc_seq_ops = { .show = c_show, .start = c_start, .next = c_next, .stop = c_stop }; static int dsp_proc_open(struct inode *inode, struct file *file) { int ret = 0; struct seq_file *m; ret = seq_open(file, &proc_seq_ops); m = file->private_data; m->private = file->f_dentry->d_iname; return ret; } static int dsp_proc_read(struct seq_file *m, void *p) { int num = 0; u8 *name, *cputype, *cpufreq, *ramsize, *attr; name = m->private; num = name[3] - '0'; cpufreq = dsp_data[num-1].cpufreq; cputype = dsp_data[num-1].cputype; ramsize = dsp_data[num-1].ramsize; attr = dsp_data[num-1].attr; seq_printf(m, "attr : %s\n", attr); seq_printf(m, "cputype : %s\n", cputype); seq_printf(m, "cpufreq : %s\n", cpufreq); seq_printf(m, "ramsize : %s\n", ramsize); seq_printf(m, "\n"); return 0; } static int dsp_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *offp) { int value; int procfs_buffer_size; if(count > PROCFS_MAX_SIZE) { procfs_buffer_size = PROCFS_MAX_SIZE; } else { procfs_buffer_size = count; } if (copy_from_user(S_procfs_buffer, buffer, procfs_buffer_size)) { return -EFAULT; } *(S_procfs_buffer+procfs_buffer_size) = 0; if(sscanf(S_procfs_buffer , "set debug %d" , &value)==1) { S_debug = value; } else { printk("=================\n"); printk("usage: \n"); printk("set debug <value>\n"); printk("=================\n"); } return count; } static struct file_operations proc_fops = { .open = dsp_proc_open, .read = seq_read, .write = dsp_proc_write, }; int dsp_create_proc(char *name) { struct proc_dir_entry *dsp_proc_entries; u8 proc_name[50]={0}; if(PROC_DIR == NULL) { sprintf(proc_name, "%s", name); } else { sprintf(proc_name, "%s/%s", PROC_DIR, name); } dsp_proc_entries = proc_create(proc_name, 0644, NULL, &proc_fops); if (NULL == dsp_proc_entries) { remove_proc_entry(proc_name, NULL); printk("Error: Could not initialize /proc/%s\n", proc_name); return -ENOMEM; } return 0; } int dsp_create_proc_parentdir(void) { struct proc_dir_entry *mydir = NULL; mydir = proc_mkdir(PROC_DIR, NULL); if (!mydir) { printk(KERN_ERR "Can't create /proc/%s\n", PROC_DIR); return -1; } return 0; } void dsp_remove_proc(char *name) { u8 proc_name[50]={0}; if(PROC_DIR == NULL) { sprintf(proc_name, "%s", name); } else { sprintf(proc_name, "%s/%s", PROC_DIR, name); } remove_proc_entry(proc_name, NULL); return; } void dsp_remove_proc_parentdir(void) { if(PROC_DIR != NULL) { remove_proc_entry(PROC_DIR, NULL); } return; } static int __init driver_proc_init(void) { printk("%s...\n", __func__); dsp_create_proc_parentdir(); dsp_create_proc("dsp1"); dsp_create_proc("dsp2"); dsp_create_proc("dsp3"); return 0; } static void __exit driver_proc_exit(void) { printk("%s...\n", __func__); dsp_remove_proc("dsp1"); dsp_remove_proc("dsp2"); dsp_remove_proc("dsp3"); dsp_remove_proc_parentdir(); } module_init(driver_proc_init); module_exit(driver_proc_exit); MODULE_AUTHOR("Jimmy"); MODULE_DESCRIPTION("driver for proc test"); MODULE_LICENSE("GPL");Makefile文件:
ifneq ($(KERNELRELEASE),) obj-m := driver_proc.o else KERNELDIR ?= /ljm/git_imx6/linux-fsl/src/linux-3-14-28-r0 TARGET_CROSS = arm-none-linux-gnueabi- PWD := $(shell pwd) default: $(MAKE) ARCH=arm CROSS_COMPILE=$(TARGET_CROSS) -C $(KERNELDIR) M=$(PWD) modules endif install: $(MAKE) ARCH=arm CROSS_COMPILE=$(TARGET_CROSS) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers *.order
相关文章推荐
- kobox: key_proc.c -v1 怎样使用proc文件系统调试驱动
- Proc文件系统接口调试
- /proc 文件系统——提供一种驱动调试的利器
- 内核驱动之proc文件系统
- linux设备驱动学习--proc文件系统
- 五。内核代码调试方法——proc文件系统、seqfile文件系统
- 驱动调试之打印到proc虚拟文件1
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】揭开Linux Proc文件系统的神秘面纱
- 设备驱动之一 - proc文件系统接口
- Linux RTC驱动分析(三)----sys和proc文件系统
- 驱动调试之打印到proc虚拟文件3--实验
- 驱动调试之打印到proc虚拟文件2--编写程序
- proc文件系统用于内核调试
- PROC文件系统介绍 &&以PROC在线调试LCM && EXPORT_SYMBOL的用法
- 设备驱动之一 - proc文件系统接口
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】揭开Linux Proc文件系统的神秘面纱
- /proc/kcore失效,调试其文件系统相关模块,使重新正常工作
- CSS样式,使用VS2005本地文件系统调试能显示,改成使用IIS就死活不显示了!【解决方法汇总说明】
- Windows 驱动:向 DbgPrintf 一样将调试信息输出到文件
- Linux系统面面观 PROC文件系统详细介绍