找回密码
 加入怎通
查看: 499|回复: 3

[其他] Linux驱动开发入门与实战.txt

[复制链接]
杨莹莹连 发表于 2013-11-11 16:00:05 | 显示全部楼层 |阅读模式
         
  r. K. M7 i& `  F" `9 u2 E) I2 [  G& y  J) w! z' W
  第6章  简单的字符设备驱动程序9 D, M2 N$ y" _( }$ J

( |5 E# F9 B# I" p7 W7 R  在Linux设备驱动程序的家族中,字符设备驱动程序是较为简单的驱动程序,同时也是应用非常广泛的驱动程序。所以学习字符设备驱动程序,对构建Linux设备驱动程序的知识结构非常重要。本章将带领读者编写一个完整的字符设备驱动程序。+ P; s  r) s# a8 W4 A# S- u

# N( x' A6 P! X% b6 e! K  61  字符设备驱动程序框架
; O0 |! C) ~) Q( Y8 y7 k" ?. @7 ]. |2 z( M6 W" u
  本节对字符设备驱动程序框架进行了简要的分析。字符设备驱动程序中有许多非常重要的概念,下面将从最简单的概念讲起:字符设备和块设备。
, e3 d$ N4 v1 y& K1 Z/ V
1 G) u: v4 ?8 u" E. R- }# A  611  字符设备和块设备3 d( X; s% U  l

7 J' s5 {, S. w+ q2 n0 m. [5 |  Linux系统将设备分为3种类型:字符设备、块设备和网络接口设备。- j+ ~) ]' F4 u
8 Y) Z4 J  P: a2 t
  其中字符设备和块设备难以区分,下面将对其进行重要讲解。! g4 I4 C* f. A
9 L* S# z* D( b% {
  1.字符设备9 o  F' w: ?& @+ ?$ U3 q
4 y* Y/ I  r0 y* X
  字符设备是指那些只能一个字节一个字节读写数据的设备,不能随机读取设备内存中的某一数据。其读取数据需要按照先后顺序,从这点来看,字符设备是面向数据流的设备。
# p0 o( e9 d) g* f! s6 y
, Z& B9 I) P' P1 X  常见的字符有鼠标、键盘、串口、控制台和LED等设备。* j; g. D5 k5 m# s& p& X% _7 M

0 x6 C8 f9 `( ^  2.块设备
/ J5 M8 r3 z# b" H8 k, X/ D/ d* k4 i5 `3 A/ x. W3 d
  块设备是指那些可以从设备的任意位置读取一定长度数据的设备。其读取数据不必按照先后顺序,可以定位到设备的某一具体位置,读取数据。
' ~9 ^1 D5 H7 ^" a! e
) ?1 ^+ D- @$ T6 J4 _5 h2 U  常见的块设备有硬盘、磁盘、U盘、SD卡等。# K' t' m3 ^  d3 d

4 L9 s: b& w, i( l+ t* s+ m  \  3.字符设备和块设备的区分
9 Q' }1 c6 u0 ?) O$ ^. t3 |9 V- w2 }: z3 `
  每一个字符设备或者块设备都在/dev目录下对应一个设备文件。读者可以通过查看/dev目录下的文件的属性,来区分设备是字符设备还是块设备。
% R' h8 F8 Y5 T7 G
. b' n  h  W( I2 x4 l  使用cd命令进入/dev目录,并执行ls -l命令就可以看到设备的属性。& U! x4 T4 ~0 N+ W# q, \# i

' x0 l! t( Q. S' T! h! V$ N  [root@tom /]# cd /dev                                                        /*进入/dev目录*/
4 y+ T) k$ ?" G0 t
; i" y( Z8 ]" M! F  [root@tom dev]# ls -l                                                         /*列出/dev中文件的信息*/、
5 t/ W5 y% c+ V% _5 ~3 o% n# e
2 z; V" E  h' a  t% j, g4 ]( D  /*第1字段     2  3  4      5    6         7      8  */
/ C! z  h2 V8 f0 n
& v. ]$ i5 |3 O  crw-rw----+         1 root root    14,  12         12-21 22:56 adsp7 E: C1 l2 B; U9 P. X

