好难啊!这些东西完全不知道该那些地方入手,只能硬着头皮吸收一些自己可以看得懂的;
有些看得懂,有些看不懂,都不知道怎么查,总算知道为啥底层工程师这么少了;
可不能放弃,内核打我千百遍,我当内核是我爹,混熟了应该就好了吧!
make menuconfig 或者kernel_root_dir/.config 编译内核时,提供的DEBUG 选项及其作用
实例内核版本:kernel-3.4.39 (高亮为实例不支持)
#undef PDEBUG /*取消该宏名称的定义,防止重复声明*/
#ifdef device_debug /*开启debug标识*/
#ifdef __kernel__ /*处于内核空间 执行的debug方式 基于printk*/
#define PDEBUG(fmt,args...) printk(KERN_DEBUG "device_name:"fmt,##args)
#else /*处于用户空间 执行的debug方式 基于fprintf*/
#define PDEBUG(fmt,args...) fprintf(stderr,fmt,##args)
#endif
#else /*关闭debug标识,去掉宏定义的内容不与输出到伪终端*/
#define PDEBUG(fmt,args...)
#endif
DEBUG := y
ifeq($(DEBUG),y)
DEBFLAGS = -O -g -Ddevice_debug
else
DEBFLAGS = -O2
endif
CFLAGS += $(DEBFLAGS)
用户空间向内核请求关于内核属性与日常设备需求的数据的只读接口
创建调用:实现proc_read 函数–>创建proc文件入口并关联Proc_read
销毁调用:调用宏 remove_proc_entry(name, parent)
创建内核数据入口:绑定Proc_Read函数后可以获取内核数据;
args 1 :虚拟系统文件名,又称入口名
args 2 :proc文件的保护属性,默认为0
args 3 :指定创建proc文件的根目录,如果base =NULL 则在 proc 根目录创建;L;
return :返回为proc 目录结构指针
#include
/*创建proc 文件入口 需要绑定read函数*/
struct proc_dir_entry *create_proc_entry(const char *name, umode_t mode,struct proc_dir_entry *parent)
{
struct proc_dir_entry *ent;
nlink_t nlink;
if (S_ISDIR(mode)) {
if ((mode & S_IALLUGO) == 0)
mode |= S_IRUGO | S_IXUGO;
nlink = 2;
} else {
if ((mode & S_IFMT) == 0)
mode |= S_IFREG;
if ((mode & S_IALLUGO) == 0)
mode |= S_IRUGO;
nlink = 1;
}
ent = __proc_create(&parent, name, mode, nlink);
if (ent) {
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
}
}
return ent;
}
内核数据读取:驱动程序调用此函将数据,传回到内核分配的PAGE_SIZE用户空间内存页;
args 1 :开始放置虚拟文件数据的内存页起始位置
args 2 :向用户空间写入的数据,从内存页的哪里开始读取;
args 3 :如果*start为非NULL,则page +offset =start,否则为0;
args 4 : 需要传送的字节数量;
args 5 :没有数据返回时,驱动程序设置数值;
args 6 :用户空间传递的参数;
return :返回成功成功放置到内存页缓冲区的字节数;
#include
/*Read函数声明指针*/
int (*read_proc)
(char *page,char **start,off_t offset,int count,int *eof,void *data);
卸载数据入口:通常在驱动被卸载时调用执行该函数定义;
args 1 : 虚拟系统文件名,又称入口名
args 2 : 指定创建proc文件的根目录,如果parent =NULL 则从 proc 根目录移除文件;
return :空
#include
/*implement kernel_root_dir/fs/proc/generic.c:784*/
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
{
struct proc_dir_entry **p;
struct proc_dir_entry *de = NULL;
const char *fn = name;
unsigned int len;
spin_lock(&proc_subdir_lock);
if (__xlate_proc_name(name, &parent, &fn) != 0) {
spin_unlock(&proc_subdir_lock);
return;
}
len = strlen(fn);
for (p = &parent->subdir; *p; p=&(*p)->next ) {
if (proc_match(len, fn, *p)) {
de = *p;
*p = de->next;
de->next = NULL;
break;
}
}
spin_unlock(&proc_subdir_lock);
if (!de) {
WARN(1, "name '%s'\n", name);
return;
}
spin_lock(&de->pde_unload_lock);
/*
* Stop accepting new callers into module. If you're
* dynamically allocating ->proc_fops, save a pointer somewhere.
*/
de->proc_fops = NULL;
/* Wait until all existing callers into module are done. */
if (de->pde_users > 0) {
DECLARE_COMPLETION_ONSTACK(c);
if (!de->pde_unload_completion)
de->pde_unload_completion = &c;
spin_unlock(&de->pde_unload_lock);
wait_for_completion(de->pde_unload_completion);
spin_lock(&de->pde_unload_lock);
}
while (!list_empty(&de->pde_openers)) {
struct pde_opener *pdeo;
pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh);
list_del(&pdeo->lh);
spin_unlock(&de->pde_unload_lock);
pdeo->release(pdeo->inode, pdeo->file);
kfree(pdeo);
spin_lock(&de->pde_unload_lock);
}
spin_unlock(&de->pde_unload_lock);
if (S_ISDIR(de->mode))
parent->nlink--;
de->nlink = 0;
WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory "
"'%s/%s', leaking at least '%s'\n", __func__,
de->parent->name, de->name, de->subdir->name);
pde_put(de);
}
#include
struct seq_operations {
/*迭代器的入口,初始化函数指针实现,*/
void * (*start) (struct seq_file *m, loff_t *pos);
/*使用结束的清除工作*/
void (*stop) (struct seq_file *m, void *v);
/*移动到下一个迭代器的位置,pos 为cdev的偏移量 如果pos 大于设备数量,则返回NULL*/
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
/*用于将实际的数据输出到用户空间*/
int (*show) (struct seq_file *m, void *v);
};
#include
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
};
#include
/*只有seq_*的函数可以在 seq_file 中使用,以下函数等同于对应的应用层函数。*/
int seq_putc(struct seq_file *sfile,char c);
int seq_puts(struct seq_file *sfile,const char *s);
int seq_escape(struct seq_file *m,const char *s,const char *esc);
int seq_printf(struct seq_file *sfile,const char * fmt,...);