-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
507 lines (287 loc) · 881 KB
/
atom.xml
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>兔子的个人博客 - Hexo Blog</title>
<subtitle>非学无以广才,非志无以成学</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://proudrabbit.gitee.io/"/>
<updated>2022-08-27T05:29:32.396Z</updated>
<id>https://proudrabbit.gitee.io/</id>
<author>
<name>路痴的兔子</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Android Studio Chipmunk版本解决gradle报错connection refuse的问题.md</title>
<link href="https://proudrabbit.gitee.io/Android-Studio-Chipmunk%E7%89%88%E6%9C%AC%E8%A7%A3%E5%86%B3gradle%E6%8A%A5%E9%94%99connection-refuse%E7%9A%84%E9%97%AE%E9%A2%98.html"/>
<id>https://proudrabbit.gitee.io/Android-Studio-Chipmunk%E7%89%88%E6%9C%AC%E8%A7%A3%E5%86%B3gradle%E6%8A%A5%E9%94%99connection-refuse%E7%9A%84%E9%97%AE%E9%A2%98.html</id>
<published>2022-08-27T02:57:12.000Z</published>
<updated>2022-08-27T05:29:32.396Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><h2 id="Android-Studio-Chipmunk版本解决gradle报错connection-refuse的问题"><a href="#Android-Studio-Chipmunk版本解决gradle报错connection-refuse的问题" class="headerlink" title="Android Studio Chipmunk版本解决gradle报错connection refuse的问题"></a>Android Studio Chipmunk版本解决gradle报错connection refuse的问题</h2><p>[toc]</p><h3 id="一、问题出现的原因"><a href="#一、问题出现的原因" class="headerlink" title="一、问题出现的原因"></a>一、问题出现的原因</h3><p> 因为gradle使用的仓库是国外的,很多时候访问不了,或者公司里面进行了管控导致无法下载依赖,所以gradle会同步出错。目前网上的教程都比较老,已经不适用于Android Studio Chipmunk版本了,因此摸索出了这个方法。</p><h3 id="二、解决办法"><a href="#二、解决办法" class="headerlink" title="二、解决办法"></a>二、解决办法</h3><ol><li><p>使用KX工具,不会翻墙的程序员不是一个好程序员。</p></li><li><p>使用国内镜像源</p><p>这里推荐推荐阿里云的镜像源<a href="https://developer.aliyun.com/mvn/guide" target="_blank" rel="noopener">https://developer.aliyun.com/mvn/guide</a>,地址是上面的地址。添加方法有三种,分别是工程添加,全局添加,使用工程模板。</p><ul><li><p>工程模板:安卓北极狐版本后添加工程模板较为繁琐,暂不推荐。<a href="https://www.jianshu.com/p/fa9b1357ebe7" target="_blank" rel="noopener">https://www.jianshu.com/p/fa9b1357ebe7</a></p></li><li><p>工程添加:</p><p>在工程根目录下的 <code>settings.gradle</code>文件下,修改部分内容为以下内容。</p><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">dependencyResolutionManagement {</span><br><span class="line"> repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)</span><br><span class="line"> repositories {</span><br><span class="line"> maven { url <span class="string">'https://maven.aliyun.com/repository/public'</span>}</span><br><span class="line"> maven { url <span class="string">'https://maven.aliyun.com/repository/google'</span>}</span><br><span class="line"> maven { url <span class="string">'https://maven.aliyun.com/repository/gradle-plugin'</span>}</span><br><span class="line"> </span><br><span class="line"> google()</span><br><span class="line"> mavenCentral()</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>全局添加:</p><p>在<code>C:\Users\your_username\.gradle\wrapper\dists\gradle-7.3.3-bin\一串乱码\gradle-7.3.3\init.d</code> 文件夹下新建一个 <code>.gradle</code> 结尾的文件,如 <code>init.gradle</code>,然后输入以下内容,这样每次在 gradle 执行的时候会首先加载这个文件设置仓库。</p><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">settingsEvaluated { settings -> </span><br><span class="line"> settings.dependencyResolutionManagement {</span><br><span class="line"> repositories {</span><br><span class="line"> maven { url <span class="string">'https://maven.aliyun.com/repository/public'</span>}</span><br><span class="line"> maven { url <span class="string">'https://maven.aliyun.com/repository/google'</span>}</span><br><span class="line"> maven { url <span class="string">'https://maven.aliyun.com/repository/gradle-plugin'</span>}</span><br><span class="line"> mavenLocal()</span><br><span class="line"> mavenCentral()</span><br><span class="line"> google()</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li></ol>]]></content>
<summary type="html">
解决Android Studio Chipmunk版本在使用gradle解决依赖时报错connection refuse的问题。2022年
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="安卓" scheme="https://proudrabbit.gitee.io/tags/%E5%AE%89%E5%8D%93/"/>
<category term="gradle" scheme="https://proudrabbit.gitee.io/tags/gradle/"/>
</entry>
<entry>
<title>2021第十六届智能车讯飞智慧餐厅及智能机器人分拣挑战赛代码开源</title>
<link href="https://proudrabbit.gitee.io/2021%E7%AC%AC%E5%8D%81%E5%85%AD%E5%B1%8A%E6%99%BA%E8%83%BD%E8%BD%A6%E8%AE%AF%E9%A3%9E%E6%99%BA%E6%85%A7%E9%A4%90%E5%8E%85%E5%8F%8A%E6%99%BA%E8%83%BD%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%88%86%E6%8B%A3%E6%8C%91%E6%88%98%E8%B5%9B%E4%BB%A3%E7%A0%81%E5%BC%80%E6%BA%90.html"/>
<id>https://proudrabbit.gitee.io/2021%E7%AC%AC%E5%8D%81%E5%85%AD%E5%B1%8A%E6%99%BA%E8%83%BD%E8%BD%A6%E8%AE%AF%E9%A3%9E%E6%99%BA%E6%85%A7%E9%A4%90%E5%8E%85%E5%8F%8A%E6%99%BA%E8%83%BD%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%88%86%E6%8B%A3%E6%8C%91%E6%88%98%E8%B5%9B%E4%BB%A3%E7%A0%81%E5%BC%80%E6%BA%90.html</id>
<published>2021-12-11T09:06:17.000Z</published>
<updated>2022-04-12T13:36:29.115Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>[toc]</p><h2 id="一、第十六届全国大学生智能车竞赛创意组讯飞智慧餐厅"><a href="#一、第十六届全国大学生智能车竞赛创意组讯飞智慧餐厅" class="headerlink" title="一、第十六届全国大学生智能车竞赛创意组讯飞智慧餐厅"></a>一、第十六届全国大学生智能车竞赛创意组讯飞智慧餐厅</h2><ol><li>演示视频:<a href="https://www.bilibili.com/video/BV1p64y187nd" target="_blank" rel="noopener">https://www.bilibili.com/video/BV1p64y187nd</a></li><li>镜像地址:「参赛资源」,点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。链接:<a href="https://www.aliyundrive.com/s/zNGHkYyWTrL" target="_blank" rel="noopener">https://www.aliyundrive.com/s/zNGHkYyWTrL</a></li><li>仓库地址:<a href="https://gitee.com/Lidan5/ucar_ws" target="_blank" rel="noopener">https://gitee.com/Lidan5/ucar_ws</a> 分支:<code>master</code></li><li><strong>PS:使用的小车是科大讯飞的晓-mini。</strong></li></ol><a id="more"></a><h2 id="二、智能机器人分拣挑战赛"><a href="#二、智能机器人分拣挑战赛" class="headerlink" title="二、智能机器人分拣挑战赛"></a>二、智能机器人分拣挑战赛</h2><ol><li>演示视频:<a href="https://www.bilibili.com/video/BV1fq4y1N7r4" target="_blank" rel="noopener">https://www.bilibili.com/video/BV1fq4y1N7r4</a></li><li>镜像地址:「参赛资源」,点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。链接:<a href="https://www.aliyundrive.com/s/zNGHkYyWTrL" target="_blank" rel="noopener">https://www.aliyundrive.com/s/zNGHkYyWTrL</a></li><li>仓库地址:<ul><li>小车:<a href="https://gitee.com/Lidan5/ucar_ws" target="_blank" rel="noopener">https://gitee.com/Lidan5/ucar_ws</a> 分支:<code>xf_uarm</code></li><li>机械臂:<a href="https://gitee.com/proudrabbit/xf_uarm_ws" target="_blank" rel="noopener">https://gitee.com/proudrabbit/xf_uarm_ws</a></li></ul></li><li><strong>PS:使用的小车是科大讯飞的晓-mini,机械臂是白的uarm。</strong></li></ol><h2 id="三、实物图片"><a href="#三、实物图片" class="headerlink" title="三、实物图片"></a>三、实物图片</h2><p>小车图片:</p><p><img src="https://s2.loli.net/2021/12/11/ny3TiHetFj4wk1x.jpg" alt="小车图片.jpg" title="小车图片"></p><p>机械臂图片:</p><p><img src="https://s2.loli.net/2021/12/11/8L3UatgypKQ9DzR.jpg" alt="机械臂图片.jpg" title="机械臂图片"></p>]]></content>
<summary type="html">
2021第十六届全国大学生智能车竞赛创意组讯飞智慧餐厅,以及智能机器人分拣挑战赛的代码和镜像开源。
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>Conda导入环境时显示ResolvePackageNotFound错误</title>
<link href="https://proudrabbit.gitee.io/Conda%E5%AF%BC%E5%85%A5%E7%8E%AF%E5%A2%83%E6%97%B6%E6%98%BE%E7%A4%BAResolvePackageNotFound%E9%94%99%E8%AF%AF.html"/>
<id>https://proudrabbit.gitee.io/Conda%E5%AF%BC%E5%85%A5%E7%8E%AF%E5%A2%83%E6%97%B6%E6%98%BE%E7%A4%BAResolvePackageNotFound%E9%94%99%E8%AF%AF.html</id>
<published>2021-09-06T13:14:21.000Z</published>
<updated>2022-04-12T13:36:29.119Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><code>Conda</code>导入环境时有时候会出现ResolvePackageNotFound错误,该错误的解决方式,博主<a href="https://blog.csdn.net/weixin_42240667/article/details/115773535" target="_blank" rel="noopener">哦啦哦啦</a>已经说明了怎么解决了,但是手动去删除包后面的详细配置信息还是比较麻烦的,我这里给出使用正则去删除的方法。首先用支持正则匹配的文本编辑器打开,推荐<code>VScode</code>、<code>Notepad3</code>。PS:不推荐<code>notepad++</code>,原因的话百度notepad++作者即可知道。</p><a id="more"></a><ol><li>使用<code>VScode</code>或<code>Notepad3</code>打开<code>conda</code>导出的<code>yaml</code>环境文件,然后打开替换,输入如下正则表达式</li></ol><figure class="highlight re"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(?<=^ {<span class="number">2</span>}-.*=.*=).*</span><br></pre></td></tr></table></figure><p>Notepad3匹配结果,直接点击全部替换即可。<br><img src="https://img-blog.csdnimg.cn/16bedbfc0f714bae9f0fae573726fc19.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6Lev55e055qE5YWU5a2Q,size_20,color_FFFFFF,t_70,g_se,x_16" alt="Notepad3匹配结果"></p><ol start="2"><li>使用第一步替换后,每一行的行尾漏了一个等号,再使用如下正则表达式全部替换即可。</li></ol><figure class="highlight re"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">=$</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/b399fd228c2d4658ac97da94b3f65580.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6Lev55e055qE5YWU5a2Q,size_20,color_FFFFFF,t_70,g_se,x_16" alt="替换结果"></p>]]></content>
<summary type="html">
使用正则去除anaconda导出环境配置时的详细信息,防止导入环境时出现ResolvePackageNotFound错误。
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="软件使用" scheme="https://proudrabbit.gitee.io/tags/%E8%BD%AF%E4%BB%B6%E4%BD%BF%E7%94%A8/"/>
<category term="anaconda" scheme="https://proudrabbit.gitee.io/tags/anaconda/"/>
</entry>
<entry>
<title>hexo博客yilia-puls主题使用aplayer音乐插件</title>
<link href="https://proudrabbit.gitee.io/hexo%E5%8D%9A%E5%AE%A2yilia-puls%E4%B8%BB%E9%A2%98%E4%BD%BF%E7%94%A8aplayer%E9%9F%B3%E4%B9%90%E6%8F%92%E4%BB%B6.html"/>
<id>https://proudrabbit.gitee.io/hexo%E5%8D%9A%E5%AE%A2yilia-puls%E4%B8%BB%E9%A2%98%E4%BD%BF%E7%94%A8aplayer%E9%9F%B3%E4%B9%90%E6%8F%92%E4%BB%B6.html</id>
<published>2021-08-23T05:46:47.000Z</published>
<updated>2021-08-25T14:11:38.180Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>[toc]</p><h1 id="hexo博客yilia-puls主题使用aplayer音乐插件"><a href="#hexo博客yilia-puls主题使用aplayer音乐插件" class="headerlink" title="hexo博客yilia-puls主题使用aplayer音乐插件"></a>hexo博客yilia-puls主题使用aplayer音乐插件</h1><p>由于<code>yilia-puls</code>使用的网易云插件放歌比较麻烦,所以添加了<code>aplayer</code>音乐插件,支持播放歌单,可以在我的博客查看效果<a href="https://proudrabbit.gitee.io/">兔子的个人博客 - Hexo Blog (gitee.io)</a>。经过测试,能够支持QQ音乐和网易云音乐歌单(其他的只是我没测,酷狗除外,确定不支持了)。</p><h2 id="一、安装并启用aplayer插件"><a href="#一、安装并启用aplayer插件" class="headerlink" title="一、安装并启用aplayer插件"></a>一、安装并启用aplayer插件</h2><ol><li><p>安装aplayer插件</p><p>直接使用<code>npm install --save hexo-tag-aplayer</code>安装即可。</p></li><li><p>使用aplayer插件</p><p>在博客的根目录下的<code>_config.yml</code>,<strong>注意</strong>不是主题的<code>_config.yml</code>文件,下添加如下代码。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">aplayer:</span><br><span class="line"> meting: true</span><br></pre></td></tr></table></figure></li><li><p>文章中使用</p><p>只需要在文章对应位置添加如下代码即可,详细的配置项的意义见<a href="https://github.com/MoePlayer/hexo-tag-aplayer" target="_blank" rel="noopener">MoePlayer/hexo-tag-aplayer: Embed aplayer in Hexo posts/pages (github.com)</a></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{% meting "60198" "netease" "playlist" "autoplay" "mutex:false" "listmaxheight:340px" "preload:none" "theme:#ad7a86" %}</span><br></pre></td></tr></table></figure></li></ol><a id="more"></a><h2 id="二、添加aplayer插件到主页"><a href="#二、添加aplayer插件到主页" class="headerlink" title="二、添加aplayer插件到主页"></a>二、添加aplayer插件到主页</h2><p>和上一篇博客说的一样,同样可以自己配置,或者直接拉取修改好的代码。修改完效果如下</p><p><img src="https://z3.ax1x.com/2021/08/23/hCME6J.png" alt="aplayer效果"></p><h3 id="1-直接拉取仓库到本地。"><a href="#1-直接拉取仓库到本地。" class="headerlink" title="1.直接拉取仓库到本地。"></a>1.直接拉取仓库到本地。</h3><p>我已经将代码修改后向<code>yilia-plus</code>的原作者<a href="https://github.com/JoeyBling/hexo-theme-yilia-plus" target="_blank" rel="noopener">JoeyBling/hexo-theme-yilia-plus: 一个简洁优雅的hexo主题</a>提出了PR请求,等待同意后,拉取更新即可,如果不想等,拉取我从原作者fork的仓库下来也行<a href="https://github.com/ProudRabbit/hexo-theme-yilia-plus" target="_blank" rel="noopener">ProudRabbit/hexo-theme-yilia-plus</a>,拉取到你的博客主题下之后进行配置即可,最好先备份下你原来的配置,防止配置丢失。在主题的配置文件<code>_config.yml</code>的<code>169</code>行,将歌单信息填写进去即可。</p><blockquote><p>我的hexo版本</p><p>hexo: 4.2.1<br>hexo-cli: 3.1.0<br>os: Windows_NT 10.0.19042 win32 x64<br>node: 12.18.2<br>v8: 7.8.279.23-node.39<br>uv: 1.38.0<br>zlib: 1.2.11<br>brotli: 1.0.7<br>ares: 1.16.0<br>modules: 72<br>nghttp2: 1.41.0<br>napi: 6<br>llhttp: 2.0.4<br>http_parser: 2.9.3<br>openssl: 1.1.1g<br>cldr: 37.0<br>icu: 67.1<br>tz: 2019c<br>unicode: 13.0</p></blockquote><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Header-菜单</span></span><br><span class="line"><span class="attr">menu:</span></span><br><span class="line"> <span class="string">主页:</span> <span class="string">/</span></span><br><span class="line"> <span class="string">技术笔记:</span> <span class="string">https://zhousiwei.gitee.io/ibooks/</span></span><br><span class="line"> <span class="string">随笔:</span> <span class="string">/tags/随笔/</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># subNav-子导航</span></span><br><span class="line"><span class="attr">subNav:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">github:</span> <span class="string">"#"</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">github:</span> <span class="string">"#"</span> <span class="comment"># (支持设置多个)</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">gitee:</span> <span class="string">"#"</span> <span class="comment"># 码云</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">jianshu:</span> <span class="string">"#"</span> <span class="comment">#简书</span></span><br><span class="line"> <span class="comment"># - cnblog: "#"</span></span><br><span class="line"> <span class="comment"># - blog: "#"</span></span><br><span class="line"> <span class="comment"># - csdn: "#"</span></span><br><span class="line"> <span class="comment"># - rss: "#"</span></span><br><span class="line"> <span class="comment"># - zhihu: "#"</span></span><br><span class="line"> <span class="comment"># - qq: "img/2434387555.jpg"</span></span><br><span class="line"> <span class="comment"># - weixin: "img/weixin_.png"</span></span><br><span class="line"> <span class="comment"># - weibo: "#"</span></span><br><span class="line"> <span class="comment"># - douban: "#"</span></span><br><span class="line"> <span class="comment"># - segmentfault: "#"</span></span><br><span class="line"> <span class="comment"># - bilibili: "#"</span></span><br><span class="line"> <span class="comment"># - acfun: "#"</span></span><br><span class="line"> <span class="comment"># - mail: "mailto:zhousiwei0911@qq.com"</span></span><br><span class="line"> <span class="comment"># - facebook: "#"</span></span><br><span class="line"> <span class="comment"># - google: "#"</span></span><br><span class="line"> <span class="comment"># - twitter: "#"</span></span><br><span class="line"> <span class="comment"># - linkedin: "#"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 悬停预览图片效果</span></span><br><span class="line"><span class="attr">hover_effect:</span></span><br><span class="line"> <span class="comment">## `global` 0: Set separately, 1: Enable global 2: Close global</span></span><br><span class="line"> <span class="comment">## `global` 0: 分开设置, 1: 全局启用, 2: 全局关闭</span></span><br><span class="line"> <span class="attr">global:</span> <span class="number">2</span></span><br><span class="line"> <span class="comment"># SubNav-导航</span></span><br><span class="line"> <span class="attr">subNav:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># RSS订阅(关于如何配置启用:https://www.jianshu.com/p/2aaac7a19736)</span></span><br><span class="line"><span class="attr">rss:</span> <span class="string">/atom.xml</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 是否需要修改 root 路径</span></span><br><span class="line"><span class="comment"># 如果您的网站存放在子目录中,例如 http://yoursite.com/blog,</span></span><br><span class="line"><span class="comment"># 请将您的 url 设为 http://yoursite.com/blog 并把 / 设为 /blog/。</span></span><br><span class="line"><span class="comment"># 新版本已弃用,请在博客根目录文件进行配置</span></span><br><span class="line"><span class="comment"># root: /</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Content</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 文章太长,截断按钮文字(在需要截断的行增加此标记:<!--more-->)</span></span><br><span class="line"><span class="attr">excerpt_link:</span> <span class="string">more</span></span><br><span class="line"><span class="comment"># 文章卡片右下角常驻链接,不需要请设置为false</span></span><br><span class="line"><span class="attr">show_all_link:</span> <span class="string">'展开全文'</span></span><br><span class="line"><span class="comment"># 数学公式</span></span><br><span class="line"><span class="attr">mathjax:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Open link in a new tab | 是否在新窗口打开链接</span></span><br><span class="line"><span class="attr">open_in_new:</span></span><br><span class="line"> <span class="attr">article:</span> <span class="literal">true</span> <span class="comment"># 文章链接</span></span><br><span class="line"> <span class="attr">menu:</span> <span class="literal">true</span> <span class="comment"># 导航菜单</span></span><br><span class="line"> <span class="attr">subNav:</span> <span class="literal">true</span> <span class="comment"># 子菜单</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 打赏</span></span><br><span class="line"><span class="comment"># 打赏type设定:0-关闭打赏; 1-文章对应的md文件里有reward:true属性,才有打赏; 2-所有文章均有打赏</span></span><br><span class="line"><span class="attr">reward_type:</span> <span class="number">2</span></span><br><span class="line"><span class="comment"># 打赏wording</span></span><br><span class="line"><span class="attr">reward_wording:</span> <span class="string">'谢谢你请我吃糖果'</span></span><br><span class="line"><span class="comment"># 支付宝二维码图片地址,跟你设置头像的方式一样。比如:/assets/img/alipay.jpg</span></span><br><span class="line"><span class="attr">alipay:</span> <span class="string">/img/alipay.jpg</span></span><br><span class="line"><span class="comment"># 微信二维码图片地址</span></span><br><span class="line"><span class="attr">weixin:</span> <span class="string">/img/weixin.png</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 目录</span></span><br><span class="line"><span class="comment"># 目录设定:0-不显示目录; 1-文章对应的md文件里有toc:true属性,才有目录; 2-所有文章均显示目录</span></span><br><span class="line"><span class="attr">toc:</span> <span class="number">1</span></span><br><span class="line"><span class="comment"># 根据自己的习惯来设置,如果你的目录标题习惯有标号,置为true即可隐藏hexo重复的序号;否则置为false</span></span><br><span class="line"><span class="attr">toc_hide_index:</span> <span class="literal">true</span></span><br><span class="line"><span class="comment"># 目录为空时的提示</span></span><br><span class="line"><span class="attr">toc_empty_wording:</span> <span class="string">'目录,不存在的…'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 是否有快速回到顶部的按钮</span></span><br><span class="line"><span class="attr">top:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Miscellaneous</span></span><br><span class="line"><span class="comment"># 百度统计</span></span><br><span class="line"><span class="attr">baidu_analytics:</span> <span class="string">''</span></span><br><span class="line"><span class="attr">google_analytics:</span> <span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 网站图标</span></span><br><span class="line"><span class="attr">favicon:</span> <span class="string">/favicon.ico</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 你的头像url</span></span><br><span class="line"><span class="attr">avatar:</span> <span class="string">/img/head.jpg</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 是否开启分享</span></span><br><span class="line"><span class="attr">share_jia:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 评论:1、畅言;2、Disqus;3、Gitment;4、Giteement 5、beaudar-表达</span></span><br><span class="line"><span class="comment"># 不需要使用某项,直接设置值为false,或注释掉</span></span><br><span class="line"><span class="comment"># 具体请参考wiki:https://github.com/JoeyBling/hexo-theme-yilia-plus/wiki</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 1、畅言</span></span><br><span class="line"><span class="attr">changyan_appid:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">changyan_conf:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2、Disqus 在hexo根目录的config里也有disqus_shortname字段,优先使用yilia-plus的</span></span><br><span class="line"><span class="attr">disqus:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3、Gitment----基于GitHub的评论系统(关闭请设置gitment_owner为false)</span></span><br><span class="line"><span class="comment"># 关于如何集成:https://www.jianshu.com/p/ac7658cc912f</span></span><br><span class="line"><span class="attr">gitment_owner:</span> <span class="literal">false</span> <span class="comment">#你的 GitHub ID</span></span><br><span class="line"><span class="comment"># 是否使用官方js(false可以提升访问速度,本地修改过一部分的js,官方js可能会出现服务器不稳定,不太建议使用)</span></span><br><span class="line"><span class="attr">gitment_remote:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">gitment_repo:</span> <span class="string">''</span> <span class="comment">#存储评论的 repo name(需要在Github创建)</span></span><br><span class="line"><span class="attr">gitment_oauth:</span></span><br><span class="line"> <span class="attr">client_id:</span> <span class="string">''</span> <span class="comment">#client ID</span></span><br><span class="line"> <span class="attr">client_secret:</span> <span class="string">''</span> <span class="comment">#client secret</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 4、Giteement----【国内用户建议使用这个,相对比较快】</span></span><br><span class="line"><span class="comment"># 关于如何集成:https://www.jianshu.com/p/f5c4633524c7</span></span><br><span class="line"><span class="comment"># 基于码云的评论系统(https://gitee.com/zhousiwei/giteement)</span></span><br><span class="line"><span class="attr">giteement:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span> <span class="comment"># 是否启用码云评论系统</span></span><br><span class="line"> <span class="comment"># 是否使用官方js(false可以提升访问速度)</span></span><br><span class="line"> <span class="attr">remote:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">redirect_uri:</span> <span class="string">''</span> <span class="comment"># 应用回调地址(请和配置的第三方应用保持一致)</span></span><br><span class="line"> <span class="comment"># 不能更改(网上开源项目`https://github.com/Rob--W/cors-anywhere`作者提供的专门用来跨域服务器的配置)</span></span><br><span class="line"> <span class="attr">oauth_uri:</span> <span class="string">https://cors-anywhere.herokuapp.com/https://gitee.com/oauth/token</span></span><br><span class="line"> <span class="attr">giteeID:</span> <span class="string">''</span> <span class="comment"># 你的码云账号英文名</span></span><br><span class="line"> <span class="comment"># 存储评论的 repo name(需要在码云仓库创建公开仓库)</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="string">''</span></span><br><span class="line"> <span class="attr">gitment_oauth:</span></span><br><span class="line"> <span class="attr">client_id:</span> <span class="string">''</span> <span class="comment">#client ID</span></span><br><span class="line"> <span class="attr">client_secret:</span> <span class="string">''</span> <span class="comment">#client secret</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 5、beaudar-表达 评论,由于giteement和gitment都不能使用了,所以使用beaudar</span></span><br><span class="line"><span class="comment"># 插件配置地址 https://beaudar.lipk.org/</span></span><br><span class="line"><span class="attr">beaudar:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="string">''</span> <span class="comment"># 仓库名称 注意直接从GitHub上复制 / 左右可能有空格,注意删除</span></span><br><span class="line"> <span class="attr">issue_term:</span> <span class="string">'pathname'</span> <span class="comment"># beaudar 生成的博客文章 ↔️ Issue 映射关系</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">'comment'</span> <span class="comment"># issue 标签,选择将分配给 Beaudar 创建的问题的标签</span></span><br><span class="line"> <span class="attr">theme:</span> <span class="string">'github-light'</span> <span class="comment"># beaudar 主题</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 访问量统计功能(不蒜子)</span></span><br><span class="line"><span class="attr">busuanzi:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">site_visit:</span> <span class="literal">true</span> <span class="comment"># 站点访问量显示</span></span><br><span class="line"> <span class="attr">article_visit:</span> <span class="literal">true</span> <span class="comment"># 文章访问量显示</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 音乐插件</span></span><br><span class="line"><span class="attr">music:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment"># 是否使用音乐插件</span></span><br><span class="line"> <span class="attr">text:</span> <span class="string">''</span> <span class="comment"># 提示文本(关闭请设置为false)</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">cloudMusic:</span> <span class="comment"># 网易云音乐插件</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span> <span class="comment"># 使用网易云</span></span><br><span class="line"> <span class="comment"># 播放器尺寸类型(1:长尺寸、2:短尺寸)</span></span><br><span class="line"> <span class="attr">type:</span> <span class="number">2</span></span><br><span class="line"> <span class="attr">id:</span> <span class="number">30245064</span> <span class="comment"># 网易云分享的音乐ID(更换音乐请更改此配置项) 572578819 奏之曲 5308028 My Soul 30245064再次,四月是你的谎言 33785991 badApple 八音盒版</span></span><br><span class="line"> <span class="attr">autoPlay:</span> <span class="literal">false</span> <span class="comment"># 是否开启自动播放</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># aplayer 音乐插件,https://github.com/MoePlayer/hexo-tag-aplayer/blob/master/docs/README-zh_cn.md</span></span><br><span class="line"> <span class="comment"># 确保安装了 npm install --save hexo-tag-aplayer,并且在hexo的配置文件_config.yml文件中添加以下两行</span></span><br><span class="line"> <span class="comment"># aplayer:</span></span><br><span class="line"> <span class="comment"># meting: true</span></span><br><span class="line"> <span class="comment"># 如果想在文章中使用 在文章对应位置添加 以下代码即可</span></span><br><span class="line"> <span class="comment"># {% meting "60198" "netease" "playlist" "autoplay" "mutex:false" "listmaxheight:340px" "preload:none" "theme:#ad7a86" ... %}</span></span><br><span class="line"> <span class="attr">aplayer:</span> <span class="comment"># aplayer 音乐插件</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment"># 使用aplayer</span></span><br><span class="line"> <span class="attr">id:</span> <span class="string">'7786619105'</span> <span class="comment"># 必须值 歌曲 id / 播放列表 id / 相册 id / 搜索关键字</span></span><br><span class="line"> <span class="attr">server:</span> <span class="string">'tencent'</span> <span class="comment"># 必须值 音乐平台: netease, tencent, kugou, xiami, baidu</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">'playlist'</span> <span class="comment"># 必须值 song, playlist, album, search, artist</span></span><br><span class="line"> <span class="attr">fixed:</span> <span class="literal">true</span> <span class="comment"># false 开启固定模式 true 开启吸底模式</span></span><br><span class="line"> <span class="attr">loop:</span> <span class="string">none</span> <span class="comment"># 列表循环模式:all, one,none</span></span><br><span class="line"> <span class="attr">order:</span> <span class="string">random</span> <span class="comment"># 列表播放模式: list, random</span></span><br><span class="line"> <span class="attr">volume:</span> <span class="number">0.4</span> <span class="comment"># 播放器音量</span></span><br><span class="line"> <span class="attr">listfolded:</span> <span class="literal">true</span> <span class="comment"># 指定音乐播放列表是否折叠</span></span><br><span class="line"> <span class="attr">autoplay:</span> <span class="literal">false</span> <span class="comment"># 自动播放,移动端浏览器暂时不支持此功能</span></span><br><span class="line"> <span class="attr">mutex:</span> <span class="literal">true</span> <span class="comment"># 该选项开启时,如果同页面有其他 aplayer 播放,该播放器会暂停</span></span><br><span class="line"> <span class="attr">listmaxheight:</span> <span class="string">400px</span><span class="comment"># 播放列表的最大长度</span></span><br><span class="line"> <span class="attr">preload:</span> <span class="string">none</span> <span class="comment"># 音乐文件预载入模式,可选项: none, metadata, auto</span></span><br><span class="line"> <span class="attr">theme:</span> <span class="comment">#00b9f1 # 播放器风格色彩设置</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 页面点击小红心</span></span><br><span class="line"><span class="attr">clickLove:</span></span><br><span class="line"> <span class="comment"># (关闭请设置为false)</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># GitHub Ribbons(https://github.blog/2008-12-19-github-ribbons/)</span></span><br><span class="line"><span class="attr">github:</span></span><br><span class="line"> <span class="comment"># (关闭请设置为false)</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://github.com/JoeyBling/hexo-theme-yilia-plus</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 页脚 Litten(此配置项已弃用)</span></span><br><span class="line"><span class="comment"># 帮助我们让更多人可以更方便使用Hexo,请尽量不要修改此主题配置</span></span><br><span class="line"><span class="attr">pageFooter:</span></span><br><span class="line"> <span class="attr">litten:</span> <span class="string">GitHub:<a</span> <span class="string">href="https://github.com/JoeyBling/hexo-theme-yilia-plus"</span> <span class="string">target="_blank">hexo-theme-yilia-plus</a></span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 开启百度站长平台自动推送(https://ziyuan.baidu.com/linksubmit/index)</span></span><br><span class="line"><span class="attr">baidu_push:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 版权声明</span></span><br><span class="line"><span class="comment"># 版权声明type设定:0-关闭版权声明; 1-文章对应的md文件里有copyright: true属性,才有版权声明; 2-所有文章均有版权声明</span></span><br><span class="line"><span class="attr">copyright_type:</span> <span class="number">2</span></span><br><span class="line"><span class="comment"># 版权声明自定义文本(关闭请设置为false)</span></span><br><span class="line"><span class="attr">copyright_text:</span> </span><br><span class="line"></span><br><span class="line"><span class="comment"># 网站成立年份(默认为 2018,若填入年份小于当前年份,则显示为 2018-2019 类似的格式)</span></span><br><span class="line"><span class="attr">since:</span> <span class="number">2018</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Progress Bar | 页面加载进度条</span></span><br><span class="line"><span class="comment"># Demo: http://github.hubspot.com/pace/docs/welcome/</span></span><br><span class="line"><span class="comment"># type: barber-shop|big-counter|bounce|center-atom|center-circle|</span></span><br><span class="line"><span class="comment"># center-radar|center-simple|corner-indicator|flash|flat-top|</span></span><br><span class="line"><span class="comment"># loading-bar|mac-osx|minimal</span></span><br><span class="line"><span class="comment"># color: black|blue|green|orange|pink|purple|red|silver|white|yellow|</span></span><br><span class="line"><span class="attr">progressBar:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">'minimal'</span> <span class="comment"># Keep Quotes | 保留引号避免出错(某些type会导致样式重叠排版错误)</span></span><br><span class="line"> <span class="attr">color:</span> <span class="string">blue</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Apple Touch icon 苹果图标(关闭请设置为false)</span></span><br><span class="line"><span class="attr">apple_touch_icon:</span> <span class="string">'/apple-touch-icon-180x180.png'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Tab Title Change | 标签页标题切换</span></span><br><span class="line"><span class="attr">tab_title_change:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">left_tab_title:</span> <span class="string">'(つェ⊂) 我藏好了哦~ '</span></span><br><span class="line"> <span class="attr">return_tab_title:</span> <span class="string">'(*´∇`*) 被你发现啦~ '</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># https://github.com/willin/hexo-wordcount</span></span><br><span class="line"><span class="comment"># 是否开启字数统计(关闭请设置enable为false)</span></span><br><span class="line"><span class="comment"># 也可以单独在md文件里Front-matter设置`no_word_count: true`属性,来自定义关闭字数统计</span></span><br><span class="line"><span class="attr">word_count:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># 只在文章详情显示(不在首页显示)</span></span><br><span class="line"> <span class="attr">only_article_visit:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 文字输入特效</span></span><br><span class="line"><span class="comment"># https://github.com/disjukr/activate-power-mode</span></span><br><span class="line"><span class="attr">activate_power_mode:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># 使输入模式丰富多彩</span></span><br><span class="line"> <span class="attr">colorful:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># 是否开启摇动</span></span><br><span class="line"> <span class="attr">shake:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 飘雪特效</span></span><br><span class="line"><span class="comment"># https://github.com/MlgmXyysd/snow.js</span></span><br><span class="line"><span class="attr">snow:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">type:</span> <span class="number">1</span> <span class="comment"># 1 小雪花 2 大雪花</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># https://github.com/hustcc/canvas-nest.js</span></span><br><span class="line"><span class="comment"># 配置详见: https://github.com/hustcc/canvas-nest.js#configuration</span></span><br><span class="line"><span class="comment"># 动态线条效果,会向鼠标集中</span></span><br><span class="line"><span class="attr">canvas_nest:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">color:</span> <span class="string">'28,28,28'</span> <span class="comment"># 线条颜色, default: '0,0,0'; RGB values: (R,G,B).(<span class="doctag">note:</span> 使用 ',' 分开.)</span></span><br><span class="line"> <span class="attr">pointColor:</span> <span class="string">'26,1,57'</span> <span class="comment"># 点的颜色, default: '0,0,0'; RGB values: (R,G,B).(<span class="doctag">note:</span> 使用 ',' 分开.)</span></span><br><span class="line"> <span class="attr">opacity:</span> <span class="string">'0.5'</span> <span class="comment"># 线条不透明度 (0~1), default: 0.5. 1不透明</span></span><br><span class="line"> <span class="attr">count:</span> <span class="string">'99'</span> <span class="comment"># 线条数量, default: 99.</span></span><br><span class="line"> <span class="attr">zIndex:</span> <span class="string">'-1'</span> <span class="comment"># z-index 背景属性, default: -1.</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 看板娘动态模型插件</span></span><br><span class="line"><span class="comment">## https://github.com/JoeyBling/live2d-widget.js</span></span><br><span class="line"><span class="attr">live2d:</span></span><br><span class="line"> <span class="comment"># (关闭请设置为false)</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment"># 模型名称(取值请参考:https://github.com/JoeyBling/hexo-theme-yilia-plus/wiki/live2d%E6%A8%A1%E5%9E%8B%E5%8C%85%E5%B1%95%E7%A4%BA)</span></span><br><span class="line"> <span class="attr">model:</span> <span class="string">hibiki</span></span><br><span class="line"> <span class="attr">display:</span></span><br><span class="line"> <span class="attr">position:</span> <span class="string">right</span> <span class="comment"># 显示位置:left/right(default: 'right')</span></span><br><span class="line"> <span class="attr">width:</span> <span class="number">145</span> <span class="comment"># 模型的长度(default: 150)</span></span><br><span class="line"> <span class="attr">height:</span> <span class="number">315</span> <span class="comment"># 模型的高度(default: 300)</span></span><br><span class="line"> <span class="attr">hOffset:</span> <span class="number">50</span> <span class="comment"># 水平偏移(default: 0)</span></span><br><span class="line"> <span class="comment">#vOffset: -20 # 垂直偏移(default: -20)</span></span><br><span class="line"> <span class="attr">mobile:</span></span><br><span class="line"> <span class="attr">show:</span> <span class="literal">false</span> <span class="comment"># 是否在移动设备上显示(default: true)</span></span><br><span class="line"> <span class="attr">scale:</span> <span class="number">0.6</span> <span class="comment"># 移动设备上的缩放(default: 0.5)</span></span><br><span class="line"> <span class="attr">react:</span></span><br><span class="line"> <span class="attr">opacity:</span> <span class="number">0.8</span> <span class="comment"># 模型透明度(default: 0.7)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 样式定制 - 一般不需要修改,除非有很强的定制欲望…</span></span><br><span class="line"><span class="attr">style:</span></span><br><span class="line"> <span class="comment"># 头像上面的背景颜色</span></span><br><span class="line"> <span class="comment"># header: '#D3D1DC'</span></span><br><span class="line"> <span class="attr">header:</span> <span class="string">'#4d4d4d'</span></span><br><span class="line"> <span class="attr">gif:</span></span><br><span class="line"> <span class="comment"># 是否启用左侧边栏动态图效果</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment"># 自定义背景图路径(默认可以不设置,提供默认背景图)</span></span><br><span class="line"> <span class="comment"># path: /img/biubiubiu.gif</span></span><br><span class="line"> <span class="comment"># 右滑板块背景</span></span><br><span class="line"> <span class="attr">slider:</span> <span class="string">'linear-gradient(200deg,#a0cfe4,#e8c37e)'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># slider的设置</span></span><br><span class="line"><span class="attr">slider:</span></span><br><span class="line"> <span class="comment"># 是否默认展开tags板块</span></span><br><span class="line"> <span class="attr">showTags:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 智能菜单</span></span><br><span class="line"><span class="comment"># 如不需要,将该对应项置为false</span></span><br><span class="line"><span class="comment"># 比如</span></span><br><span class="line"><span class="comment">#smart_menu:</span></span><br><span class="line"><span class="comment"># friends: false</span></span><br><span class="line"><span class="attr">smart_menu:</span></span><br><span class="line"> <span class="attr">innerArchive:</span> <span class="string">'所有文章'</span></span><br><span class="line"> <span class="attr">friends:</span> <span class="string">'友链'</span></span><br><span class="line"> <span class="attr">aboutme:</span> <span class="string">'关于我'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 友情链接</span></span><br><span class="line"><span class="attr">friends:</span></span><br><span class="line"> <span class="string">技术笔记:</span> <span class="comment">#网站名称</span></span><br><span class="line"> <span class="comment">#网站地址</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://zhousiwei.gitee.io/ibooks/</span></span><br><span class="line"> <span class="comment">#网站图片(可忽略不写)</span></span><br><span class="line"> <span class="attr">img:</span> <span class="string">https://zhousiwei.gitee.io/ibooks/favicon.ico</span></span><br><span class="line"> <span class="comment">#网站简介(可忽略不写)</span></span><br><span class="line"> <span class="attr">description:</span> <span class="string">记录工作和学习过程中的笔记:Java、前端开发、Hexo博客、聚合支付、Linux笔记、ElasticSearch、ELK日志分析</span></span><br><span class="line"> <span class="attr">GitHub:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://github.com/JoeyBling</span></span><br><span class="line"> <span class="string">码云:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://gitee.com/zhousiwei</span></span><br><span class="line"> <span class="string">简书:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://www.jianshu.com/u/02cbf31a043a</span></span><br><span class="line"> <span class="attr">CSDN:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://blog.csdn.net/qq_30930805</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 关于我</span></span><br><span class="line"><span class="attr">aboutme:</span> <span class="string">主要涉及技术:<br>Java后端开发、聚合支付、<br>公众号开发、开源爱好者、Linux<br><br>联系QQ:2434387555<br><br>很惭愧<br><br>只做了一点微小的工作<br>谢谢大</span></span><br></pre></td></tr></table></figure><h3 id="2-自己进行配置"><a href="#2-自己进行配置" class="headerlink" title="2.自己进行配置"></a>2.自己进行配置</h3><ol><li>修改<code>yilia-plus/layout/_partial/left-col.ejs</code>文件,将原来网易云音乐所在的代码用替换为以下代码</li></ol><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><% if (theme.music){ %></span><br><span class="line"> <%# "打开音乐插件" %></span><br><span class="line"> <% if (theme.music.text || theme.music.text==null){ %></span><br><span class="line"> <% var musicText=( theme.music.text==null || theme.music.text==true ) ? "这似乎是首纯音乐,请尽情的欣赏它吧!" : theme.music.text; %></span><br><span class="line"> <p style="font-size: 12px;"><%-musicText%> <p></span><br><span class="line"> <% } %></span><br><span class="line"></span><br><span class="line"> <% if (theme.music.cloudMusic.enable){ %></span><br><span class="line"> <%# "网易云音乐插件" %></span><br><span class="line"> <%# "bottom:120px; left:auto;position:absolute; width:85%" %></span><br><span class="line"> <% var defaultHeight=theme.music.cloudMusic.type==1 ? '32' : '66' ; %></span><br><span class="line"> <% var defaultIframeHeight=theme.music.cloudMusic.type==1 ? '52' : '86' ; %></span><br><span class="line"> <div><iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="240"height="<%=defaultIframeHeight%>"</span><br><span class="line"> src="//music.163.com/outchain/player?type=2&id=<%=theme.music.cloudMusic.id||1334445174%>&auto=<%=theme.music.cloudMusic.autoPlay?1:0%>&height=<%=defaultHeight%>"></span><br><span class="line"> </iframe></span><br><span class="line"> </div></span><br><span class="line"> <% } %></span><br><span class="line"></span><br><span class="line"> <% if (theme.music.aplayer.enable){ %></span><br><span class="line"> <%# "aplayer音乐插件" %></span><br><span class="line"> <div id="aplayer-hjnObCgk" class="aplayer aplayer-tag-marker meting-tag-marker" data-id="<%=theme.music.aplayer.id%>"</span><br><span class="line"> data-server="<%=theme.music.aplayer.server%>" data-type="<%=theme.music.aplayer.type%>" data-loop="<%=theme.music.aplayer.loop%>"</span><br><span class="line"> data-order="<%=theme.music.aplayer.order%>" data-lrctype="0" data-listfolded="<%=theme.music.aplayer.listfolded%>" </span><br><span class="line"> data-fixed="<%=theme.music.aplayer.fixed%>" data-autoplay="<%=theme.music.aplayer.autoplay%>" </span><br><span class="line"> data-volume="<%=theme.music.aplayer.volume%>" data-mutex="<%=theme.music.aplayer.mutex%>" </span><br><span class="line"> data-listmaxheight="<%=theme.music.aplayer.listmaxheight%>" data-preload="<%=theme.music.aplayer.preload%>" </span><br><span class="line"> data-theme="<%=theme.music.aplayer.theme%>"></span><br><span class="line"> </div></span><br><span class="line"> <% } %></span><br><span class="line"><% } %></span><br></pre></td></tr></table></figure><ol start="2"><li>修改<code>yilia-plus/_config.yml</code>文件</li></ol><p>将原来网易云音乐的配置项改为以下内容。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 音乐插件</span></span><br><span class="line"><span class="attr">music:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment"># 是否使用音乐插件</span></span><br><span class="line"> <span class="attr">text:</span> <span class="string">''</span> <span class="comment"># 提示文本(关闭请设置为false)</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">cloudMusic:</span> <span class="comment"># 网易云音乐插件</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span> <span class="comment"># 使用网易云</span></span><br><span class="line"> <span class="comment"># 播放器尺寸类型(1:长尺寸、2:短尺寸)</span></span><br><span class="line"> <span class="attr">type:</span> <span class="number">2</span></span><br><span class="line"> <span class="attr">id:</span> <span class="number">30245064</span> <span class="comment"># 网易云分享的音乐ID(更换音乐请更改此配置项) 572578819 奏之曲 5308028 My Soul 30245064再次,四月是你的谎言 33785991 badApple 八音盒版</span></span><br><span class="line"> <span class="attr">autoPlay:</span> <span class="literal">false</span> <span class="comment"># 是否开启自动播放</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># aplayer 音乐插件,https://github.com/MoePlayer/hexo-tag-aplayer/blob/master/docs/README-zh_cn.md</span></span><br><span class="line"> <span class="comment"># 确保安装了 npm install --save hexo-tag-aplayer,并且在hexo的配置文件_config.yml文件中添加以下两行</span></span><br><span class="line"> <span class="comment"># aplayer:</span></span><br><span class="line"> <span class="comment"># meting: true</span></span><br><span class="line"> <span class="comment"># 如果想在文章中使用 在文章对应位置添加 以下代码即可</span></span><br><span class="line"> <span class="comment"># {% meting "60198" "netease" "playlist" "autoplay" "mutex:false" "listmaxheight:340px" "preload:none" "theme:#ad7a86" ... %}</span></span><br><span class="line"> <span class="attr">aplayer:</span> <span class="comment"># aplayer 音乐插件</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment"># 使用aplayer</span></span><br><span class="line"> <span class="attr">id:</span> <span class="string">'7786619105'</span> <span class="comment"># 必须值 歌曲 id / 播放列表 id / 相册 id / 搜索关键字</span></span><br><span class="line"> <span class="attr">server:</span> <span class="string">'tencent'</span> <span class="comment"># 必须值 音乐平台: netease, tencent, kugou, xiami, baidu</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">'playlist'</span> <span class="comment"># 必须值 song, playlist, album, search, artist</span></span><br><span class="line"> <span class="attr">fixed:</span> <span class="literal">true</span> <span class="comment"># false 开启固定模式 true 开启吸底模式</span></span><br><span class="line"> <span class="attr">loop:</span> <span class="string">none</span> <span class="comment"># 列表循环模式:all, one,none</span></span><br><span class="line"> <span class="attr">order:</span> <span class="string">random</span> <span class="comment"># 列表播放模式: list, random</span></span><br><span class="line"> <span class="attr">volume:</span> <span class="number">0.4</span> <span class="comment"># 播放器音量</span></span><br><span class="line"> <span class="attr">listfolded:</span> <span class="literal">true</span> <span class="comment"># 指定音乐播放列表是否折叠</span></span><br><span class="line"> <span class="attr">autoplay:</span> <span class="literal">false</span> <span class="comment"># 自动播放,移动端浏览器暂时不支持此功能</span></span><br><span class="line"> <span class="attr">mutex:</span> <span class="literal">true</span> <span class="comment"># 该选项开启时,如果同页面有其他 aplayer 播放,该播放器会暂停</span></span><br><span class="line"> <span class="attr">listmaxheight:</span> <span class="string">400px</span><span class="comment"># 播放列表的最大长度</span></span><br><span class="line"> <span class="attr">preload:</span> <span class="string">none</span> <span class="comment"># 音乐文件预载入模式,可选项: none, metadata, auto</span></span><br><span class="line"> <span class="attr">theme:</span> <span class="comment">#00b9f1 # 播放器风格色彩设置</span></span><br></pre></td></tr></table></figure><h2 id="三、一些问题"><a href="#三、一些问题" class="headerlink" title="三、一些问题"></a>三、一些问题</h2><p>在PC端的音乐软件需要先将歌单分享到QQ空间或者微博,然后用浏览器打开生成的歌单链接才能获取到歌单的<code>id</code>,网页URL最后的那一串数字就是歌单id。</p>]]></content>
<summary type="html">
hexo博客yilia-puls主题添加aplayer音乐插件。
</summary>
<category term="软件使用" scheme="https://proudrabbit.gitee.io/tags/%E8%BD%AF%E4%BB%B6%E4%BD%BF%E7%94%A8/"/>
<category term="hexo" scheme="https://proudrabbit.gitee.io/tags/hexo/"/>
<category term="aplayer" scheme="https://proudrabbit.gitee.io/tags/aplayer/"/>
</entry>
<entry>
<title>hexo博客yilia-plus主题更换Beaudar评论插件</title>
<link href="https://proudrabbit.gitee.io/hexo%E5%8D%9A%E5%AE%A2yilia-plus%E4%B8%BB%E9%A2%98%E6%9B%B4%E6%8D%A2Beaudar%E8%AF%84%E8%AE%BA%E6%8F%92%E4%BB%B6.html"/>
<id>https://proudrabbit.gitee.io/hexo%E5%8D%9A%E5%AE%A2yilia-plus%E4%B8%BB%E9%A2%98%E6%9B%B4%E6%8D%A2Beaudar%E8%AF%84%E8%AE%BA%E6%8F%92%E4%BB%B6.html</id>
<published>2021-08-23T05:30:03.000Z</published>
<updated>2021-08-25T14:11:38.171Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>[toc]</p><h1 id="hexo博客yilia-plus主题更换Beaudar评论插件"><a href="#hexo博客yilia-plus主题更换Beaudar评论插件" class="headerlink" title="hexo博客yilia-plus主题更换Beaudar评论插件"></a>hexo博客yilia-plus主题更换Beaudar评论插件</h1><p>因为<code>yilia-plus</code>自带的<code>giteement</code>和<code>gitment</code>评论插件都不能用了,所以更换评论插件为<a href="https://beaudar.lipk.org/" target="_blank" rel="noopener">Beaudar - 表达</a>。可以在我的博客查看效果<a href="https://proudrabbit.gitee.io/">兔子的个人博客 - Hexo Blog (gitee.io)</a>。<code>Beaudar</code>名称源于粤语“表达”的发音,是 <a href="http://utteranc.es/" target="_blank" rel="noopener">Utterances</a> 的中文版本,在此感谢<strong>执手对影成双</strong>大佬。关于各评论插件的优缺点可以看这篇博客<a href="https://www.yunyoujun.cn/share/third-party-comment-system/" target="_blank" rel="noopener">第三方评论系统之我见 | 云游君的小站 (yunyoujun.cn)</a>,这里不再赘述。</p><a id="more"></a><h2 id="一、安装Beaudar-app。"><a href="#一、安装Beaudar-app。" class="headerlink" title="一、安装Beaudar app。"></a>一、安装Beaudar app。</h2><p>首先需要给仓库安装<a href="https://github.com/apps/beaudar" target="_blank" rel="noopener">GitHub Apps - Beaudar</a>。我这里安装过了,所以显示的是配置,安装时,选择安装到你要保存评论的仓库。</p><p><img src="https://i.loli.net/2021/08/23/fO4RCc1YZMWljwX.png" alt="Beaudarapp安装界面"></p><p>安装完成后需要对其进行配置,在这里<a href="https://beaudar.lipk.org/" target="_blank" rel="noopener">Beaudar - 表达 (lipk.org)</a>对其进行配置。配置完成后,会在网页最下面生成代码,代码如下。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://beaudar.lipk.org/client.js"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">repo</span>=<span class="string">"在此处输入仓库"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">issue-term</span>=<span class="string">"pathname"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">theme</span>=<span class="string">"github-light"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">async</span>></span></span><br><span class="line"><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><h2 id="二、添加到主题中"><a href="#二、添加到主题中" class="headerlink" title="二、添加到主题中"></a>二、添加到主题中</h2><p>经过第一步的操作,已经拿到了自己的代码,接下来只要添加到自己的主题中就行,添加方式分两种,首先说第一种。</p><h3 id="1-直接拉取仓库到本地。"><a href="#1-直接拉取仓库到本地。" class="headerlink" title="1.直接拉取仓库到本地。"></a>1.直接拉取仓库到本地。</h3><p>我已经将代码修改后向<code>yilia-plus</code>的原作者<a href="https://github.com/JoeyBling/hexo-theme-yilia-plus" target="_blank" rel="noopener">JoeyBling/hexo-theme-yilia-plus: 一个简洁优雅的hexo主题</a>提出了PR请求,等待同意后,拉取更新即可,如果不想等,拉取我从原作者fork的仓库下来也行<a href="https://github.com/ProudRabbit/hexo-theme-yilia-plus" target="_blank" rel="noopener">ProudRabbit/hexo-theme-yilia-plus</a>,拉取到你的博客主题下之后进行配置即可,最好先备份下你原来的配置,防止配置丢失。在主题的配置文件<code>_config.yml</code>的<code>136</code>行,将第一步得到的配置信息填写进去即可。</p><blockquote><p>我的hexo版本</p><p>hexo: 4.2.1<br>hexo-cli: 3.1.0<br>os: Windows_NT 10.0.19042 win32 x64<br>node: 12.18.2<br>v8: 7.8.279.23-node.39<br>uv: 1.38.0<br>zlib: 1.2.11<br>brotli: 1.0.7<br>ares: 1.16.0<br>modules: 72<br>nghttp2: 1.41.0<br>napi: 6<br>llhttp: 2.0.4<br>http_parser: 2.9.3<br>openssl: 1.1.1g<br>cldr: 37.0<br>icu: 67.1<br>tz: 2019c<br>unicode: 13.0</p></blockquote><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Header-菜单</span></span><br><span class="line"><span class="attr">menu:</span></span><br><span class="line"> <span class="string">主页:</span> <span class="string">/</span></span><br><span class="line"> <span class="string">技术笔记:</span> <span class="string">https://zhousiwei.gitee.io/ibooks/</span></span><br><span class="line"> <span class="string">随笔:</span> <span class="string">/tags/随笔/</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># subNav-子导航</span></span><br><span class="line"><span class="attr">subNav:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">github:</span> <span class="string">"#"</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">github:</span> <span class="string">"#"</span> <span class="comment"># (支持设置多个)</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">gitee:</span> <span class="string">"#"</span> <span class="comment"># 码云</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">jianshu:</span> <span class="string">"#"</span> <span class="comment">#简书</span></span><br><span class="line"> <span class="comment"># - cnblog: "#"</span></span><br><span class="line"> <span class="comment"># - blog: "#"</span></span><br><span class="line"> <span class="comment"># - csdn: "#"</span></span><br><span class="line"> <span class="comment"># - rss: "#"</span></span><br><span class="line"> <span class="comment"># - zhihu: "#"</span></span><br><span class="line"> <span class="comment"># - qq: "img/2434387555.jpg"</span></span><br><span class="line"> <span class="comment"># - weixin: "img/weixin_.png"</span></span><br><span class="line"> <span class="comment"># - weibo: "#"</span></span><br><span class="line"> <span class="comment"># - douban: "#"</span></span><br><span class="line"> <span class="comment"># - segmentfault: "#"</span></span><br><span class="line"> <span class="comment"># - bilibili: "#"</span></span><br><span class="line"> <span class="comment"># - acfun: "#"</span></span><br><span class="line"> <span class="comment"># - mail: "mailto:zhousiwei0911@qq.com"</span></span><br><span class="line"> <span class="comment"># - facebook: "#"</span></span><br><span class="line"> <span class="comment"># - google: "#"</span></span><br><span class="line"> <span class="comment"># - twitter: "#"</span></span><br><span class="line"> <span class="comment"># - linkedin: "#"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 悬停预览图片效果</span></span><br><span class="line"><span class="attr">hover_effect:</span></span><br><span class="line"> <span class="comment">## `global` 0: Set separately, 1: Enable global 2: Close global</span></span><br><span class="line"> <span class="comment">## `global` 0: 分开设置, 1: 全局启用, 2: 全局关闭</span></span><br><span class="line"> <span class="attr">global:</span> <span class="number">2</span></span><br><span class="line"> <span class="comment"># SubNav-导航</span></span><br><span class="line"> <span class="attr">subNav:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># RSS订阅(关于如何配置启用:https://www.jianshu.com/p/2aaac7a19736)</span></span><br><span class="line"><span class="attr">rss:</span> <span class="string">/atom.xml</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 是否需要修改 root 路径</span></span><br><span class="line"><span class="comment"># 如果您的网站存放在子目录中,例如 http://yoursite.com/blog,</span></span><br><span class="line"><span class="comment"># 请将您的 url 设为 http://yoursite.com/blog 并把 / 设为 /blog/。</span></span><br><span class="line"><span class="comment"># 新版本已弃用,请在博客根目录文件进行配置</span></span><br><span class="line"><span class="comment"># root: /</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Content</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 文章太长,截断按钮文字(在需要截断的行增加此标记:<!--more-->)</span></span><br><span class="line"><span class="attr">excerpt_link:</span> <span class="string">more</span></span><br><span class="line"><span class="comment"># 文章卡片右下角常驻链接,不需要请设置为false</span></span><br><span class="line"><span class="attr">show_all_link:</span> <span class="string">'展开全文'</span></span><br><span class="line"><span class="comment"># 数学公式</span></span><br><span class="line"><span class="attr">mathjax:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Open link in a new tab | 是否在新窗口打开链接</span></span><br><span class="line"><span class="attr">open_in_new:</span></span><br><span class="line"> <span class="attr">article:</span> <span class="literal">true</span> <span class="comment"># 文章链接</span></span><br><span class="line"> <span class="attr">menu:</span> <span class="literal">true</span> <span class="comment"># 导航菜单</span></span><br><span class="line"> <span class="attr">subNav:</span> <span class="literal">true</span> <span class="comment"># 子菜单</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 打赏</span></span><br><span class="line"><span class="comment"># 打赏type设定:0-关闭打赏; 1-文章对应的md文件里有reward:true属性,才有打赏; 2-所有文章均有打赏</span></span><br><span class="line"><span class="attr">reward_type:</span> <span class="number">2</span></span><br><span class="line"><span class="comment"># 打赏wording</span></span><br><span class="line"><span class="attr">reward_wording:</span> <span class="string">'谢谢你请我吃糖果'</span></span><br><span class="line"><span class="comment"># 支付宝二维码图片地址,跟你设置头像的方式一样。比如:/assets/img/alipay.jpg</span></span><br><span class="line"><span class="attr">alipay:</span> <span class="string">/img/alipay.jpg</span></span><br><span class="line"><span class="comment"># 微信二维码图片地址</span></span><br><span class="line"><span class="attr">weixin:</span> <span class="string">/img/weixin.png</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 目录</span></span><br><span class="line"><span class="comment"># 目录设定:0-不显示目录; 1-文章对应的md文件里有toc:true属性,才有目录; 2-所有文章均显示目录</span></span><br><span class="line"><span class="attr">toc:</span> <span class="number">1</span></span><br><span class="line"><span class="comment"># 根据自己的习惯来设置,如果你的目录标题习惯有标号,置为true即可隐藏hexo重复的序号;否则置为false</span></span><br><span class="line"><span class="attr">toc_hide_index:</span> <span class="literal">true</span></span><br><span class="line"><span class="comment"># 目录为空时的提示</span></span><br><span class="line"><span class="attr">toc_empty_wording:</span> <span class="string">'目录,不存在的…'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 是否有快速回到顶部的按钮</span></span><br><span class="line"><span class="attr">top:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Miscellaneous</span></span><br><span class="line"><span class="comment"># 百度统计</span></span><br><span class="line"><span class="attr">baidu_analytics:</span> <span class="string">''</span></span><br><span class="line"><span class="attr">google_analytics:</span> <span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 网站图标</span></span><br><span class="line"><span class="attr">favicon:</span> <span class="string">/favicon.ico</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 你的头像url</span></span><br><span class="line"><span class="attr">avatar:</span> <span class="string">/img/head.jpg</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 是否开启分享</span></span><br><span class="line"><span class="attr">share_jia:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 评论:1、畅言;2、Disqus;3、Gitment;4、Giteement 5、beaudar-表达</span></span><br><span class="line"><span class="comment"># 不需要使用某项,直接设置值为false,或注释掉</span></span><br><span class="line"><span class="comment"># 具体请参考wiki:https://github.com/JoeyBling/hexo-theme-yilia-plus/wiki</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 1、畅言</span></span><br><span class="line"><span class="attr">changyan_appid:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">changyan_conf:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2、Disqus 在hexo根目录的config里也有disqus_shortname字段,优先使用yilia-plus的</span></span><br><span class="line"><span class="attr">disqus:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3、Gitment----基于GitHub的评论系统(关闭请设置gitment_owner为false)</span></span><br><span class="line"><span class="comment"># 关于如何集成:https://www.jianshu.com/p/ac7658cc912f</span></span><br><span class="line"><span class="attr">gitment_owner:</span> <span class="literal">false</span> <span class="comment">#你的 GitHub ID</span></span><br><span class="line"><span class="comment"># 是否使用官方js(false可以提升访问速度,本地修改过一部分的js,官方js可能会出现服务器不稳定,不太建议使用)</span></span><br><span class="line"><span class="attr">gitment_remote:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">gitment_repo:</span> <span class="string">''</span> <span class="comment">#存储评论的 repo name(需要在Github创建)</span></span><br><span class="line"><span class="attr">gitment_oauth:</span></span><br><span class="line"> <span class="attr">client_id:</span> <span class="string">''</span> <span class="comment">#client ID</span></span><br><span class="line"> <span class="attr">client_secret:</span> <span class="string">''</span> <span class="comment">#client secret</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 4、Giteement----【国内用户建议使用这个,相对比较快】</span></span><br><span class="line"><span class="comment"># 关于如何集成:https://www.jianshu.com/p/f5c4633524c7</span></span><br><span class="line"><span class="comment"># 基于码云的评论系统(https://gitee.com/zhousiwei/giteement)</span></span><br><span class="line"><span class="attr">giteement:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span> <span class="comment"># 是否启用码云评论系统</span></span><br><span class="line"> <span class="comment"># 是否使用官方js(false可以提升访问速度)</span></span><br><span class="line"> <span class="attr">remote:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">redirect_uri:</span> <span class="string">''</span> <span class="comment"># 应用回调地址(请和配置的第三方应用保持一致)</span></span><br><span class="line"> <span class="comment"># 不能更改(网上开源项目`https://github.com/Rob--W/cors-anywhere`作者提供的专门用来跨域服务器的配置)</span></span><br><span class="line"> <span class="attr">oauth_uri:</span> <span class="string">https://cors-anywhere.herokuapp.com/https://gitee.com/oauth/token</span></span><br><span class="line"> <span class="attr">giteeID:</span> <span class="string">''</span> <span class="comment"># 你的码云账号英文名</span></span><br><span class="line"> <span class="comment"># 存储评论的 repo name(需要在码云仓库创建公开仓库)</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="string">''</span></span><br><span class="line"> <span class="attr">gitment_oauth:</span></span><br><span class="line"> <span class="attr">client_id:</span> <span class="string">''</span> <span class="comment">#client ID</span></span><br><span class="line"> <span class="attr">client_secret:</span> <span class="string">''</span> <span class="comment">#client secret</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 5、beaudar-表达 评论,由于giteement和gitment都不能使用了,所以使用beaudar</span></span><br><span class="line"><span class="comment"># 插件配置地址 https://beaudar.lipk.org/</span></span><br><span class="line"><span class="attr">beaudar:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="string">''</span> <span class="comment"># 仓库名称 注意直接从GitHub上复制 / 左右可能有空格,注意删除</span></span><br><span class="line"> <span class="attr">issue_term:</span> <span class="string">'pathname'</span> <span class="comment"># beaudar 生成的博客文章 ↔️ Issue 映射关系</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">'comment'</span> <span class="comment"># issue 标签,选择将分配给 Beaudar 创建的问题的标签</span></span><br><span class="line"> <span class="attr">theme:</span> <span class="string">'github-light'</span> <span class="comment"># beaudar 主题</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 访问量统计功能(不蒜子)</span></span><br><span class="line"><span class="attr">busuanzi:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">site_visit:</span> <span class="literal">true</span> <span class="comment"># 站点访问量显示</span></span><br><span class="line"> <span class="attr">article_visit:</span> <span class="literal">true</span> <span class="comment"># 文章访问量显示</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 音乐插件</span></span><br><span class="line"><span class="attr">music:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment"># 是否使用音乐插件</span></span><br><span class="line"> <span class="attr">text:</span> <span class="string">''</span> <span class="comment"># 提示文本(关闭请设置为false)</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">cloudMusic:</span> <span class="comment"># 网易云音乐插件</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span> <span class="comment"># 使用网易云</span></span><br><span class="line"> <span class="comment"># 播放器尺寸类型(1:长尺寸、2:短尺寸)</span></span><br><span class="line"> <span class="attr">type:</span> <span class="number">2</span></span><br><span class="line"> <span class="attr">id:</span> <span class="number">30245064</span> <span class="comment"># 网易云分享的音乐ID(更换音乐请更改此配置项) 572578819 奏之曲 5308028 My Soul 30245064再次,四月是你的谎言 33785991 badApple 八音盒版</span></span><br><span class="line"> <span class="attr">autoPlay:</span> <span class="literal">false</span> <span class="comment"># 是否开启自动播放</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># aplayer 音乐插件,https://github.com/MoePlayer/hexo-tag-aplayer/blob/master/docs/README-zh_cn.md</span></span><br><span class="line"> <span class="comment"># 确保安装了 npm install --save hexo-tag-aplayer,并且在hexo的配置文件_config.yml文件中添加以下两行</span></span><br><span class="line"> <span class="comment"># aplayer:</span></span><br><span class="line"> <span class="comment"># meting: true</span></span><br><span class="line"> <span class="comment"># 如果想在文章中使用 在文章对应位置添加 以下代码即可</span></span><br><span class="line"> <span class="comment"># {% meting "60198" "netease" "playlist" "autoplay" "mutex:false" "listmaxheight:340px" "preload:none" "theme:#ad7a86" ... %}</span></span><br><span class="line"> <span class="attr">aplayer:</span> <span class="comment"># aplayer 音乐插件</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment"># 使用aplayer</span></span><br><span class="line"> <span class="attr">id:</span> <span class="string">'7786619105'</span> <span class="comment"># 必须值 歌曲 id / 播放列表 id / 相册 id / 搜索关键字</span></span><br><span class="line"> <span class="attr">server:</span> <span class="string">'tencent'</span> <span class="comment"># 必须值 音乐平台: netease, tencent, kugou, xiami, baidu</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">'playlist'</span> <span class="comment"># 必须值 song, playlist, album, search, artist</span></span><br><span class="line"> <span class="attr">fixed:</span> <span class="literal">true</span> <span class="comment"># false 开启固定模式 true 开启吸底模式</span></span><br><span class="line"> <span class="attr">loop:</span> <span class="string">none</span> <span class="comment"># 列表循环模式:all, one,none</span></span><br><span class="line"> <span class="attr">order:</span> <span class="string">random</span> <span class="comment"># 列表播放模式: list, random</span></span><br><span class="line"> <span class="attr">volume:</span> <span class="number">0.4</span> <span class="comment"># 播放器音量</span></span><br><span class="line"> <span class="attr">listfolded:</span> <span class="literal">true</span> <span class="comment"># 指定音乐播放列表是否折叠</span></span><br><span class="line"> <span class="attr">autoplay:</span> <span class="literal">false</span> <span class="comment"># 自动播放,移动端浏览器暂时不支持此功能</span></span><br><span class="line"> <span class="attr">mutex:</span> <span class="literal">true</span> <span class="comment"># 该选项开启时,如果同页面有其他 aplayer 播放,该播放器会暂停</span></span><br><span class="line"> <span class="attr">listmaxheight:</span> <span class="string">400px</span><span class="comment"># 播放列表的最大长度</span></span><br><span class="line"> <span class="attr">preload:</span> <span class="string">none</span> <span class="comment"># 音乐文件预载入模式,可选项: none, metadata, auto</span></span><br><span class="line"> <span class="attr">theme:</span> <span class="comment">#00b9f1 # 播放器风格色彩设置</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 页面点击小红心</span></span><br><span class="line"><span class="attr">clickLove:</span></span><br><span class="line"> <span class="comment"># (关闭请设置为false)</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># GitHub Ribbons(https://github.blog/2008-12-19-github-ribbons/)</span></span><br><span class="line"><span class="attr">github:</span></span><br><span class="line"> <span class="comment"># (关闭请设置为false)</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://github.com/JoeyBling/hexo-theme-yilia-plus</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 页脚 Litten(此配置项已弃用)</span></span><br><span class="line"><span class="comment"># 帮助我们让更多人可以更方便使用Hexo,请尽量不要修改此主题配置</span></span><br><span class="line"><span class="attr">pageFooter:</span></span><br><span class="line"> <span class="attr">litten:</span> <span class="string">GitHub:<a</span> <span class="string">href="https://github.com/JoeyBling/hexo-theme-yilia-plus"</span> <span class="string">target="_blank">hexo-theme-yilia-plus</a></span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 开启百度站长平台自动推送(https://ziyuan.baidu.com/linksubmit/index)</span></span><br><span class="line"><span class="attr">baidu_push:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 版权声明</span></span><br><span class="line"><span class="comment"># 版权声明type设定:0-关闭版权声明; 1-文章对应的md文件里有copyright: true属性,才有版权声明; 2-所有文章均有版权声明</span></span><br><span class="line"><span class="attr">copyright_type:</span> <span class="number">2</span></span><br><span class="line"><span class="comment"># 版权声明自定义文本(关闭请设置为false)</span></span><br><span class="line"><span class="attr">copyright_text:</span> </span><br><span class="line"></span><br><span class="line"><span class="comment"># 网站成立年份(默认为 2018,若填入年份小于当前年份,则显示为 2018-2019 类似的格式)</span></span><br><span class="line"><span class="attr">since:</span> <span class="number">2018</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Progress Bar | 页面加载进度条</span></span><br><span class="line"><span class="comment"># Demo: http://github.hubspot.com/pace/docs/welcome/</span></span><br><span class="line"><span class="comment"># type: barber-shop|big-counter|bounce|center-atom|center-circle|</span></span><br><span class="line"><span class="comment"># center-radar|center-simple|corner-indicator|flash|flat-top|</span></span><br><span class="line"><span class="comment"># loading-bar|mac-osx|minimal</span></span><br><span class="line"><span class="comment"># color: black|blue|green|orange|pink|purple|red|silver|white|yellow|</span></span><br><span class="line"><span class="attr">progressBar:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">'minimal'</span> <span class="comment"># Keep Quotes | 保留引号避免出错(某些type会导致样式重叠排版错误)</span></span><br><span class="line"> <span class="attr">color:</span> <span class="string">blue</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Apple Touch icon 苹果图标(关闭请设置为false)</span></span><br><span class="line"><span class="attr">apple_touch_icon:</span> <span class="string">'/apple-touch-icon-180x180.png'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Tab Title Change | 标签页标题切换</span></span><br><span class="line"><span class="attr">tab_title_change:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">left_tab_title:</span> <span class="string">'(つェ⊂) 我藏好了哦~ '</span></span><br><span class="line"> <span class="attr">return_tab_title:</span> <span class="string">'(*´∇`*) 被你发现啦~ '</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># https://github.com/willin/hexo-wordcount</span></span><br><span class="line"><span class="comment"># 是否开启字数统计(关闭请设置enable为false)</span></span><br><span class="line"><span class="comment"># 也可以单独在md文件里Front-matter设置`no_word_count: true`属性,来自定义关闭字数统计</span></span><br><span class="line"><span class="attr">word_count:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># 只在文章详情显示(不在首页显示)</span></span><br><span class="line"> <span class="attr">only_article_visit:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 文字输入特效</span></span><br><span class="line"><span class="comment"># https://github.com/disjukr/activate-power-mode</span></span><br><span class="line"><span class="attr">activate_power_mode:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># 使输入模式丰富多彩</span></span><br><span class="line"> <span class="attr">colorful:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># 是否开启摇动</span></span><br><span class="line"> <span class="attr">shake:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 飘雪特效</span></span><br><span class="line"><span class="comment"># https://github.com/MlgmXyysd/snow.js</span></span><br><span class="line"><span class="attr">snow:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">type:</span> <span class="number">1</span> <span class="comment"># 1 小雪花 2 大雪花</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># https://github.com/hustcc/canvas-nest.js</span></span><br><span class="line"><span class="comment"># 配置详见: https://github.com/hustcc/canvas-nest.js#configuration</span></span><br><span class="line"><span class="comment"># 动态线条效果,会向鼠标集中</span></span><br><span class="line"><span class="attr">canvas_nest:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">color:</span> <span class="string">'28,28,28'</span> <span class="comment"># 线条颜色, default: '0,0,0'; RGB values: (R,G,B).(<span class="doctag">note:</span> 使用 ',' 分开.)</span></span><br><span class="line"> <span class="attr">pointColor:</span> <span class="string">'26,1,57'</span> <span class="comment"># 点的颜色, default: '0,0,0'; RGB values: (R,G,B).(<span class="doctag">note:</span> 使用 ',' 分开.)</span></span><br><span class="line"> <span class="attr">opacity:</span> <span class="string">'0.5'</span> <span class="comment"># 线条不透明度 (0~1), default: 0.5. 1不透明</span></span><br><span class="line"> <span class="attr">count:</span> <span class="string">'99'</span> <span class="comment"># 线条数量, default: 99.</span></span><br><span class="line"> <span class="attr">zIndex:</span> <span class="string">'-1'</span> <span class="comment"># z-index 背景属性, default: -1.</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 看板娘动态模型插件</span></span><br><span class="line"><span class="comment">## https://github.com/JoeyBling/live2d-widget.js</span></span><br><span class="line"><span class="attr">live2d:</span></span><br><span class="line"> <span class="comment"># (关闭请设置为false)</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment"># 模型名称(取值请参考:https://github.com/JoeyBling/hexo-theme-yilia-plus/wiki/live2d%E6%A8%A1%E5%9E%8B%E5%8C%85%E5%B1%95%E7%A4%BA)</span></span><br><span class="line"> <span class="attr">model:</span> <span class="string">hibiki</span></span><br><span class="line"> <span class="attr">display:</span></span><br><span class="line"> <span class="attr">position:</span> <span class="string">right</span> <span class="comment"># 显示位置:left/right(default: 'right')</span></span><br><span class="line"> <span class="attr">width:</span> <span class="number">145</span> <span class="comment"># 模型的长度(default: 150)</span></span><br><span class="line"> <span class="attr">height:</span> <span class="number">315</span> <span class="comment"># 模型的高度(default: 300)</span></span><br><span class="line"> <span class="attr">hOffset:</span> <span class="number">50</span> <span class="comment"># 水平偏移(default: 0)</span></span><br><span class="line"> <span class="comment">#vOffset: -20 # 垂直偏移(default: -20)</span></span><br><span class="line"> <span class="attr">mobile:</span></span><br><span class="line"> <span class="attr">show:</span> <span class="literal">false</span> <span class="comment"># 是否在移动设备上显示(default: true)</span></span><br><span class="line"> <span class="attr">scale:</span> <span class="number">0.6</span> <span class="comment"># 移动设备上的缩放(default: 0.5)</span></span><br><span class="line"> <span class="attr">react:</span></span><br><span class="line"> <span class="attr">opacity:</span> <span class="number">0.8</span> <span class="comment"># 模型透明度(default: 0.7)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 样式定制 - 一般不需要修改,除非有很强的定制欲望…</span></span><br><span class="line"><span class="attr">style:</span></span><br><span class="line"> <span class="comment"># 头像上面的背景颜色</span></span><br><span class="line"> <span class="comment"># header: '#D3D1DC'</span></span><br><span class="line"> <span class="attr">header:</span> <span class="string">'#4d4d4d'</span></span><br><span class="line"> <span class="attr">gif:</span></span><br><span class="line"> <span class="comment"># 是否启用左侧边栏动态图效果</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment"># 自定义背景图路径(默认可以不设置,提供默认背景图)</span></span><br><span class="line"> <span class="comment"># path: /img/biubiubiu.gif</span></span><br><span class="line"> <span class="comment"># 右滑板块背景</span></span><br><span class="line"> <span class="attr">slider:</span> <span class="string">'linear-gradient(200deg,#a0cfe4,#e8c37e)'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># slider的设置</span></span><br><span class="line"><span class="attr">slider:</span></span><br><span class="line"> <span class="comment"># 是否默认展开tags板块</span></span><br><span class="line"> <span class="attr">showTags:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 智能菜单</span></span><br><span class="line"><span class="comment"># 如不需要,将该对应项置为false</span></span><br><span class="line"><span class="comment"># 比如</span></span><br><span class="line"><span class="comment">#smart_menu:</span></span><br><span class="line"><span class="comment"># friends: false</span></span><br><span class="line"><span class="attr">smart_menu:</span></span><br><span class="line"> <span class="attr">innerArchive:</span> <span class="string">'所有文章'</span></span><br><span class="line"> <span class="attr">friends:</span> <span class="string">'友链'</span></span><br><span class="line"> <span class="attr">aboutme:</span> <span class="string">'关于我'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 友情链接</span></span><br><span class="line"><span class="attr">friends:</span></span><br><span class="line"> <span class="string">技术笔记:</span> <span class="comment">#网站名称</span></span><br><span class="line"> <span class="comment">#网站地址</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://zhousiwei.gitee.io/ibooks/</span></span><br><span class="line"> <span class="comment">#网站图片(可忽略不写)</span></span><br><span class="line"> <span class="attr">img:</span> <span class="string">https://zhousiwei.gitee.io/ibooks/favicon.ico</span></span><br><span class="line"> <span class="comment">#网站简介(可忽略不写)</span></span><br><span class="line"> <span class="attr">description:</span> <span class="string">记录工作和学习过程中的笔记:Java、前端开发、Hexo博客、聚合支付、Linux笔记、ElasticSearch、ELK日志分析</span></span><br><span class="line"> <span class="attr">GitHub:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://github.com/JoeyBling</span></span><br><span class="line"> <span class="string">码云:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://gitee.com/zhousiwei</span></span><br><span class="line"> <span class="string">简书:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://www.jianshu.com/u/02cbf31a043a</span></span><br><span class="line"> <span class="attr">CSDN:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://blog.csdn.net/qq_30930805</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 关于我</span></span><br><span class="line"><span class="attr">aboutme:</span> <span class="string">主要涉及技术:<br>Java后端开发、聚合支付、<br>公众号开发、开源爱好者、Linux<br><br>联系QQ:2434387555<br><br>很惭愧<br><br>只做了一点微小的工作<br>谢谢大家</span></span><br></pre></td></tr></table></figure><h3 id="2-自己进行配置"><a href="#2-自己进行配置" class="headerlink" title="2. 自己进行配置"></a>2. 自己进行配置</h3><p>首先在<code>yilia-plus/layout/_partial/article.ejs</code>文件最后追加以下代码</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><!-- beaudar评论插件 --></span><br><span class="line"><% if (theme.beaudar){ %></span><br><span class="line"> <%- partial('post/beaudar', { </span><br><span class="line"> key: post.slug, </span><br><span class="line"> title: post.title, </span><br><span class="line"> url: config.url+url_for(post.path) </span><br><span class="line"> }) %></span><br><span class="line"><% } %></span><br></pre></td></tr></table></figure><p>然后新建<code>yilia-plus/layout/_partial/post/beaudar.ejs</code>文件,写入以下内容</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><% if (!index && post.comments && theme.beaudar && theme.beaudar.enable){ %></span><br><span class="line"><div id="beaudar-comment"></span><br><span class="line"><link rel="stylesheet" href="<%- url_for('lib/beaudar.css') %>"> <!--这里是我自己的css文件,如果你没有弄的话,可以不写。--></span><br><span class="line"><script src="https://beaudar.lipk.org/client.js" </span><br><span class="line">repo="<%=theme.beaudar.repo%>" </span><br><span class="line">issue-term="<%=theme.beaudar.issue_term%>"</span><br><span class="line">label="<%=theme.beaudar.label%>"</span><br><span class="line">theme="<%=theme.beaudar.theme%>"</span><br><span class="line">crossorigin="anonymous" async></span><br><span class="line"></script></span><br><span class="line"></div></span><br><span class="line"><% } %></span><br></pre></td></tr></table></figure><p>然后在<code>yilia-plus/_config.yml</code>文件中,添加以下配置即可</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 5、beaudar-表达 评论,由于giteement和gitment都不能使用了,所以使用beaudar</span></span><br><span class="line"><span class="comment"># 插件配置地址 https://beaudar.lipk.org/</span></span><br><span class="line"><span class="attr">beaudar:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="string">''</span> <span class="comment"># 仓库名称 注意直接从GitHub上复制 / 左右可能有空格,注意删除</span></span><br><span class="line"> <span class="attr">issue_term:</span> <span class="string">'pathname'</span> <span class="comment"># beaudar 生成的博客文章 ↔️ Issue 映射关系</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">'comment'</span> <span class="comment"># issue 标签,选择将分配给 Beaudar 创建的问题的标签</span></span><br><span class="line"> <span class="attr">theme:</span> <span class="string">'github-light'</span> <span class="comment"># beaudar 主题</span></span><br></pre></td></tr></table></figure><h2 id="三、-一些问题"><a href="#三、-一些问题" class="headerlink" title="三、 一些问题"></a>三、 一些问题</h2><ol><li><p>由于<code>Beaudar</code>提供的评论框主题和<code>yilia-plus</code>的风格不符,所以需要自定义下<code>Beaudar</code>的样式,详细的样式配置可以去看<a href="https://beaudar.lipk.org/" target="_blank" rel="noopener">Beaudar - 表达 (lipk.org)</a>网站上的说明,这里给出我自己简单的配置,只是简单将评论框拉宽到和文章页面等宽,因为我觉得<code>Beaudar</code>自带的主题<code>github-light</code>风格还行。</p><p>新建<code>yilia-plus/source/lib/beaudar.css</code>文件,添加以下代码。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#beaudar-comment</span> {<span class="attribute">padding</span>: <span class="number">0</span> <span class="number">30px</span><span class="meta">!important</span>;<span class="attribute">min-width</span>: <span class="number">20px</span>;}<span class="selector-class">.beaudar</span>{<span class="attribute">max-width</span>: none;}</span><br></pre></td></tr></table></figure></li><li><p>评论报错,显示 缺少 “beaudar.json” 配置 或 不允许 xxx 发布到 xxx/xxx</p><p>作者有说详细的解决办法<a href="https://www.lipk.org/blog/2020/06/08/beauder-qa/#q缺少-beaudarjson-配置-或-不允许-xxx-发布到-xxxxxx" target="_blank" rel="noopener">执手对影成双 - 关于 Beaudar 的 Q&A (lipk.org)</a>。方式就是你需要新建<code>beaudar.json</code>文件,并且这个文件生成在在<code>hexo</code>生成的<code>public</code>文件夹下,我是放在了<code>yilia-plus/source/beaudar.json</code>下,这样<code>hexo</code>编译的时候就会将这个文件放在<code>public</code>文件夹下了。该文件写入的内容如下</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"><span class="attr">"origins"</span>: [</span><br><span class="line"> <span class="string">"这里写入你博客的地址,多个地址用逗号分隔"</span></span><br><span class="line">]</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol>]]></content>
<summary type="html">
因为yilia-plus自带的gitment和giteement评论插件都不能用了,所以将评论插件更换为Beaudar(表达)。
</summary>
<category term="软件使用" scheme="https://proudrabbit.gitee.io/tags/%E8%BD%AF%E4%BB%B6%E4%BD%BF%E7%94%A8/"/>
<category term="Bug" scheme="https://proudrabbit.gitee.io/tags/Bug/"/>
<category term="hexo" scheme="https://proudrabbit.gitee.io/tags/hexo/"/>
</entry>
<entry>
<title>Git撤销修改</title>
<link href="https://proudrabbit.gitee.io/Git%E6%92%A4%E9%94%80%E4%BF%AE%E6%94%B9.html"/>
<id>https://proudrabbit.gitee.io/Git%E6%92%A4%E9%94%80%E4%BF%AE%E6%94%B9.html</id>
<published>2021-07-07T07:39:20.000Z</published>
<updated>2021-08-25T14:11:37.954Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><h1 id="Git撤销修改"><a href="#Git撤销修改" class="headerlink" title="Git撤销修改"></a>Git撤销修改</h1><p>本篇文章主要分为两部分,一是主要说明下如何使用<code>Git</code>来撤销对文件的修改,二是如何恢复误删的文件。以前一直没有弄明白,现在终于弄清了<code>QAQ</code>。在说操作之前,先说明下<code>Git</code>的<code>工作区</code>、<code>暂存区</code>和<code>版本库</code>的概念。先上图,用的是<a href="https://www.runoob.com/git/git-workspace-index-repo.html" target="_blank" rel="noopener">菜鸟教程</a>的图。</p><p><img src="https://www.runoob.com/wp-content/uploads/2015/02/1352126739_7909.jpg" alt=""></p><ul><li><strong>工作区:</strong>就是你在电脑里能看到的目录。</li><li><strong>暂存区:</strong>英文叫 stage 或 index。一般存放在 <strong><code>.git</code></strong> 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。</li><li><strong>版本库:</strong>工作区有一个隐藏目录 <strong><code>.git</code></strong>,这个不算工作区,而是 Git 的版本库。</li><li>当对<strong>工作区</strong>修改(或新增)的文件执行<code>git add</code>命令时,<strong>暂存区</strong>的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。</li><li>当执行提交操作<code>git commit</code>时,<strong>暂存区</strong>的目录树写到<strong>版本库(对象库)</strong>中,<code>master</code>分支会做相应的更新。即 <code>master</code>指向的目录树就是提交时暂存区的目录树。</li></ul><a id="more"></a><hr><p>明白了以上概念后,接下来来说下如何撤销修改以及恢复删除的文件。</p><h2 id="一、撤销修改"><a href="#一、撤销修改" class="headerlink" title="一、撤销修改"></a>一、撤销修改</h2><p> 撤销修改分为以下三种情况:</p><ol><li>已经<code>push</code>推送到远程仓库。</li><li>已经<code>commit</code>提交到版本库。</li><li>已经<code>add</code>提交到暂存区。</li><li>暂未提交到暂存区,所有修改都在工作区。</li></ol><p> 接下来就这四种情况说明下如何撤销修改。</p><hr><ol><li><p>如果<code>push</code>到<strong>远程仓库</strong>了,并且没有远程仓库的管理权限,那就放弃把,没救了。</p></li><li><p>已经使用<code>commit</code>提交到了<strong>版本库</strong>。</p><blockquote><p>因为已经产生了新的提交,所以撤销修改可以使用<code>git reset --hard HEAD^</code>来回退到上一个版本,从而达到撤销修改的效果。</p></blockquote></li><li><p>已经使用<code>add</code>提交到<strong>暂存区</strong>,但是没有使用<code>commit</code>提交到<strong>版本库</strong>。</p><blockquote><p>因为已经提交到<strong>暂存区</strong>了,所以撤销修改需要先将提交到<strong>暂存区</strong>的修改拿回到<strong>工作区</strong>。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">></span><span class="bash">git reset HEAD <file></span></span><br></pre></td></tr></table></figure><p>命令<code>git reset HEAD <file></code>可以把<strong>暂存区</strong>的修改撤销掉,重新放回<strong>工作区</strong>。==注意该命令和回退版本的命令的区别,因为很相似。==这样所有的修改就回到了<strong>工作区</strong>,丢弃<strong>工作区</strong>的修改只需执行以下命令。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">></span><span class="bash">git checkout -- <file> <span class="comment"># 使用 git restore <file> 的效果一样</span></span></span><br></pre></td></tr></table></figure><p>命令<code>git checkout -- <file></code>会将<strong>工作区</strong>的修改撤回到最后一次<code>git add</code>或<code>git commit</code>时的状态。</p></blockquote></li><li><p>文件修改都在<strong>工作区</strong>,没有提交到<strong>暂存区</strong>。</p><blockquote><p>丢弃<strong>工作区</strong>的修改只需要执行一下命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">></span><span class="bash">git checkout -- <file><span class="comment"># 使用 git restore <file> 的效果一样</span></span></span><br></pre></td></tr></table></figure><p>命令<code>git checkout -- <file></code>会将<strong>工作区</strong>的修改撤回到最后一次<code>git add</code>或<code>git commit</code>时的状态。有两种情况,即:</p><ul><li>一种是<code>file</code>自修改后还没有被放到<strong>暂存区</strong>,现在,撤销修改就回到和<strong>版本库</strong>一模一样的状态;</li><li>另一种是<code>file</code>已经添加到<strong>暂存区</strong>后,又作了修改,现在,撤销修改就回到添加到<strong>暂存区</strong>后的状态。</li></ul></blockquote></li></ol><h2 id="二、文件删除"><a href="#二、文件删除" class="headerlink" title="二、文件删除"></a>二、文件删除</h2><p> 文件删除其实也是一个修改动作。当使用<code>rm</code>命令或者通过鼠标右击删除文件时,<strong>工作区</strong>就产生了修改。这时候有两种选择:</p><p> 1.确实要从<strong>版本库</strong>中删除该文件,使用命令<code>git rm <file></code>然后使用<code>git commit</code>进行提交。==<strong>PS</strong>==:<strong>工作区</strong>删除文件后,然后使用<code>git add <file></code>的效果和直接使用<code>git rm <file></code>的效果是一样的。<br> 2. 另一种情况是删除错了,这时候只要使用<code>git checkout -- <file></code>即可把<strong>误删的文件恢复到最新版本,最后一次提交后修改的内容会丢失</strong>。==<strong>PS:从来没有被添加到版本库就被删除的文件,是无法恢复的!</strong>==</p>]]></content>
<summary type="html">
Git在使用中如何撤销对文件的修改。
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="软件使用" scheme="https://proudrabbit.gitee.io/tags/%E8%BD%AF%E4%BB%B6%E4%BD%BF%E7%94%A8/"/>
<category term="Git" scheme="https://proudrabbit.gitee.io/tags/Git/"/>
</entry>
<entry>
<title>使用代理解决ros安装过程中rosdep update连接超时的问题</title>
<link href="https://proudrabbit.gitee.io/%E4%BD%BF%E7%94%A8%E4%BB%A3%E7%90%86%E8%A7%A3%E5%86%B3ros%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B%E4%B8%ADrosdep%20update%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E7%9A%84%E9%97%AE%E9%A2%98.html"/>
<id>https://proudrabbit.gitee.io/%E4%BD%BF%E7%94%A8%E4%BB%A3%E7%90%86%E8%A7%A3%E5%86%B3ros%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B%E4%B8%ADrosdep%20update%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E7%9A%84%E9%97%AE%E9%A2%98.html</id>
<published>2021-03-05T10:31:32.000Z</published>
<updated>2021-08-06T09:37:30.489Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><h1 id="使用代理解决ROS安装过程中rosdep-update连接超时的问题"><a href="#使用代理解决ROS安装过程中rosdep-update连接超时的问题" class="headerlink" title="使用代理解决ROS安装过程中rosdep update连接超时的问题"></a>使用代理解决ROS安装过程中rosdep update连接超时的问题</h1><p>相信好多朋友都会遇到在使用<code>sudo rosdep init</code>和<code>rosdep update</code>时连接超时的问题。网上的教程都是改<code>/etc/hosts</code>文件来解决的,如果修改了<code>host</code>解决了<code>rosdep update</code>连接超时的问题,那下面的教程就不需要看了。假如你修改<code>host</code>后问题依旧,那么恭喜你,你和我的网络一样差。(总算有人和我的网络一样垃圾了^__^)希望下面的教程对你有点帮助。</p><p><strong>本人系统是Ubuntu 18.04.5</strong></p><a id="more"></a><h2 id="一、下载Shadowsocks-Qt5"><a href="#一、下载Shadowsocks-Qt5" class="headerlink" title="一、下载Shadowsocks-Qt5"></a>一、下载Shadowsocks-Qt5</h2><p>首先需要下载<code>Shadowsocks-Qt5</code>软件,</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://github.com/shadowsocks/shadowsocks-qt5/releases/download/v3.0.1/Shadowsocks-Qt5-3.0.1-x86_64.AppImage</span><br></pre></td></tr></table></figure><p>给该文件添加可执行权限,然后执行</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">chmod a+x Shadowsocks-Qt5-3.0.1-x86_64.AppImage</span><br><span class="line"></span><br><span class="line">sudo ./Shadowsocks-Qt5-3.0.1-x86_64.AppImage</span><br></pre></td></tr></table></figure><p>这时会打开软件,一开始是什么都没有的,然后点击<code>连接->添加->手动</code> ,根据你自己的服务商来填写里面的参数。(PS:感谢师弟!) 最后点击保存,然后链接。</p><p><img src="https://i.loli.net/2021/03/05/s9KejYDxBJ6Q2d4.png" alt="1">)<img src="https://i.loli.net/2021/03/05/uObmrsHyfeV8BLx.png" alt="2"></p><h2 id="二、修改Ubuntu的设置中的网络代理"><a href="#二、修改Ubuntu的设置中的网络代理" class="headerlink" title="二、修改Ubuntu的设置中的网络代理"></a>二、修改Ubuntu的设置中的网络代理</h2><p>打开Ubuntu的<code>设置->网络->网络代理</code>点击后面的齿轮,选择手动填写<code>Socks主机</code>中的参数,地址就是上面添加<code>Shadowsocks-Qt5</code>的连接中显示的地址和端口。这个时候打开浏览器就可以进谷歌了,然后你会发现,只有浏览器走代理,终端还是依旧不走啊QAQ。别急,接下来才是重头戏。</p><p><img src="https://i.loli.net/2021/03/05/UBXrVcRaFKWzQM4.png" alt="3"></p><h2 id="三、使终端走代理"><a href="#三、使终端走代理" class="headerlink" title="三、使终端走代理"></a>三、使终端走代理</h2><p>首先需要安装终端代理神器 <code>proxychains</code></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install proxychains4</span><br></pre></td></tr></table></figure><p>在使用<code>apt</code>安装时会有<code>proxychains</code>和<code>proxychains4</code>两个版本,我用的是<code>proxychains4</code>。</p><p>安装好需要修改配置文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo vim /etc/proxychains4.conf</span><br></pre></td></tr></table></figure><p>在最后一行将</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[ProxyList]</span><br><span class="line">socks4 127.0.0.1 9050</span><br></pre></td></tr></table></figure><p>修改为还是上面<code>Shadowsocks-Qt5</code>的连接中显示的地址和端口</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[ProxyList]</span><br><span class="line">socks5 127.0.0.1 1080</span><br></pre></td></tr></table></figure><p>因为我使用的是本地 socks5 的代理,其他的可以根据他给的例子填写。写好后记得<code>wq</code>保存推出。</p><p>到此就配置好了,要让终端走代理只需要在命令前面添加<code>proxychains4</code>即可。例如</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">proxychains4 rosdep update</span><br></pre></td></tr></table></figure><p>接下来就是见证奇迹的时刻。</p><p><img src="https://i.loli.net/2021/03/05/McdtJk4wLE8ojWG.png" alt="4"></p><p><strong>不用的时候记得把<code>Shadowsocks-Qt5</code>关闭和Ubuntu中的网络代理设置改为禁止,不然会没有网络。</strong></p><h2 id="感谢下面博主所提供的教程"><a href="#感谢下面博主所提供的教程" class="headerlink" title="感谢下面博主所提供的教程"></a>感谢下面博主所提供的教程</h2><p><a href="https://my.oschina.net/chinaliuhan/blog/3065303" target="_blank" rel="noopener">https://my.oschina.net/chinaliuhan/blog/3065303</a></p><p><a href="https://www.cnblogs.com/wAther/p/10472889.html" target="_blank" rel="noopener">https://www.cnblogs.com/wAther/p/10472889.html</a></p><p><a href="https://blog.csdn.net/u011745228/article/details/103588004?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control" target="_blank" rel="noopener">https://blog.csdn.net/u011745228/article/details/103588004?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control</a></p>]]></content>
<summary type="html">
使用代理解决ros安装过程中rosdep update连接超时的问题
</summary>
<category term="Linux" scheme="https://proudrabbit.gitee.io/tags/Linux/"/>
<category term="ros" scheme="https://proudrabbit.gitee.io/tags/ros/"/>
</entry>
<entry>
<title>Linux下printf函数不加\n就不能输出相关的内容</title>
<link href="https://proudrabbit.gitee.io/Linux%E4%B8%8Bprintf%E5%87%BD%E6%95%B0%E4%B8%8D%E5%8A%A0%E6%8D%A2%E8%A1%8C%E7%AC%A6%E5%B0%B1%E4%B8%8D%E8%83%BD%E8%BE%93%E5%87%BA%E7%9B%B8%E5%85%B3%E7%9A%84%E5%86%85%E5%AE%B9.html"/>
<id>https://proudrabbit.gitee.io/Linux%E4%B8%8Bprintf%E5%87%BD%E6%95%B0%E4%B8%8D%E5%8A%A0%E6%8D%A2%E8%A1%8C%E7%AC%A6%E5%B0%B1%E4%B8%8D%E8%83%BD%E8%BE%93%E5%87%BA%E7%9B%B8%E5%85%B3%E7%9A%84%E5%86%85%E5%AE%B9.html</id>
<published>2021-01-11T06:30:09.000Z</published>
<updated>2021-08-06T09:37:30.366Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>转载自:</strong><a href="https://blog.csdn.net/qq_26093511/article/details/53255970" target="_blank" rel="noopener">CSDN博主Alen.Wang</a> 地址:<a href="https://blog.csdn.net/qq_26093511/article/details/53255970" target="_blank" rel="noopener">https://blog.csdn.net/qq_26093511/article/details/53255970</a></p><p><strong>原因: 输出缓冲区的问题。</strong></p><p><code>unix</code>上标准输入输出都是带有缓存的,一般是行缓存。</p><p>对于标准输出,需要输出的数据并不是直接输出到终端上,而是首先缓存到某个地方,当遇到行刷新标志或者该缓存已满的情况下,才会把缓存的数据显示到终端设备上。</p><p><code>ANSI C</code>中定义换行符<code>\n</code>可以认为是行刷新标志。所以,<code>printf</code>函数没有带<code>\n</code>是不会自动刷新输出流,直至缓存被填满。</p><a id="more"></a><p>解决方案:</p><p>方案1、在<code>printf</code>里加<code>\n</code></p><p>方案2、在<code>printf</code>后面调用<code>fflush(stdout)</code>函数来刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上 。</p><p>方案3、使用<code>setvbuf(stdout,NULL,_IONBF,0);</code>函数来禁止缓冲区,这样就会直接进行输出。</p><p>这两个函数都是有关流缓冲区的. 具体使用和说明网上有很多. 我只说一下什么是流缓冲区, 是做什么用的。</p><p>操作系统为减少IO操作所以设置了缓冲区。等缓冲区满了再去操作IO,这样是为了提高效率。</p><p>下面是测试代码:</p><p>方案一、</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><unistd.h></span></span></span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> <span class="keyword">for</span>(i=<span class="number">0</span>;i<<span class="number">10</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\r %d%% is complete.\n"</span>,i);</span><br><span class="line"> sleep(<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\n"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>方案二、</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><unistd.h></span></span></span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> <span class="keyword">for</span>(i=<span class="number">0</span>;i<<span class="number">10</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\r %d%% is complete."</span>,i);</span><br><span class="line"> fflush(<span class="built_in">stdout</span>);</span><br><span class="line"> sleep(<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\n"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>方案三、</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><unistd.h></span></span></span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> setvbuf(<span class="built_in">stdout</span>,<span class="literal">NULL</span>,_IONBF,<span class="number">0</span>); <span class="comment">//直接将缓冲区禁止了. 它就直接输出了</span></span><br><span class="line"> <span class="keyword">for</span>(i=<span class="number">0</span>;i<<span class="number">10</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\r %d%% is complete."</span>,i);</span><br><span class="line"> sleep(<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\n"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
Linux下printf函数不加\n就不能输出相关的内容
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="Linux" scheme="https://proudrabbit.gitee.io/tags/Linux/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(十一)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%8D%81%E4%B8%80%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%8D%81%E4%B8%80%EF%BC%89.html</id>
<published>2021-01-11T06:26:52.000Z</published>
<updated>2021-08-25T14:11:38.093Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><h2 id="一、异步通知简介"><a href="#一、异步通知简介" class="headerlink" title="一、异步通知简介"></a>一、异步通知简介</h2><h3 id="1-1-硬件中断"><a href="#1-1-硬件中断" class="headerlink" title="1.1 硬件中断"></a>1.1 硬件中断</h3><p>中断是处理器提供的一种异步机制,配置好中断以后就可以让处理器去处理其他的事情了,当中断发生以后会触发事先设置好的中断服务函数,在中断服务函数中做具体的处理。</p><h3 id="1-2-信号"><a href="#1-2-信号" class="headerlink" title="1.2 信号"></a>1.2 信号</h3><p>信号类似于我们硬件上使用的“中断”,信号是软件层次上对中断机制的一种模拟,也叫作软中断信号。<strong>和软中断不是一个概念。</strong></p><a id="more"></a><p>驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了,应用程序获取到信号以后就可以从驱动设备中读取或者写入数据。整个过程就相当于应用程序收到了驱动发送过来了的一个中断,然后应用程序去响应这个中断。</p><p>异步通知的核心就是信号,在<code>arch/xtensa/include/uapi/asm/signal.h</code>中定义了<code>Linux</code>所持的信号,如下所示。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGHUP 1 <span class="comment">/* 终端挂起或控制进程终止 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGINT 2 <span class="comment">/* 终端中断(Ctrl+C 组合键) */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGQUIT 3 <span class="comment">/* 终端退出(Ctrl+\组合键) */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGILL 4 <span class="comment">/* 非法指令 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGTRAP 5 <span class="comment">/* debug 使用,有断点指令产生 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGABRT 6 <span class="comment">/* 由 abort(3)发出的退出指令 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGIOT 6 <span class="comment">/* IOT 指令 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGBUS 7 <span class="comment">/* 总线错误 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGFPE 8 <span class="comment">/* 浮点运算错误 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGKILL 9 <span class="comment">/* 杀死、终止进程 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGUSR1 10 <span class="comment">/* 用户自定义信号 1 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGSEGV 11 <span class="comment">/* 段违例(无效的内存段) */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGUSR2 12 <span class="comment">/* 用户自定义信号 2 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGPIPE 13 <span class="comment">/* 向非读管道写入数据 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGALRM 14 <span class="comment">/* 闹钟 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGTERM 15 <span class="comment">/* 软件终止 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGSTKFLT 16 <span class="comment">/* 栈异常 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGCHLD 17 <span class="comment">/* 子进程结束 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGCONT 18 <span class="comment">/* 进程继续 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGSTOP 19 <span class="comment">/* 停止进程的执行,只是暂停 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGTSTP 20 <span class="comment">/* 停止进程的运行(Ctrl+Z 组合键) */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGTTIN 21 <span class="comment">/* 后台进程需要从终端读取数据 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGTTOU 22 <span class="comment">/* 后台进程需要向终端写数据 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGURG 23 <span class="comment">/* 有"紧急"数据 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGXCPU 24 <span class="comment">/* 超过 CPU 资源限制 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGXFSZ 25 <span class="comment">/* 文件大小超额 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGVTALRM 26 <span class="comment">/* 虚拟时钟信号 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGPROF 27 <span class="comment">/* 时钟信号描述 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGWINCH 28 <span class="comment">/* 窗口大小改变 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGIO 29 <span class="comment">/* 可以进行输入/输出操作 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGPOLL SIGIO</span></span><br><span class="line"><span class="comment">/* #define SIGLOS 29 */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGPWR 30 <span class="comment">/* 断点重启 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGSYS 31 <span class="comment">/* 非法的系统调用 */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SIGUNUSED 31 <span class="comment">/* 未使用信号 */</span></span></span><br></pre></td></tr></table></figure><p>这些信号中,除了 <code>SIGKILL(9)</code>和 <code>SIGSTOP(19)</code>这两个信号不能被忽略外,其他的信号都可以忽略。这些信号就相当于中断号,不同的中断号代表了不同的中断,不同的中断所做的处理不同,因此,驱动程序可以通过向应用程序发送不同的信号来实现不同的功能。</p><h3 id="1-3-信号处理函数"><a href="#1-3-信号处理函数" class="headerlink" title="1.3 信号处理函数"></a>1.3 信号处理函数</h3><p>使用中断的时候需要设置中断处理函数,同样的,如果要在应用程序中使用信号,那么就必须设置信号所使用的信号处理函数,在<strong>应用程序</strong>中使用 <code>signal</code> 函数来设置指定信号的处理函数, <code>signal</code> 函数原型如下所示</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param signum 要设置处理函数的信号。</span></span><br><span class="line"><span class="comment"> * @param handler 信号的处理函数。</span></span><br><span class="line"><span class="comment"> * @return 设置成功的话返回信号的前一个处理函数,设置失败的话返回 SIG_ERR。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">sighandler_t</span> <span class="title">signal</span><span class="params">(<span class="keyword">int</span> signum, <span class="keyword">sighandler_t</span> handler)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 信号处理函数原型 */</span></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">void</span> <span class="params">(*<span class="keyword">sighandler_t</span>)</span><span class="params">(<span class="keyword">int</span>)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="1-4-驱动中对异步通知的处理"><a href="#1-4-驱动中对异步通知的处理" class="headerlink" title="1.4 驱动中对异步通知的处理"></a>1.4 驱动中对异步通知的处理</h3><ol><li><p>需要在驱动程序中定义一个<code>fasync_struct</code>结构体指针变量,<code>fasync_struct</code>结构体内容如下:</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">><span class="class"><span class="keyword">struct</span> <span class="title">fasync_struct</span> {</span></span><br><span class="line">><span class="keyword">spinlock_t</span> fa_lock;</span><br><span class="line">><span class="keyword">int</span> magic;</span><br><span class="line">><span class="keyword">int</span> fa_fd;</span><br><span class="line">><span class="class"><span class="keyword">struct</span> <span class="title">fasync_struct</span> *<span class="title">fa_next</span>;</span></span><br><span class="line">><span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">fa_file</span>;</span></span><br><span class="line">><span class="class"><span class="keyword">struct</span> <span class="title">rcu_head</span> <span class="title">fa_rcu</span>;</span></span><br><span class="line">>};</span><br></pre></td></tr></table></figure><p>一般将<code>fasync_struct</code>结构体指针变量定义到设备结构体中。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"> ><span class="class"><span class="keyword">struct</span> <span class="title">imx6uirq_dev</span> {</span></span><br><span class="line"> ><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span>;</span></span><br><span class="line"> ><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">cls</span>;</span></span><br><span class="line"> ><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span></span><br><span class="line"></span><br><span class="line">......</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fasync_struct</span> *<span class="title">async_queue</span>;</span><span class="comment">/* 异步相关结构体 */</span></span><br><span class="line"> >};</span><br></pre></td></tr></table></figure></blockquote></li><li><p>要实现<code>file_operations</code>里面的<code>fasync</code>函数。</p><blockquote><p>要使用异步通知,需要在设备驱动中实现 <code>file_operations</code> 操作集中的 <code>fasync</code> 函数,格式如下所示</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> (*fasync) (<span class="keyword">int</span> fd, struct file *filp, <span class="keyword">int</span> on);</span><br></pre></td></tr></table></figure><p><code>fasync</code> 函数里面一般通过调用 <code>fasync_helper</code> 函数来初始化前面定义的 <code>fasync_struct</code>结构体指针, <code>fasync_helper</code> 函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">fasync_helper</span><span class="params">(<span class="keyword">int</span> fd, struct file * filp, <span class="keyword">int</span> on, struct fasync_struct **fapp)</span></span>;</span><br></pre></td></tr></table></figure><p>当应用程序通过 <code>fcntl(fd, F_SETFL, flags | FASYNC)</code> 改变 <code>fasync</code> 标记的时候,驱动程序 <code>file_operations</code> 操作集中的 <code>fasync</code> 函数就会执行。</p></blockquote></li><li><p>向应用程序发送信号,<code>kill_fasync</code>函数</p><blockquote><p>当设备可以访问的时候,驱动程序需要向应用程序发出信号,相当于产生“中断”。<code>kill_fasync</code> 函数负责发送指定的信号, <code>kill_fasync</code> 函数原型如下所示</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">><span class="comment">/**</span></span><br><span class="line"><span class="comment">>* @param fp 要操作的 fasync_struct。</span></span><br><span class="line"><span class="comment">>* @param sig 要发送的信号</span></span><br><span class="line"><span class="comment">>* @param band 可读时设置为 POLL_IN,可写时设置为 POLL_OUT。</span></span><br><span class="line"><span class="comment">>*/</span></span><br><span class="line">><span class="function"><span class="keyword">void</span> <span class="title">kill_fasync</span><span class="params">(struct fasync_struct **fp, <span class="keyword">int</span> sig, <span class="keyword">int</span> band)</span></span>;</span><br></pre></td></tr></table></figure></blockquote></li><li><p>关闭驱动时,需要删除信号。</p><blockquote><p>关闭驱动文件的时候需要在 <code>file_operations</code> 操作集中的 <code>release</code> 函数中释放 <code>fasync_struct</code>,<code>fasync_struct</code> 的释放函数同样为 <code>fasync_helper</code>。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">xxx_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> xxx_fasync(<span class="number">-1</span>, filp, <span class="number">0</span>);<span class="comment">/* 删除异步通知 */</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></blockquote><p><strong>驱动中 <code>fasync</code> 函数参考示例</strong></p></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">xxx_dev</span> {</span></span><br><span class="line">......</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fasync_struct</span> *<span class="title">async_queue</span>;</span><span class="comment">/* 异步相关结构体 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">xxx_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> xxx_fasync(<span class="number">-1</span>, filp, <span class="number">0</span>);<span class="comment">/* 删除异步通知 */</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">xxx_fasync</span><span class="params">(<span class="keyword">int</span> fd, struct file *filp, <span class="keyword">int</span> on)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">xxx_dev</span> *<span class="title">dev</span> = (<span class="title">xxx_dev</span>)<span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (fasync_helper(fd, filp, on, &dev->async_queue) < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> -EIO;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">xxx_ops</span> = {</span></span><br><span class="line"> ......</span><br><span class="line"> </span><br><span class="line"> .fasync = xxx_fasync,</span><br><span class="line"> </span><br><span class="line"> ......</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="1-5-应用程序对异步通知的处理"><a href="#1-5-应用程序对异步通知的处理" class="headerlink" title="1.5 应用程序对异步通知的处理"></a>1.5 应用程序对异步通知的处理</h3><ol><li><p>注册信号处理函数</p><blockquote><p>使用 <code>signal()</code> 函数来设置指定信号的处理函数。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">><span class="comment">/* 设置信号处理函数 */</span></span><br><span class="line">>signal(SIGIO, sigio_signal_func);</span><br></pre></td></tr></table></figure></blockquote></li><li><p>将本应用程序的进程号告诉给内核</p><p>使用 <code>fcntl(fd, F_SETOWN, getpid());</code> 将本应用程序的进程号告诉给内核。</p></li><li><p>开启异步通知</p><blockquote><p>使用如下两行程序开启异步通知</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 开启异步通知 */</span></span><br><span class="line">flags = fcntl(fd, F_GETFL);<span class="comment">/* 获取当前的进程状态 */</span></span><br><span class="line">fcntl(fd, F_SETFL, flags | FASYNC);<span class="comment">/* 开启当前进程异步通知功能 */</span></span><br></pre></td></tr></table></figure><p><strong>重点就是通过 <code>fcntl</code> 函数设置进程状态为 <code>FASYNC</code>,经过这一步,驱动程序中的 <code>fasync</code>函数就会执行。</strong></p></blockquote></li></ol><h2 id="二、实验驱动编写"><a href="#二、实验驱动编写" class="headerlink" title="二、实验驱动编写"></a>二、实验驱动编写</h2><h3 id="2-1-驱动程序"><a href="#2-1-驱动程序" class="headerlink" title="2.1 驱动程序"></a>2.1 驱动程序</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/interrupt.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_NAME<span class="meta-string">"keyirq"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY_NUM1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY0_VALUE0X01</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> INVAKEY0XFF<span class="comment">/* 无效按键值 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">int</span> gpio;<span class="comment">/* IO编号 */</span></span><br><span class="line"><span class="keyword">int</span> irqNum;<span class="comment">/* 中断号 */</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> value;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">char</span> name[<span class="number">10</span>];<span class="comment">/* 名称 */</span></span><br><span class="line"><span class="keyword">irqreturn_t</span> (*handler)(<span class="keyword">int</span>, <span class="keyword">void</span>*);<span class="comment">/* 中断处理函数 */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span> <span class="title">tasklet</span>;</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">/* 设备ID */</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">/* 主设备号 */</span></span><br><span class="line"><span class="keyword">int</span> minor;<span class="comment">/* 次设备号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span><span class="comment">/* 字符设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">/* 设备类 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">/* 设备节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span><span class="comment">/* 设备树节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span> <span class="title">key</span>[<span class="title">KEY_NUM</span>];</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定时器 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">atomic_t</span> keyValue;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">atomic_t</span> keyRelease;<span class="comment">/* 按键是否释放 */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fasync_struct</span> *<span class="title">fasync</span>;</span><span class="comment">/* 定义一个异步通知结构体 */</span></span><br><span class="line"></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> <span class="title">keyirq</span>;</span><span class="comment">/* 定义一个keyirq设备 */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_fasync</span><span class="params">(<span class="keyword">int</span> fd, struct file *filp, <span class="keyword">int</span> on)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> fasync_helper(fd, filp, on, &dev->fasync);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &keyirq;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> keyirq_fasync(<span class="number">-1</span>, filp, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_read</span><span class="params">(struct file *filp, <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyValue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyRelease;</span><br><span class="line"></span><br><span class="line">keyValue = atomic_read(&dev->keyValue);</span><br><span class="line">keyRelease = atomic_read(&dev->keyRelease);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (keyRelease)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 一次有效按键 */</span></span><br><span class="line"><span class="keyword">if</span> (keyValue & <span class="number">0X80</span>)</span><br><span class="line">{</span><br><span class="line">keyValue &= ~<span class="number">0X80</span>;<span class="comment">// 去除标记</span></span><br><span class="line">ret = copy_to_user(buf, &keyValue, <span class="keyword">sizeof</span>(keyValue));</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">0</span>);</span><br><span class="line">} </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">data_err:</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 操作集 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">keyirq_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = keyirq_open,</span><br><span class="line">.<span class="built_in">release</span> = keyirq_release,</span><br><span class="line">.<span class="built_in">write</span> = keyirq_write,</span><br><span class="line">.<span class="built_in">read</span> = keyirq_read,</span><br><span class="line">.fasync = keyirq_fasync, </span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 定时器处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 用户参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_func</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span>*)<span class="title">arg</span>;</span></span><br><span class="line"><span class="keyword">int</span> value = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">value = gpio_get_value(dev->key[<span class="number">0</span>].gpio);</span><br><span class="line"><span class="keyword">if</span> (value == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键按下</span></span><br><span class="line">printk(<span class="string">"KEY0 Press!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(value == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键释放</span></span><br><span class="line">printk(<span class="string">"KEY0 Release!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value | <span class="number">0X80</span>);<span class="comment">// 打上标签,标记按键按下</span></span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (atomic_read(&dev->keyRelease) == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 如果是一次有效的按键 */</span></span><br><span class="line">kill_fasync(&dev->fasync, SIGIO, POLL_IN);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief key0 tasklet 处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 传递的参数</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">key0_tasklet</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span> *)<span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 启动定时器来延时消抖 */</span></span><br><span class="line">dev->timer.data = (<span class="keyword">volatile</span> <span class="keyword">unsigned</span> <span class="keyword">long</span>)arg;</span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(<span class="number">20</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键中断处理函数</span></span><br><span class="line"><span class="comment"> * @param irq 中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">irqreturn_t</span> <span class="title">key0_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line">tasklet_schedule(&dev->key[<span class="number">0</span>].tasklet);<span class="comment">/* 调度对应的tasklet */</span></span><br><span class="line"><span class="keyword">return</span> IRQ_HANDLED;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键初始化</span></span><br><span class="line"><span class="comment"> * @param dev 设备结构体</span></span><br><span class="line"><span class="comment"> * @return 错误类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyio_init</span><span class="params">(struct keyirq_dev *dev)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键初始化 */</span></span><br><span class="line">dev->nd = of_find_node_by_path(<span class="string">"/key"</span>);</span><br><span class="line"><span class="keyword">if</span> (dev->nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_nd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 可能有多个按键,因此需要根据实际数量来读取 */</span></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line">dev->key[i].gpio = of_get_named_gpio(dev->nd, <span class="string">"key-gpios"</span>, i);</span><br><span class="line"><span class="keyword">if</span> (dev->key[i].gpio < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_getGpio;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">memset</span>(dev->key[i].name, <span class="number">0</span>, <span class="keyword">sizeof</span>(dev->key[i].name));</span><br><span class="line"><span class="built_in">sprintf</span>(dev->key[i].name, <span class="string">"KEY%d"</span>, i);</span><br><span class="line">ret = gpio_request(dev->key[i].gpio, dev->key[i].name);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_requestGpio;</span><br><span class="line">}</span><br><span class="line">ret = gpio_direction_input(dev->key[i].gpio);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setGpioDir;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取中断号,两种方式皆可 */</span></span><br><span class="line">dev->key[i].irqNum = gpio_to_irq(dev->key[i].gpio);</span><br><span class="line"><span class="comment">// dev->key[i].irqNum = irq_of_parse_and_map(dev->nd, i);</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键中断初始化 */</span></span><br><span class="line">dev->key[<span class="number">0</span>].handler = key0_handler;</span><br><span class="line">dev->key[<span class="number">0</span>].value = KEY0_VALUE;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 跳变沿触发方式 */</span></span><br><span class="line">ret = request_irq(dev->key[i].irqNum, dev->key[i].handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev->key[i].name, dev);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"irq %d request failed!\r\n"</span>, dev->key[i].irqNum);</span><br><span class="line"><span class="keyword">goto</span> fail_irq;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>没有根据多个按键来初始化各自的tasklet,实际中需要根据情况来编写 */</span></span><br><span class="line">tasklet_init(&dev->key[i].tasklet, key0_tasklet, (<span class="keyword">unsigned</span> <span class="keyword">long</span>)dev);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化定时器 */</span></span><br><span class="line">init_timer(&dev->timer);</span><br><span class="line">dev->timer.function = timer_func;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_irq:</span><br><span class="line">fail_setGpioDir:</span><br><span class="line"><span class="keyword">for</span> (i = i<span class="number">-1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line">{</span><br><span class="line">gpio_free(dev->key[i].gpio);</span><br><span class="line">}</span><br><span class="line">fail_requestGpio:</span><br><span class="line">fail_getGpio:</span><br><span class="line">fail_nd:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">keyirq_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">keyirq.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(keyirq.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">keyirq.devid = MKDEV(keyirq.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(keyirq.devid, KEYIRQ_CNT, KEYIRQ_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&keyirq.devid, <span class="number">0</span>,KEYIRQ_CNT,KEYIRQ_NAME);</span><br><span class="line">keyirq.major = MAJOR(keyirq.devid);</span><br><span class="line">keyirq.minor = MINOR(keyirq.devid);</span><br><span class="line">printk(<span class="string">"dev Major ID:%d\r\n"</span>,keyirq.major);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">keyirq.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&keyirq.cdev, &keyirq_fops);</span><br><span class="line">ret = cdev_add(&keyirq.cdev, keyirq.devid, KEYIRQ_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备类 */</span></span><br><span class="line">keyirq<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">KEYIRQ_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">keyirq.device = device_create(keyirq.class, <span class="literal">NULL</span>, keyirq.devid, <span class="literal">NULL</span>, KEYIRQ_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化IO */</span></span><br><span class="line">ret = keyio_init(&keyirq);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_init;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化原子变量 */</span></span><br><span class="line">atomic_set(&keyirq.keyValue, INVAKEY);</span><br><span class="line">atomic_set(&keyirq.keyRelease, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_init:</span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(keyirq.devid, KEYIRQ_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">keyirq_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 释放中断和IO */</span></span><br><span class="line">free_irq(keyirq.key[i].irqNum, &keyirq);</span><br><span class="line">gpio_free(keyirq.key[i].gpio);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 删除定时器 */</span></span><br><span class="line">del_timer_sync(&keyirq.timer);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注销字符设备驱动 */</span></span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">unregister_chrdev_region(keyirq.devid,KEYIRQ_CNT);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(keyirq_init);</span><br><span class="line">module_exit(keyirq_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h3 id="2-2-测试APP程序"><a href="#2-2-测试APP程序" class="headerlink" title="2.2 测试APP程序"></a>2.2 测试APP程序</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/ioctl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><signal.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> fd;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 信号处理函数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">sigio_signal_func</span><span class="params">(<span class="keyword">int</span> num)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> data;</span><br><span class="line">ret = <span class="built_in">read</span>(fd, &data, <span class="keyword">sizeof</span>(data));</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* code */</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"sigio signal! key value = %d\r\n"</span>, data);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ./asyncnotiAPP /dev/keyirq</span></span><br><span class="line"><span class="comment"> * @param argc 应用程序参数个数</span></span><br><span class="line"><span class="comment"> * @param argv 保存的参数,字符串形式。</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">char</span> *filename;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> data;</span><br><span class="line"><span class="keyword">int</span> flags = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">if (argc != 3)</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">printf("输入错误\r\n");</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line">filename = argv[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">fd = <span class="built_in">open</span>(filename, O_RDWR);</span><br><span class="line"><span class="keyword">if</span>(fd < <span class="number">0</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Open %s fail.\r\n"</span>,filename);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 设置信号处理函数 */</span></span><br><span class="line">signal(SIGIO, sigio_signal_func);</span><br><span class="line"></span><br><span class="line">fcntl(fd, F_SETOWN, getpid());<span class="comment">/* 设置当前进程接收SIGIO信号 */</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">/* 开启异步通知 */</span></span><br><span class="line">flags = fcntl(fd, F_GETFL);<span class="comment">/* 获取当前的进程状态 */</span></span><br><span class="line">fcntl(fd, F_SETFL, flags | FASYNC);<span class="comment">/* 开启当前进程异步通知功能 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line">sleep(<span class="number">2</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 关闭 */</span></span><br><span class="line">ret = <span class="built_in">close</span>(fd);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Close %s fail.\r\n"</span>, filename);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(十)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%8D%81%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%8D%81%EF%BC%89.html</id>
<published>2021-01-08T03:21:09.000Z</published>
<updated>2021-08-25T14:11:38.102Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><h2 id="一、Linux阻塞和非阻塞IO"><a href="#一、Linux阻塞和非阻塞IO" class="headerlink" title="一、Linux阻塞和非阻塞IO"></a>一、Linux阻塞和非阻塞IO</h2><h3 id="1-1-阻塞和非阻塞简介"><a href="#1-1-阻塞和非阻塞简介" class="headerlink" title="1.1 阻塞和非阻塞简介"></a>1.1 阻塞和非阻塞简介</h3><p>这里的 <code>IO</code> 指的是 <code>Input/Output</code>,也就是输入/输出,是应用程序对驱动设备的输入/输出操作。当应用程序对设备驱动进行操作的时候,如果不能获取到设备资源,那么阻塞式 <code>IO</code> 就会将应用程序对应的线程挂起,直到设备资源可以获取为止。对于非阻塞 <code>IO</code>,应用程序对应的线程不会挂起,它要么一直轮询等待,直到设备资源可以使用,要么就直接放弃。</p><a id="more"></a><ul><li><p>阻塞式<code>IO</code>:</p><blockquote><p>当资源不可用时,应用程序就会挂起。当资源可用的时候,唤醒任务。应用程序使用<code>open</code>打开驱动文件,默认是阻塞方式打开。</p><p>阻塞式<code>IO</code>访问示意图:</p><p><img src="https://i.loli.net/2020/12/23/Hb3IhCd95umSLcD.png" alt="阻塞式IO" title="阻塞式IO"></p></blockquote></li><li><p>非阻塞式<code>IO</code>:</p><blockquote><p>当资源不可用的时候,应用程序轮询查看,或放弃。会有超时处理。应用程序如果想在使用<code>open</code>打开驱动文件时使用非阻塞的方式打开,需要使用<code>O_NONBLOCK</code>。</p><p>非阻塞式<code>IO</code>访问示意图:</p><p><img src="https://i.loli.net/2020/12/23/TPzJBZXh7eqCg6V.png" alt="非阻塞式IO" title="非阻塞式IO"></p></blockquote></li></ul><h3 id="1-2-等待队列(阻塞访问)"><a href="#1-2-等待队列(阻塞访问)" class="headerlink" title="1.2 等待队列(阻塞访问)"></a>1.2 等待队列(阻塞访问)</h3><ol><li><p>等待队列头</p><p>阻塞访问最大的好处就是当设备文件不可操作的时候进程可以进入休眠态,这样可以将<code>CPU</code> 资源让出来。但是,当设备文件可以操作的时候就必须唤醒进程,一般在中断函数里面完成唤醒工作。 <code>Linux</code>内核提供了等待队列(<code>wait queue</code>)来实现阻塞进程的唤醒工作,如果我们要在驱动中使用等待队列,必须创建并初始化一个等待队列头,等待队列头使用结构体<code>wait_queue_head_t</code> 表示:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> __<span class="title">wait_queue_head</span> {</span></span><br><span class="line"> <span class="keyword">spinlock_t</span> lock;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">task_list</span>;</span></span><br><span class="line">};</span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> __<span class="title">wait_queue_head</span> <span class="title">wait_queue_head_t</span>;</span></span><br></pre></td></tr></table></figure><p>定义好等待队列头以后需要初始化,使用 <code>init_waitqueue_head</code> 函数初始化等待队列头,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param q 等待队列头</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">init_waitqueue_head</span><span class="params">(<span class="keyword">wait_queue_head_t</span> *q)</span></span></span><br></pre></td></tr></table></figure><p>也可以使用宏 <code>DECLARE_WAIT_QUEUE_HEAD</code> 来一次性完成等待队列头的定义和初始化。</p></li><li><p>等待队列项</p><p>等待队列头就是一个等待队列的头部,每个访问设备的进程都是一个队列项,当设备不可用的时候就要将这些进程对应的等待队列项添加到等待队列里面。结构体 <code>wait_queue_t</code> 表示等待队列项。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> __<span class="title">wait_queue</span> {</span></span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">int</span> flags;</span><br><span class="line"> <span class="keyword">void</span> *<span class="keyword">private</span>;</span><br><span class="line"> <span class="keyword">wait_queue_func_t</span> func;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">task_list</span>;</span></span><br><span class="line">};</span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> __<span class="title">wait_queue</span> <span class="title">wait_queue_t</span>;</span></span><br></pre></td></tr></table></figure><p>同样可以使用宏 <code>DECLARE_WAITQUEUE</code> 定义并初始化一个等待队列项。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param name 等待队列项的名字</span></span><br><span class="line"><span class="comment"> * @param tsk 表示该等待队列项属于哪个任务(进程),一般为 current</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">DECLARE_WAITQUEUE(name, tsk)</span><br></pre></td></tr></table></figure></li><li><p>添加/移除等待队列项</p><p>当设备不可访问的时候就需要将进程对应的等待队列项添加到前面创建的等待队列头中,只有添加到等待队列头中以后进程才能进入休眠态。当设备可以访问以后再将进程对应的等待队列项从等待队列头中移除即可。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 添加等待队列项到等待队列头</span></span><br><span class="line"><span class="comment"> * @param q 等待队列头</span></span><br><span class="line"><span class="comment"> * @param wait 等待队列项</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add_wait_queue</span><span class="params">(<span class="keyword">wait_queue_head_t</span> *q,<span class="keyword">wait_queue_t</span> *wait)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 将等待队列项从等待队列头中移除</span></span><br><span class="line"><span class="comment"> * @param q 等待队列头</span></span><br><span class="line"><span class="comment"> * @param wait 等待队列项</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">remove_wait_queue</span><span class="params">(<span class="keyword">wait_queue_head_t</span> *q,<span class="keyword">wait_queue_t</span> *wait)</span></span></span><br></pre></td></tr></table></figure></li><li><p>等待唤醒</p><p>当设备可以使用的时候就要唤醒进入休眠态的进程,唤醒可以使用如下两个函数。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 唤醒等待队列头下所有的进程</span></span><br><span class="line"><span class="comment"> * @param q 要唤醒的等待队列头</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">wake_up</span><span class="params">(<span class="keyword">wait_queue_head_t</span> *q)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">wake_up_interruptible</span><span class="params">(<span class="keyword">wait_queue_head_t</span> *q)</span></span>;</span><br></pre></td></tr></table></figure><p><strong><code>wake_up</code> 函数可以唤醒处于 <code>TASK_INTERRUPTIBLE</code> 和 <code>TASK_UNINTERRUPTIBLE</code> 状态的进程,而 <code>wake_up_interruptible</code> 函数只能唤醒处于 <code>TASK_INTERRUPTIBLE</code> 状态的进程。</strong></p></li><li><p>等待事件</p><p>除了主动唤醒以外,也可以设置等待队列等待某个事件,当这个事件满足以后就自动唤醒等待队列中的进程,和等待事件有关的<code>API</code>函数如下。</p><table><thead><tr><th>函数</th><th>描述</th></tr></thead><tbody><tr><td>wait_event(wq, condition)</td><td>等待以 <code>wq</code> 为等待队列头的等待队列被唤醒,前提是 <code>condition</code> 条件必须满足(为真),否则一直阻塞。此 函 数 会 将 进 程 设 置 为<code>TASK_UNINTERRUPTIBLE</code> 状态。</td></tr><tr><td>wait_event_timeout(wq, condition, timeout)</td><td>功能和 <code>wait_event</code> 类似,但是此函数可以添加超时时间,以 <code>jiffies</code> 为单位。此函数有返回值,如果返回 <code>0</code> 的话表示超时时间到,而且 <code>condition</code> 为假。为 <code>1</code> 的话表示 <code>condition</code> 为真,也就是条件满足了。</td></tr><tr><td>wait_event_interruptible(wq, condition)</td><td>与 <code>wait_event</code> 函数类似,但是此函数将进程设置为<code>TASK_INTERRUPTIBLE</code>,就是可以被信号打断。</td></tr><tr><td>wait_event_interruptible_timeout(wq,condition, timeout)</td><td>与 <code>wait_event_timeout</code> 函数类似,此函数也将进 程设置为<code>TASK_INTERRUPTIBLE</code>,可以被信号打断。</td></tr></tbody></table></li></ol><h3 id="1-3-轮询(非阻塞访问)"><a href="#1-3-轮询(非阻塞访问)" class="headerlink" title="1.3 轮询(非阻塞访问)"></a>1.3 轮询(非阻塞访问)</h3><p>如果用户应用程序以非阻塞的方式访问设备,设备驱动程序就要提供非阻塞的处理方式,也就是轮询。 <code>poll</code>、 <code>epoll</code> 和 <code>select</code> 可以用于处理轮询,应用程序通过 <code>select</code>、 <code>epoll</code> 或 <code>poll</code> 函数来查询设备是否可以操作,如果可以操作的话就从设备读取或者向设备写入数据。</p><p>当应用程序调用 <code>select</code>、 <code>epoll</code> 或 <code>poll</code> 函数的时候,设备驱动程序中的 <code>poll</code> 函数就会执行,因此需要在设备驱动程序中编写 <code>poll</code> 函数。</p><p>驱动里<code>poll</code>函数原型如下。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param filp 要打开的设备文件(文件描述符)</span></span><br><span class="line"><span class="comment"> * @param wait 结构体 poll_table_struct 类型指针,由应用程序传递进来。一般将此参数传递给 poll_wait 函数。</span></span><br><span class="line"><span class="comment"> * @return 向应用程序返回设备或者资源状态。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="title">int</span> <span class="params">(*poll)</span><span class="params">(struct file *filp, struct poll_table_struct *wait)</span></span>;</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* return 可以返回的资源状态 */</span></span><br><span class="line">POLLIN <span class="comment">// 有数据可以读取。</span></span><br><span class="line">POLLPRI <span class="comment">// 有紧急的数据需要读取。</span></span><br><span class="line">POLLOUT <span class="comment">// 可以写数据。</span></span><br><span class="line">POLLERR<span class="comment">// 指定的文件描述符发生错误。</span></span><br><span class="line">POLLHUP<span class="comment">// 指定的文件描述符挂起。</span></span><br><span class="line">POLLNVAL<span class="comment">// 无效的请求。</span></span><br><span class="line">POLLRDNORM<span class="comment">// 等同于 POLLIN,普通数据可读</span></span><br></pre></td></tr></table></figure><p>需要在驱动程序的 <code>poll</code> 函数中调用 <code>poll_wait</code> 函数, <code>poll_wait</code> 函数不会引起阻塞,只是将应用程序添加到 <code>poll_table</code> 中。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param filp 文件描述符</span></span><br><span class="line"><span class="comment"> * @param wait_address 要添加到 poll_table 中的等待队列头</span></span><br><span class="line"><span class="comment"> * @param p poll_table,就是file_operations 中 poll 函数的 wait 参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">poll_wait</span><span class="params">(struct file *filp, <span class="keyword">wait_queue_head_t</span> *wait_address, poll_table *p)</span></span></span><br></pre></td></tr></table></figure><ol><li><p><code>select</code>函数</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">><span class="comment">/**</span></span><br><span class="line"><span class="comment">>* @param nfds 所要监视的这三类文件描述集合中,最大文件描述符加1。</span></span><br><span class="line"><span class="comment">>* @param readfds 监视指定描述符集的读变化,也就是监视文件是否可读</span></span><br><span class="line"><span class="comment">>* @param writefds 监视文件是否可以进行写操作</span></span><br><span class="line"><span class="comment">>* @param exceptfds 监视这些文件的异常</span></span><br><span class="line"><span class="comment">>* @param timeout 超时时间,为 NULL 的时候就表示无限期的等待。</span></span><br><span class="line"><span class="comment">>* @return 0,表示的话就表示超时发生,但是没有任何文件描述符可以进行操作;-1,发生错误;其他值,可以进行操作的文件描述符个数。</span></span><br><span class="line"><span class="comment">>*/</span></span><br><span class="line">><span class="function"><span class="keyword">int</span> <span class="title">select</span><span class="params">(<span class="keyword">int</span> nfds, fd_set *readfds, fd_set *writefds, </span></span></span><br><span class="line"><span class="function"><span class="params"> fd_set *exceptfds, struct timeval *timeout)</span></span>;</span><br><span class="line"></span><br><span class="line">><span class="comment">/* timeval结构体 */</span></span><br><span class="line">><span class="class"><span class="keyword">struct</span> <span class="title">timeval</span> {</span></span><br><span class="line"><span class="keyword">long</span> tv_sec; <span class="comment">/* 秒 */</span></span><br><span class="line"><span class="keyword">long</span> tv_usec; <span class="comment">/* 微妙 */</span></span><br><span class="line">>};</span><br></pre></td></tr></table></figure><p>比如现在要从一个设备文件中读取数据,那么就可以定义一个 <code>fd_set</code> 变量,这个变量要传递给参数 <code>readfds</code>。当我们定义好一个 <code>fd_set</code> 变量以后可以使用如下所示几个宏进行操作</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">><span class="function"><span class="keyword">void</span> <span class="title">FD_ZERO</span><span class="params">(fd_set *<span class="built_in">set</span>)</span></span>;</span><br><span class="line">><span class="function"><span class="keyword">void</span> <span class="title">FD_SET</span><span class="params">(<span class="keyword">int</span> fd, fd_set *<span class="built_in">set</span>)</span></span>;</span><br><span class="line">><span class="function"><span class="keyword">void</span> <span class="title">FD_CLR</span><span class="params">(<span class="keyword">int</span> fd, fd_set *<span class="built_in">set</span>)</span></span>;</span><br><span class="line">><span class="function"><span class="keyword">int</span> <span class="title">FD_ISSET</span><span class="params">(<span class="keyword">int</span> fd, fd_set *<span class="built_in">set</span>)</span></span>;</span><br></pre></td></tr></table></figure><p><code>FD_ZERO</code> 用于将 <code>fd_set</code> 变量的所有位都清零, <code>FD_SET</code> 用于将 <code>fd_set</code> 变量的某个位置 <code>1</code>,也就是向 <code>fd_set</code> 添加一个文件描述符,参数 <code>fd</code> 就是要加入的文件描述符。<code>FD_CLR</code> 用于将<code>fd_set</code>变量的某个位清零,也就是将一个文件描述符从 <code>fd_set</code>中删除,参数 <code>fd</code> 就是要删除的文件描述符。 <code>FD_ISSET</code> 用于测试一个文件是否属于某个集合,参数 <code>fd</code> 就是要判断的文件描述符。</p><p>使用 <code>select</code> 函数对某个设备驱动文件进行读非阻塞访问的操作示例如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function">></span>{</span><br><span class="line"><span class="keyword">int</span> ret, fd; <span class="comment">/* 要监视的文件描述符 */</span></span><br><span class="line">fd_set readfds; <span class="comment">/* 读操作文件描述符集 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timeval</span> <span class="title">timeout</span>;</span><span class="comment">/* 超时结构体 */</span></span><br><span class="line"></span><br><span class="line">fd = <span class="built_in">open</span>(<span class="string">"dev_xxx"</span>, O_RDWR | O_NONBLOCK); <span class="comment">/* 非阻塞式访问 */</span></span><br><span class="line"></span><br><span class="line">FD_ZERO(&readfds); <span class="comment">/* 清除 readfds */</span></span><br><span class="line">FD_SET(fd, &readfds); <span class="comment">/* 将 fd 添加到 readfds 里面 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 构造超时时间 */</span></span><br><span class="line">timeout.tv_sec = <span class="number">0</span>;</span><br><span class="line">timeout.tv_usec = <span class="number">500000</span>; <span class="comment">/* 500ms */</span></span><br><span class="line"></span><br><span class="line">ret = select(fd + <span class="number">1</span>, &readfds, <span class="literal">NULL</span>, <span class="literal">NULL</span>, &timeout);</span><br><span class="line"><span class="keyword">switch</span> (ret) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">0</span>: <span class="comment">/* 超时 */</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"timeout!\r\n"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">-1</span>: <span class="comment">/* 错误 */</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"error!\r\n"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>: <span class="comment">/* 可以读取数据 */</span></span><br><span class="line"> <span class="keyword">if</span>(FD_ISSET(fd, &readfds)) { <span class="comment">/* 判断是否为 fd 文件描述符 */</span></span><br><span class="line"> <span class="comment">/* 使用 read 函数读取数据 */</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line">>}</span><br></pre></td></tr></table></figure></blockquote></li><li><p><code>poll</code>函数</p><blockquote><p>在单个线程中, <code>select</code> 函数能够监视的文件描述符数量有最大的限制,一般为 <code>1024</code>,可以修改内核将监视的文件描述符数量改大,但是这样会降低效率!这个时候就可以使用 <code>poll</code> 函数, <code>poll</code> 函数本质上和 <code>select</code> 没有太大的差别,但是 <code>poll</code> 函数没有最大文件描述符限制。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param fds 要监视的文件描述符集合以及要监视的事件,为一个数组</span></span><br><span class="line"><span class="comment"> * @param nfds poll函数要监视的文件描述符数量</span></span><br><span class="line"><span class="comment"> * @param timeout 超时时间,单位为 ms。</span></span><br><span class="line"><span class="comment"> * @return 返回 revents 域中不为 0 的 pollfd 结构体个数,也就是发生事件或错误的文件描述符数量;0,超时;-1,发生错误,并且设置 errno 为错误类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">poll</span><span class="params">(struct pollfd *fds, <span class="keyword">nfds_t</span> nfds, <span class="keyword">int</span> timeout)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* pollfd 结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">pollfd</span> {</span></span><br><span class="line"> <span class="keyword">int</span> fd; <span class="comment">/* 文件描述符 */</span></span><br><span class="line"> short events; <span class="comment">/* 请求的事件 */</span></span><br><span class="line"> short revents; <span class="comment">/* 返回的事件 */</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p><code>pollfd</code> 结构体中 <code>fd</code> 是要监视的文件描述符,如果 <code>fd</code> 无效的话那么 <code>events</code> 监视事件也就无效,并且 <code>revents</code>返回 <code>0</code>。 <code>events</code>是要监视的事件,可监视的事件类型如下所示, <code>revents</code> 是返回参数,也就是返回的事件, 由 <code>Linux</code> 内核设置具体的返回事件</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">POLLIN <span class="comment">/* 有数据可以读取。*/</span></span><br><span class="line">POLLPRI <span class="comment">/* 有紧急的数据需要读取。 */</span></span><br><span class="line">POLLOUT <span class="comment">/* 可以写数据。 */</span></span><br><span class="line">POLLERR <span class="comment">/* 指定的文件描述符发生错误。 */</span></span><br><span class="line">POLLHUP <span class="comment">/* 指定的文件描述符挂起。 */</span></span><br><span class="line">POLLNVAL <span class="comment">/* 无效的请求。 */</span></span><br><span class="line">POLLRDNORM <span class="comment">/* 等同于 POLLIN */</span></span><br></pre></td></tr></table></figure><p>使用 <code>poll</code> 函数对某个设备驱动文件进行读非阻塞访问的操作示例如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> ret;</span><br><span class="line"> <span class="keyword">int</span> fd;<span class="comment">/* 要监视的文件描述符 */</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">pollfd</span> <span class="title">fds</span>;</span></span><br><span class="line"></span><br><span class="line"> fd = <span class="built_in">open</span>(filename, O_RDWR | O_NONBLOCK);<span class="comment">/* 非阻塞式访问 */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 构造结构体 */</span></span><br><span class="line"> fds.fd = fd;</span><br><span class="line"> fds.events = POLLIN;<span class="comment">/* 监视数据是否可以读取 */</span></span><br><span class="line"></span><br><span class="line"> ret = poll(&fds, <span class="number">1</span>, <span class="number">500</span>);<span class="comment">/* 轮询文件是否可操作,超时 500ms */</span></span><br><span class="line"> <span class="keyword">if</span> (ret) { <span class="comment">/* 数据有效 */</span></span><br><span class="line"> ......</span><br><span class="line"> <span class="comment">/* 读取数据 */</span></span><br><span class="line"> ......</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (ret == <span class="number">0</span>) {<span class="comment">/* 超时 */</span></span><br><span class="line"> ......</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (ret < <span class="number">0</span>) {<span class="comment">/* 错误 */</span></span><br><span class="line"> ......</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></blockquote></li><li><p><code>epoll</code>函数</p><blockquote><p>传统的 <code>selcet</code> 和 <code>poll</code> 函数都会随着所监听的 <code>fd</code> 数量的增加,出现效率低下的问题,而且 <code>poll</code> 函数每次必须遍历所有的描述符来检查就绪的描述符,这个过程很浪费时间。为此, <code>epoll</code> 应运而生, <code>epoll</code> 就是为处理大并发而准备的,一般常常在网络编程中使用 <code>epoll</code> 函数。应用程序需要先使用 <code>epoll_create</code> 函数创建一个 <code>epoll</code> 句柄。</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"> ><span class="comment">/**</span></span><br><span class="line"><span class="comment">* @param size 从Linux2.6.8开始此参数已无意义,随便填写一个大于0的值即可。</span></span><br><span class="line"><span class="comment">* @return epoll句柄,如果为-1的话表示创建失败。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"> >int epoll_create(int size);</span><br></pre></td></tr></table></figure><p><code>epoll</code> 句柄创建成功以后使用 <code>epoll_ctl</code> 函数向其中添加要监视的文件描述符以及监视的事件。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"> ><span class="comment">/**</span></span><br><span class="line"><span class="comment">* @param epfd 要操作的epoll句柄,也就是使用epoll_create函数创建的epoll句柄。</span></span><br><span class="line"><span class="comment">* @param op 表示要对 epfd(epoll 句柄)进行的操作。</span></span><br><span class="line"><span class="comment">* @param fd 要监视的文件描述符。</span></span><br><span class="line"><span class="comment">* @param event 要监视的事件类型。</span></span><br><span class="line"><span class="comment">* @return 0,成功; -1,失败,并且设置 errno 的值为相应的错误码。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"> ><span class="function"><span class="keyword">int</span> <span class="title">epoll_ctl</span><span class="params">(<span class="keyword">int</span> epfd, <span class="keyword">int</span> op, <span class="keyword">int</span> fd, struct epoll_event *event)</span></span>;</span><br><span class="line"></span><br><span class="line"> ><span class="comment">/* op 可以选择的设置 */</span></span><br><span class="line"> >EPOLL_CTL_ADD <span class="comment">// 向 epfd 添加文件参数 fd 表示的描述符。</span></span><br><span class="line"> >EPOLL_CTL_MOD <span class="comment">// 修改参数 fd 的 event 事件。</span></span><br><span class="line"> >EPOLL_CTL_DEL <span class="comment">// 从 epfd 中删除 fd 描述符。</span></span><br><span class="line"></span><br><span class="line"> ><span class="comment">/* epoll_event 结构体 */</span></span><br><span class="line"> ><span class="class"><span class="keyword">struct</span> <span class="title">epoll_event</span> {</span></span><br><span class="line"> <span class="keyword">uint32_t</span> events;<span class="comment">/* epoll 事件 */</span></span><br><span class="line"> <span class="keyword">epoll_data_t</span> data;<span class="comment">/* 用户数据 */</span></span><br><span class="line"> >};</span><br></pre></td></tr></table></figure><p>结构体 <code>epoll_event</code> 的 <code>events</code> 成员变量表示要监视的事件,可选的事件如下,彼此之间可以进行或操作:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">>EPOLLIN<span class="comment">// 有数据可以读取。</span></span><br><span class="line">>EPOLLOUT<span class="comment">// 可以写数据。</span></span><br><span class="line">>EPOLLPRI<span class="comment">// 有紧急的数据需要读取。</span></span><br><span class="line">>EPOLLERR<span class="comment">// 指定的文件描述符发生错误。</span></span><br><span class="line">>EPOLLHUP<span class="comment">// 指定的文件描述符挂起。</span></span><br><span class="line">>EPOLLET<span class="comment">// 设置 epoll 为边沿触发,默认触发模式为水平触发。</span></span><br><span class="line">>EPOLLONESHOT<span class="comment">// 一次性的监视,当监视完成以后还需要再次监视某个 fd,那么就需要将 fd 重新添加到 epoll 里面。</span></span><br></pre></td></tr></table></figure><p>一切都设置好以后应用程序就可以通过 <code>epoll_wait</code> 函数来等待事件的发生,类似 <code>select</code> 函数。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"> ><span class="comment">/**</span></span><br><span class="line"><span class="comment">* @param epfd 要等待的 epoll</span></span><br><span class="line"><span class="comment">* @param events 指向 epoll_event 结构体的数组,当有事件发生的时候 Linux 内核会填写 events,调</span></span><br><span class="line"><span class="comment"> >用者可以根据 events 判断发生了哪些事件。</span></span><br><span class="line"><span class="comment">* @param maxevents events 数组大小,必须大于0</span></span><br><span class="line"><span class="comment">* @param timeout 超时时间,单位为ms。</span></span><br><span class="line"><span class="comment">* @return 0,超时;-1,错误;其他值,准备就绪的文件描述符数量。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"> ><span class="function"><span class="keyword">int</span> <span class="title">epoll_wait</span><span class="params">(<span class="keyword">int</span> epfd, struct epoll_event *events, <span class="keyword">int</span> maxevents, <span class="keyword">int</span> timeout)</span></span>;</span><br></pre></td></tr></table></figure><p><strong><code>epoll</code> 更多的是用在大规模的并发服务器上,因为在这种场合下 <code>select</code> 和 <code>poll</code> 并不适合,当设计到的文件描述符(<code>fd</code>)比较少的时候就适合用 <code>selcet</code> 和 <code>poll</code>。</strong></p></blockquote></li></ol><h2 id="二、编写试验驱动"><a href="#二、编写试验驱动" class="headerlink" title="二、编写试验驱动"></a>二、编写试验驱动</h2><h3 id="2-1-阻塞式访问驱动"><a href="#2-1-阻塞式访问驱动" class="headerlink" title="2.1 阻塞式访问驱动"></a>2.1 阻塞式访问驱动</h3><ol><li>等待事件</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/interrupt.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_NAME<span class="meta-string">"keyirq"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY_NUM1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY0_VALUE0X01</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> INVAKEY0XFF<span class="comment">/* 无效按键值 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">int</span> gpio;<span class="comment">/* IO编号 */</span></span><br><span class="line"><span class="keyword">int</span> irqNum;<span class="comment">/* 中断号 */</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> value;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">char</span> name[<span class="number">10</span>];<span class="comment">/* 名称 */</span></span><br><span class="line"><span class="keyword">irqreturn_t</span> (*handler)(<span class="keyword">int</span>, <span class="keyword">void</span>*);<span class="comment">/* 中断处理函数 */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span> <span class="title">tasklet</span>;</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">/* 设备ID */</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">/* 主设备号 */</span></span><br><span class="line"><span class="keyword">int</span> minor;<span class="comment">/* 次设备号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span><span class="comment">/* 字符设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">/* 设备类 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">/* 设备节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span><span class="comment">/* 设备树节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span> <span class="title">key</span>[<span class="title">KEY_NUM</span>];</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定时器 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">atomic_t</span> keyValue;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">atomic_t</span> keyRelease;<span class="comment">/* 按键是否释放 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">wait_queue_head_t</span> r_wait;<span class="comment">/* 读等待队列头 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> <span class="title">keyirq</span>;</span><span class="comment">/* 定义一个keyirq设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &keyirq;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_read</span><span class="params">(struct file *filp, <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyValue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyRelease;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 等待事件 */</span></span><br><span class="line">wait_event_interruptible(dev->r_wait, atomic_read(&dev->keyRelease));</span><br><span class="line"></span><br><span class="line"><span class="comment">// <span class="doctag">NOTE:</span>wait_event 不可以被信号打断,使用 kill -9 PID 无法杀掉任务</span></span><br><span class="line"><span class="comment">// wait_event(dev->r_wait, atomic_read(&dev->keyRelease));/* 等待按键值有效 */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">keyValue = atomic_read(&dev->keyValue);</span><br><span class="line">keyRelease = atomic_read(&dev->keyRelease);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (keyRelease)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 一次有效按键 */</span></span><br><span class="line"><span class="keyword">if</span> (keyValue & <span class="number">0X80</span>)</span><br><span class="line">{</span><br><span class="line">keyValue &= ~<span class="number">0X80</span>;<span class="comment">// 去除标记</span></span><br><span class="line">ret = copy_to_user(buf, &keyValue, <span class="keyword">sizeof</span>(keyValue));</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">0</span>);</span><br><span class="line">} </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">data_err:</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 操作集 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">keyirq_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = keyirq_open,</span><br><span class="line">.<span class="built_in">release</span> = keyirq_release,</span><br><span class="line">.<span class="built_in">write</span> = keyirq_write,</span><br><span class="line">.<span class="built_in">read</span> = keyirq_read,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 定时器处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 用户参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_func</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span>*)<span class="title">arg</span>;</span></span><br><span class="line"><span class="keyword">int</span> value = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">value = gpio_get_value(dev->key[<span class="number">0</span>].gpio);</span><br><span class="line"><span class="keyword">if</span> (value == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键按下</span></span><br><span class="line">printk(<span class="string">"KEY0 Press!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(value == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键释放</span></span><br><span class="line">printk(<span class="string">"KEY0 Release!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value | <span class="number">0X80</span>);<span class="comment">// 打上标签,标记按键按下</span></span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 唤醒进程 */</span></span><br><span class="line"><span class="keyword">if</span>(atomic_read(&dev->keyRelease))</span><br><span class="line">{</span><br><span class="line">wake_up(&dev->r_wait);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief key0 tasklet 处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 传递的参数</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">key0_tasklet</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span> *)<span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 启动定时器来延时消抖 */</span></span><br><span class="line">dev->timer.data = (<span class="keyword">volatile</span> <span class="keyword">unsigned</span> <span class="keyword">long</span>)arg;</span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(<span class="number">20</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键中断处理函数</span></span><br><span class="line"><span class="comment"> * @param irq 中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">irqreturn_t</span> <span class="title">key0_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line">tasklet_schedule(&dev->key[<span class="number">0</span>].tasklet);<span class="comment">/* 调度对应的tasklet */</span></span><br><span class="line"><span class="keyword">return</span> IRQ_HANDLED;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键初始化</span></span><br><span class="line"><span class="comment"> * @param dev 设备结构体</span></span><br><span class="line"><span class="comment"> * @return 错误类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyio_init</span><span class="params">(struct keyirq_dev *dev)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键初始化 */</span></span><br><span class="line">dev->nd = of_find_node_by_path(<span class="string">"/key"</span>);</span><br><span class="line"><span class="keyword">if</span> (dev->nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_nd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 可能有多个按键,因此需要根据实际数量来读取 */</span></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line">dev->key[i].gpio = of_get_named_gpio(dev->nd, <span class="string">"key-gpios"</span>, i);</span><br><span class="line"><span class="keyword">if</span> (dev->key[i].gpio < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_getGpio;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">memset</span>(dev->key[i].name, <span class="number">0</span>, <span class="keyword">sizeof</span>(dev->key[i].name));</span><br><span class="line"><span class="built_in">sprintf</span>(dev->key[i].name, <span class="string">"KEY%d"</span>, i);</span><br><span class="line">ret = gpio_request(dev->key[i].gpio, dev->key[i].name);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_requestGpio;</span><br><span class="line">}</span><br><span class="line">ret = gpio_direction_input(dev->key[i].gpio);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setGpioDir;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取中断号,两种方式皆可 */</span></span><br><span class="line">dev->key[i].irqNum = gpio_to_irq(dev->key[i].gpio);</span><br><span class="line"><span class="comment">// dev->key[i].irqNum = irq_of_parse_and_map(dev->nd, i);</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键中断初始化 */</span></span><br><span class="line">dev->key[<span class="number">0</span>].handler = key0_handler;</span><br><span class="line">dev->key[<span class="number">0</span>].value = KEY0_VALUE;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 跳变沿触发方式 */</span></span><br><span class="line">ret = request_irq(dev->key[i].irqNum, dev->key[i].handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev->key[i].name, dev);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"irq %d request failed!\r\n"</span>, dev->key[i].irqNum);</span><br><span class="line"><span class="keyword">goto</span> fail_irq;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>没有根据多个按键来初始化各自的tasklet,实际中需要根据情况来编写 */</span></span><br><span class="line">tasklet_init(&dev->key[i].tasklet, key0_tasklet, (<span class="keyword">unsigned</span> <span class="keyword">long</span>)dev);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化定时器 */</span></span><br><span class="line">init_timer(&dev->timer);</span><br><span class="line">dev->timer.function = timer_func;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_irq:</span><br><span class="line">fail_setGpioDir:</span><br><span class="line"><span class="keyword">for</span> (i = i<span class="number">-1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line">{</span><br><span class="line">gpio_free(dev->key[i].gpio);</span><br><span class="line">}</span><br><span class="line">fail_requestGpio:</span><br><span class="line">fail_getGpio:</span><br><span class="line">fail_nd:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">keyirq_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">keyirq.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(keyirq.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">keyirq.devid = MKDEV(keyirq.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(keyirq.devid, KEYIRQ_CNT, KEYIRQ_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&keyirq.devid, <span class="number">0</span>,KEYIRQ_CNT,KEYIRQ_NAME);</span><br><span class="line">keyirq.major = MAJOR(keyirq.devid);</span><br><span class="line">keyirq.minor = MINOR(keyirq.devid);</span><br><span class="line">printk(<span class="string">"dev Major ID:%d\r\n"</span>,keyirq.major);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">keyirq.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&keyirq.cdev, &keyirq_fops);</span><br><span class="line">ret = cdev_add(&keyirq.cdev, keyirq.devid, KEYIRQ_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备类 */</span></span><br><span class="line">keyirq<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">KEYIRQ_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">keyirq.device = device_create(keyirq.class, <span class="literal">NULL</span>, keyirq.devid, <span class="literal">NULL</span>, KEYIRQ_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化IO */</span></span><br><span class="line">ret = keyio_init(&keyirq);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_init;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化原子变量 */</span></span><br><span class="line">atomic_set(&keyirq.keyValue, INVAKEY);</span><br><span class="line">atomic_set(&keyirq.keyRelease, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化等待队列头 */</span></span><br><span class="line">init_waitqueue_head(&keyirq.r_wait);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_init:</span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(keyirq.devid, KEYIRQ_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">keyirq_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 释放中断和IO */</span></span><br><span class="line">free_irq(keyirq.key[i].irqNum, &keyirq);</span><br><span class="line">gpio_free(keyirq.key[i].gpio);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 删除定时器 */</span></span><br><span class="line">del_timer_sync(&keyirq.timer);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注销字符设备驱动 */</span></span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">unregister_chrdev_region(keyirq.devid,KEYIRQ_CNT);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(keyirq_init);</span><br><span class="line">module_exit(keyirq_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><ol start="2"><li>等待队列项</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/interrupt.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_NAME<span class="meta-string">"keyirq"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY_NUM1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY0_VALUE0X01</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> INVAKEY0XFF<span class="comment">/* 无效按键值 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">int</span> gpio;<span class="comment">/* IO编号 */</span></span><br><span class="line"><span class="keyword">int</span> irqNum;<span class="comment">/* 中断号 */</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> value;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">char</span> name[<span class="number">10</span>];<span class="comment">/* 名称 */</span></span><br><span class="line"><span class="keyword">irqreturn_t</span> (*handler)(<span class="keyword">int</span>, <span class="keyword">void</span>*);<span class="comment">/* 中断处理函数 */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span> <span class="title">tasklet</span>;</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">/* 设备ID */</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">/* 主设备号 */</span></span><br><span class="line"><span class="keyword">int</span> minor;<span class="comment">/* 次设备号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span><span class="comment">/* 字符设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">/* 设备类 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">/* 设备节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span><span class="comment">/* 设备树节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span> <span class="title">key</span>[<span class="title">KEY_NUM</span>];</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定时器 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">atomic_t</span> keyValue;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">atomic_t</span> keyRelease;<span class="comment">/* 按键是否释放 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">wait_queue_head_t</span> r_wait;<span class="comment">/* 读等待队列头 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> <span class="title">keyirq</span>;</span><span class="comment">/* 定义一个keyirq设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &keyirq;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_read</span><span class="params">(struct file *filp, <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyValue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyRelease;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line"><span class="comment">/* 等待事件 */</span></span><br><span class="line">wait_event_interruptible(dev->r_wait, atomic_read(&dev->keyRelease));<span class="comment">/* 等待按键值有效 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// <span class="doctag">NOTE:</span>wait_event 不可以被信号打断,使用 kill -9 PID 无法杀掉任务</span></span><br><span class="line"><span class="comment">// wait_event(dev->r_wait, atomic_read(&dev->keyRelease));/* 等待按键值有效 */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="comment">/* 等待队列项 */</span></span><br><span class="line">DECLARE_WAITQUEUE(wait, current);<span class="comment">/* 定义一个等待队列项 */</span></span><br><span class="line"></span><br><span class="line">add_wait_queue(&dev->r_wait, &wait);<span class="comment">/* 将等待队列项添加到等待队列头中 */</span></span><br><span class="line">__set_current_state(TASK_INTERRUPTIBLE);<span class="comment">/* 设置当前进程为可以被打断的状态 */</span></span><br><span class="line">schedule();<span class="comment">/* 切换 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 唤醒后,进程从这里运行 */</span></span><br><span class="line"><span class="keyword">if</span> (signal_pending(current))<span class="comment">/* 判断当前进程是否有信号需要处理,返回值不为零表示有信号需要进行处理 */</span></span><br><span class="line">{</span><br><span class="line">ret = -ERESTARTSYS;</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">keyValue = atomic_read(&dev->keyValue);</span><br><span class="line">keyRelease = atomic_read(&dev->keyRelease);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (keyRelease)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 一次有效按键 */</span></span><br><span class="line"><span class="keyword">if</span> (keyValue & <span class="number">0X80</span>)</span><br><span class="line">{</span><br><span class="line">keyValue &= ~<span class="number">0X80</span>;<span class="comment">// 去除标记</span></span><br><span class="line">ret = copy_to_user(buf, &keyValue, <span class="keyword">sizeof</span>(keyValue));</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">0</span>);</span><br><span class="line">} </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">data_err:</span><br><span class="line">__set_current_state(TASK_RUNNING);<span class="comment">/* 设置当前任务为运行状态 */</span></span><br><span class="line">remove_wait_queue(&dev->r_wait, &wait);<span class="comment">/* 将对应的队列项从等待队列头删除 */</span></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 操作集 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">keyirq_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = keyirq_open,</span><br><span class="line">.<span class="built_in">release</span> = keyirq_release,</span><br><span class="line">.<span class="built_in">write</span> = keyirq_write,</span><br><span class="line">.<span class="built_in">read</span> = keyirq_read,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 定时器处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 用户参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_func</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span>*)<span class="title">arg</span>;</span></span><br><span class="line"><span class="keyword">int</span> value = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">value = gpio_get_value(dev->key[<span class="number">0</span>].gpio);</span><br><span class="line"><span class="keyword">if</span> (value == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键按下</span></span><br><span class="line">printk(<span class="string">"KEY0 Press!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(value == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键释放</span></span><br><span class="line">printk(<span class="string">"KEY0 Release!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value | <span class="number">0X80</span>);<span class="comment">// 打上标签,标记按键按下</span></span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 唤醒进程 */</span></span><br><span class="line"><span class="keyword">if</span>(atomic_read(&dev->keyRelease))</span><br><span class="line">{</span><br><span class="line">wake_up(&dev->r_wait);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief key0 tasklet 处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 传递的参数</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">key0_tasklet</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span> *)<span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 启动定时器来延时消抖 */</span></span><br><span class="line">dev->timer.data = (<span class="keyword">volatile</span> <span class="keyword">unsigned</span> <span class="keyword">long</span>)arg;</span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(<span class="number">20</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键中断处理函数</span></span><br><span class="line"><span class="comment"> * @param irq 中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">irqreturn_t</span> <span class="title">key0_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line">tasklet_schedule(&dev->key[<span class="number">0</span>].tasklet);<span class="comment">/* 调度对应的tasklet */</span></span><br><span class="line"><span class="keyword">return</span> IRQ_HANDLED;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键初始化</span></span><br><span class="line"><span class="comment"> * @param dev 设备结构体</span></span><br><span class="line"><span class="comment"> * @return 错误类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyio_init</span><span class="params">(struct keyirq_dev *dev)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键初始化 */</span></span><br><span class="line">dev->nd = of_find_node_by_path(<span class="string">"/key"</span>);</span><br><span class="line"><span class="keyword">if</span> (dev->nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_nd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 可能有多个按键,因此需要根据实际数量来读取 */</span></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line">dev->key[i].gpio = of_get_named_gpio(dev->nd, <span class="string">"key-gpios"</span>, i);</span><br><span class="line"><span class="keyword">if</span> (dev->key[i].gpio < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_getGpio;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">memset</span>(dev->key[i].name, <span class="number">0</span>, <span class="keyword">sizeof</span>(dev->key[i].name));</span><br><span class="line"><span class="built_in">sprintf</span>(dev->key[i].name, <span class="string">"KEY%d"</span>, i);</span><br><span class="line">ret = gpio_request(dev->key[i].gpio, dev->key[i].name);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_requestGpio;</span><br><span class="line">}</span><br><span class="line">ret = gpio_direction_input(dev->key[i].gpio);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setGpioDir;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取中断号,两种方式皆可 */</span></span><br><span class="line">dev->key[i].irqNum = gpio_to_irq(dev->key[i].gpio);</span><br><span class="line"><span class="comment">// dev->key[i].irqNum = irq_of_parse_and_map(dev->nd, i);</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键中断初始化 */</span></span><br><span class="line">dev->key[<span class="number">0</span>].handler = key0_handler;</span><br><span class="line">dev->key[<span class="number">0</span>].value = KEY0_VALUE;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 跳变沿触发方式 */</span></span><br><span class="line">ret = request_irq(dev->key[i].irqNum, dev->key[i].handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev->key[i].name, dev);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"irq %d request failed!\r\n"</span>, dev->key[i].irqNum);</span><br><span class="line"><span class="keyword">goto</span> fail_irq;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>没有根据多个按键来初始化各自的tasklet,实际中需要根据情况来编写 */</span></span><br><span class="line">tasklet_init(&dev->key[i].tasklet, key0_tasklet, (<span class="keyword">unsigned</span> <span class="keyword">long</span>)dev);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化定时器 */</span></span><br><span class="line">init_timer(&dev->timer);</span><br><span class="line">dev->timer.function = timer_func;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_irq:</span><br><span class="line">fail_setGpioDir:</span><br><span class="line"><span class="keyword">for</span> (i = i<span class="number">-1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line">{</span><br><span class="line">gpio_free(dev->key[i].gpio);</span><br><span class="line">}</span><br><span class="line">fail_requestGpio:</span><br><span class="line">fail_getGpio:</span><br><span class="line">fail_nd:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">keyirq_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">keyirq.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(keyirq.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">keyirq.devid = MKDEV(keyirq.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(keyirq.devid, KEYIRQ_CNT, KEYIRQ_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&keyirq.devid, <span class="number">0</span>,KEYIRQ_CNT,KEYIRQ_NAME);</span><br><span class="line">keyirq.major = MAJOR(keyirq.devid);</span><br><span class="line">keyirq.minor = MINOR(keyirq.devid);</span><br><span class="line">printk(<span class="string">"dev Major ID:%d\r\n"</span>,keyirq.major);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">keyirq.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&keyirq.cdev, &keyirq_fops);</span><br><span class="line">ret = cdev_add(&keyirq.cdev, keyirq.devid, KEYIRQ_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备类 */</span></span><br><span class="line">keyirq<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">KEYIRQ_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">keyirq.device = device_create(keyirq.class, <span class="literal">NULL</span>, keyirq.devid, <span class="literal">NULL</span>, KEYIRQ_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化IO */</span></span><br><span class="line">ret = keyio_init(&keyirq);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_init;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化原子变量 */</span></span><br><span class="line">atomic_set(&keyirq.keyValue, INVAKEY);</span><br><span class="line">atomic_set(&keyirq.keyRelease, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化等待队列头 */</span></span><br><span class="line">init_waitqueue_head(&keyirq.r_wait);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_init:</span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(keyirq.devid, KEYIRQ_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">keyirq_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 释放中断和IO */</span></span><br><span class="line">free_irq(keyirq.key[i].irqNum, &keyirq);</span><br><span class="line">gpio_free(keyirq.key[i].gpio);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 删除定时器 */</span></span><br><span class="line">del_timer_sync(&keyirq.timer);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注销字符设备驱动 */</span></span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">unregister_chrdev_region(keyirq.devid,KEYIRQ_CNT);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(keyirq_init);</span><br><span class="line">module_exit(keyirq_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h3 id="2-2-非阻塞式访问"><a href="#2-2-非阻塞式访问" class="headerlink" title="2.2 非阻塞式访问"></a>2.2 非阻塞式访问</h3><ol><li>驱动程序</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/interrupt.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/poll.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_NAME<span class="meta-string">"keyirq"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY_NUM1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY0_VALUE0X01</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> INVAKEY0XFF<span class="comment">/* 无效按键值 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">int</span> gpio;<span class="comment">/* IO编号 */</span></span><br><span class="line"><span class="keyword">int</span> irqNum;<span class="comment">/* 中断号 */</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> value;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">char</span> name[<span class="number">10</span>];<span class="comment">/* 名称 */</span></span><br><span class="line"><span class="keyword">irqreturn_t</span> (*handler)(<span class="keyword">int</span>, <span class="keyword">void</span>*);<span class="comment">/* 中断处理函数 */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span> <span class="title">tasklet</span>;</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">/* 设备ID */</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">/* 主设备号 */</span></span><br><span class="line"><span class="keyword">int</span> minor;<span class="comment">/* 次设备号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span><span class="comment">/* 字符设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">/* 设备类 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">/* 设备节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span><span class="comment">/* 设备树节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span> <span class="title">key</span>[<span class="title">KEY_NUM</span>];</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定时器 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">atomic_t</span> keyValue;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">atomic_t</span> keyRelease;<span class="comment">/* 按键是否释放 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">wait_queue_head_t</span> r_wait;<span class="comment">/* 读等待队列头 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> <span class="title">keyirq</span>;</span><span class="comment">/* 定义一个keyirq设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &keyirq;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_read</span><span class="params">(struct file *filp, <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyValue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyRelease;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(filp->f_flags & O_NONBLOCK) </span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 非阻塞方式访问 */</span></span><br><span class="line"><span class="keyword">if</span>(atomic_read(&dev->keyRelease) == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> -EAGAIN;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 阻塞访问方式 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 等待事件 */</span></span><br><span class="line">wait_event_interruptible(dev->r_wait, atomic_read(&dev->keyRelease));<span class="comment">/* 等待按键值有效 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// <span class="doctag">NOTE:</span>wait_event 不可以被信号打断,使用 kill -9 PID 无法杀掉任务</span></span><br><span class="line"><span class="comment">// wait_event(dev->r_wait, atomic_read(&dev->keyRelease));/* 等待按键值有效 */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line">DECLARE_WAITQUEUE(wait, current);<span class="comment">/* 定义一个等待队列项 */</span></span><br><span class="line">add_wait_queue(&dev->r_wait, &wait);<span class="comment">/* 将等待队列项添加到等待队列头中 */</span></span><br><span class="line">__set_current_state(TASK_INTERRUPTIBLE);<span class="comment">/* 设置当前进程为可以被打断的状态 */</span></span><br><span class="line">schedule();<span class="comment">/* 切换 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 唤醒后,进程从这里运行 */</span></span><br><span class="line"><span class="keyword">if</span> (signal_pending(current))<span class="comment">/* 判断当前进程是否有信号需要处理,返回值不为零表示有信号需要进行处理 */</span></span><br><span class="line">{</span><br><span class="line">ret = -ERESTARTSYS;</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">keyValue = atomic_read(&dev->keyValue);</span><br><span class="line">keyRelease = atomic_read(&dev->keyRelease);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (keyRelease)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 一次有效按键 */</span></span><br><span class="line"><span class="keyword">if</span> (keyValue & <span class="number">0X80</span>)</span><br><span class="line">{</span><br><span class="line">keyValue &= ~<span class="number">0X80</span>;<span class="comment">// 去除标记</span></span><br><span class="line">ret = copy_to_user(buf, &keyValue, <span class="keyword">sizeof</span>(keyValue));</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">0</span>);</span><br><span class="line">} </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">data_err:</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line">__set_current_state(TASK_RUNNING);<span class="comment">/* 设置当前任务为运行状态 */</span></span><br><span class="line">remove_wait_queue(&dev->r_wait, &wait);<span class="comment">/* 将对应的队列项从等待队列头删除 */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="title">keyirq_poll</span><span class="params">(struct file *filp, struct poll_table_struct *wait)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> mask = <span class="number">0</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line">poll_wait(filp, &dev->r_wait, wait);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 是否可读 */</span></span><br><span class="line"><span class="keyword">if</span> (atomic_read(&dev->keyRelease))</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 按键按下,可读 */</span></span><br><span class="line">mask = POLL_IN | POLLRDNORM;<span class="comment">/* 返回POLL_IN */</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> mask;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 操作集 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">keyirq_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = keyirq_open,</span><br><span class="line">.<span class="built_in">release</span> = keyirq_release,</span><br><span class="line">.<span class="built_in">write</span> = keyirq_write,</span><br><span class="line">.<span class="built_in">read</span> = keyirq_read,</span><br><span class="line">.poll = keyirq_poll, </span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 定时器处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 用户参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_func</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span>*)<span class="title">arg</span>;</span></span><br><span class="line"><span class="keyword">int</span> value = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">value = gpio_get_value(dev->key[<span class="number">0</span>].gpio);</span><br><span class="line"><span class="keyword">if</span> (value == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键按下</span></span><br><span class="line">printk(<span class="string">"KEY0 Press!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(value == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键释放</span></span><br><span class="line">printk(<span class="string">"KEY0 Release!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value | <span class="number">0X80</span>);<span class="comment">// 打上标签,标记按键按下</span></span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 唤醒进程 */</span></span><br><span class="line"><span class="keyword">if</span>(atomic_read(&dev->keyRelease))</span><br><span class="line">{</span><br><span class="line">wake_up(&dev->r_wait);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief key0 tasklet 处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 传递的参数</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">key0_tasklet</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span> *)<span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 启动定时器来延时消抖 */</span></span><br><span class="line">dev->timer.data = (<span class="keyword">volatile</span> <span class="keyword">unsigned</span> <span class="keyword">long</span>)arg;</span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(<span class="number">20</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键中断处理函数</span></span><br><span class="line"><span class="comment"> * @param irq 中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">irqreturn_t</span> <span class="title">key0_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line">tasklet_schedule(&dev->key[<span class="number">0</span>].tasklet);<span class="comment">/* 调度对应的tasklet */</span></span><br><span class="line"><span class="keyword">return</span> IRQ_HANDLED;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键初始化</span></span><br><span class="line"><span class="comment"> * @param dev 设备结构体</span></span><br><span class="line"><span class="comment"> * @return 错误类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyio_init</span><span class="params">(struct keyirq_dev *dev)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键初始化 */</span></span><br><span class="line">dev->nd = of_find_node_by_path(<span class="string">"/key"</span>);</span><br><span class="line"><span class="keyword">if</span> (dev->nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_nd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 可能有多个按键,因此需要根据实际数量来读取 */</span></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line">dev->key[i].gpio = of_get_named_gpio(dev->nd, <span class="string">"key-gpios"</span>, i);</span><br><span class="line"><span class="keyword">if</span> (dev->key[i].gpio < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_getGpio;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">memset</span>(dev->key[i].name, <span class="number">0</span>, <span class="keyword">sizeof</span>(dev->key[i].name));</span><br><span class="line"><span class="built_in">sprintf</span>(dev->key[i].name, <span class="string">"KEY%d"</span>, i);</span><br><span class="line">ret = gpio_request(dev->key[i].gpio, dev->key[i].name);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_requestGpio;</span><br><span class="line">}</span><br><span class="line">ret = gpio_direction_input(dev->key[i].gpio);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setGpioDir;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取中断号,两种方式皆可 */</span></span><br><span class="line">dev->key[i].irqNum = gpio_to_irq(dev->key[i].gpio);</span><br><span class="line"><span class="comment">// dev->key[i].irqNum = irq_of_parse_and_map(dev->nd, i);</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键中断初始化 */</span></span><br><span class="line">dev->key[<span class="number">0</span>].handler = key0_handler;</span><br><span class="line">dev->key[<span class="number">0</span>].value = KEY0_VALUE;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 跳变沿触发方式 */</span></span><br><span class="line">ret = request_irq(dev->key[i].irqNum, dev->key[i].handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev->key[i].name, dev);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"irq %d request failed!\r\n"</span>, dev->key[i].irqNum);</span><br><span class="line"><span class="keyword">goto</span> fail_irq;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>没有根据多个按键来初始化各自的tasklet,实际中需要根据情况来编写 */</span></span><br><span class="line">tasklet_init(&dev->key[i].tasklet, key0_tasklet, (<span class="keyword">unsigned</span> <span class="keyword">long</span>)dev);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化定时器 */</span></span><br><span class="line">init_timer(&dev->timer);</span><br><span class="line">dev->timer.function = timer_func;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_irq:</span><br><span class="line">fail_setGpioDir:</span><br><span class="line"><span class="keyword">for</span> (i = i<span class="number">-1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line">{</span><br><span class="line">gpio_free(dev->key[i].gpio);</span><br><span class="line">}</span><br><span class="line">fail_requestGpio:</span><br><span class="line">fail_getGpio:</span><br><span class="line">fail_nd:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">keyirq_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">keyirq.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(keyirq.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">keyirq.devid = MKDEV(keyirq.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(keyirq.devid, KEYIRQ_CNT, KEYIRQ_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&keyirq.devid, <span class="number">0</span>,KEYIRQ_CNT,KEYIRQ_NAME);</span><br><span class="line">keyirq.major = MAJOR(keyirq.devid);</span><br><span class="line">keyirq.minor = MINOR(keyirq.devid);</span><br><span class="line">printk(<span class="string">"dev Major ID:%d\r\n"</span>,keyirq.major);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">keyirq.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&keyirq.cdev, &keyirq_fops);</span><br><span class="line">ret = cdev_add(&keyirq.cdev, keyirq.devid, KEYIRQ_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备类 */</span></span><br><span class="line">keyirq<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">KEYIRQ_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">keyirq.device = device_create(keyirq.class, <span class="literal">NULL</span>, keyirq.devid, <span class="literal">NULL</span>, KEYIRQ_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化IO */</span></span><br><span class="line">ret = keyio_init(&keyirq);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_init;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化原子变量 */</span></span><br><span class="line">atomic_set(&keyirq.keyValue, INVAKEY);</span><br><span class="line">atomic_set(&keyirq.keyRelease, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化等待队列头 */</span></span><br><span class="line">init_waitqueue_head(&keyirq.r_wait);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_init:</span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(keyirq.devid, KEYIRQ_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">keyirq_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 释放中断和IO */</span></span><br><span class="line">free_irq(keyirq.key[i].irqNum, &keyirq);</span><br><span class="line">gpio_free(keyirq.key[i].gpio);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 删除定时器 */</span></span><br><span class="line">del_timer_sync(&keyirq.timer);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注销字符设备驱动 */</span></span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">unregister_chrdev_region(keyirq.devid,KEYIRQ_CNT);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(keyirq_init);</span><br><span class="line">module_exit(keyirq_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><ol start="2"><li>测试APP程序</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/ioctl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/select.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/time.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><poll.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ./keyReadAPP /dev/keyirq</span></span><br><span class="line"><span class="comment"> * @param argc 应用程序参数个数</span></span><br><span class="line"><span class="comment"> * @param argv 保存的参数,字符串形式。</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> fd = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">char</span> *filename;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> data;</span><br><span class="line"><span class="comment">/* 使用select */</span></span><br><span class="line"><span class="comment">// fd_set readfds;/* */</span></span><br><span class="line"><span class="comment">// struct timeval timeout;/* 超时时间 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用poll */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">pollfd</span> <span class="title">fds</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">if (argc != 3)</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">printf("输入错误\r\n");</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line">filename = argv[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">fd = <span class="built_in">open</span>(filename, O_RDWR | O_NONBLOCK);<span class="comment">/* 非阻塞方式打开 */</span></span><br><span class="line"><span class="keyword">if</span>(fd < <span class="number">0</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Open %s fail.\r\n"</span>,filename);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 循环读取 */</span></span><br><span class="line"><span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line"><span class="comment">/* 使用select */</span></span><br><span class="line">FD_ZERO(&readfds);</span><br><span class="line">FD_SET(fd, &readfds);</span><br><span class="line"></span><br><span class="line">timeout.tv_sec = <span class="number">0</span>;</span><br><span class="line">timeout.tv_usec = <span class="number">500000</span>;<span class="comment">/* 超时时间500毫秒 */</span></span><br><span class="line">ret = select(fd + <span class="number">1</span>, &readfds, <span class="literal">NULL</span>, <span class="literal">NULL</span>, &timeout);</span><br><span class="line"><span class="keyword">switch</span> (ret)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">case</span> <span class="number">0</span>:<span class="comment">/* 超时 */</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"select 超时\r\n"</span>);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> <span class="number">-1</span>:<span class="comment">/* 错误 */</span></span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">default</span>:<span class="comment">/* 可以读取数据 */</span></span><br><span class="line"><span class="keyword">if</span>(FD_ISSET(fd, &readfds))</span><br><span class="line">{</span><br><span class="line">ret = <span class="built_in">read</span>(fd, &data, <span class="keyword">sizeof</span>(data));</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{ </span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"keyValue = %#x\r\n"</span>, data);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用poll */</span></span><br><span class="line">fds.fd = fd;</span><br><span class="line">fds.events = POLLIN;</span><br><span class="line">ret = poll(&fds, <span class="number">1</span>, <span class="number">500</span>);<span class="comment">/* 超时时间500ms */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 超时 */</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"poll 超时\r\n"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 错误 */</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 可以读取 */</span></span><br><span class="line"><span class="keyword">if</span> (fds.revents | POLLIN)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 可读取 */</span></span><br><span class="line">ret = <span class="built_in">read</span>(fd, &data, <span class="keyword">sizeof</span>(data));</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{ </span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"keyValue = %#x\r\n"</span>, data);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 关闭 */</span></span><br><span class="line">ret = <span class="built_in">close</span>(fd);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Close %s fail.\r\n"</span>, filename);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(九)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B9%9D%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B9%9D%EF%BC%89.html</id>
<published>2021-01-08T03:19:03.000Z</published>
<updated>2021-08-25T14:11:37.985Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><h2 id="一、Linux内核中断处理"><a href="#一、Linux内核中断处理" class="headerlink" title="一、Linux内核中断处理"></a>一、Linux内核中断处理</h2><h3 id="1-1-裸机中断"><a href="#1-1-裸机中断" class="headerlink" title="1.1 裸机中断"></a>1.1 裸机中断</h3><ul><li>使能中断,初始化相应的寄存器。</li><li>注册中断服务函数,也就是向<code>irqTable</code>数组(裸机例程)的指定标号处写入中断服务函数。</li><li>中断发生后进入<code>IRQ</code>中断服务函数,在<code>IRQ</code>中断服务函数中,根据中断号在<code>irqTable</code>里面查找具体的中断处理函数,找到以后执行相应的中断处理函数。</li></ul><a id="more"></a><h3 id="1-2-Linux中断"><a href="#1-2-Linux中断" class="headerlink" title="1.2 Linux中断"></a>1.2 Linux中断</h3><ul><li><p>先知道要使用的中断对应的中断号。</p></li><li><p>根据终端号申请<code>request_irq</code>,<code>request_irq</code>函数可能会导致睡眠,此函数同时会激活中断。</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @param irq 中断号</span></span><br><span class="line"><span class="comment"> * @param handler 中断服务函数 </span></span><br><span class="line"><span class="comment"> * @param flags 中断标志、中断触发方式</span></span><br><span class="line"><span class="comment"> * @param name 中断名字</span></span><br><span class="line"><span class="comment"> * @param dev 使用共享中断时,唯一用来区分的标志。当多个设备共享一个中断线,共享的所有中断都必须指定此标志。</span></span><br><span class="line"><span class="comment"> * @return 0 中断申请成功,其他负值 中断申请失败,如果返回 -EBUSY 的话表示中断已经被申请了。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">request_irq</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> irq, <span class="keyword">irq_handler_t</span> handler, </span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">unsigned</span> <span class="keyword">long</span> flags, <span class="keyword">const</span> <span class="keyword">char</span> *name, <span class="keyword">void</span> *dev)</span></span>;</span><br></pre></td></tr></table></figure></blockquote></li><li><p>不再使用中断时,需要释放中断<code>free_irq</code>。</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @param irq 中断号</span></span><br><span class="line"><span class="comment"> * @param dev 如果中断设置为共享(IRQF_SHARED)的话,此参数用来区分具体的中断。</span></span><br><span class="line"><span class="comment"> * 共享中断只有在释放最后中断处理函数的时候才会被禁止掉。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">free_irq</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> irq, <span class="keyword">void</span> *dev)</span></span>;</span><br></pre></td></tr></table></figure></blockquote></li><li><p>在使用<code>request_irq</code>函数申请中断的时候需要设置中断处理函数,中断处理函数格式如下所示</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">irqreturn_t</span> (*<span class="keyword">irq_handler_t</span>) (<span class="keyword">int</span>, <span class="keyword">void</span> *)</span><br></pre></td></tr></table></figure><p>第一个参数是要中断处理函数要相应的中断号。第二个参数是一个指向 <code>void</code> 的指针,也就是个通用指针,需要与 <code>request_irq</code> 函数的 <code>dev</code> 参数保持一致。用于区分共享中断的不同设备,<code>dev</code> 也可以指向设备数据结构。中断处理函数的返回值为 <code>irqreturn_t</code> 类型, <code>irqreturn_t</code> 类型定义如下所示:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span> irqreturn {</span><br><span class="line"> IRQ_NONE = (<span class="number">0</span> << <span class="number">0</span>),</span><br><span class="line"> IRQ_HANDLED = (<span class="number">1</span> << <span class="number">0</span>),</span><br><span class="line"> IRQ_WAKE_THREAD = (<span class="number">1</span> << <span class="number">1</span>),</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">enum</span> irqreturn <span class="keyword">irqreturn_t</span>;</span><br></pre></td></tr></table></figure><p><code>irqreturn_t</code>是个枚举类型,一共有三种返回值。一般中断服务函数返回值使用如下形式:</p><p><code>return IRQ_RETVAL(IRQ_HANDLED)</code></p></blockquote></li><li><p>中断使能和禁止</p><blockquote><p><code>enable_irq</code> 和 <code>disable_irq</code> 用于使能和禁止指定的中断,<code>irq</code> 就是要禁止的中断号。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">enable_irq</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> irq)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">disable_irq</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> irq)</span></span>;</span><br></pre></td></tr></table></figure><p><code>disable_irq</code>函数要等到当前正在执行的中断处理函数执行完才返回,因此需要保证不会产生新的中断,并且确保所有已经开始执行的中断处理程序已经全部退出。在这种情况下,可以使用另外一个中断禁止函数:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">disable_irq_nosync</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> irq)</span></span></span><br></pre></td></tr></table></figure><p><code>disable_irq_nosync</code> 函数调用以后立即返回,不会等待当前中断处理程序执行完毕。</p><hr><p>上面三个函数都是使能或者禁止某一个中断,有时候我们需要关闭当前处理器的整个中断系统,也就是在学习 <code>STM32</code> 的时候常说的关闭全局中断,这个时候可以使用如下两个函数:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">local_irq_enable();</span><br><span class="line">local_irq_disable();</span><br></pre></td></tr></table></figure><p><code>local_irq_enable</code> 用于使能当前处理器中断系统,<code>local_irq_disable</code>用于禁止当前处理器中断系统。</p><hr><p>但是在任务中使用这两个函数会出现问题。比如假如 <code>A</code> 任务调用 <code>local_irq_disable</code> 关闭全局中断10秒,当关闭了2秒的时候 <code>B</code> 任务开始运行, <code>B</code> 任务也调用 <code>local_irq_disable</code> 关闭全局中断3秒, 3秒以后 <code>B</code> 任务调用 <code>local_irq_enable</code> 函数将全局中断打开了。此时才过去 2+3=5 秒的时间,然后全局中断就被打开了,此时 <code>A</code> 任务要关闭10秒全局中断的愿望就破灭了,然后 <code>A</code> 任务就“生气了”,结果很严重,可能系统都要被<code>A</code>任务整崩溃。为了解决这个问题, <code>B</code> 任务不能直接简单粗暴的通过<code>local_irq_enable</code> 函数来打开全局中断,而是将中断状态恢复到以前的状态,要考虑到别的任务的感受,此时就要用到下面两个函数:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">local_irq_save(flags);</span><br><span class="line">local_irq_restore(flags);</span><br></pre></td></tr></table></figure><p>这两个函数是一对, <code>local_irq_save</code> 函数用于禁止中断,并且将中断状态保存在 <code>flags</code> 中。<br><code>local_irq_restore</code> 用于恢复中断,将中断恢复到 <code>flags</code> 状态。</p></blockquote></li></ul><h3 id="1-3-上半部和下半部"><a href="#1-3-上半部和下半部" class="headerlink" title="1.3 上半部和下半部"></a>1.3 上半部和下半部</h3><ul><li><p>上半部:上半部就是中断处理函数,那些处理过程比较快,不会占用很长时间的处理就可以放在上半部完成。</p></li><li><p>下半部:如果中断处理过程比较耗时,那么就将这些比较耗时的代码提出来,交给下半部去执行,这样中断处理函数就会快进快出。</p></li><li><p>关于代码属于上半部或下半部的参考</p><blockquote><ol><li>如果要处理的内容不希望被其他中断打断,那么可以放到上半部。</li><li>如果要处理的任务对时间敏感,可以放到上半部。</li><li>如果要处理的任务与硬件有关,可以放到上半部。</li><li>除了上述三点以外的其他任务,优先考虑放到下半部。</li></ol></blockquote></li></ul><hr><p><strong><code>Linux</code>对下半部的处理方式。</strong></p><h4 id="1-3-1-软中断"><a href="#1-3-1-软中断" class="headerlink" title="1.3.1 软中断"></a>1.3.1 软中断</h4><p><strong>软中断必须在编译的时候静态注册(写入到内核中)!软中断不要去用。</strong></p><p><code>Linux</code> 内核使用结构体<code>softirq_action</code> 表示软中断,<code>softirq_action</code>结构体定义在文件 <code>include/linux/interrupt.h</code> 中,内容如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">softirq_action</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">void</span> (*action)(struct softirq_action *);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>在 <code>kernel/softirq.c</code> 文件中一共定义了 10 个软中断,如下所示:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">softirq_action</span> <span class="title">softirq_vec</span>[<span class="title">NR_SOFTIRQS</span>];</span></span><br></pre></td></tr></table></figure><p><code>NR_SOFTIRQS</code> 是枚举类型,定义在文件 <code>include/linux/interrupt.h</code> 中,定义如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span> </span><br><span class="line">{</span><br><span class="line"> HI_SOFTIRQ = <span class="number">0</span>, <span class="comment">/* 高优先级软中断 */</span></span><br><span class="line"> TIMER_SOFTIRQ, <span class="comment">/* 定时器软中断 */</span></span><br><span class="line"> NET_TX_SOFTIRQ, <span class="comment">/* 网络数据发送软中断 */</span></span><br><span class="line"> NET_RX_SOFTIRQ,<span class="comment">/* 网络数据接收软中断 */</span></span><br><span class="line"> BLOCK_SOFTIRQ,</span><br><span class="line"> BLOCK_IOPOLL_SOFTIRQ,</span><br><span class="line"> TASKLET_SOFTIRQ,<span class="comment">/* tasklet 软中断 */</span></span><br><span class="line"> SCHED_SOFTIRQ,<span class="comment">/* 调度软中断 */</span></span><br><span class="line"> HRTIMER_SOFTIRQ,<span class="comment">/* 高精度定时器软中断 */</span></span><br><span class="line"> RCU_SOFTIRQ,<span class="comment">/* RCU 软中断 */</span></span><br><span class="line"> NR_SOFTIRQS</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p><code>softirq_action</code> 结构体中的 <code>action</code> 成员变量就是软中断的服务函数,数组 <code>softirq_vec</code> 是个全局数组,因此所有的 <code>CPU</code>(对于 <code>SMP</code> 系统而言)都可以访问到,每个 <code>CPU</code> 都有自己的触发和控制机制,并且只执行自己所触发的软中断。但是各个 <code>CPU</code> 所执行的软中断服务函数确是相同的,都是数组 <code>softirq_vec</code> 中定义的 <code>action</code> 函数。</p><hr><ul><li><p>要使用软中断要先注册。</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @brief 注册软中断服务函数</span></span><br><span class="line"><span class="comment"> * @param nr 要开启的软中断 是上面枚举中的一个。</span></span><br><span class="line"><span class="comment"> * @param action 软中断对应的处理函数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">open_softirq</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span> (*action)(struct softirq_action *))</span></span></span><br></pre></td></tr></table></figure><p>软中断必须在编译的时候静态注册!</p></blockquote></li><li><p>触发软中断</p><blockquote><p>注册好软中断以后需要通过 <code>raise_softirq</code> 函数触发, <code>raise_softirq</code> 函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @brief 触发软中断</span></span><br><span class="line"><span class="comment"> * @param nr 要触发的软中断</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">raise_softirq</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> nr)</span></span></span><br></pre></td></tr></table></figure></blockquote></li></ul><h4 id="1-3-2-tasklet"><a href="#1-3-2-tasklet" class="headerlink" title="1.3.2 tasklet"></a>1.3.2 tasklet</h4><p><code>tasklet</code> 是利用软中断来实现的另外一种下半部机制,建议使用 <code>tasklet</code>。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span> *<span class="title">next</span>;</span> <span class="comment">/* 下一个 tasklet */</span></span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">long</span> state; <span class="comment">/* tasklet 状态 */</span></span><br><span class="line"> <span class="keyword">atomic_t</span> count; <span class="comment">/* 计数器,记录对 tasklet 的引用数 */</span></span><br><span class="line"> <span class="keyword">void</span> (*func)(<span class="keyword">unsigned</span> <span class="keyword">long</span>);<span class="comment">/* tasklet 执行的函数 */</span></span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">long</span> data;<span class="comment">/* 函数 func 的参数 */</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>如果要使用 <code>tasklet</code>,必须先定义一个 <code>tasklet</code>,然后使用 <code>tasklet_init</code> 函数初始化 <code>tasklet</code>,<code>taskled_init</code> 函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @brief 初始化 tasklet</span></span><br><span class="line"><span class="comment"> * @param t 要初始化的 tasklet</span></span><br><span class="line"><span class="comment"> * @param func tasklet 的处理函数。</span></span><br><span class="line"><span class="comment"> * @param data 要传递给 func 函数的参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">tasklet_init</span><span class="params">(struct tasklet_struct *t, <span class="keyword">void</span> (*func)(<span class="keyword">unsigned</span> <span class="keyword">long</span>), <span class="keyword">unsigned</span> <span class="keyword">long</span> data)</span></span>;</span><br></pre></td></tr></table></figure><p>也 可 以 使 用 宏 <code>DECLARE_TASKLET</code> 来 一 次 性 完 成 <code>tasklet</code> 的 定 义 和 初 始 化 ,<code>DECLARE_TASKLET</code> 定义在 <code>include/linux/interrupt.h</code> 文件中,定义如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* name 为要定义的 tasklet 名字,</span></span><br><span class="line"><span class="comment"> * 这个名字就是一个 tasklet_struct 类型的结构变量,</span></span><br><span class="line"><span class="comment"> * func 就是 tasklet 的处理函数,data 是传递给 func 函数的参数。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">DECLARE_TASKLET(name, func, data);</span><br></pre></td></tr></table></figure><p>在上半部,也就是中断处理函数中调用 <code>tasklet_schedule</code> 函数就能使 <code>tasklet</code> 在合适的时间运<br>行, <code>tasklet_schedule</code> 函数原型如下:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @param t 要调度的 tasklet,也就是 DECLARE_TASKLET 宏里面的 name。*/</span></span><br><span class="line">void tasklet_schedule(struct tasklet_struct *t);</span><br></pre></td></tr></table></figure><hr><p><strong><code>tasklet</code> 使用顺序:</strong></p><ol><li>定义一个<code>tasklet</code>。</li><li>初始化<code>tasklet</code>,重点是设置对应的处理函数。</li><li>在上半部中调用<code>tasklet_schedule</code>函数,使 <code>tasklet</code> 在合适的时间运行。</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 定义 taselet */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span> <span class="title">testtasklet</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* tasklet 处理函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">testtasklet_func</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> data)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">/* tasklet 具体处理内容 */</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 中断处理函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">irqreturn_t</span> <span class="title">test_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *dev_id)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ......</span><br><span class="line"> <span class="comment">/* 调度 tasklet */</span></span><br><span class="line"> tasklet_schedule(&testtasklet);</span><br><span class="line"> ......</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 驱动入口函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">xxxx_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ......</span><br><span class="line"> <span class="comment">/* 初始化 tasklet */</span></span><br><span class="line"> tasklet_init(&testtasklet, testtasklet_func, data);</span><br><span class="line"> <span class="comment">/* 注册中断处理函数 */</span></span><br><span class="line"> request_irq(xxx_irq, test_handler, <span class="number">0</span>, <span class="string">"xxx"</span>, &xxx_dev);</span><br><span class="line"> ......</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="1-3-3-工作队列"><a href="#1-3-3-工作队列" class="headerlink" title="1.3.3 工作队列"></a>1.3.3 工作队列</h4><p>工作队列是另外一种下半部执行方式,工作队列在进程上下文执行,工作队列将要推后的工作交给一个内核线程去执行,因为工作队列工作在进程上下文,因此工作队列允许睡眠或重新调度。因此如果要推后的工作可以睡眠那么就可以选择工作队列,否则的话就只能选择软中断或 <code>tasklet</code>。</p><p><code>Linux</code> 内核使用 <code>work_struct</code> 结构体表示一个工作,内容如下(省略掉条件编译):</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">work_struct</span> {</span></span><br><span class="line"> <span class="keyword">atomic_long_t</span> data;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">entry</span>;</span></span><br><span class="line"> <span class="keyword">work_func_t</span> func; <span class="comment">/* 工作队列处理函数 */</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>这些工作组织成工作队列,工作队列使用 <code>workqueue_struct</code> 结构体表示,内容如下(省略掉条件编译):</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">workqueue_struct</span> {</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">pwqs</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">list</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">mutex</span>;</span></span><br><span class="line"> <span class="keyword">int</span> work_color;</span><br><span class="line"> <span class="keyword">int</span> flush_color;</span><br><span class="line"> <span class="keyword">atomic_t</span> nr_pwqs_to_flush;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wq_flusher</span> *<span class="title">first_flusher</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">flusher_queue</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">flusher_overflow</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">maydays</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">worker</span> *<span class="title">rescuer</span>;</span></span><br><span class="line"> <span class="keyword">int</span> nr_drainers;</span><br><span class="line"> <span class="keyword">int</span> saved_max_active;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">workqueue_attrs</span> *<span class="title">unbound_attrs</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">pool_workqueue</span> *<span class="title">dfl_pwq</span>;</span></span><br><span class="line"> <span class="keyword">char</span> name[WQ_NAME_LEN];</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">rcu_head</span> <span class="title">rcu</span>;</span></span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">int</span> flags ____cacheline_aligned;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">pool_workqueue</span> __<span class="title">percpu</span> *<span class="title">cpu_pwqs</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">pool_workqueue</span> __<span class="title">rcu</span> *<span class="title">numa_pwq_tbl</span>[];</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p><code>Linux</code> 内核使用工作者线程<code>(worker thread)</code>来处理工作队列中的各个工作, <code>Linux</code> 内核使用<code>worker</code> 结构体表示工作者线程, <code>worker</code> 结构体内容如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">worker</span> {</span></span><br><span class="line"> <span class="keyword">union</span> {</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">entry</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span> <span class="title">hentry</span>;</span></span><br><span class="line"> };</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">work_struct</span> *<span class="title">current_work</span>;</span></span><br><span class="line"> <span class="keyword">work_func_t</span> current_func;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">pool_workqueue</span> *<span class="title">current_pwq</span>;</span></span><br><span class="line"> <span class="keyword">bool</span> desc_valid;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">scheduled</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">task_struct</span> *<span class="title">task</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">worker_pool</span> *<span class="title">pool</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">node</span>;</span></span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">long</span> last_active;</span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">int</span> flags;</span><br><span class="line"> <span class="keyword">int</span> id;</span><br><span class="line"> <span class="keyword">char</span> desc[WORKER_DESC_LEN];</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">workqueue_struct</span> *<span class="title">rescue_wq</span>;</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>每个 <code>worker</code> 都有一个工作队列,工作者线程处理自己工作队列中的所有工作。在实际的驱动开发中,只需要定义工作<code>(work_struct)</code>即可,关于工作队列和工作者线程基本不用去管。</p><ul><li><p>创建工作直接定一个<code>work_struct</code>结构体,然后使用<code>INIT_WORK</code>宏来初始化工作即可,<code>INIT_WORK</code>宏定义如下:</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* _work 表示要初始化的工作, _func 是工作对应的处理函数。*/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> INIT_WORK(_work, _func)</span></span><br></pre></td></tr></table></figure><p>也可以使用<code>DECLARE_WORK</code>宏一次性完成工作的创建和初始化,宏定义如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* n 表示定义的工作(work_struct), f 表示工作对应的处理函数。*/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DECLARE_WORK(n, f)</span></span><br></pre></td></tr></table></figure></blockquote></li><li><p>同<code>tasklet</code>一样,工作也是需要调度才能运行的,工作的调度函数为 <code>schedule_work</code>,函数原型如下所示:</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @brief 调度工作</span></span><br><span class="line"><span class="comment">* @param work 要调度的工作</span></span><br><span class="line"><span class="comment">* @return 结果 0 成功,其他值 失败</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">schedule_work</span><span class="params">(struct work_struct *work)</span></span></span><br></pre></td></tr></table></figure></blockquote></li></ul><hr><p><strong>工作队列使用顺序:</strong></p><ol><li>定义一个<code>work</code>。</li><li>初始化<code>work</code>,重点同样是是设置对应的处理函数。</li><li>在上半部中调用<code>schedule_work</code>函数,使 <code>work</code> 在合适的时间运行。</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 定义工作(work) */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">work_struct</span> <span class="title">testwork</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* work 处理函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">testwork_func_t</span><span class="params">(struct work_struct *work)</span></span>;</span><br><span class="line">{</span><br><span class="line"> <span class="comment">/* 根据成员变量反推出结构体的首地址 */</span></span><br><span class="line"> <span class="comment">//struct demo_struct *p = container_of(work, struct demo_struct, 成员变量名);</span></span><br><span class="line"><span class="comment">/* work 具体处理内容 */</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 中断处理函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">irqreturn_t</span> <span class="title">test_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *dev_id)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ......</span><br><span class="line"> <span class="comment">/* 调度 work */</span></span><br><span class="line"> schedule_work(&testwork);</span><br><span class="line"> ......</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 驱动入口函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">xxxx_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ......</span><br><span class="line"> <span class="comment">/* 初始化 work */</span></span><br><span class="line"> INIT_WORK(&testwork, <span class="keyword">testwork_func_t</span>);</span><br><span class="line"> <span class="comment">/* 注册中断处理函数 */</span></span><br><span class="line"> request_irq(xxx_irq, test_handler, <span class="number">0</span>, <span class="string">"xxx"</span>, &xxx_dev);</span><br><span class="line"> ......</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="1-4-设备树中断节点信息"><a href="#1-4-设备树中断节点信息" class="headerlink" title="1.4 设备树中断节点信息"></a>1.4 设备树中断节点信息</h3><p><code>#interrupt-cells</code>指定中断域编码中断说明符所需的单元数。对于设备来说,会使用<code>interrupts</code>属性来描述中断信息,而<code>#interrupt-cells</code>则指定了描述一个中断信息需要几个数值。</p><blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">intc: interrupt-controller@<span class="number">00</span>a01000 {</span><br><span class="line"> compatible = <span class="string">"arm,cortex-a7-gic"</span>;</span><br><span class="line"> <span class="meta">#interrupt-cells = <span class="meta-string"><3>;</span></span></span><br><span class="line"> interrupt-controller;</span><br><span class="line"> reg = <<span class="number">0x00a01000</span> <span class="number">0x1000</span>>,</span><br><span class="line"> <<span class="number">0x00a02000</span> <span class="number">0x100</span>>;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">gpio5: gpio@<span class="number">020</span>ac000 {</span><br><span class="line"> compatible = <span class="string">"fsl,imx6ul-gpio"</span>, <span class="string">"fsl,imx35-gpio"</span>;</span><br><span class="line"> reg = <<span class="number">0x020ac000</span> <span class="number">0x4000</span>>;</span><br><span class="line"> <span class="built_in">interrupts</span> = <GIC_SPI <span class="number">74</span> IRQ_TYPE_LEVEL_HIGH>,</span><br><span class="line"> <GIC_SPI <span class="number">75</span> IRQ_TYPE_LEVEL_HIGH>;</span><br><span class="line"> gpio-controller;</span><br><span class="line"> <span class="meta">#gpio-cells = <span class="meta-string"><2>;</span></span></span><br><span class="line"> interrupt-controller;<span class="comment">// 表示当前节点是中断控制器</span></span><br><span class="line"> <span class="meta">#interrupt-cells = <span class="meta-string"><2>;</span></span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>从<code>gpio5</code>的<code>interrupts</code>属性可以看到描述一个中断信息需要三个<code>cell</code>,分别是</p><ul><li>第一个 <code>cell</code>:中断类型, <code>0</code> 表示 <code>SPI</code> 中断(共享中断,不是 <code>SPI</code>通讯的中断), <code>1</code> 表示 <code>PPI</code> 中断。</li><li>第二个 <code>cell</code>:中断号,对于 <code>SPI</code> 中断来说中断号的范围为 <code>0~987</code>,对于 <code>PPI</code> 中断来说中断号的范围为 <code>0~15</code>。</li><li>第三个 <code>cell</code>:标志, <code>bit[3:0]</code>表示中断触发类型,为 <code>1</code> 的时候表示上升沿触发,为 <code>2</code> 的时候表示下降沿触发,为 <code>4</code> 的时候表示高电平触发,为 <code>8</code> 的时候表示低电平触发。<code>bit[15:8]</code>为 <code>PPI</code> 中断的 <code>CPU 掩码</code>。</li></ul></blockquote><hr><p>在NXP的官方<code>6ull</code>开发板上有一个磁力计芯片<code>fxls8471</code>,<code>fxls8471</code>的中断引脚链接到<code>I.MX6ULL</code>的<code>SNVS_TAMPER0</code>引脚上,而这个引脚可以复用为<code>GPIO_IO0</code>。在设备树中<code>fxls8471</code>的描述如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">fxls8471@<span class="number">1</span>e {</span><br><span class="line"> compatible = <span class="string">"fsl,fxls8471"</span>;</span><br><span class="line"> reg = <<span class="number">0x1e</span>>;</span><br><span class="line"> <span class="built_in">position</span> = <<span class="number">0</span>>;</span><br><span class="line"> interrupt-parent = <&gpio5>;</span><br><span class="line"> <span class="built_in">interrupts</span> = <<span class="number">0</span> <span class="number">8</span>>;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><ul><li><code>interrupt-parent</code> 属性设置中断控制器,这里使用 <code>gpio5</code> 作为中断控制器。</li><li><code>interrupts</code> 属性设置中断信息,因为在上面 <code>gpio5</code> 的节点中将 <code>#interrupt-cells</code> 设置为了<code>2</code>,所以这里的 <code>interrupts</code> 属性,需要使用两个 <code>cell</code> 来描述中断信息。</li></ul><hr><p>从设备树中获取中断号</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @brief 获取中断号</span></span><br><span class="line"><span class="comment"> * @param dev 设备节点</span></span><br><span class="line"><span class="comment"> * @param index 索引号</span></span><br><span class="line"><span class="comment"> * @return 中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="title">irq_of_parse_and_map</span><span class="params">(struct device_node *dev, <span class="keyword">int</span> index)</span></span></span><br></pre></td></tr></table></figure><p>如果使用 <code>GPIO</code> 的话,可以使用 <code>gpio_to_irq</code> 函数来获取 <code>gpio</code> 对应的中断号,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @brief 获取gpio对应的中断号</span></span><br><span class="line"><span class="comment"> * @param gpio 要获取的GPIO编号</span></span><br><span class="line"><span class="comment"> * @return GPIO对应的中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">gpio_to_irq</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> gpio)</span></span></span><br></pre></td></tr></table></figure><h2 id="二、编写按键中断实验驱动"><a href="#二、编写按键中断实验驱动" class="headerlink" title="二、编写按键中断实验驱动"></a>二、编写按键中断实验驱动</h2><h3 id="2-1-配置设备树"><a href="#2-1-配置设备树" class="headerlink" title="2.1 配置设备树"></a>2.1 配置设备树</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">/dts-v1/;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><dt-bindings/input/input.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"imx6ull.dtsi"</span></span></span><br><span class="line"></span><br><span class="line">/ {</span><br><span class="line">model = <span class="string">"Freescale i.MX6 ULL 14x14 EVK Board"</span>;</span><br><span class="line">compatible = <span class="string">"fsl,imx6ull-14x14-evk"</span>, <span class="string">"fsl,imx6ull"</span>;</span><br><span class="line"></span><br><span class="line">……</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 自己添加的节点 2020-9-17 */</span></span><br><span class="line"></span><br><span class="line">……</span><br><span class="line"></span><br><span class="line">key {</span><br><span class="line">compatible = <span class="string">"atkalpha,key"</span>;</span><br><span class="line">pinctrl-names = <span class="string">"default"</span>;</span><br><span class="line">pinctrl<span class="number">-0</span> = <&pinctrl_key>;</span><br><span class="line">key-gpios = <&gpio1 <span class="number">18</span> GPIO_ACTIVE_HIGH>;</span><br><span class="line">status = <span class="string">"okay"</span>;</span><br><span class="line">interrupt-parent = <&gpio1>;</span><br><span class="line"><span class="built_in">interrupts</span> = <<span class="number">18</span> IRQ_TYPE_EDGE_BOTH>;</span><br><span class="line">};</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">……</span><br><span class="line"></span><br><span class="line">&iomuxc {</span><br><span class="line">pinctrl-names = <span class="string">"default"</span>;</span><br><span class="line">pinctrl<span class="number">-0</span> = <&pinctrl_hog_1>;</span><br><span class="line">imx6ul-evk {</span><br><span class="line">pinctrl_hog_1: hoggrp<span class="number">-1</span> {</span><br><span class="line">fsl,pins = <</span><br><span class="line">MX6UL_PAD_UART1_RTS_B__GPIO1_IO19<span class="number">0x17059</span> <span class="comment">/* SD1 CD */</span></span><br><span class="line">MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT<span class="number">0x17059</span> <span class="comment">/* SD1 VSELECT */</span></span><br><span class="line">MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 <span class="number">0x17059</span> <span class="comment">/* SD1 RESET */</span></span><br><span class="line">>;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 自己定义的IO复用 START */</span></span><br><span class="line"></span><br><span class="line">……</span><br><span class="line"></span><br><span class="line">pinctrl_key: keygrp {</span><br><span class="line">fsl,pins = <</span><br><span class="line">MX6UL_PAD_UART1_CTS_B__GPIO1_IO18<span class="number">0XF080</span></span><br><span class="line">>;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 自己定义的IO复用 END */</span></span><br><span class="line"></span><br><span class="line">……</span><br><span class="line">};</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">……</span><br></pre></td></tr></table></figure><h3 id="2-2-按键中断驱动程序"><a href="#2-2-按键中断驱动程序" class="headerlink" title="2.2 按键中断驱动程序"></a>2.2 按键中断驱动程序</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/interrupt.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_NAME<span class="meta-string">"keyirq"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY_NUM1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY0_VALUE0X01</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> INVAKEY0XFF<span class="comment">/* 无效按键值 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">int</span> gpio;<span class="comment">/* IO编号 */</span></span><br><span class="line"><span class="keyword">int</span> irqNum;<span class="comment">/* 中断号 */</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> value;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">char</span> name[<span class="number">10</span>];<span class="comment">/* 名称 */</span></span><br><span class="line"><span class="keyword">irqreturn_t</span> (*handler)(<span class="keyword">int</span>, <span class="keyword">void</span>*);<span class="comment">/* 中断处理函数 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">/* 设备ID */</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">/* 主设备号 */</span></span><br><span class="line"><span class="keyword">int</span> minor;<span class="comment">/* 次设备号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span><span class="comment">/* 字符设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">/* 设备类 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">/* 设备节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span><span class="comment">/* 设备树节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span> <span class="title">key</span>[<span class="title">KEY_NUM</span>];</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定时器 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">atomic_t</span> keyValue;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">atomic_t</span> keyRelease;<span class="comment">/* 按键是否释放 */</span></span><br><span class="line"></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> <span class="title">keyirq</span>;</span><span class="comment">/* 定义一个keyirq设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &keyirq;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_read</span><span class="params">(struct file *filp, <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyValue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyRelease;</span><br><span class="line"></span><br><span class="line">keyValue = atomic_read(&dev->keyValue);</span><br><span class="line">keyRelease = atomic_read(&dev->keyRelease);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (keyRelease)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 一次有效按键 */</span></span><br><span class="line"><span class="keyword">if</span> (keyValue & <span class="number">0X80</span>)</span><br><span class="line">{</span><br><span class="line">keyValue &= ~<span class="number">0X80</span>;<span class="comment">// 去除标记</span></span><br><span class="line">ret = copy_to_user(buf, &keyValue, <span class="keyword">sizeof</span>(keyValue));</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">0</span>);</span><br><span class="line">} </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">data_err:</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 操作集 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">keyirq_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = keyirq_open,</span><br><span class="line">.<span class="built_in">release</span> = keyirq_release,</span><br><span class="line">.<span class="built_in">write</span> = keyirq_write,</span><br><span class="line">.<span class="built_in">read</span> = keyirq_read,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 定时器处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 用户参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_func</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span>*)<span class="title">arg</span>;</span></span><br><span class="line"><span class="keyword">int</span> value = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">value = gpio_get_value(dev->key[<span class="number">0</span>].gpio);</span><br><span class="line"><span class="keyword">if</span> (value == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键按下</span></span><br><span class="line">printk(<span class="string">"KEY0 Press!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(value == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键释放</span></span><br><span class="line">printk(<span class="string">"KEY0 Release!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value | <span class="number">0X80</span>);<span class="comment">// 打上标签,标记按键按下</span></span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键中断处理函数</span></span><br><span class="line"><span class="comment"> * @param irq 中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">irqreturn_t</span> <span class="title">key0_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 启动定时器来延时消抖 */</span></span><br><span class="line">dev->timer.data = (<span class="keyword">volatile</span> <span class="keyword">unsigned</span> <span class="keyword">long</span>)arg;</span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(<span class="number">20</span>));</span><br><span class="line"><span class="keyword">return</span> IRQ_HANDLED;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键初始化</span></span><br><span class="line"><span class="comment"> * @param dev 设备结构体</span></span><br><span class="line"><span class="comment"> * @return 错误类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyio_init</span><span class="params">(struct keyirq_dev *dev)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键初始化 */</span></span><br><span class="line">dev->nd = of_find_node_by_path(<span class="string">"/key"</span>);</span><br><span class="line"><span class="keyword">if</span> (dev->nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_nd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 可能有多个按键,因此需要根据实际数量来读取 */</span></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line">dev->key[i].gpio = of_get_named_gpio(dev->nd, <span class="string">"key-gpios"</span>, i);</span><br><span class="line"><span class="keyword">if</span> (dev->key[i].gpio < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_getGpio;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">memset</span>(dev->key[i].name, <span class="number">0</span>, <span class="keyword">sizeof</span>(dev->key[i].name));</span><br><span class="line"><span class="built_in">sprintf</span>(dev->key[i].name, <span class="string">"KEY%d"</span>, i);</span><br><span class="line">ret = gpio_request(dev->key[i].gpio, dev->key[i].name);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_requestGpio;</span><br><span class="line">}</span><br><span class="line">ret = gpio_direction_input(dev->key[i].gpio);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setGpioDir;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取中断号 */</span></span><br><span class="line">dev->key[i].irqNum = gpio_to_irq(dev->key[i].gpio);</span><br><span class="line"><span class="comment">// dev->key[i].irqNum = irq_of_parse_and_map(dev->nd, i);</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键中断初始化 */</span></span><br><span class="line">dev->key[<span class="number">0</span>].handler = key0_handler;</span><br><span class="line">dev->key[<span class="number">0</span>].value = KEY0_VALUE;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 跳变沿触发方式 */</span></span><br><span class="line">ret = request_irq(dev->key[i].irqNum, dev->key[i].handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev->key[i].name, dev);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"irq %d request failed!\r\n"</span>, dev->key[i].irqNum);</span><br><span class="line"><span class="keyword">goto</span> fail_irq;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化定时器 */</span></span><br><span class="line">init_timer(&dev->timer);</span><br><span class="line">dev->timer.function = timer_func;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_irq:</span><br><span class="line">fail_setGpioDir:</span><br><span class="line"><span class="keyword">for</span> (i = i<span class="number">-1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line">{</span><br><span class="line">gpio_free(dev->key[i].gpio);</span><br><span class="line">}</span><br><span class="line">fail_requestGpio:</span><br><span class="line">fail_getGpio:</span><br><span class="line">fail_nd:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">keyirq_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">keyirq.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(keyirq.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">keyirq.devid = MKDEV(keyirq.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(keyirq.devid, KEYIRQ_CNT, KEYIRQ_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&keyirq.devid, <span class="number">0</span>,KEYIRQ_CNT,KEYIRQ_NAME);</span><br><span class="line">keyirq.major = MAJOR(keyirq.devid);</span><br><span class="line">keyirq.minor = MINOR(keyirq.devid);</span><br><span class="line">printk(<span class="string">"dev Major ID:%d\r\n"</span>,keyirq.major);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">keyirq.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&keyirq.cdev, &keyirq_fops);</span><br><span class="line">ret = cdev_add(&keyirq.cdev, keyirq.devid, KEYIRQ_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备类 */</span></span><br><span class="line">keyirq<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">KEYIRQ_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">keyirq.device = device_create(keyirq.class, <span class="literal">NULL</span>, keyirq.devid, <span class="literal">NULL</span>, KEYIRQ_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化IO */</span></span><br><span class="line">ret = keyio_init(&keyirq);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_init;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化原子变量 */</span></span><br><span class="line">atomic_set(&keyirq.keyValue, INVAKEY);</span><br><span class="line">atomic_set(&keyirq.keyRelease, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_init:</span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(keyirq.devid, KEYIRQ_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">keyirq_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 释放中断和IO */</span></span><br><span class="line">free_irq(keyirq.key[i].irqNum, &keyirq);</span><br><span class="line">gpio_free(keyirq.key[i].gpio);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 删除定时器 */</span></span><br><span class="line">del_timer_sync(&keyirq.timer);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注销字符设备驱动 */</span></span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">unregister_chrdev_region(keyirq.devid,KEYIRQ_CNT);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(keyirq_init);</span><br><span class="line">module_exit(keyirq_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h3 id="2-3-使用下半部tasklet的按键中断驱动程序"><a href="#2-3-使用下半部tasklet的按键中断驱动程序" class="headerlink" title="2.3 使用下半部tasklet的按键中断驱动程序"></a>2.3 使用下半部<code>tasklet</code>的按键中断驱动程序</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/interrupt.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEYIRQ_NAME<span class="meta-string">"keyirq"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY_NUM1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> KEY0_VALUE0X01</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> INVAKEY0XFF<span class="comment">/* 无效按键值 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">int</span> gpio;<span class="comment">/* IO编号 */</span></span><br><span class="line"><span class="keyword">int</span> irqNum;<span class="comment">/* 中断号 */</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> value;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">char</span> name[<span class="number">10</span>];<span class="comment">/* 名称 */</span></span><br><span class="line"><span class="keyword">irqreturn_t</span> (*handler)(<span class="keyword">int</span>, <span class="keyword">void</span>*);<span class="comment">/* 中断处理函数 */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">tasklet_struct</span> <span class="title">tasklet</span>;</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">/* 设备ID */</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">/* 主设备号 */</span></span><br><span class="line"><span class="keyword">int</span> minor;<span class="comment">/* 次设备号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span><span class="comment">/* 字符设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">/* 设备类 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">/* 设备节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span><span class="comment">/* 设备树节点 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">key_dev</span> <span class="title">key</span>[<span class="title">KEY_NUM</span>];</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定时器 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">atomic_t</span> keyValue;<span class="comment">/* 按键值 */</span></span><br><span class="line"><span class="keyword">atomic_t</span> keyRelease;<span class="comment">/* 按键是否释放 */</span></span><br><span class="line"></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> <span class="title">keyirq</span>;</span><span class="comment">/* 定义一个keyirq设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &keyirq;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyirq_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">keyirq_read</span><span class="params">(struct file *filp, <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyValue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> keyRelease;</span><br><span class="line"></span><br><span class="line">keyValue = atomic_read(&dev->keyValue);</span><br><span class="line">keyRelease = atomic_read(&dev->keyRelease);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (keyRelease)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 一次有效按键 */</span></span><br><span class="line"><span class="keyword">if</span> (keyValue & <span class="number">0X80</span>)</span><br><span class="line">{</span><br><span class="line">keyValue &= ~<span class="number">0X80</span>;<span class="comment">// 去除标记</span></span><br><span class="line">ret = copy_to_user(buf, &keyValue, <span class="keyword">sizeof</span>(keyValue));</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">0</span>);</span><br><span class="line">} </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> data_err;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">data_err:</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 操作集 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">keyirq_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = keyirq_open,</span><br><span class="line">.<span class="built_in">release</span> = keyirq_release,</span><br><span class="line">.<span class="built_in">write</span> = keyirq_write,</span><br><span class="line">.<span class="built_in">read</span> = keyirq_read,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 定时器处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 用户参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_func</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span>*)<span class="title">arg</span>;</span></span><br><span class="line"><span class="keyword">int</span> value = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">value = gpio_get_value(dev->key[<span class="number">0</span>].gpio);</span><br><span class="line"><span class="keyword">if</span> (value == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键按下</span></span><br><span class="line">printk(<span class="string">"KEY0 Press!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(value == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 按键释放</span></span><br><span class="line">printk(<span class="string">"KEY0 Release!\r\n"</span>);</span><br><span class="line">atomic_set(&dev->keyValue, dev->key[<span class="number">0</span>].value | <span class="number">0X80</span>);<span class="comment">// 打上标签,标记按键按下</span></span><br><span class="line">atomic_set(&dev->keyRelease, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief key0 tasklet 处理函数</span></span><br><span class="line"><span class="comment"> * @param arg 传递的参数</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">key0_tasklet</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = (<span class="title">struct</span> <span class="title">keyirq_dev</span> *)<span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 启动定时器来延时消抖 */</span></span><br><span class="line">dev->timer.data = (<span class="keyword">volatile</span> <span class="keyword">unsigned</span> <span class="keyword">long</span>)arg;</span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(<span class="number">20</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键中断处理函数</span></span><br><span class="line"><span class="comment"> * @param irq 中断号</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">irqreturn_t</span> <span class="title">key0_handler</span><span class="params">(<span class="keyword">int</span> irq, <span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">keyirq_dev</span> *<span class="title">dev</span> = <span class="title">arg</span>;</span></span><br><span class="line"></span><br><span class="line">tasklet_schedule(&dev->key[<span class="number">0</span>].tasklet);<span class="comment">/* 调度对应的tasklet */</span></span><br><span class="line"><span class="keyword">return</span> IRQ_HANDLED;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 按键初始化</span></span><br><span class="line"><span class="comment"> * @param dev 设备结构体</span></span><br><span class="line"><span class="comment"> * @return 错误类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">keyio_init</span><span class="params">(struct keyirq_dev *dev)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键初始化 */</span></span><br><span class="line">dev->nd = of_find_node_by_path(<span class="string">"/key"</span>);</span><br><span class="line"><span class="keyword">if</span> (dev->nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_nd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 可能有多个按键,因此需要根据实际数量来读取 */</span></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line">dev->key[i].gpio = of_get_named_gpio(dev->nd, <span class="string">"key-gpios"</span>, i);</span><br><span class="line"><span class="keyword">if</span> (dev->key[i].gpio < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_getGpio;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">memset</span>(dev->key[i].name, <span class="number">0</span>, <span class="keyword">sizeof</span>(dev->key[i].name));</span><br><span class="line"><span class="built_in">sprintf</span>(dev->key[i].name, <span class="string">"KEY%d"</span>, i);</span><br><span class="line">ret = gpio_request(dev->key[i].gpio, dev->key[i].name);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span> )</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_requestGpio;</span><br><span class="line">}</span><br><span class="line">ret = gpio_direction_input(dev->key[i].gpio);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setGpioDir;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取中断号,两种方式皆可 */</span></span><br><span class="line">dev->key[i].irqNum = gpio_to_irq(dev->key[i].gpio);</span><br><span class="line"><span class="comment">// dev->key[i].irqNum = irq_of_parse_and_map(dev->nd, i);</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键中断初始化 */</span></span><br><span class="line">dev->key[<span class="number">0</span>].handler = key0_handler;</span><br><span class="line">dev->key[<span class="number">0</span>].value = KEY0_VALUE;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 跳变沿触发方式 */</span></span><br><span class="line">ret = request_irq(dev->key[i].irqNum, dev->key[i].handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev->key[i].name, dev);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"irq %d request failed!\r\n"</span>, dev->key[i].irqNum);</span><br><span class="line"><span class="keyword">goto</span> fail_irq;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>没有根据多个按键来初始化各自的tasklet,实际中需要根据情况来编写 */</span></span><br><span class="line">tasklet_init(&dev->key[i].tasklet, key0_tasklet, (<span class="keyword">unsigned</span> <span class="keyword">long</span>)dev);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化定时器 */</span></span><br><span class="line">init_timer(&dev->timer);</span><br><span class="line">dev->timer.function = timer_func;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_irq:</span><br><span class="line">fail_setGpioDir:</span><br><span class="line"><span class="keyword">for</span> (i = i<span class="number">-1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line">{</span><br><span class="line">gpio_free(dev->key[i].gpio);</span><br><span class="line">}</span><br><span class="line">fail_requestGpio:</span><br><span class="line">fail_getGpio:</span><br><span class="line">fail_nd:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">keyirq_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">keyirq.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(keyirq.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">keyirq.devid = MKDEV(keyirq.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(keyirq.devid, KEYIRQ_CNT, KEYIRQ_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&keyirq.devid, <span class="number">0</span>,KEYIRQ_CNT,KEYIRQ_NAME);</span><br><span class="line">keyirq.major = MAJOR(keyirq.devid);</span><br><span class="line">keyirq.minor = MINOR(keyirq.devid);</span><br><span class="line">printk(<span class="string">"dev Major ID:%d\r\n"</span>,keyirq.major);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">keyirq.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&keyirq.cdev, &keyirq_fops);</span><br><span class="line">ret = cdev_add(&keyirq.cdev, keyirq.devid, KEYIRQ_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备类 */</span></span><br><span class="line">keyirq<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">KEYIRQ_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">keyirq.device = device_create(keyirq.class, <span class="literal">NULL</span>, keyirq.devid, <span class="literal">NULL</span>, KEYIRQ_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(keyirq.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(keyirq.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化IO */</span></span><br><span class="line">ret = keyio_init(&keyirq);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_init;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化原子变量 */</span></span><br><span class="line">atomic_set(&keyirq.keyValue, INVAKEY);</span><br><span class="line">atomic_set(&keyirq.keyRelease, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_init:</span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(keyirq.devid, KEYIRQ_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">keyirq_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < KEY_NUM; i++)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 释放中断和IO */</span></span><br><span class="line">free_irq(keyirq.key[i].irqNum, &keyirq);</span><br><span class="line">gpio_free(keyirq.key[i].gpio);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 删除定时器 */</span></span><br><span class="line">del_timer_sync(&keyirq.timer);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注销字符设备驱动 */</span></span><br><span class="line">device_destroy(keyirq.class, keyirq.devid);</span><br><span class="line">class_destroy(keyirq.class);</span><br><span class="line">cdev_del(&keyirq.cdev);</span><br><span class="line">unregister_chrdev_region(keyirq.devid,KEYIRQ_CNT);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(keyirq_init);</span><br><span class="line">module_exit(keyirq_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h3 id="2-4-测试APP程序"><a href="#2-4-测试APP程序" class="headerlink" title="2.4 测试APP程序"></a>2.4 测试APP程序</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/ioctl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ./keyReadAPP /dev/keyirq</span></span><br><span class="line"><span class="comment"> * @param argc 应用程序参数个数</span></span><br><span class="line"><span class="comment"> * @param argv 保存的参数,字符串形式。</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> fd = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">char</span> *filename;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> data;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">if (argc != 3)</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">printf("输入错误\r\n");</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line">filename = argv[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">fd = <span class="built_in">open</span>(filename, O_RDWR);</span><br><span class="line"><span class="keyword">if</span>(fd < <span class="number">0</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Open %s fail.\r\n"</span>,filename);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 循环读取 */</span></span><br><span class="line"><span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line">ret = <span class="built_in">read</span>(fd, &data, <span class="keyword">sizeof</span>(data));</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{ </span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"keyValue = %#x\r\n"</span>, data);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 关闭 */</span></span><br><span class="line">ret = <span class="built_in">close</span>(fd);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Close %s fail.\r\n"</span>, filename);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(八)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%85%AB%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%85%AB%EF%BC%89.html</id>
<published>2020-11-17T14:51:31.000Z</published>
<updated>2021-08-25T14:11:38.012Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><h1 id="Linux内核定时器和ioctl函数"><a href="#Linux内核定时器和ioctl函数" class="headerlink" title="Linux内核定时器和ioctl函数"></a>Linux内核定时器和ioctl函数</h1><ol><li><p>内核时间管理</p><p>1.1 对于<code>Cortex-M</code>内核来说,一般使用<code>systick</code>硬件定时器作为系统定时器,使用过<code>FreeRTOS</code>等操作系统的也知道,<code>FreeRTOS</code>一般就是使用<code>systick</code>来提供系统时钟,同样<code>Linux</code>也需要系统时钟。</p><p>1.2 <code>Linux</code>内核频率可以配置,在图形化界面可以配置。在<code>include/aasm-generic/param.h</code>文件中可以看到内核配置的节拍率<code>HZ</code>(系统频率)。</p><p>1.3 <code>HZ</code>表示每秒的节拍数。</p><a id="more"></a></li><li><p>节拍率高低的缺陷</p><p>系统使用硬件定时中断来计时,中断周期性产生的频率就是系统频率,也叫作节拍率<code>tick rate</code>。</p><p>节拍率越高,时间精度越高,同样也会加剧系统的负担。</p></li><li><p><code>jiffies</code></p><p><code>Linux</code>内核使用全局变量<code>jiffies</code>来记录系统从启动以来的系统节拍数,系统启动的时候会将其初始化为0,<code>jiffies</code>定义在文件<code>include/linux/jiffies.h</code>中。<code>jiffies</code>/<code>HZ</code>就是系统运行时间,单位为秒。</p></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/************** 判断是否超时的api函数 ***************/</span> </span><br><span class="line"></span><br><span class="line"><span class="comment">/* unkown 通常为 jiffies, known 通常是需要对比的值。 */</span></span><br><span class="line">time_after(unkown, known)</span><br><span class="line">time_before(unkown, known) </span><br><span class="line">time_after_eq(unkown, known)</span><br><span class="line">time_before_eq(unkown, known)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/************** jiffies 和 ms、us、ns的转化函数 ***************/</span> </span><br><span class="line"></span><br><span class="line"><span class="comment">/* 将 jiffies 类型的参数 j 分别转换为对应的毫秒、微秒、纳秒。 */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">jiffies_to_msecs</span><span class="params">(<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> j)</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">jiffies_to_usecs</span><span class="params">(<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> j)</span> </span></span><br><span class="line"><span class="function">u64 <span class="title">jiffies_to_nsecs</span><span class="params">(<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> j)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="comment">/* 将毫秒、微秒、纳秒转换为 jiffies 类型。 */</span></span></span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="title">msecs_to_jiffies</span><span class="params">(<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> m)</span></span></span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="title">usecs_to_jiffies</span><span class="params">(<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> u)</span> </span></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="title">nsecs_to_jiffies</span><span class="params">(u64 n)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="comment">/***************** 使用 jiffies 判断超时 ****************/</span> </span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">long</span> timeout</span>;</span><br><span class="line">timeout = jiffies + (<span class="number">2</span> * HZ); <span class="comment">/* 超时的时间点 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 判断有没有超时 */</span></span><br><span class="line"><span class="keyword">if</span>(time_before(jiffies, timeout)) </span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 超时未发生 */</span></span><br><span class="line">} </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 超时发生 */</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><ol start="4"><li><p>内核定时器</p><p>4.1 软件定时器不像硬件定时器一样是直接设置周期值的。软件定时器是设置期限满以后的时间点。</p><p>4.2 需要编写定时器处理函数。</p><p>4.3 内核定时器不是周期性的,一次定时时间到了以后就会关闭,除非重新打开。</p></li><li><p>定时器<code>API</code>函数</p></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/******** timer_list 结构体 **********/</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> {</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">entry</span>;</span></span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">long</span> expires; <span class="comment">/* 定时器超时时间,单位是节拍数 */</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">tvec_base</span>* <span class="title">base</span>;</span></span><br><span class="line"> <span class="keyword">void</span> (*function)(<span class="keyword">unsigned</span> <span class="keyword">long</span>);<span class="comment">/* 定时处理函数 */</span></span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">long</span> data; <span class="comment">/* 要传递给 function 函数的参数 */</span></span><br><span class="line"> <span class="keyword">int</span> slack;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/************ api函数 ************/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">init_timer</span><span class="params">(struct timer_list* timer)</span></span>;<span class="comment">// 初始化定时器</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add_timer</span><span class="params">(struct timer_list* timer)</span></span>;<span class="comment">// 向Linux内核注册定时器,同时启动定时器</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">del_timer</span><span class="params">(struct timer_list* timer)</span></span>;<span class="comment">// 删除一个定时器</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">del_timer_sync</span><span class="params">(struct timer_list* timer)</span></span>;<span class="comment">// del_timer 函数的同步版,会等待其他处理器使用完定时器再删除,del_timer_sync 不能使用在中断上下文中</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">mod_timer</span><span class="params">(struct timer_list* timer, <span class="keyword">unsigned</span> <span class="keyword">long</span> expires)</span></span>;<span class="comment">// 修改定时值,同时启动定时器</span></span><br></pre></td></tr></table></figure><ol start="6"><li>内核短延时函数</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">ndelay</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> nsecs)</span></span>;<span class="comment">// 纳秒延时</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">udelay</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> usecs)</span></span>;<span class="comment">// 微秒延时</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">mdelay</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> mseces)</span></span>;<span class="comment">// 毫秒延时</span></span><br></pre></td></tr></table></figure><h1 id="定时器使用练手"><a href="#定时器使用练手" class="headerlink" title="定时器使用练手"></a>定时器使用练手</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> TIMER_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> TIMER_NAME<span class="meta-string">"timer"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDOFF0</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDON 1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;</span><br><span class="line"><span class="keyword">int</span> major;</span><br><span class="line"><span class="keyword">int</span> minor;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span></span><br><span class="line"><span class="keyword">int</span> led_gpio;<span class="comment">/* led 所使用的 GPIO 编号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定义一个定时器 */</span></span><br><span class="line"></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span> <span class="title">timerdev</span>;</span><span class="comment">/* 定义一个设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">led_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &timerdev;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">led_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">led_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> databuff[<span class="number">1</span>];</span><br><span class="line"><span class="keyword">int</span> ret;</span><br><span class="line"></span><br><span class="line">ret = copy_from_user(databuff, buf, count);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"kernel write failed!\r\n"</span>);</span><br><span class="line"><span class="keyword">return</span> -EFAULT;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(databuff[<span class="number">0</span>] == LEDON)</span><br><span class="line">{</span><br><span class="line">gpio_set_value(dev->led_gpio, <span class="number">0</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">gpio_set_value(dev->led_gpio, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">led_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = led_open,</span><br><span class="line">.<span class="built_in">release</span> = led_release,</span><br><span class="line">.<span class="built_in">write</span> = led_write,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_function</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">mod_timer(&timerdev.timer, jiffies + msecs_to_jiffies(<span class="number">500</span>));<span class="comment">// 修改时间点,并重新开启定时器。</span></span><br><span class="line">gpio_set_value(timerdev.led_gpio, i);</span><br><span class="line">i = !i;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">timer_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">timerdev.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(timerdev.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">timerdev.devid = MKDEV(timerdev.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&timerdev.devid, <span class="number">0</span>,TIMER_CNT,TIMER_NAME);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">timerdev.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&timerdev.cdev, &led_fops);</span><br><span class="line">ret = cdev_add(&timerdev.cdev, timerdev.devid, TIMER_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建类 */</span></span><br><span class="line">timerdev<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">TIMER_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(timerdev.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(timerdev.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">timerdev.device = device_create(timerdev.class, <span class="literal">NULL</span>, timerdev.devid, <span class="literal">NULL</span>, TIMER_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(timerdev.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(timerdev.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取设备节点 */</span></span><br><span class="line">timerdev.nd = of_find_node_by_path(<span class="string">"/gpioled"</span>);</span><br><span class="line"><span class="keyword">if</span> (timerdev.nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取LED对应的GPIO */</span></span><br><span class="line">timerdev.led_gpio = of_get_named_gpio(timerdev.nd, <span class="string">"led-gpios"</span>, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (timerdev.led_gpio < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 申请IO */</span></span><br><span class="line">ret = gpio_request(timerdev.led_gpio, <span class="string">"led_gpio"</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"failed to request the led\r\n"</span>);</span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>申请失败的话,大部分原因这个IO被别的外设占用</span></span><br><span class="line"><span class="comment"> * 需要在设备树中屏蔽相关代码,或者status属性值设置为disable</span></span><br><span class="line"><span class="comment"> * 检查复用,也就是pinctl</span></span><br><span class="line"><span class="comment"> * gpio使用 </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用IO 设置为输出 默认为低电平*/</span></span><br><span class="line">ret = gpio_direction_output(timerdev.led_gpio, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setoutput;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">init_timer(&timerdev.timer);<span class="comment">// 初始化定时器</span></span><br><span class="line">timerdev.timer.function = timer_function;</span><br><span class="line">timerdev.timer.expires = jiffies + msecs_to_jiffies(<span class="number">500</span>);<span class="comment">// 两秒</span></span><br><span class="line">add_timer(&timerdev.timer);<span class="comment">// 添加到系统</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_setoutput:</span><br><span class="line">gpio_free(timerdev.led_gpio);</span><br><span class="line">fail_findnd:</span><br><span class="line">device_destroy(timerdev.class, timerdev.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(timerdev.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&timerdev.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(timerdev.devid, TIMER_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">timer_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">/* 释放IO */</span></span><br><span class="line">gpio_free(timerdev.led_gpio);</span><br><span class="line">device_destroy(timerdev.class, timerdev.devid);</span><br><span class="line">class_destroy(timerdev.class);</span><br><span class="line">cdev_del(&timerdev.cdev);</span><br><span class="line">unregister_chrdev_region(timerdev.devid,TIMER_CNT);</span><br><span class="line">del_timer(&timerdev.timer);<span class="comment">// 删除定时器</span></span><br><span class="line">gpio_set_value(timerdev.led_gpio, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(timer_init);</span><br><span class="line">module_exit(timer_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h1 id="使用ioctl函数控制"><a href="#使用ioctl函数控制" class="headerlink" title="使用ioctl函数控制"></a>使用<code>ioctl</code>函数控制</h1><p>用户<code>APP</code>中使用<code>ioctl</code>函数</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">unlocked_ioctl();</span><br><span class="line">compat_ioctl();</span><br></pre></td></tr></table></figure><p>对应驱动里的函数</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 如果是64位的应用程序运行在64位的内核上,调用的是unlocked_ioctl,</span></span><br><span class="line"><span class="comment"> * 如果是32位的应用程序运行在32位的内核上,调用的也是unlocked_ioctl。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">long</span> (*unlocked_ioctl)(struct file *, <span class="keyword">unsigned</span> <span class="keyword">int</span>, <span class="keyword">unsigned</span> <span class="keyword">long</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment"> * 支持64位系统的驱动必须要实现的ioctl,当有32位的应用程序调用64位内核的ioctl时,</span></span><br><span class="line"><span class="comment"> * 这个回调函数会被调用,如果没有实现compat_ioctl,那么32位的应用程序在64位的内核上</span></span><br><span class="line"><span class="comment"> * 执行ioctl时会返回错误:Not a typewriter</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">long</span> (*compat_ioctl)(struct file *, <span class="keyword">unsigned</span> <span class="keyword">int</span>, <span class="keyword">unsigned</span> <span class="keyword">long</span>);</span><br></pre></td></tr></table></figure><p><code>ioctl</code>的命令是自己定义的,但是要符合<code>Linux</code>的<strong>规则</strong>。具体的说明可以查看博主<a href="https://blog.csdn.net/coolwriter" target="_blank" rel="noopener">coolwriter</a>的博客。</p><p><code>cmd</code>拆分如下</p><table><thead><tr><th align="center">幻数(type)</th><th align="center">序数(number)</th><th align="center">数据传输方向(direction)</th><th align="center">数据大小(size)</th></tr></thead><tbody><tr><td align="center">8bit</td><td align="center">8bit</td><td align="center">2bit</td><td align="center">14bit</td></tr></tbody></table><ul><li>幻数:是一个<code>0~0xFF</code>的数,是用来区分不同的书驱动的。</li><li>序数:用这个数来给自己的命令编号。</li><li>数据传输方向:如果涉及到要传参,内核要求描述一下传输的方向。<ul><li><code>_IOC_NONE</code>:值为0,无数据传输。</li><li><code>_IOC_READ</code>:值为1,从设备驱动读取数据。</li><li><code>_IOC_WRITE</code>:值为2,向设备驱动写入数据。</li><li><code>_IOC_READ|_IOC_WRITE</code>:双向数据传输。</li></ul></li><li>数据大小:==与体系结构相关==,<code>ARM</code>下占<code>14bit(_IOC_SIZEBITS)</code>,如果数据是<code>int</code>,内核给这个赋的值就是<code>sizeof(int)</code>。</li></ul><p>构建命令</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* type是幻数,nr是序数,size是大小 */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _IO(type, nr)<span class="comment">// 没有参数的命令</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _IOR(type, nr, size)<span class="comment">// 该命令是从驱动读取数据</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _IOW(type, nr, size)<span class="comment">// 该命令是从驱动写入数据</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _IOWR(type, nr, size)<span class="comment">// 双向数据传输</span></span></span><br></pre></td></tr></table></figure><p>驱动程序</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/timer.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/jiffies.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> TIMER_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> TIMER_NAME<span class="meta-string">"timer"</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment"> * 构建命令</span></span><br><span class="line"><span class="comment"> * 0xEF是在Linux内核文档中找的没用被其他驱动程序占用的。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> CLOSE_CMD_IO(0xEF, 1)<span class="comment">// 关闭命令</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OPEN_CMD_IO(0xEF, 2)<span class="comment">// 打开命令</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SET_PERIOD_CMD_IOW(0xEF, 3, int)<span class="comment">// 设置周期</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义设备驱动结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;</span><br><span class="line"><span class="keyword">int</span> major;</span><br><span class="line"><span class="keyword">int</span> minor;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span></span><br><span class="line"><span class="keyword">int</span> led_gpio;<span class="comment">/* led 所使用的 GPIO 编号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">timer</span>;</span><span class="comment">/* 定义一个定时器 */</span></span><br><span class="line"><span class="keyword">atomic_t</span> timePeriod;<span class="comment">/* 定时器时间周期,使用原子变量,保护数据 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span> <span class="title">timerdev</span>;</span><span class="comment">/* 定义一个设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">timer_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &timerdev;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">timer_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">long</span> <span class="title">timer_ioctl</span><span class="params">(struct file* filp, <span class="keyword">unsigned</span> <span class="keyword">int</span> cmd, <span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> value = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">switch</span> (cmd)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">case</span> CLOSE_CMD:</span><br><span class="line"><span class="comment">/* 关闭定时器 */</span></span><br><span class="line">del_timer_sync(&dev->timer);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> OPEN_CMD:</span><br><span class="line"><span class="comment">/* 设置时间点 */</span></span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(atomic_read(&dev->timePeriod)));</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> SET_PERIOD_CMD:</span><br><span class="line"><span class="comment">/* 根据APP程序设置的周期来设置定时器的时间点 */</span></span><br><span class="line">ret = copy_from_user(&value, (<span class="keyword">int</span> *)arg, <span class="keyword">sizeof</span>(<span class="keyword">int</span>));</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> -EFAULT;</span><br><span class="line">}</span><br><span class="line">atomic_set(&dev->timePeriod, value);</span><br><span class="line">mod_timer(&dev->timer, jiffies + msecs_to_jiffies(atomic_read(&dev->timePeriod)));</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">timer_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = timer_open,</span><br><span class="line">.<span class="built_in">release</span> = timer_release,</span><br><span class="line">.unlocked_ioctl = timer_ioctl,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定时器处理函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">timer_function</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> arg)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">/* 修改时间点,并重新开启定时器。 */</span></span><br><span class="line">mod_timer(&timerdev.timer, jiffies + msecs_to_jiffies(atomic_read(&timerdev.timePeriod)));</span><br><span class="line">gpio_set_value(timerdev.led_gpio, i);</span><br><span class="line">i = !i;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">timer_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备ID */</span></span><br><span class="line">timerdev.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(timerdev.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">timerdev.devid = MKDEV(timerdev.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&timerdev.devid, <span class="number">0</span>,TIMER_CNT,TIMER_NAME);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化字符设备 */</span></span><br><span class="line">timerdev.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&timerdev.cdev, &timer_fops);</span><br><span class="line">ret = cdev_add(&timerdev.cdev, timerdev.devid, TIMER_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建类 */</span></span><br><span class="line">timerdev<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">TIMER_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(timerdev.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(timerdev.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建设备 */</span></span><br><span class="line">timerdev.device = device_create(timerdev.class, <span class="literal">NULL</span>, timerdev.devid, <span class="literal">NULL</span>, TIMER_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(timerdev.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(timerdev.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取设备节点 */</span></span><br><span class="line">timerdev.nd = of_find_node_by_path(<span class="string">"/gpioled"</span>);</span><br><span class="line"><span class="keyword">if</span> (timerdev.nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取LED对应的GPIO */</span></span><br><span class="line">timerdev.led_gpio = of_get_named_gpio(timerdev.nd, <span class="string">"led-gpios"</span>, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (timerdev.led_gpio < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 申请IO */</span></span><br><span class="line">ret = gpio_request(timerdev.led_gpio, <span class="string">"led_gpio"</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"failed to request the led\r\n"</span>);</span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>申请失败的话,大部分原因这个IO被别的外设占用</span></span><br><span class="line"><span class="comment"> * 需要在设备树中屏蔽相关代码,或者status属性值设置为disable</span></span><br><span class="line"><span class="comment"> * 检查复用,也就是pinctl</span></span><br><span class="line"><span class="comment"> * gpio使用 </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用IO 设置为输出 默认为低电平*/</span></span><br><span class="line">ret = gpio_direction_output(timerdev.led_gpio, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setoutput;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">init_timer(&timerdev.timer);<span class="comment">// 初始化定时器</span></span><br><span class="line">atomic_set(&timerdev.timePeriod, <span class="number">500</span>);<span class="comment">// 设置初始周期值</span></span><br><span class="line">timerdev.timer.function = timer_function;</span><br><span class="line">timerdev.timer.expires = jiffies + msecs_to_jiffies(atomic_read(&timerdev.timePeriod));<span class="comment">// 500ms</span></span><br><span class="line">add_timer(&timerdev.timer);<span class="comment">// 添加到系统</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_setoutput:</span><br><span class="line">gpio_free(timerdev.led_gpio);</span><br><span class="line">fail_findnd:</span><br><span class="line">device_destroy(timerdev.class, timerdev.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(timerdev.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&timerdev.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(timerdev.devid, TIMER_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">timer_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">/* 释放IO */</span></span><br><span class="line">gpio_free(timerdev.led_gpio);</span><br><span class="line">device_destroy(timerdev.class, timerdev.devid);</span><br><span class="line">class_destroy(timerdev.class);</span><br><span class="line">cdev_del(&timerdev.cdev);</span><br><span class="line">unregister_chrdev_region(timerdev.devid,TIMER_CNT);</span><br><span class="line">del_timer(&timerdev.timer);<span class="comment">// 删除定时器</span></span><br><span class="line">gpio_set_value(timerdev.led_gpio, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(timer_init);</span><br><span class="line">module_exit(timer_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><p>测试APP程序</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/ioctl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 驱动里定义的命令 */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> CLOSE_CMD_IO(0xEF, 1)<span class="comment">// 关闭命令</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OPEN_CMD_IO(0xEF, 2)<span class="comment">// 打开命令</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SET_PERIOD_CMD_IOW(0xEF, 3, int)<span class="comment">// 设置周期</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ./timerAPP <filename> <0:1></span></span><br><span class="line"><span class="comment"> * @param argc 应用程序参数个数</span></span><br><span class="line"><span class="comment"> * @param argv 保存的参数,字符串形式。</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> fd = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">char</span> *filename;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">int</span> cmd;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">int</span> arg;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">if (argc != 3)</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">printf("输入错误\r\n");</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line">filename = argv[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">fd = <span class="built_in">open</span>(filename, O_RDWR);</span><br><span class="line"><span class="keyword">if</span>(fd < <span class="number">0</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Open %s fail.\r\n"</span>,filename);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"请输入命令(1:关闭定时器,2:打开定时器,3:设置周期,4:关闭文件):"</span>);</span><br><span class="line">ret = <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &cmd);</span><br><span class="line">fflush(<span class="built_in">stdin</span>);<span class="comment">// 清空输入缓存,防止下次scanf时读取到上次遗留下的回车\n。</span></span><br><span class="line"><span class="keyword">if</span> (cmd == <span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line">ioctl(fd, CLOSE_CMD, <span class="number">0</span>);</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> (cmd == <span class="number">2</span>)</span><br><span class="line">{</span><br><span class="line">ioctl(fd, OPEN_CMD, <span class="number">0</span>);</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> (cmd == <span class="number">3</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"请输入定时器周期:"</span>);</span><br><span class="line">ret = <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &arg);</span><br><span class="line">fflush(<span class="built_in">stdin</span>);</span><br><span class="line">ioctl(fd, SET_PERIOD_CMD, &arg);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (cmd == <span class="number">4</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 关闭 */</span></span><br><span class="line">ret = <span class="built_in">close</span>(fd);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: Close %s fail.\r\n"</span>, filename);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(七)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%83%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%83%EF%BC%89.html</id>
<published>2020-11-17T14:45:49.000Z</published>
<updated>2021-08-25T14:11:37.968Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><h1 id="Linux并发与竞争"><a href="#Linux并发与竞争" class="headerlink" title="Linux并发与竞争"></a>Linux并发与竞争</h1><h2 id="一、并发与竞争"><a href="#一、并发与竞争" class="headerlink" title="一、并发与竞争"></a>一、并发与竞争</h2><p>多线程对共享资源同时进行访问,比如全局变量,就会产生并发与竞争现象。以打印机为例,当线程A和线程B同时操作打印机时,就会出现竞争现象,如果没有处理就会导致数据错乱。</p><a id="more"></a><h2 id="二、原子操作atomic"><a href="#二、原子操作atomic" class="headerlink" title="二、原子操作atomic"></a>二、原子操作<code>atomic</code></h2><p>对整形变量或者位进行保护,确保对其进行操作时是最小操作,不会被干扰。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line"> <span class="keyword">int</span> counter;</span><br><span class="line">} <span class="keyword">atomic_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">atomic_t</span> a = ATOMIC_INIT(<span class="number">0</span>);<span class="comment">// 定义原子变量a并赋初值为0;</span></span><br></pre></td></tr></table></figure><p>原子操作<code>API</code>函数</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">AIOMIC_INIT(<span class="keyword">int</span> i)<span class="comment">// 定义原子变量的时候对其初始化</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">atomic_read</span><span class="params">(<span class="keyword">atomic_t</span>* v)</span><span class="comment">// 读取原子变量的值,并返回</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">atomic_set</span><span class="params">(<span class="keyword">atomic_t</span>* v, <span class="keyword">int</span> i)</span><span class="comment">// 给原子变量设置为i值</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">atomic_add</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">atomic_t</span>* v)</span><span class="comment">// 给原子变量加上i值</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">atomic_sub</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">atomic_t</span>* v)</span><span class="comment">// 给原子变量减去i值</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">atomic_inc</span><span class="params">(<span class="keyword">atomic_t</span>* v)</span><span class="comment">// 原子变量自增1</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">atomic_dec</span><span class="params">(<span class="keyword">atomic_t</span>* v)</span><span class="comment">// 原子变量自减1</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">atomic_dec_return</span><span class="params">(<span class="keyword">atomic_t</span>* v)</span><span class="comment">// 原子变量减1,并且返回v的值</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">atomic_inc_return</span><span class="params">(<span class="keyword">atomic_t</span>* v)</span><span class="comment">// 原子变量加1,并且返回v的值</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">atomic_sub_and_test</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">atomic_t</span>* v)</span><span class="comment">// 从v减i,如果结果为0就返回真,否则返回假</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">atomic_add_and_test</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">atomic_t</span>* v)</span><span class="comment">// 给v加i,如果结果为0就返回真,否则返回假</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">atomic_dec_and_test</span><span class="params">(<span class="keyword">atomic_t</span>* v)</span><span class="comment">// 从v减1,如果结果为0就返回真,否则返回假</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">atomic_inc_and_test</span><span class="params">(<span class="keyword">atomic_t</span>* v)</span><span class="comment">// 给v加1,如果结果为0就返回真,否则返回假</span></span></span><br></pre></td></tr></table></figure><h2 id="三、原子位操作"><a href="#三、原子位操作" class="headerlink" title="三、原子位操作"></a>三、原子位操作</h2><p>原子位操作不像原子整形变量那样有个<code>atomic_t</code>的数据结构,原子位操作是直接对内存进行操作。</p><p><code>API</code>函数如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">set_bit</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span>* p)</span><span class="comment">// 将p地址的第nr位置1</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">clear_bit</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span>* p)</span><span class="comment">// 将p地址的第nr位清零</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">change_bit</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span>* p)</span><span class="comment">// 将p地址的第nr位翻转</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">test_bit</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span>* p)</span><span class="comment">// 获取p地址的第nr位的值</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">test_and_set_bit</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span>* p)</span><span class="comment">// 将p地址的第nr位置1,并返回nr位原来的值</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">test_and_clear_bit</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span>* p)</span><span class="comment">// 将p地址的第nr位清零,并返回nr位原来的值</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">test_and_change_bit</span><span class="params">(<span class="keyword">int</span> nr, <span class="keyword">void</span>* p)</span><span class="comment">// 将p地址的第nr位翻转,并返回nr位原来的值</span></span></span><br></pre></td></tr></table></figure><h2 id="四、自旋锁spinlock"><a href="#四、自旋锁spinlock" class="headerlink" title="四、自旋锁spinlock"></a>四、自旋锁<code>spinlock</code></h2><ul><li>用于多核<code>SMP</code> 。</li><li>适合短时间加锁,轻量级加锁。</li><li>自旋锁会自动禁止抢占。</li><li>使用自旋锁,要注意死锁现象的发生,被自旋锁保护的临界区一定不能调用任何能够引起睡眠和阻塞的<code>API函数</code>。(线程与线程中之间,线程与中断之间)。</li></ul><p><code>API</code>函数</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">spinlock_t</span> lock;<span class="comment">// 定义自旋锁</span></span><br><span class="line">DEFINE_SPINLOCK(<span class="keyword">spinlock_t</span> lock)<span class="comment">// 定义并初始化一个自旋锁变量</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">spin_lock_init</span><span class="params">(<span class="keyword">spinlock_t</span>* lock)</span><span class="comment">// 初始化自旋锁</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">spin_lock</span><span class="params">(<span class="keyword">spinlock_t</span>* lock)</span><span class="comment">// 获取指定的自旋锁,也叫加锁</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">spin_unlock</span><span class="params">(<span class="keyword">spinlock_t</span>* lock)</span><span class="comment">// 是否指定的自旋锁</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">spin_trylock</span><span class="params">(<span class="keyword">spinlock_t</span>* lock)</span><span class="comment">// 尝试获取指定的自旋锁,如果没有获取到就返回0</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">spin_is_locked</span><span class="params">(<span class="keyword">spinlock_t</span>* lock)</span><span class="comment">// 检查指定的自旋锁是否被获取,如果没有被获取就返回非0,否则返回0</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">spin_lock_irq</span><span class="params">(<span class="keyword">spinlock_t</span>* lock)</span><span class="comment">// 禁止本地中断,并获取自旋锁。</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">spin_unlock_irq</span><span class="params">(<span class="keyword">spinlock_t</span>* lock)</span><span class="comment">// 激活本地中断,并释放自旋锁。</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">spin_lock_irqsave</span><span class="params">(<span class="keyword">spinlock_t</span>* lock, <span class="keyword">unsigned</span> <span class="keyword">long</span> flags)</span><span class="comment">// 保存中断状态,禁止本地中断,并获取自旋锁。</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">spin_unlock_irqrestore</span><span class="params">(<span class="keyword">spinlock_t</span>* lock, <span class="keyword">unsigned</span> <span class="keyword">long</span> flags)</span><span class="comment">// 将中断状态恢复到以前的状态,并且激活本地中断,释放自旋锁。</span></span></span><br></pre></td></tr></table></figure><p>使用示例:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">DEFINE_SPINLOCK(lock) <span class="comment">// 定义并初始化一个锁</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 线程 A */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">functionA</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">long</span> flags;<span class="comment">// 中断状态</span></span><br><span class="line"> spin_lock_irqsave(&lock, flags)<span class="comment">// 获取锁</span></span><br><span class="line"> <span class="comment">/* 临界区 */</span></span><br><span class="line"> spin_unlock_irqrestore(&lock, flags)<span class="comment">// 释放锁</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 中断服务函数 */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">irq</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> spin_lock(&lock)<span class="comment">// 获取锁</span></span><br><span class="line"> <span class="comment">/* 临界区 */</span></span><br><span class="line"> spin_unlock(&lock)<span class="comment">// 释放锁</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="五、信号量semaphore"><a href="#五、信号量semaphore" class="headerlink" title="五、信号量semaphore"></a>五、信号量<code>semaphore</code></h2><ul><li>信号量可以使等待资源线程进入休眠状态,因此适用于占用资源比较久的场合。</li><li>信号量不能用于中断中,因为信号量会引起休眠,中断不能休眠。</li><li>信号量会将等待信号量中休眠的线程唤醒。</li><li>如果共享资源的持有时间比较短,那就不适合适用信号量了。</li></ul><p><code>API</code>函数</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">DEFINE_SEAMPHORE(name)<span class="comment">// 定义一个信号量,并且设置信号量的值为1</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">sema_init</span><span class="params">(struct semaphore* sem, <span class="keyword">int</span> val)</span><span class="comment">// 初始化信号量sem,设置信号量值为val</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">down</span><span class="params">(struct semaphore* sem)</span><span class="comment">// 获取信号量,因为会导致休眠,因此不能在中断中使用。</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">down_trylock</span><span class="params">(struct semaphore* sem)</span><span class="comment">// 尝试获取信号量,如果能获取到信号量就获取,并且返回0。如果不能就返回非0,并且不会进入休眠。</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">down_interruptible</span><span class="params">(struct semaphore* sem)</span><span class="comment">// 获取信号量,和down类似,只是使用down进入休眠状态的咸亨不能被信号打断。而使用此函数进入休眠以后是可以被信号打断的。</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">up</span><span class="params">(struct semaphore* sem)</span><span class="comment">// 释放信号量</span></span></span><br></pre></td></tr></table></figure><p>使用方式如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">semaphore</span> <span class="title">sem</span>;</span><span class="comment">// 定义信号量</span></span><br><span class="line">sema_init(&sem, <span class="number">1</span>);<span class="comment">// 初始化信号量</span></span><br><span class="line"></span><br><span class="line">down(&sem);<span class="comment">// 申请信号量</span></span><br><span class="line"><span class="comment">/* 临界区 */</span></span><br><span class="line">up(&sem);<span class="comment">// 释放信号量</span></span><br></pre></td></tr></table></figure><h2 id="六、互斥锁mutex"><a href="#六、互斥锁mutex" class="headerlink" title="六、互斥锁mutex"></a>六、互斥锁<code>mutex</code></h2><ul><li>互斥体可以导致休眠,因此不能在中断中使用,中断中只能使用自旋锁。</li><li>互斥体保护的临界区可以调用引起阻塞的<code>API函数</code> 。</li><li>一次只有一个线程可以持有互斥体,因此必须由<code>mutex</code>的持有者释放<code>mutex</code>。不能递归上锁和解锁。</li></ul><p><code>API</code>函数:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">DEFINE_MUTEX(name)<span class="comment">// 定义并初始化一个 mutex 变量。</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">mutex_init</span><span class="params">(struct mutex* lock)</span><span class="comment">// 初始化 mutex。</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">mutex_lock</span><span class="params">(struct mutex* lock)</span><span class="comment">// 获取 mutex,也就是给 mutex 上锁。如果获取不到就进休眠。</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">mutex_unlock</span><span class="params">(struct mutex* lock)</span><span class="comment">// 释放 mutex,也就给 mutex 解锁。</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">mutex_trylock</span><span class="params">(struct mutex* lock)</span><span class="comment">// 尝试获取 mutex,如果成功就返回 1,如果失败就返回 0。</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">mutex_is_locked</span><span class="params">(struct mutex* lock)</span><span class="comment">// 判断 mutex 是否被获取,如果是的话就返回1,否则返回 0。</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">mutex_lock_interruptible</span><span class="params">(struct mutex* lock)</span><span class="comment">// 使用此函数获取信号量失败进入休眠以后可以被信号打断</span></span></span><br></pre></td></tr></table></figure><p>使用示例:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">lock</span>;</span><span class="comment">// 定义一个互斥体</span></span><br><span class="line">mutex_init(&lock);<span class="comment">// 初始化互斥体</span></span><br><span class="line"></span><br><span class="line">mutex_lock(&lock);<span class="comment">// 上锁</span></span><br><span class="line"><span class="comment">/* 临界区 */</span></span><br><span class="line">mutex_unlock(&lock);<span class="comment">// 解锁</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>Visio调整图形的间距</title>
<link href="https://proudrabbit.gitee.io/Visio%E8%B0%83%E6%95%B4%E5%9B%BE%E5%BD%A2%E7%9A%84%E9%97%B4%E8%B7%9D.html"/>
<id>https://proudrabbit.gitee.io/Visio%E8%B0%83%E6%95%B4%E5%9B%BE%E5%BD%A2%E7%9A%84%E9%97%B4%E8%B7%9D.html</id>
<published>2020-11-11T13:07:19.000Z</published>
<updated>2021-08-25T14:11:38.133Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p> 有时候在<code>Visio</code>绘图时我们想要自定义图形之间的间距选项,但是在选中后图形,在<code>开始->位置->间距选项</code>中调整了间距后,但是却没有效果。</p><p> 解决这个问题的方法很简单,微软也说明了,点击间距选项上的<code>?</code>即可。</p><p><img src="https://i.loli.net/2020/11/11/qQEA8Ky1O39TVoj.png" alt="image-20201111213107031"></p><p> 在弹出的网页中,可以看到说明</p><a id="more"></a><p><img src="https://i.loli.net/2020/11/11/nF3IjH6gQTlLK5e.png" alt="image-20201111213237155"></p><p>只要使用连接线将图形相连接,不用全部链接,然后选中要调整的图形。</p><p><img src="https://i.loli.net/2020/11/11/Pv5Jw2cHoOIgWtQ.png" alt="image-20201111213810222"></p><p>然后再次使用<code>间距选项</code>调整间距即可,最后将连接线删除。</p><p><img src="https://i.loli.net/2020/11/11/idpIgm8Vy4teGrR.png" alt="image-20201111213909216"></p>]]></content>
<summary type="html">
Visio有时候使用间距选项调整间距时无法调整间距,这里给出解决办法。
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="软件使用" scheme="https://proudrabbit.gitee.io/tags/%E8%BD%AF%E4%BB%B6%E4%BD%BF%E7%94%A8/"/>
<category term="Visio" scheme="https://proudrabbit.gitee.io/tags/Visio/"/>
</entry>
<entry>
<title>Word一行排列多个图片并插入题注</title>
<link href="https://proudrabbit.gitee.io/Word%E4%B8%80%E8%A1%8C%E6%8E%92%E5%88%97%E5%A4%9A%E4%B8%AA%E5%9B%BE%E7%89%87%E5%B9%B6%E6%8F%92%E5%85%A5%E9%A2%98%E6%B3%A8.html"/>
<id>https://proudrabbit.gitee.io/Word%E4%B8%80%E8%A1%8C%E6%8E%92%E5%88%97%E5%A4%9A%E4%B8%AA%E5%9B%BE%E7%89%87%E5%B9%B6%E6%8F%92%E5%85%A5%E9%A2%98%E6%B3%A8.html</id>
<published>2020-11-09T01:31:21.000Z</published>
<updated>2021-08-25T14:11:38.140Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><h2 id="Word中一行排列多个图片并插入题注"><a href="#Word中一行排列多个图片并插入题注" class="headerlink" title="Word中一行排列多个图片并插入题注"></a>Word中一行排列多个图片并插入题注</h2><h4 id="1-首先根据图片要排列成样式,插入表格。"><a href="#1-首先根据图片要排列成样式,插入表格。" class="headerlink" title="1. 首先根据图片要排列成样式,插入表格。"></a>1. 首先根据图片要排列成样式,插入表格。</h4><h4 id="2-然后将图片放入表格中。就像这样。"><a href="#2-然后将图片放入表格中。就像这样。" class="headerlink" title="2. 然后将图片放入表格中。就像这样。"></a>2. 然后将图片放入表格中。就像这样。</h4><p><img src="https://i.loli.net/2020/11/09/DncZMLsP9YoSkdG.png" alt="表格内插入图片"></p><p>图片大小可能要调一调。</p><a id="more"></a><h4 id="3-对图片插入题注"><a href="#3-对图片插入题注" class="headerlink" title="3. 对图片插入题注"></a>3. 对图片插入题注</h4><p><img src="https://i.loli.net/2020/11/09/7MP2HxEA9foDKnB.png" alt="图片添加题注"></p><h4 id="4-取消表格边框"><a href="#4-取消表格边框" class="headerlink" title="4. 取消表格边框"></a>4. 取消表格边框</h4><p><img src="https://i.loli.net/2020/11/09/7wXfaelDWUtzoxC.png" alt="取消表格边框"></p><h4 id="5-其他地方引用"><a href="#5-其他地方引用" class="headerlink" title="5. 其他地方引用"></a>5. 其他地方引用</h4><p><img src="https://i.loli.net/2020/11/09/HkInlzMGBebjERo.png" alt="其他地方引用"></p>]]></content>
<summary type="html">
Word中排列图片并且添加题注,方便后期引用。
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="软件使用" scheme="https://proudrabbit.gitee.io/tags/%E8%BD%AF%E4%BB%B6%E4%BD%BF%E7%94%A8/"/>
<category term="Word" scheme="https://proudrabbit.gitee.io/tags/Word/"/>
</entry>
<entry>
<title>寄存器映射</title>
<link href="https://proudrabbit.gitee.io/%E5%AF%84%E5%AD%98%E5%99%A8%E6%98%A0%E5%B0%84.html"/>
<id>https://proudrabbit.gitee.io/%E5%AF%84%E5%AD%98%E5%99%A8%E6%98%A0%E5%B0%84.html</id>
<published>2020-09-22T13:31:44.000Z</published>
<updated>2021-08-25T14:11:38.193Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><h2 id="寄存器映射原理"><a href="#寄存器映射原理" class="headerlink" title="寄存器映射原理"></a>寄存器映射原理</h2><p>首先看下这行代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">((<span class="keyword">unsigned</span> <span class="keyword">int</span> *)(GPIOB_BASE+<span class="number">0X00</span>))</span><br></pre></td></tr></table></figure><p>其中<code>GPIOB_BASE</code>是GPIOB寄存器的起始地址,它是一个4字节(32位)的地址。但是电脑不知道它地址,因此需要在前面加一个<code>(unsigned int *)</code>对其进行强制类型转换,这个的作用就是把<code>GPIOB_BASE + 0x00</code>强制转化为地址,因为<code>*</code>符号运算的是地址,所以<code>(unsigned int *)(GPIOB_BASE + 0x00)</code>这一串就成了地址,相当与一个指针常量,当需要向其写入或者读取数据时就可以按按照指针的操作方式对其进行操作,如</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">*((<span class="keyword">unsigned</span> <span class="keyword">int</span> *)(GPIOB_BASE+<span class="number">0X00</span>)) = <span class="number">0xffffffff</span>; <span class="comment">// 向GPIOB_BASE内写入 0xFFFFFFFF;</span></span><br></pre></td></tr></table></figure><a id="more"></a><p>然后看下这行代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> GPIOB ((GPIO_TypeDef *)GPIOB_BASE)</span></span><br></pre></td></tr></table></figure><p>这个是把<code>GPIOB_BASE</code>这个地址强制转换为<code>GPIO_TypeDef</code>结构体类型的基地址,<code>GPIOB_BASE</code>它的地址分配就和结构体一样了,<code>((GPIO_TypeDef *)GPIOB_BASE)</code>相当于一个结构体指针,因此就可以对结构体成员进行操作了。</p><p>这里是<code>STM32</code>的库函数中的<code>RCC</code>寄存器地址映射代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义RCC寄存器的基地址</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RCC_BASE (AHB1PERIPH_BASE + 0x3800)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//使用结构体来自动对齐RCC相关寄存器</span></span><br><span class="line"><span class="comment">//因为寄存器是32位/4字节,并且是连续的</span></span><br><span class="line"><span class="comment">//根据结构体数据的特性,使用 unsigned int (32位/4字节)可实现自动对齐</span></span><br><span class="line"><span class="comment">//__IO #define __IO volatile</span></span><br><span class="line"><span class="comment">//uint32_t typedef unsigned int uint32_t;</span></span><br><span class="line"><span class="comment">//RESERVED1[] : 保留地址,因为有些寄存器地址不连续,所以要对其进行占位,达到对齐的目的</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> CR; <span class="comment">/*!< RCC clock control register, Address offset: 0x00 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> PLLCFGR; <span class="comment">/*!< RCC PLL configuration register, Address offset: 0x04 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> CFGR; <span class="comment">/*!< RCC clock configuration register, Address offset: 0x08 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> CIR; <span class="comment">/*!< RCC clock interrupt register, Address offset: 0x0C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB1RSTR; <span class="comment">/*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB2RSTR; <span class="comment">/*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB3RSTR; <span class="comment">/*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */</span></span><br><span class="line"> <span class="keyword">uint32_t</span> RESERVED0; <span class="comment">/*!< Reserved, 0x1C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> APB1RSTR; <span class="comment">/*!< RCC APB1 peripheral reset register, Address offset: 0x20 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> APB2RSTR; <span class="comment">/*!< RCC APB2 peripheral reset register, Address offset: 0x24 */</span></span><br><span class="line"> <span class="keyword">uint32_t</span> RESERVED1[<span class="number">2</span>]; <span class="comment">/*!< Reserved, 0x28-0x2C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB1ENR; <span class="comment">/*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB2ENR; <span class="comment">/*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB3ENR; <span class="comment">/*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */</span></span><br><span class="line"> <span class="keyword">uint32_t</span> RESERVED2; <span class="comment">/*!< Reserved, 0x3C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> APB1ENR; <span class="comment">/*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> APB2ENR; <span class="comment">/*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */</span></span><br><span class="line"> <span class="keyword">uint32_t</span> RESERVED3[<span class="number">2</span>]; <span class="comment">/*!< Reserved, 0x48-0x4C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB1LPENR; <span class="comment">/*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB2LPENR; <span class="comment">/*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> AHB3LPENR; <span class="comment">/*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */</span></span><br><span class="line"> <span class="keyword">uint32_t</span> RESERVED4; <span class="comment">/*!< Reserved, 0x5C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> APB1LPENR; <span class="comment">/*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> APB2LPENR; <span class="comment">/*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */</span></span><br><span class="line"> <span class="keyword">uint32_t</span> RESERVED5[<span class="number">2</span>]; <span class="comment">/*!< Reserved, 0x68-0x6C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> BDCR; <span class="comment">/*!< RCC Backup domain control register, Address offset: 0x70 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> CSR; <span class="comment">/*!< RCC clock control & status register, Address offset: 0x74 */</span></span><br><span class="line"> <span class="keyword">uint32_t</span> RESERVED6[<span class="number">2</span>]; <span class="comment">/*!< Reserved, 0x78-0x7C */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> SSCGR; <span class="comment">/*!< RCC spread spectrum clock generation register, Address offset: 0x80 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> PLLI2SCFGR; <span class="comment">/*!< RCC PLLI2S configuration register, Address offset: 0x84 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> PLLSAICFGR; <span class="comment">/*!< RCC PLLSAI configuration register, Address offset: 0x88 */</span></span><br><span class="line"> __IO <span class="keyword">uint32_t</span> DCKCFGR; <span class="comment">/*!< RCC Dedicated Clocks configuration register, Address offset: 0x8C */</span></span><br><span class="line"></span><br><span class="line">} RCC_TypeDef;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将RCC_BASE 转换为RCC_TypeDef型指针</span></span><br><span class="line"><span class="comment">// 这样结构体就和寄存器地址一一对应起来了 寄存器映射</span></span><br><span class="line"><span class="comment">// 使用指针RCC 即可对其进行访问。</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RCC ((RCC_TypeDef *) RCC_BASE)</span></span><br></pre></td></tr></table></figure><p>这是RCC寄存器映射表,(详细的映射表请看STM32F4XX参考手册)</p><p><img src="https://i.loli.net/2020/09/22/2LSEdfQt3KiFvCr.png" alt="RCC寄存器映射表"></p>]]></content>
<summary type="html">
<h2 id="寄存器映射原理"><a href="#寄存器映射原理" class="headerlink" title="寄存器映射原理"></a>寄存器映射原理</h2><p>首先看下这行代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">((<span class="keyword">unsigned</span> <span class="keyword">int</span> *)(GPIOB_BASE+<span class="number">0X00</span>))</span><br></pre></td></tr></table></figure><p>其中<code>GPIOB_BASE</code>是GPIOB寄存器的起始地址,它是一个4字节(32位)的地址。但是电脑不知道它地址,因此需要在前面加一个<code>(unsigned int *)</code>对其进行强制类型转换,这个的作用就是把<code>GPIOB_BASE + 0x00</code>强制转化为地址,因为<code>*</code>符号运算的是地址,所以<code>(unsigned int *)(GPIOB_BASE + 0x00)</code>这一串就成了地址,相当与一个指针常量,当需要向其写入或者读取数据时就可以按按照指针的操作方式对其进行操作,如</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">*((<span class="keyword">unsigned</span> <span class="keyword">int</span> *)(GPIOB_BASE+<span class="number">0X00</span>)) = <span class="number">0xffffffff</span>; <span class="comment">// 向GPIOB_BASE内写入 0xFFFFFFFF;</span></span><br></pre></td></tr></table></figure>
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
</entry>
<entry>
<title>Ubuntu修改默认终端</title>
<link href="https://proudrabbit.gitee.io/Ubuntu%E4%BF%AE%E6%94%B9%E9%BB%98%E8%AE%A4%E7%BB%88%E7%AB%AF.html"/>
<id>https://proudrabbit.gitee.io/Ubuntu%E4%BF%AE%E6%94%B9%E9%BB%98%E8%AE%A4%E7%BB%88%E7%AB%AF.html</id>
<published>2020-09-19T13:59:47.000Z</published>
<updated>2021-08-06T09:37:30.403Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>在终端中输入如下命令即可,当然前提是安装了<code>Debian</code>的深度终端。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gsettings set org.gnome.desktop.default-applications.terminal exec /usr/bin/deepin-terminal </span><br><span class="line"></span><br><span class="line">gsettings set org.gnome.desktop.default-applications.terminal exec-arg "-x"</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
在Ubuntu下修改默认终端为Debian终端。
</summary>
<category term="随笔" scheme="https://proudrabbit.gitee.io/tags/%E9%9A%8F%E7%AC%94/"/>
<category term="Linux" scheme="https://proudrabbit.gitee.io/tags/Linux/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(六)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%85%AD%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%85%AD%EF%BC%89.html</id>
<published>2020-09-19T13:55:47.000Z</published>
<updated>2021-08-25T14:11:38.085Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><p><strong>正常工作中进行驱动开发的方式——子系统。</strong></p><h2 id="一、pinctrl子系统"><a href="#一、pinctrl子系统" class="headerlink" title="一、pinctrl子系统"></a>一、pinctrl子系统</h2><p> 借助<code>pinctrl</code>来设置一个<code>pin</code>的复用和电气属性。</p><p> <code>pinctrl</code> 子系统主要工作内容如下:</p><ol><li>获取设备树中的<code>pin</code>信息。</li><li>根据获取到的<code>pin</code>信息来设置<code>pin</code>的复用功能。</li><li>根据获取到的<code>pin</code>信息来设置<code>pin</code>的电气特性,比如上/下拉、速度、驱动能力等。</li></ol><a id="more"></a><p>对于使用者来说,只要在设备树里面设置某个<code>pin</code>的相关属性即可,其他的初始化工作由<code>pinctrl</code>子系统来完成,<code>pinctrl</code>子系统源码目录为<code>drivers/pinctrl</code>。根据设备的类型,会创建对应的子节点,然后设备所用<code>pin</code>都放到此节点。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">imx6ul-evk {</span><br><span class="line">pinctrl_hog_1: hoggrp-1 {</span><br><span class="line">fsl,pins = <</span><br><span class="line">MX6UL_PAD_UART1_RTS_B__GPIO1_IO190x17059 /* SD1 CD */</span><br><span class="line">MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT0x17059 /* SD1 VSELECT */</span><br><span class="line">MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */</span><br><span class="line">>;</span><br><span class="line">};</span><br><span class="line">......</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h2 id="二、gpio子系统"><a href="#二、gpio子系统" class="headerlink" title="二、gpio子系统"></a>二、gpio子系统</h2><p> 使用<code>gpio</code>子系统来使用<code>gpio</code>。</p><h2 id="三、驱动编写"><a href="#三、驱动编写" class="headerlink" title="三、驱动编写"></a>三、驱动编写</h2><ol><li>设备树修改</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">/ {</span><br><span class="line"> ......</span><br><span class="line"> </span><br><span class="line"> gpioled {</span><br><span class="line">compatible = <span class="string">"atkalpha,gpioled"</span>;</span><br><span class="line">pinctrl-names = <span class="string">"default"</span>;</span><br><span class="line">pinctrl<span class="number">-0</span> = <&pinctrl_gpioled>;</span><br><span class="line">led-gpios = <&gpio1 <span class="number">3</span> GPIO_ACTIVE_LOW>;</span><br><span class="line">status = <span class="string">"okay"</span>;</span><br><span class="line"></span><br><span class="line">}; </span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">&iomuxc {</span><br><span class="line">pinctrl-names = <span class="string">"default"</span>;</span><br><span class="line">pinctrl<span class="number">-0</span> = <&pinctrl_hog_1>;</span><br><span class="line">imx6ul-evk {</span><br><span class="line">pinctrl_hog_1: hoggrp<span class="number">-1</span> {</span><br><span class="line">fsl,pins = <</span><br><span class="line">MX6UL_PAD_UART1_RTS_B__GPIO1_IO19<span class="number">0x17059</span> <span class="comment">/* SD1 CD */</span></span><br><span class="line">MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT<span class="number">0x17059</span> <span class="comment">/* SD1 VSELECT */</span></span><br><span class="line">MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 <span class="number">0x17059</span> <span class="comment">/* SD1 RESET */</span></span><br><span class="line">>;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 自己定义的led */</span></span><br><span class="line">pinctrl_gpioled: ledgrp {</span><br><span class="line">fsl,pins = <</span><br><span class="line">MX6UL_PAD_GPIO1_IO03__GPIO1_IO03<span class="number">0X10B0</span></span><br><span class="line">>;</span><br><span class="line">};</span><br><span class="line"> ......</span><br><span class="line"> };</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">&tsc {</span><br><span class="line">pinctrl-names = <span class="string">"default"</span>;</span><br><span class="line">pinctrl<span class="number">-0</span> = <&pinctrl_tsc>;</span><br><span class="line">xnur-gpio = <&gpio1 <span class="number">3</span> GPIO_ACTIVE_LOW>;</span><br><span class="line">measure-<span class="built_in">delay</span>-time = <<span class="number">0xffff</span>>;</span><br><span class="line">pre-charge-time = <<span class="number">0xfff</span>>;</span><br><span class="line">status = <span class="string">"disable"</span>;<span class="comment">// 因为和LED灯使用引脚冲突,所以需要关闭</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><ol start="2"><li>驱动程序</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> GPIOLED_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> GPIOLED_NAME<span class="meta-string">"gpioled"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDOFF0</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDON 1</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">gpioled_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;</span><br><span class="line"><span class="keyword">int</span> major;</span><br><span class="line"><span class="keyword">int</span> minor;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span></span><br><span class="line"><span class="keyword">int</span> led_gpio;<span class="comment">/* led 所使用的 GPIO 编号 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">gpioled_dev</span> <span class="title">gpioled</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">led_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &gpioled;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">led_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">gpioled_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">led_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">gpioled_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> databuff[<span class="number">1</span>];</span><br><span class="line"><span class="keyword">int</span> ret;</span><br><span class="line"></span><br><span class="line">ret = copy_from_user(databuff, buf, count);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"kernel write failed!\r\n"</span>);</span><br><span class="line"><span class="keyword">return</span> -EFAULT;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(databuff[<span class="number">0</span>] == LEDON)</span><br><span class="line">{</span><br><span class="line">gpio_set_value(dev->led_gpio, <span class="number">0</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">gpio_set_value(dev->led_gpio, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">led_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">open</span> = led_open,</span><br><span class="line">.<span class="built_in">release</span> = led_release,</span><br><span class="line">.<span class="built_in">write</span> = led_write,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">led_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册字符设备驱动 */</span></span><br><span class="line">gpioled.major = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span>(gpioled.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 给定设备号 */</span></span><br><span class="line">gpioled.devid = MKDEV(gpioled.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">alloc_chrdev_region(&gpioled.devid, <span class="number">0</span>,GPIOLED_CNT,GPIOLED_NAME);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化cdev */</span></span><br><span class="line">gpioled.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&gpioled.cdev, &led_fops);</span><br><span class="line">ret = cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建类 */</span></span><br><span class="line">gpioled<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">GPIOLED_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(gpioled.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(gpioled.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 创建设备节点 */</span></span><br><span class="line">gpioled.device = device_create(gpioled.class, <span class="literal">NULL</span>, gpioled.devid, <span class="literal">NULL</span>, GPIOLED_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(gpioled.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(gpioled.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取设备节点 */</span></span><br><span class="line">gpioled.nd = of_find_node_by_path(<span class="string">"/gpioled"</span>);</span><br><span class="line"><span class="keyword">if</span> (gpioled.nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取LED对应的GPIO */</span></span><br><span class="line">gpioled.led_gpio = of_get_named_gpio(gpioled.nd, <span class="string">"led-gpios"</span>, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (gpioled.led_gpio < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 申请IO */</span></span><br><span class="line">ret = gpio_request(gpioled.led_gpio, <span class="string">"led_gpio"</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"failed to request the led\r\n"</span>);</span><br><span class="line"><span class="comment">/* <span class="doctag">NOTE:</span>申请失败的话,大部分原因这个IO被别的外设占用</span></span><br><span class="line"><span class="comment"> * 需要在设备树中屏蔽相关代码,或者status属性值设置为disable</span></span><br><span class="line"><span class="comment"> * 检查复用,也就是pinctl</span></span><br><span class="line"><span class="comment"> * gpio使用 </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用IO 设置为输出 默认为低电平*/</span></span><br><span class="line">ret = gpio_direction_output(gpioled.led_gpio, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_setoutput;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_setoutput:</span><br><span class="line">gpio_free(gpioled.led_gpio);</span><br><span class="line">fail_findnd:</span><br><span class="line">device_destroy(gpioled.class, gpioled.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(gpioled.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&gpioled.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">led_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">/* 释放IO */</span></span><br><span class="line">gpio_free(gpioled.led_gpio);</span><br><span class="line">device_destroy(gpioled.class, gpioled.devid);</span><br><span class="line">class_destroy(gpioled.class);</span><br><span class="line">cdev_del(&gpioled.cdev);</span><br><span class="line">unregister_chrdev_region(gpioled.devid,GPIOLED_CNT);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(led_init);</span><br><span class="line">module_exit(led_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(五)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%94%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%94%EF%BC%89.html</id>
<published>2020-09-19T13:51:40.000Z</published>
<updated>2021-08-25T14:11:38.004Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><h2 id="一、什么是设备树"><a href="#一、什么是设备树" class="headerlink" title="一、什么是设备树"></a>一、什么是设备树</h2><ol><li>设备树:设备和树。</li><li>描述设备树的文件叫做<code>DTS</code>(Device Tree Source),这个 <code>DTS</code> 文件采用树形结构描述本板级设备,也就是开发板上的设备信息。比如CPU数量、内存基地址、<code>IIC</code> 接口上外接了哪些设备等等。</li><li>由于以前板级信息都是写到 <code>.c</code> 文件里面,导致 <code>linux</code> 内核臃肿。因此将板级信息做成独立的格式,文件扩展名为 <code>.dts</code> 。一个平台或者机器对应一个 <code>.dts</code> 。</li></ol><a id="more"></a><h2 id="二、DTS、DTB和DTC的关系"><a href="#二、DTS、DTB和DTC的关系" class="headerlink" title="二、DTS、DTB和DTC的关系"></a>二、DTS、DTB和DTC的关系</h2><p><code>.dts</code> 相当于 <code>.c</code> ,就是DTS源码文件。<code>DTC</code> 工具相当于 <code>gcc</code> 编译器,将 <code>.dts</code> 编译成 <code>.dtb</code> 。<code>dtb</code> 相当于 <code>bin</code> 文件或可执行文件。</p><p>通过 <code>make dtbs</code> 命令来编译所有的 <code>.dts</code> 文件,通过 <code>make xxxxx.dtb</code> 来编译对应的 <code>.dts</code> 文件,需要在 <code>makefile</code> 中添加 <code>.dts</code> 文件所在路径。编译 <code>dts</code> 文件的 <code>Makefile</code> 在 <code>arch/arm/boot/dts</code> 下。</p><h2 id="三、DTS基本语法"><a href="#三、DTS基本语法" class="headerlink" title="三、DTS基本语法"></a>三、DTS基本语法</h2><p>这篇<a href="https://blog.csdn.net/u014717231/article/details/53139968" target="_blank" rel="noopener">DTS入门知识</a>博客对<code>DTS</code>进行了入门的讲解。</p><ol><li><p>DTS是 <code>/</code> 开始。</p></li><li><p>从 <code>/</code> 根节点开始描述设备信息。</p></li><li><p>在 <code>/</code> 根节点外有一些 <code>&cpu0</code> 的语句是”追加“。</p></li><li><p>节点名字的要求</p><p><code>label: node-name@unit-address</code> 标签: 节点名字@地址。</p><ul><li><code>label</code> :为了方便的访问节点。</li><li><code>node-name</code> :可使用的字符 [0~9] [a~z] [A~Z] [ , . + - _ ]。约定使用小写。</li><li><code>unit-address</code> :一般是外设寄存器的起始地址。有的是外设的设备地址或者其他含义,需要根据情况来分析。</li></ul></li></ol><h2 id="四、设备树在系统中的体现"><a href="#四、设备树在系统中的体现" class="headerlink" title="四、设备树在系统中的体现"></a>四、设备树在系统中的体现</h2><p>系统启动以后可以在根文件系统里面看到设备树的节点信息。在 <code>/proc/device-tree/</code> <code>-></code> <code>/sys/firmware/devicetree/base</code> 目录下存放着设备树信息。</p><p>内核启动的时候会解析设备树,然后在 <code>/proc/device-tree/</code>目录下呈现出来。</p><h2 id="五、特殊节点"><a href="#五、特殊节点" class="headerlink" title="五、特殊节点"></a>五、特殊节点</h2><ol><li><code>aliases</code> 节点,对节点进行取别名。</li><li><code>chosen</code> 节点,主要目的就是将 <code>uboot</code> 里面的 <code>bootargs</code> 环境变量值,传递给 <code>linux</code> 内核作为命令行参数 <code>cmd line</code> 。<code>uboot</code> 会将 <code>bootargs</code> 环境变量写入 <code>chosen</code> 节点中,通过 <code>fdt_chosen</code> 函数。</li></ol><h2 id="六、属性"><a href="#六、属性" class="headerlink" title="六、属性"></a>六、属性</h2><table><thead><tr><th>嵌入式不常用或弃用属性</th><th>实例</th><th>作用</th></tr></thead><tbody><tr><td>ranges</td><td>ranges = <child-bus-address,parent-bus-address,length> / <code>ranges;</code></td><td>ranges是一个地址映射/转换表,ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:<br><code>child-bus-address</code>:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占用的字长。<br><code>parent-bus-address</code>:父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物理地址所占用的字长。<br><code>length</code>:子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长。<br>如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换。</td></tr><tr><td>name</td><td></td><td>name 属性用于记录节点名字,name 属性已经被弃用,不推荐使用name 属性,一些老的设备树文件可能会使用此属性。</td></tr><tr><td>device_type</td><td>device_type = “cpu”;</td><td>用于描述设备的 FCode,但是设备树没有 FCode,所以此属性也被抛弃了。此属性只能用于 cpu 节点或者 memory 节点。imx6ull.dtsi 的 cpu0 节点用到了此属性。</td></tr></tbody></table><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* ranges属性不为空时 */</span></span><br><span class="line">soc {</span><br><span class="line">compatible = <span class="string">"simple-bus"</span>;</span><br><span class="line"><span class="meta">#address-cells = <span class="meta-string"><1>;</span></span></span><br><span class="line"><span class="meta">#size-cells = <span class="meta-string"><1>;</span></span></span><br><span class="line">ranges = <<span class="number">0x0</span> <span class="number">0xe0000000</span> <span class="number">0x00100000</span>>;</span><br><span class="line"></span><br><span class="line">serial {</span><br><span class="line">device_type = <span class="string">"serial"</span>;</span><br><span class="line">compatible = <span class="string">"ns16550"</span>;</span><br><span class="line">reg = <<span class="number">0x4600</span> <span class="number">0x100</span>>;</span><br><span class="line">clock-frequency = <<span class="number">0</span>>;</span><br><span class="line"><span class="built_in">interrupts</span> = <<span class="number">0xA</span> <span class="number">0x8</span>>;</span><br><span class="line">interrupt-parent = <&ipic>;</span><br><span class="line">};</span><br><span class="line">};</span><br><span class="line"> </span><br><span class="line">第 <span class="number">6</span> 行,节点 soc 定义的 ranges 属性,值为<<span class="number">0x0</span> <span class="number">0xe0000000</span> <span class="number">0x00100000</span>>,此属性值指定</span><br><span class="line">了一个 <span class="number">1024</span>KB(<span class="number">0x00100000</span>)的地址范围,子地址空间的物理起始地址为 <span class="number">0x0</span>,父地址空间的物</span><br><span class="line">理起始地址为 <span class="number">0xe0000000</span>。</span><br><span class="line">第 <span class="number">11</span> 行, serial 是串口设备节点, reg 属性定义了 serial 设备寄存器的起始地址为 <span class="number">0x4600</span>,</span><br><span class="line">寄存器长度为 <span class="number">0x100</span>。经过地址转换, serial 设备可以从 <span class="number">0xe0004600</span> 开始进行读写操作,</span><br><span class="line"><span class="number">0xe0004600</span> = <span class="number">0x4600</span> + <span class="number">0xe0000000</span>。</span><br></pre></td></tr></table></figure><hr><table><thead><tr><th>属性</th><th>实例/可选值</th><th>作用</th></tr></thead><tbody><tr><td>compatible</td><td>compatible = “fsl,imx6ul-evk-wm8960”,”fsl,imx-audio-wm8960”;</td><td>设备兼容属性</td></tr><tr><td>mode</td><td>model = “wm8960-audio”;</td><td>描述设备模块信息</td></tr><tr><td>status</td><td><code>okay</code>/<code>disabled</code>/<code>fail</code>/<code>fail-sss</code></td><td>描述设备状态</td></tr><tr><td>#address-cells</td><td>#address-cells = <1>;</td><td>描述了<strong>子节点</strong><code>reg</code>属性中地址信息所占用的字长(32 位)</td></tr><tr><td>#size-cells</td><td>#size-cells = <1>;</td><td>描述了<strong>子节点</strong><code>reg</code>属性中长度信息所占的字长(32 位)</td></tr><tr><td>reg</td><td>reg = <address1 length1 address2 length2……></td><td>描述设备起始地址和长度</td></tr></tbody></table><h2 id="七、特殊的属性"><a href="#七、特殊的属性" class="headerlink" title="七、特殊的属性"></a>七、特殊的属性</h2><p><code>compatible</code>属性,值是字符串。</p><p>根节点<code>/</code>下的<code>compatible</code>属性,内核在启动的时候会检查是否支持此平台,在以前不使用设备树的时候会通过<code>machine id</code>来判断内核是否支持此机器。使用设备数后不再使用机器ID,而是使用根节点<code>/</code>下的<code>compatible</code>属性。</p><p>未使用设备树的结构体</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MACHINE_START(_type,_name)\</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">machine_desc</span> __<span class="title">mach_desc_</span>##_<span class="title">type</span>\</span></span><br><span class="line"><span class="class">__<span class="title">used</span>\</span></span><br><span class="line"><span class="class">__<span class="title">attribute__</span>((__<span class="title">section__</span>(".<span class="title">arch</span>.<span class="title">info</span>.<span class="title">init</span>"))) = {</span>\</span><br><span class="line">.nr = MACH_TYPE_##_type,\</span><br><span class="line">.name = _name,\</span><br><span class="line"> </span><br><span class="line">#define MACHINE_END\</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>使用设备树的结构体</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DT_MACHINE_START(_name, _namestr)\</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">machine_desc</span> __<span class="title">mach_desc_</span>##_<span class="title">name</span>\</span></span><br><span class="line"><span class="class">__<span class="title">used</span> \</span></span><br><span class="line"><span class="class">__<span class="title">attribute__</span>((__<span class="title">section__</span>(".<span class="title">arch</span>.<span class="title">info</span>.<span class="title">init</span>"))) = {</span> \</span><br><span class="line">.nr = ~<span class="number">0</span>,\</span><br><span class="line">.name = _namestr,\</span><br><span class="line"></span><br><span class="line">#define MACHINE_END\</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h2 id="八、Linux内核的OF操作函数"><a href="#八、Linux内核的OF操作函数" class="headerlink" title="八、Linux内核的OF操作函数"></a>八、Linux内核的OF操作函数</h2><ol><li><p>驱动如何获取到设备树中的设备信息。在驱动中使用<code>OF</code>函数获取设备树属性内容。</p><ol start="2"><li><p>驱动要想获取到设备树节点内容,首先要找到节点。</p></li><li><p>查找节点的of函数:</p><ul><li><p><code>of_find_node_by_name</code>函数</p><p>of_find_node_by_name 函数通过节点名字查找指定的节点,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">struct device_node *<span class="title">of_find_node_by_name</span><span class="params">(struct device_node *from, <span class="keyword">const</span> <span class="keyword">char</span> *name)</span></span>;</span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>from:开始查找的节点,如果为<code>NULL</code>表示从根节点开始查找整个设备树。<br>name:要查找的节点名字。<br>返回值:找到的节点,如果为<code>NULL</code>表示查找失败。</p></li><li><p><code>of_find_node_by_type</code>函数</p><p>of_find_node_by_type 函数通过<code>device_type</code>属性查找指定的节点,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">struct device_node *<span class="title">of_find_node_by_type</span><span class="params">(struct device_node *from, <span class="keyword">const</span> <span class="keyword">char</span> *type)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>from:开始查找的节点,如果为 <code>NULL</code> 表示从根节点开始查找整个设备树。<br>type:要查找的节点对应的 <code>type</code> 字符串,也就是<code>device_type</code>属性值。<br>返回值:找到的节点,如果为<code>NULL</code>表示查找失败。</p></li><li><p><code>of_find_compatible_node</code>函数</p><p>of_find_compatible_node 函数根据<code>device_type</code>和<code>compatible</code>这两个属性查找指定的节点,<br>函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">struct device_node *<span class="title">of_find_compatible_node</span><span class="params">(struct device_node *from,</span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">const</span> <span class="keyword">char</span> *type, <span class="keyword">const</span> <span class="keyword">char</span> *compatible)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>from:开始查找的节点,如果为<code>NULL</code>表示从根节点开始查找整个设备树。<br>type:要查找的节点对应的<code>type</code>字符串,也就是<code>device_type</code>属性值,可以为<code>NULL</code>,表示忽略掉<code>device_type</code>属性。<br>compatible:要查找的节点所对应的<code>compatible</code>属性列表。<br>返回值:找到的节点,如果为<code>NULL</code>表示查找失败。</p></li><li><p><code>of_find_matching_node_and_match</code>函数</p><p>of_find_matching_node_and_match 函数通过<code>of_device_id</code>匹配表来查找指定的节点,函数原<br>型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">struct device_node *<span class="title">of_find_matching_node_and_match</span><span class="params">(struct device_node *from,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> struct of_device_id *matches,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> struct of_device_id **match)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:</p><p>from:开始查找的节点,如果为<code>NULL</code>表示从根节点开始查找整个设备树。<br>matches:<code>of_device_id</code>匹配表,也就是在此匹配表里面查找节点。<br>match:找到的匹配的<code>of_device_id</code>。</p><p>返回值:找到的节点,如果为<code>NULL</code>表示查找失败。</p></li><li><p><code>of_find_node_by_path</code>函数<br>of_find_node_by_path 函数通过路径来查找指定的节点,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">struct device_node *<span class="title">of_find_node_by_path</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *path)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>path:带有全路径的节点名,可以使用节点的别名,比如<code>/backlight</code>就是<code>backlight</code>这个节点的全路径。<br>返回值:找到的节点,如果为<code>NULL</code>表示查找失败。</p></li></ul></li></ol></li><li><p>查找父/子节点的of函数</p><ul><li><p><code>of_get_parent</code>函数</p><p>of_get_parent 函数用于获取指定节点的父节点(如果有父节点的话),函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">struct device_node *<span class="title">of_get_parent</span><span class="params">(<span class="keyword">const</span> struct device_node *node)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:</p><p>node:要查找的父节点的节点。<br>返回值:找到的父节点。</p></li><li><p><code>of_get_next_child</code>函数</p><p>of_get_next_child 函数用迭代的查找子节点,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">struct device_node *<span class="title">of_get_next_child</span><span class="params">(<span class="keyword">const</span> struct device_node *node,</span></span></span><br><span class="line"><span class="function"><span class="params">struct device_node *prev)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>node:父节点。<br>prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为<code>NULL</code>,表示从第一个子节点开始。<br>返回值:找到的下一个子节点。</p></li></ul></li><li><p>提取属性值的of函数</p><p>节点的属性信息里面保存了驱动所需要的内容,因此对于属性值的提取非常重要, Linux 内<br>核中使用结构体<code>property</code>表示属性,此结构体同样定义在文件<code>include/linux/of.h</code>中,内容如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">property</span> {</span></span><br><span class="line"><span class="keyword">char</span> *name;<span class="comment">/* 属性名字 */</span></span><br><span class="line"><span class="keyword">int</span> length; <span class="comment">/* 属性长度*/</span></span><br><span class="line"><span class="keyword">void</span> *value;<span class="comment">/* 属性值 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">property</span> *<span class="title">next</span>;</span><span class="comment">/* 下一个属性*/</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">long</span> _flags; </span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">int</span> unique_id;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">bin_attribute</span> <span class="title">attr</span>;</span> </span><br><span class="line">};</span><br></pre></td></tr></table></figure><ul><li><p><code>of_find_property</code>函数</p><p>of_find_property 函数用于查找指定的属性,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">property *<span class="title">of_find_property</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">const</span> <span class="keyword">char</span> *name,<span class="keyword">int</span> *lenp)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>name:属性名字。<br>lenp:属性值的字节数<br>返回值:找到的属性。</p></li><li><p><code>of_property_count_elems_of_size</code>函数</p><p>of_property_count_elems_of_size 函数用于获取属性中元素的数量,比如<code>reg</code>属性值是一个<br>数组,那么使用此函数可以获取到这个数组的大小,此函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_count_elems_of_size</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">const</span> <span class="keyword">char</span> *propname, <span class="keyword">int</span> elem_size)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>proname:需要统计元素数量的属性名字。<br>elem_size:元素长度。<br>返回值:得到的属性元素数量。</p></li><li><p><code>of_property_read_u32_index</code>函数</p><p>of_property_read_u32_index 函数用于从属性中获取指定标号的<code>u32</code>类型数据值(无符号 32<br>位),比如某个属性有多个<code>u32</code>类型的值,那么就可以使用此函数来获取指定标号的数据值,此<br>函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u32_index</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">const</span> <span class="keyword">char</span> *propname, u32 index,</span></span></span><br><span class="line"><span class="function"><span class="params"> u32 *out_value)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>proname:要读取的属性名字。<br>index:要读取的值标号。<br>out_value:读取到的值<br>返回值:0 读取成功,负值,读取失败,<code>-EINVAL</code>表示属性不存在,<code>-ENODATA</code>表示没有<br>要读取的数据,<code>-EOVERFLOW</code>表示属性值列表太小。</p></li><li><p><code>of_property_read_u8_array</code> 函数<br><code>of_property_read_u16_array</code> 函数<br><code>of_property_read_u32_array</code> 函数<br><code>of_property_read_u64_array</code> 函数</p><p>这 4 个函数分别是读取属性中 <code>u8</code>、<code>u16</code>、<code>u32</code> 和 <code>u64</code> 类型的数组数据,比如大多数的<code>reg</code>属<br>性都是数组数据,可以使用这 4 个函数一次读取出<code>reg</code>属性中的所有数据。这四个函数的原型<br>如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u8_array</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span> *propname,</span></span></span><br><span class="line"><span class="function"><span class="params"> u8 *out_values, <span class="keyword">size_t</span> sz)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u16_array</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span> *propname,</span></span></span><br><span class="line"><span class="function"><span class="params"> u16 *out_values, <span class="keyword">size_t</span> sz)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u32_array</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span> *propname,</span></span></span><br><span class="line"><span class="function"><span class="params"> u32 *out_values, <span class="keyword">size_t</span> sz)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u64_array</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span> *propname,</span></span></span><br><span class="line"><span class="function"><span class="params"> u64 *out_values,<span class="keyword">size_t</span> sz)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>proname:要读取的属性名字。<br>out_value:读取到的数组值,分别为<code>u8</code>、<code>u16</code>、<code>u32</code>和<code>u64</code>。<br>sz:要读取的数组元素数量。<br>返回值:0,读取成功,负值,读取失败,<code>-EINVAL</code>表示属性不存在,<code>-ENODATA</code>表示没<br>有要读取的数据,<code>-EOVERFLOW</code>表示属性值列表太小。</p></li><li><p><code>of_property_read_u8</code> 函数<br><code>of_property_read_u16</code> 函数<br><code>of_property_read_u32</code> 函数<br><code>of_property_read_u64</code> 函数</p><p>有些属性只有一个整形值,这四个函数就是用于读取这种只有一个整形值的属性,分别用<br>于读取 u8、u16、u32 和 u64 类型属性值,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u8</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">const</span> <span class="keyword">char</span> *propname, u8*out_value)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u16</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span> *propname, u16 *out_value)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u32</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span>*propname, u32 *out_value)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_u64</span><span class="params">(<span class="keyword">const</span> struct device_node *np,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span> *propname, u64 *out_value)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>proname:要读取的属性名字。<br>out_value:读取到的数组值。<br>返回值:0,读取成功,负值,读取失败,<code>-EINVAL</code>表示属性不存在,<code>-ENODATA</code>表示没<br>有要读取的数据,<code>-EOVERFLOW</code>表示属性值列表太小。</p></li><li><p><code>of_property_read_string</code> 函数</p><p>of_property_read_string 函数用于读取属性中字符串值,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_property_read_string</span><span class="params">(struct device_node *np,<span class="keyword">const</span> <span class="keyword">char</span> *propname,</span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">const</span> <span class="keyword">char</span> **out_string)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>proname:要读取的属性名字。<br>out_string:读取到的字符串值。<br>返回值:0,读取成功,负值,读取失败。</p></li><li><p><code>of_n_addr_cells</code> 函数</p><p>of_n_addr_cells 函数用于获取<code>#address-cells</code>属性值,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_n_addr_cells</span><span class="params">(struct device_node *np)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>返回值:获取到的<code>#address-cells</code>属性值。</p></li><li><p><code>of_n_size_cells</code> 函数</p><p>of_size_cells 函数用于获取<code>#size-cells</code>属性值,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_n_size_cells</span><span class="params">(struct device_node *np)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>返回值:获取到的<code>#size-cells</code>属性值。</p></li></ul></li><li><p>其他常用of函数</p><ul><li><p><code>of_device_is_compatible</code>函数</p><p>of_device_is_compatible 函数用于查看节点的<code>compatible</code>属性是否有包含<code>compat</code>指定的字<br>符串,也就是检查设备节点的兼容性,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_device_is_compatible</span><span class="params">(<span class="keyword">const</span> struct device_node *device,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">char</span> *compat)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>device:设备节点。<br>compat:要查看的字符串。<br>返回值: 0,节点的<code>compatible</code>属性中不包含<code>compat</code>指定的字符串;正数,节点的 <code>compatible</code><br>属性中包含<code>compat</code>指定的字符串。</p></li><li><p><code>of_get_address</code> 函数</p><p>of_get_address 函数用于获取地址相关属性,主要是<code>reg</code>或者<code>assigned-addresses</code>属性<br>值,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">const</span> __be32 *<span class="title">of_get_address</span><span class="params">(struct device_node *dev,<span class="keyword">int</span> index,</span></span></span><br><span class="line"><span class="function"><span class="params"> u64 *<span class="built_in">size</span>, <span class="keyword">unsigned</span> <span class="keyword">int</span> *flags)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>dev:设备节点。<br>index:要读取的地址标号。<br>size:地址长度。<br>flags:参数,比如<code>IORESOURCE_IO</code>、<code>IORESOURCE_MEM</code>等<br>返回值:读取到的地址数据首地址,为<code>NULL</code>的话表示读取失败。</p></li><li><p><code>of_translate_address</code> 函数</p><p>of_translate_address 函数负责将从设备树读取到的地址转换为物理地址,函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">u64 <span class="title">of_translate_address</span><span class="params">(struct device_node *dev,<span class="keyword">const</span> __be32 *in_addr)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>dev:设备节点。<br>in_addr:要转换的地址。<br>返回值:得到的物理地址,如果为<code>OF_BAD_ADDR</code>的话表示转换失败。</p></li><li><p><code>of_address_to_resource</code> 函数</p><p><code>IIC</code>、<code>SPI</code>、<code>GPIO</code> 等这些外设都有对应的寄存器,这些寄存器其实就是一组内存空间,Linux<br>内核使用<code>resource</code>结构体来描述一段内存空间,“ resource”翻译出来就是“资源”,因此用<code>resource</code>结构体描述的都是设备资源信息,<code>resource</code>结构体定义在文件<code>include/linux/ioport.h</code>中,定义如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">resource</span> {</span></span><br><span class="line"> <span class="keyword">resource_size_t</span> start;</span><br><span class="line"> <span class="keyword">resource_size_t</span> <span class="built_in">end</span>;</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span> *name;</span><br><span class="line"> <span class="keyword">unsigned</span> <span class="keyword">long</span> flags;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">resource</span> *<span class="title">parent</span>, *<span class="title">sibling</span>, *<span class="title">child</span>;</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>对于 32 位的 SOC 来说,<code>resource_size_t</code>是 <code>u32</code> 类型的。其中<code>start</code>表示开始地址,<code>end</code> 表示结束地址,<code>name</code>是这个资源的名字,<code>flags</code>是资源标志位,一般表示资源类型,可选的资源标志<br>定义在文件<code>include/linux/ioport.h</code>中,如下所示:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_BITS 0x000000ff</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_TYPE_BITS 0x00001f00</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_IO 0x00000100</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_MEM 0x00000200</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_REG 0x00000300</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_IRQ 0x00000400</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_DMA 0x00000800</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_BUS 0x00001000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_PREFETCH 0x00002000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_READONLY 0x00004000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_CACHEABLE 0x00008000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_RANGELENGTH 0x00010000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_SHADOWABLE 0x00020000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_SIZEALIGN 0x00040000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_STARTALIGN 0x00080000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_MEM_64 0x00100000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_WINDOW 0x00200000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_MUXED 0x00400000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_EXCLUSIVE 0x08000000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_DISABLED 0x10000000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_UNSET 0x20000000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_AUTO 0x40000000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IORESOURCE_BUSY 0x80000000</span></span><br></pre></td></tr></table></figure><p>一般最常见的资源标志就是<code>IORESOURCE_MEM</code>、 <code>IORESOURCE_REG</code>和<code>IORESOURCE_IRQ</code>等。接下来我们回到<code>of_address_to_resource</code>函数,此函数看名字像是从设备树里面提取资源值,但是本质上就是将<code>reg</code>属性值,然后将其转换为<code>resource</code>结构体类型,函数原型如下所示:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">of_address_to_resource</span><span class="params">(struct device_node *dev,<span class="keyword">int</span> index,</span></span></span><br><span class="line"><span class="function"><span class="params"> struct resource *r)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>dev:设备节点。<br>index:地址资源标号。<br>r:得到的<code>resource</code>类型的资源值。<br>返回值:0,成功;负值,失败。</p></li><li><p><code>of_iomap</code>函数</p><p>of_iomap 函数用于直接内存映射,以前我们会通过<code>ioremap</code>函数来完成物理地址到虚拟地<br>址的映射,采用设备树以后就可以直接通过<code>of_iomap</code>函数来获取内存地址所对应的虚拟地址,<br>不需要使用<code>ioremap</code>函数了。当然了,你也可以使用<code>ioremap</code>函数来完成物理地址到虚拟地址<br>的内存映射,只是在采用设备树以后,大部分的驱动都使用<code>of_iomap</code>函数了,<code>of_iomap</code>函数本<br>质上也是将<code>reg</code>属性中地址信息转换为虚拟地址,如果<code>reg</code>属性有多段的话,可以通过<code>index</code>参<br>数指定要完成内存映射的是哪一段,<code>of_iomap</code>函数原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> __iomem *<span class="title">of_iomap</span><span class="params">(struct device_node *np, <span class="keyword">int</span> index)</span></span></span><br></pre></td></tr></table></figure><p>函数参数和返回值含义如下:<br>np:设备节点。<br>index:<code>reg</code>属性中要完成内存映射的段,如果<code>reg</code>属性只有一段的话<code>index</code>就设置为 0。<br>返回值:经过内存映射后的虚拟内存首地址,如果为<code>NULL</code>的话表示内存映射失败。</p></li></ul></li></ol><h2 id="九、设备树添加内容(开发中一般不使用这种方式)"><a href="#九、设备树添加内容(开发中一般不使用这种方式)" class="headerlink" title="九、设备树添加内容(开发中一般不使用这种方式)"></a>九、设备树添加内容(开发中一般不使用这种方式)</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 自己添加的节点 2020-9-17 */</span></span><br><span class="line">alphaled {</span><br><span class="line"> <span class="meta">#address-cells = <span class="meta-string"><1>;</span></span></span><br><span class="line"> <span class="meta">#size-cells = <span class="meta-string"><1>;</span></span></span><br><span class="line"> compatible = <span class="string">"atkalpha-led"</span>;</span><br><span class="line"> status = <span class="string">"okay"</span>;</span><br><span class="line"> reg = <<span class="number">0X020C406C</span> <span class="number">0X04</span><span class="comment">/* CCM_CCGR1_BASE */</span></span><br><span class="line"> <span class="number">0X020E0068</span> <span class="number">0X04</span><span class="comment">/* SW_MUX_GPIO1_IO03_BASE */</span></span><br><span class="line"> <span class="number">0X020E02F4</span> <span class="number">0X04</span><span class="comment">/* SW_PAD_GPIO1_IO03_BASE */</span></span><br><span class="line"> <span class="number">0X0209C000</span> <span class="number">0X04</span><span class="comment">/* GPIO1_DR_BASE */</span></span><br><span class="line"> <span class="number">0X0209C004</span> <span class="number">0X04</span><span class="comment">/* GPIO1_GPIR_BASE */</span></span><br><span class="line"> >;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h2 id="十、驱动使用设备树例子"><a href="#十、驱动使用设备树例子" class="headerlink" title="十、驱动使用设备树例子"></a>十、驱动使用设备树例子</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 入口和出口函数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">dtsof_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">np</span> = <span class="title">NULL</span>;</span> <span class="comment">// 节点</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">property</span> *<span class="title">comppro</span> = <span class="title">NULL</span>;</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span> *str;</span><br><span class="line">u32 def_value = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> elesize = <span class="number">0</span>;</span><br><span class="line">u32 *brival;</span><br><span class="line"><span class="keyword">int</span> i;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 找到backlight节点 */</span></span><br><span class="line">np = of_find_node_by_path(<span class="string">"/backlight"</span>);</span><br><span class="line"><span class="keyword">if</span> (np == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取属性 */</span></span><br><span class="line">comppro = of_find_property(np, <span class="string">"compatible"</span>, <span class="literal">NULL</span>);</span><br><span class="line"><span class="keyword">if</span> (comppro == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_findpro;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"compatible=%s\r\n"</span>, (<span class="keyword">char</span> *)comppro->value);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">ret = of_property_read_string(np, <span class="string">"status"</span>, &str);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_rs;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"status=%s\r\n"</span>, str);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3 获取数字属性值 */</span></span><br><span class="line">ret = of_property_read_u32(np, <span class="string">"default-brightness-level"</span>, &def_value);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_read_u32;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"default-brightness-level = %d\r\n"</span>, def_value);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取数组类型的属性 */</span></span><br><span class="line">elesize = of_property_count_elems_of_size(np, <span class="string">"brightness-levels"</span>, <span class="keyword">sizeof</span>(u32));</span><br><span class="line"><span class="keyword">if</span> (elesize < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_readele;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"brightness-levels elems size = %d\r\n"</span>, elesize);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 申请内存 */</span></span><br><span class="line">brival = kmalloc(elesize * <span class="keyword">sizeof</span>(u32), GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (!brival)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_mem;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取数组 */</span></span><br><span class="line">ret = of_property_read_u32_array(np, <span class="string">"brightness-levels"</span>, brival, elesize);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_read32array;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">for</span> ( i = <span class="number">0</span>; i < elesize; i++)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"brightness-levels[%d] = %d \r\n"</span>, i, brival[i]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">kfree(brival);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">fail_read32array:</span><br><span class="line">kfree(brival);<span class="comment">/* 释放内存 */</span></span><br><span class="line">fail_mem:</span><br><span class="line">fail_readele:</span><br><span class="line">fail_read_u32:</span><br><span class="line">fail_rs:</span><br><span class="line">str = <span class="literal">NULL</span>;</span><br><span class="line">fail_findpro:</span><br><span class="line">fail_findnd:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">dtsof_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 注册入口和出口函数</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line">module_init(dtsof_init);</span><br><span class="line">module_exit(dtsof_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h2 id="十一、设备树下的LED驱动实验"><a href="#十一、设备树下的LED驱动实验" class="headerlink" title="十一、设备树下的LED驱动实验"></a>十一、设备树下的LED驱动实验</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_address.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/of_irq.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DTSLED_CNT1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DTSLED_NAME<span class="meta-string">"dtsled"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDOFF0</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDON 1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 虚拟地址的指针 */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *CCM_CCGR1;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *SW_MUX_GPIO1_IO03;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *SW_PAD_GPIO1_IO03;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *GPIO1_GDIR;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *GPIO1_DR;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">dtsled_dev</span> {</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">/* 设备号 */</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">/* 主设备号 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">/* 类 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">/* 设备 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">nd</span>;</span><span class="comment">/* 设备节点 */</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">dtsled_dev</span> <span class="title">dtsled</span>;</span><span class="comment">/* LED设备 */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">led_toggle</span><span class="params">(u8 state)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">u32 val = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(state == LEDON)</span><br><span class="line">{</span><br><span class="line">val = readl(GPIO1_DR);</span><br><span class="line">val &= ~(<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_DR);<span class="comment">// 打开LED</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">val = readl(GPIO1_DR);</span><br><span class="line">val |= (<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_DR);<span class="comment">// 关闭LED</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">dtsled_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = &dtsled;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">dtsled_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">dtsled_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">dtsled_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> count, <span class="keyword">loff_t</span> *ppos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> retvalue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> databuff[<span class="number">1</span>];</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">dtsled_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br><span class="line"></span><br><span class="line">retvalue = copy_from_user(databuff, buf, count);</span><br><span class="line"><span class="keyword">if</span> (retvalue < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"kernel write failed!\r\n"</span>);</span><br><span class="line"><span class="keyword">return</span> -EFAULT;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (databuff[<span class="number">0</span>] == LEDON)</span><br><span class="line">{</span><br><span class="line">led_toggle(LEDON);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">led_toggle(LEDOFF);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 字符操作设备集 */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">dtsled_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">write</span> = dtsled_write,</span><br><span class="line">.<span class="built_in">open</span> = dtsled_open,</span><br><span class="line">.<span class="built_in">release</span> = dtsled_release,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 入口和出口 */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">dtsled_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> i;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span> *str;</span><br><span class="line">u32 regdata[<span class="number">10</span>];</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">int</span> val;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 1.注册字符设备 */</span></span><br><span class="line"><span class="comment">/* 1.1 申请设备号 */</span></span><br><span class="line">dtsled.major = <span class="number">0</span>;<span class="comment">/* 设备号由内核分配 */</span></span><br><span class="line"><span class="keyword">if</span> (dtsled.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 定义了设备号 */</span></span><br><span class="line">dtsled.devid = MKDEV(dtsled.major,<span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="comment">/* 没有给定设备号,向内核申请*/</span></span><br><span class="line">ret = alloc_chrdev_region(&dtsled.devid, <span class="number">0</span>, DTSLED_CNT, DTSLED_NAME);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 1.1 添加字符设备 */</span></span><br><span class="line">dtsled.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&dtsled.cdev, &dtsled_fops);</span><br><span class="line">ret = cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3.自动创建设备节点 */</span></span><br><span class="line"><span class="comment">/* 3.1 创建类 */</span></span><br><span class="line">dtsled<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>,<span class="title">DTSLED_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(dtsled.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(dtsled.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3.2创建设备节点 */</span></span><br><span class="line">dtsled.device = device_create(dtsled.class, <span class="literal">NULL</span>, dtsled.devid, <span class="literal">NULL</span>, DTSLED_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(dtsled.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(dtsled.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 获取设备树属性内容 */</span></span><br><span class="line">dtsled.nd = of_find_node_by_path(<span class="string">"/alphaled"</span>);</span><br><span class="line"><span class="keyword">if</span> (dtsled.nd == <span class="literal">NULL</span>)</span><br><span class="line">{</span><br><span class="line">ret = -EINVAL;</span><br><span class="line"><span class="keyword">goto</span> fail_findnd;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">ret = of_property_read_string(dtsled.nd, <span class="string">"status"</span>, &str);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_rs;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"status = %s\r\n"</span>, str);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">ret = of_property_read_string(dtsled.nd, <span class="string">"compatible"</span>, &str);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_rs;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"compatible = %s\r\n"</span>, str);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line">ret = of_property_read_u32_array(dtsled.nd, <span class="string">"reg"</span>, regdata, <span class="number">10</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_rs;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"red data:"</span>);</span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < <span class="number">10</span>; i++)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"%#x "</span>, regdata[i]);</span><br><span class="line">}</span><br><span class="line">printk(<span class="string">"\r\n"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* LED初始化 */</span></span><br><span class="line"><span class="comment">/* 地址映射 */</span></span><br><span class="line"></span><br><span class="line">CCM_CCGR1 = ioremap(regdata[<span class="number">0</span>], regdata[<span class="number">1</span>]);</span><br><span class="line">SW_MUX_GPIO1_IO03 = ioremap(regdata[<span class="number">2</span>], regdata[<span class="number">3</span>]);</span><br><span class="line">SW_PAD_GPIO1_IO03 = ioremap(regdata[<span class="number">4</span>], regdata[<span class="number">5</span>]);</span><br><span class="line">GPIO1_DR = ioremap(regdata[<span class="number">6</span>], regdata[<span class="number">7</span>]);</span><br><span class="line">GPIO1_GDIR = ioremap(regdata[<span class="number">8</span>], regdata[<span class="number">9</span>]);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="comment">/* 使用of_iomap直接获取地址映射 */</span></span><br><span class="line">CCM_CCGR1 = of_iomap(dtsled.nd, <span class="number">0</span>);</span><br><span class="line">SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, <span class="number">1</span>);</span><br><span class="line">SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, <span class="number">2</span>);</span><br><span class="line">GPIO1_DR = of_iomap(dtsled.nd, <span class="number">3</span>);</span><br><span class="line">GPIO1_GDIR = of_iomap(dtsled.nd, <span class="number">4</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化 */</span></span><br><span class="line">val = readl(CCM_CCGR1);</span><br><span class="line">val &= ~(<span class="number">3</span> << <span class="number">26</span>);</span><br><span class="line">val |= (<span class="number">3</span> << <span class="number">26</span>);</span><br><span class="line">writel(val, CCM_CCGR1);<span class="comment">// 使能时钟</span></span><br><span class="line"></span><br><span class="line">writel(<span class="number">0x5</span>, SW_MUX_GPIO1_IO03);<span class="comment">// 设置复用</span></span><br><span class="line">writel(<span class="number">0x10b0</span>, SW_PAD_GPIO1_IO03);<span class="comment">// 设置电气属性</span></span><br><span class="line"></span><br><span class="line">val = readl(GPIO1_GDIR);</span><br><span class="line">val |= (<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_GDIR);<span class="comment">// 设置输出</span></span><br><span class="line"></span><br><span class="line">val = readl(GPIO1_DR);</span><br><span class="line">val &= ~(<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_DR);<span class="comment">// 默认打开LED</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_rs:</span><br><span class="line">fail_findnd:</span><br><span class="line">device_destroy(dtsled.class, dtsled.devid);</span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(dtsled.class);</span><br><span class="line">fail_class:</span><br><span class="line">cdev_del(&dtsled.cdev);</span><br><span class="line">fail_cdev:</span><br><span class="line">unregister_chrdev_region(dtsled.devid, DTSLED_CNT);</span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">dtsled_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">/* 取消地址映射 */</span></span><br><span class="line">iounmap(CCM_CCGR1);</span><br><span class="line">iounmap(SW_MUX_GPIO1_IO03);</span><br><span class="line">iounmap(SW_PAD_GPIO1_IO03);</span><br><span class="line">iounmap(GPIO1_DR);</span><br><span class="line">iounmap(GPIO1_GDIR);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 摧毁设备 */</span></span><br><span class="line">device_destroy(dtsled.class, dtsled.devid);</span><br><span class="line"><span class="comment">/* 摧毁类 */</span></span><br><span class="line">class_destroy(dtsled.class);</span><br><span class="line"><span class="comment">/* 删除字符设备 */</span></span><br><span class="line">cdev_del(&dtsled.cdev);</span><br><span class="line"><span class="comment">/* 释放设备号 */</span></span><br><span class="line">unregister_chrdev_region(dtsled.devid, DTSLED_CNT);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注册驱动和卸载驱动 */</span></span><br><span class="line">module_init(dtsled_init);</span><br><span class="line">module_exit(dtsled_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h2 id="十二、测试应用程序"><a href="#十二、测试应用程序" class="headerlink" title="十二、测试应用程序"></a>十二、测试应用程序</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ./ledAPP <filename> <0:1> 1 表示开灯 0 表示关灯</span></span><br><span class="line"><span class="comment"> * @param argc 应用程序参数个数</span></span><br><span class="line"><span class="comment"> * @param argv 保存的参数,字符串形式。</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> fd = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">char</span> *filename;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> databuff[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> ( argc !=<span class="number">3</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"输入错误\r\n"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">filename = argv[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">fd = <span class="built_in">open</span>(filename, O_RDWR);</span><br><span class="line"><span class="keyword">if</span>(fd < <span class="number">0</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: %s\r\n"</span>,filename);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 读 */</span></span><br><span class="line"><span class="comment">/* if (atoi(argv[2]) ==1 )// 传递过来的是字符串,需要转换成数字</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">ret = read(fd, readbuf, 10);</span></span><br><span class="line"><span class="comment">if (ret < 0)</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">printf("read file %s failed\r\n", filename);</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">else</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">} */</span></span><br><span class="line"></span><br><span class="line">databuff[<span class="number">0</span>] = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 写 */</span></span><br><span class="line">ret = <span class="built_in">write</span>(fd, databuff, <span class="keyword">sizeof</span>(databuff));</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"LED control failed!\r\n"</span>);</span><br><span class="line"><span class="built_in">close</span>(fd);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 关闭 */</span></span><br><span class="line">ret = <span class="built_in">close</span>(fd);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>IMX6ULL嵌入式Linux驱动学习笔记(四)</title>
<link href="https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%9B%9B%EF%BC%89.html"/>
<id>https://proudrabbit.gitee.io/IMX6ULL%E5%B5%8C%E5%85%A5%E5%BC%8FLinux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E5%9B%9B%EF%BC%89.html</id>
<published>2020-09-19T13:48:02.000Z</published>
<updated>2021-08-25T14:11:38.110Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p><strong>IMX6ULL嵌入式Linux驱动开发学习</strong></p><p>以下内容是我在学习正点原子<code>IMX6ULL</code>开发板<code>alpha</code>中记录的笔记,部分摘录自正点原子<code>IMX6ULL开发手册</code>。</p><h2 id="一、新字符设备驱动原理(相比于上一篇笔记)"><a href="#一、新字符设备驱动原理(相比于上一篇笔记)" class="headerlink" title="一、新字符设备驱动原理(相比于上一篇笔记)"></a>一、新字符设备驱动原理(相比于上一篇笔记)</h2><ol><li><p>以前的缺点:</p><p>使用 <code>register_chrdev</code> 函数注册字符设备,会浪费很多次设备号,而且需要手动指定。</p></li><li><p>新的方法:</p><p>使用 <code>alloc_chrdev_region</code> 函数申请设备号。原型如下:</p><a id="more"></a></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">alloc_chrdev_region</span><span class="params">(<span class="keyword">dev_t</span> *dev, <span class="keyword">unsigned</span> baseminor, <span class="keyword">unsigned</span> count, <span class="keyword">const</span> <span class="keyword">char</span> *name)</span></span></span><br></pre></td></tr></table></figure><p>卸载驱动的时候,使用 <code>unregister_chrdev_region</code> 函数释放前面申请的设备号,原型如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">unregister_chrdev_region</span><span class="params">(<span class="keyword">dev_t</span> from, <span class="keyword">unsigned</span> count)</span></span></span><br></pre></td></tr></table></figure><ol start="3"><li><p>指定设备号</p><p>如果指定主设备号,使用 <code>register_chrdev_region</code> 函数来注册,原型如下:</p></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">register_chrdev_region</span><span class="params">(<span class="keyword">dev_t</span> from, <span class="keyword">unsigned</span> count, <span class="keyword">const</span> <span class="keyword">char</span> *name)</span></span></span><br></pre></td></tr></table></figure><pre><code>一般是给定主设备号,然后使用 `MADEV` 构建完整的 `dev_t` ,一般次设备号选择`0`。</code></pre><ol start="4"><li><p>实际的驱动编写</p><p>需要考虑实际情况,因为在实际开发中会有两种情况:给定设备号和没有给定设备号。</p></li><li><p>字符设备注册</p><p><code>cdev</code> 结构体表示字符设备,然后使用 <code>cdev_init</code> 函数来初始化 <code>cdev</code> ,原型</p></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cdev_init(struct cdev *cdev, <span class="keyword">const</span> struct file_operations *fops)</span><br></pre></td></tr></table></figure><p> <code>cdev_init</code> 初始化完成 <code>cdev</code> 后,使用 <code>cdev_add</code> 添加到Linux内核,删除字符设备使用 <code>cdev_del</code> 。</p><h2 id="二、自动创建设备节点"><a href="#二、自动创建设备节点" class="headerlink" title="二、自动创建设备节点"></a>二、自动创建设备节点</h2><ol><li>linux内核在2.6版本中引入了 <code>udev</code> 机制,替换<code>devfs</code> 。<code>udev</code> 机制提供热插拔管理,可以在加载驱动的时候自动创建 <code>/dev/xxx</code> 设备文件。</li><li>在使用busybox构建根文件系统的时候,busybox会创建一个 <code>udev</code> 的简化版本 <code>mdev</code> ,所以在嵌入式linux中使用 <code>mdev</code> 来实现设备节点文件的自动创建和删除。linux系统中的热插拔事件也由 <code>mdev</code> 管理,在 <code>/etc/init.d/rsS</code> 文件中如下语句。</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">11 <span class="built_in">echo</span> /sbin/mdev > /proc/sys/kernel/hotplug</span><br><span class="line">12 mdev -s</span><br></pre></td></tr></table></figure><ol start="3"><li><p>创建设备节点<br>3.1. 创建设备类</p><p>创建设备节点需要先使用<code>class_create()</code> 函数创建类。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 创建类 */</span></span><br><span class="line">newChrLed<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">LED_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(newChrLed.class))</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> PTR_ERR(newChrLed.class);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>3.2. 创建设备节点</p><p>使用 <code>device_create()</code> 函数来创建设备节点。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">newChrLed.device = device_create(newChrLed.class, <span class="literal">NULL</span>, newChrLed.devid, <span class="literal">NULL</span>, LED_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(newChrLed.device))</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> PTR_ERR(newChrLed.device);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>销毁设备节点和类</p><p>在驱动卸载的时候,需要对设备节点进行销毁。在驱动出口函数中使用如下代码进行销毁:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 摧毁设备节点 */</span></span><br><span class="line">device_destroy(newChrLed.class, newChrLed.devid);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 摧毁类 */</span></span><br><span class="line">class_destroy(newChrLed.class);</span><br></pre></td></tr></table></figure></li></ol><p> <strong>因为创建设备节点是根据类来创建的,因此在销毁时,需要先销毁设备节点再销毁类。</strong></p><h2 id="三、文件私有数据"><a href="#三、文件私有数据" class="headerlink" title="三、文件私有数据"></a>三、文件私有数据</h2><ol><li>在 <code>open</code> 函数里设置 <code>filp->private_data</code> 为设备变量。</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 设置私有数据 */</span></span><br><span class="line">filp->private_data= &newChrLed;</span><br></pre></td></tr></table></figure><ol start="2"><li>在其他的函数里,要访问设备的时候,直接读取私有数据</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">newChrLed_dev</span> *<span class="title">dev</span> = <span class="title">filp</span>-><span class="title">private_data</span>;</span></span><br></pre></td></tr></table></figure><h2 id="四、错误处理"><a href="#四、错误处理" class="headerlink" title="四、错误处理"></a>四、错误处理</h2><p> 在 <code>xxx_init</code> 加载驱动出现错误的时候,可以使用 <code>goto</code> 语句,对错误进行处理。比如:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">newChrLed.cdev.owner = THIS_MODULE;</span><br><span class="line">ret = cdev_init(&newChrLed.cdev, &newChrLed_fops);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">ret = cdev_add(&newChrLed.cdev, newChrLed.devid, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">fail_cdev:</span><br><span class="line"><span class="comment">/* 删除字符设备 */</span></span><br><span class="line">cdev_del(&newChrLed.cdev);</span><br><span class="line"><span class="comment">/* 因为cdev初始化失败,所以需要注销设备号 */</span></span><br><span class="line">unregister_chrdev_region(newChrLed.devid, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br></pre></td></tr></table></figure><h2 id="五、整体程序(开发中不使用这种方式)"><a href="#五、整体程序(开发中不使用这种方式)" class="headerlink" title="五、整体程序(开发中不使用这种方式)"></a>五、整体程序(开发中不使用这种方式)</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/kernel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/delay.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/ide.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/init.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/module.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/gpio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/mach/map.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/uaccess.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><asm/io.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><linux/cdev.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LED_NAME<span class="meta-string">"LED"</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 寄存器物理地址 */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> CCM_CCGR1_BASE(0X020C406C)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SW_MUX_GPIO1_IO03_BASE(0X020E0068)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SW_PAD_GPIO1_IO03_BASE(0X020E02F4)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> GPIO1_GDIR_BASE(0X0209C004)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> GPIO1_DR_BASE(0X0209C000)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 虚拟地址的指针 */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *CCM_CCGR1;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *SW_MUX_GPIO1_IO03;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *SW_PAD_GPIO1_IO03;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *GPIO1_GDIR;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> __iomem *GPIO1_DR;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDOFF0</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEDON 1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* LED设备结构体 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">newChrLed_dev</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span><span class="comment">// cdev</span></span><br><span class="line"><span class="keyword">dev_t</span> devid;<span class="comment">// 设备号</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">class</span> *<span class="title">class</span>;</span><span class="comment">// 类</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">device</span>;</span><span class="comment">// 设备</span></span><br><span class="line"><span class="keyword">int</span> major;<span class="comment">// 主设备号</span></span><br><span class="line"><span class="keyword">int</span> minor;<span class="comment">// 次设备号</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">newChrLed_dev</span> <span class="title">newChrLed</span>;</span><span class="comment">// LED设备</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">led_toggle</span><span class="params">(u8 state)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">u32 val = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(state == LEDON)</span><br><span class="line">{</span><br><span class="line">val = readl(GPIO1_DR);</span><br><span class="line">val &= ~(<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_DR);<span class="comment">// 打开LED</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">val = readl(GPIO1_DR);</span><br><span class="line">val |= (<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_DR);<span class="comment">// 关闭LED</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">newchrled_open</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">/* 设置私有数据 */</span></span><br><span class="line">filp->private_data= &newChrLed;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">newchrled_release</span><span class="params">(struct inode *inode, struct file *filp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">filp->private_data = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">newchrled_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> len, <span class="keyword">loff_t</span> * off)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> retvalue;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> databuff[<span class="number">1</span>];</span><br><span class="line"><span class="comment">// struct newChrLed_dev *dev = filp->private_data;</span></span><br><span class="line">retvalue = copy_from_user(databuff, buf, len);</span><br><span class="line"><span class="keyword">if</span> (retvalue < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"kernel write failed!\r\n"</span>);</span><br><span class="line"><span class="keyword">return</span> -EFAULT;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (databuff[<span class="number">0</span>] == LEDON)</span><br><span class="line">{</span><br><span class="line">led_toggle(LEDON);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">led_toggle(LEDOFF);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">newChrLed_fops</span> = {</span></span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.<span class="built_in">write</span> = newchrled_write,</span><br><span class="line">.<span class="built_in">open</span> = newchrled_open,</span><br><span class="line">.<span class="built_in">release</span> = newchrled_release,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 入口</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">newchrled_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="comment">/* 1.初始化LED */</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">int</span> val = <span class="number">0</span>;</span><br><span class="line"><span class="comment">/* 初始化LED灯,地址映射 */</span></span><br><span class="line">CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, <span class="number">4</span>);</span><br><span class="line">SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, <span class="number">4</span>);</span><br><span class="line">SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, <span class="number">4</span>);</span><br><span class="line">GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, <span class="number">4</span>);</span><br><span class="line">GPIO1_DR = ioremap(GPIO1_DR_BASE, <span class="number">4</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 初始化 */</span></span><br><span class="line">val = readl(CCM_CCGR1);</span><br><span class="line">val &= ~(<span class="number">3</span> << <span class="number">26</span>);</span><br><span class="line">val |= (<span class="number">3</span> << <span class="number">26</span>);</span><br><span class="line">writel(val, CCM_CCGR1);<span class="comment">// 使能时钟</span></span><br><span class="line"></span><br><span class="line">writel(<span class="number">0x5</span>, SW_MUX_GPIO1_IO03);<span class="comment">// 设置复用</span></span><br><span class="line">writel(<span class="number">0x10b0</span>, SW_PAD_GPIO1_IO03);<span class="comment">// 设置电气属性</span></span><br><span class="line"></span><br><span class="line">val = readl(GPIO1_GDIR);</span><br><span class="line">val |= (<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_GDIR);<span class="comment">// 设置输出</span></span><br><span class="line"></span><br><span class="line">val = readl(GPIO1_DR);</span><br><span class="line">val &= ~(<span class="number">1</span> << <span class="number">3</span>);</span><br><span class="line">writel(val, GPIO1_DR);<span class="comment">// 默认打开LED</span></span><br><span class="line"></span><br><span class="line">newChrLed.major = <span class="number">0</span>;<span class="comment">// 设置为0,表示由系统自动分配设备号</span></span><br><span class="line"><span class="comment">/* 2.注册字符设备 */</span></span><br><span class="line"><span class="keyword">if</span> (newChrLed.major)</span><br><span class="line">{</span><br><span class="line"><span class="comment">// 给定主设备号</span></span><br><span class="line">newChrLed.devid = MKDEV(newChrLed.major, <span class="number">0</span>);</span><br><span class="line">ret = register_chrdev_region(newChrLed.devid, <span class="number">1</span>, LED_NAME);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="comment">// 没有给定主设备号</span></span><br><span class="line">ret = alloc_chrdev_region(&newChrLed.devid, <span class="number">0</span>, <span class="number">1</span>, LED_NAME);</span><br><span class="line">newChrLed.major = MAJOR(newChrLed.devid);</span><br><span class="line">newChrLed.minor = MINOR(newChrLed.devid);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">printk(<span class="string">"newchrled chrdev_region error!\r\n"</span>);</span><br><span class="line"><span class="keyword">goto</span> fail_devid;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">printk(<span class="string">"newchrled major = %d, minor = %de\r\n"</span>, newChrLed.major, newChrLed.minor);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3.字符设备注册 */</span></span><br><span class="line">newChrLed.cdev.owner = THIS_MODULE;</span><br><span class="line">cdev_init(&newChrLed.cdev, &newChrLed_fops);</span><br><span class="line">ret = cdev_add(&newChrLed.cdev, newChrLed.devid, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">goto</span> fail_cdev;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 4.自动创建设备节点 */</span></span><br><span class="line"><span class="comment">/* 创建类 */</span></span><br><span class="line">newChrLed<span class="class">.<span class="keyword">class</span> = <span class="title">class_create</span>(<span class="title">THIS_MODULE</span>, <span class="title">LED_NAME</span>);</span></span><br><span class="line"><span class="keyword">if</span> (IS_ERR(newChrLed.class))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(newChrLed.class);</span><br><span class="line"><span class="keyword">goto</span> fail_class;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 创建设备节点 */</span></span><br><span class="line">newChrLed.device = device_create(newChrLed.class, <span class="literal">NULL</span>, newChrLed.devid, <span class="literal">NULL</span>, LED_NAME);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(newChrLed.device))</span><br><span class="line">{</span><br><span class="line">ret = PTR_ERR(newChrLed.device);</span><br><span class="line"><span class="keyword">goto</span> fail_device;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">fail_device:</span><br><span class="line">class_destroy(newChrLed.class);</span><br><span class="line"></span><br><span class="line">fail_class:</span><br><span class="line"><span class="comment">/* 删除字符设备 */</span></span><br><span class="line">cdev_del(&newChrLed.cdev);</span><br><span class="line"></span><br><span class="line">fail_cdev:</span><br><span class="line"><span class="comment">/* 因为cdev初始化失败,所以需要注销设备号 */</span></span><br><span class="line">unregister_chrdev_region(newChrLed.devid, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">fail_devid:</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 出口</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">newchrled_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">/* 取消地址映射 */</span></span><br><span class="line">iounmap(IMX6U_CCM_CCGR1);</span><br><span class="line">iounmap(SW_MUX_GPIO1_IO03);</span><br><span class="line">iounmap(SW_PAD_GPIO1_IO03);</span><br><span class="line">iounmap(GPIO1_DR);</span><br><span class="line">iounmap(GPIO1_GDIR);</span><br><span class="line"> </span><br><span class="line"><span class="comment">/* 删除字符设备 */</span></span><br><span class="line">cdev_del(&newChrLed.cdev);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注销设备号 */</span></span><br><span class="line">unregister_chrdev_region(newChrLed.devid, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 摧毁设备 */</span></span><br><span class="line">device_destroy(newChrLed.class, newChrLed.devid);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 摧毁类 */</span></span><br><span class="line">class_destroy(newChrLed.class);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 注册入口和出口</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line">module_init(newchrled_init);</span><br><span class="line">module_exit(newchrled_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">"GPL"</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">"fengyuhang"</span>);</span><br></pre></td></tr></table></figure><h2 id="六、测试应用程序"><a href="#六、测试应用程序" class="headerlink" title="六、测试应用程序"></a>六、测试应用程序</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ./ledAPP <filename> <0:1> 1 表示开灯 0 表示关灯</span></span><br><span class="line"><span class="comment"> * @param argc 应用程序参数个数</span></span><br><span class="line"><span class="comment"> * @param argv 保存的参数,字符串形式。</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> fd = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">char</span> *filename;</span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> databuff[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> ( argc !=<span class="number">3</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"输入错误\r\n"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">filename = argv[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">fd = <span class="built_in">open</span>(filename, O_RDWR);</span><br><span class="line"><span class="keyword">if</span>(fd < <span class="number">0</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"Error: %s\r\n"</span>,filename);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 读 */</span></span><br><span class="line"><span class="comment">/* if (atoi(argv[2]) == 1)// 传递过来的是字符串,需要转换成数字</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">ret = read(fd, readbuf, 10);</span></span><br><span class="line"><span class="comment">if (ret < 0)</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">printf("read file %s failed\r\n", filename);</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">else</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">} */</span></span><br><span class="line"></span><br><span class="line">databuff[<span class="number">0</span>] = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 写 */</span></span><br><span class="line">ret = <span class="built_in">write</span>(fd, databuff, <span class="keyword">sizeof</span>(databuff));</span><br><span class="line"><span class="keyword">if</span> (ret < <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"LED control failed!\r\n"</span>);</span><br><span class="line"><span class="built_in">close</span>(fd);</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 关闭 */</span></span><br><span class="line">ret = <span class="built_in">close</span>(fd);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
正点原子alpha开发板IMX6ULL嵌入式Linux开发学习笔记。
</summary>
<category term="嵌入式" scheme="https://proudrabbit.gitee.io/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
<category term="IMX6ULL" scheme="https://proudrabbit.gitee.io/tags/IMX6ULL/"/>
<category term="学习笔记" scheme="https://proudrabbit.gitee.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
</feed>