如何编写Linux的设备驱动程序
这就用到函数
static int write_tibet(struct inode *inode,struct file *file,
const char *buf,int count)
{
return count;
}
static int open_tibet(struct inode *inode,struct file *file )
{
MOD_INC_USE_COUNT;
return 0;
} static void release_tibet(struct inode *inode,struct file *file )
{
MOD_DEC_USE_COUNT;
}
verify_area.
这几个函数都是空操纵
提供函数指针。
.实际挪用产生时什么也不做,他们仅仅为下面的结构
struct file_operations test_fops = {
NULL,
read_test,
write_test,
NULL, /* test_readdir */
NULL,
NULL, /* test_ioctl */
NULL, /* test_mmap */
open_test,
release_test, NULL, /* test_fsync */
NULL, /* test_fasync */
/* nothing more, fill with NULLs */
};
设置装备摆设驱动程序的主体可以说是写好了。现在要把驱动程序嵌入内核。驱动程序
可以根据两种方法编译。一种是编译进
kernel,另一种是编译成模块(modules),
如果编译进内核的话,会增长内核的巨细,还要改动内核的源文件,而且不克不及
动态的卸载,不利于调试,所以推荐利用模块方法。
int init_module(void)
{
int result;
result = register_chrdev(0, "test", &test_fops);
if (result < 0) {
printk(KERN_INFO "test: can't get major number ");
return result;
}
if (test_major == 0) test_major = result; /* dynamic */
return 0;
}
在用
这里,
设置装备摆设。
零的话,体系将选择一个没有被占用的设置装备摆设号返回。参数二是设置装备摆设文件名,
参数三用来注销驱动程序实际执行操纵的函数的指针。
如果注销成功,返回设置装备摆设的主设置装备摆设号,不行功,返回一个负值。
insmod命令将编译好的模块调入内存时,init_module 函数被挪用。在init_module只做了一件事,便是向体系的字符设置装备摆设表注销了一个字符register_chrdev需要三个参数,参数一是希望得到的设置装备摆设号,如果是
void cleanup_module(void)
{
unregister_chrdev(test_major, "test");
}
在用
rmmod卸载模块时,cleanup_module函数被挪用,它开释字符设置装备摆设test
在体系字符设置装备摆设表中占据的表项。
一个极端简单的字符设置装备摆设可以说写好了,文件名就叫
下面编译
test.c吧。
$ gcc -O2 -DMODULE -D__KERNEL__ -c test.c
得到文件
如果设置装备摆设驱动程序有多个文件,把每个文件按下面的命令行编译,然后
test.o便是一个设置装备摆设驱动程序。
ld -r file1.o file2.o -o modulename.
驱动程序曾经编译好了,现在把它安置到体系中去。
$ insmod -f test.o
如果安置成功,在
/proc/devices文件中就可以看到设置装备摆设test,
并可以看到它的主设置装备摆设号
要卸载的话,运转
,。
$ rmmod test
下一步要创建设置装备摆设文件。
mknod /dev/test c major minor
c
用
是指字符设置装备摆设,major是主设置装备摆设号,便是在/proc/devices里看到的。shell命令
$ cat /proc/devices | awk "\$2=="test" {print \$1}"
就可以得到主设置装备摆设号,可以把下面的命令行参加你的
shell script中去。
minor
我们现在可以经过设置装备摆设文件来拜访我们的驱动程序。写一个小小的测试程序。
是从设置装备摆设号,设置成0就可以了。
#include
#include
#include
#include
main()
{
int testdev;
int i;
char buf[10];
testdev = open("/dev/test",O_RDWR);
if ( testdev == -1 )
{
printf("Cann't open file ");
exit(0);
}
read(testdev,buf,10);
for (i = 0; i < 10;i++)
printf("%d ",buf[i]);
close(testdev);
}
编译运转,看看是不是打印出全
以上只是一个简单的演示。真正实用的驱动程序要庞大的多,要处置惩罚如停止,
1 ?
DMA
,I/O port等题目。这些才是真正的难点。请看下节,实际情况的处置惩罚。
如何编写Linux操纵体系下的设置装备摆设驱动程序
Roy G
三
设置装备摆设驱动程序中的一些具体题目。
1. I/O Port.
在
对恣意的
误用端口。
和硬件打交道离不开I/O Port,老的ISA设置装备摆设每每是占用实际的I/O端口,linux下,操纵体系没有对I/O口屏蔽,也便是说,任何驱动程序都可以I/O口操纵,这样就很容易引起杂乱。每个驱动程序应该本身避免
有两个紧张的kernel函数可以包管驱动程序做到这一点。
1
)check_region(int io_port, int off_set)这个函数观察体系的I/O表,看能否有别的驱动程序占用某一段I/O口。
参数1:io端口的基地点,
参数2:io端口占用的范畴。
返回值:0 没有占用, 非0,曾经被占用。
2
之前,必须向体系注销,以防止被其他程序占用。注销后,在
)request_region(int io_port, int off_set,char *devname)如果这段I/O端口没有被占用,在我们的驱动程序中就可以利用它。在利用/proc/ioports
文件中可以看到你注销的
io口。
参数1:io端口的基地点。
参数2:io端口占用的范畴。
参数3:利用这段io地点的设置装备摆设名。
在对I/O口注销后,就可以担心肠用inb(), outb()之类的函来拜访了。
于拜访一段内存。每每性的,我们要得到一块内存的物理地点。在
(之所以不说是
在是太简单,太不安全了)只需用段:偏移就可以了。在
在一些pci设置装备摆设中,I/O端口被映射到一段内存中去,要拜访这些端口就相称dos环境下,dos操纵体系是因为我认为DOS根本就不是一个操纵体系,它实window95中,95ddk
提供了一个
在
vmm 挪用 _MapLinearToPhys,用以把线性地点转化为物理地点。但Linux中是怎样做的呢?
2
内存操纵
在设置装备摆设驱动程序中动态开发内存,不是用malloc,而是kmalloc,或者用
get_free_pages
直接请求页。开释内存用的是kfree,或free_pages. 请细致,
kmalloc
等函数返回的是物理地点!而malloc等返回的是线性地点!关于
kmalloc
地点的转换是由
驱动程序异样也不克不及直接利用物理地点而是线性地点。但是事实上
返回的是物理地点这一点自己有点不太明白:既然从线性地点到物理386cpu硬件完成的,那样汇编指令的操纵数应该是线性地点,kmalloc
返回的确实是物理地点,而且也可以直接经过它拜访实际的
以由两种表明,一种是在核心态克制分页,但是这好像不太实际;另一种是
RAM,我想这样可
linux
不知对不对,还请高手指教。
的页目录和页表项设计得正好使得物理地点等同于线性地点。我的想法
结构占用了。
言反正传,要细致kmalloc最大只能开发128k-16,16个字节是被页描述符kmalloc用法参见khg.内存映射的I/O口,存放器或者是硬件设置装备摆设的RAM(如显存)一般占用F0000000
以上的地点空间。在驱动程序中不克不及直接拜访,要经过
重新映射当前的地点。
kernel函数vremap得到
驻留在内存,不克不及被互换到文件中去。但是
这可以经过牺牲一些体系内存的方法来解决。
具体做法是:好比说你的呆板由
另外,许多硬件需要一块比力大的连续内存用作DMA传送。这块内存需要一直kmalloc最多只能开发128k的内存。32M的内存,在lilo.conf的启动参数中加上
mem=30M
,这样linux就认为你的呆板只有30M的内存,剩下的2M内存在vremap
之后就可以为
请记着,用
DMA所用了。vremap映射后的内存,不用时使用unremap开释,否则会糜费页表。
3
停止处置惩罚
同处置惩罚I/O端口一样,要利用一个停止,必须先向体系注销。
int request_irq(unsigned int irq ,
void(*handle)(int,void *,struct pt_regs *),
unsigned int long flags,
const char *device);
irq:
是要请求的停止。
handle
:停止处置惩罚函数指针。
flags
:SA_INTERRUPT 请求一个疾速停止,0 正常停止。
device
:设置装备摆设名。
停止。
如果注销成功,返回0,这时在/proc/interrupts文件中可以看你请求的
4
一些罕见的题目。
的话,
对硬件操纵,偶然时序很紧张。但是如果用C言语写一些低级的硬件操纵gcc每每会对你的程序进行优化,这样时序就错掉了。如果用汇编写呢,
gcc
办法是克制优化。这当然只能对一部门你本身编写的代码。如果对所有的代码
都不优化,你会发现驱动程序根本无法装载。这是因为在编译驱动程序时要
用到
出来。
异样会对汇编代码进行优化,除非你用volatile要害字修饰。最保险的gcc的一些扩展特性,而这些扩展特性必须在加了优化选项之后才能表现
不胜感激。我一直都在
关于kernel的调试东西,我现在还没有发现有符合的。有谁晓得请报告我,printk打印调试信息,倒也还拼集。
我还不是很明白,不敢胡说。
关于设置装备摆设驱动程序还有许多内容,如等待/唤醒机制,块设置装备摆设的编写等。
接待各人品评指正。
- 文章作者: 福州军威计算机技术有限公司
军威网络是福州最专业的电脑维修公司,专业承接福州电脑维修、上门维修、IT外包、企业电脑包年维护、局域网网络布线、网吧承包等相关维修服务。
版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和声明。否则将追究法律责任。
TAG:
评论加载中...
|
下一篇: 用VB编写入侵监听程序