通过第一个hello world驱动程序,我们学会了驱动程序的框架。
知道了,如何编译,如何加载,如何卸载一个驱动程序。接下来我们来做一个完整的驱动程序
Demo_Driver.c
#include<linux/kernel.h>
#include<linux/init.h>#include<linux/fs.h>
#include<linux/module.h>
#define Demo_MAJOR 98 //定义主设备号
#define Demo_DEBUG
#define VERSION "Demo_Driver"
void showversin(void)
{
printk(KERN_EMERG"***********************************************\n");
printk(KERN_EMERG"\tVERSION\t\n");
printk(KERN_EMERG"***********************************************\n");
}
//static int Demo_temp_count=0;
size_t Demo_read(struct file *file,char *buf,size_t count,loff_t *f_ops)
{
#ifdef Demo_DEBUG
printk(KERN_EMERG"Demo_read[-kernel--]\n");
#endif
return count;
}
size_t Demo_write(struct file *file,const char *buf,size_t count,loff_t * f_ops)
{
#ifdef Demo_DEBUG
printk(KERN_EMERG"Demo_write[-kernel-]\n");
#endif
return count;
}
int Demo_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long data)
{
#ifdef Demo_DEBUG
printk(KERN_EMERG"Demo_ioctl[-kernel-]\n");
#endif
return 0;
}
int Demo_open(struct inode * inode,struct file * file)
{
#ifdef Demo_DEBUG
printk(KERN_EMERG"Demo_open[-kernel-]\n");
#endif
//MOD_INC_USE_COUNT;
return 0;
}
int Demo_release(struct inode *inode,struct file *file)
{
#ifdef Demo_DEBUG
printk(KERN_EMERG"Demo_release[-kernel-]\n");
#endif
//MOD_DEC_USE_COUNT;
return 0;
}
struct file_operations Test_ctl_ops={
open: Demo_open,
read: Demo_read,
write: Demo_write,
ioctl: Demo_ioctl,
release: Demo_release,
};//a
static int HW_Test_CTL_init(void)
{
int ret = -ENODEV;
ret = register_chrdev(Demo_MAJOR,"demo_drv",&Test_ctl_ops);
if(ret<0)
{
printk(KERN_EMERG"Demo_module failed with %d\n[-kernel-]",ret);
return ret;
}
else
{
printk(KERN_EMERG"Demo_driver register success!!![-kernel-]\n");
}
printk("\n...\nret=%x\n...\n",ret);
showversin();
return ret;
}
static int Demo_Test_CTL_init(void)
{
int ret = -ENODEV;
#ifdef Demo_DEBUG
printk(KERN_EMERG"Demo_Test_CTL_init[-kernel-]\n");
#endif
ret = HW_Test_CTL_init();
if(ret)
return ret;
return 0;
}
static void cleanup_Test_ctl(void)
{
#ifdef Demo_DEBUG
printk(KERN_EMERG"cleanup_INT_CTL[-kernel-]\n");
#endif
unregister_chrdev(Demo_MAJOR,"demo_drv");
}
MODULE_DESCRIPTION("simple int drive module");
MODULE_LICENSE("GPL");
module_init(Demo_Test_CTL_init);
module_exit(cleanup_Test_ctl);
相比于hello world驱动程序,上面这个程序更加完整。
首先要介绍一个重要的结构体
struct file_operations fops={
read: device_read;
write: device_write;
open: device_open;
release: device_release;
}
它的原型在<include/linux/fs.h>中
struct file_operations{
struct module * owner;
loff_t (*llseek)();
ssize_t (*read)();
ssize_t (*aio_read)();
ssize_te (*write)();
.........
}
在结构体file_operations{}中,每一个成员的名字都对应一个系统调用,对应着设备驱动程序提供的入口位置
使用方法如第一个file_operations
read:device_read;........
这样我们在应用程序中调用read()对设备文件进行操作时,
驱动程序就会直接调用device_read()来进行读操作了。
现在我们知道了,应用程序中的函数是怎么与驱动程序中的操作函数对应起来了。那么驱动程序中的操作函数是
如何连接到设备文件上的呢?
靠register_chrdev()注册我们的设备
如上面代码:
ret = register_chrdev(Demo_MAJOR,"demo_drv",&Test_ctl_ops);
第一个参数是我们的主设备号,第二个是我们要注册的设备的设备名,第三个是我们建立的结构体file_operations。
这三个参数都是有重要作用的。
第一个主设备号是内核识别我们设备的标志,内核通过主设备号识别我们的设备文件。
第二个是我们要注册的设备名,这个参数要与我们在/dev 目录下建立的设备文件名一致,这样我们才可以打开设备文件。
第三个是我们的结构体,它建立设备文件到设备操作函数的对应关系。
另外一个函数是:
unregister_chrdev()
unregister_chrdev(Demo_MAJOR,"demo_drv");
用来卸载我们的设备。
Makefile代码如下:
KERNELDIR ?= /lib/modules/2.6.25-14.fc9.i686/build/
PWD := $(shell pwd)
#CC=$(CROSS_COMPILE)gcc
obj-m :=Demo_Driver.o
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
然后执行命令:make
得到我们要加载的模块Demo_Driver.ko
这时候需要我们建立一个设备节点,也就是/dev/目录下的设备文件
mknod /dev/demo_drv c 98 0
第二个命令参数是我们注册的设备名
第三个命令参数是c代表char 字符型设备 b代表block块设备 u 是unbuff p是fifo文件
第四个参数是主设备号,第五个参数是次设备号
接着我们编写一个应用程序进行一下测试
test_drive.c
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#define DEVICE_NAME "/dev/demo_drv"
int main()
{
int fd;
int ret;
char *i;
printf("\nstart Demo_driver test\n\n");
fd=open(DEVICE_NAME,O_RDWR);
printf("fd=%d\n",fd);
if(fd==-1)
{
printf("open device %s error\n",DEVICE_NAME);
}
else
{
read(fd,NULL,0);
write(fd,NULL,0);
ioctl(fd);
ret=close(fd);
printf("ret=%d\n",ret);
printf("close Demo_driver test\n");
}
return 0;
}
gcc test_drive.c -o test_drive
然后执行程序
./test_drive
会有如下打印信息
鉴于本人比较懒,运行结果大家自己分析吧。
这个例子主要是告诉大家完整的驱动程序框架。
主要熟记三个东西
file_operation
register_chrdev
unregister_chrdev