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

📄 5.html

📁 linux操作系统内核编程-----LINUX系统开发非常好的资料
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<html><head><title>黄金书屋</title><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><link rel="stylesheet" href="/goldnets.css"></head><body bgcolor="#E4EBF1"><center><a href="http://ad.myrice.com/RealMedia/ads/click_nx.ads/goldnets.myrice.com/banner1@Top" target=_blanck ><script language=JavaScript><!---todayd = new Date();var seconds = todayd.getTime();document.write("<img src=\"http://ad.myrice.com/RealMedia/ads/adstream_nx.ads/goldnets.myrice.com/banner1@Top?dd=seconds\" border=0 width=468 height=60>");//--></script></a></center><br><table width="756" border="0" cellspacing="0" cellpadding="0" align="center" bgcolor="#E4EBF1">  <tr>    <td colspan="2" valign="top" align="center">      <div align="center">        <table width="100%" border="0" cellspacing="0" cellpadding="0" height="52">          <tr>            <td valign="top"><br>              <div align="center">                <table width="100%" border="0" cellspacing="0" cellpadding="0">                  <tr>                    <td valign="bottom">                      <table width="100%" border="0" cellspacing="0" cellpadding="0">                        <tr>                          <td><a href="/index.html">首页</a>&gt;&gt; <font color="#CC0000"><a href="/book/152/1015178.html">Linux内核编程</a></font></td>                          <td width="22%"> <a href="/index.html">[ 点此回首页 ]</a></td>                        </tr>                        <tr>                          <td colspan="2"><img src="/image/1x1.gif" width="1" height="2"></td>                        </tr>                        <tr bgcolor="#FFCC00">                          <td colspan="2"><img src="/image/1x1.gif" width="1" height="1"></td>                        </tr>                        <tr>                          <td colspan="2"><img src="/image/1x1.gif" width="1" height="6"></td>                        </tr>                      </table>                    </td>                  </tr>                </table>                <br>                <table width="590" border="0" cellspacing="0" cellpadding="0">                  <tr>                    <td><center><a href='4.html'>上一页 </a>||<a href='6.html'>下一页</a></center><br><hr><div style=font-size:12pt><pre>                             2.字符设备文件
那么,现在我们是原始级的内核程序员,我们知道如何写不做任何事情的内核模块。
我们为自己而骄傲并且高昂起头来。但是不知何故我们感觉到缺了什么东西。患有精神紧张
症的模块不是那么有意义。
内核模块同进程对话有两种主要途径。一种是通过设备文件(比如/dev 目录中的文件),
另一种是使用proc文件系统。我们把一些东西写入内核的一个主要原因就是支持一些硬件
设备,所以我们从设备文件开始。	
设备文件的最初目的是允许进程同内核中的设备驱动通信,并且通过它们和物理设备
通信(modem,终端,等等)。这种方法的实现如下:
每个设备驱动都对应着一定类型的硬件设备,并且被赋予一个主码。设备驱动的列表
和它们的主码可以在in/proc/devices中找到。每个设备驱动管理下的物理设备也被赋予一个
从码。无论这些设备是否真的安装,在/dev目录中都将有一个文件,称作设备文件,对应着
每一个设备。
例如,如果你进行ls –l /dev/hd[ab] *操作,你将看见可能联结到某台机器上的所有的IDE
硬盘分区。注意它们都使用了同一个主码,3,但是从码却互不相同。(声明:这是在PC结
构上的情况,我不知道在其他结构上运行的linux是否如此。)
在系统安装时,所有设备文件在mknod命令下被创建。它们必须创建在/dev目录下没
有技术上的原因,只是一种使用上的便利。如果是为测试目的而创建的设备文件,比如我们
这里的练习,可能放在你编译内核模块的的目录下更加合适。
设备可以被分成两类:字符设备和块设备。它们的区别是块设备有一个用于请求的缓
冲区,所以它们可以选择用什么样的顺序来响应它们。这对于存储设备是非常重要的,读取
相邻的扇区比互相远离的分区速度会快得多。另一个区别是块设备只能按块(块大小对应不
同设备而变化)接受输入和返回输出,而字符设备却按照它们能接受的最少字节块来接受输
入。大部分设备是字符设备,因为它们不需要这种类型的缓冲。你可以通过观看ls -l命令的
输出中的第一个字符而知道一个设备文件是块设备还是字符设备。如果是b就是块设备,如
果是c就是字符设备。
这个模块可以被分成两部分:模块部分和设备及设备驱动部分。Init_module函数调用
module_register_chrdev在内核得块设备表里增加设备驱动。同时返回该驱动所使用的主码。
Cleanup_module函数撤销设备的注册。
这些操作(注册和注销)是这两个函数的主要功能。内核中的函数不是象进程一样自
发运行的,而是通过系统调用,或硬件中断或者内核中的其它部分(只要是调用具体的函数)
被进程调用的。所以,当你向内和中增加代码时,你应该把它注册为具体某种事件的句柄,
而当你把它删除的时候,你需要注销这个句柄。
设备驱动完全由四个设备_<action〉函数构成,它们在希望通过有主码的设备文件实现
一些操作时被调用。内核调用它们的途径是通过file_operation结构Fops。此结构在设备被
注册是创建,它包含指向这四个函数的指针。
另一点我们需要记住的是,我们不能允许管理员随心所欲的删除内核模块。这是因为
如果设备文件是被进程打开的,那么我们删除内核模块的时候,要使用这些文件就会导致访
问正常的函数(读/写)所在的内存位置。如果幸运,那里不会有其他代码被装载,我们将
得到一个恶性的错误信息。如果不行,另一个内核模块会被装载到同一个位置,这将意味着
会跳入内核中另一个程序的中间,结果将是不可预料的恶劣。
通常你不希望一个函数做什么事情的时候,会从那个函数返回一个错误码(一个负数)。
但这在cleanup_module中是不可能的,因为它是一个void型的函数。一旦cleanup_module
被调用,这个模块就死掉了。然而有一个计数器记录着有多少个内核模块在使用这个模块,
这个计数器称为索引计数器(/proc/modules中没行的最后一个数字)。如果这个数字不是0,
删除就会失败。模块的索引计数器包含在变量mod_use_count_中。有定义好的处理这个变
量的宏(MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT),所以我们一般使用宏而
不是直接使用变量mod_use_count_,这样在以后实现变化的时候会带来安全性。

