首页 > 系统相关 >linux内核模块 字符设备驱动模板

linux内核模块 字符设备驱动模板

时间:2024-08-13 22:57:11浏览次数:20  
标签:struct dev cdev linux device static my 模板 内核模块

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

内核版本 5.10.92
linux内核模块 字符设备驱动模板
cdev注册字符设备,创建一个/dev/下设备节点和/sys下的设备节点
方便调试


提示:以下是本篇文章正文内容,下面案例可供参考

一、linux内核模块是什么?

Linux 内核模块是独立于内核主体的程序代码块,它们可以在系统运行时被动态加载到内核中或从内核中卸载。这种特性使得内核能够保持精简并仅包含最基本的组件,同时又能够在需要时扩展功能。

加载模块:
insmod xxx.ko 或 modprobe xxx.ko(命令可以自动处理模块依赖关系并加载所需的模块。)

卸载模块:
rmmod xxx.ko

查看模块:
lsmod

二、代码示例

Makefile

obj-m += module_char_test.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

module_char_test.c

#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sysfs.h>

#define DEVICE_NAME "mychardev"
#define CLASS_NAME "mychardev_class"

static dev_t dev_num; // 设备号
static struct cdev my_cdev; // cdev 结构体
static struct class *my_class; // 设备类
static struct device * my_device;


// 设备打开操作
static int my_open(struct inode *inode, struct file *file)
{
    // 在这里执行打开设备的操作
    return 0;
}

// 设备关闭操作
static int my_release(struct inode *inode, struct file *file)
{
    // 在这里执行关闭设备的操作
    return 0;
}

// 设备读取操作
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    // 在这里执行读取数据的操作
    return count;
}

// 设备写入操作
static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    // 在这里执行写入数据的操作
    char command[256];
    int cmd = 0;
    int ret = 0;
    
    if (count > sizeof(command) - 1) {
        return -EINVAL;
    }
    
    ret = copy_from_user(command, buf, count);
    if (ret) {
        return -EFAULT;
    }

    // 终止字符串
    command[count] = '\0';
    
    sscanf(command, "%d", &cmd);
    printk("cmd = %d\n", cmd);


    return count;
}

// 设备 ioctl 操作
static long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    // 在这里执行 ioctl 操作
    return 0;
}


// 设备操作函数表
static const struct file_operations fops = {
    .owner          = THIS_MODULE,
    .open           = my_open,
    .release        = my_release,
    .read           = my_read,
    .write          = my_write,
    .unlocked_ioctl          = my_ioctl,
};



static ssize_t show_my_sysfs_node(struct device *dev, struct device_attribute *attr, char *buf)
{
    /* 这里实现读取 sysfs 文件的内容 */
    return sprintf(buf, "Hello from the kernel!\n");
}

static ssize_t store_my_sysfs_node(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    /* 这里实现写入 sysfs 文件的行为 */
    pr_info("Received '%.*s'\n", (int)count, buf);
    return count;
}

static DEVICE_ATTR(my_sysfs_node, 0644, show_my_sysfs_node, store_my_sysfs_node);

// 模块加载时的初始化函数
static int __init my_init(void)
{
    int result;

    // 动态分配设备号
    result = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
    if (result < 0) {
        printk(KERN_ERR "Failed to allocate character device region.\n");
        return result;
    }

    // 初始化 cdev 结构体
    cdev_init(&my_cdev, &fops);

    // 注册 cdev
    result = cdev_add(&my_cdev, dev_num, 1);
    if (result) {
        unregister_chrdev_region(dev_num, 1);
        printk(KERN_ERR "Failed to add cdev.\n");
        return result;
    }

    // 创建设备类
    my_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(my_class)) {
        cdev_del(&my_cdev);
        unregister_chrdev_region(dev_num, 1);
        printk(KERN_ERR "Failed to create device class.\n");
        return PTR_ERR(my_class);
    }

    // 创建设备节点
    my_device = device_create(my_class, NULL, dev_num, NULL, DEVICE_NAME);

    printk(KERN_INFO "Character device '%s' created with major number %d.\n", DEVICE_NAME, MAJOR(dev_num));

    // 创建 sysfs 文件节点
    device_create_file(my_device, &dev_attr_my_sysfs_node);

    return 0;
}