4 h( \+ D6 ?2 u5 Q1 K  crw-------          1 root root    10, 175         12-21 22:56 agpgart! {: N3 K' X' o  s- m  a2 X, g

( V: \" t+ w2 ]1 R2 C  crw-rw----+         1 root root    14,   4         12-21 22:56 audio
+ F8 p3 V4 `! T, F2 C9 D+ q) p# k' y; x7 Z
  brw-r-----          1 root disk   253,   0         12-21 22:56 dm-05 ^& t; J: N" I$ K+ O- ^5 w5 a* E, e$ P
$ j) h% t# U+ E6 ~
  brw-r-----          1 root disk   253,   1         12-21 22:56 dm-1
/ O) D4 t# n: W0 F/ V' f5 L
; r6 u. v2 H2 ^  crw-rw----          1 root root    14,   9         12-21 22:56 dmmidi
7 P* l( u$ A/ ^3 `3 \+ n
* s. Q: Z, I/ @. @  ls -l命令的第一字段中的第一个字符c表示设备是字符设备,b表示设备是块设备。第234字段对驱动程序开发来说没有关系。
- a# S4 y3 U  @* A# J: r7 U- o6 S* X$ u. s! T. k0 v
  第5,6字段分别表示设备的主设备号和次设备号,将在612节讲解。第7字段表示文件的最后修改时间。第8字段表示设备的名字。" c. g/ {+ d$ C+ H. X

6 r/ \; J: C; T3 ]' t0 F+ V  由第1和8字段可知,adsp是字符设备,dm-0是块设备。其中adsp设备的主设备号是14,次设备号是12。2 w9 R" {: {# q- \( k
: n, d! t* c( `8 w$ m/ m) ]
  612  主设备号和次设备号
  r, D+ I3 E1 P2 m, y% z- P$ y/ z  H# w# k2 }) o
  一个字符设备或者块设备都有一个主设备号和次设备号。
! T' H  o3 |- r: E" \, d2 m2 I& c3 @0 s4 h; ~1 `) v( i
  主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。
3 u+ Q) C2 l. j& ]% \
' L9 ^9 i/ K4 k% ?3 G  例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。- m  l# x& M2 L0 _9 C; W- s; K" \' ~

  P4 L8 I3 I" s' `( b7 R  1.主设备号和次设备号的表示" ?4 I4 `8 p8 j4 h. `
* z3 t- `! V, H
  在Linux内核中,dev_t类型用来表示设备号。在Linux 26294中,dev_t定义为一个无符号长整型变量,如下:
! `" k% N7 n2 _* p' q
  V( L" B" M( g& ?  typedef u_long dev_t;
# D9 U& c1 i. H$ D8 d$ [0 G
$ ~/ O! _+ i0 \* ]  u_long在32位机中是4个字节,在64位机中是8字节。以32位机为例,其中高12表示主设备号,低20为表示次设备号,如图61所示。
; Z7 p. ]& ]  X4 j# o
1 g, W# k$ `2 k7 M' w, k6 |  图61  dev_t结构" x9 o- {6 |4 J$ s+ M- C. C8 w

& c- Z$ _/ t7 n" M  2.主设备号和次设备号的获取
0 Z; K: m$ t3 n) \' f2 x- k1 Q: w, z7 O3 H4 w/ c2 Z
  为了写出可移植的驱动程序,不能假定主设备号和次设备号的位数。不同的机型中,主设备号和次设备号的位数可能是不同的。应该使用MAJOR宏得到主设备号,使用MINOR宏来得到次设备号。
