⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 一个简单的演示用的linux字符设备驱动程序.htm

📁 一个嵌入式linux字符驱动的例子。适合于初学者。
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0041)http://linuxipy.blogchina.com/507920.html -->
<HTML><HEAD><TITLE>一个简单的演示用的Linux字符设备驱动程序--BlackMagic Workshop</TITLE>
<META http-equiv=Content-Type content="text/html; charset=GBK">
<META http-equiv=Pragma content=no-cache>
<META http-equiv=Cache-Control content=no-cache>
<META http-equiv=Expires content=0>
<META 
content="IBM developerWorks Linux 专题一个简单的演示用的Linux字符设备驱动程序linux下S3C44B0X Jtag工具(支持cfly.org Jtag cable)  博客 博客中国 博客动力 blog blogdriver blogger 中国" 
name=description>
<META 
content="BlackMagic Workshop IBM developerWorks Linux 专题一个简单的演示用的Linux字符设备驱动程序linux下S3C44B0X Jtag工具(支持cfly.org Jtag cable) 博客 博客中国 博客动力 blog blogdriver blogger 中国" 
name=keywords><LINK href="一个简单的演示用的Linux字符设备驱动程序.files/diary.css" type=text/css 
rel=stylesheet>
<SCRIPT language=JavaScript src="一个简单的演示用的Linux字符设备驱动程序.files/UBB.js"></SCRIPT>

<SCRIPT src="一个简单的演示用的Linux字符设备驱动程序.files/blog.js" 
type=text/javascript></SCRIPT>

<META content="MSHTML 6.00.2900.2912" name=GENERATOR></HEAD>
<BODY>
<DIV id=container>
<DIV id=header>
<H1 class=title><A href="http://linuxipy.blogchina.com/index.html">BlackMagic 
Workshop</A></H1></DIV>
<DIV id=category><A title=上一篇 
href="http://linuxipy.blogchina.com/429261.html">IBM developerWorks Linux 
专题</A>- -| <A href="http://linuxipy.blogchina.com/index.html">回首页</A> | <A 
href="http://linuxipy.blogchina.com/catalog_2005.html">2005年索引</A> | - -<A 
title=下一篇 href="http://linuxipy.blogchina.com/3568520.html">linux下S3C44B0X 
Jtag工具(支持cfly.org Jtag cable)</A></DIV>
<DIV class=entity>
<H2 
class=diaryTitle>一个简单的演示用的Linux字符设备驱动程序</H2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

