?? 一個簡單的演示用的linux字符設備驅動程序.htm
字號:
<!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>
<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", &char8139_fops);<BR>if(result<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 + -