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

📄 1036.html

📁 著名的linux英雄站点的文档打包
💻 HTML
📖 第 1 页 / 共 4 页
字号:
首先,文件系统通过调用ll_rw_block发出块读写命令,读写请求管理层接到命令后,向系统申请一块读写请求缓冲区,在填写完请求信息后,请求进入设备的读写请求队列等候处理。如果队列是空的,则请求立即得到处理,否则由系统负责任务调度,唤醒请求处理。在请求处理过程中,系统向I/O空间发出读写指令返回。当读写完毕后,通过中断通知系统,同时调用与设备相应的读写中断响应函数。<br>
<br>
<br>
<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
添加字符设备<br>
<br>
五. 添加一个字符设备<br>
作为对linux设备管理的分析的总结,我们介绍一下如何添加一个设备,首先介绍如何添加一个字符设备。在后面的文章中,我们将新添加的设备称为新设备,说明以我们实现的虚拟的字符设备为例,步骤基本如下:<br>
1. 确定设备的设备名称和主设备号:<br>
我们必须找一个还没有被使用的主设备号,分配给自己的字符设备。假设主设备号为30(在2.0.34的内核中还没有以30作为主设备号的字符设备)。<br>
<br>
2. 确定编写需要的file_operations中的操作函数,包括:<br>
static int my_open(struct inode * inode,struct file * file)<br>
//通过宏指令MINOR()提取inode参数的I_rdev字段,确定辅助设备号,然后检查相应的读写忙标志,看新设备是否已经打开。如果是,返回错误信息;<br>
否则置读写忙标志为true,阻止再次打开新设备。<br>
static void my_release(struct inode * inode,struct file * file)<br>
//同my_open类似,只是置读写忙标志为false,允许再次打开新设备。<br>
static int my _write(struct inode * inode,struct file * file,const char * bu<br>
ffer,int count)<br>
//用于对该设备的写<br>
static int my _read(struct inode * inode , struct file * file,char * buffer,<br>
int count)<br>
//用于对该设备的读<br>
static int my_ioctl(struct inode * inode, struct file * file,<br>
unsigned int cmd, unsigned long arg)<br>
//用于传送特殊的控制信息给设备驱动程序,或者长设备驱动程序取得状态信息,在我们实现的虚拟字符设备中,这个函数的功能是用来打开和关闭跟踪功能。<br>
<br>
3. 确定编写需要的初始化函数:<br>
void my_init(void)<br>
//首先需要将上述的file_operations中的操作函数的地址赋给某个file_operations的结构变量my_fops中的相应域;然后调用标准内核函数登记该设备:register_chrdev(30,"mychd",&my_fops);最后对必要的变量(例如读写忙标志、跟踪标志等)赋初值。<br>
<br>
4. 在drivers/char/mem.c中添加相应语句;<br>
在chr_dev_init函数之前添加drgn_init的原型说明:<br>
void my_init (void);<br>
在chr_dev_init函数的return语句之前添加以下语句:<br>
my_init (); //用于在字符设备初始化时初始化新设备<br>
<br>
5. 修改drivers/char/Makefile;<br>
假设我们把所以必要的函数写mychd.c中,则找到"L_OBJS := tty_io.o n_tty.o con<br>
sole.o "行,将"mychd.o"加到其中。<br>
6. 将该设备私有的*.c,*.h复制到目录drivers/char下。<br>
7. 用命令:make clean;make dep;make zImage重新编译内核。<br>
8. 用mknod命令在目录/dev下建立相应主设备号的用于读写的特殊文件。<br>
完成了上述步骤,你在linux环境下编程时就可以使用新设备了。<br>
<br>
<br>
<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
添加块设备<br>
<br>
六. 添加一个块设备<br>
接下来我们将介绍如何添加一个块设备。在后面的文章中,我们将新添加的块设备称为新设备,块设备的添加过程和字符设备有相似之处,我们将主要介绍其不同点,步骤基本如下:<br>
1. 确定设备的设备名称和主设备号<br>
我们必须找一个还没有被使用的主设备号,分配给自己的新设备。假设主设备号为30(在2.0.34的内核中还没有以30作为主设备号的块设备),则需要在include/linux/major.h中加入如下句:<br>
#define MY_MAJOR 30<br>
这样我们可以通过MY_MAJOR来确定设备为新设备,保证通用性。<br>
<br>
2. 确定编写需要的file_operations中的操作函数:<br>
static int my_open(struct inode * inode,struct file * file)<br>
static void my_release(struct inode * inode,struct file * file)<br>
static int my_ioctl(struct inode * inode, struct file * file,<br>
unsigned int cmd, unsigned long arg)<br>
由于使用了高速缓存,块设备驱动程序就不需要包含自己的read()、write()和fsync()函数,但必须使用自己的open()、 release()和 ioctl()函数,这些函数的作用和字符设备的相应函数类似。<br>
<br>
3. 确定编写需要的输入/输出函数:<br>
static int my _read(void) //正确处理时返回值为1,错误时返回值为0<br>
static int my _write(void) //正确处理时返回值为1,错误时返回值为0<br>
值得注意的是这两个函数和字符设备中的my read()、mywrite()函数不同:<br>
<br>
参数不同:字符设备中的函数是带参数的,用于对其工作空间(也可以看成是简单的缓冲区)中的一定长度(长度也是参数传递的)的字符进行读写;而块设备的函数是没有参数的,它通过当前请求中的信息访问高速缓存中的相应的块,因此不需要参数输入。<br>
调用形式不同:字符设备中的函数地址是存放在file_operations中的,在对字符设备进行读写时就调用了;而块设备的读写函数是在需要进行实际I/O时在request中调用。这在后面可以看到。<br>
<br>
4. 确定编写需要的请求处理函数:<br>
static void my_request(void)<br>
在块设备驱动程序中,不带中断服务子程序的请求处理函数是简单的,典型的格式如下<br>
:<br>
static void my_request(void)<br>
{<br>
loop:<br>
INIT_REQUEST;<br>
<br>
if (MINOR(CURRENT-&gt;dev)&gt;MY_MINOR_MAX)<br>
{<br>
end_request(0);<br>
goto loop;<br>
}<br>
<br>
if (CURRENT -&gt;cmd==READ)<br>
//CUREENT是指向请求队列头的request结构指针<br>
{<br>
end_request(my_read()); //my_read()在前面已经定义<br>
goto loop;<br>
}<br>
<br>
if (CURRENT -&gt;cmd==WRITE)<br>
{<br>
end_request(my_write()); //my_write()在前面已经定义<br>
goto loop;<br>
}<br>
<br>
end_request(0);<br>
goto loop;<br>
}<br>
实际上,一个真正的块设备一般不可能没有中断服务子程序,另外设备驱动程序是在系统调用中被调用的,这时由内核程序控制CPU,因此不能抢占,只能自愿放弃;因此驱动程序必须调用sleep_on()函数,释放对CPU的占用;在中断服务子程序将所需的数据复制到内核内存后,再由它来发出wake_up()调用,<br>
<br>
5. 如果需要,编写中断服务子程序<br>
实际上,一个真正的块设备一般不可能没有中断服务子程序,另外设备驱动程序是在系统调用中被调用的,这时由内核程序控制CPU,因此不能抢占,只能自愿放弃;因此驱动程序必须调用sleep_on()函数,释放对CPU的占用;在中断服务子程序将所需的数据复制到内核内存后,再由它来发出wake_up()调用。<br>
另外两段中断服务子程序都要访问和修改特定的内核数据结构时,必须要仔细协调,以防止出现灾难性的后果。<br>
<br>
首先,在必要时可以禁止中断,这可以通过sti()和cli()来允许和禁止中断请求。<br>
其次,修改特定的内核数据结构的程序段要尽可能的短,使中断不至于延时过长。含有中断服务子程序的块设备驱动程序的编写相对比较复杂,我们还没有完全实现,主要问题是在中断处理之间的协调。因为这些程序是要加入内核的,系统默认为你是完全正确的,如果引起循环或者中断长时间不响应,结果非常严重。我们正在努力实现这一程序。<br>
<br>
6. 确定编写需要的初始化函数:<br>
void my_init(void)<br>
需要将的file_operations中的操作函数的地址赋给某个file_operations的结构变量my_fops中的相应域;一个典型的形式是:<br>
struct file_operations my_fops=<br>
{<br>
0,<br>
block_read,<br>
block_write,<br>
0,<br>
0,<br>
my_ioctl,<br>
0,<br>
my_open,<br>
my_release,<br>
block_fsync,<br>
0,<br>
0,<br>
0,<br>
}<br>
my_init中需要作的工作有:<br>
<br>
首先调用标准内核函数登记该设备:<br>
register_chrdev(MY_MOJOR,"my--bdev",&my_fops);<br>
将request()函数的地址告诉内核:<br>
blk_dev[MY_MAJOR].request_fn=DEVICE_REQUEST;<br>
DEVICE_REQUEST是请求处理函数的地址,它的定义将在稍后可以看到。<br>
告诉新设备的高速缓存的数据块的块大小:<br>
my_block_size=512; //也可以是1024等等<br>
blksize_size[MY_MAJOR]=& my_block_size;<br>
为了系统在初始化时能够对新设备进行初始化,需要在blk_dev_init()中添加一行代码,可以插在blk_dev_init()中return 0的前面,格式为:<br>
my_init();<br>
<br>
7. 在include/linux/blk.h中添加相应语句;<br>
到目前为止,除了DEVICE_REQUEST符合外,还没有告诉内核到那里去找你的request()函数,为此需要将一些宏定义加到blk.h中。在blk.h中找到类似的一行:<br>
#endif /*MAJOR_NR==whatever */<br>
在这行前面加入如下宏定义:<br>
#elif (MAJOR_NR==whatever)<br>
<br>
static void my_request(void);<br>
#define DEVICE_NAME "MY_BLK_DEV" //驱动程序名称<br>
#define DEVICE_REQUEST my_request //request()函数指针<br>
#define DEVIEC_NR(device) (MINOR(device)) //计算实际设备号<br>
#define DEVIEC_ON(device) //用于需要打开的设备<br>
#define DEVIEC_OFF(device) //用于需要关闭的设备<br>
8. 修改drivers/block/Makefile;<br>
假设我们把所以必要的函数写mybd.c中,则找到"L_OBJS := tty_io.o n_tty.o cons<br>
ole.o "行,将"mybd.o"加到其中。<br>
9. 将该设备私有的*.c,*.h复制到目录drivers/block下。<br>
10. 用命令:make clean;make dep;make zImage重新编译内核。<br>
11. 用mknod命令在目录/dev下建立相应主设备号的用于读写的特殊文件。<br>
完成了上述步骤,你在linux环境下编程时就可以使用新设备了。<br>
<br>
<br>
<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
一个虚拟的字符设备驱动程序<br>
<br>
七. 一个虚拟的字符设备驱动程序<br>
以下是一个虚拟的字符设备驱动程序,该程序是我和潘刚同学的试验结果,本来我们还打算写一个虚拟的块设备驱动程序,由于时间关系,没有能够完全明白中断中断服务子程序的编写方法,因此没有没有能够实现一个可以所有的虚拟的块设备,非常遗憾。不过主要步骤已经在上文中进行了介绍,我想再有一段时间应该能够完成,到时候一定交给李老师看一下。<br>
虚拟的字符设备驱动程序如下,在潘刚同学的试验报告中也有介绍:<br>
/* drgn.h */<br>
#ifdef KERNEL<br>
#define TRACE_TXT(text) {if(drgn_trace) {console_print(text);console_print("<br>
");}}<br>
#define TRACE_CHR(chr) {if(drgn_trace) console_print(chr);}<br>
#define DRGN_READ 1<br>
#define DRGN_WRITE 0<br>
#endif<br>
#define FALSE 0<br>
#define TRUE 1<br>
#define MAX_BUF 120<br>
#define DRGN_TRON (('M' &lt;&lt; icon_cool.gif|0x01)<br>
#define DRGN_TROFF (('M' &lt;&lt; icon_cool.gif|0x02)<br>
struct drgn_buf<br>
{<br>
int buf_size;<br>
char buffer[MAX_BUF];<br>
struct drgn_buf *link;<br>
};<br>
/* drgn.c */<br>
#define KERNEL<br>
#include &lt;linux/kernel.h&gt;<br>

⌨️ 快捷键说明

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