当前位置: 首页 > news >正文

Linux .ko字符串驱动模块

Linux分为内核态和用户态

实则就是分为了用户操作空间和内核操作空间

Linux驱动开发分为两种,可以将驱动编译到内核kernel中即image,或者module中,即.ko文件,内核文件编译比较繁杂,通常编译到.ko文件中

#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("You");
MODULE_DESCRIPTION("Simple test character device module");static int __init mymodule_init(void){    printk("mymodule_init\n");    return 0;}static void __exit mymodule_exit(void){    printk("mymodule_exit\n");}
/*
*   模块的出口与入口函数
*/
module_init(mymodule_init);
module_exit(mymodule_exit);

这是一个最简单的字符串设备的驱动注册程序,这个代码的编写并没有难度,完全按照Linux官方的格式编写。难点在于这个程序的编译,Linux的编译多数使用Makefile文件,发展到今天已经形成了标准化的格式。对于模块驱动(.ko)的编译也不例外,使用标准格式即可。以下是Makefile文件的编写

KERNEL := /home/pro/prj/k230_linux_sdk/output/k230_canmv_lckfb_defconfig/build/linux-7d4e1f444f461dbe3833bd99a4640e7b6c2cd529
INC := /opt/toolchain/Xuantie-900-gcc-linux-6.6.0-glibc-x86_64-V3.0.2/include
CURRENT_PATH := $(shell pwd)
obj-m := mymodule.o
# Cross-compiler prefix (no trailing gcc) — used by kernel build system
CROSS_COMPILE := /opt/toolchain/Xuantie-900-gcc-linux-6.6.0-glibc-x86_64-V3.0.2/bin/riscv64-unknown-linux-gnu-
# Target architecture
ARCH ?= riscvbuild: kernel_moduleskernel_modules:
    $(MAKE) -C $(KERNEL) M=$(CURRENT_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modulesclean:
    $(MAKE) -C $(KERNEL),$(INC) M=$(CURRENT_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) clean

字符串设备

注册设备我们需要使用一个函数register_chrdev,并且在卸载设备的时候也需要先注销一个注册的设备使用函数unregister_chrdev。
register_chrdev函数用于注册字符设备,此函数一共有三个参数,这三个参数的含义如下:

  • major:主设备号,Linux下每个设备都有一个设备号,设备号分为主设备号和次设备号两 部分,关于设备号后面会详细讲解。
  • name:设备名字,指向一串字符串。
  • fops:结构体file_operations类型指针,指向设备的操作函数集合变量。
    unregister_chrdev函数用户注销字符设备,此函数有两个参数,这两个参数含义如下:
  • major:要注销的设备对应的主设备号。
  • name:要注销的设备对应的设备名。
//设备号的原始类型,即一个无符号的32位整型
typedef u32 __kernel_dev_t;typedef __kernel_fd_set     fd_set;
typedef __kernel_dev_t      dev_t;

Linux内核将设备号分为两类,主设备号和次设备号,故主设备号会占用高12位,次设备号占用低20位。

register_chrdev(unsigned int major, const char *name, const struct file_operations *fops);
unregister_chrdev(unsigned int major, const char *name);

这两个函数的注册方式在现在看来过于片面,可以在第一个参数中看出,在注册设备时只能填写major,但在一个设备注册时应该有主设备和次设备号互相作用的。这样就导致了注册到一个MAJOR时会直接忽略掉次设备号的全部字段, 2^12 = 4096个设备号被浪费。

const struct file_operations

这是Linux设备的属性结构体,其中定义了许多设备功能,就比如一个设备只有在注册的时候拥有open、close、read和write等等,这样在C语言中调用open函数这些函数时才有效。在内核文件Linux/include/fs.h中有着完整的结构体定义。

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
    int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *,
            unsigned int flags);
    int (*iterate_shared) (struct file *, struct dir_context *);
    __poll_t (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    unsigned long mmap_supported_flags;
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, loff_t, loff_t, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
    int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    void (*splice_eof)(struct file *file);
    int (*setlease)(struct file *, int, struct file_lock **, void **);
    long (*fallocate)(struct file *file, int mode, loff_t offset,
              loff_t len);
    void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
    unsigned (*mmap_capabilities)(struct file *);
#endif
    ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
            loff_t, size_t, unsigned int);
    loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
                   struct file *file_out, loff_t pos_out,
                   loff_t len, unsigned int remap_flags);
    int (*fadvise)(struct file *, loff_t, loff_t, int);
    int (*uring_cmd)(struct io_uring_cmd *ioucmd, unsigned int issue_flags);
    int (*uring_cmd_iopoll)(struct io_uring_cmd *, struct io_comp_batch *,
                unsigned int poll_flags);
} __randomize_layout;

字符设备驱动的函数实现

上面了解到一个字符串设备是否有功能,完全取决于动作结构体的实现。


待更新

http://www.jsqmd.com/news/177491/

相关文章:

  • YOLOFuse术语表整理:统一技术词汇翻译标准
  • AI 大模型数字化监测系统:用智能技术重构监测新范式
  • YOLOFuse JavaScript前端控制台调试技巧分享
  • YOLOFuse训练脚本train_dual.py使用说明及参数配置建议
  • YOLOFuse医疗影像探索:体温异常人群筛查初步尝试
  • YOLOFuse英文文档改进:提升国际影响力的关键一步
  • 东方博宜OJ 2142:福布斯富豪排行榜 ← 结构体 + 结构体排序
  • YOLOFuse如何应对不同分辨率RGB与IR图像配准问题?
  • 2025年度盘点:国内喷淋塔除尘器口碑排行榜,静电除尘器/水帘除尘器/滤筒除尘器喷淋塔除尘器直销厂家排行 - 品牌推荐师
  • YOLOFuse c#调用python注意事项:环境隔离与异常捕获
  • 【水下车辆】RRT和粒子群算法PSO复杂的水下环境中自主水下车辆AUVs高效且无碰撞的能量传输路径【含Matlab源码 14806期】
  • YOLOFuse标注要求说明:只需基于RGB图像生成YOLO格式txt标签
  • YOLOFuse小红书种草文案:女性工程师视角分享体验
  • YOLOFuse产品化路径思考:从开源项目到商业闭环
  • 【无人机控制】基于matlab四旋翼无人机的3D路径规划与轨迹跟踪Matlab仿真系统【含Matlab源码 14807期】
  • YOLOFuse弹性伸缩机制:根据负载自动调整资源
  • YOLOFuse账单查询功能:随时掌握算力使用情况
  • YOLOFuse训练日志分析:通过matplotlib生成精度变化曲线
  • python+vue小区物业报修系统
  • YOLOFuse学习率调度策略解析:自适应调整提升收敛速度
  • YOLOFuse CSDN博客同步更新:中文开发者首选平台
  • YOLOFuse适合哪些应用场景?夜间监控、自动驾驶、安防必看
  • YOLOFuse主题论坛创建:促进开发者交流经验
  • YOLOFuse思否技术访谈:创始人讲述开发背后故事
  • YOLOFuse野生动物监测项目:保护濒危物种活动轨迹追踪
  • 【无人机控制】四旋翼无人机的3D路径规划与轨迹跟踪Matlab仿真系统【含Matlab源码 14807期】
  • ‌大模型驱动的自动化测试脚本修复技术
  • YOLOFuse推理输出路径曝光:检测可视化图片存于runs/predict/exp
  • YOLOFuse移动端适配可行性分析:结合MNN或NCNN部署前景
  • ‌测试数据生成的Transformer模型优化方案