编写字串符类型的Linux内核模块驱动

前言

实验课要求要编写字串符类型的Linux内核驱动。在这里记录下相关流程。

源码

先给实验编写出来的Linux内核模块源码

vser.c 文件:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kfifo.h>

#define VSER_MAJOR	256
#define VSER_MINOR	0
#define VSER_DEV_CNT	1
#define VSER_DEV_NAME	"vser"

static struct cdev vsdev;
DEFINE_KFIFO(vsfifo, char, 32);

static int vser_open(struct inode *inode, struct file *filp)
{
	return 0;
}

static int vser_release(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
	unsigned int copied = 0;

	kfifo_to_user(&vsfifo, buf, count, &copied);

	return copied;
}

static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
	unsigned int copied = 0;

	kfifo_from_user(&vsfifo, buf, count, &copied);

	return copied;
}

static struct file_operations vser_ops = {
	.owner = THIS_MODULE,
	.open = vser_open,
	.release = vser_release,
	.read = vser_read,
	.write = vser_write,
};

static int __init vser_init(void)
{
	int ret;
	dev_t dev;

	dev = MKDEV(VSER_MAJOR, VSER_MINOR);
	ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
	if (ret)
		goto reg_err;

	cdev_init(&vsdev, &vser_ops);
	vsdev.owner = THIS_MODULE;

	ret = cdev_add(&vsdev, dev, VSER_DEV_CNT);
	if (ret)
		goto add_err;

	return 0;

add_err:
	unregister_chrdev_region(dev, VSER_DEV_CNT);
reg_err:
	return ret;
}

static void __exit vser_exit(void)
{
	
	dev_t dev;

	dev = MKDEV(VSER_MAJOR, VSER_MINOR);

	cdev_del(&vsdev);
	unregister_chrdev_region(dev, VSER_DEV_CNT);
}

module_init(vser_init);
module_exit(vser_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
MODULE_DESCRIPTION("A simple character device driver");
MODULE_ALIAS("virtual-serial");

Makefile

ifeq ($(KERNELRELEASE),)

ifeq ($(ARCH),arm)
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
ROOTFS ?= /nfs/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
clean:
	rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
else

obj-m := vser.o

endif
		

将两个文件放在一起。

编译

在两个文件所在的目录 执行make命令。如果没有报错,当前文件夹下面会生成vser.ko文件

加载驱动模块


执行lnsmode vser.ko加载内核模块。然后执行 lsmod | grep vser 查看是否加载成功。

创建设备节点

我们刚刚写的内核模块默认不会自动创建设备节点,我们需要手动创建下设备树节点。

sudo mknod /dev/vser c 256 0
sudo chmod 666 /dev/vser

可以看到 此时 /dev 目录下面多出了一个 vser文件(Linux下一切皆文件)

测试内核模块

执行下述命令

写入数据命令:

echo "hello linux" > /dev/vser

读取数据命令

cat /dev/vser

可以看到执行完上述命令 终端输出了 hello linux字样。输出了则代字串符类型的内核模块加载成功。

移除内核模块

别忘记移除内核模块

sudo rmmod vser

后记:一个小小的改进

刚刚的实验用的代码需要我们手动创建设备节点,但是实际上是可以自动化创建设备节点。

下面是改进版本的vser.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kfifo.h>
#include <linux/device.h>
#include <linux/version.h>

#define VSER_MAJOR      256
#define VSER_MINOR      0
#define VSER_DEV_CNT    1
#define VSER_DEV_NAME   "vser"

static struct cdev vsdev;
static DEFINE_KFIFO(vsfifo, char, 32);

static struct class *vser_class;
static struct device *vser_device;

static int vser_open(struct inode *inode, struct file *filp)
{
    return 0;
}

static int vser_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
    unsigned int copied = 0;
    int ret;

    ret = kfifo_to_user(&vsfifo, buf, count, &copied);
    if (ret)
        return ret;

    return copied;
}

static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
    unsigned int copied = 0;
    int ret;

    ret = kfifo_from_user(&vsfifo, buf, count, &copied);
    if (ret)
        return ret;

    return copied;
}

static struct file_operations vser_ops = {
    .owner = THIS_MODULE,
    .open = vser_open,
    .release = vser_release,
    .read = vser_read,
    .write = vser_write,
};

static int __init vser_init(void)
{
    int ret;
    dev_t dev;

    dev = MKDEV(VSER_MAJOR, VSER_MINOR);

    ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
    if (ret)
        goto reg_err;

    cdev_init(&vsdev, &vser_ops);
    vsdev.owner = THIS_MODULE;

    ret = cdev_add(&vsdev, dev, VSER_DEV_CNT);
    if (ret)
        goto add_err;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)
    vser_class = class_create(VSER_DEV_NAME);
#else
    vser_class = class_create(THIS_MODULE, VSER_DEV_NAME);
#endif

    if (IS_ERR(vser_class)) {
        ret = PTR_ERR(vser_class);
        goto class_err;
    }

    vser_device = device_create(vser_class, NULL, dev, NULL, VSER_DEV_NAME);
    if (IS_ERR(vser_device)) {
        ret = PTR_ERR(vser_device);
        goto device_err;
    }

    printk(KERN_INFO "vser: module loaded, /dev/%s created\n", VSER_DEV_NAME);

    return 0;

device_err:
    class_destroy(vser_class);

class_err:
    cdev_del(&vsdev);

add_err:
    unregister_chrdev_region(dev, VSER_DEV_CNT);

reg_err:
    return ret;
}

static void __exit vser_exit(void)
{
    dev_t dev;

    dev = MKDEV(VSER_MAJOR, VSER_MINOR);

    device_destroy(vser_class, dev);
    class_destroy(vser_class);

    cdev_del(&vsdev);
    unregister_chrdev_region(dev, VSER_DEV_CNT);

    printk(KERN_INFO "vser: module unloaded, /dev/%s removed\n", VSER_DEV_NAME);
}

module_init(vser_init);
module_exit(vser_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
MODULE_DESCRIPTION("A simple character device driver");
MODULE_ALIAS("virtual-serial");

替换文件后,清理垃圾文件并重新编译

make clean
make

然后,重新加载模块,但是这个版本不需要我们手动创建设备节点。加载模块后/dev 目录下已经自动生成vser文件了。

--------------

本文标题为:

编写字串符类型的Linux内核模块驱动

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