找回密码
 加入怎通
查看: 456|回复: 0

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

[复制链接]
杨莹莹连 发表于 2013-11-11 16:00:05 | 显示全部楼层 |阅读模式
          + n2 x5 I1 t' S
7 k8 H7 l3 T$ f5 y' Y
  第6章  简单的字符设备驱动程序% P9 h& Y: u( K, o1 m. U

/ O. Y: Y1 h' y! v* I8 Z' a  在Linux设备驱动程序的家族中,字符设备驱动程序是较为简单的驱动程序,同时也是应用非常广泛的驱动程序。所以学习字符设备驱动程序,对构建Linux设备驱动程序的知识结构非常重要。本章将带领读者编写一个完整的字符设备驱动程序。
/ z) P1 ^- i0 q" W* l) D4 j- d  `  J6 t4 C( a& _, D, k3 F
  61  字符设备驱动程序框架
& E7 S& ]# o" {- P/ [! u8 g7 w0 j3 J5 a7 w
  本节对字符设备驱动程序框架进行了简要的分析。字符设备驱动程序中有许多非常重要的概念,下面将从最简单的概念讲起:字符设备和块设备。) N& z4 V) y  x% h: s0 L% B/ I

& k& P, i8 O. J* ?  611  字符设备和块设备7 {( h8 j7 g0 s6 D0 G5 b5 G

& T9 ?$ g5 P5 F5 E  Linux系统将设备分为3种类型:字符设备、块设备和网络接口设备。; G* h+ Y6 O) K. H
. }- d! [- i! m+ J8 A
  其中字符设备和块设备难以区分,下面将对其进行重要讲解。
. {- e) t  W6 q# B& t, n( ?8 y. p. J6 \2 R; M
  1.字符设备
+ G; r4 b$ ^3 o1 T# U9 R0 j8 C
$ A; R- ^( [4 i* N2 K6 Q8 h0 ]5 T" I  字符设备是指那些只能一个字节一个字节读写数据的设备,不能随机读取设备内存中的某一数据。其读取数据需要按照先后顺序,从这点来看,字符设备是面向数据流的设备。! I. M" R6 \1 b/ F/ Y

8 l# Q: I$ R$ K; y  常见的字符有鼠标、键盘、串口、控制台和LED等设备。, o# {$ K( k& @* Y6 B0 f! v& h5 G
- I* i7 e) q8 }9 R/ i3 p
  2.块设备
) h9 ]8 b; K% h- F& L2 c' b$ I! l( x5 z1 ^
  块设备是指那些可以从设备的任意位置读取一定长度数据的设备。其读取数据不必按照先后顺序,可以定位到设备的某一具体位置,读取数据。; r7 ~6 l9 _' r1 F+ M7 z2 K

) m& V; [, B* K6 W7 ^# f9 s! s  常见的块设备有硬盘、磁盘、U盘、SD卡等。
$ {  ?8 T8 m; x$ `
# [3 k2 h- U: e  3.字符设备和块设备的区分
! {0 @1 G0 L5 ^  R9 d1 A
( |0 T! ^6 ]; O2 y9 B% n  每一个字符设备或者块设备都在/dev目录下对应一个设备文件。读者可以通过查看/dev目录下的文件的属性,来区分设备是字符设备还是块设备。: M& c' J$ l6 h- B8 w+ k% G" @

' [1 D% t7 k0 C! I  使用cd命令进入/dev目录,并执行ls -l命令就可以看到设备的属性。6 u$ H! j  I) P

8 j0 x) _0 `5 R4 U; x" c& _  [root@tom /]# cd /dev                                                        /*进入/dev目录*/
% i( a6 p0 Z) q- f3 Z, H1 O0 w0 y" w2 c1 d
  [root@tom dev]# ls -l                                                         /*列出/dev中文件的信息*/、; x5 n0 @0 j% H+ B/ `/ O% C

- u' {! [2 X) u( ?  /*第1字段     2  3  4      5    6         7      8  */2 F" K5 U% e: E6 c. G
0 a8 f$ u1 T, S, E' w
  crw-rw----+         1 root root    14,  12         12-21 22:56 adsp
( e1 ]$ |# `! G" M. h4 h6 C  D. a1 t6 {# P: }0 u
  crw-------          1 root root    10, 175         12-21 22:56 agpgart
# b' e' z% M7 [4 s1 w0 |2 ^  a* m( R: v- T( f6 f
  crw-rw----+         1 root root    14,   4         12-21 22:56 audio
6 l8 R. j% l) X3 A; B: B9 Q
7 {; i) W* Q* S( o7 E  brw-r-----          1 root disk   253,   0         12-21 22:56 dm-0" Z2 v1 n7 t" y; [$ J' O6 r

+ e9 ?* _! Y7 [4 W  brw-r-----          1 root disk   253,   1         12-21 22:56 dm-18 P3 M7 k' ?9 w

3 Q: H8 S2 q9 x! |& a5 R  crw-rw----          1 root root    14,   9         12-21 22:56 dmmidi$ c& Y+ @" v2 j  N5 k
& T9 M" `' c. T+ ]; f
  ls -l命令的第一字段中的第一个字符c表示设备是字符设备,b表示设备是块设备。第234字段对驱动程序开发来说没有关系。: Z8 B! N- R& ?9 R6 P

* l2 ?  m" o' |( L- x  第5,6字段分别表示设备的主设备号和次设备号,将在612节讲解。第7字段表示文件的最后修改时间。第8字段表示设备的名字。
1 s. ~7 A2 B2 z8 j- |0 B
( l1 c0 P* h5 o& P  由第1和8字段可知,adsp是字符设备,dm-0是块设备。其中adsp设备的主设备号是14,次设备号是12。2 ^# r/ {1 N) u2 l% H; ?

* S" N1 r: q$ {0 A0 ~+ l! o  612  主设备号和次设备号
* t" q* v- L/ X: Y, J  a
3 ]8 {. _+ b( ^2 B" I  一个字符设备或者块设备都有一个主设备号和次设备号。8 [2 P5 Q& x; C  z( @

1 F2 h& [9 _  a/ a, J% |2 O  主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。( h6 \$ H/ Z) n& q# F* b: Z

( S. n1 x' S  Q" E  例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。
* ]9 U$ @" `- n; R' A( R# z$ G) K6 f; ]) n# u" @" M: k
  1.主设备号和次设备号的表示
. t2 D- q7 ]. V# t" V3 I3 u5 @  f% W" ?1 ^8 \
  在Linux内核中,dev_t类型用来表示设备号。在Linux 26294中,dev_t定义为一个无符号长整型变量,如下:
( C1 P2 {6 j0 i5 Z/ p
3 y% f" r% G6 W  typedef u_long dev_t;, F5 x% R; ~/ t8 A% k

7 P6 v( c8 q" R  u_long在32位机中是4个字节,在64位机中是8字节。以32位机为例,其中高12表示主设备号,低20为表示次设备号,如图61所示。/ E4 d+ M8 j0 P$ i
5 M" }5 a; x0 ~5 b9 ?3 q
  图61  dev_t结构
" K* I. r4 ^* r# {: r3 W3 L7 `5 T: H
  2.主设备号和次设备号的获取( C# Y% X5 H! Y3 W& n

  y4 d* Y2 T8 }! L, S$ O; [  为了写出可移植的驱动程序,不能假定主设备号和次设备号的位数。不同的机型中,主设备号和次设备号的位数可能是不同的。应该使用MAJOR宏得到主设备号,使用MINOR宏来得到次设备号。' s$ }1 ^: K8 f4 ~7 T9 [

7 o! s. g$ N# n- c$ i  大发888下面是两个宏的定义:
* u. n' Q3 d" G; j! h5 `" j, d: m
, w+ m/ T9 f7 G. l* B  A( I7 T! `  #define MINORBITS        20                                                                         /*次设备号位数*/  d0 T- |- F) F) F. T+ C' W. o% M
; E1 W% v, l5 [
  #define MINORMASK        ((1U > MINORBITS))
) m) {) P" i2 R- R" q, m; Q* y, e
- ~6 p, }  g* n# p% A4 I0 S                                                                                           /*dev右移20位得到主设备号*/+ Y4 L9 @+ J3 Q+ b

1 b" x( u9 N3 d* `$ R6 W  #define MINOR(dev)        ((unsigned int) ((dev)  MINORMASK))- q& r8 u5 l$ x% s; s& C8 P  Y, Y
. M# C6 t, |0 b2 P
                                                                                          /*与次设备掩码与,得到次设备号*/9 Z( b3 ?( m' Y: {3 R

. A; X5 f4 p0 E- X0 y- M  MAJOR宏将dev_t向右移动20位,得到主设备号;MINOR宏将dev_t的高12位清零,得到次设备号。相反,可以将主设备号和次设备号转换为设备号类型(dev_t),使用宏MKDEV可以完成这个功能。
# X6 W7 [* _+ N* }$ s( `- ~
/ G4 w1 G0 [' W  #define MKDEV(ma,mi)        (((ma)
) i/ s% t* S+ R& @7 C! `, X( j  Y' P1 e2 M
  MKDEV宏将主设备号(ma)左移20位,然后与次设备号(mi)相与,得到设备号。, Q" }' R2 _+ x, ^9 j' t4 Q. g
, \1 T7 n* c7 Y: {2 E2 Q# F% Q
  3.静态分配设备号& v' t. H# U% N( w/ o- u: N8 d

- ?8 G: P6 \6 W1 G  静态分配设备号,就是驱动程序开发者,静态地指定一个设备号。对于一部分常用的设备,内核开发者已经为其分配了设备号。这些设备号可以在内核源码documentation/ devicestxt文件中找到。
% X# ~6 w" I; L, M2 }7 O9 Y' a3 [1 z( b# i3 B
  如果只有开发者自己使用这些设备驱动程序,那么其可以选择一个尚未使用的设备号。在不添加新硬件的时候,这种方式不会产生设备号冲突。但是当添加新硬件时,则很可能造成设备号冲突,影响设备的使用。
- H# U5 I/ _; u- p5 V0 ~2 w4 \: d. A' ?2 u; M
  4.动态分配设备号, A, j+ i  `! U+ d# a) ~2 j
( c0 B) ~# u/ K. M6 p4 f
  由于静态分配设备号存在冲突的问题( z4 s5 t* x' y* @

1 @0 P* D5 d. `2 {/ y9 [
回复

使用道具 举报

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

    本版积分规则

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

    GMT+8, 2026-4-28 03:40 , Processed in 0.173935 second(s), 24 queries , Gzip On.

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

    Powered by Discuz! X3.5

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