别说爱就一个字,你数数你说过几次; 别说程序员好干,你看看你年薪几万!~ 别说你爱的太真,伤的却太深——只要真心的投入就无悔、无怨恨 别说失去的太多,那是不懂得收获;别说爱了又错过,那是你没有去收获住那么硕果!~ 请真心你现在所拥有的一切——守侯住属于你的爱情!FOR ever

Linux内核模块编程之字符设备文件

上一篇 / 下一篇  2008-02-13 16:45:35 / 个人分类:辞海

查看( 63 ) / 评论( 2 )
字符设备文件IXPUB技术博客.YS?"K+KW8{#yh
IXPUB技术博客 ba-C[ Yx*]hL
   因此现在我们是大胆的内核程序员而且我们知道如何写什么也不做的内核模块。我们为自己而自豪并且可以高高的仰起我们的头。但是不知何故我们感到遗失了什么。令人紧张的模块并不是很有趣的。
'Z+q6I,Hv)N [P0
a Asw ~.V(S_a0   内核模块有两种主要的途径和进程对话。一种是通过设备文件 (像 /dev 目录中的文件), 另一种是使用 proc 文件系统。因为写内核中的某些东西的一个主要的原因是去支持某种硬件,所以我们从设备文件开始。IXPUB技术博客;I1b.Qyx S1EK0[$f!n|
IXPUB技术博客^G4QD4V X)iD
   设备文件的原始目的是允许进程和内核中的设备驱动程序通信以通过它们和物理设备通信 (调制解调器, 终端, 等等)。 这个办法的实现是像下面这样的。IXPUB技术博客:r)cj:_o9kJgI9Nv^

K*HJL D8k%`;Y0   每个设备驱动程序负责某种硬件,它被分配一个主设备号。驱动程序的列表和它们的主设备号可以在 /proc/devices找到。每一个物理设备由设备驱动程序控制且被分配一个次设备号。 /dev 目录被假设包含每一个这样的设备的被称之为设备文件的特殊文件,无论它是否被真正的安装在系统上。IXPUB技术博客3ASI(O%a

N9A8mZ qp0   例如,如果你 ls -l /dev/hd[ab]*,你将看到所有的可能被连接到系统上的IDE硬盘的分区。注意它们都使用相同的主设备号,3。但是次设备号彼此都不相同。IXPUB技术博客xQn |H;P
否认申明: 这是假设你正字使用 PC 架构的系统。我不知道基于其他架构的Linux设备的情况。.
6E+N+{ nx'Sv$HAZ#vw0
Jpj+V'Z`@0   当系统被安装,所有的那些设备文件被 mknod 命令创建。从技术上说没有必须将它们放在 /dev目录的原因,这只是一个有用的惯例。像练习所示的那样,当为了测试的目的而创建一个设备文件,将它放在你编译内核模块的那个目录也许更有意义。IXPUB技术博客J3a3I'w{#RKx ^K
IXPUB技术博客9a/_ZLa S Q
   设备分为两种:字符设备和块设备。不同之处在于块设备对于请求有缓冲区,因此它们可以选择以什么顺序进行响应。对于存储设备而言这一点是很重要的,因为在读写连续的扇区时比远远的分离的扇区更快。另一个不同就是块设备只能以块为单位接受输入和返回输出(块的大小根据设备的不同而不同),而字符设备只能使用它们可能使用的或多或少的字节大小。大多数设备是字符设备,因为它们不需要这种缓冲而且不以固定块大小进行操作。你可以用ls -l区分一个设备文件是块设备还是字符设备.如果开头是“b”,那么它就是块设备;如果是“c”,那么就是字符设备。IXPUB技术博客1U Dn5ok9P Q.@

