- 论坛徽章:
- 0
|
Linux 2.4的内核下驱动编译出来的名字通常是*.o的文件,而在Linux 2.6的内核下编译出来的文件是*.ko的文件。在编译驱动的时候,注意要在编译的时候加__DKERNEL__和_DMODULE参数。还要注意在 makefile 文件里面正确地指定 KERNELDIR 和INCLUDEDIR。驱动程序有两种加载方式,内核自动加载和手动加载。通常的做法是在调试过程中采用手动加载的方式,等调试好了之后,就可以编译到内核里面采用自动加载的方式。驱动相对于内核来说就是内核的模块。
内核驱动模块的加载命令用insmod,如insmod mydriver.o。这个命令其实就是调用驱动里面的mydriver_init()函数。用insmod命令将编译好的模块调入内存时,就是向系统的字符设备表登记了一个字符设备。如果登记成功,返回设备的主设备号,不成功,返回一个负值。那么内核驱动模块的卸载就是调用rmmod mydriver,这是调用驱动里面的mydriver_exit()函数,它释放字符设备test在系统字符设备表中占有的表项。当然,上层如果要访问内核的驱动模块,还需要在dev目录下添加设备访问节点,在dev目录下执行mknod c主设备号从设备号:
mknod mydriver c 10 174
从设备号可以从0-254,主设备号在include/linux/major.h文件里可以看到具体的定义,在include/linux/miscdevices.h文件里可以看到从设备号的一些定义,在定义自己的设备号的时候注意不要和系统内核中原有的设备号冲突。
另外一点需要注意如果使用了devfs文件系统的话,设备节点的目录是不同的。设备的访问节点要改成/dev/misc/mydriver。可以通过查看编译出来的 system.map 文件或 cat /proc/ksyms查看底层驱动导出的函数。
当内核加载了驱动之后,上层就可以通过驱动对底层设备进行操作了。如下所示的代码是一个简单的对mydriver进行读写和ioctl的例子。
test.c
#include
#include
#include
#include
#include
#include
#if 0
#define DEV_MYDRIVER "/dev/misc/mydriver"
#else
#define DEV_MYDRIVER "/dev/mydriver"
#endif
#define MYDRIVER_IOC_RESET
_IO(MYDRIVER_IOC_MAGIC, MYDRIVER_IOC_BASE + 5)
int dev_cmd(const char * dev, int cmd, unsigned long arg)
{
int fd;
fd = open(dev, O_RDWR);
if ( fd {
perror(dev);
return -1;
}
ioctl(fd, cmd, arg);
close(fd);
return 0;
}
void test_ioctl(void)
{
dev_cmd(DEV_MYDRIVER,MYDRIVER_IOC_RESET,0);
}
void test_mydriver(void)
{
int i, j;
int fd;
char buf[34];
i = 0;
while ( 1 )
{
i++;
printf("\n***** count: %d *****\n", i);
fd = open(DEV_MYDRIVER, O_RDWR);
for ( j = 0; j {
read(fd, buf, sizeof(buf));
write(fd, buf, sizeof(buf));
}
close(fd);
}
}
int main(int argc, char * argv[])
{
if ( argc {
printf("test \n");
return 1;
}
switch ( argv[1][0] )
{
case 'a':
test_mydriver();
break;
case 'c':
test_ioctl ();
break;
}
return 0;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/110576/showart_2182782.html |
|