找回密码
 加入怎通
查看: 480|回复: 2

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

[复制链接]
杨莹莹连 发表于 2013-11-11 16:00:05 | 显示全部楼层 |阅读模式
          7 C4 y- a, q. K- c0 I7 A) p) H

" E% p8 L( r0 \5 h9 ~7 p$ K7 m  第6章  简单的字符设备驱动程序
" L% h: P) R( o/ Y# a) `; `$ l6 g, T  S6 B3 i4 x
  在Linux设备驱动程序的家族中,字符设备驱动程序是较为简单的驱动程序,同时也是应用非常广泛的驱动程序。所以学习字符设备驱动程序,对构建Linux设备驱动程序的知识结构非常重要。本章将带领读者编写一个完整的字符设备驱动程序。; M; B5 g% k+ j! S- a2 e; W0 J
$ E1 [* T1 |8 P& v0 Q
  61  字符设备驱动程序框架" d7 \" x* o9 T
5 R, ~9 G; \: {7 Q; E* g
  本节对字符设备驱动程序框架进行了简要的分析。字符设备驱动程序中有许多非常重要的概念,下面将从最简单的概念讲起:字符设备和块设备。5 o7 ^' n" @  w) O6 d

7 |) _; Q2 m; Q  611  字符设备和块设备& T& [3 _: l) B% ]

; R6 P' A: j" e8 ~& h  Linux系统将设备分为3种类型:字符设备、块设备和网络接口设备。; M: @! M5 A  O/ q: R7 X# F$ ?1 q
  q' V& o- k4 T3 U
  其中字符设备和块设备难以区分,下面将对其进行重要讲解。
