📄 一个简单的演示用的linux字符设备驱动程序.htm
字号:
data_size指定缓冲区中有效数据的字节数。我们的设备<BR>只支持读不支持写。我们在char8139_init()中为缓冲区分配空间。<BR><BR>char8139_exit()里面的操作就是char8139_init()里面操作的反向操作。<BR><BR><BR>现在我们来看看,假如用户调用了"cat
/dev/char8139_3"这个命令会发生什么事情。<BR>根据前面的介绍,我们驱动程序中的open()函数会被调用。<BR><BR>int
char8139_open(struct inode *node, struct file *flip)<BR>{<BR>int type =
MINOR(node->i_rdev)>>4;<BR>int num = MINOR(node->i_rdev) &
0x0F;<BR><BR>/* put some char in buffer to reflect the minor device number
*/<BR>*buffer=(unsigned char)('0');<BR>*(buffer+1)=(unsigned
char)('x');<BR>*(buffer+2)=(unsigned char)('0'+type);<BR>*(buffer+3)=(unsigned
char)('0'+num);<BR>*(buffer+4)=(unsigned
char)('\n');<BR>data_size+=5;<BR><BR>PDBG("Ok. Find treasure! 8139 I/O port
base: %x\n", detect_8139_io_port());<BR>PDBG("OK. Find treasure! 8139 I/O memory
base address:
%lx\n",<BR>detect_8139_io_mem());<BR><BR>MOD_INC_USE_COUNT;<BR><BR>return
0;<BR>}<BR>这里演示了次设备号的作用,它让我们知道用户操作的是哪一个"次设备",是/dev/char8139_0还是<BR>/dev/char8139_3,因为对不同的"次设备",具体的操作方法可能是不一样的,这样就为一个驱动程序<BR>控制多个类似的设备提供了可能。<BR><BR>我们根据次设备号的不同,在buffer中填入不同的字符(次设备号的16进制表示)。<BR><BR>接着驱动程序中的read()函数会被调用,因为cat程序的实现就是读取文件中的内容。<BR><BR>ssize_t
char8139_read (struct file *filp, char *buf, size_t count, loff_t
*f_pos)<BR>{<BR>ssize_t ret=0;<BR><BR>PDBG("copy to user. count=%d,
f_pos=%ld\n", (int)count, (long)*f_pos);<BR>if(*f_pos>= data_size)<BR>return
ret;<BR>if(*f_pos + count > data_size)<BR>count =
data_size-*f_pos;<BR>if(copy_to_user(buf, p_buf, count))<BR>{<BR>PDBG("OOps,
copy to user error.\n");<BR>return -EFAULT;<BR>}<BR><BR>p_buf +=
count;<BR>*f_pos += count;<BR>ret=count;<BR><BR>return
ret;<BR>}<BR><BR>要正确的实现一个read()调用,你得想一想一个应用程序是如何调用read()从文件中读取数据的。<BR>如果你想明白了就很简单,驱动程序所要做的就是把恰当的数据传递给应用程序,这是使用<BR>copy_to_user()函数完成的。<BR><BR>另外,我们必须得意识到,这里只是一个很简单的演示。还有很多复杂的问题有待考虑,比如两个<BR>应用程序可能同时打开我们设备,我们的设备应该怎样反应(这取决于具体的设备应有的行为),还有<BR>互斥的问题。<BR><BR>然后我们看看I/O端口和I/O内存的操作。这里使用8139网卡作为一个硬件实例来演示I/O端口和<BR>I/O内存的操作。没有什么特别的,都是标准的步骤。在使用时需要注意,如果你的系统中已经有<BR>8139网卡的驱动程序,必须先关掉网络设备,卸载驱动,然后再使用本驱动程序。<BR><BR>使用程序包的步骤:(在我的Debian系统上如此,你的可能不同)<BR>1.
解压<BR>2. 编译(/usr/src/linux处必须要有内核源代码)<BR>3. ifconfig eth0 down 关掉网络设备<BR>rmmod
8139too 卸载原来的8139网卡驱动<BR>insmod char8139.o 插入我们的模块<BR>(insmod会出错,
如果你现在运行的linux版本不是你编译本驱动程序时使用的内<BR>核源代码的版本,insmod时会报告模块版本与内核版本不一致。这时,你得看看<BR>内核源代码中/include/linux/version.h文件,这个文件中的UTS_RELEASE<BR>定义了内核的版本号,你可以在驱动程序中预先定义这个宏为当前运行的内核的<BR>版本号,这样就能避免上述错误。)<BR><BR>4.
mknode(见本文前述)<BR>5. 试试我们的设备<BR>./readtest<BR>或者<BR>cat /dev/char8139_0或<BR>cat
/dev/char8139_1或<BR>cat /dev/char8139_2或<BR>cat /dev/char8139_3<BR>6.
恢复系统<BR>rmmod char8139<BR>modprobe 8139too<BR>ifconfig eth0
up<BR>如果你使用dhcp可能还需要运行dhclient <BR><BR></P>
<P class=diaryFoot>【作者: <A
onclick="window.open('http://publishblog.blogchina.com/blog/postMessage.b?receiver=89297','发送短消息','width=520, height=455')"
href="javascript:void(0);">linuxipy</A>】【访问统计:
<SCRIPT language=JavaScript
src="一个简单的演示用的Linux字符设备驱动程序.files/PageServlet.htm"></SCRIPT>
】【2005年01月6日 星期四 23:53】【 <A
href="javascript:void(keyit=window.open('http://blogmark.blogchina.com/jsp/key/quickaddkey.jsp?k='+encodeURI('一个简单的演示用的Linux字符设备驱动程序')+'&u='+encodeURI('http://linuxipy.blogchina.com/linuxipy/507920.html')+'&c='+encodeURI(''),'keyit','scrollbars=no,width=500,height=430,status=no,resizable=yes'));keyit.focus();">加入博采</A>】【<A
href="javascript:window.print();">打印</A>】 </TD></P></DIV>
<DIV class=operation><A name=trackback>
<H3>Trackback</H3></A>
<P class=trackback>你可以使用这个链接引用该篇文章
http://publishblog.blogchina.com/blog/tb.b?diaryID=507920 </P></DIV>
<DIV class=operation><A name=comment>
<H3>回复</H3></A>
<TABLE cellSpacing=0 cellPadding=0 width=700 border=0>
<TBODY></TBODY></TABLE></DIV>
<DIV class=operation>
<TABLE class=comment cellSpacing=0 cellPadding=0 width=700 border=0>
<FORM id=replyForm method=post><INPUT type=hidden value=86487 name=blogID>
<INPUT type=hidden value=507920 name=diaryID> <INPUT type=hidden
value=linuxipy name=blogDomino>
<SCRIPT>
if(getCookie('userID') == null){
document.write('<tr><td width="70">发布人:</td>');
document.write('<td width="150"> <input name="remark.authorNameFUI" type="text" size="20" class="inputStyle" maxlength="20"></td>');
document.write('<td width="70">邮箱:</td>');
document.write('<td width="435"> <input name="remark.authorEmail" type="text" size="20" class="inputStyle" maxlength="40"></td>');
document.write('</tr><tr><td>主 页:</td>');
document.write('<td colspan="3"> <input name="remark.authorURL" type="text" class="inputStyle" value="HTTP://" size="63" maxlength="100"></td></tr>');
}else{
document.write('<input type="hidden" name="remark.authorNameFUI" value="Blogchina网友">');
}
</SCRIPT>
<TBODY>
<TR>
<TD width=70>验证码:</TD>
<TD><INPUT class=inputStyle maxLength=4 name=validateCode></TD>
<TD> <IMG src="一个简单的演示用的Linux字符设备驱动程序.files/getValidateImg.gif"
border=0></TD></TR>
<TR align=left>
<TD colSpan=4>评论内容:<BR><TEXTAREA class=textStyle id=remark name=remark.remarkFUI rows=8 cols=60> </TEXTAREA>
</TD></TR>
<TR align=left>
<TD colSpan=4> <INPUT onclick=reply() type=button value=提交>
<INPUT type=reset value=重置> </TD></TR></FORM></TBODY></TABLE></DIV></DIV>
<SCRIPT src="一个简单的演示用的Linux字符设备驱动程序.files/extend3.js"
type=text/javascript></SCRIPT>
<DIV id=footer><A href="http://blog.bokee.com/">2003-2004 BOKEE.COM All rights
reserved</A><BR><A href="http://www.blogdriver.com/">Powered by BlogDriver
2.1</A> </DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -