Linux添加设备驱动步骤和实例

在系统内部,I/O设备等等存取通过一组固定的入口点来进行,这组入口点由每个

设备的设备驱动程序提供。在Linux系统里,设备驱动程序提供的入口点由一个结构来向系统进行说明,此结构体定义为:

Structfile_operations{

    int (*lseek)(struct innode *innode, structfile *file,off_t off, int pos);

       /*移动文件指针的位置*/

       int (*read)(struct innode *innode, structfile *file, char *buf, int count);

       /*读操作,buf为存放读取结果的缓冲区,count为要读取的数据长度*/

       int (*write)(struct innode *innode, structfile *file, char *buf, int count);

       /*写操作,与read类似*/

    int (*readdir)(struct innode *innode, structfile *file, struct dirent *dirent, int count);

       /*取得下一个目录入口点*/

    int (*select)(struct innode *innode, structfile *file, int sel_type, select_table *wait);

       /*检查设备,看数据是否可读或设备是否可用于写数据*/

    int (*ioctl)(struct innode *innode, structfile *file, unsigned int cmd, unsigned int arg);

       /*进行读写以外的其他特殊操作,参数cmd为自定义的命令*/

    int (*mmap)(void)

       /*把设备的内容映射到地址空间*/

    int (*open)(struct innode *innode, structfile *file);

       /*打开设备进行I/O操作*/

int (*release)(struct innode *innode, structfile *file);

/*关闭设备*/

}

 

操作步骤

①编写设备驱动程序zhangjiajie.c;

#include
#include
#include
#include
#include
#include

unsigned int zjj_major = 0;

/*buf涓哄瓨鏀捐鍙栫粨鏋滅殑缂撳啿鍖猴紝length涓鸿璇诲彇鏁版嵁鐨勯暱搴?/
static ssize_t zjj_read(struct file *file, char *buf, size_t length, loff_t *offset)
{
	int n = 0;
	n = min( strlen("zhangjiajie's driver!"), length );
	if( copy_to_user(buf,"zhangjiajie's driver!", n) )
	{
		return -EFAULT;
	}
	return n;
}

static ssize_t zjj_write( struct file *file, const char *buf, size_t length,loff_t *offset)
{
	return length;
}

static int zjj_open(struct inode *inode, struct file *file)
{
	printk("open file succeed\n");
	return 0;
}

static int zjj_release(struct inode *inode, struct file *file)
{
	printk("close file succeed\n");
	return 0;
}

static const struct file_operations zjj_fops = {
	.open = zjj_open,
	.read = zjj_read,
	.write = zjj_write,
	.release = zjj_release,
};

static int  __init zjj_init(void)
{
	zjj_major = register_chrdev(0,"ZJJ_DRIVER",&zjj_fops);
	if( zjj_major < 0 )
	{
		printk("register dirver error\n");
		return -1;
	}
	else{
		printk("register driver %d succeed\n",zjj_major);
	}
	return 0;
}

static void __exit zjj_exit(void)
{
	unregister_chrdev(zjj_major,"ZJJ_DRIVER"); 
	printk("unistall driver succeed\n");	
}

module_init(zjj_init);
module_exit(zjj_exit);


 

②在zhangjiajie.c同一目录下编写Makefile文件;

obj-m:=zhangjiajie.o
KERNELBUILD:=/lib/modules/3.2.13/build
default:


 

③ $make:编译Makefile文件,生成zhangjiajie.ko文件;

④ $insmod./zhangjiajie.ko:挂载驱动;

⑤ $cat/proc/devices:查看添加的设备的主驱动号,我的驱动号为250,如下图3所示;

⑥ $mknod/dev/zhangjiajie c 250 0:挂载设备驱动。

⑦编译测试程序,测试驱动。

#include
#include
#include 
#include
 
int main(void)
{
	int fd, n;
	char string[32];

	for(n = 0; n < 32; n++){
		string[n] = ' ';
	}

	printf("Input string: ");
	scanf("%s",string);
	
	fd = open("/dev/ZJJ_DRIVER",O_RDWR);
	write(fd,string,32);
	read(fd,string,32);
	printf("from ZJJ_DRIVER: %s\n",string);
	
	return 1;
}

 

用到的函数说明

(一)intregister_chrdev(unsigned int major, const char *name, struct

file_operations*fops);

       major为设备驱动程序向系统申请的主设备号,如果为0则系统为此驱动程序动态分配一个主设备号。Name是设备名。Fops为对各个调用的入口点的说明。

       返回0便是返回成功,返回-EINVAL表示申请的主设备号非法,返回-EBUSY表示说申请的主设备号正被其他设备驱动程序使用。如果动态分配主设备号成功,会返回说分配的主设备号。

       如果register_chrdev成功,设备名就会出现在/proc/devices文件里。

 

(二) obj-m:=zhangjiajie.o

Makefile中的该语句表示最终生成模块文件,生成的模块文件名为zhangjiajie.o。

 

(三) Make –Cxxx M=$(shell pwd) modules

表示首先改变目录到-C指定的位置,M=选项是makefile在构造modukes目标前,返

回到模块源码目录。然后modules目标指向obj-m变量中设定的模块。

 

 

 

操作过程中要注意到的

①   .c驱动程序文件和 .o文件名要一致;

②   Makefile文件名的M要大写;

③  make时需要切换到root权限。

 

 

你可能感兴趣的:(linux)