scull阅读笔记.doc_第1页
scull阅读笔记.doc_第2页
scull阅读笔记.doc_第3页
scull阅读笔记.doc_第4页
scull阅读笔记.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

scull的阅读笔记2009-07-24 21:07-scull-Simple Character Utility for Loading Localities,区域装载的简单字符工具。scull设备:scull0,scull1,scull2,scull3.这四个设备分别由一个全局且持久的内存区域组成。可以使用常用命令来访问和测试这个设备,如cp,cat以及shell的I/O重定向等。-主设备号和次设备号-设备,位于/dev目录,字符设备的标志是c,块设备的标志是b。主设备号标识设备对应的驱动程序,次设备号由内核使用,用于正确确定设备文件所指的设备。dev_t类型(中定义),用来保存设备编号,主设备号12位,次设备号20位。由dev_t类型获得主设备号和次设备号:MAJOR(dev_t dev); /*/MINOR(dev_t dev);将主设备号和次设备号转换成dev_t类型:MKDEV(int major,int minor); /*/-分配和释放设备编号-获得设备编号:int register_chrdev_region(dev_t first,unsigned int count,char *name); /*/first:设备编号范围的起始值count:连续设备编号的个数name:和该设备编号范围关联的设备名称,将出现在/proc/devices和sysfs中。设备编号的动态分配int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);dev:保存申请到的第一个设备号firstminor:第一个次设备号count,name:同register_chrdev_region().释放设备编号:void unregister_chrdev_region(dev_t first,unsigned int count);在用户空间程序可以访问上述设备编号之前,驱动程序需要将设备编号和内部函数连接起来,这些内部函数用来实现设备的操作。动态分配主设备号驱动程序应该始终使用动态分配机制获取主设备号,即使用alloc_chrdev_region,而不是register_chrdev_region.分配过设备号以后,可以从 /proc/devices中读取到。用来获取主设备号的代码:if(SCULL_MAJOR)dev = MKDEV(SCULL_MAJOR,SCULL_MINOR);result = register_chrdev_region(dev,scull_nr_devs,scull);elseresult = alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,scull);scull_major = MAJOR(dev);if(result 0)printk(KERN_WARNING scull: cant get major %dn,scull_major);return result;-一些重要的数据结构-file_operatons,file,inodefile_operations结构:就是用来建立设备编号与驱动程序操作的链接的。file_operations结构在中定义。这个结构的每一个字段指向实现特定操作的函数。scull设备驱动的file_operations结构:struct file_operations scull_fops =.ownner = THIS_MODULE,.llseek = scull_llseek,.read = scull_read,.write = scull_write,.ioctl = scull_ioctl,.open = scull_open,.release= scull_release,;file结构:在中定义。file结构代表一个打开的文件,系统中每个打开的文件在内核空间都有一个对应的file结构。它由内核在open时创建,并传递给在该文件上进行操作的所有函数,知道close。inode结构:内核用inode结构在内部表示文件。其中的两个字段如下dev_t i_rdev 设备编号struct cdev *icdev 字符设备的内部结构-字符设备的注册-内核用struct cdev结构表示字符设备,头文件在内核调用设备的操作之前,必须分配并注册一个或多个上述结构。struct cdev *my_cdev = cdev_alloc();my_cdev-ops = &my_fops;这时,可以将cdev结构嵌入到自己的设备特定结构中。初始已分配到的机构:void cdev_init(struct cdev *cdev,struct file_operations *fops);在cdev结构设置好之后,最后的步骤是通过下面的调用告诉内核该结构的信息:int cdev_add(struct cdev *dev,dev_t num,unsigned int count);num:第一个设备编号count:设备编号的数量移出一个字符设备:void cdev_del(struct cdev *dev);-scull中的设备注册-在scull内部,通过struct scull_dev的结构来表示每个设备。struct scull_devstruct scull_qset *data; /*指向第一个量子集的指针*/int quantum; /*当前量子的大小*/int qset; /*当前数组的大小*/unsigned long size; /*保存在其中的数据总量*/unsigned int access_key; /*由sculluid和scullpriv使用*/struct semaphore sem; /*互斥信号量*/struct cdev cdev; /*字符设备结构*/;cdev的代码:static void scull_setup_cdev(struct scull_dev *dev,int index)int err,devno = MKDEV(scull_major,scull_minor+index);cdev_init(&dev-cdev,&scull_fops);dev-cdev.owner = THIS_MODULE;dev-cdev.ops = &scull_fops;err = cdev_add(&dev-cdev,devno,1);if(err) printk(KERN_NOTICE Error %d adding scull %d,err,index);-早期的办法-早期不使用cdev接口。注册一个字符设备驱动程序的经典方式是:int register_chrdev(unsigned int major,const char *name,struct file_operations *fops);移出的函数:int unregister_chrdev(unsigned int major,const char *name);-open和release-open方法open方法做初始化的工作。open的原型:int (*open)(struct inode *inode,struct file *filp);inode参数的i_cdev字段包含了所需要的信息,唯一的问题是,我们通常不需要cdev本身,而是希望得到包含cdev结构的scull_dev结构,这可以通过中的container_of宏来实现:container_of(pointer,container_type,container_field);struct scull_dev *dev; /*device information*/dev = container_of(inode-i_cdev,struct scull_dev,cdev);filp-private_data = dev;一旦代码找到scull_dev结构之后,scull将一个指针保存到file结构的private_data字段,方便今后对该指针的访问!scull_open代码如下:int scull_open(struct inode *inode,struct file *filp)struct scull_dev *dev; /*device information*/dev = container_of(inode-i_cdev,struct scull_dev,cdev);filp-private_data = dev;if(filp-f_flags & O_ACCMODE) = O_WRONLY) scull_trim(dev);return 0;release方法释放由open分配的、保存在filp-private_data中的所有内容,在最后一次关闭操作时关闭设备。-scull的内存使用-scull驱动程序引入了linux内核中用于内存管理的两个核心函数。定义在中,它们是void *kmalloc(size_t size,int flags); flags:GFP_KERNELvoid kfree(void *ptr);在scull中,每个设备都是一个scull_qset结构体组成的链表,每个scull_qset结构体里有一个指针数组(称量子集),指针数组里的每个指针指向一个4000字节的内存区(称量子)。scull_trim简单地遍历链表,释放所有找到的量子和量子集。int scull_trim(struct scull_dev *dev)struct scull_qset *next,*dptr;int qset = dev-qset; /*量子集大小*/int i;for(dptr = dev-data;dptr;dptr = next) if(dptr-data) for(i=0;idatai); kfree(dptr-data); dptr-data = NULL; next = dptr-next; kfree(dptr);|dev-size = 0;dev-quantum = scull_quantum;dev-qset = scull_qset;dev-data = NULL;return 0;-read和write-read完成的任务是从内核空间拷贝数据到应用程序空间;write则是从应用程序空间拷贝数据到内核空间。ssize_t read(struct file *filp,char _user *buff,size_t count,loff_t *offp);ssize_t write(struct file *filp,const _user *buff,size_t count,loff_t *offp);offp:指明文件中存取操作的位置。buff:是用户空间的指针。很显然,驱动程序必须访问用户空间的缓冲区以便完成自己的工作。为了确保安全,这种访问应始终通过内核提供的专用函数完成。unsigned long copy_to_user(void _user *to,const void *from,unsigned long count);unsigned long copy_from_user(void *to,const void _user *from,unsigned long count);read的代码:ssize_t scull_read(struct file *filp,char _user *buf,size_t count,loff_t *f_pos)struct scull_dev *dev = filp-private_data;struct scull_qset *dptr;int quantum = dev-quantum,qset = dev-qset;int itemsize = quantum * qset;int item,s_pos,q_pos,rest;ssize_t retval = 0;if(down_interruptible(&dev-sem) return -ERESTARTSYS;if(*f_pos = dev-size) goto out;if(*f_pos+count dev-size) count = dev-size-*f_pos;/*在量子集中寻找链表项、qset索引以及偏移量*/item = (long)*f_pos / itemsize;rest = (long)*f_pos % itemsize;s_pos = rest / quantum;q_pos = rest % quantum;dptr = scull_

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论