找回密码
 加入怎通
查看: 463|回复: 1

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

[复制链接]
杨莹莹连 发表于 2013-11-11 16:00:05 | 显示全部楼层 |阅读模式
          7 K1 G/ E4 T3 c+ U
$ |" w# [. x; v, c) O
  第6章  简单的字符设备驱动程序: L+ A' t1 w- {6 P* r1 O* u

5 U+ c4 f7 d8 B  在Linux设备驱动程序的家族中,字符设备驱动程序是较为简单的驱动程序,同时也是应用非常广泛的驱动程序。所以学习字符设备驱动程序,对构建Linux设备驱动程序的知识结构非常重要。本章将带领读者编写一个完整的字符设备驱动程序。
) k" L% x6 j  F! x. Q2 P6 U. Q! U! i5 P
  61  字符设备驱动程序框架
. i$ D' x( Z9 I( b) l- V- V& K2 }% `3 @5 Z. V  ]: w2 I# `
  本节对字符设备驱动程序框架进行了简要的分析。字符设备驱动程序中有许多非常重要的概念,下面将从最简单的概念讲起:字符设备和块设备。
9 {$ G  [  M4 L. ~8 Z
: u, {7 l. }! S5 K* ?" S& o  611  字符设备和块设备+ \4 l  Z+ ]2 d; H( W% _9 B- ^

  [2 a2 s# Z6 [% x' v  L  Linux系统将设备分为3种类型:字符设备、块设备和网络接口设备。- o9 F4 T: x, t- C2 f" O0 u3 Y8 q
/ x6 E7 G6 u9 j0 V9 c
  其中字符设备和块设备难以区分,下面将对其进行重要讲解。- k( i# m& L) K1 P6 ]) W/ n0 N

1 U% ~1 B' J+ M- S( x: i  ]  1.字符设备# w. f6 Y; h, v9 e

( F) s( X# Q# Z2 R* E" X( @  字符设备是指那些只能一个字节一个字节读写数据的设备,不能随机读取设备内存中的某一数据。其读取数据需要按照先后顺序,从这点来看,字符设备是面向数据流的设备。
' M; G4 A' J+ E% Z
' ~- A% f) }1 U( K1 c2 I9 J+ _  常见的字符有鼠标、键盘、串口、控制台和LED等设备。# O* }8 v" {3 _0 L4 j2 h

0 S- [+ q4 P+ g. q  2.块设备( W2 D8 z0 a2 i& D

1 ~5 V, ]3 g9 T' u, H4 T2 k+ {  块设备是指那些可以从设备的任意位置读取一定长度数据的设备。其读取数据不必按照先后顺序,可以定位到设备的某一具体位置,读取数据。2 O. w* V5 S1 u/ S4 Y: F" F

7 V, T' x8 m" [! _6 N7 M  常见的块设备有硬盘、磁盘、U盘、SD卡等。
! ]/ A( k( y2 b6 J4 |. R# r2 i& n
9 ^7 q+ W* n! m  a  3.字符设备和块设备的区分
! b5 G  t4 f4 w9 g0 P
9 M0 [8 m, T% t6 r2 C  每一个字符设备或者块设备都在/dev目录下对应一个设备文件。读者可以通过查看/dev目录下的文件的属性,来区分设备是字符设备还是块设备。( K/ N4 h' I1 b" _; I
' K/ H" Y7 f) t! v
  使用cd命令进入/dev目录,并执行ls -l命令就可以看到设备的属性。: D) N- H" n8 E1 U1 W

0 R" o/ B- h' j2 C* W! n  [root@tom /]# cd /dev                                                        /*进入/dev目录*/- ]0 y' a" L) u, b6 X+ |: ~
! g' e8 w& s8 d9 ^7 H4 M
  [root@tom dev]# ls -l                                                         /*列出/dev中文件的信息*/、
" ~. `& g  ~+ \: p  X0 X3 n" |* Q
  /*第1字段     2  3  4      5    6         7      8  */
6 d; R% \& e  J- n$ Y6 D, h. k0 s, M1 E* G" g, T7 q$ Z" `( E  e
  crw-rw----+         1 root root    14,  12         12-21 22:56 adsp
7 Y0 Q9 w; o& T/ W8 ?' S& a3 [  }/ B! \- j
  crw-------          1 root root    10, 175         12-21 22:56 agpgart9 p9 a0 [7 ~$ S# S8 g9 E1 ~
2 R: L* s5 m& F" m6 o; F1 X/ j$ Y, f
  crw-rw----+         1 root root    14,   4         12-21 22:56 audio% ?) f* p9 P8 f8 `8 H) J  C

% E5 p( Y$ f: `/ m! v5 N+ k  brw-r-----          1 root disk   253,   0         12-21 22:56 dm-0' S+ X6 E! x; h" }4 N

# u2 A6 l' X' ^: U  brw-r-----          1 root disk   253,   1         12-21 22:56 dm-1
, Z* a* i& b$ S; q$ |) Y- @( l; P- p) U* [" s7 _) k
  crw-rw----          1 root root    14,   9         12-21 22:56 dmmidi" Y! b* s( k9 n# y; `

! E; s' e0 B9 o6 U' V& T  }! R  ls -l命令的第一字段中的第一个字符c表示设备是字符设备,b表示设备是块设备。第234字段对驱动程序开发来说没有关系。9 P5 u  K0 c( X& f' }% d

4 O! ]" N9 A7 s* v/ p6 G$ _& V  第5,6字段分别表示设备的主设备号和次设备号,将在612节讲解。第7字段表示文件的最后修改时间。第8字段表示设备的名字。
' z" R; \+ K8 B* g! c9 D( A% b6 ]
/ I. F; ?9 O. @1 M  由第1和8字段可知,adsp是字符设备,dm-0是块设备。其中adsp设备的主设备号是14,次设备号是12。
* _) z! p, [' s2 `7 e
, \. C8 M5 f; R2 k- G' \  612  主设备号和次设备号, v. d1 y7 F+ H) {' t

( Y* G+ ^  d+ W; u  {# t3 [9 W  一个字符设备或者块设备都有一个主设备号和次设备号。4 a7 N4 ^- s; H* a6 v

( w8 _3 q- I2 n2 z1 Q3 R  主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。
0 _  K5 x& a' M0 x$ K3 I8 w( x6 X0 G) \7 T  g5 W  T2 N9 x6 a! q8 K
  例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。
6 G* c/ ^: g5 o$ _6 Q9 e" r5 ^6 N0 J& _  q
  1.主设备号和次设备号的表示
8 \0 i" @/ v6 D% J% M/ W
* G" V1 }& K, u. f/ c( Y  在Linux内核中,dev_t类型用来表示设备号。在Linux 26294中,dev_t定义为一个无符号长整型变量,如下:" H8 @! o: P; m% W) [+ [3 q
9 @$ y1 X) w, g
  typedef u_long dev_t;" u+ w  k. u. F0 H5 D, e7 l
2 S+ r, E6 w+ t3 T# j
  u_long在32位机中是4个字节,在64位机中是8字节。以32位机为例,其中高12表示主设备号,低20为表示次设备号,如图61所示。
7 V) q) }. {+ C+ f6 h
" v4 A7 s9 z+ r* l8 Y  图61  dev_t结构
% A% T' [$ I# V0 @( f4 [3 A
5 R1 q- m3 t3 z  2.主设备号和次设备号的获取% q1 ], A% S% j7 H7 x* Z+ @
' a" W* a/ L/ A0 w4 G" \% Q5 x
  为了写出可移植的驱动程序,不能假定主设备号和次设备号的位数。不同的机型中,主设备号和次设备号的位数可能是不同的。应该使用MAJOR宏得到主设备号,使用MINOR宏来得到次设备号。" Y( w) H9 P/ j& n* S
+ w! x: C( m8 c- d3 ?
  大发888下面是两个宏的定义:
9 z2 h+ o& t* c' s" u" p, ?, X0 B6 ]/ R0 W9 ?+ W
  #define MINORBITS        20                                                                         /*次设备号位数*/
5 v1 J9 g% \. q3 u. @+ M, P
9 c! P& L7 L2 I) o  #define MINORMASK        ((1U > MINORBITS))
0 a! ^% z6 V8 b7 k5 {) l& u
, G0 _  w4 J: E/ w                                                                                           /*dev右移20位得到主设备号*/
9 g+ k, L  @6 ~$ i4 }% x
/ w  i9 Q8 ~$ ~7 o* X1 W' ]  #define MINOR(dev)        ((unsigned int) ((dev)  MINORMASK))- L, T7 F: N' C
* l/ W( ^, v- n: q9 n; j+ a
                                                                                          /*与次设备掩码与,得到次设备号*/, A) v! l6 |8 k. y

( ?: x% @" l5 \1 I4 N  MAJOR宏将dev_t向右移动20位,得到主设备号;MINOR宏将dev_t的高12位清零,得到次设备号。相反,可以将主设备号和次设备号转换为设备号类型(dev_t),使用宏MKDEV可以完成这个功能。
7 j. a! ?& y! @  E9 k2 W
, F7 T: ~7 p5 h3 W& N9 m: p' a  #define MKDEV(ma,mi)        (((ma)
# b* Z/ P* x% _4 X/ T, g
: D9 }9 b0 N' B3 r& e  MKDEV宏将主设备号(ma)左移20位,然后与次设备号(mi)相与,得到设备号。$ z4 J  [+ _  U1 g; G" Y7 I1 B

: q+ I! ]' e/ i" l- u% x3 B  3.静态分配设备号4 _$ u5 ~/ A- E3 o
$ {! P& ^1 _+ O0 j4 ]
  静态分配设备号,就是驱动程序开发者,静态地指定一个设备号。对于一部分常用的设备,内核开发者已经为其分配了设备号。这些设备号可以在内核源码documentation/ devicestxt文件中找到。& K- V; H9 _# N9 E* O( V

0 F0 Y5 j' F2 q" C3 V  ^: n  如果只有开发者自己使用这些设备驱动程序,那么其可以选择一个尚未使用的设备号。在不添加新硬件的时候,这种方式不会产生设备号冲突。但是当添加新硬件时,则很可能造成设备号冲突,影响设备的使用。
' C: z; C; k/ _6 G0 \  E. R0 P. y$ k1 L/ b" E3 p2 g8 Z( [/ N
  4.动态分配设备号
% A$ D( d* C* a5 U: K6 u: t9 ~. P( h5 _, I4 F9 n/ V
  由于静态分配设备号存在冲突的问题
5 `- p  D+ D5 t2 D
9 z- P  u! O: s2 @, z
回复

使用道具 举报

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

使用道具 举报

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

    本版积分规则

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

    GMT+8, 2026-6-12 11:59 , Processed in 0.094071 second(s), 24 queries , Gzip On.

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

    Powered by Discuz! X3.5

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