ImageVerifierCode 换一换
格式:DOC , 页数:12 ,大小:121KB ,
资源ID:4206601      下载积分:20 文钱
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,省得不是一点点
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.wenke99.com/d-4206601.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(字符设备驱动程序.doc)为本站会员(hw****26)主动上传,文客久久仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知文客久久(发送邮件至hr@wenke99.com或直接QQ联系客服),我们立即给予删除!

字符设备驱动程序.doc

1、Linux 设备驱动程序学习(1)-字符设备驱动程序 Linux 设备驱动程序学习(1) -字符设备驱动程序 今天进入Linux 设备驱动程序(第 3 版)第三章字符设备驱动程序的学习。 这一章主要通过介绍字符设备 scull(Simple Character Utility for Loading Localities,区域装载的简单字符工具)的驱动程序编写,来学习 Linux 设备 驱动的基本知识。scull 可以为真正的设备驱动程序提供样板。 一、主设备号和次设备号 主设备号表示设备对应的驱动程序;次设备号由内核使用,用于正确确定设备 文件所指的设备。 内核用 dev_t 类型( )来保

2、存设备编号,dev_t 是一个 32 位的数,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); /指定设备编号 int alloc_ch

3、rdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name); /动态生成设备编号 void unregister_chrdev_region(dev_t first, unsigned int count); /释放设备编号 分配主设备号的最佳方式是:默认采用动态分配,同时保留在加载甚 至是编译时指定主设备号的余地。 以下是在 scull.c 中用来获取主设备号的代码: if (scull_major) dev = MKDEV(scull_major, scull_minor); result