8j2g&L#B+K%N7NK u0   这个模块分为两部分:登记设备模块部分和设备驱动部分。 init_module 调用 module_register_chrdev 而将设备驱动程序加入内核的字符设备驱动程序表。它也返回该设备将使用的主设备号。 cleanup_module 注销该设备。
O:p&k i2g_6HF0
.}){Ei+G2A2f{0   这(登记什么和注销它)是那两种功能的常规功能。内核中的东西不想普通进程那样主动运行自己,而是由进程通过系统调用,或者由硬件通过中断,或者由内核的其他部分(简单的讲,由特殊的调用)进行调用。结果,当你向内核中加入代码,你被假设将之登记为某种句柄,而当你移除它时,你被假设出注销它。
4Zc:Iei/P}["W0
-JQX3RZz |K0f0   严格意义上讲,设备驱动程序由四个device_函数组成,当某人试图用我们的主设备号的设备文件做什么事时它被调用。内核是通过 file_operations结构知道要调用它们的,Fops, 在设备被登记时被给出,它包含那四个的。IXPUB技术博客9xrR%f/p
IXPUB技术博客iV-g8r2Ia.q
   另一点我们在这必须记住的是我们不能允许内核模块在任何根感觉需要的时候被rmmod。原因是如果设备文件正被一个进程打开然后我们移除那个内核模块,这将使用那个文件,而这又将导致对那个适当的读写函数所在的内存区域的调用。如果幸运的话,没有其他的代码被加载到那儿,我们得到一个难看的错误消息。如果不幸运的话,另一个内核模块被加载到同一区域,这就意味着跳到内核中的另一个的中间,结果是不可预见的,但肯定不是什么好事。IXPUB技术博客3Bpn#r+C+G8q'@l
IXPUB技术博客P}t+kPV k3Q1{
   通常,当你不允许什么事情发生,你会从被假设做这件事的返回一个用负数表示的错误代码。使用cleanup_module 是不可能的,因为它不返回任何值。一旦cleanup_module 被调用,模块即死亡了。然而,这儿有一个被称为引用计数器(在/proc/modules中的相应行的最后一个数字)的计数器计算有多少其他的内核模块正在使用该模块。如果该数字非零 rmmod 调用将失败。模块的引用计数器在变量mod_use_count_中. 因为有处理这个变量的宏定义 (MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT),我们最好使用它们而不直接使用 mod_use_count_ ,这样,如果将来实现方法改变了我们会更安全
Es)p;]s&j0范例 chardev.cIXPUB技术博客qP&ES/[!S)CBv

