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

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

[复制链接]
杨莹莹连 发表于 2013-11-11 16:00:05 | 显示全部楼层 |阅读模式
          5 {6 A' \% L7 q# g4 q/ T( f

* r5 T6 T' z; P' I+ _( S  第6章  简单的字符设备驱动程序
2 l) V# s( l$ l) ?0 \# I4 O7 o( s6 o+ s4 O& e
  在Linux设备驱动程序的家族中,字符设备驱动程序是较为简单的驱动程序,同时也是应用非常广泛的驱动程序。所以学习字符设备驱动程序,对构建Linux设备驱动程序的知识结构非常重要。本章将带领读者编写一个完整的字符设备驱动程序。% D. y' \: n% X7 k* \& T

; R1 b+ \8 x& ~$ |  H1 T  61  字符设备驱动程序框架/ Z% h% c8 k% n
" _7 ?, l0 O$ u  V, \  g7 K
  本节对字符设备驱动程序框架进行了简要的分析。字符设备驱动程序中有许多非常重要的概念,下面将从最简单的概念讲起:字符设备和块设备。" I# x/ i5 H# Z* R$ I  f& Q* n% v

3 U4 q3 b9 Z9 E# L* t: `3 m  611  字符设备和块设备
! O. |8 A- E  O, o2 D' T. z
9 i- ~  n0 ?# j  Linux系统将设备分为3种类型:字符设备、块设备和网络接口设备。
4 H0 u2 H5 j& d! D. D2 G* [$ S# u' c
  其中字符设备和块设备难以区分,下面将对其进行重要讲解。
, z4 k2 r9 t1 a: W; a0 G6 s7 R' C- a+ E, B; G. S( `/ B2 G/ g3 w8 ~
  1.字符设备% y8 s: U5 ^8 ]+ i( l, d
4 R* d) j& ]: z2 s2 n) _: W
  字符设备是指那些只能一个字节一个字节读写数据的设备,不能随机读取设备内存中的某一数据。其读取数据需要按照先后顺序,从这点来看,字符设备是面向数据流的设备。
; h% _! L% l+ o9 _8 G/ r5 [. J2 M- G* |
  常见的字符有鼠标、键盘、串口、控制台和LED等设备。! b5 B# I: P0 n2 F: h# q* |3 x

; Z7 K; a7 x5 P* t# q$ Z" s" z  2.块设备" ^$ x) ?6 A! C& |5 n/ P
$ X' o* `5 l" j, k$ l7 G/ h
  块设备是指那些可以从设备的任意位置读取一定长度数据的设备。其读取数据不必按照先后顺序,可以定位到设备的某一具体位置,读取数据。
, i$ A2 w, K* |; X% p: e3 \/ ^$ i# B4 c( ]$ c
  常见的块设备有硬盘、磁盘、U盘、SD卡等。
+ M6 }- B) |1 s/ U0 ~2 T" p/ z- z' W4 N, I
  3.字符设备和块设备的区分
