【驱动】linux驱动程序开发及环境搭建
1.mystery引入
1)设备驱动程序对外提供如下的功能:
1)设备初始化:对硬件设备进行初始化操作
2)数据交换:数据交换包括由内核层向硬件层传送数据、从硬件层读取数据到内核层;
应用程序向设备文件传送数据、设备文件向应用程序回送数据
3)设备请求与检测:检测各硬件设备的各种参数信息、错误信息
4)设备释放:设备使用完后的资源释放
2)驱动一般分为字符设备驱动、块设备驱动和网络设备驱动
1)字符设备驱动:可以按字节操作的方式对设备文件进行存取,一般对应慢速设备,例如串口设备
2)块设备驱动:是按数据块的方式对设备文件进行访问,一般对应高速设备,例如DMA
3)网络设备驱动:是面向网卡设备,用于处理网络报文的发送与接收
3)字符设备与块设备均可以通过访问文件的方式进行操作,二者唯一的不同的是Linux对于它们的数据管理方式的不同。
4)应用程序对字符设备的I/O操作,会直接传送到内核驱动层,而块设备的操作,则是需要借助于中间的缓存区,以间接的方式进行数据交换。
2.环境搭建及测试
1)下载对应版本的内核源码包
2)因为现在对内核还不是很熟,加上内核源码比较大,所以我先下一个内核的开发包
3)终端:
1 | sudo yum install kernel-devel |
4)如图
5)环境搭建好了,问题又来了。。uname -r 的结果和我系统内核版本不一样。。
这里我直接用我系统的内核版本号作测试了,我的系统内核版本是3.6.10-2.fc17.i686
6)第一个版本的Makefile文件如下:
1 2 3 4 5 6 7 | obj-m:=chardev.o KDIR:= /lib/modules/3 .6.10-2.fc17.i686 /build SRCPWD:=$(shell pwd ) all: make -C $(KDIR) M=$(SRCPWD) modules clean: rm -rf chardev.o |
7)编译结果如图
3.驱动验证
1)设备安装
当安装驱动时,又出现错误了,纠结。。错误:编译使用的内核和当前系统的内核不一样!
2)反思
1)这时我才想起,前断时间我更新了下系统,当时把系统内核升级到了3.6,但是无法进入系统,所以我直接把grub项的3.6内核的引导删掉了,现在打开grub查找错误
2)grub中关于内核3.6开机引导项内容如下:
3)看了这断代码,对升级后新内核无法进入系统的原因就明了了,我在想,为什么升级内核的时候没有制作initrd
4)于是我退后一步,自己制作initrd,终端下:
1 | mkinitrd initrd-3.6.6 3.6.6 |
(先切换到linux-3.6.6的上一级目录),由于系统升级内核时已经编译过内核镜像和内核模块了,并且也已经安装过内核模块了
5)所以我要做的就是将initrd复制到boot目录下,然后再添加新的引导项
6)在上图 echo 'Loading Fedora (3.6.10-2.fc17.i686)' 的下一行添加自己制作的initrd,代码:initrd/boot/initrd-3.6.10-2.fc17.i686.img
7)重启电脑,OK,成功引导进行新内核,但是有很多地方不尽人意
1)电脑需要重装显卡驱动,分辨率太低
2)无法联网,需要重装网卡驱动
3)无法挂载FAT格式的盘
4)无法挂载NTFS格式的盘
8)因此,我还是决定用3.3的内核,只是在3.6下作驱动程序测试
4.驱动测试
1)如图所示:
2)驱动设备创建好后,编写一个程序验证下
3)效果如图:
4)这里出现OPEN错误和READ错误,但是却又读出了驱动函数的内容,表示驱动还是成功的,由于这个内核开始出现的不尽人意,也没有去调试这个错误的原因
5.驱动源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #include <linux/kernel.h> #include <linux/fs.h> #include <linux/module.h> #include <asm/uaccess.h> #include <linux/cdev.h> static int char_read( struct file *filp, char __user *buffer, size_t ,loff_t *); static int char_open( struct inode *, struct file *); static int char_write( struct file *filp, const char __user *buffer, size_t ,loff_t*); static int char_release( struct inode *, struct file *); static int device_open_count; static int major; static const struct file_operations file_ops = { .read = char_read, .write = char_write, .open = char_open, .release = char_release, }; static int __init char_init( void ) { int value; major = 0; value = register_chrdev(major, "chardev" , &file_ops); if (value < 0) { printk( "无法注册设备" ); return value; } if (major == 0) major = value; return 0; } static int char_open( struct inode *inode, struct file *file) { if (device_open_count == 0) device_open_count++; else { printk( "设备已经被打开\n" ); return -1; } try_module_get(THIS_MODULE); return 0; } static int char_release( struct inode *inode, struct file *file) { device_open_count--; module_put(THIS_MODULE); return 0; } static int char_read( struct file *filp, char __user *buffer, size_t length,loff_t *offset) { if (length < 0) return -1; else if (length > 12) length = 12; if (copy_to_user(buffer, "Hello Linux!" ,length)) return length; return -1; } static int char_write( struct file *filp, const char __user *buffer, size_t length,loff_t *offset) { return 0; } static void __exit module_close( void ) { unregister_chrdev(major, "chardev" ); } module_init(char_init); module_exit(module_close); |
6.Makefile源代码
1 2 3 4 5 6 7 | obj-m:=chardev.o KDIR:= /lib/modules/ $(shell uname -r) /build SRCPWD:=$(shell pwd ) all: make -C $(KDIR) M=$(SRCPWD) modules clean: rm -rf chardev.o |
7.测试程序源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <string.h> int main( void ) { int testdev; int i,rf=0; char buf[15]; memset (buf, 0, sizeof (buf)); testdev = open( "/dev/chardev" ,O_RDWR); if ( testdev == -1 ) { perror ( "open\n" ); exit (0); } rf=read(testdev,buf,11); if (rf<0) perror ( "read error\n" ); printf ( "R:%s\n" ,buf); close(testdev); return 0; } |
本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1155153
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 开发的设计和重构,为开发效率服务
· 从零开始开发一个 MCP Server!
· Ai满嘴顺口溜,想考研?浪费我几个小时
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)