ex chardev.c    
 
/* chardev.c 
 * Copyright (C) 1998-1999 by Ori Pomerantz
 * 
 * Create a character device (read only)
 */

/* The necessary header files */

/* Standard in kernel modules */
#include <linux/kernel.h>   /* We\'re doing kernel work */
#include <linux/module.h>   /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif        

/* For character devices */
#include <linux/fs.h>       /* The character device 
                             * definitions are here */
#include <linux/wrapper.h>  /* A wrapper which does 
                             * next to nothing at
                             * at present, but may 
                             * help for compatibility
                             * with future versions 
                             * of Linux */


/* In 2.2.3 /usr/include/linux/version.h includes 
 * a macro for this, but 2.0.35 doesn\'t - so I add 
 * it here if necessary. */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif


/* Conditional compilation. LINUX_VERSION_CODE is 
 * the code (as per KERNEL_VERSION) of this version. */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)
#include <asm/uaccess.h>  /* for put_user */
#endif

			     

#define SUCCESS 0


/* Device Declarations **************************** */

/* The name for our device, as it will appear 
 * in /proc/devices */
#define DEVICE_NAME \"char_dev\"


/* The maximum length of the message from the device */
#define BUF_LEN 80

/* Is the device open right now? Used to prevent 
 * concurent access into the same device */
static int Device_Open = 0;

/* The message the device will give when asked */
static char Message[BUF_LEN];

/* How far did the process reading the message 
 * get? Useful if the message is larger than the size 
 * of the buffer we get to fill in device_read. */
static char *Message_Ptr;


/* This function is called whenever a process 
 * attempts to open the device file */
static int device_open(struct inode *inode, 
		       struct file *file)
{
  static int counter = 0;

#ifdef DEBUG
  printk (\"device_open(%p,%p)\\n\", inode, file);
#endif

  /* This is how you get the minor device number in 
   * case you have more than one physical device using 
   * the driver. */
  printk(\"Device: %d.%d\\n\", 
	 inode->i_rdev >> 8, inode->i_rdev & 0xFF);

  /* We don\'t want to talk to two processes at the 
   * same time */
  if (Device_Open)
    return -EBUSY;

  /* If this was a process, we would have had to 
* be more careful here.
  *
*In the case of processes, the danger would be 
*that one process might have check Device_Open 
*and then be replaced by the schedualer by another 
*process which runs this function. Then, when 
*the first process was back on the CPU, it would assume 
*the device is still not open. 
* However, Linux guarantees that a process won\'t 
* be replaced while it is running in kernel context. 
   *
* In the case of SMP, one CPU might increment 
*Device_Open while another CPU is here, right after the check. 
*However, in version 2.0 of the kernel this is not a problem 
*because there\'s a lock to guarantee only one CPU will 
*be kernel module at the same time. 
*This is bad in  terms of  performance, so version 2.2 changed it. 
*Unfortunately, I don\'t have access to an SMP box 
*to check how it works with SMP.
   */

  Device_Open++;

  /* Initialize the message. */
  sprintf(Message, 
    \"If I told you once, I told you %d times - %s\",
    counter++,
    \"Hello, world\\n\");
  /* The only reason we\'re allowed to do this sprintf 
   * is because the maximum length of the message 
   * (assuming 32 bit integers - up to 10 digits
   * with the minus sign) is less than BUF_LEN, which 

⌨️ 快捷键说明

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