驱动调试之proc文件系统
来源:互联网 发布:js调用手机相册插件 编辑:程序博客网 时间:2024/04/30 18:52
一、思维导读
我们知道在/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.oelseKERNELDIR ?= /ljm/git_imx6/linux-fsl/src/linux-3-14-28-r0TARGET_CROSS = arm-none-linux-gnueabi-PWD := $(shell pwd)default:$(MAKE) ARCH=arm CROSS_COMPILE=$(TARGET_CROSS) -C $(KERNELDIR) M=$(PWD) modulesendifinstall:$(MAKE) ARCH=arm CROSS_COMPILE=$(TARGET_CROSS) -C $(KERNELDIR) M=$(PWD) modules_installclean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers *.order
0 0
- 驱动调试之proc文件系统
- 内核驱动之proc文件系统
- /proc 文件系统——提供一种驱动调试的利器
- proc文件系统之 /proc/stat
- Linux设备驱动---/proc文件系统
- Linux文件系统之proc文件系统
- aix 文件系统之 PROC
- linux 文件系统之/proc
- /proc文件系统用于内核调试
- proc文件系统用于内核调试
- 学习笔记 --- LINUX 驱动调试之使用proc
- linux设备驱动学习笔记--内核调试方法之proc
- 驱动调试之打印到proc虚拟文件1
- 驱动调试之打印到proc虚拟文件3--实验
- Linux之Proc文件系统详解
- 设备驱动之一 - proc文件系统接口
- 给globalmem驱动添加proc调试输出
- linux设备驱动学习笔记--内核调试方法之proc(补充seq_file)
- Linux基础学习(二)
- 快速排序
- android 小球绕外圆旋转
- 安全漏洞扫描之Sql注入解析
- split用法举例
- 驱动调试之proc文件系统
- HTML5学习_day01(5)--css常见样式background
- 关于对webrtc的初次亲密接触的一点感想!
- Android 四种启动模式和 Activity 的 Flag
- 最长上升子序列
- Ajax请求下载文件
- unity5 测试导出场景和光照贴图丢失的问题
- (三)5阻塞型IO实现
- 输入子系统 input_match_device 匹配过程剖析