字符设备驱动程序.doc

上传人:hw****26 文档编号:4206601 上传时间:2019-10-04 格式:DOC 页数:12 大小:121KB
下载 相关 举报
字符设备驱动程序.doc_第1页
第1页 / 共12页
字符设备驱动程序.doc_第2页
第2页 / 共12页
字符设备驱动程序.doc_第3页
第3页 / 共12页
字符设备驱动程序.doc_第4页
第4页 / 共12页
字符设备驱动程序.doc_第5页
第5页 / 共12页
点击查看更多>>
资源描述

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个工作日内予以改正。