美食网站开发的目标,北京市住房与建设厅官方网站,app网站建设手机APP软件开发,大学网页制作学什么若该文为原创文章#xff0c;转载请注明原文出处 本文章博客地址#xff1a;https://hpzwl.blog.csdn.net/article/details/134533533
红胖子网络科技博文大全#xff1a;开发技术集合#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…若该文为原创文章转载请注明原文出处 本文章博客地址https://hpzwl.blog.csdn.net/article/details/134533533
红胖子网络科技博文大全开发技术集合包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等持续更新中…
Linux系统移植和驱动开发专栏
上一篇《Linux驱动开发笔记三基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试》 下一篇敬请期待… 前言 驱动的开发需要先熟悉基本概念类型本篇讲解linux杂项设备基础还是基于虚拟机ubuntu去制作驱动只需要虚拟机就可以尝试编写注册杂项设备的基本流程。 linux三大设备驱动
字符设备IO的传输过程是以字符为单位的没有缓冲比如I2CSDA、SCLSPIMISO、MOSI、SCLK、CS。块设备IO的传输过程是以块为单位的跟存储相关的都属于块设备比如tf卡sd卡。网络设备IO的传输以socket套接字来访问的。 杂项设备
杂项设备是属于字符设备可以自动生成设备节点设备节点位于/dev/目录下是设备名称如/dev/ttyS9等。主设备号相同统一为10次设备号不同主设备相同可以节省内核资源。 通过下列指令可以查看系统杂项设备
cat /proc/misc在虚拟机上测试查看杂项
设备号分为主设备号和次设备号主设备号是唯一的次设备号不一定唯一。 通过下列指令可以查看系统主设备号
cat /proc/devices杂项设备描述结构体 ubuntu来说自带的/usr/src下的就是内核的头文件。
cd /usr/src/linux-headers-4.18.0-15
vi include/linux/miscdevice.h定位到之前ubuntu自带的内核头文件下 查看到杂项设备的结构体
struct miscdevice {int minor; // 次设备号const char *name; // 设备节点名称如/dev/ttyS8则ttyS是名称const struct file_operations *fops; // 文件操作集非常重要struct list_head list; struct device *parent;struct device *this_device;const struct attribute_group **groups; const char *nodename; umode_t mode;
};注意没打注释的一般不管
杂项设备文件操作集
cd /usr/src/linux-headers-4.18.0-15
vi include/linux/fs.h搜索到vi则直接使用“/”:
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 *);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 *);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 (*setfl)(struct file *, unsigned long);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 *);
#endifssize_t (*copy_file_range)(struct file *, loff_t, struct file *,loff_t, size_t, unsigned int);int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,u64);ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,u64);
} __randomize_layout;例如read函数那么就是打开驱动使用系统read打开这个设备驱动的句柄那么久会调用read函数其他的以此类推还比较好理解。 以我们一个registerHelloWorld为例子来简单说明。 驱动编写空模板准备 首先复制之前的hello world的驱动改个名字为registerMiscDev
cd ~/work/drive
cp -arf hellowolrd registerMiscDevcd registerMiscDev/
rm *.ko *.o *.order *.symvers这里删除起来麻烦修改makefile添加clean 然后测试一下 继续修改源码文件名称
mv helloworld.c registerMiscDev.c修改完如下 然后修改makefile里面的obj-m模块名称改下模板准备好了 下面基于registerMiscDev.c文件进行注册杂项设备在修改.c文件
#include linux/init.h
#include linux/module.hstatic int registerMiscDev_init(void)
{ // 在内核里面无法使用基础c库printf需要使用内核库printkprintk(Hello, I’m hongPangZi, registerMiscDev_init\n); return 0;
}
static void registerMiscDev_exit(void)
{printk(bye-bye!!!\n);
}
MODULE_LICENSE(GPL);
module_init(registerMiscDev_init);module_exit(registerMiscDev_exit); 杂项设备注册流程Demo
步骤一填充miscdevice结构体 在编写驱动的时候代码中填充信息结构体。 添加头文件miscdevice.h
#include linux/miscdevice.h
#include linux/fs.h然后填充杂项设备结构体 (注意开始为“.”结束为“,”最后一行习惯加“,”了这样可以全部统一复制啥的省的加没加的)
struct miscdevice misc_dev {.minor MISC_DYNAMIC_MINRO, // 这个宏是动态分配次设备号避免冲突.name register_hongPangZi_misc, // 设备节点名称.fops misc_fops, // 这个变量记住自己起的步骤二使用
}步骤二填充file_operations结构体 在编写驱动的时候代码中填充文件操作结构体。
struct file_operations misc_fops {.owner THIS_MODULE
}步骤三注册杂项设备并生成设备节点 注册到内核
static int registerMiscDev_init(void)
{ // 在内核里面无法使用基础c库printf需要使用内核库printkprintk(Hello, I’m hongPangZi, registerMiscDev_init\n); int ret 0;ret misc_register(misc_dev);if(ret 0){printk(Failed to misc_register(misc_dev)\n); return -1;} return 0;
}有注册就有注销
static int registerMiscDev_init(void)
{ // 在内核里面无法使用基础c库printf需要使用内核库printkprintk(Hello, I’m hongPangZi, registerMiscDev_init\n); int ret 0;ret misc_register(misc_dev);if(ret 0){printk(Failed to misc_register(misc_dev)\n); return -1;} return 0;
}完整的文件源码
#include linux/init.h
#include linux/module.h#include linux/miscdevice.h
#include linux/fs.hstruct file_operations misc_fops {.owner THIS_MODULE,
};struct miscdevice misc_dev {.minor MISC_DYNAMIC_MINOR, // 这个宏是动态分配次设备号避免冲突.name register_hongPangZi_misc, // 设备节点名称.fops misc_fops, // 这个变量记住自己起的步骤二使用
};static int registerMiscDev_init(void)
{ // 在内核里面无法使用基础c库printf需要使用内核库printkprintk(Hello, I’m hongPangZi, registerMiscDev_init\n); int ret 0;ret misc_register(misc_dev);if(ret 0){printk(Failed to misc_register(misc_dev)\n); return -1;} return 0;
}static void registerMiscDev_exit(void)
{misc_deregister(misc_dev);printk(bye-bye!!!\n);
}MODULE_LICENSE(GPL);
module_init(registerMiscDev_init);
module_exit(registerMiscDev_exit);步骤四编译make
make直接在驱动工程目录编译 下面这个警告实际上定义要在任何使用函数之前 修改下 编译成功
步骤五加载卸载驱动测试 将驱动拷贝到开发板或者目标系统然后使用加载指令
sudo insmod registerMiscDev.ko会打印入口加载的printk输出。 出现问题可能原因一是内核编译使用的编译器和模块使用的编译器版本不一致。ubuntu中printk终端打入内核日志消息了可以使用dmesg进行查看
dmesg然后查看是否加入了杂项设备节点 然后注销
sudo rmmod registerMiscDev.ko跟随着结点消失了 入坑
入坑一编译报错结构体之后未加分号
问题 编译错误结构体后面加分号
解决 加分号脑袋有点蒙
入坑二编译错误文件操作指针问题
问题 解决 这是写错了是指针需要加取地址。 上一篇《Linux驱动开发笔记三基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试》 下一篇敬请期待… 若该文为原创文章转载请注明原文出处 本文章博客地址https://hpzwl.blog.csdn.net/article/details/134533533