网络推荐



本广告位招租!

推荐给好友 上一篇 | 下一篇

Writing a pseudo device

原文http://www.netbsd.org/Documentation/kernel/pseudo/BSD爱好者乐园X.nU }._0|W'o }]a%K

:f2yC$Hw5F/yxNetBSD文档:如何编写一个伪设备BSD爱好者乐园A#Sfc:}+Rn
BSD爱好者乐园d7zJ)af$@4Q^
简介BSD爱好者乐园1jM3l#? h'W'b.Q[X$Y
本文是为那些想学习写内核驱动的人的入门指南,全文围绕一个简单的伪设备展开。阅读本文你需要熟悉内核的编译、makefile、安装内核这些本文没涉及的内容。本文也不涉及内核编程本身,它和应用编程相当不同。总之,本文是你进入内核编程世界必经之路。
zEt9_M#}%\BSD爱好者乐园8Cn a"rm t GV;?$P
你的代码BSD爱好者乐园-rP;b}#Gdn~
pseudo_dev_skel.c文件给出了伪设备的框架,pseudo_dev_skel.h定义了内核函数原型和ioctl数据结构以及ioctl号。注意,不同于一般的驱动,伪设备没有常规的探测过程,因为这没必要,这简化了开发过程因为我们不必和autoconfig框架打交道。我们提供了一个支持open、close和ioctl调用的例子,这是一个真正的伪设备最小的功能集。一般伪设备还会有read、write、mmap和其他的设备函数,但它们都和open、close和ioctl一样遵循同样的模式,因此,本文就省略了这些内容。BSD爱好者乐园'\v7L E.c(t
也许你需要弄清的首要任务是怎么称呼你的新设备。有很多方便的用来生成内核结构的宏可以把设备名和函数调用名联系起来,如果你要在内核配置文件中添加一项的话这些宏就会派上用场,配置文件项并不指定头文件名。在我们的示例驱动中我们管这个为设备叫“skeleton”,所以我们得有一个叫skeleton的配置文件项。这意味着attach、open、close和ioctl函数以skeletonattach、skeletonopen、skeletonclose和skeletonioctl的名字被调用。另一个问题是,你写的伪设备是块设备还是字符设备,这将影响到你的代码和内核的交互,毕竟是你自己写这些代码。写设备驱动就面临着块设备驱动还是字符设备驱动的问题,这取决于它们跟什么设备通信,根块设备通信就最好选块设备,反之亦然。有些设备即支持块模式又支持字符模式,有时称之为“raw”设备,因为它不提供数据块抽象操作。伪设备就没有这个问题,根本不必考虑硬件,而根据它的用途来确定,模拟磁盘就选块设备驱动,但是我们的例子是个字符设备。BSD爱好者乐园&L%[t;j8}"Rt
一旦问题确定了我们就开始弄代码了,在此之前我们要决定代码放在哪里,如果我们的伪设备要在多平台下使用就放在/usr/src/sys/dev,如果只在x86下用就放在/usr/src/sys/arch/i386/的相应目录下。pseudo_dev_skel.c的头部应该是skeleton_softc结构,<你的设备名>_softc这样的softc结构是必须的,其第一个成员必须是        struct device类型,entry的名字不重要,但是必须是第一个,因为autoconfig读取softc结构而不加检查,并且必须是一个struct device。每个softc对应一个设备的子设备号,如果子设备需要保存状态信息的话softc结构可以比struct device保存更多的成员。BSD爱好者乐园;lM(f&e!d]%y!Z H t:i
BSD爱好者乐园-kHpe|c7} T \$fl
函数BSD爱好者乐园J~ |5Z.b(Bu\ |
你的设备的内核接口可以通过一组函数来被用户态程序访问。一个设备不需要支持全部接口,但是一个有用的设备最少要支持open和close。记住这些函数和你的设备被联系起来了。BSD爱好者乐园7T \f9yHc_So
1. attach()
'zR |$l'I N)\        该函数在内核初始化时被调用一次,被用来设置所有被稍后用于分配需要的用作缓冲的内核空间的调用所引用的变量。该函数只有一个参数就是要操纵的驱动的设备号。
@\*db2k;T&Zk2. open()
f)a4OY4S4]        打开设备。简单的情况会返回成功,一般还要检查状态确认是否成功。该函数有四个参数:
*]w hD`~        devBSD爱好者乐园w^R0t9d}$\H
                要操纵的设备的子设备号。BSD爱好者乐园%s3b,FEV:Pm"lm
        flagsBSD爱好者乐园? f w6YDP+L(J!q
                就是应用编程中open的flags参数BSD爱好者乐园-nr|'@xa K
        mode
@,c$M,_6QdL ?9O3D(`                打开的模式
^K&@ sjv z%P1Ji7D        procBSD爱好者乐园|3P:},D3|p$`/X
                指向打开设备的进程的指针,它允许被进程确认。BSD爱好者乐园gJ1TM.fD'Wiu6VA
3. close()
\]$@1` ^K        关闭设备。也可以是简单的返回成功、释放先前非配的内存、更新驱动状态等等。和open的参数一样。BSD爱好者乐园Z:W:KJ0Nd rCXM v
4. read()
&F5k1AR2O4` Y#N        读数据。参数:BSD爱好者乐园s;B Q Wj
        devBSD爱好者乐园"U s@i7rJGbM:Sh'E
                子设备号。BSD爱好者乐园Qsx&F2J0U^m$A
        uio
[ Wot#T\                指向uio结构的指针,read会用它要返回给用户的数据填uio结构。BSD爱好者乐园'QN|G8fHI:m1Y
        flags
*x3V0a:yGe                就是flagsBSD爱好者乐园D"b5G h P;s&~
5. write()BSD爱好者乐园,AU!\8y+a
        写。参数和read一样,不同就是要写的数据填uio结构。BSD爱好者乐园r!E"| m{g2|bA$R
6. ioctl()BSD爱好者乐园'YGe:uy'Kw
        I/O控制命令。参数:BSD爱好者乐园cW'^K z
        dev
]r-M%qEUr+v                子设备号
y{*V8c$R8m O |        cmd
(` _F-NJ[#R3A5g'q$\                命令,命令在内核代码和用户态代码共同的头文件中定义。参见sample header。BSD爱好者乐园A:? U0zhx
        data
}e/d/E` D#p&yz                指向用户态代码传过来的参数,在该参数的内容由ioctl的实现决定。
/sZ | N nO9L7. stop()BSD爱好者乐园3Q*VT5\(},}R
        如果是tty设备,在tty设备上停止输出。参数:
5M{#Bv9H.V ].c        ttyBSD爱好者乐园)O'ucR+fP+j
                和tty相关联的设备
A Ns+V wXh        flagsBSD爱好者乐园 h$C0n\ J/O{5O
                就是flags
4f+JA'yTKF$gC6i)u8. poll()
]%D(L/E B#q#i V.|N        通过读数据来检查设备,轮询,参数:
^3u,L}a7@        dev
sCS,DJtDq                子设备号
{$q i$[9~zG)E        eventsBSD爱好者乐园VI:^zEy
                来自用户态代的调用轮询的事件
N4jy`Cg#f.Awi        procBSD爱好者乐园:o+uit)PDvD4P Z
                指向ioctl要求的用户态进程的指针BSD爱好者乐园{ z5H(ZO2e2w
9. mmap()
Y n*j\/GZ K        支持高性能的把驱动缓冲映射到用户态程序的地址空间中去,参数是:BSD爱好者乐园c4Szpf&A
        dev
&E:Bi'h6U^\ld'r1s3y bi                设备的子设备号BSD爱好者乐园1bFjP? [:L*slI
        offsetBSD爱好者乐园 {\^(i7BF?
                开始映射的地方,从缓冲区开始算的偏移量
2p {p:g*`~l        port
PZ!e|*C                mmap的类型,只读还是读写,设备驱动并不支持所有的类型
h$c Ac7q4}#xXv你的设备驱动支持的函数的名称必须被加到<你的模块名>_cdevsw那个struct cdevsw中去(如果是字符设备,块设备是struct bdevsw),本例是skeleton_cdevsw。注意:这些结构中包含所有的接口而你只须实现一部分。与其强迫所有人实现不必要的函数不如放一些预定义的插桩函数,当no函数(如noread、nowrite等)被调用时,它们返回ENODEV或null(nullread、nullwrite等),但是预定义的插桩函数会返回成功但是什么也不做,你的设备不必支持块设备和字符设备的这些预定义的插桩函数。
3y d$\ J:z jI.T'm ]BSD爱好者乐园mE(JTMKi{*a4e7`
向内核添加你的设备BSD爱好者乐园(~ |atg'G M:}
一旦你写好了你的伪设备,就要hook进内核测试一下了。加载伪设备和实际设备不同,伪设备没有探测和自动配置的过程,让内核使用你的伪设备要修改下面这些文件:BSD爱好者乐园*@5L j2be
1. /usr/src/sys/conf/majors或/usr/src/sys/<arch>/conf/majors.<arch>BSD爱好者乐园)S5g \9hHr
        这些文件包含NetBSD的主设备号列表,/usr/src/sys/conf/majors包含机器无关的主设备号列表,某特殊平台的在/usr/src/sys/<arch>/conf/majors.<arch>中。它们以下面的形式被列出:
$EQy@+xJ+vceQ;x
PHM&IDu)tU7B
QUOTE:
device-major    prefix                type      number        condition

D:N E,QQrb这些符号的意思详见config(5)BSD爱好者乐园a0]s3J|t
        device-majorBSD爱好者乐园4N!T ?8v Z6S
                标示主设备号的关键字BSD爱好者乐园9} Z bYatNe
        prefix
oc7u |u\ U&z,jD.F_                前缀,被自动加到所有函数的前面,如本例的skeleton
w,e"B+X!sI6} NG5D        type
W/BV|:i f3R-mO                主设备的类型,char还是block,你可以通过重复type/number来制定一个既是块设备又是字符设备的设备BSD爱好者乐园k.clyBTQ
        numberBSD爱好者乐园%O,V,E&]J9~V]4Y^
                主设备号,选下一个可用的数字(当前设备用了1-8你就用9),你需要在/dev下为它创建一个设备节点
~/?(n Qv&I6U:`B        conditionBSD爱好者乐园x+X1wjdiuf[
                设备被包含进内核的条件,需要和你在内核配置文件(下面讲)的描述一致。
*\May5lr.K因为我们的skeleton示例是个字符设备,并只工作在i386下,我们把下面一行添到/usr/src/sys/arch/i386/conf/majors.i386中去,这里主设备号是140。
^\4Kf.xaBSD爱好者乐园 o/HN*Cj Y
QUOTE:
device-major        skeleton        char        140        skeleton
BSD爱好者乐园b"J7L:rF p:UztL
向config(1)添加你的设备
(@uD1p4\+ls)Y!Jho让config(1)认识你的设备我们需要修改/usr/src/sys/conf/files(机器无关的设备)或/usr/src/sys/arch/<arch>/conf/files.<arch>。这些文件告诉config活跃的设备的名字和那些设备和哪个文件相关联。首先我们找到伪设备的定义那一节,以defpseudo开头,本例中我们需要修改/usr/src/sys/arch/i386/conf/files.i386,找到
4I(E4L|:ilv8K
h u dN4p
QUOTE:
defpseudo skeleton

WW AgBTf|这一行告诉config(1)我们有个叫skeleton的伪设备接下来需要告诉config(1)的是skeleton和哪个文件关联,我们只需加入一行就行:BSD爱好者乐园 NG5P4hx{
BSD爱好者乐园e1X,g+g%z0maX%c]
QUOTE:
file dev/skeleton.c           skeleton        needs-flag

N;M2D ~!{g Xc&yD6Nfile是关键字,dev/skeleton.c就是那个文件(通常在/usr/src/sys),skeleton是驱动的名字,needs-flag告诉config(1)生成skeleton.h文件。注意:在这里第二项的文件名和我们的文件名是对应相同的。BSD爱好者乐园 wk!ShZh8_6]
BSD爱好者乐园6K+SXn)s(y O
向内核配置文件添加新设备BSD爱好者乐园 h%xNr+Yt
一旦config(1)被告知了有个设备,向内核配置文件添加设备就简单了,加一行就行:BSD爱好者乐园jhR1B o$oJz1^

v9Q"_4u:@E:R{
QUOTE:
pseudo-device  skeleton
BSD爱好者乐园V o7v%oj
在内核配置文件中pseudo-device 这一行和前面的defpseudo那一行对应。新的定义可以通过option关键字加入内核,配置会产生一个makefile,给option的项的cc命令加-D参数。BSD爱好者乐园a*x\l H1u[
BSD爱好者乐园(~xy+X4II:bQ#O
使用户态程序可以访问你的设备BSD爱好者乐园GS7B5Jo8?5K
在编译和安装新内核之后,就需要为设备新建一个设备节点,你可以在文件系统你可以访问的任何地方创建节点,但一般是在/etc下。创建设备节点你只需打这么一个mknod( 8 )命令:
{7\)H3a"]xgBSD爱好者乐园Z}6V-wXL9?8V!E4x
QUOTE:
# mknod /dev/skel c 140 0
BSD爱好者乐园4Ji(s~l5M&p![
一旦你创建了节点就可以打开它测试一下。sample.c就是测试文件。下面的命令编译它:BSD爱好者乐园 J-mbg_O%z^n#[
BSD爱好者乐园,_#zszPc Q%G C5_,U
QUOTE:
$ cc -o sample sample.c

G H/r^nrOG&j会得到一个叫sample的二进制文件。注意:你必须已经在编译目录运行过make includes,即把你的pseudo_dev_skel.h拷贝到了系统的includes目录下。你运行sample可以在终端和/var/log/messages查看内核消息。消息是这个样子的:
boI-}S2X`BSD爱好者乐园7~"r2u3Bo{XQ#~8}[
QUOTE:
May 17 20:32:57 siren /netbsd: Got number of 42 and string of Hello World

[版权声明]BSD爱好者乐园站内文章,如来源不是互联网,则均系原创或翻译之作,可随意转载,或以此为基础进行演译,但务必以链接形式注明原始出处和作者信息,否则属于侵权行为。另对本站转载他处文章,俱有说明,如有侵权请联系本人,本人将会在第一时间删除侵权文章。
TAG: netbsd 翻译 pseudo
 

评分:0

我来说两句

seccode