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

📄 文件和设备编程.htm

📁 介绍linux下文件和设备编程
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<P>清单 1:
<P>&nbsp;&nbsp;&nbsp; void main(void) {<BR>&nbsp;&nbsp;&nbsp; char 
buf[100];<BR>&nbsp;&nbsp;&nbsp; int num;
<P>&nbsp;&nbsp;&nbsp; num = read(0, buf, sizeof(buf));<BR>&nbsp;&nbsp;&nbsp; 
write(1, "I got: ", 7); /* Length of "I got: " is 7! */<BR>&nbsp;&nbsp;&nbsp; 
write(1, buf, num);<BR>&nbsp;&nbsp;&nbsp; }
<P>&nbsp;&nbsp;&nbsp; 关于这个处理有两个值得注意的问题。首先,我们要求 read() 返回 100 
个字符,但如果我们运行这个程序,只有在用户按下了 "enter" 
键以后才能获得输入。许多文件操作都根据最佳效果工作:它们尝试返回程序要求的所有信息,但只有部分能够成功。缺省情况下,终端配置成一旦存在 "\n" 
或新行符(通过按 "enter" 键产生)时,就从 read() 
调用返回。这实际上非常方便,因为大多数用户都希望程序无论如何都是面向行的。但常规数据文件并非如此,如果依靠它就可能产生不可预料的结果。
<P>&nbsp;&nbsp;&nbsp; 另一个要注意的问题是我们不必在显示输出后写一个 \n。read() 调用给了我们来自用户的 \n,只将那个 \n 
通过 write() 写回标准输出。如果您希望在没有新行符的情况下看到发生的事件,尝试将最后一行改为
<P>write(1, buf, num - 1);
<P>&nbsp;&nbsp;&nbsp; 有关这个简单示例的最后一点:buf 绝对不包含实际的 C 字符串。C 字符串由标记字符串结束的单一 \0 
字符终止。因为 read() 不将 \0 添加到缓冲区的结尾,在 read() 上使用 strlen()(或任何其它 C 
字符串函数)将可能铸成大错!这种行为可以让 read() 和 write() 对包括 \0 字符的数据处理,而这对于一般字符串函数来说是不可能的。
<P>&nbsp;&nbsp;&nbsp; read() 和 write() 系统调用可以对绝大多数文件起作用。但它们不对目录起作用,目录应该通过特殊函数(例如 
readdir())来访问。另外,read() 和 write() 对于某些类型的套接字也不起作用。
<P>&nbsp;&nbsp;&nbsp; 某些文件,例如常规文件和块设备文件,使用文件指针的概念。它指定在文件中,下一个 read() 调用从哪里读取,下一个 
write() 调用从哪里写入。read() 或 write() 
后,文件指针随着已处理的字符数(在内部,通过内核)增加。这样,使用单一循环就可以方便地读取文件中的所有数据。清单 2 就是示例:
<P>清单 2:
<P>&nbsp;&nbsp;&nbsp; char buffer[1024];<BR>&nbsp;&nbsp;&nbsp; while ((num = 
read(0, buffer, 1024))) {<BR>&nbsp;&nbsp;&nbsp; printf("got some 
data\n");<BR>&nbsp;&nbsp;&nbsp; }
<P>
<P><BR>&nbsp;&nbsp;&nbsp; 
这个循环将读取标准输入上的所有数据,自动在每次读取后增加内核的内部文件指针。当文件指针处于文件结尾时,read() 将返回 0 
并退出循环。某些文件(例如字符设备 -- 终端就是很好的一例)本身没有文件指针,所以对于这一点,该程序将继续运行,直到用户提供文件结束标记(通过按 
"Ctrl-D")为止。
<P>&nbsp;&nbsp;&nbsp; 
到现在为止,我们已经知道如何读写文件了,下一步要学习如何打开一个新文件。打开不同类型的文件有不同方法;我们将在这里讨论的方法是通过路径名打开在文件系统中表示的文件;包括常规文件、目录、设备文件和指定的管道。某些套接字文件有路径名,那些必须通过替代方法打开。
<P>&nbsp;&nbsp;&nbsp; 撇开放弃权利的,open() 系统调用可以让程序访问大多数系统文件。open() 
是个不寻常的系统调用,因为它获取两个或者三个自变量:
<P>int open(const char *<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
pathname,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int flags);
<P>或者,<BR>int open(const char 
*<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
pathname,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int 
flags,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int perm);
<P>&nbsp;&nbsp;&nbsp; 
第一种形式更普遍一些;它打开一个已存在的文件。第二种格式应该在需要创建文件时使用。第三个自变量指定应该给予新文件的访问权限。
<P>&nbsp;&nbsp;&nbsp; open() 的第一个参数是以正常 C 字符串表示的全路径名(即以 \0 
终止)。第二个参数指定文件应该如何打开,并包括逻辑“与”操作的一个或多个以下标志:
<P>&nbsp;&nbsp;&nbsp; O_RDONLY:文件可以只读<BR>&nbsp;&nbsp;&nbsp; 
O_RDWR:文件可以读写<BR>&nbsp;&nbsp;&nbsp; O_APPEND:文件可以读或附加<BR>&nbsp;&nbsp;&nbsp; 
O_CREAT:如果文件还不存在则应该创建<BR>&nbsp;&nbsp;&nbsp; O_EXCL:如果文件已存在,失败而不是创建它(只应该使用 
O_CREAT)<BR>&nbsp;&nbsp;&nbsp; O_TRUNC:如果文件已存在,从中除去所有数据(与创建新文件类似)
<P>&nbsp;&nbsp;&nbsp; open() 的第三个参数只在使用 O_CREAT 时需要;它指定了以数字表示的文件许可权(格式与 chown 
命令的数值许可权自变量的格式相同。为 open() 指定的许可权受用户的 umask 
影响,后者允许用户指定一系列新文件应该获得的缺省许可权。大多数创建文件的程序都使用第三个自变量 0666 调用 open(),可以让用户通过 umask 
来控制程序的缺省许可权。(大多数 shell 的 umask 命令都可以更改它。)
<P>&nbsp;&nbsp;&nbsp; 例如,清单 3 显示了如何为进行读写打开文件、如果它不存在则创建,以及废弃其中的数据:
<P>清单 3:
<P>int fd;<BR>fd = open("myfile", O_RDWR | O_CREAT | O_TRUNC, 0666)<BR>if (fd 
&lt; 0) {<BR>&nbsp;&nbsp; /* Some error occurred */<BR>&nbsp;&nbsp; /* ... 
*/<BR>}
<P>&nbsp;&nbsp;&nbsp; open() 返回引用文件的文件描述符。回忆一下,文件描述符总是 &gt;= 0。如果 open() 
返回了一个负值,就表示发生了错误,全局变量错误号包含了描述问题的 Unix 错误代码。open() 总尽量返回最小数,如果没有使用文件描述符 0,open() 
将总返回 0。
<P>&nbsp;&nbsp;&nbsp; 进程带文件结束时,它应该通过 close() 系统调用关闭它,该系统调用的格式为:
<P>int close(int fd);
<P>&nbsp;&nbsp;&nbsp; close 的文件描述符是传递给 close() 的唯一自变量,在成功情况下返回 0。尽管 close() 
失败的情况比较少见,但如果文件描述符引用的是远程服务器上的文件,系统无法正确清空它的高速缓存,close() 
就可能真的失败。进程终止时,内核自动关闭所有还在打开的文件。
<P>&nbsp;&nbsp;&nbsp; 
最后的一个常见文件操作是移动文件指针。这(自然)只对带文件指针的文件有意义,如果尝试在不恰当的文件上尝试该操作就会返回错误。lseek() 
系统调用用于以下目的:
<P>off_t lseek(int fd, off_t pos, int whence);
<P>&nbsp;&nbsp;&nbsp; off_t 类型是表达 longint (long 就是 lseek 中 "l" 
的来历)的一种别致方法。lseek() 返回相对于文件开始处文件指针的最终位置,如果有错误,则返回 
-1。这个系统调用希望被移动的文件指针所属的文件描述符作为第一个自变量,将它移动到文件中的位置作为第二个自变量。最后一个自变量描述文件指针的移动方式。
<P>&nbsp;&nbsp;&nbsp; SEEK_SET 将它移动到从文件开始算起的 pos 字节。<BR>&nbsp;&nbsp;&nbsp; 
SEEK_END 将它移动到从文件结尾算起的 pos 字节。<BR>&nbsp;&nbsp;&nbsp; SEEK_CUR 从它当前位置开始向文件结尾移动 
pos 字节。
<P>&nbsp;&nbsp;&nbsp; open()、close()、write()、read() 和 lseek() 的组合为 Linux 
提供了基本的文件访问 API。虽然还有许多其它操纵文件的函数,但这里描述的是最常用的。
<P>&nbsp;&nbsp;&nbsp; 大多数程序员都使用熟悉的 ANSI C 库文件函数,例如 fopen() 和 
fread(),而不是在此描述的低级系统调用。可以预见到,fopen() 和 fread() 
是在用户级别库中这些系统调用的基础上实现的。仍然会经常看到低级系统调用的使用,特别是在更复杂的程序中。通过熟悉这些例程和接口,您就可以成为一个真正的 Unix 
黑客了。
<P>关于作者<BR>&nbsp;&nbsp;&nbsp; Erik Troan 是 Red Hat Software 的开发者,Linux 
Application Development 一书的作者之一。可以通过 ewt@redhat.com 与他联系。
<P><BR>
<CENTER><A 
href="file:///E:/linux资料/linux笔记及源码/joyfire-0206.htm/system/10.html#Content">[目录]</A></CENTER>
<HR>
<BR><A id=I320 name=I320></A>
<CENTER><B><FONT size=+2>网卡驱动编写</FONT></B></CENTER><BR>&nbsp;&nbsp;&nbsp; 
工作需要写了我们公司一块网卡的Linux驱动程序。经历一个从无到有的过程,深感技术交流的重要。Linux作为挑战微软垄断的强有力武器,日益受到大家的喜爱。真希望她能在中国迅速成长。把程序文档贴出来,希望和大家探讨Linux技术和应用,促进Linux在中国的普及。<BR>&nbsp;&nbsp;&nbsp; 
本文可随意转载,但请不要在盈利性出版物上刊登。
<P>------------------ Linux操作系统网络驱动程序编写 -------------------<BR>------------ 
Contact the author by mailto:bordi@bordi.dhs.org ------
<P>Linux操作系统网络驱动程序编写
<P>一.Linux系统设备驱动程序概述<BR>&nbsp; 1.1 Linux设备驱动程序分类<BR>&nbsp; 1.2 
编写驱动程序的一些基本概念<BR>二.Linux系统网络设备驱动程序<BR>&nbsp; 2.1 网络驱动程序的结构<BR>&nbsp; 2.2 
网络驱动程序的基本方法<BR>&nbsp; 2.3 网络驱动程序中用到的数据结构<BR>&nbsp; 2.4 
常用的系统支持<BR>三.编写Linux网络驱动程序中可能遇到的问题<BR>&nbsp; 3.1 中断共享<BR>&nbsp; 3.2 
硬件发送忙时的处理<BR>&nbsp; 3.3 流量控制(flow control)<BR>&nbsp; 3.4 调试<BR>四.进一步的阅读<BR>五.杂项 
<CENTER><A 
href="file:///E:/linux资料/linux笔记及源码/joyfire-0206.htm/system/10.html#Content">[目录]</A></CENTER>
<HR>
<BR><A id=I321 name=I321></A>
<CENTER><B><FONT size=+2>概述</FONT></B></CENTER><BR>一.Linux系统设备驱动程序概述<BR>1.1 
Linux设备驱动程序分类<BR>&nbsp;&nbsp;&nbsp; 
Linux设备驱动程序在Linux的内核源代码中占有很大的比例,源代码的长度日益增加,主要是驱动程序的增加。在Linux内核的不断升级过程中,驱动程序的结构还是相对稳定。在2.0.xx到2.2.xx的变动里,驱动程序的编写做了一些改变,但是从2.0.xx的驱动到2.2.xx的移植只需做少量的工作。
<P>&nbsp;&nbsp;&nbsp; Linux系统的设备分为字符设备(char device),块设备(block 
device)和网络设备(network 
device)三种。字符设备是指存取时没有缓存的设备。块设备的读写都有缓存来支持,并且块设备必须能够随机存取(random 
access),字符设备则没有这个要求。典型的字符设备包括鼠标,键盘,串行口等。块设备主要包括硬盘软盘设备,CD-ROM等。一个文件系统要安装进入操作系统必须在块设备上。
<P>&nbsp;&nbsp;&nbsp; 网络设备在Linux里做专门的处理。Linux的网络系统主要是基于BSD 
unix的socket机制。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。
<P>1.2 编写驱动程序的一些基本概念<BR>&nbsp;&nbsp;&nbsp; 
无论是什么操作系统的驱动程序,都有一些通用的概念。操作系统提供给驱动程序的支持也大致相同。下面简单介绍一下网络设备驱动程序的一些基本要求。
<P>1.2.1 发送和接收<BR>&nbsp;&nbsp;&nbsp; 
这是一个网络设备最基本的功能。一块网卡所做的无非就是收发工作。所以驱动程序里要告诉系统你的发送函数在哪里,系统在有数据要发送时就会调用你的发送程序。还有驱动程序由于是直接操纵硬件的,所以网络硬件有数据收到最先能得到这个数据的也就是驱动程序,它负责把这些原始数据进行必要的处理然后送给系统。这里,操作系统必须要提供两个机制,一个是找到驱动程序的发送函数,一个是驱动程序把收到的数据送给系统。
<P>1.2.2 中断<BR>&nbsp;&nbsp;&nbsp; 
中断在现代计算机结构中有重要的地位。操作系统必须提供驱动程序响应中断的能力。一般是把一个中断处理程序注册到系统中去。操作系统在硬件中断发生后调用驱动程序的处理程序。Linux支持中断的共享,即多个设备共享一个中断。
<P>1.2.3 时钟<BR>&nbsp;&nbsp;&nbsp; 
在实现驱动程序时,很多地方会用到时钟。如某些协议里的超时处理,没有中断机制的硬件的轮询等。操作系统应为驱动程序提供定时机制。一般是在预定的时间过了以后回调注册的时钟函数。在网络驱动程序中,如果硬件没有中断功能,定时器可以提供轮询(poll)方式对硬件进行存取。或者是实现某些协议时需要的超时重传等。
<P>
<P><BR>
<CENTER><A 
href="file:///E:/linux资料/linux笔记及源码/joyfire-0206.htm/system/10.html#Content">[目录]</A></CENTER>
<HR>
<BR><A id=I322 name=I322></A>
<CENTER><B><FONT size=+2>设备驱动</FONT></B></CENTER><BR>二.Linux系统网络设备驱动程序
<P>2.1 网络驱动程序的结构<BR>&nbsp;&nbsp;&nbsp; 
所有的Linux网络驱动程序遵循通用的接口。设计时采用的是面向对象的方法。一个设备就是一个对象(device 
结构),它内部有自己的数据和方法。每一个设备的方法被调用时的第一个参数都是这个设备对象本身。这样这个方法就可以存取自身的数据(类似面向对象程序设计时的this引用)。<BR>&nbsp;&nbsp;&nbsp; 
一个网络设备最基本的方法有初始化、发送和接收。
<P>&nbsp;&nbsp;&nbsp;&nbsp; 
-------------------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
---------------------<BR>&nbsp;&nbsp;&nbsp; |deliver packets&nbsp;&nbsp;&nbsp; 
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |receive packets 
queue|<BR>&nbsp;&nbsp;&nbsp; |(dev_queue_xmit()) 
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
|them(netif_rx())&nbsp;&nbsp;&nbsp;&nbsp; |<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
-------------------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
---------------------<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

⌨️ 快捷键说明

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