// 模块卸载时的清理函数
static void __exit my_exit(void)
{
    // 删除 sysfs 文件节点
    device_remove_file(my_device, &dev_attr_my_sysfs_node);
    // 删除设备节点
    device_destroy(my_class, dev_num);

    // 删除设备类
    class_destroy(my_class);

    // 删除 cdev
    cdev_del(&my_cdev);

    // 释放设备号
    unregister_chrdev_region(dev_num, 1);

    printk(KERN_INFO "Character device '%s' removed.\n", DEVICE_NAME);
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple character device driver.");


总结

linux内核模块 字符设备驱动模板,可以编译运行,代码仅供参考可以调试使用

标签:struct,dev,cdev,linux,device,static,my,模板,内核模块
From: https://blog.csdn.net/qq_37077309/article/details/141166002

相关文章

  • Linux基础-总结篇
    作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。经过前面30多小节的内容介绍,我们从虚拟机的安装,到Linux文件的基本操作(增删改查),打包解压。磁盘的基本操作(分区,格式化,挂载,inode)。网络的基本操作:配......
  • linux高级编程——IO
    linux高级编程——IO标准IO:stdio.h文件IO标准IO:stdio.hIO也就是输入input和输出output;I:键盘是标准输入设备,默认输入就是指键盘/dev/input;O:显示器是标准输出设备,默认输出就是指显示器;stdio是属于C语言标准库,那么它存在哪呢?stdio.h存放的路径是:/usr/include/std......
  • Linux操作系统的安装和配置
    一、Linux的安装与常用命令1.安装VMware;   2.使用VMware安装配置Linux;3.实现要求的shell函数#hello函数,输入参数个数为0,输出hello,world!到标准输出。functionhello(){echo"hello,world!"}#tell_who_i_am函数,输入参数个数为0,输出当前用户的账号......
  • Linux系统五大资源常用命令(大全)
    系统五大资源常用命令Linux系统五大资源(CPU、内存、磁盘、网络、进程)的常用查询或管理命令,指令列表:资源查询或管理命令说明CPUtop实时显示各进程的CPU和内存使用情况。htop更友好的top替代工具,图形化显示CPU使用情况。mpstat显示每个CPU的使用情况,常用于多核系统。lscpu......
  • Linux下截图并识别文字
    1.安装tesseract-ocr软件:sudoapt-yinstalltesseract-ocr2.安装全部语言:sudoapt-yinstalltesseract-ocr-all3.安装gImageReader软件:sudoapt-yinstallgimagereader4.安装ksnip:sudoapt-yinstallksnip5.截屏,运行ksnip,在系统任务栏上显示“K”字样的图标。设置......
  • arch linux 安装Budgie桌面
    Budgie具体请查看官网:https://wiki.archlinuxcn.org/wiki/Budgie在ArchLinux上安装Budgie桌面环境的步骤如下:首先,确保你的系统是最新的。打开终端并运行以下命令进行系统更新:sudopacman-Syu更新完成后,重启你的系统以应用更新:sudoreboot接下来,你可以从ArchLi......
  • Linux驱动开发基础(LED驱动)
    所学来自百问网目录1.LED原理2.普适的GPIO引脚操作方法2.1GPIO模块的一般结构2.2GPIO框图2.3寄存器的操作2.3.1一般的操作方式2.3.2高效的操作方式3.基于IMX6UL_6ULL的GPIO操作方法3.1GPIO框图3.2CCM3.3IOMUXC3.4GPIO模块内部3.5读写GPIO4.LED驱......
  • 重头开始嵌入式第十九天(Linux系统编程 文件IO)
    缓冲区 1.行缓冲行缓冲,1k, terminal,主要用于人机交互stdout缓存区满或者遇到\n刷新1024行缓存多是关于终端的一些操作1.遇到\n刷新2.缓存区满刷新3.程序结束刷新4.fflush刷新  fflush(stdout);2.全缓冲全缓冲,4k,主要用于文件的读写缓存区满刷新缓存区 4096对......
  • Linux:文件管理,目录管理,文件类型,链接类型
    1,文件管理用户(标识号:UID):一定资源的使用者,可以创建和管理文件以及访问其他用户文件。可以从属于多个群组。用户组(标识号:GID):由一定数量的对某些文件具有相同操作权限的用户组成的小组。可以拥有多个用户。root用户:超级管理员,可以为所欲为。为何要区分用户和用户组?答:一种功......
  • Linuxu-引导过程与服务控制
    系列文章目录`提示:仅用于个人学习,进行查漏补缺使用。1.Linux介绍、目录结构、文件基本属性、Shell2.Linux常用命令3.Linux文件管理4.Linux命令安装(rpm、install)5.Linux账号管理6.Linux文件/目录权限管理7.Linux磁盘管理/文件系统8.Linux逻辑卷管理LVM9.Li......