4、 = register_chrdev_region(dev, scull_nr_devs, “scull“); else result = alloc_chrdev_region( scull_major = MAJOR(dev); if (result cdev.owner = THIS_MODULE; dev-cdev.ops = /这句可以省略,在 cdev_init中 已经做过 err = cdev_add ( /* Fail gracefully if need be 这步值得注意*/ if (err) printk(KERN_NOTICE “Error %d adding scul

5、l%d“, err, index); 四、scull 模型的内存使用 以下是 scull 模型的结构体: /* * Representation of scull quantum sets. */ struct scull_qset void *data; struct scull_qset *next; ; struct scull_dev struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* the current quantum size */ int qset; /* the curren

6、t array size */ unsigned long size; /* amount of data stored here */ unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */ ; scull 驱动程序引入了两个 Linux 内核中用于内存管理的核心函数, 它们的定 义都在: void *kmalloc(size

7、_t size, int flags); void kfree(void *ptr); 以下是 scull 模块中的一个释放整个数据区的函数(类似清零),将在 scull 以 写方式打开和 scull_cleanup_module 中被调用: 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) /* 循环 scull_set 个数次,直到 d

8、ptr 为 NULL 为止。*/ if (dptr-data) for (i = 0; i datai);/* 释放其中一个量子的空 间*/ kfree(dptr-data);/* 释放当前的 scull_set的量子集 的空间*/ dptr-data = NULL;/* 释放一个 scull_set中的 void *data指针*/ next = dptr-next; /* 准备下个 scull_set的指针*/ kfree(dptr);/* 释放当前的 scull_set*/ dev-size = 0; /* 当前的 scull_device所存的数据为 0字节*/ dev-quantum

9、 = scull_quantum;/* 初始化一个量子的大小*/ dev-qset = scull_qset;/* 初始化一个量子集中量子的个数*/ dev-data = NULL;/* 释放当前的 scull_device的 struct scull_qset *data指针*/ return 0; 以下是 scull 模块中的一个沿链表前行得到正确 scull_set指针的函数,将在 read和 write方法中被调用: /*Follow the list*/ struct scull_qset *scull_follow(struct scull_dev *dev, int n) str

10、uct scull_qset *qs = dev-data; /* Allocate first qset explicitly if need be */ if (! qs) qs = dev-data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL); if (qs = NULL) return NULL; /* Never mind */ memset(qs, 0, sizeof(struct scull_qset); /* Then follow the list */ while (n-) if (!qs-next) qs-next =

11、 kmalloc(sizeof(struct scull_qset), GFP_KERNEL); if (qs-next = NULL) return NULL; /* Never mind */ memset(qs-next, 0, sizeof(struct scull_qset); qs = qs-next; continue; return qs; 其实这个函数的实质是:如果已经存在这个 scull_set,就返回这个 scull_set 的指针。如果不存在这个 scull_set,一边沿链表为 scull_set分配空间一边 沿链表前行,直到所需要的 scull_set被分配到空间并

12、初始化为止,就返回这 个 scull_set的指针。 五、open 和 release open 方法提供给驱动程序以初始化的能力,为以后的操作作准备。应完成的工作如下: (1)检查设备特定的错误(如设备未就绪或硬件问题); (2)如果设备是首次打开,则对其进行初始化; (3)如有必要,更新 f_op 指针; (4)分配并填写置于 filp-private_data 里的数据结构。 而根据 scull 的实际情况,他的 open 函数只要完成第四步(将初始化过的 struct scull_dev dev的指针传递到 filp-private_data 里,以备后用)就好了, 所以 open 函

13、数很简单。但是其中用到了定义在 中的 container_of 宏,源码如下: #define container_of(ptr, type, member) ( const typeof( (type *)0)-member ) *_mptr = (ptr); (type *)( (char *)_mptr - offsetof(type,member) );) 其实从源码可以看出,其作用就是:通过指针 ptr,获得包含 ptr所指向数据(是 member结构体)的 type结构体的指针。即是用指针得到另外一个指针。 release 方法提供释放内存,关闭设备的功能。应完成的工作如下: (1

14、)释放由 open 分配的、保存在 file-private_data 中的所有内容; (2)在最后一次关闭操作时关闭设备。 由于前面定义了 scull 是一个全局且持久的内存区,所以他的 release 什么都不做。 六、read 和 write read 和 write 方法的主要作用就是实现内核与用户空间之间的数据拷贝。因为 Linux 的内核空间和用户空间隔离的,所以要实现数据拷贝就必须使用在 中定义的: unsigned long copy_to_user(void _user *to, const void *from, unsigned long count); unsigned

15、 long copy_from_user(void *to, const void _user *from, unsigned long count); 而值得一提的是以上两个函数和 #define _copy_from_user(to,from,n) (memcpy(to, (void _force *)from, n), 0) #define _copy_to_user(to,from,n) (memcpy(void _force *)to, from, n), 0) 之间的关系:通过源码可知,前者调用后者,但前者在调用前对用户空间指针进行了检查。 至于 read和 write 的具体函数

16、比较简单,就在实验中验证好了。 七、模块实验 这次模块实验的使用是友善之臂 SBC2440V4,使用 Linux2.6.22.2内核。 模块程序链接: scull 模块源程序 模块测试程序链接:模块测试程序 测试结果: 量子大小为 6: Tekkaman2440SBC2440V4#cd /lib/modules/ Tekkaman2440SBC2440V4#insmod scull.ko scull_quantum=6 Tekkaman2440SBC2440V4#cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 /dev/vc/

17、0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 14 sound 81 video4linux 89 i2c 90 mtd 116 alsa 128 ptm 136 pts 180 usb 189 usb_device 204 s3c2410_serial 252 scull 253 usb_endpoint 254 rtc Block devices: 1 ramdisk 256 rfd 7 loop 31 mtdblock 93 nftl 96 inftl 179 mmc Tekkama

18、n2440SBC2440V4#mknod -m 666 scull0 c 252 0 Tekkaman2440SBC2440V4#mknod -m 666 scull1 c 252 1 Tekkaman2440SBC2440V4#mknod -m 666 scull2 c 252 2 Tekkaman2440SBC2440V4#mknod -m 666 scull3 c 252 3 启动测试程序 Tekkaman2440SBC2440V4#./scull_test write error! code=6 write error! code=6 write error! code=6 write

19、 ok! code=2 read error! code=6 read error! code=6 read error! code=6 read ok! code=2 0=0 1=1 2=2 3=3 4=4 5=5 6=6 7=7 8=8 9=9 10=10 11=11 12=12 13=13 14=14 15=15 16=16 17=17 18=18 19=19 改变量子大小为默认值 4000: Tekkaman2440SBC2440V4#cd /lib/modules/ Tekkaman2440SBC2440V4#rmmod scull Tekkaman2440SBC2440V4#ins

20、mod scull.ko 启动测试程序 Tekkaman2440SBC2440V4#./scull_test write ok! code=20 read ok! code=20 0=0 1=1 2=2 3=3 4=4 5=5 6=6 7=7 8=8 9=9 10=10 11=11 12=12 13=13 14=14 15=15 16=16 17=17 18=18 19=19 Tekkaman2440SBC2440V4# 改变量子大小为 6,量子集大小为 2: Tekkaman2440SBC2440V4#cd /lib/modules/ Tekkaman2440SBC2440V4#rmmod

21、scull Tekkaman2440SBC2440V4#insmod scull.ko scull_quantum=6 scull_qset=2 启动测试程序 Tekkaman2440SBC2440V4#./scull_test write error! code=6 write error! code=6 write error! code=6 write ok! code=2 read error! code=6 read error! code=6 read error! code=6 read ok! code=2 0=0 1=1 2=2 3=3 4=4 5=5 6=6 7=7 8=8 9=9 10=10 11=11 12=12 13=13 14=14 15=15 16=16 17=17 18=18 19=19

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。