您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > Linux字符驱动设备-学习笔记(最新实例)
-1-字符驱动开发学习笔记Linux下的设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得Windows的设备操作犹如文件一般。在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,如open()、close()、read()、write()等。Linux主要将设备分为二类:字符设备和块设备。字符设备是指设备发送和接收数据以字符的形式进行;而块设备则以整个数据缓冲区的形式进行。字符设备的驱动相对比较简单。 下面假设一个非常简单的虚拟字符设备:这个设备中只有一个4个字节的全局变量intglobal_var,设备的名为gobalvar。对gobalvar设备的读写等操作即是对其中全局变量global_var的操作。友情提示:在此,希望各位读者不要直接复制我的代码,至少按照我的代码敲一遍,关键是理解才行。我们的学习才刚刚开始,与诸位共勉!!!1、编写globalvar.c文件,代码如下:打开终端,在test文件夹下创建globalvar.c文件PC$cd~/test//进入工作目录PC$geditglobalvar.c//创建文件源文件globalvar.c代码如下,我所使用的内核是2.6版本。#includelinux/module.h#includelinux/init.h#includelinux/fs.h#includelinux/cdev.h#includelinux/uaccess.hMODULE_LICENSE(GPL);intglobalvar_open(structinode*,structfile*);intglobalvar_release(structinode*,structfile*);ssize_tglobalvar_read(structfile*,char*,size_t,loff_t*);1-2-ssize_tglobalvar_write(structfile*,constchar*,size_t,loff_t*);intdev_major=0;intdev_minor=0;structfile_operationsglobalvar_fops=//将文件操作预分配的设备号相连{.owner=THIS_MODULE,.open=globalvar_open,.release=globalvar_release,.read=globalvar_read,.write=globalvar_write,};structglobalvar_dev//用来表示我们定义设备的结构{intglobal_var;//设备变量或者称为设备内存(只有4个字节)structcdevcdev;//内核中表示字符设备的结构};structglobalvar_dev*my_dev;//设备结构指针staticvoid__exitglobalvar_exit(void)//退出模块时的操作{dev_tdevno=MKDEV(dev_major,dev_minor);//dev_t是用来表示设备编号的结构cdev_del(&my_dev-cdev);//从系统中移除一个字符设备kfree(my_dev);//释放自定义的设备结构unregister_chrdev_region(devno,1);//注销已注册的驱动程序printk(globalvarunregistersuccess\n);}staticint__initglobalvar_init(void)//初始化模块的操作{intret,err;if(dev_major){dev_tdevno=MKDEV(dev_major,dev_minor);ret=register_chrdev_region(devno,1,globalvar);}else{ret=alloc_chrdev_region(&devno,dev_minor,1,globalvar);//动态分配设备号dev_major=MAJOR(devno);//保存动态分配的主设备号2-3-}if(ret0){printk(globalvarregisterfailure\n);globalvar_exit();//如果注册设备号失败就退出returnret;}else{printk(globalvarregistersuccess\n);}my_dev=kmalloc(sizeof(structglobalvar_dev),GFP_KERNEL);//为设备分配内核空间if(!my_dev)//如果分配失败返回错误信息{ret=-ENOMEM;printk(createdevicefailed\n);}else//如果分配成功就可以完成设{my_dev-global_var=0;//设备变量初始化为0cdev_init(&my_dev-cdev,&globalvar_fops);//初始化设备中的cdev结构my_dev-cdev.owner=THIS_MODULE;//初始化cdev中的所有者字段err=cdev_add(&my_dev-cdev,devno,1);//向内核添加cdev结构的信息if(err0)//如果添加失败打印错误消息printk(adddevicefailure\n);elseprintk(adddevicesuccess\n);}returnret;}//打开操作intglobalvar_open(structinode*inode,structfile*filp){structglobalvar_dev*dev;//根据inode结构的cdev字段,获得这个设备结构的指针dev=container_of(inode-i_cdev,structglobalvar_dev,cdev);filp-private_data=dev;//保存数据指针return0;}//释放操作intglobalvar_release(structinode*inode,structfile*filp)3-4-{return0;}//读操作ssize_tglobalvar_read(structfile*filp,char*buf,size_tlen,loff_t*off){structglobalvar_dev*dev=filp-private_data;//获取已指向分配数据的指针if(copy_to_user(buf,&dev-global_var,sizeof(int)))//将设备变量值复制到用户空间{return-EFAULT;}returnsizeof(int);//返回读取数据的大小}//写操作ssize_tglobalvar_write(structfile*filp,constchar*buf,size_tlen,loff_t*off){structglobalvar_dev*dev=filp-private_data;//获取已指向分配数据的指针if(copy_from_user(&dev-global_var,buf,sizeof(int)))//将设备变量值复制到用户空间{return-EFAULT;}returnsizeof(int);//返回写数据的大小}module_init(globalvar_init);module_exit(globalvar_exit);2、编写Makefile文件,内容如下:ifneq($(KERNELRELEASE),)obj-m:=globalvar.oelseKERNELDIR:=/lib/modules/2.6.32.41+drm33.18/buildPWD:=$(shellpwd)all:$(MAKE)-C$(KERNELDIR)M=$(PWD)modulesclean:$(MAKE)-C$(KERNELDIR)M=$(PWD)cleanendif4-5-3、当前工作目录开始编译模块PC$cd~/testPC$make4、加载模块,并用lsmod或dmesg查看PC$sudoinsmodglobalvar.koPC$lsmodModuleSizeUsedbyglobalvar12910binfmt_misc65871vmnet4098317………………PC$dmesg…………[8175.764585]globalvarregistersuccess[8175.764588]adddevicesuccess5、查看动态生成的设备号(主设备号)PC$cat/proc/devicesCharacterdevices:…………189usb_device226drm251globalvar252usbmon…………6、使用mknod命令创建设备节点文件PC$sudomknod/dev/globalvarc2510PC$chgrpstaff/dev/globalvarPC$chmod664/dev/globalvar另外一种方法:在上述步骤4、5、6所实现的工作可以用另外一种简便的方法实现。详细内容请继续阅读下文:为了加载一个使用动态主设备号的设备驱动程序,对insmod的调用可以替换为一个简单的脚本文件,该脚本文件在调用insmod之后,利用awk这类工具读取/proc/devices以获取新分配的主设备号,然后创建对应的设备文件。下面是一个命名为globalvar_load的脚本文件,使用以模块方式发布的驱动程序的用户可以在系统rc.local文件中调用这个脚本。或是在需要此模块式时手5-6-工调用(本文中我们选用手工调用此脚本)。脚本内容如下:#!/bin/shmodule=globalvarmode=664/sbin/insmod./$module.ko$*||exit1rm-f/dev/$modulemajor=$(awk\$2==\$module\{print\$1}/proc/devices)mknod/dev/$modulec$major0ifgrep-q'^staff:'/etc/group;thengroup=staffelsegroup=wheelfichgrp$group/dev/$modulechmod$mode/dev/$module这个脚本也同样适用于其它驱动程序,只要重新定义变量并根据需求调整mknod语句就可以了。7、编写测试程序//test.c#includesys/types.h#includesys/stat.h#includestdio.h#includefcntl.hmain(){intfd,num;fd=open(/dev/globalvar,O_RDWR,S_IRWXU|S_IRWXG);//可读写方式打开设备if(fd!=-1){read(fd,&num,sizeof(int));//读取设备变量printf(Theglobalvaris%d\n,num);printf(Pleaseinputthenumwrittentoglobalvar\n);scanf(%d,&num);write(fd,&num,sizeof(int));//写设备变量read(fd,&num,sizeof(int));//再次读取刚才写的值printf(Theglobalvarischangeto%dnow!\n,num);close(fd);//关闭设备文件}elseprintf(Deviceopenfailure\n);}8、编译test.cPC$gcc–otesttest.c6-7-PC$sudo./testTheglobalvaris0Pleaseinputthenumwrittentoglobalvar100Theglobalvarischangeto100now!结论:如果可以出现上面的的提示则证明字符设备驱动编写成功。7
本文标题:Linux字符驱动设备-学习笔记(最新实例)
链接地址:https://www.777doc.com/doc-1307004 .html