您现在的位置是: 首页 > 安装教程 安装教程
精通linux 设备驱动程序开发_linux设备驱动开发详解视频
ysladmin 2024-05-13 人已围观
简介精通linux 设备驱动程序开发_linux设备驱动开发详解视频 好的,现在我来为大家谈一谈精通linux 设备驱动程序开发的问题,希望我的回答能够解答大家的
好的,现在我来为大家谈一谈精通linux 设备驱动程序开发的问题,希望我的回答能够解答大家的疑惑。关于精通linux 设备驱动程序开发的话题,我们开始说说吧。
1.做linux下的驱动开发,需要掌握哪些技能和知识点?有没具体的要求列一下.谢谢各位
2.linuxarm驱动开发linuxarm驱动
3.Linux驱动程序开发实例的目录
4.如何玩转linux驱动
5.如何自学linux驱动开发,做驱动开发需要哪些方面的知识
6.linux USB驱动资料
做linux下的驱动开发,需要掌握哪些技能和知识点?有没具体的要求列一下.谢谢各位
.您要驱动什么东西?抛开Linux系统的约束,您对要驱动的东西是如何工作的、如何去编程驱动它了解吗?是一点不了解?半知半解?一般了解?还是熟知?精通?如果对要驱动的东西都不了解,或者纯粹就想泛泛地学习Linux驱动编程,估计收获不会很大。
2.做过多线程编程吗?为什么要多线程?深刻理会了多线程中如何访问临界资源,如何使用mutex,semaphore?多个线程工作起来,怎么控制它们像我们几个人一起协作干活那样,该各干各的,又该相互通知与配合呢?
3.如果把操作系统比作一个大的执行程序,那么驱动程序就相当于以动态链接库形式提供的“插件”。您有没有做过“插件”式的应用程序?没做过也没关系,您认真思考一下这样的问题:您要做一个控制小车的程序,您这个程序功能很牛X,您希望无论是张家的小车,还是李家的小车都能被您控制,无奈您手头上只有牛家的小车,但你明白,张家、李家的小车功能和你牛家的差不多,控制也就那些事,就是目前不知道具体该如何控制。您得想个法子,留好接口,尽可能保证以后张家、李家的小车都可以被你的程序控制——这时候,你的程序该怎么设计结构比较好呢?
4.CPU在时钟脉冲“PIA-PIA”的节奏下都在干些什么?无论是X86或是ARM,要做驱动,对这个还是得有点基本的了解。
5.保护模式,虚拟内存,大致的道理明白吗?这个得知道。咱们现在大多数的处理器都有cache,cache干啥用?对DMA会有些什么不良影响?这个如果要搞DMA(例如PCI设备驱动)需要明白。
6.按楼上的兄弟说的,找本LDD学习
7.总的来说,设备驱动程序干的是驱动硬件的活,但它的编写更需要注重软件的思路、结构和方法。前面说的写小车控制程序能一定程度上说明这个问题。当然,听起来好像有点难,但是干起来还是挺爽的,没有想的那么复杂
linuxarm驱动开发linuxarm驱动
1、国内的书内容都差不多,相互抄来抄去。
国外的书质量虽然高,但是一般人阅读速度吃不消。
不过,还是建议读国外的书(如果有时间的话),长痛不如短痛。
2、不一定非要有开发板,可以用skyeye等软件模拟。
但是,软件模拟和实体机肯定是有区别的。还是建议选一块开发板。
3、ARM板是个硬件,可以用来学习WinCE、Vxworks、Linux、uCos等等系统开发。
可以用来学习以上系统的驱动和应用开发。
Linux驱动分两块内容:学习硬件工作流程(单片机程序),
Linux驱动上层结构
(platform、mtd、字符设备、块设备、网络设备、各种总线 等上层结构)
4.前景大大滴好,但是道路十分之曲折。
要有心里准备,得有文火久煨的毅力。
Linux驱动程序开发实例的目录
linux内核目录driver/usb/serial/option.c驱动请教?arch下面是体系架构,以及平台相关文件:
比如,把arch/arm/config里面的s3c2410_defconfig,拷贝到内核根目录,命名为.config
再修改根目录Makefile,选择arm交叉编译工具,执行makemenuconfig就可以配置
你定义的内核,选择自己的驱动。
USB、TTY、LCD、网卡等驱动在不同的目录,建议先了解和熟悉linux目录树结构,
以及各自对应的功能。
比如/net目录是网络驱动,但是/driver/net/下面是网络相关的具体设备驱动。
假设你有两个网卡,一个是DM9000,一个是CS8900,在/driver/net/下面,对应两个目录,但是这两个设备驱动,都属于网卡驱动,在/net下面。
建议结合书本和代码,来一步一步学习。比如LDD等经典书籍。
安卓内核能不能移植至ARM9开发板?
先学PC上的linux编程,内核编程,驱动编程。然后嵌入式移植到ARM9。
linux驱动开发和单片机驱动的区别?
.lonux驱动开发和单片机驱动开发的区别塞以下几点?ARM-Linux应用开发和单片机lonux:
这里先要做一个说明,对于ARM的应用开发主要有两种方式:一种是直接在ARM芯片上进行应用开发,不采用操作系统,也称为裸机编程,这种开发方式主要应用于一些低端的ARM芯片上,其开发过程非常类似单片机,这里不多叙述。
还有一种是在ARM芯片上运行操作系统,对于硬件的操作需要编写相应的驱动程序,应用开发则是基于操作系统的,这种方式的嵌入式应用开发与单片机开发差异较大。ARM-Linux应用开发和单片机的开发主要有以下几点不同:
(1)应用开发环境的硬件设备不同单片机:开发板,仿真器(调试器),USB线;ARM-Linux:开发板,网线,串口线,SD卡;对于ARM-Linux开发,通常是没有硬件的调试器的,尤其是在应用开发的过程中,很少使用硬件的调试器,程序的调试主要是通过串口进行调试的;但是需要说明的是,对于ARM芯片也是有硬件仿真器的,但通常用于裸机开发。
(2)程序下载方式不同单片机:仿真器(调试器)下载,或者是串口下载;
ARM-Linux:串口下载、tftp网络下载、或者直接读写SD、MMC卡等存储设备,实现程序下载;这个与开发环境的硬件设备是有直接关系的,由于没有硬件仿真器,故ARM-Linux开发时通常不采用仿真器下载;这样看似不方便,其实给ARM-Linux的应用开发提供了更多的下载方式。
(3)芯片的硬件资源不同单片机:通常是一个完整的计算机系统,包含片内RAM,片内FLASH,以及UART、I2C、AD、DA等各种外设;
ARM:通常只有CPU,需要外部电路提供RAM以供ARM正常运行,外部电路提供FLASH、SD卡等存储系统映像,并通过外部电路实现各种外设功能。由于ARM芯片的处理能力很强,通过外部电路可以实现各种复杂的功能,其功能远远强于单片机。
(4)固件的存储位置不同单片机:通常具备片内flash存储器,固件程序通常存储在该区域,若固件较大则需要通过外部电路设计外部flash用于存储固件。
ARM-Linux:由于其没有片内的flash,并且需要运行操作系统,整个系统映像通常较大,故ARM-Linux开发的操作系统映像和应用通常存储在外部的MMC、SD卡上,或者采用SATA设备等。
(5)启动方式不同单片机:其结构简单,内部集成flash,通常是芯片厂商在程序上电时加入固定的跳转指令,直接跳转到程序入口(通常在flash上);开发的应用程序通过编译器编译,采用专用下载工具直接下载到相应的地址空间;所以系统上电后直接运行到相应的程序入口,实现系统的启动。
ARM-Linux:由于采用ARM芯片,执行效率高,功能强大,外设相对丰富,是功能强大的计算机系统,并且需要运行操作系统,所以其启动方式和单片机有较大的差别,但是和家用计算机的启动方式基本相同。其启动一般包括BIOS,bootloader,内核启动,应用启动等阶段;
(a)启动BIOS:BIOS是设备厂家(芯片或者是电路板厂家)设置的相应启动信息,在设备上电后,其将读取相应硬件设备信息,进行硬件设备的初始化工作,然后跳转到bootloader所在位置(该位置是一个固定的位置,由BIOS设置)。(根据个人理解,BIOS的启动和单片机启动类似,需要采用相应的硬件调试器进行固件的写入,存储在一定的flash空间,设备上电启动后读取flash空间的指令,从而启动BIOS程序。)
(b)启动bootloader:该部分已经属于嵌入式Linux软件开发的部分,可以通过代码修改定制相应的bootloader程序,bootloader的下载通常是采用直接读写SD卡等方式。即编写定制相应的bootloader,编译生成bootloader映象文件后,利用工具(专用或通用)下载到SD卡的MBR区域(通常是存储区的第一个扇区)。此时需要在BIOS中设置,或者通过电路板的硬件电路设置,选择bootloader的加载位置;若BIOS中设置从SD卡启动,则BIOS初始化结束后,将跳转到SD卡的位置去执行bootloader,从而实现bootloader的启动。Bootloader主要作用是初始化必要的硬件设备,创建内核需要的一些信息并将这些信息通过相关机制传递给内核,从而将系统的软硬件环境带到一个合适的状态,最终调用操作系统内核,真正起到引导和加载内核的作用。
(c)启动内核:bootloader启动完成初始化等相关工作之后,将调用内核启动程序。这就进入了实际的操作系统相关内容的启动了,包括相应的硬件配置,任务管理,资源管理等内核程序的启动。
(d)启动应用:在操作系统内核启动之后,就可以开始启动需要的应用,去完成真正的业务操作了。
如何玩转linux驱动
前言第1章 Linux设备驱动程序模型 1
1.1 设备驱动程序基础 1
1.1.1 驱动程序的概念 1
1.1.2 驱动程序的加载方式 2
1.1.3 编写可加载模块 3
1.1.4 带参数的可加载模块 5
1.1.5 设备驱动程序的分类 6
1.2 字符设备驱动程序原理 7
1.2.1 file_operations结构 7
1.2.2 使用register_chrdev注册字符
设备 9
1.2.3 使用cdev_add注册字符设备 11
1.2.4 字符设备的读写 13
1.2.5 ioctl接口 14
1.2.6 seek接口 16
1.2.7 poll接口 18
1.2.8 异步通知 22
1.3 proc文件系统 24
1.3.1 proc文件系统概述 24
1.3.2 seq_file机制 25
1.3.3 使用proc文件系统 27
1.4 块设备驱动程序 32
1.4.1 Linux块设备驱动程序原理 32
1.4.2 简单的块设备驱动程序实例 35
1.5 网络设备驱动程序 39
1.5.1 网络设备的特殊性 39
1.5.2 sk_buff结构 40
1.5.3 Linux网络设备驱动程序架构 42
1.5.4 虚拟网络设备驱动程序实例 46
1.6 Linux 2.6设备管理机制 50
1.6.1 kobject和kset 50
1.6.2 sysfs文件系统 51
1.6.3 设备模型层次 52
1.6.4 platform的概念 54
第2章 Linux内核同步机制 58
2.1 锁机制 58
2.1.1 自旋锁 58
2.1.2 读写锁 60
2.1.3 RCU 61
2.2 互斥 64
2.2.1 原子操作 64
2.2.2 信号量 65
2.2.3 读写信号量 67
2.3 等待队列 68
2.3.1 等待队列原理 68
2.3.2 阻塞式I/O实例 68
2.3.3 完成事件 70
2.4 关闭中断 71
第3章 内存管理与链表 72
3.1 物理地址和虚拟地址 72
3.2 内存分配与释放 72
3.3 IO端口到虚拟地址的映射 73
3.3.1 静态映射 73
3.3.2 动态映射 75
3.4 内核空间到用户空间的映射 76
3.4.1 内核空间到用户空间的地址
映射原理 76
3.4.2 mmap地址映射实例 78
3.5 内核链表 80
3.5.1 Linux内核中的链表 80
3.5.2 内核链表实例 81
第4章 延迟处理 83
4.1 内核线程 83
4.2 软中断机制 85
4.2.1 软中断原理 85
4.2.2 tasklet 87
4.3 工作队列 89
4.3.1 工作队列原理 89
4.3.2 工作队列实例 91
4.4 内核时间 92
4.4.1 Linux中的时间概念 92
4.4.2 Linux中的延迟 93
4.4.3 内核定时器 93
第5章 简单设备驱动程序 96
5.1 寄存器访问 96
5.1.1 S3C6410地址映射 96
5.1.2 S3C6410看门狗驱动程序实例 98
5.1.3 S3C6410蜂鸣器驱动程序实例 102
5.2 电平控制 107
5.2.1 S3C6410 LED驱动程序实例 107
5.2.2 扫描型S3C6410按键驱动
程序实例 109
5.3 时序产生 112
5.3.1 时序图原理 112
5.3.2 AT24C02芯片原理 112
5.3.3 AT24C02驱动程序开发实例 115
5.4 硬中断处理 123
5.4.1 硬中断处理原理 123
5.4.2 中断型S3C6410按键驱动
程序实例 127
5.5 Linux I/O端口控制 132
5.5.1 Linux I/O端口读写 132
5.5.2 在应用层访问Linux I/O
端口 133
5.5.3 /dev/port设备 134
第6章 深入Linux内核 135
6.1 嵌入式Linux系统构成 135
6.2 Linux内核导读 136
6.2.1 Linux内核组成 136
6.2.2 Linux的代码结构 137
6.2.3 内核Makefile 138
6.2.4 S3C6410硬件初始化 139
6.3 Linux文件系统 141
6.3.1 虚拟文件系统 141
6.3.2 根文件系统 143
6.3.3 文件系统加载 143
6.3.4 ext3文件系统 145
6.4 Flash文件系统 145
6.4.1 MTD设备 145
6.4.2 MTD字符设备 148
6.4.3 MTD块设备 150
6.4.4 cramfs文件系统 153
6.4.5 JFFS2文件系统 153
6.4.6 YAFFS文件系统 155
6.4.7 文件系统总结 156
6.5 Linux内核移植 156
6.5.1 体系配置 156
6.5.2 添加yaffs2 157
6.5.3 Nand flash驱动程序移植 157
6.5.4 配置启动参数 159
6.5.5 移植RTC驱动程序 160
6.6 根文件系统制作 162
6.6.1 Busybox 162
6.6.2 shell基础 165
6.6.3 根文件系统构建实例 166
6.7 udev模型 167
6.7.1 udev模型原理 167
6.7.2 mdev的使用 167
第7章 I2C总线驱动程序 169
7.1 Linux的I2C驱动程序架构 169
7.1.1 I2C适配器 169
7.1.2 I2C算法 170
7.1.3 I2C驱动程序结构 170
7.1.4 I2C从设备 171
7.1.5 i2c-dev设备层 171
7.2 Linux I2C驱动程序开发 174
7.2.1 S3C2410X的I2C控制器 174
7.2.2 S3C2410X的I2C驱动程序
分析 175
7.3 S3C2410的I2C访问实例 182
7.4 I2C客户端驱动程序 185
第8章 TTY与串口驱动程序 190
8.1 TTY概念 190
8.2 Linux TTY驱动程序体系 190
8.2.1 TTY驱动程序调用关系 190
8.2.2 TTY驱动程序原理 191
8.3 线路规程 194
8.4 串口驱动程序与TTY 196
8.4.1 串口设备驱动程序原理 196
8.4.2 S3C6410的串口驱动程序
实例 199
8.5 TTY应用层 202
第9章 网络设备驱动程序 205
9.1 DM9000网卡驱动程序
开发 205
9.1.1 DM9000原理 205
9.1.2 DM9000X驱动程序分析 207
9.1.3 DM9000网口驱动程序移植 215
9.2 NFS根文件系统搭建 219
9.2.1 主机配置 219
9.2.2 NFS根文件系统搭建实例 220
9.3 netlink Socket 224
9.3.1 netlink机制 224
9.3.2 netlink应用层编程 228
9.3.3 netlink驱动程序实例 229
第10章 framebuffer驱动程序 232
10.1 Linux framebuffer驱动
程序原理 232
10.1.1 framebuffer核心数据结构 232
10.1.2 framebuffer操作接口 234
10.1.3 framebuffer驱动程序的文件
接口 236
10.1.4 framebuffer驱动程序框架 236
10.2 S3C6410 显示控制器 238
10.3 S3C6410 LCD驱动程序实例 243
10.4 framebuffer应用层 250
10.5 Qt4界面系统移植 251
第11章 输入子系统驱动程序 253
11.1 Linux输入子系统概述 253
11.1.1 input_dev结构 253
11.1.2 输入事件 255
11.2 input_handler 256
11.2.1 Input Handler层 256
11.2.2 常用的Input Handler 259
11.3 输入设备应用层 261
11.4 键盘输入设备驱动程序
实例 262
11.5 event接口 267
11.6 触摸屏驱动程序实例 270
11.6.1 S3C6410触摸屏控制器 270
11.6.2 S3C6410触摸屏驱动程序
设计 273
11.7 触摸屏校准 282
11.7.1 触摸屏校准原理 282
11.7.2 利用TSLIB库校准触摸屏 282
第12章 USB驱动程序 284
12.1 USB体系概述 284
12.1.1 USB系统组成 284
12.1.2 USB主机 284
12.1.3 USB设备逻辑层次 285
12.2 Linux USB驱动程序体系 287
12.2.1 USB总体结构 287
12.2.2 USB设备驱动程序 287
12.2.3 主机控制器驱动程序 288
12.2.4 USB请求块urb 289
12.2.5 USB请求块的填充 291
12.3 S3C6410 USB主机控制器
驱动程序 292
12.3.1 USB主机控制器驱动程序
分析 292
12.3.2 S3C6410 USB驱动程序
加载 294
12.4 USB键盘设备驱动程序
分析 296
12.5 USB Gadget驱动程序 301
12.5.1 Linux USB Gadget驱动程序 301
12.5.2 Linux USB Gadget驱动程序
实例 302
第13章 音频设备驱动程序 303
13.1 ALSA音频体系 303
13.2 ALSA驱动层API 304
13.2.1 声卡和设备管理 304
13.2.2 PCM API 304
13.2.3 控制与混音API 305
13.2.4 AC97 API 306
13.2.5 SOC层驱动 307
13.3 ALSA驱动程序实例 308
13.3.1 S3C6410的AC97控制
单元 308
13.3.2 S3C6410声卡电路原理 309
13.3.3 S3C6410的数字音频接口 310
13.3.4 wm9713的数字音频接口 313
13.4 ALSA音频编程接口 316
13.4.1 ALSA PCM接口实例 316
13.4.2 ALSA MIDI接口实例 320
13.4.3 ALSA mixer接口实例 321
13.4.4 ALSA timer接口实例 322
第14章 video4linux2视频
驱动程序 327
14.1 video4linux2驱动程序
架构 327
14.1.1 video4linux2驱动程序的
注册 327
14.1.2 v4l2_fops接口 331
14.1.3 常用的结构 332
14.1.4 video4linux2的ioctl函数 333
14.2 S3C6410摄像头驱动程序
分析 333
14.2.1 电路原理 333
14.2.2 驱动程序分析 334
14.3 video4linux2应用层实例 339
第15章 SD卡驱动程序 346
15.1 Linux SD卡驱动程序体系 346
15.1.1 SD卡电路原理 346
15.1.2 MMC卡驱动程序架构 347
15.1.3 MMC卡驱动程序相关
结构 347
15.1.4 MMC卡块设备驱动程序 350
15.1.5 SD卡主机控制器接口驱动
程序 356
15.2 S3C6410 SD卡控制器驱动
程序分析 360
15.2.1 电路原理 360
15.2.2 S3C6410 SDHCI驱动
程序原理 360
15.2.3 SD卡的加载实例 364
参考文献 366
如何自学linux驱动开发,做驱动开发需要哪些方面的知识
说玩转驱动这话,其实有点过头,玩驱动是个长期积累的过程,写出来是一回事,调试起来也是一种磨练。为了让大家明白玩驱动的乐趣和掌握编写驱动的捷径,我分享一些经验,算是抛砖引玉。不过正所谓一口吃不了个胖子,只有写够了足够多的代码,调试了足够多的模块,玩转驱动也不再话下。希望今天的唠叨对想踏入或者即将踏入驱动行业的你有些帮助。
我们很明白Linux 设备驱动的学习是一项浩大的工程,正是由于这个原因,一些人不免望而生畏,其实,只要我们有足够的积累和全面的知识,玩转驱动,也是早晚的事。闲话少说,开始来干货。
对于驱动工程师来说,首先要明白驱动在整个系统中的作用,
大家从上图中可以看出,linux驱动②在这个构架中起到承上硬件①启下应用程序③的作用。在程序的编写中,我们常用高内聚低耦合的标准,因此,驱动的引入显得意义更加重大:一方面,使嵌入式应用工程师不用考虑过多的硬件差异,另一方面,通过将设备驱动融入内核,面向操作系统内核的接口,这样的接口由操作系统规定,对一类设备而言结构一致,独立于具体的设备。同时由于linux操作系统有内存管理和进程管理,因此对于多任务并发的要求时,操作系统和驱动的引入使得任务变得简单。但是对于不需要多任务调度、文件系统、内存管理等复杂功能时,在一个大while(1)循环中既可以完成相关的任务。
上面分析了驱动的意义,那么,玩转linux驱动需要那方面的知识呢,现在罗列下:
第一、Linux 驱动工程师要有良好的硬件基础。这个要求不言而喻,linux驱动工程师的主要任务就是隐藏硬件的差异,给应用工程师一个统一的接口,因此需要能看懂电路图,理解SRAM、Flash、SDRAM、磁盘等模块的读写方式,知道UART、I2C、USB 等设备的接口以及常规操作,了解轮询、中断、DMA 的原理,PCI 总线的工作方式以及CPU 的内存管理单元(MMU)等。不过对于这种常见的模块,linux内核中有相关的配置,因此需要有阅读linux内核的能力和修改linux内核的能力。
第二 、Linux驱动工程师具有良好的C 语言基础。作为一个面向硬件底层和应用层的关键人物,C语言功底是必须要牢固的。在编写linux的字符设备和块设备驱动中常用的fopen()、fwrite()、fread()、fclose()以及内存分配中经常使用结构体和指针。因此能灵活地运用C 语言的结构体、指针、函数指针及内存动态申请和释放显现的尤为重要。
例如字符设备驱动中的读函数函数的定义
/* 读设备*/
ssize_t xxx_read(struct file *filp, char _ _user *buf, size_t count,loff_t*f_pos)
{
...
copy_to_user(buf, ..., ...);
...
}
从中看出C语言功底的重要性。
第三、 Linux 驱动工程师具有一定的Linux 内核基础,虽然并不要求工程师对内核各个部分有深入的研究,但至少要了解设备驱动与内核的接口,尤其是对于块设备、网络设备、Flash设备、串口设备等复杂设备。现在工作起来,嵌入式驱动工程师的工作量相对会小一点,因为一般常见的硬件设备供应商都会提供相应的linux版本驱动,驱动工程师的任务就是调试这些驱动能正常运行在自己的系统中,同时保证系统的稳定。
第四、 Linux 驱动工程师具有良好的操作系统知识。这个要求对于没有学习过操作系统的人来说唯一的痛苦之处就是对于专有名词不是很理解,例如上半部,下半部,原子操作等。其实刚开始或许是个痛苦的过程,但是只要认真的分析了一个或者几个驱动程序后,你就会发现其中的规律。毕竟linux驱动大体分为字符设备驱动、块设备驱动和网络设备驱动三类,正所谓抓其纲要,举一反三,便可融会贯通。因此linux中多任务并发控制和同步等基础很重要,因为在设备驱动中会大量使用自旋锁、互斥、信号量、等待队列等并发与同步机制。
第五、动手能力。
纸上得来终觉浅,因此,看再多的书也没有真正的调试一个驱动来的认识深刻。这时你需要搭建宿主机平台,购买开发板。不要好大喜功,从简单的小驱动开始一步一步走,以蚂蚁啃骨头的精神进行学习,收获会很大。
经历了痛苦的折磨,现在看下嵌入式驱动工程师的甜蜜吧,工作个三五年,你已经是大师了,可以去招聘网站浏览下,这方面的待遇都是面议奖金都是大大的,红色票票也随心所愿了。想到这些,你还不下定决心来经受linux驱动的虐待,相信只要以“驱动虐我千百遍,我待驱动如初恋”的决心,相信你可以玩转linux驱动。
linux USB驱动资料
做嵌入式应用的话一般的编程就可以了。那么嵌入式驱动开发与内核开发的话就需要学习多个方面的知识。我就把这方面的要求给你交流一下:
(一家之言啊,自己多年从事嵌入式开发的一点感悟)
嵌入式驱动开发需要了解的知识大概有以下几类:
1 嵌入式操作系统驱动框架。每一个操作系统都有自己的构架,应该了解驱动在整个系统中的具体位置与构建驱动程序的主要事项
2 总线知识,比如PCI、USB总线。
3 芯片知识。驱动其实就是对设备上一些寄存器的配置、CPU与设备本身的通讯以及对不同命令的处理
4 要做好驱动,必须对所使用的CPU体系结构有一个比较深刻的认识
5 C++基本用不上,主要是C和汇编。
6 做驱动最好要懂内核调试(比如说linux)
《Linux设备驱动程序》(十六)-中断处理
《LINUX设备驱动程序》
USB骨架程序(usb-skeleton),是USB驱动程序的基础,通过对它源码的学习和理解,可以使我们迅速地了解USB驱动架构,迅速地开发我们自己的USB硬件的驱动。
前言
在上篇《Linux下的硬件驱动--USB设备(上)(驱动配制部分)》中,我们知道了在Linux下如何去使用一些最常见的USB设备。但对于做系统设计的程序员来说,这是远远不够的,我们还需要具有驱动程序的阅读、修改和开发能力。在此下篇中,就是要通过简单的USB驱动的例子,随您一起进入 USB驱动开发的世界。
USB驱动开发
在掌握了USB设备的配置后,对于程序员,我们就可以尝试进行一些简单的USB驱动的修改和开发了。这一段落,我们会讲解一个最基础USB框架的基础上,做两个小的USB驱动的例子。
USB骨架
在Linux kernel源码目录中driver/usb/usb-skeleton.c为我们提供了一个最基础的USB驱动程序。我们称为USB骨架。通过它我们仅需要修改极少的部分,就可以完成一个USB设备的驱动。我们的USB驱动开发也是从她开始的。
那些linux下不支持的USB设备几乎都是生产厂商特定的产品。如果生产厂商在他们的产品中使用自己定义的协议,他们就需要为此设备创建特定的驱动程序。当然我们知道,有些生产厂商公开他们的USB协议,并帮助Linux驱动程序的开发,然而有些生产厂商却根本不公开他们的USB协议。因为每一个不同的协议都会产生一个新的驱动程序,所以就有了这个通用的USB驱动骨架程序, 它是以pci 骨架为模板的。
如果你准备写一个linux驱动程序,首先要熟悉USB协议规范。USB主页上有它的帮助。一些比较典型的驱动可以在上面发现,同时还介绍了USB urbs的概念,而这个是usb驱动程序中最基本的。
Linux USB 驱动程序需要做的第一件事情就是在Linux USB 子系统里注册,并提供一些相关信息,例如这个驱动程序支持那种设备,当被支持的设备从系统插入或拔出时,会有哪些动作。所有这些信息都传送到USB 子系统中,在usb骨架驱动程序中是这样来表示的:
static struct usb_driver skel_driver = {
name: "skeleton",
probe: skel_probe,
disconnect: skel_disconnect,
fops: &skel_fops,
minor: USB_SKEL_MINOR_BASE,
id_table: skel_table,
};
变量name是一个字符串,它对驱动程序进行描述。probe 和disconnect 是函数指针,当设备与在id_table 中变量信息匹配时,此函数被调用。
fops和minor变量是可选的。大多usb驱动程序钩住另外一个驱动系统,例如SCSI,网络或者tty子系统。这些驱动程序在其他驱动系统中注册,同时任何用户空间的交互操作通过那些接口提供,比如我们把SCSI设备驱动作为我们USB驱动所钩住的另外一个驱动系统,那么我们此USB设备的 read、write等操作,就相应按SCSI设备的read、write函数进行访问。但是对于扫描仪等驱动程序来说,并没有一个匹配的驱动系统可以使用,那我们就要自己处理与用户空间的read、write等交互函数。Usb子系统提供一种方法去注册一个次设备号和file_operations函数指针,这样就可以与用户空间实现方便地交互。
设备与处理器之间的工作通常来说是异步,设备数据要传递给处理器通常来说有以下几种方法:轮询、等待和中断。让CPU进行轮询等待总是不能让人满意,所以通常都采用中断的形式,让设备来通知CPU读取数据。
2.6内核的函数参数与现在的参数有所区别,这里都主要介绍概念,具体实现方法需要结合具体的内核版本。
request_irq函数申请中断,返回0表示申请成功,其他返回值表示申请失败,其具体参数解释如下:
flags 掩码可以使用以下几个:
快速和慢速处理例程 :现代内核中基本没有这两个概念了,使用SA_INTERRUPT位后,当中断被执行时,当前处理器的其他中断都将被禁止。通常不要使用SA_INTERRUPT标志位,除非自己明确知道会发生什么。
共享中断 :使用共享中断时,一方面要使用SA_SHIRQ位,另一个是request_irq中的dev_id必须是唯一的,不能为NULL。这个限制的原因是:内核为每个中断维护了一个共享处理例程的列表,例程中的dev_id各不相同,就像设备签名。如果dev_id相同,在卸载的时候引起混淆(卸载了另一个中断),当中断到达时会产生内核OOP消息。
共享中断需要满足以下一个条件才能申请成功:
当不需要使用该中断时,需要使用free_irq释放中断。
通常我们会在模块加载的时候申请安装中断处理例程,但书中建议:在设备第一次打开的时候安装,在设备最后一次关闭的时候卸载。
如果要查看中断触发的次数,可以查看 /proc/interrupts 和 /proc/stat。
书中讲述了如何自动检测中断号,在嵌入式开发中通常都是查看原理图和datasheet来直接确定。
自动检测的原理如下:驱动程序通知设备产生中断,然后查看哪些中断信号线被触发了。Linux提供了以下方法来进行探测:
探测工作耗时较长,建议在模块加载的时候做。
中断处理函数和普通函数其实差不多,唯一的区别是其运行的中断上下文中,在这个上下文中有以下注意事项:
中断处理函数典型用法如下:
中断处理函数的参数和返回值含义如下:
返回值主要有两个:IRQ_NONE和IRQ_HANDLED。
对于中断我们是可以进行开启和关闭的,Linux中提供了以下函数操作单个中断的开关:
该方法可以在所有处理器上禁止或启用中断。
需要注意的是:
如果要关闭当前处理器上所有的中断,则可以调用以下方法:
local_irq_save 会将中断状态保持到flags中,然后禁用处理器上的中断;如果明确知道中断没有在其他地方被禁用,则可以使用local_irq_disable,否则请使用local_irq_save。
locat_irq_restore 会根据上面获取到flags来恢复中断;local_irq_enable 会无条件打开所有中断。
在中断中需要做一些工作,如果工作内容太多,必然导致中断处理所需的时间过长;而中断处理又要求能够尽快完成,这样才不会影响正常的系统调度,这两个之间就产生了矛盾。
现在很多操作系统将中断分为两个部分来处理上面的矛盾:顶半部和底半部。
顶半部就是我们用request_irq来注册的中断处理函数,这个函数要求能够尽快结束,同时在其中调度底半部,让底半部在之后来进行后续的耗时工作。
顶半部就不再说明了,就是上面的中断处理函数,只是要求能够尽快处理完成并返回,不要处理耗时工作。
底半部通常使用tasklet或者工作队列来实现。
tasklet的特点和注意事项:
工作队列的特点和注意事项:
好了,关于“精通linux 设备驱动程序开发”的话题就讲到这里了。希望大家能够通过我的讲解对“精通linux 设备驱动程序开发”有更全面、深入的了解,并且能够在今后的工作中更好地运用所学知识。