前言
中文互联网真的依托矢
就一个简简单单的内核驱动,不少人居然还设置了关注可见,甚至是VIP专栏,醉了
大部分入门的内核驱动都是字符设备的hello world,那个文章一抓一大把,不过相比用字符驱动输出helloworld,我觉得还是proc更简单
源码和Makefile
arcoproc.c(和Makefile中的obj保持一致)
这里创建了两个proc文件fa和fb, 以fa为例 调用链如下:
arcoproc_init
arco_init_proc
create_fa
.open=fa_open
.read=fa_read
fa是自己实现的read:在第n+1次尝试读时返回0强制结束(否则用cat读取会无限输出)
fb通过seq_file系列函数实现了open,读函数为seq_read
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/proc_fs.h>
#include<linux/seq_file.h> // seq_read
#include<linux/string.h>
#include <linux/uaccess.h> // copy_to_user
#define FAName "fa"
#define FBName "fb"
// proc file and ops
struct procfileops{
struct proc_dir_entry* file;
struct file_operations ops;
};
struct kirin {
struct proc_dir_entry* procfs;
struct procfileops fa;
struct procfileops fb;
};
struct kirin kirin7;
int arcoproc_flag = 0;
int fa_flag = 0;
int fb_flag = 0;
int fa_read_flag = 0;
// fa funcs
int fa_open(struct inode *inode, struct file *filp) {
return 0;
}
int fa_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) {
fa_read_flag = ~fa_read_flag;
if (!fa_read_flag) return 0;
char str[32] = "arco say: this is fa\n";
int len = strlen(str);
if (copy_to_user(buf, str, len)) {
return -1;
}
*ppos += len;
return len;
}
int create_fa(void) {
printk("arcoproc create fa~\n");
kirin7.fa.ops.open = fa_open;
kirin7.fa.ops.read = fa_read;
kirin7.fa.file = proc_create(FAName, 0444, kirin7.procfs, &kirin7.fa.ops);
if (kirin7.fa.file == NULL) {
printk("arco create fa failed!\n");
return -1;
}
fa_flag = 1;
return 0;
}
// fb funcs
int single_fb_open(struct seq_file* m, void* v) {
char str[32] = "arco say: this is fb\n";
seq_printf(m, str);
return 0;
}
int fb_open(struct inode *inode, struct file *filp) {
return single_open(filp, single_fb_open, NULL);
}
int create_fb(void) {
printk("arcoproc create fb~\n");
kirin7.fb.ops.open = fb_open;
kirin7.fb.ops.read = seq_read;
kirin7.fb.file = proc_create(FBName, 0444, kirin7.procfs, &kirin7.fb.ops);
if (kirin7.fb.file == NULL) {
printk("arco create fb failed!\n");
return -1;
}
fb_flag = 1;
return 0;
}
int arco_init_proc(void) {
printk("arco init proc~\n");
kirin7.procfs = proc_mkdir("arcoproc", NULL);
if (kirin7.procfs == NULL) {
printk("arco init proc dir failed!\n");
return -1;
}
create_fa();
create_fb();
return 0;
}
static int __init arcoproc_init(void) {
printk("arcoproc init~\n");
arco_init_proc();
return 0;
}
static void __exit arcoproc_exit(void) {
proc_remove(kirin7.procfs);
if (fa_flag) proc_remove(kirin7.fa.file);
if (fb_flag) proc_remove(kirin7.fb.file);
printk("arco say: bye~\n");
}
module_init(arcoproc_init);
module_exit(arcoproc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ARCO");
MODULE_DESCRIPTION("arco proc test");
Makefile
KDIR := /home/arco/kernel/linux-imx
obj-m=arcoproc.o
PWD=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
编译运行
编译 上传
make clean
make
if [ $? -eq 0 ];then
scpauto arcoproc.ko root@192.168.0.30:/home/arco/drivers 123456
fi
上述的scpauto是我用expect封装的一个脚本,功能是自动填充ssh的密码
基于expect的ssh自动输入密码脚本
运行
这里是用minicom连接的串口,printk直接打印出来了
可以看到,在/proc目录下创建了arcoproc目录,然后在其下生成了fa和fb两个文件
insmod #插入驱动
rmmode #移除驱动