网站优化包括哪些内容,wordpress自定义模块,分类信息网站,网站的友情连接怎么做1.简介
字符设备驱动#xff1a;按照字节流进行读写操作的设备#xff0c;例如点灯、按键、IIC、SPI、LCD。
Linux系统中一切皆文件#xff0c;驱动加载成功#xff0c;就会在/dev目录生成文件#xff0c;对文件操作#xff0c;则可实现对硬件操作。应用程序运行在用户…1.简介
字符设备驱动按照字节流进行读写操作的设备例如点灯、按键、IIC、SPI、LCD。
Linux系统中一切皆文件驱动加载成功就会在/dev目录生成文件对文件操作则可实现对硬件操作。应用程序运行在用户空间驱动运行在内核空间用户空间不能直接对内核操作因此借助系统调用实现。
2.字符设备驱动开发
2.1 内核驱动操作函数集合
include/linux/fs.h 中 file_operations 结构体
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 (*iterate) (struct file *, struct dir_context *);unsigned int (*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 *);int (*mremap)(struct file *, struct vm_area_struct *);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 (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);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);int (*setlease)(struct file *, long, 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_MMUunsigned (*mmap_capabilities)(struct file *);#endif
};owner该结构体的模块的指针一般为THIS_MODULE llseek修改文件读写位置 read读取设备文件 write写入设备文件 poll查询设备是否可以进行非阻塞读写 unlocked_ioctl对应ioctl控制设备 campat_ioctl 64 位系统上 32 位的应用程序调用将会使用此函数。在 32 位的系统上运行 32 位的应用程序调用的是 unlocked_ioctl mmap设备内存映射到用户空间一般用于帧缓冲设备这样应用程序可以直接操纵内核空间避免数据在用户空间和内核空间来回复制 open打开设备文件 release关闭设备文件对应close函数 fasync刷新待处理数据 aio_fsync异步刷新待处理和数据
2.2 驱动开发步骤
1模块加载和卸载
module_init(xxx_init); ///模块加载函数
module_exit(xxx_exit); ///模块卸载函数2字符设备注册与注销
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)static inline void unregister_chrdev(unsigned int major, const char *name)
major模块的主设备号 主设备号由32个bit组成高12个bit为主设备号低20个为次设备号。 设备号可以静态分配或动态分配静态分配则代表自己去指定可以使用cat /proc/devices查看系统中已使用的设备号也可以通过上面函数的方式由系统动态分配推荐是动态分配静态指定容易造成冲突
fopsfile_operations文件操作集合结构体指针 name设备名 3实现字符设备操作函数
static struct file_operations user_fops {.owner THIS_MODULE,.open user_open,.release user_close,.read user_read,.write user_write
};4LICENSE、作者信息
MODULE_LICENSE(GPL);
MODULE_AUTHOR(xuzhangxin); 2.3 实战
2.3.1 vscode工程配置
ctrlshiftp添加一个Cpp工程配置文件其中设置包含头文件的目录便于查找函数声明 会自动创建好.vscode其中有一个c_cpp_properties.json添加linux kernel源码的头文件路径
{configurations: [{name: Linux,includePath: [${workspaceFolder}/**,/home/xzx/share/project_ipc/study_linux_project/linux_bsp/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7/include,/home/xzx/share/project_ipc/study_linux_project/linux_bsp/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7/arch/arm/include,/home/xzx/share/project_ipc/study_linux_project/linux_bsp/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7/arch/arm/include/generated/],defines: [],compilerPath: /usr/bin/gcc,cStandard: c11,cppStandard: gnu14,intelliSenseMode: linux-gcc-x64}],version: 4
}2.3.2 全部源码
2.3.2.1 驱动部分
1驱动源码
#include linux/types.h
#include linux/kernel.h
#include linux/delay.h
#include linux/ide.h
#include linux/init.h
#include linux/module.h
#include linux/uaccess.h#define USER_MAJOR 201
#define USER_NAME user_chrdevchar pri_buf[1024] {0};static int user_open(struct inode *node, struct file *file)
{printk(user driver open);
}static int user_close(struct inode *node, struct file *file)
{printk(user driver close);
}static ssize_t user_read (struct file *file, char __user *data, size_t cnt, loff_t *off)
{printk(user driver read);int ret 0;ret copy_to_user(data, pri_buf, cnt);if (ret 0){printk(user driver read failed:%d, ret);return ret;}printk(user driver read sucess, ret:%d, ret);return ret;
}
static ssize_t user_write(struct file *file, const char __user *data, size_t cnt, loff_t *off)
{printk(user driver write);int ret 0;ret copy_from_user(pri_buf, data, cnt);if (ret 0){printk(user driver write failed:%d, ret);return ret;}printk(user driver write sucess, ret:%d, ret);return ret;
}static struct file_operations user_fops {.owner THIS_MODULE,.open user_open,.release user_close,.read user_read,.write user_write};static int __init user_init(void)
{/// 注册驱动int ret register_chrdev(USER_MAJOR, USER_NAME, user_fops);if (ret 0){printk(user driver registration failed);}printk(user driver init);return 0;
}static int __exit user_exit(void)
{/// 注销驱动unregister_chrdev(USER_MAJOR, USER_NAME);printk(user driver exit);
}module_init(user_init);
module_exit(user_exit);MODULE_LICENSE(GPL);
MODULE_AUTHOR(xuzhangxin);2驱动编译Makefile 这里要根据自己的路径等更改
KERNELDIR : /home/xzx/share/project_ipc/study_linux_project/linux_bsp/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7
CURRENT_PATH : $(shell pwd)obj-m : user_chrdev.o build: kernel_modules
kernel_modules:$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) clean3加载驱动 编译生成user_chrdev_ko随后拷贝到板子上使用tftp、nfs等都可以。 使用insmod user_chrdev_ko加载驱动 同时使用lsmod或者cat /proc/devices能看到驱动是否加载成功。 4创建设备节点文件 mknod /dev/user_chrdev c 201 0 创建/dev/user_chrdev节点c代表节点为字符设备201为主设备号0为次设备号 至此驱动部分就准备完毕了开始用应用代码去测试驱动啦 5卸载驱动 在不用的时候可以用rmmod卸载驱动当然不是现在哈
2.3.2.2 应用测试部分
1源码
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdlib.h
#include string.hint main(int argc, char **argv)
{char w_buf[1024] {0};char r_buf[1024] {0};int fd open(/dev/user_chrdev, O_RDWR);if (fd 0){return -1;}printf(open success\n);snprintf(w_buf, sizof(w_buf) / sizeof(w_buf[10]), hello world);write(fd, w_buf, 10);read(fd, r_buf, 10);printf(r_buf :%s, r_buf);close(fd);return 0;
}2验证 gcc 编译后拷贝到板子上运行查看有没有驱动内添加的打印即可
3. 源码地址
哈喽~我是Embedded-Xin沪漂嵌入式开发工程师一枚立志成为嵌入式全栈开发工程师成为优秀博客创作者共同学习进步。 以上代码全部放在我私人的github地址其中有许多自己辛苦敲的例程源码供大家参考、批评指正有兴趣还可以直接提patch修改我的仓库~ https://github.com/Xuzhangxin/study_linux_project.git 觉得不错的话可以点个收藏和star~