您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > 第3章字符设备驱动程序.
11324第3章字符设备驱动程序scull的设计主设备号与次设备号一些重要的数据结构字符设备的注册open和releasescull的内存使用read和write5672scull的设计scull0~scull3由全局且持久的内存区组成,可被多次打开,关闭后再打开,仍能保持原数据scullpipe0toscullpipe3FIFO(先进先出)设备,类似管道,可由一个进程读,另一个进程写Scullsingle、scullpriv、sculluid、scullwuid与scull0类似,但在open操作方面有些限制31324第3章字符设备驱动程序scull的设计主设备号与次设备号一些重要的数据结构字符设备的注册open和releasescull的内存使用read和write5674主设备号与次设备号$ls–l/devcrw-rw-rw-1rootroot1,3Apr112002nullcrw-------1rootroot10,1Apr112002psauxcrw-------1rootroot4,1Oct2803:04tty1crw-rw-rw-1roottty4,64Apr112002ttys0crw-rw----1rootuucp4,65Apr112002ttyS1crw--w----1vcsatty7,1Apr112002vcs1crw--w----1vcsatty7,129Apr112002vcsa1crw-rw-rw-1rootroot1,5Apr112002zero主设备号通常用于标识设备对应的驱动程序,号相同的设备共用一个驱动程序;次设备号用于标识驱动程序所服务的具体设备主设备号次设备号5主设备号与次设备号设备编号的内部表达内核中,设备编号数据类型为dev_t,定义在linux/types.h中操作设备编号的宏MAJOR(dev_tdev);由dev_t数得到主设备号MINOR(dev_tdev);由dev_t数得到次设备号MKDEV(intmajor,intminor);由主、次设备号得到dev_t数主设备号次设备号12位20位dev_t6主设备号与次设备号静态分配设备编号intregister_chrdev_region(dev_tfirst,unsignedintcount,char*name);first:主设备号范围起始值,次设备号通常为0count:连续设备号的个数name:设备编号范围关联的设备名称,将出现在/proc/devices和/sysfs中成功返回0,失败返回负数静态分配需要预先知道可使用的设备号,如何知道?内核源代码树的Documenttation/devices.text可查到尚有哪些号可用7主设备号与次设备号动态分配设备编号intalloc_chrdev_region(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);dev:调用成功后保存分配到的设备编号范围的第一个数firstminor:第一个次设备号,通常用是0count与name与静态分配时相同释放设备编号voidunregister_chrdev_region(dev_tfirst,unsignedintcount);8主设备号与次设备号scull设备号分配if(scull_major){dev=MKDEV(scull_major,scull_minor);result=register_chrdev_region(dev,scull_nr_devs,scull);}else{result=alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,scull);scull_major=MAJOR(dev);}if(result0){printk(KERN_WARNINGscull:can'tgetmajor%d\n,scull_major);returnresult;}scull_major为全局变量,初始化值为SCULL_MAJOR,定义在scull.h中,设为0时为动态分配(默认),否则为静态分配。9主设备号与次设备号scull_load静态分配的问题是:若驱动程序仅自己使用,选择一个未用的号来用没什么问题,但若驱动程序被广泛使用,则可能造成冲突动态分配的问题是:由于分配的主设备号不能始终一至,所以无法预先创建设备节点一旦分配了设备号,就可从/proc/devices中读到,因此可写一脚本代替insmod,在载入模块后读出设备号并创建节点。即用一脚本完成加载模块、读出主设备号及创建设备节点等操作。scull设备的这一脚本叫scull_load10主设备号与次设备号/proc/devices文件如下:Characterdevices:1mem2pty3ttyp4ttyS6lp7vcs10misc13input14sound21sg180usbBlockdevices:2fd8sd11sr65sd66sd11主设备号与次设备号/*Scull_load*/#!/bin/shmodule=sculldevice=scullmode=664/sbin/insmod./$module.ko$*||exit1rm-f/dev/${device}[0-3]major=$(awk\$2==\$module\{print\$1}/proc/devices)mknod/dev/${device}0c$major0mknod/dev/${device}1c$major1mknod/dev/${device}2c$major2mknod/dev/${device}3c$major3group=staff“grep-q'^staff:'/etc/group||group=wheel“chgrp$group/dev/${device}[0-3]chmod$mode/dev/${device}[0-3]#awk‘条件类型1{动作1}条件类型2{动作2}…’filename#grep[参数]‘搜索字符串’filename12主设备号与次设备号也可编写一个init脚本放在/etc/init.d下,可在系统初始化时加载模块、并根据主设备号创建节点若只涉及单个驱动,因动态设备号的分配并不是真正随机生成的,故只需在第一次加载时创建节点,以后加载时无需再创节点131324第3章字符设备驱动程序scull的设计主设备号与次设备号一些重要的数据结构字符设备的注册open和releasescull的内存使用read和write56714一些重要的数据结构大部分的驱动程序操作涉及到3个重要的内核数据结构,分别是:file_operations:文件操作结构,保存文件操作方法file:文件结构,对应一个打开的文件inode:节点结构,对应一个文件在编写真正的驱动程序前,需要对这3个结构有一个基本的认识。15一些重要的数据结构file_operations,在linux/fs.h中定义structfile_operations{structmodule*owner;loff_t(*llseek)(structfile*,loff_t,int);ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);ssize_t(*aio_read)(structkiocb*,char__user*,size_t,loff_t);ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);ssize_t(*aio_write)(structkiocb*,constchar__user*,size_t,loff_t*);int(*readdir)(structfile*,void*,filldir_t);unsignedint(*poll)(structfile*,structpoll_table_struct*);int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);int(*mmap)(structfile*,structvm_area_struct*);16一些重要的数据结构int(*open)(structinode*,structfile*);int(*flush)(structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structfile*,structdentry*,int);int(*aio_fsync)(structkiocb*,int);int(*fasync)(int,structfile*,int);int(*lock)(structfile*,int,structfile_lock*);ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*sendfile)(structfile*,loff_t*,size_t,read_actor_t,void*);ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);int(*check_flags)(int);int(*dir_notify)(structfile*,unsignedlong);};17一些重要的数据结构structmodule*owner第一个file_operations成员不是一个操作,是一个指向拥有这个结构的模块的指针。这个成员用来在它的操作还在被使用时阻止模块被卸载。几乎所有时间中,它被初始化为THIS_MODULE,一个在linux/module.h中定义的宏。loff_t(*llseek)(structfile*,loff_t,int);llseek方法用于改变文件中的当前读/写位置,并且将新位置作为(正的)返回值。loff_t参数是一个“longoffset”,并且就算在32位平台上也至少有64位宽。出错时返回一个负的返回值。如果这个函数指针是NULL,seek调用会以无法预测的方式修改file结构中的位置计数器(在file结构一节中描述)。18一些重要的数据结构ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);用来从设备中获取数据。非负返回值代表成功读取的字节数(返回值是一个“signedsize”类型,常常是目标平台本地的整数类型)。该函数指针为NULL时将导致调用失败并返回-EINVAL(“Invalidargument”)ssize_t(*aio_read)(structkiocb*,char__user*,size_t,loff_t);初始化一个异步读--在函数返回前可能不会结束的读操作。如果这个方法是NULL,所有的读操作会由read代替进行(同步地)。19一些重要的数据结构ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);发送数据给设备。非负返回值代表成功发送的字节数.ssize_t(*aio_write)(structkiocb*,constchar__user*,size_t,
本文标题:第3章字符设备驱动程序.
链接地址:https://www.777doc.com/doc-2155718 .html