前言
內核驅動:運行在內核態(tài)的動態(tài)模塊,遵循內核模塊框架接口,更傾向于插件。
應用程序:運行在用戶態(tài)的進程。
應用程序與內核驅動交互通過既定接口,內核態(tài)和用戶態(tài)訪問依然遵循內核既定接口。文章來源:http://www.zghlxwxcb.cn/news/detail-678704.html
環(huán)境搭建
系統(tǒng):openEuler-20.03-LTS-SP3文章來源地址http://www.zghlxwxcb.cn/news/detail-678704.html
yum install gcc kernel-devel
編寫源碼
- char_module.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/device.h> //下面這三個頭文件是由于動態(tài)創(chuàng)建需要加的
#include <linux/device.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
#define DEVICE_NAME "char_module"
#define BUF_SIZE 32
static struct class *cdev_class;
dev_t dev_num = 0; // 這里是動態(tài)分配設備號和動態(tài)創(chuàng)建設備結點需要用到的
struct cdev dev_c;
static char context_buf[BUF_SIZE]={"this a test context buffer\0"};
static ssize_t read(struct file *, char *, size_t, loff_t *);
static ssize_t write(struct file *, const char *, size_t, loff_t *);
static int open(struct inode *, struct file *);
static int release(struct inode *, struct file *);
// 初始化字符設備驅動的 file_operations 結構體
struct file_operations fops = {
.read = read,
.write = write,
.open = open,
.release = release
};
static int __init demo_init(void)
{
int ret, err;
printk(KERN_INFO "%s: %s", DEVICE_NAME , __func__);
// 注冊設備驅動
ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME); // 動態(tài)分配設備號
if (ret)
{
printk("demo_init register failure\n");
unregister_chrdev_region(dev_num, 1);
return ret;
}
printk("demo_init register success\n");
// 初始化設備操作
cdev_init(&dev_c, &fops);
err = cdev_add(&dev_c, dev_num, 1);
if (err)
{
printk(KERN_NOTICE "error %d adding cdev\n", err);
unregister_chrdev_region(dev_num, 1);
return err;
}
// 動態(tài)創(chuàng)建設備結點
cdev_class = class_create(THIS_MODULE, DEVICE_NAME);
if (IS_ERR(cdev_class))
{
printk("ERR:cannot create a cdev_class\n");
unregister_chrdev_region(dev_num, 1);
return -1;
}
device_create(cdev_class, NULL, dev_num, 0, DEVICE_NAME);
return ret;
}
static void __exit demo_exit(void)
{
printk(KERN_INFO "%s: %s", DEVICE_NAME , __func__);
// 注銷設備驅動
device_destroy(cdev_class, dev_num);
class_destroy(cdev_class);
unregister_chrdev_region(dev_num, 1);
}
static ssize_t read(struct file *filp, char *buf, size_t len, loff_t *off)
{
// 內核空間到用戶空間copy
printk(KERN_INFO "%s: %s", DEVICE_NAME , __func__);
if (raw_copy_to_user(buf, &context_buf, sizeof(context_buf)))
{
return -EFAULT;
}
printk(KERN_INFO "user space: %pF", buf);
printk(KERN_INFO "read: %pF; size: %ld; data: %s", &context_buf, sizeof(context_buf), context_buf);
return BUF_SIZE;
}
static ssize_t write (struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
// 用戶空間到內核空間copy
printk(KERN_INFO "%s: %s", DEVICE_NAME , __func__);
if (raw_copy_from_user(&context_buf, buf, sizeof(context_buf)))
{
return -EFAULT;
}
printk(KERN_INFO "user space: %pF", buf);
printk(KERN_INFO "write: %pF; size: %ld; data: %s", &context_buf, sizeof(context_buf), context_buf);
return BUF_SIZE;
}
static int open(struct inode *inodp, struct file *filp)
{
printk(KERN_INFO "%s: %s", DEVICE_NAME , __func__);
return 0;
}
static int release(struct inode *inodp, struct file *filp)
{
printk(KERN_INFO "%s: %s", DEVICE_NAME, __func__);
return 0;
}
module_init(demo_init);
module_exit(demo_exit);
- Makefile
ifneq ($(KERNELRELEASE),)
obj-m := char_module.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules modules_install
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.*
endif
app.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define CHAR_DEV_NAME "/dev/char_module"
int main()
{
int ret;
int fd;
char buf[32];
fd = open(CHAR_DEV_NAME, O_RDWR | O_NDELAY);
if(fd < 0)
{
printf("open failed!\n");
return -1;
}
int size = read(fd, buf, 32);
printf("read size: %d;\nbuffer:[%s]\n", size, buf);
char *write_buf = "use a application wirte to driver buffer";
int w_size = write(fd, write_buf, strlen(write_buf));
printf("write size: %d;\nbuffer:[%s]\n", w_size, write_buf);
close(fd);
return 0;
}
構建并測試
- 驅動構建
make && insmod char_module.ko
- 驅動信息確認
- 應用程序構建
gcc app.c -o app ./app
- 應用程序運行結果
- 查看驅動日志
dmesg
到了這里,關于字符設備驅動(內核態(tài)用戶態(tài)內存交互)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!