设为首页 收藏本站
查看: 680|回复: 0

[经验分享] 《linux设备驱动详解》学习笔记(二)---字符设备驱动程序

[复制链接]

尚未签到

发表于 2016-4-5 10:17:50 | 显示全部楼层 |阅读模式
一、程序的基本构架如下:

1、头文件包含、宏定义

2、设备结构体(一般都包括cdev结构体与设备的其他参数)

3、用户接口定义(打开文件,关闭文件,写文件,读文件,定位文件等等)

4、用户接口结构体(struct file_operations)

5、加载模块

(1)申请结构体的内存

(2)初始化cdev以及设备的其他参数(cdev_init( ),register_chrdev_region( )静态申请设备号,alloc_chrdev_region( )动态申请设备号)

(3)向内核添加cdev(cdev_add( ))

6、卸载模块

(1)注销cdev(cdev_del( ))

(2)释放设备结构体的内存

(3)释放设备号(unregister_chrdev_region( ))

7、其他声明(MODULE_AUTHOR( )声明作者、MODULE_LICENSE( )声明证书等等)

二、以下就解释一下主要的几部分
1、设备结构体
/*globalmem设备结构体*/struct globalmem_dev{struct cdev cdev;/*cdev结构体*/unsigned char mem[GLOBALMEM_SIZE];/*全局内存*/struct semaphore sem/*并发控制用的信号量*/};一般设备结构体都会包含(1)cdev结构体,这是内核结构体,包含了设备号、文件操作结构体、所属模块等数据项(2)操控设备过程中要用到的一些变量或存储空间,比如并发控制需要用到的信号量或自旋锁、支持阻塞操作需要用到的阻塞等待队列头等等


2、用户接口结构体
/*file operation struct*/static const struct file_operations globalmem_fops={.owner=THIS_MODULE,.llseek=globalmem_llseek,.read=globalmem_read,.write=globalmem_write,.ioctl=globalmem_ioctl,.open=globalmem_open,.release=globalmem_release,};
用户程序主要是为用户服务,而驱动程序主要是为用户程序服务。因为用户程序是通过系统调用来实现某项功能,而驱动程序正是为用户程序提供这些系统调用。用户程序对一个设备的操作一般都不止一个,比如说用户程序对字符设备的操作有打开、定位、读、写、关闭等,而这么多的操作,它们对应的程序到底在哪里呢?所以需要一个(struct file_operations)用户接口结构体来管理着,这个结构体的每一项都是一个函数指针,都指向一个操作函数程序,用户如果需要对该设备进行什么操作,只要通过该结构体就可以找到该操作对应的程序在哪里。


3、加载模块
/*初始化并注册cdev*/static void globalmem_setup_cdev(struct globalmem_dev *dev,int index){int err,devno=MKDEV(globalmem_major,index);cdev_init(&dev->cdev,&globalmem_fops);dev->cdev.owner=THIS_MODULE;err=cdev_add(&dev->cdev,devno,1);if(err)printk(KERN_INFO "Error %d adding globalmem %d",err,index);}/*设备驱动模块加载函数*/int globalmem_init(void){int result;dev_t devno=MKDEV(globalmem_major,0);/*申请设备号*/if(globalmem_major)result=register_chrdev_region(devno,1,"globalmem");else{/*动态申请设备号*/result=alloc_chrdev_region(&devno,0,1,"globalmem");globalmem_major=MAJOR(devno);}if(result<0)return result;/*动态申请结构体的内存*/globalmem_devp=kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL);if(!globalmem_devp){/*申请失败*/result=-ENOMEM;goto fail_malloc;}memset(globalmem_devp,0,sizeof(struct globalmem_dev));globalmem_setup_cdev(globalmem_devp,0);init_MUTEX(&globalmem_devp->sem);/*初始化信号量*/return 0;fail_malloc:unregister_chrdev_region(devno,1);return 0;}
一般加载模块的主要工作有二:
(1)初始化设备结构体,即初始化cdev结构体和操控设备过程中要用到的一些变量或存储空间,不过在初始化cdev结构体之前,你需要通过静态或动态的方式申请号主设备号;
(2)向系统添加该设备,系统会对cdev和设备号有个登记的,这样用户程序才能通过系统来使用该设备。


4、卸载模块
/*模块卸载函数*/void globalmem_exit(void){cdev_del(&globalmem_devp->cdev);/*注销cdev*/kfree(globalmem_devp);/*释放设备结构体内存*/unregister_chrdev_region(MKDEV(globalmem_major,0),1);/*释放设备号*/}
卸载模块主要是对设备结构做善后处理,释放设备结构体的内存,不过释放前要先注销cdev,释放后要释放设备号,因为这两者在你加载进去的时候,系统都有记录的。比如小车开进某个小区时,需要要登记你的车牌号表示你进入该小区,离开时你需要让门卫将你的车牌号从登记表上划掉,表示你离开了该小区。


5、出入口
module_init(globalmem_init);module_exit(globalmem_exit);
用户程序都会使用main函数来告知系统该程序应该从哪里执行,驱动程序同样也有,它是通过module_init和module_exit来告知系统应该从哪里进入,从哪里出来。
三、完整代码会在《并发控制》那一篇blog贴出


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-199884-1-1.html 上篇帖子: centos6配置本地光盘yum源、rhel7修改网卡名称为eth0 下篇帖子: CentOS系统启动流程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表