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

📄 linuxdriverdevice.txt

📁 Linux kernel 2.4.18.rmk7 配置系统解析
💻 TXT
📖 第 1 页 / 共 2 页
字号:
INIT_REQUEST;

if (MINOR(CURRENT->dev)>MY_MINOR_MAX)
{
end_request(0);
goto loop;
}

if (CURRENT ->cmd==READ)
//CUREENT是指向请求队列头的request结构指针
{
end_request(my_read()); //my_read()在前面已经定义
goto loop;
}


if (CURRENT ->cmd==WRITE)
{
end_request(my_write()); //my_write()在前面已经定义
goto loop;
}

end_request(0);
goto loop;
}
实际上,一个真正的块设备一般不可能没有中断服务子程序,另外设备驱动程序是在系统调用中被调用的,这时由内核程序控制CPU,因此不能抢占,只能自愿放弃;因此驱动程序必须调用sleep_on()函数,释放对CPU的占用;在中断服务子程序将所需的数据复制到内核内存后,再由它来发出wake_up()调用,

5. 假如需要,编写中断服务子程序
实际上,一个真正的块设备一般不可能没有中断服务子程序,另外设备驱动程序是在系统调用中被调用的,这时由内核程序控制CPU,因此不能抢占,只能自愿放弃;因此驱动程序必须调用sleep_on()函数,释放对CPU的占用;在中断服务子程序将所需的数据复制到内核内存后,再由它来发出wake_up()调用。
另外两段中断服务子程序都要访问和修改特定的内核数据结构时,必须要仔细协调,以防止出现灾难性的后果。

首先,在必要时可以禁止中断,这可以通过sti()和cli()来答应和禁止中断请求。
其次,修改特定的内核数据结构的程序段要尽可能的短,使中断不至于延时过长。含有中断服务子程序的块设备驱动程序的编写相对比较复杂,我们还没有完全实现,主要问题是在中断处理之间的协调。因为这些程序是要加入内核的,系统默认为你是完全正确的,假如引起循环或者中断长时间不响应,结果非常严重。我们正在努力实现这一程序。

6. 确定编写需要的初始化函数:
void my_init(void)
需要将的file_operations中的操作函数的地址赋给某个file_operations的结构变量my_fops中的相应域;一个典型的形式是:
struct file_operations my_fops=
{
0,
block_read,
block_write,
0,
0,
my_ioctl,
0,
my_open,
my_release,
block_fsync,
0,
0,
0,
}
my_init中需要作的工作有:

首先调用标准内核函数登记该设备:
register_chrdev(MY_MOJOR,"my--bdev",&my_fops);
将request()函数的地址告诉内核:
blk_dev[MY_MAJOR].request_fn=DEVICE_REQUEST;
DEVICE_REQUEST是请求处理函数的地址,它的定义将在稍后可以看到。
告诉新设备的高速缓存的数据块的块大小:
my_block_size=512; //也可以是1024等等
blksize_size[MY_MAJOR]=& my_block_size;
为了系统在初始化时能够对新设备进行初始化,需要在blk_dev_init()中添加一行代码,可以插在blk_dev_init()中return 0的前面,格式为:
my_init();

7. 在include/linux/blk.h中添加相应语句;
到目前为止,除了DEVICE_REQUEST符合外,还没有告诉内核到那里去找你的request()函数,为此需要将一些宏定义加到blk.h中。在blk.h中找到类似的一行:
#endif /*MAJOR_NR==whatever */
在这行前面加入如下宏定义:
#elif (MAJOR_NR==whatever)

static void my_request(void);
#define DEVICE_NAME "MY_BLK_DEV" //驱动程序名称
#define DEVICE_REQUEST my_request //request()函数指针
#define DEVIEC_NR(device) (MINOR(device)) //计算实际设备号
#define DEVIEC_ON(device) //用于需要打开的设备
#define DEVIEC_OFF(device) //用于需要关闭的设备
8. 修改drivers/block/Makefile;
假设我们把所以必要的函数写mybd.c中,则找到"L_OBJS := tty_io.o n_tty.o cons
ole.o "行,将"mybd.o"加到其中。
9. 将该设备私有的*.c,*.h复制到目录drivers/block下。
10. 用命令:make clean;make dep;make zImage重新编译内核。
11. 用mknod命令在目录/dev下建立相应主设备号的用于读写的非凡文件。
完成了上述步骤,你在linux环境下编程时就可以使用新设备了。





[目录]

--------------------------------------------------------------------------------


一个虚拟的字符设备驱动程序

七. 一个虚拟的字符设备驱动程序
以下是一个虚拟的字符设备驱动程序,该程序是我和潘刚同学的试验结果,本来我们还打算写一个虚拟的块设备驱动程序,由于时间关系,没有能够完全明白中断中断服务子程序的编写方法,因此没有没有能够实现一个可以所有的虚拟的块设备,非常遗憾。不过主要步骤已经在上文中进行了介绍,我想再有一段时间应该能够完成,到时候一定交给李老师看一下。
虚拟的字符设备驱动程序如下,在潘刚同学的试验报告中也有介绍:
/* drgn.h */
#ifdef KERNEL
#define TRACE_TXT(text) {if(drgn_trace) {console_print(text);console_print("


