内核版本

Linux version 5.8.0-44-generic

mydev.c

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>   
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

#define BUFSIZE 100
static int irq = 20;
static int mode = 1;
static struct proc_dir_entry *ent;

static ssize_t mywrite(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
{
	int num, c, i, m;
	char buf[BUFSIZE] = {0};

	if (*ppos > 0 || count > BUFSIZE)
		return -EFAULT;
	if (copy_from_user(buf, ubuf, count))
		return -EFAULT;
	num = sscanf(buf, "%d %d", &i, &m);
	if (num != 2)
		return -EFAULT;
	irq = i;
	mode = m;
	c = strlen(buf);
	*ppos = c;
	return c;
}

static ssize_t myread(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{
	char buf[BUFSIZE] = {0};
	int len = 0;

	if (*ppos > 0 || count < BUFSIZE)
		return 0;
	len += sprintf(buf, "irq = %d\n", irq);
	len += sprintf(buf + len, "mode = %d\n", mode);

	if (copy_to_user(ubuf, buf, len))
		return -EFAULT;
	*ppos = len;
	return len;
}

static struct file_operations myops = {
	.owner = THIS_MODULE,
	.read = myread,
	.write = mywrite,
};

static int simple_init(void)
{
	ent = proc_create("mydev", 0666, NULL, (struct proc_ops *)&myops);
	printk(KERN_ALERT "hello...\n");
	return 0;
}

static void simple_cleanup(void)
{
	proc_remove(ent);
	printk(KERN_WARNING "bye ...\n");
}

module_param(irq, int, 0660);
module_param(mode, int, 0660);

module_init(simple_init);
module_exit(simple_cleanup);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Liran B.H");

Makefile

obj-m:=mydev.o  
  
CURRENT_PATH:=$(shell pwd)  
VERSION_NUM:=$(shell uname -r)  
LINUX_PATH:=/usr/src/linux-headers-$(VERSION_NUM)  
  
  
all :  
	make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules  
clean:  
	make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean 

make && install

$ make
make -C /usr/src/linux-headers-5.8.0-44-generic     M=/home/liyongjun/project/c/study/kernel/proc   modules  
make[1]: 进入目录“/usr/src/linux-headers-5.8.0-44-generic”
  CC [M]  /home/liyongjun/project/c/study/kernel/proc/mydev.o
  MODPOST /home/liyongjun/project/c/study/kernel/proc/Module.symvers
  CC [M]  /home/liyongjun/project/c/study/kernel/proc/mydev.mod.o
  LD [M]  /home/liyongjun/project/c/study/kernel/proc/mydev.ko
make[1]: 离开目录“/usr/src/linux-headers-5.8.0-44-generic”

insmod

$ sudo insmod mydev.ko 

read

$ cat /proc/mydev 
irq = 20
mode = 1

write

$ echo 55 6 > /proc/mydev 
$ cat /proc/mydev 
irq = 55
mode = 6

user_app.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

void main(void)
{
	char buf[100] = {0};

	int fd = open("/proc/mydev", O_RDWR);
	read(fd, buf, 100);
	puts(buf);

	lseek(fd, 0, SEEK_SET);
	write(fd, "33 4", 5);

	lseek(fd, 0, SEEK_SET);
	read(fd, buf, 100);
	puts(buf);
}

编译

$ gcc user_app.c -o user_app.out

运行

$ ./user_app.out 
irq = 55
mode = 6

irq = 33
mode = 4

rmmod

$ sudo rmmod mydev

参考

如何使用内核API函数 proc_create?

理解

proc_create函数内幕初探