h4bo ^S0/* chardev.c
h&psI s#l1I"Ng|0* Copyright (C) 1998-1999 by Ori Pomerantz
1Zm}w$e0*
[oj7y"Wz:Y0* 创建一个字符设备(只读)IXPUB技术博客%P"r P d-i9ud
*/
L!I9@0N^ @]+a0IXPUB技术博客+a)F yi)WD _U\
/* 必要的头文件 */
8z@$t!e#p;Z0
5lLZO7V)Y+E0/* 内核模块标准头文件 */
a \ v~p0#include /* 内核工作 */
b#F x\+Y&FI8wJ*C!g,kf0#include /* 明确指定是模块 */IXPUB技术博客? j~9Dp`
IXPUB技术博客r#}%`z#c$]?U
/* 处理 CONFIG_MODVERSIONS */
u6h*}K.?6@1Pf0#if CONFIG_MODVERSIONS==1
hyjc J#e9r6C]q0#define MODVERSIONSIXPUB技术博客w?&K3^G)Vq.A
#include
#P(k,^ER+ibe0#endif
j6n a%V1[ e0IXPUB技术博客+_u7IQU
/* 对于字符设备 */
l-^rWl0~bBr0#include /* 字符设备定义 */IXPUB技术博客`(U E L n v V
#include /* 目前对下一步没有任何用的包装IXPUB技术博客&r:t8`~ \
* 但对未来的Linux 版本在兼容性上可能有帮助*/
Y gWG&`0t-e)n0IXPUB技术博客6t wh T5uu+V\_e
/* 在2.2.3版内核 /usr/include/linux/version.h 包括这个宏,但是IXPUB技术博客O ]d'\b ?O*b3P
* 在2.0.35中没有 - 因此我在这加入它以便需要 */
Y3c5Y ?"R4@0#ifndef KERNEL_VERSION
+I4s?^H(K4~0_OW{0#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
0V7zabD8\3^$p5^0#endif
"Pp!k1cuE e~ KE7P0
]L RsL5n"g~0/* 条件编译。 LINUX_VERSION_CODE 是版本代号(经 KERNEL_VERSION) 。 */
oF&Y;? eFY(\](F ^0#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)IXPUB技术博客M(s4iB&A:NC
#include /* for put_user */
B_hcIs0#endif
'w3N d{:F Ld]6}0
_8fL9B Q9i R4s5r0#define SUCCESS 0
0{s?d9sU N0y0
1\;C^@E$U0/* 设备声明 **************************** */IXPUB技术博客U/CJNn8ZL @(nJ

!H1PE&kg VKP0/* 设备名,将出现在 /proc/devices */IXPUB技术博客/gA-l6Oj.A
#define DEVICE_NAME "char_dev"
'Dq$ul)B0^Ql8p&` e0
/l BNY6SY5{W0IXPUB技术博客#D G(c2kB{)lQ
/* 设备消息的最大长度 */
+qoW-a4X"vM0#define BUF_LEN 80IXPUB技术博客MZ'Rtf(V wO
IXPUB技术博客1hN.K'p M
/* 设备正被打开吗? 用于防止对同一设备的同时访问 */
t{MYzo0static int Device_Open = 0;IXPUB技术博客x$@E/vh4K2o
IXPUB技术博客1d~,i e#K.SIL
/* 当设备被要求时给出的信息 */
1|G7`"S0]+?0static char Message[BUF_LEN];IXPUB技术博客v(^Zv'nETU

/@"Vlso^O0/* 进程读取消息到多远?如果消息的长度大于我们要填充进 device_readIXPUB技术博客TaBl0UH
* 的缓冲区的大小,这将有用。 */IXPUB技术博客zW#BXHU)y
static char *Message_Ptr;
z*s~7myV,h/E0
,\ ~2hj9c1BN3b0/* 这个在一个进程试图打开设备文件时被调用 */IXPUB技术博客_$X:t+``#Ik'Y&W
static int device_open(struct inode *inode,
T4aW4}"H)bnHx}0struct file *file)IXPUB技术博客 ^$B.L-| d@)A
{
N @#?)F fFI0static int counter = 0;
m?gdX9W)P0IXPUB技术博客qeCHi3J
#ifdef DEBUGIXPUB技术博客?7P K0{l L([
printk ("device_open(%p,%p)\n", inode, file);IXPUB技术博客 y2I+yBV&l2LQ0V hf
#endif
&jk6Z @o0IXPUB技术博客3[B[!tZw;lN
/* 这是当你有多个物理设备使用那个驱动程序时如何得到次设备号。 */IXPUB技术博客9v6XDM%c1\bHBE
printk("Device: %d.%d\n",IXPUB技术博客A%DI,oJ
inode->i_rdev >> 8, inode->i_rdev & 0xFF);
SZ.cb(n&kD0
]i_)smW0/* 我们不想同时和两个进程通话 */IXPUB技术博客'Q6E.u7j&~.U
if (Device_Open)
1iW,BZA]d7A0return -EBUSY;
eTWrWH\mC0IXPUB技术博客4k0[;Z[#u2h&vIk*TG
/* 如果这是一个进程,我们将必须在这儿更小心。
i^%`E I&D0*IXPUB技术博客 D1ug:]g!Q
* 在进程的情况下,危险在于一个进程已经检查过 Device_Open ,
PY;iY$uz0* 然后由于另一个进程运行这个而被调度程序代替。
D4u` n jaHn_cy0* 当第一个进程处于后台,它会假设设备仍然没有打开。IXPUB技术博客P!jO8]&@-^
*IXPUB技术博客*@%AgC!\/h#T1x
* 然而,Linux 保证当一个进程在内核环境下运行时不能被代替。
dhCN(V }3[0*IXPUB技术博客 oR0[t EX%j
* 在对称多处理的情况下,一个 CPU 可能增加Device_Open 而另一个CPU 也在这里IXPUB技术博客g\%ip vpSQ
* 刚好在检查完后。然而在 2.0 版内核中这不成为问题,因为有一个锁保证在同一IXPUB技术博客i6~%MC{ f[
* 时间只有一个CPU是内核模块。这在性能上不好,因此 2.2 版改变了它。
g6nwwVu$s j0* 不幸的是,我不能使用对称多处理单元去检查它在对称多处理下是如何工作的。
Gij-N(V#cDsa4l0*/
Z-J-H2Uu P0IXPUB技术博客"ecX6H)U
Device_Open++;IXPUB技术博客F+sv+btp

gt&A4p*E3I Vx*J6c0/* 初始化消息。 */
k^7JUn(k[0sprintf(Message,
H L_ vO-Hh8d j0"If I told you once, I told you %d times - %s",IXPUB技术博客:n j"h Hhsp,h%s5_
counter++,
H+f&D{Zu^0"Hello, world\n");
h*e/N,b \r!N4v;R0/* 我们允许用 sprintf 的唯一原因是消息(假设是32位整数,等于10位带符号的十进制数)
p4Qfj.v.Ks0* 的最大长度小于 BUF_LEN的大小--80。在内核中尤其要注意缓冲区溢出!!!IXPUB技术博客$~ k!B W l
*/IXPUB技术博客MQ;T T4|q's-XB

$Z#N+L9FG;o)z0Message_Ptr = Message;
{P#S_[ S8d#|0IXPUB技术博客f5_X3|%|3V? W8x-B)L
/* 通过增加使用计数确保模块在文件正被打开时不被移除
@:C$],u8zH'u0* (对该模块的打开的引用数非零时rmmod 将失败)
zoy|6|sS`0*/
R'OwM7L ^+J7XM a4mb0MOD_INC_USE_COUNT;IXPUB技术博客1rgG!md0j6CE4l

8d2MMU/FBz&Q0return SUCCESS;
SD9V3z*o!|'c0}
.Z+z9o%ba.S1N4N;m"D/G0
_5f+i1TQA0/* 这个在一个进程关闭设备文件时被调用。在 2.0.x 版中没有返回值,因为它不能失败IXPUB技术博客Q` @5{8Oo
* (你必须总可以关闭设备)。在 2.2.x 版中允许失败 - 但我们不能允许。IXPUB技术博客d:F"A%e4cUs\
*/
`Xv*fXb0#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
h r.s'b%UQm0static int device_release(struct inode *inode,IXPUB技术博客%D Cixe]
struct file *file)
9ji2ax t1ZcPL{0#elseIXPUB技术博客,C*Gn2J3Q0dVS!F}
static void device_release(struct inode *inode,IXPUB技术博客Nj,N[Y M
struct file *file)IXPUB技术博客 E6hsB p
#endif
9S zL$i x:NDK0{
W.k5i$|,P"J&s0#ifdef DEBUG
(RI ZJ&I-Q.s[ Ku0printk ("device_release(%p,%p)\n", inode, file);
yA/p0eC j#_~5gz0#endifIXPUB技术博客;g'H h dYzi1M!y

.O*WdQ.B7JQT:?0/* 现在为下一个调用者做准备 */
Hx[BS8oG$gi0Device_Open --;
2l"Ca k4?n0IXPUB技术博客 Nn&V ~c2QN
/* 减小使用计数,否则一旦你打开了文件你将永远不能移除该模块。*/
,Hk(l jR^w m0MOD_DEC_USE_COUNT;IXPUB技术博客!IA[F {-H
IXPUB技术博客5V3z5SpG
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)IXPUB技术博客 W o:kWV E%N~\
return 0;IXPUB技术博客!BO3p~-X-Y+s
#endif
c;e%{8J@@0nH0}IXPUB技术博客 ]6V6kJn/QPkJ
IXPUB技术博客L9p }h+qN5W#? ~t
/* 这个在一个已经打开设备文件而试图从它读的时候被调用。 */IXPUB技术博客(S/iEJ%n VF

^j BU-X6~-y&@m'bc(d-Q0#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)IXPUB技术博客E U.dmS1a'c.[:m%w
static ssize_t device_read(struct file *file,
)Zr#`$N _qr0char *buffer, /* 填充数据的缓冲区 */
[&\T6h)N&]b#hB0size_t length, /* 缓冲区长度 */IXPUB技术博客(Y-|%U.y pU*` rY
loff_t *offset) /* 文件偏移量 */IXPUB技术博客(_ Mk m ez2t}S
#else
8q9Ec O{0static int device_read(struct inode *inode,
aL|d.VG@^ Q0struct file *file,
3V'Da`!_'Wmmdzi4e0char *buffer, /* 缓冲区*/
6Fjf4zA_ f,a0int length) /* 缓冲区长度 (写的长度一定不能超过它!) */IXPUB技术博客 EL n%J;a'Zb8d4H'R
#endifIXPUB技术博客*s(lv)`vh5`QP
{IXPUB技术博客9s6q.h8y#B;rfQh
/* 实际上写入缓冲区的字节数 */
x { G8C)q]#c"f _0int bytes_read = 0;
'GZ&n/W)cD1j8H0IXPUB技术博客\^SU9ax!o"J
/* 如果在消息尾,返回 0 (表示文件尾) */IXPUB技术博客9A&}'S1BJ
if (*Message_Ptr == 0)
*im#dmY"[I` C0return 0;IXPUB技术博客4D T+DBH
IXPUB技术博客w!q? |eh K N7YJN
/* 实际上将数据放入缓冲区 */
nr2u?RI0while (length && *Message_Ptr) {IXPUB技术博客6CkO#j TU N.AA1I

u Og1c:I0/* 因为缓冲区在用户数据段而不在内核数据段,靠分配是不行的。
1cl:N!r ^5L$jB[9k0* 我们不得不使用 put_user 将数据从内核数据段拷贝到用户数据段*/
[H__2]'wXl h0put_user(*(Message_Ptr++), buffer++);IXPUB技术博客8B$q8H`3n}8RVz

+X8\2f#{3|r:L6Vw0
iB+D0Y-z0length --;
F!A%@`)`Q*c6\4eF0bytes_read ++;
yO d8F"p0}
"^LF1b{vyD0IXPUB技术博客,Sl8W1T?[/@IF
#ifdef DEBUGIXPUB技术博客XC2E.~g6n-Fi,P]
printk ("Read %d bytes, %d left\n",IXPUB技术博客ie+o E0aRK1D,Q.{
bytes_read, length);
:}#Xv'm9Ve \I0#endifIXPUB技术博客v/h2l4w7}!_$a

U1]:B&G{0/* 读被假设返回实际上插入缓冲区的字节数 */
8P,^5RMM9O#U0return bytes_read;
|,R?,[0y:n0}IXPUB技术博客$e%nr`8T]-l
IXPUB技术博客:E@8K}4|!U
/* 这个在某人试图向我们的设备中写时被调用--在这个例子中不被支持 */IXPUB技术博客T(p.XQ(RiJ
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
qN)zT$q"b6L_7B/x0static ssize_t device_write(struct file *file,
#rXq6h2X(^0const char *buffer, /* 缓冲区 */IXPUB技术博客h6d9?Wpge%`*u;f
size_t length, /* 缓冲区长度 */
,p(R M4mg0loff_t *offset) /* 文件偏移量 */
4\/@$}I[2J I0#elseIXPUB技术博客.|jY3h:A@W:|
static int device_write(struct inode *inode,IXPUB技术博客z3u0lpen.A
struct file *file,
@ U1_6["H0const char *buffer,
T sD5}(f5DC3?6W&p0int length)
#T.o0njp*si?0#endifIXPUB技术博客-q3bL2f(T#M(Kd
{IXPUB技术博客_v jWf&k$YGu
return -EINVAL;
L\6l%Ut\#A;u0}
P.Mu3H3g5|m#R [0IXPUB技术博客 wA7V@U!_6R;c$t
/* 模块声明 ***************************** */IXPUB技术博客d;Kgwh)ow

3|Rp Dti0/* 设备的主设备号。这是全局的(是的,是静态的,在这个文件中是全局的)IXPUB技术博客0Wj1].K3oC&?
* 因为在登记和释放时它都应可见。 */IXPUB技术博客th?$P]H
static int Major;IXPUB技术博客~5ZL3{9|p*C[

5}'~Hn(k2|0/* 当一个进程对我们创建的设备做什么时,这个结构将保存被调用的。
(g&JOwk&N0* 既然这个结构的保存在设备表中,所以它不能对init_module是局部的.
2Dh'V&\nkT1N0* NULL 代替未实现的。 */IXPUB技术博客V]cw:ZJ
IXPUB技术博客 [vlBf g
struct file_operations Fops = {IXPUB技术博客 op ~c1VPe$V
NULL, /* 寻找 */
1[;Y2hK_Y.V0device_read,IXPUB技术博客zMg9Ozb%N
device_write,
8| sF8ZI5hK7n&FF]0NULL, /* 读目录 */
3u vbLw2K S"aq0NULL, /* 选择 */
jI{`g*[0NULL, /* ioctl */
-[Xe$V+F}0O0NULL, /* mmap */IXPUB技术博客!i+~'o_w t6g
device_open,
[,I'Q6s1B7F)}!v8G/E0#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
mk,Rccs1T A[h-h.f'S0NULL, /* 刷新 */IXPUB技术博客{8P'AV}M/h
#endifIXPUB技术博客+@,@|0Al1MR Y-X GS:c
device_release /* 关闭 */IXPUB技术博客,N/QLh3v![/n6W7DV n!l
};
.qq^ J/m0
/{1tT*R)VL{ q0/* 初始化模块 - 登记字符设备 */
m Ca~4O(D+?b2C0u0int init_module()IXPUB技术博客V ~y%JM7Vfjt*a
{
-mX;k$EE jn1~Y0/* 登记字符设备(至少试图登记) */
*[#a)Zq-j5vC0Major = module_register_chrdev(0,
4^:p i#c:~/[7K@t2W(p0DEVICE_NAME,IXPUB技术博客`%o;j+v)d$V+t;`;Z'L
&Fops);
VY;ZLWUYB0
7F$\*h3?'OE0/* 负数表示错误 */IXPUB技术博客 mK ]8wB p h)zX
if (Major < 0) {IXPUB技术博客0O1Z#~g4TK nfH
printk ("%s device failed with %d\n",IXPUB技术博客zP(udi]+vD:A
"Sorry, registering the character",IXPUB技术博客x)Su[r? ?9mj
Major);IXPUB技术博客;Y D8p"nE0q/@
return Major;IXPUB技术博客gR3~5TR@4P Z
}
j4L/xd(L r$H!H0
i1o(I v.?0printk ("%s The major device number is %d.\n",IXPUB技术博客K h$a4cp s(FF6]
"Registeration is a success.",IXPUB技术博客Li l4Y&dN
Major);
h v#T\ riiSx0printk ("If you want to talk to the device driver,\n");IXPUB技术博客)B*i8f%W?l
printk ("you'll have to create a device file. \n");IXPUB技术博客O6KM9wn:H`-E
printk ("We suggest you use:\n");IXPUB技术博客5RrNaR t
printk ("mknod c %d \n", Major);IXPUB技术博客:nIO.@a ['r7Te[)I"~
printk ("You can try different minor numbers %s",IXPUB技术博客:VLw2aTsf [6d
"and see what happens.\n");
n-w#i k6W[:Z2?St0IXPUB技术博客w3sdE1D-l
return 0;IXPUB技术博客k%s;a0cf`;j;zb*M!{4i
}
+?]"ES+cGG1a0
`q4`Zo!\[:Y0
T#]6WqnF5P&u'w)v0/* 清除 - 从 from /proc 注销适当的文件*/
G2uv*u8L@y5D?h0void cleanup_module()
6h4G jz8gTx3V0{IXPUB技术博客7z \a4c b
int ret;IXPUB技术博客5sk R },A.n%vg0` dK
IXPUB技术博客\7d%W#\|
/* 注销设备 */
q,w ~.M `7nSN zC0ret = module_unregister_chrdev(Major, DEVICE_NAME);
i'K.bF2D%M dB~{0
8Odi'W _([ O%x0/* 如果有错则报告 */IXPUB技术博客a!yH%@ m5d!\
if (ret < 0)IXPUB技术博客'h2^@ j_
printk("Error in unregister_chrdev: %d\n", ret);IXPUB技术博客\z`-Yh]*Z(A b7F
}IXPUB技术博客vAA7Pn:R(|A
多内核版本源文件IXPUB技术博客iH+z \!f H#?/^
IXPUB技术博客M7K!Faa6{'R:Tf{5~
   内核展现给进程的主要界面是系统调用,它通常跨版本保持相同。新的系统调用被加入,但通常老的保持和原来严格的一样。这对于向后兼容性是必要的--新的内核版本不应打破常规的进程。在大多情况下,设备文件也将保持相同。另一方面,和内核内部的可以并且在版本之间有改变。IXPUB技术博客1su&a\z3O*M&X2\xE
IXPUB技术博客 F"pmK*~C eS!v-i
   Linux内核版本分为稳定版 (n.<偶数>.m) 和开发版 (n.<奇数>.m).开发版包含所有的好的新思想,包括那些被认为是错误或需要在下一版重新实现的东西。结果,你不能期盼在那些版本中界面保持相同(这也是我为什么不在这本书中操心去支持它的原因,那需要太多的工作并且很快就过时了)。另一方面,在稳定版中我们可以期盼界面保持相同,除了错误修订版(数字m)。IXPUB技术博客9FUiZ \!Q^u ~
IXPUB技术博客6fD\8@Upj
   这个版本的内核模块编程指南包括对 2.0.x 和2.2.x 内核版本的支持。既然这两个版本间有差异,这就需要根据版本进行条件编译。可以使用宏 LINUX_VERSION_CODE来做这件事。在 a.b.c 版的内核中,这个宏的值是 216a+28b+c。为了 得到某个内核版本的值,我们可以使用 KERNEL_VERSION 宏. 因为在 2.0.35版中没有定义它, 我们可以在必要的时候自己定义它。IXPUB技术博客6a'M.J$}{j

;` v7GLAvx O}#bU8b0[本帖最后由 grjboy30 于 2008-2-13 16:45 编辑]

TAG:

jutang的博客 jutang 发布于2008-02-13 14:36:37
锅子你真强,什么都会,偶服了你了,给你顶了
我们都是只有一只翅膀的天使,无法割舍彼此 grjboy30 发布于2008-02-13 16:45:59
回复 #2 jutang 的帖子
你不说俺还没注意 权限设置的太高了
c G(@"G
tV        O(K*kblog.ixpub.net

|9^E"p!}blog.ixpub.net已经修改为!~
我来说两句

(可选)

Open Toolbar