");}}
#define TRACE_CHR(chr) {if(drgn_trace) console_print(chr);}
#define DRGN_READ 1
#define DRGN_WRITE 0
#endif
#define FALSE 0
#define TRUE 1
#define MAX_BUF 120
#define DRGN_TRON (('M' << icon_cool.gif0x01)
#define DRGN_TROFF (('M' << icon_cool.gif0x02)
struct drgn_buf
{
int buf_size;
char buffer[MAX_BUF];
struct drgn_buf *link;
};
/* drgn.c */
#define KERNEL
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "drgn.h"
static int drgn_trace;
static int write_busy;
static int read_busy;
static struct drgn_buf * qhead;
static struct drgn_buf * qtail;
static int drgn_read(struct inode * , struct file * , char * , int );
static int drgn_write(struct inode * , struct file * , const char *, int );
static int drgn_ioctl(struct inode * , struct file * , unsigned int , unsig
ned long );
static int drgn_open(struct inode *,struct file *);
static void drgn_release(struct inode *,struct file *);
/* extern void console_print(char *);*/
struct file_operations drgn_fops=
{
NULL,
drgn_read,
drgn_write,
NULL,
NULL,
drgn_ioctl,
NULL,
drgn_open,
drgn_release,
NULL,
NULL,
NULL,
NULL
};
void drgn_init(void)
{
drgn_trace=TRUE;
if(register_chrdev(30,"drgn",&drgn_fops))
TRACE_TXT("Cannot register drgn driver as major device 30.")
else
TRACE_TXT("Tiny devie driver registered successfully.")
qhead=0;
write_busy=FALSE;
read_busy=FALSE;
/* drgn_trace=FALSE;*/
return;
}
static int drgn_open(struct inode * inode,struct file * file)
{
TRACE_TXT("drgn_open")
switch (MINOR(inode->i_rdev))
{
case DRGN_WRITE:
if(write_busy)
return -EBUSY;
else{
write_busy=TRUE;
return 0;
}
case DRGN_READ:
if(read_busy)
return -EBUSY;
else{
read_busy=TRUE;
return 0;
}
default:
return -ENXIO;
}
}
static void drgn_release(struct inode * inode,struct file * file)
{
TRACE_TXT("drgn_release")
switch (MINOR(inode->i_rdev))
{
case DRGN_WRITE:
write_busy=FALSE;
return;
case DRGN_READ:
read_busy=FALSE;
return;
}
}
static int drgn_write(struct inode * inode,struct file * file,

const char * buffer,int count)
{
int i,len;
struct drgn_buf * ptr;
TRACE_TXT("drgn_write")
if (MINOR(inode->i_rdev)!=DRGN_WRITE)
return -EINVAL;
if ((ptr=kmalloc(sizeof(struct drgn_buf),GFP_KERNEL))==0)
return -ENOMEM;
len=count < MAX_BUF?count:MAX_BUF;
if (verify_area(VERIFY_READ,buffer,len))
return -EFAULT;
for(i=0;i < count && i<MAX_BUF;++i)
{
ptr->buffer[i]=(char) get_user((char*)(buffer+i));
TRACE_CHR("w")
}
ptr->link=0;
if(qhead==0)
qhead=ptr;
else
qtail->link=ptr;
qtail=ptr;
TRACE_CHR("
")
ptr->buf_size=i;
return i;
}
static int drgn_read(struct inode * inode , struct file * file,
char * buffer, int count)
{
int i,len;
struct drgn_buf * ptr;
TRACE_TXT("drgn_read")
if(MINOR(inode->i_rdev)!=DRGN_READ)
return -EINVAL;
if (qhead==0)
return -ENODATA;
ptr=qhead;
qhead=qhead->link;
len=count < ptr->buf_size?count:ptr->buf_size;
if (verify_area(VERIFY_WRITE,buffer,len))
return -EFAULT;
for (i=0; i<count && i<ptr->buf_size; ++i)
{
put_user((char) ptr->buffer[i],(char *)(buffer+i));
TRACE_CHR("r")
}
TRACE_CHR("
")
kfree_s(ptr,sizeof(struct drgn_buf));
return i;
}
static int drgn_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
TRACE_TXT("drgn_ioctl")
/* if (cmd==DRGN_TRON){
drgn_trace=TRUE;
return 0;
}
else
if (cmd==DRGN_TROFF){
drgn_trace=FALSE;
return 0;
}
else
return -EINVAL;*/
switch(cmd)
{
case DRGN_TRON:
drgn_trace=TRUE;
return 0;
case DRGN_TROFF:
drgn_trace=FALSE;
return 0;
default:
return -EINVAL;
}
} 

⌨️ 快捷键说明

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