& t) Y- n4 R* L0 p2 t2 f$ c& i% F( c( d  X+ R
  每一个字符设备或者块设备都在/dev目录下对应一个设备文件。读者可以通过查看/dev目录下的文件的属性,来区分设备是字符设备还是块设备。
. o  C  q( N% R1 e+ a
. [- w$ K' O( j+ U! H2 A/ c  使用cd命令进入/dev目录,并执行ls -l命令就可以看到设备的属性。- \; ^* P9 `& L, h" \' u

7 t* e: [9 o( |8 i0 ]8 c" d  [root@tom /]# cd /dev                                                        /*进入/dev目录*/& S6 y8 ~6 K; J" o: u; B8 Q8 ^

* e6 W: d" U3 j& M8 l" Y3 {  [root@tom dev]# ls -l                                                         /*列出/dev中文件的信息*/、
: N9 Z. ?2 `7 a' w! N" }/ _1 {- ]5 u; t  w$ h
  /*第1字段     2  3  4      5    6         7      8  */
& M2 k- X  K) U& ?! W. R0 m) e! G5 a1 h
  crw-rw----+         1 root root    14,  12         12-21 22:56 adsp
  W' a3 e! l' l& j1 e) C- U& m! t; Z6 [1 L
  crw-------          1 root root    10, 175         12-21 22:56 agpgart$ L  F" {9 s( j7 r' L
2 \2 w) x  z7 o# l" q+ C
  crw-rw----+         1 root root    14,   4         12-21 22:56 audio' x- {: w6 l6 L: j

+ J/ Q* N* _2 r3 ~! s  brw-r-----          1 root disk   253,   0         12-21 22:56 dm-0
0 L; ]" w4 q9 ~& Z! z* @' x
( \  q- s+ O' {0 Y, i  brw-r-----          1 root disk   253,   1         12-21 22:56 dm-1
: [$ q( E5 A4 ]3 T2 |! l7 d+ i
1 z( D# r* |; U* l% i. f2 P  crw-rw----          1 root root    14,   9         12-21 22:56 dmmidi3 o, M# x; c1 {
  }8 L" C/ d5 m* w6 ^  @, K2 x
  ls -l命令的第一字段中的第一个字符c表示设备是字符设备,b表示设备是块设备。第234字段对驱动程序开发来说没有关系。
# J2 c9 w1 U  }% T' U9 g0 v) Y# k* J; s4 V* n, ]* W7 P, A
  第5,6字段分别表示设备的主设备号和次设备号,将在612节讲解。第7字段表示文件的最后修改时间。第8字段表示设备的名字。# x; e% ~" z% N( O/ |- }

: e0 \4 d, v$ s6 `2 H  由第1和8字段可知,adsp是字符设备,dm-0是块设备。其中adsp设备的主设备号是14,次设备号是12。
0 Q7 {% t. T4 H8 Y
. {: m4 C  H2 N2 Z  ]0 s  612  主设备号和次设备号
9 ~! B% a8 e8 r8 X, c
0 s4 h4 t& {/ r0 w% \- p& h/ \/ ?9 s  一个字符设备或者块设备都有一个主设备号和次设备号。' ?# g# w* L5 N' B4 T( E; }
, e; i# W6 G- h+ d+ B* L9 c$ c
  主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。( O# ~) I8 K- v. y, O( n7 v6 i

7 j' H" n, Q8 K  例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。5 W2 u4 Y$ b6 G; P) U" ~# N+ Y7 k

- E' x$ ?6 ?2 C3 m* p$ G- M  1.主设备号和次设备号的表示3 K/ Z0 M  c% P# R
! M- V+ T  Y+ @: L) n
  在Linux内核中,dev_t类型用来表示设备号。在Linux 26294中,dev_t定义为一个无符号长整型变量,如下:! L+ t+ N0 l* b: R4 z# ^, j
( J5 v' {6 C2 y! c# z% @9 V! j
  typedef u_long dev_t;% T, R9 V# D1 [; i
2 s+ Q$ h( w3 k' T; L; W; }' x
  u_long在32位机中是4个字节,在64位机中是8字节。以32位机为例,其中高12表示主设备号,低20为表示次设备号,如图61所示。! F+ h% Q; L7 g8 E

: Z3 M5 W) I& T9 S5 k7 F  图61  dev_t结构
: h; \" j- m) Y
! _/ R1 k( @+ i" w2 b  2.主设备号和次设备号的获取5 X5 d$ L5 g4 G( w4 U1 _- C

5 N7 E+ v+ L' f) s3 O  为了写出可移植的驱动程序,不能假定主设备号和次设备号的位数。不同的机型中,主设备号和次设备号的位数可能是不同的。应该使用MAJOR宏得到主设备号,使用MINOR宏来得到次设备号。0 k8 k1 _  t+ Y/ ~# M" v4 x3 ?
. |$ J% ?- U3 E! N" Q* s) ]
  大发888下面是两个宏的定义:
' f  @8 b+ J0 l" b* h3 Y5 s: U( E3 Q2 W$ R- U8 X- _5 G# ^8 Y* `
  #define MINORBITS        20                                                                         /*次设备号位数*/
" |' W4 \1 D5 _9 u( ]' ~( ~
; d* w) _9 {! Z9 h5 B2 d- R7 M! J& f  #define MINORMASK        ((1U > MINORBITS))! B4 h! A. m( f' h: y  z
. i" @. C, `* P
                                                                                           /*dev右移20位得到主设备号*/
6 K- R* m2 E5 T% I, r9 d9 @' @* F9 \- B. H; X  p9 B) V
  #define MINOR(dev)        ((unsigned int) ((dev)  MINORMASK))9 d+ e# `- M( _) \  z1 u- C8 G; k

/ K+ @; L  p8 y4 v                                                                                          /*与次设备掩码与,得到次设备号*/- ]8 D* }& _# [: C4 g
/ \" X+ A8 }4 U$ F2 Q" w; K
  MAJOR宏将dev_t向右移动20位,得到主设备号;MINOR宏将dev_t的高12位清零,得到次设备号。相反,可以将主设备号和次设备号转换为设备号类型(dev_t),使用宏MKDEV可以完成这个功能。/ B: Y6 Y, E; ?5 b1 `
7 a' f/ t; F" M% K7 R# J
  #define MKDEV(ma,mi)        (((ma)
7 y6 ~4 k3 m1 b. |' H
+ I( X$ h& l; k# d3 v  Y  MKDEV宏将主设备号(ma)左移20位,然后与次设备号(mi)相与,得到设备号。2 g1 l( `. E4 g# ?+ x& j# T; \# B1 g
7 Z  _% f% Q8 z& P
  3.静态分配设备号
+ P  d! U1 t; u( G
7 |: n) C7 a5 K- k  静态分配设备号,就是驱动程序开发者,静态地指定一个设备号。对于一部分常用的设备,内核开发者已经为其分配了设备号。这些设备号可以在内核源码documentation/ devicestxt文件中找到。
% N7 J: M0 g, K$ ?* r/ I) p
- V; E, D) g, B) c  如果只有开发者自己使用这些设备驱动程序,那么其可以选择一个尚未使用的设备号。在不添加新硬件的时候,这种方式不会产生设备号冲突。但是当添加新硬件时,则很可能造成设备号冲突,影响设备的使用。# O, F- \7 ]( N  l$ w
7 ^: v4 u6 R4 C6 {3 o+ u) R
  4.动态分配设备号# }3 z/ f* _& K" J. B7 _

2 z: G  C$ X6 k: Z  由于静态分配设备号存在冲突的问题7 T6 \4 C7 |8 e: |9 u5 m' c
. u2 B' |4 N2 P& x
回复

使用道具 举报

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

使用道具 举报

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

    本版积分规则

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

    GMT+8, 2026-6-15 23:46 , Processed in 0.024351 second(s), 24 queries , Gzip On.

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

    Powered by Discuz! X3.5

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