1 g7 |3 e5 X; E
; `% k3 \7 Y" u  大发888下面是两个宏的定义:
" B$ p9 q- a, F4 [- R0 U* y: D
  #define MINORBITS        20                                                                         /*次设备号位数*/
$ K% i8 w5 N4 ]- J& _
9 ?/ x& [" `; n8 [8 O8 h7 j$ m  #define MINORMASK        ((1U > MINORBITS))2 l+ o. z, R7 G6 F

9 z& X" g3 G# L+ ?: d  D; j                                                                                           /*dev右移20位得到主设备号*/4 ^4 z: ?% l  _+ T6 f9 q' W

4 e: r2 R+ C  X: E# B2 m4 @/ N2 B  #define MINOR(dev)        ((unsigned int) ((dev)  MINORMASK))
& f; F* V* G/ ?# }1 b
  D, q4 u5 _2 `3 b( Y% L                                                                                          /*与次设备掩码与,得到次设备号*/
9 ?6 _1 m$ Q* D' s) l
+ m* S, s% b# M: P; b6 a2 _  MAJOR宏将dev_t向右移动20位,得到主设备号;MINOR宏将dev_t的高12位清零,得到次设备号。相反,可以将主设备号和次设备号转换为设备号类型(dev_t),使用宏MKDEV可以完成这个功能。( p2 s1 R1 T* \+ [( t( [

- L% q, M1 Z# m$ H* l) n  #define MKDEV(ma,mi)        (((ma)
- L7 P/ O  R8 ]' {$ f% v0 a8 U# p& [% E7 U( T2 H
  MKDEV宏将主设备号(ma)左移20位,然后与次设备号(mi)相与,得到设备号。0 K  Y8 Y" o$ V3 x7 r" [/ M

& W2 m* w7 h" G  3.静态分配设备号$ Y; C! Z+ Q5 z9 `9 m

* V6 e2 r. B& r% V  m7 P  静态分配设备号,就是驱动程序开发者,静态地指定一个设备号。对于一部分常用的设备,内核开发者已经为其分配了设备号。这些设备号可以在内核源码documentation/ devicestxt文件中找到。
" J, J6 r% H9 J( x* A3 \0 G7 w9 F
7 h4 [: Z8 D- W, k# k  如果只有开发者自己使用这些设备驱动程序,那么其可以选择一个尚未使用的设备号。在不添加新硬件的时候,这种方式不会产生设备号冲突。但是当添加新硬件时,则很可能造成设备号冲突,影响设备的使用。0 U+ M6 k5 u! v5 w

7 C- Q. @* ^2 O. r4 E/ [$ {6 j  4.动态分配设备号( r; I9 Y, I* }+ V0 Y* m7 Y
& c- t1 k+ x' a6 f7 B6 ^5 b. Z
  由于静态分配设备号存在冲突的问题# n0 m* ]; y' k4 _! z
$ Y# _* v# [' [4 R: o; D$ d

暂时无法加载帖子列表

回复

使用道具 举报

yue_菇凉 发表于 2026-05-29 22:16:42 | 显示全部楼层
楼主辛苦了,整理这么多内容,必须点赞收藏
回复

使用道具 举报

csyp2017 发表于 2026-06-30 03:33:38 | 显示全部楼层
刚好遇到类似问题,看完这个帖子心里有底了
回复

使用道具 举报

dpjanebass 发表于 2026-08-25 00:51:50 | 显示全部楼层
这个分享太实用了,刚好能用到,感谢楼主!
回复

使用道具 举报

    您需要登录后才可以回帖 登录 | 加入怎通

    本版积分规则

    QQ|手机版|小黑屋|网站地图|真牛社区 ( 苏ICP备2023040716号-2 )

    GMT+8, 2026-9-14 12:06 , Processed in 0.035635 second(s), 26 queries , Gzip On.

    免责声明:本站信息来自互联网,本站不对其内容真实性负责,如有侵权等情况请联系420897364#qq.com(把#换成@)删除。

    Powered by Discuz! X3.5

    快速回复 返回顶部 返回列表