- t- J) K9 x* q0 s
8 `: Y5 X1 n. o1 s; W. p) i  1.字符设备
1 S  b# T- b8 l/ x6 W' h) L& J, l4 l  {3 J/ Z
  字符设备是指那些只能一个字节一个字节读写数据的设备,不能随机读取设备内存中的某一数据。其读取数据需要按照先后顺序,从这点来看,字符设备是面向数据流的设备。
$ s. J+ v# [% J' O$ |) X! A8 v$ \/ T% A- [9 H
  常见的字符有鼠标、键盘、串口、控制台和LED等设备。
5 `$ e3 @( _/ s( S( c% ^" b( o
  2.块设备
6 \3 s  B0 \1 p& Z# a5 P9 [- ]6 X$ y) s4 @2 f$ R# c
  块设备是指那些可以从设备的任意位置读取一定长度数据的设备。其读取数据不必按照先后顺序,可以定位到设备的某一具体位置,读取数据。. b6 L  y- a- j% j0 `. ~
5 U* X3 j8 ?) ~. g; U7 |2 r# _
  常见的块设备有硬盘、磁盘、U盘、SD卡等。
3 Q- a: [- m  d8 O" C8 K& Q; R7 U3 ~" b+ I' P
  3.字符设备和块设备的区分
: `5 ~. m  U1 y. u4 m$ g3 g* I+ x$ C9 \- e# L' I
  每一个字符设备或者块设备都在/dev目录下对应一个设备文件。读者可以通过查看/dev目录下的文件的属性,来区分设备是字符设备还是块设备。
" L" Q5 a4 J$ V, @( t: {' {
8 U  s! j" c; `7 }  使用cd命令进入/dev目录,并执行ls -l命令就可以看到设备的属性。" F: L8 A: k  l5 d
1 P* Y. m* Y' v* \% k: }
  [root@tom /]# cd /dev                                                        /*进入/dev目录*/
/ L8 L- W6 t1 [3 i& g( A/ w0 f" a: P1 K
  [root@tom dev]# ls -l                                                         /*列出/dev中文件的信息*/、' j% Y4 C# ?7 Y% @
3 e" l8 {8 s0 U# ]
  /*第1字段     2  3  4      5    6         7      8  */. Z8 K( G- d! n" m
; s/ ~- T0 Z' j+ T$ v' P# L
  crw-rw----+         1 root root    14,  12         12-21 22:56 adsp- r2 g/ X! S$ t" I& D) g/ T: }
' D; T- c; |0 i. L% X
  crw-------          1 root root    10, 175         12-21 22:56 agpgart! f' _3 o, c$ \4 b: Y

$ t' @- F) y' R; S5 M  crw-rw----+         1 root root    14,   4         12-21 22:56 audio% Q3 `0 d9 r- p1 d1 f

" S  z9 R4 [5 W/ t# K  brw-r-----          1 root disk   253,   0         12-21 22:56 dm-0
5 T1 U9 g2 Y3 v  Y
: H0 \3 T! F* a6 W& ]6 ?  brw-r-----          1 root disk   253,   1         12-21 22:56 dm-1% ~& e! l/ a+ N" J  R% Y# I

( ^, q. I0 d4 P; k  crw-rw----          1 root root    14,   9         12-21 22:56 dmmidi
% {5 Y! @! h# d+ R
4 u: L; U' p& Y6 I/ ~6 R  ls -l命令的第一字段中的第一个字符c表示设备是字符设备,b表示设备是块设备。第234字段对驱动程序开发来说没有关系。& R3 S$ \3 K1 Z# C7 T+ F  m$ }

5 b4 W4 C: K1 I- U1 o* W  第5,6字段分别表示设备的主设备号和次设备号,将在612节讲解。第7字段表示文件的最后修改时间。第8字段表示设备的名字。
7 r" ~  q; M! d1 n. |2 n/ D7 }) c# F/ u9 D" `
  由第1和8字段可知,adsp是字符设备,dm-0是块设备。其中adsp设备的主设备号是14,次设备号是12。! Z1 g  N* i  Z3 u" Y

. v7 B# [5 j/ E4 m2 _8 C2 i  612  主设备号和次设备号  d% ^/ |) B) V0 k" O

( m8 a. o# _- U0 K0 z# _  g  一个字符设备或者块设备都有一个主设备号和次设备号。7 O( {, _1 E0 e$ ~0 v) r5 U3 ]
' X! b; i# @; ^8 X
  主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。
( E! I6 v- \# {* O
' v( H+ E2 n. U/ ]4 j% W  例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。# ]0 h/ Z+ y2 v0 B
6 J% R# ?; L8 T! q3 I6 Z" M
  1.主设备号和次设备号的表示
. e" P0 `: c# ?* N# u# U6 _( }$ F+ O( I1 _7 @
  在Linux内核中,dev_t类型用来表示设备号。在Linux 26294中,dev_t定义为一个无符号长整型变量,如下:
) }9 O1 s) ~) v: c6 I3 t" w0 n/ S3 y. R+ U, H4 i) y$ r0 V: E6 c
  typedef u_long dev_t;
; B' @' e- ?' N& f1 Y' z8 P( B, Y7 A$ ~7 Q3 m8 l5 O- S
  u_long在32位机中是4个字节,在64位机中是8字节。以32位机为例,其中高12表示主设备号,低20为表示次设备号,如图61所示。
  D* |! c5 k& Q8 o
/ e0 c- o. w2 o+ j/ ?" F. M/ c  图61  dev_t结构6 n( s3 n9 m" b0 {( z! a

, N( N! k( x$ |# \  2.主设备号和次设备号的获取
; r2 V) }: p6 g4 N
) r* f7 E3 s3 D' n: l7 v. I( R  为了写出可移植的驱动程序,不能假定主设备号和次设备号的位数。不同的机型中,主设备号和次设备号的位数可能是不同的。应该使用MAJOR宏得到主设备号,使用MINOR宏来得到次设备号。: H, L8 ~" _4 L' O2 f& ]
: H( M8 M  p) d/ P1 p1 `
  大发888下面是两个宏的定义:! ^3 n# c7 j8 [+ X3 {: q* n$ k; E* V

! F% @& S" ^1 c* H2 z" u  #define MINORBITS        20                                                                         /*次设备号位数*/
5 U# l1 J- N. a& G& u+ S" s$ i$ f# x: g6 ?2 L
  #define MINORMASK        ((1U > MINORBITS))
6 Q. B0 n, u* b( x: K
) u/ ?6 Q  e+ N, V1 R# b                                                                                           /*dev右移20位得到主设备号*/4 l' _, A! W3 i5 V2 l( Q! W
4 V2 B% m( h' R# w( ]6 z
  #define MINOR(dev)        ((unsigned int) ((dev)  MINORMASK))
2 I: O) s/ U9 h% G4 C! i: f  N& F
! ]# h' B2 _0 K7 Z  K( D                                                                                          /*与次设备掩码与,得到次设备号*/
. {& S2 `7 @, t( U; B
! N9 t5 }/ x5 M0 J7 Q  MAJOR宏将dev_t向右移动20位,得到主设备号;MINOR宏将dev_t的高12位清零,得到次设备号。相反,可以将主设备号和次设备号转换为设备号类型(dev_t),使用宏MKDEV可以完成这个功能。4 f% L/ n, F# z& Q* @
, g: g% u  d8 P" O3 J/ ]
  #define MKDEV(ma,mi)        (((ma)
" K& N7 Z9 B) w4 \5 O% m9 d( G& |3 z0 D* u: b5 ~- z. w" q
  MKDEV宏将主设备号(ma)左移20位,然后与次设备号(mi)相与,得到设备号。0 S0 k+ e- p6 h: B% ?# K
4 q1 |  t/ ]: q7 T! }
  3.静态分配设备号" t, n, u* q/ ^* Z

1 g4 d2 d3 X3 Y, o  静态分配设备号,就是驱动程序开发者,静态地指定一个设备号。对于一部分常用的设备,内核开发者已经为其分配了设备号。这些设备号可以在内核源码documentation/ devicestxt文件中找到。
/ J( n+ R: P8 j0 E! s, q
9 Z( L( p+ \% i* E- d0 `/ `; h& _  如果只有开发者自己使用这些设备驱动程序,那么其可以选择一个尚未使用的设备号。在不添加新硬件的时候,这种方式不会产生设备号冲突。但是当添加新硬件时,则很可能造成设备号冲突,影响设备的使用。
$ g7 ^0 G! `$ f, `# [: w5 S3 }1 h+ ^1 ~8 \( P
  4.动态分配设备号, }2 m* Y+ V) ~* }3 [4 [- B) N

4 j" `% V' ^3 e  t  由于静态分配设备号存在冲突的问题
0 \% B& b3 C" N0 r& ?; p% `. D" V+ l3 l$ g6 J

暂时无法加载帖子列表

回复

使用道具 举报

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

使用道具 举报

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

使用道具 举报

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

    本版积分规则

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

    GMT+8, 2026-7-27 15:19 , Processed in 0.038622 second(s), 26 queries , Gzip On.

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

    Powered by Discuz! X3.5

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