<P>实现如下的功能:<BR>--字符设备驱动程序的结构及驱动程序需要实现的系统调用<BR>--可以使用cat命令或者自编的readtest命令读出"设备"里的内容<BR>--以8139网卡为例,演示了I/O端口和I/O内存的使用<BR>本文中的大部分内容在Linux 
Device 
Driver这本书中都可以找到,<BR>这本书是Linux驱动开发者的唯一圣经。<BR>=======================================================<BR><BR>实现如下的功能:<BR>--字符设备驱动程序的结构及驱动程序需要实现的系统调用<BR>--可以使用cat命令或者自编的readtest命令读出"设备"里的内容<BR>--以8139网卡为例,演示了I/O端口和I/O内存的使用<BR><BR>下载完整程序<STRONG>[char8139.tar.gz]</STRONG>:<BR><A 
href="http://blog.blogchina.com/upload/2005-01-06/20050106234859677220.gz">http://blog.blogchina.com/upload/2005-01-06/20050106234859677220.gz</A><BR><BR>=======================================================<BR>先来看看整个驱动程序的入口,是char8139_init()这个函数<BR>如果不指定MODULE_LICENSE("GPL"), 
在模块插入内核的<BR>时候会出错,因为将非"GPL"的模块插入内核就沾污了内核的<BR>"GPL"属性。<BR>module_init(char8139_init);<BR>module_exit(char8139_exit);<BR><BR>MODULE_LICENSE("GPL");<BR>MODULE_AUTHOR("linuxipy");<BR>MODULE_DESCRIPTION("Wierd 
char device driver for Realtek 8139 
NIC");<BR><BR>接着往下看char8139_init()<BR><BR>static int __init 
char8139_init(void)<BR>{<BR>int result;<BR><BR>PDBG("hello. init.\n");<BR><BR>/* 
register our char device */<BR>result=register_chrdev(char8139_major, 
"char8139", &amp;char8139_fops);<BR>if(result&lt;0)<BR>{<BR>PDBG("Cannot 
allocate major device number!\n");<BR>return result;<BR>}<BR>/* 
register_chrdev() will assign a major device number and return if it called<BR>* 
with "major" parameter set to 0 */<BR>if(char8139_major == 
0)<BR>char8139_major=result;<BR><BR>/* allocate some kernel memory we need 
*/<BR>buffer=(unsigned char*)(kmalloc(CHAR8139_BUFFER_SIZE, 
GFP_KERNEL));<BR>if(!buffer)<BR>{<BR>PDBG("Cannot allocate 
memory!\n");<BR>result= -ENOMEM;<BR>goto init_fail;<BR>}<BR>memset(buffer, 0, 
CHAR8139_BUFFER_SIZE);<BR>p_buf=buffer;<BR><BR>return 0; /* everything's ok 
*/<BR><BR>init_fail:<BR>char8139_exit();<BR>return 
result;<BR>}<BR><BR>这个函数首先的工作就是使用register_chrdev()注册我们的设备的主设备号和系统调用。<BR>系统调用对于字符设备驱动程序来说就是file_operations接口。<BR><BR>我们先来看看char8139_major的定义,<BR>#define 
DEFAULT_MAJOR 145<BR>/* data structure used by our driver */<BR>int 
char8139_major=DEFAULT_MAJOR; /* major device number. if initial value is 
0,<BR>the kernel will dynamically assign a major device<BR>number in 
register_chrdev() */<BR>这里我们指定我们的设备的主设备号是145,你必须找到一个系统中没有用的主设备号,<BR>可以通过"cat 
/proc/devices"命令来查看系统中已经使用的主设备号。<BR><BR>[michael@char8139]$ cat 
/proc/devices<BR>Character devices:<BR>1 mem<BR>2 pty<BR>3 ttyp<BR>4 ttyS<BR>5 
cua<BR>7 vcs<BR>10 misc<BR>14 sound<BR>116 alsa<BR>128 ptm<BR>136 pts<BR>162 
raw<BR>180 usb<BR>195 nvidia<BR>226 drm<BR><BR>Block devices:<BR>2 fd<BR>3 
ide0<BR>22 
ide1<BR>[michael@char8139]$<BR><BR>可见在我的系统中,145还没有被使用。<BR><BR>指定主设备号值得考虑。像上面这样指定一个主设备号显然缺乏灵活性,而且不能保证<BR>一个驱动程序在所有的机器上都能用。可以在调用register_chrdev()时将第一个<BR>参数,即主设备号指定为0,这样register_chrdev()会分配一个空闲的主设备号<BR>作为返回值。 
但是这样也有问题,我们只有在将模块插入内核之后才能得到我们设备<BR>的主设备号(使用 "cat 
/proc/devices"),但是要操作设备需要在系统/dev目录<BR>下建立设备结点,而建立结点时要指定主设备号。当然,你可以写一个脚本来自动完成<BR>这些事情。<BR><BR>总之,作为一个演示,我们还是指定主设备号为145<BR>这样我们可以在/dev/目录下建立几个设备节点。<BR><BR>[root@char8139]$ 
mknod /dev/char8139_0 c 145 0<BR>[root@char8139]$ mknod /dev/char8139_0 c 145 
17<BR>[root@char8139]$ mknod /dev/char8139_0 c 145 36<BR>[root@char8139]$ mknod 
/dev/char8139_0 c 145 145<BR><BR>看一下我们建立的节点<BR><BR>[michael@char8139]$ ll 
/dev/char8139*<BR>crw-r--r-- 1 root root 145, 0 2004-12-26 20:33 
/dev/char8139_0<BR>crw-r--r-- 1 root root 145, 17 2004-12-26 20:34 
/dev/char8139_1<BR>crw-r--r-- 1 root root 145, 36 2004-12-26 20:34 
/dev/char8139_2<BR>crw-r--r-- 1 root root 145, 145 2004-12-26 20:34 
/dev/char8139_3<BR>[michael@char8139]$<BR><BR>我们建立了四个节点,使用了四个次设备号,后面我们会说明次设备号的作用。<BR><BR><BR>再来看看我们的file_operations的定义。这里其实只实现了read(),open(),release()三个<BR>系统调用,ioctl()只是简单返回。更有write()等函数甚至根本没有声明,没有声明的<BR>函数系统可能会调用默认的操作。<BR>struct 
file_operations char8139_fops =<BR>{<BR>owner: THIS_MODULE,<BR>read: 
char8139_read,<BR>ioctl: char8139_ioctl,<BR>open: char8139_open,<BR>release: 
char8139_release,<BR>};<BR><BR>file_operations是每个字符设备驱动程序必须实现的系统调用,当用户对/dev中我们的设备对应<BR>结点进行操作时,linux就会调用我们驱动程序中提供的系统调用。比如用户敲入<BR>"cat 
/dev/char8139_0"命令,想想cat这个应用程序的实现,首先它肯定调用C语言库里的open()<BR>函数去打开/dev/char8139_0这个文件,到了系统这一层,系统会看到/dev/char8139_0不是普通<BR>磁盘文件,而是一个代表字符设备的节点,所以系统会根据/dev/char8139_0的主设备号来查找是不是<BR>已经有驱动程序使用这个相同的主设备号进行了注册,如果有,就调用驱动程序的open()实现。<BR><BR>为什么要这样干?因为要提供抽象,提供统一的接口,别忘了操作系统的作用之一就是这个。因为<BR>我们的设备提供的统一的接口,所以cat这个应用程序使用一般的文件操作就能从我们的设备中读出数据,<BR>而且more, 
less这些应用程序都能从我们的设备中读出数据。<BR><BR>现在来看看我们的设备<BR>#define CHAR8139_BUFFER_SIZE 
2000<BR>unsigned char *buffer=NULL; /* driver data buffer */<BR>unsigned char 
*p_buf;<BR>unsigned int data_size=0;<BR>我们的设备很简单,一个2000字节的缓冲区, 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -