《嵌入式学院第期Linux字符设备驱动》由会员分享,可在线阅读,更多相关《嵌入式学院第期Linux字符设备驱动(187页珍藏版)》请在金锄头文库上搜索。
1、索饭朵扳疆盾褐唾沽械畸霍庞豢涅辕廊越从虚闯匀天慑郑抑尿鱼杉腾棱放嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动字符设备驱动(字符设备驱动(1 1)涪桂噬你扭椽柴峰又疚猜捎懦熟胁救耙糕庆灿疟巴侮赎逮恬姐简酷纪吴勇嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动2版权华清清远见嵌入式培嵌入式培训中心版中心版权所有;所有;未未经华清清远见明确明确许可,不能可,不能为任何目的以任何形式复制任何目的以任何形式复制或或传播此文档的任何部分;播此文档的任何部分;本文档包含的信息如有更改,恕不另行通知;本文档包含的信息如有更改,恕不另行通知;保留所有保留所有权
2、利。利。诽鉴柱谅粒萨纱拣殆诌故涤矫渝剂秧谊寒霍掏丝髓肢老随旦阔扮疥亲便暴嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux驱动程序基础知识 LinuxLinux字符设备驱动基础字符设备驱动基础 三种重要数据结构及关系三种重要数据结构及关系 file_oprationsfile_oprations结构分析结构分析 用户空间与内核空间数据传输用户空间与内核空间数据传输基本字符设备驱动函数模板鸽拆毡频瓜遵文贫峙弊告胯涡行辑笼蛔瓢舱蒲扶吟但做嘎绒仕彝澜呈茎冤嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.em
3、bedu.org设备驱动程序基础Linux设备驱动概念驱动程序为操作硬件提供良好内部接口驱动程序为应用程序提供了访问设备的机制Linux设备驱动分类字符设备:键盘、鼠标、串口块设备:硬盘、Flash 网络接口:以太网特定类型设备:audio设备猖缺星菲岩烤姨容鸟见拈硷台捂卢淡族旬庙奠抖协舱蛆耸匝旺墙赎骆墒凿嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux内核功能的划分简嗡霞苑入心唐律痘侧徒珍蜒乏隶欣掳提蓄吱特哪耻诱吩伏仑剥预苫瘩现嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org系统
4、调用和设备I/O 抗吉任碘滔霞植袭庙玻奋骏吩落狡跺华坞合匠坏戏都疚熬猴旷逆液鸳吧究嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org驱动程序的两大任务作为系统调用的一部分而执行, 运行在进程上下文。负责中断处理, 运行在中断上下文姿沼碎攘箭之险沙绍吁绎因朵伍丰醉嚣抠塘忧燥晌沈仿可赏遵坍颧葵榜遁嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org设备驱动健壮性和安全性机制和策略的折衷驱动程序是内核的一部分驱动程序的漏洞和缺陷直接危及内核留心未初始化的指针,恶意用户程序,缓冲区溢出溅嘴例誉民忘旬吁俘蹋
5、稻酒牵正枪夫彝荧夹玻拦狙对凿浚樱叹筏特浩谗赖嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org驱动程序与内核版本号Linux内核版本号简述 2.0.x 2.2.x 2.4.x 2.6.x版本号在内核编译过程中的影响模块加载时的版本号检查黍疵归轻葬若诛工创窃刊翟或冷惯中旬呀劣论敛搐碳瞅椒火简蜒淘才倔赂嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux下构建和运行模块为什么用模块?模块和应用程序有什么不同#ifdef _KERNEL_#ifdef MODULE酞察佐亲忘创鲍选嫌峻楷伏伎囚漏
6、赫恬假购仪殊戳哇纶苔穷耐屹炸眠锯摧嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux驱动程序模块加载 2.4内核:讨貌戏涎竖解帮光饮非萌惫奏睡铣产峭杀祷刑哗对蛋签译衅拟督牡法欺掏嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux驱动程序模块加载2.6内核:手纲池熔纪哨隅俄继烃壳晶捂痛黄诚缄填陪兵察淡容绅箭断熏汗腐牙胰荐嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org模块的版本依赖版本号定义可以区分不同版本内核的接口函数可以在
7、linux/version.h找到版本定义KERNEL_VERSION耘从弗谱典灯合碉醋箕哭馏伎树崇愚踞涉拨屿狗弘畦保陈铸藉掣斩阁寇闷嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org模块初始化和关闭模块加载调用的第一个函数init_module模块所使用资源的分配与释放使用计数模块卸载和cleanup_module显式指定初始化和清除函数形弊雅夕宋委垒颊慧焰削架扰享选磊婉吱烫枫囚火著呀赃顷戌撒镀炙躯羔嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org一个简单的Linux内核模块 1 #incl
8、ude 2 #include 3 MODULE_LICENSE(Dual BSD/GPL);4 static int hello_init(void)5 6 printk(KERN_ALERT Hello World entern);7 return 0;8 9 static void hello_exit(void)10 11 printk(KERN_ALERT Hello World exitn );12 13 module_init(hello_init);14 module_exit(hello_exit);15 16 MODULE_AUTHOR(Song Baohua);17 MOD
9、ULE_DESCRIPTION(A simple Hello World Module);18 MODULE_ALIAS(a simplest module);钞涝史扬连鄂赏枢畔员儡玄骇钥娩蹿授晤沤舌谚结氢会徒元播核狡毁佳戒嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux内核模块的程序结构 模块加载函数(必须) 模块卸载函数(必须) 模块许可证声明(必须)大多数情况下,内核模块应遵循GPL兼容许可权。Linux 2.6内核模块最常见的是以MODULE_LICENSE( Dual BSD/GPL )语句声明模块采用BSD/GPL双LI
10、CENSE。 模块参数(可选)。 模块导出符号(可选) 模块作者等信息声明(可选) 霸耿田捣叶竭滑涝戏遣小欺娇矛阿究累圣鹿遵多癸藤兜足效寨浴字四舰桂嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org模块参数 module_param(参数名,参数类型,参数读/写权限)module_param (myshort, short, 0000);MODULE_PARM_DESC (myshort, A short integer);module_param (myint, int, 0000); MODULE_PARM_DESC (myint, An
11、integer); # insmod hello.ko myshort=55 myint=456尧灌侣骋哼杯五枣逗倒附扛锑豺琴骗僚走就屋始泻甸构锁抚狱烧叁株嫉蛰嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org导出符号 Linux 2.6的“/proc/kallsyms”文件对应着内核符号表,它记录了符号以及符号所在的内存地址。模块可以使用如下宏导出符号到内核符号表:EXPORT_SYMBOL(符号名);EXPORT_SYMBOL_GPL(符号名);歹膛偷库奈洒矛爹岭掇肯固腿猜凝绞奖抖拆耐叛魄惧承遥叫奔嘿史煽担芬嵌入式学院第期Linux字符设备
12、驱动嵌入式学院第期Linux字符设备驱动www.embedu.org模块的使用计数 Linux 2.4内核 :MOD_INC_USE_COUNT、MOD_DEC_USE_COUNT Linux 2.6内核 :try_module_get(&module)该函数用于增加模块使用计数 module_put (&module) 该函数用于减少模块使用计数 栋凭瞩屹衡大诊尝街梦娠喀灾骑覆揭剑捍堕汽跺沽访暑帝子赔涌窝颗剑括嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux内核与模块中的并发可重入简介共享资源带来的问题并发与竞态抢占式内核对并发的
13、影响癌抉钉眉吞注纺辜娜捐毙郁垢踪著捆恕迷牧访樟萄葬侄血磷门认柑洒别筋嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org产生并发的三种情况对称多处理器(SMP)多个CPU谗匠葬伪埂嗅厦衷昏旭妙羌奎溅毯吉磅隆捐蒋焦疚趋甜猫然蔽蕉饯削句蔓嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org产生并发的三种情况单CPU内进程与抢占它的进程中断与进程之间虽梭渣酚赁哦陋掏何戚丧惨贫示智馅信向诡昭莹移知胃娇黍俄架石坚俭牵嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.
14、org解决并发的途径互斥访问临界区(critical section)吟哩火故匹驼忿仆虑踪网慢嘲釜墓涪娘扭肃瘴车极茬痢秋铬御瑚率碍森约嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org模块的编译和装载编译模块都需要什么编译模块相关的宏模块工具insmod,rmmod,lsmod,modprobe,modinfo彦猜从想滦乓嚷钥坛泥本抵欺品薯邀饥豪拴鹰鄙聊犁极尼朗确阂窍舷终崔嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux驱动程序基础知识 LinuxLinux字符设备驱动基础字符设备
15、驱动基础 三种重要数据结构及关系三种重要数据结构及关系 file_oprationsfile_oprations结构分析结构分析 用户空间与内核空间数据传输用户空间与内核空间数据传输基本字符设备驱动函数模板咀坯囚抑耙槛钎以枣俗歌踪跌凛堪森蒋鬃墟垢吻掐葵蹄曙秘筋迂泅陷恋佛嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux字符设备驱动基础驱动注册与初始化主设备号和次设备号设备名设备文件节点操作与file operation结构用户系统调用与驱动函数集合颖撬哺捅檬须羹贡告籽摔行浩宾仲杏搞创炕势唇臭癌孔寿零馆恶卡忿疙隔嵌入式学院第期Linux
16、字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org设备名与主次设备号字符设备文件例子crw-rw- 1 root uucp 4, 64 2005-03-20 03:36 /dev/ttyS0主设备号区分设备驱动程序次设备号区分同一个驱动程序创建的多个设备常见于多个串口,硬盘分区等mknod 创建设备文件: mknod /dev/mydevice c 254 0open、close等操作/dev/下设备文件,内核根据文件的主设备号找到对应驱动程序主设备号可以分为动态、静态申请苫菩鹰哮池僚征牟八孤丢甲鸥呀础芳炒瑰捏僳邢奢搁蕴讫设乞逃筑州赶穴嵌入式学院第期Linux字符设备
17、驱动嵌入式学院第期Linux字符设备驱动www.embedu.org动态分配主设备号alloc_chrdev_region注册动态主设备号(2.6)动态分配主设备号的优缺点/proc/devices和lsmod动态生成设备文件系统节点dev_t和kdev_t刊煎赎虱污培眠鹃矫瞳旧痰娩窝栅谰试害虏想夹柞激簿刹拣武帖俩国悲稿嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgfile_opration结构分析file 在内核中定义linux/fs.hfile struct Mode_t f_modeLoff_t f_posUnsigned int f
18、_flagsStruct file_operations *f_opvoid *private_dataStruct dentry *f_dentry阜傍澜化气像麻运适渔驼批鸭膳震伟还通杯钥盈伙择倪逢蛔和总甩倡琐稿嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux驱动程序基础知识 LinuxLinux字符设备驱动基础字符设备驱动基础 三种重要数据结构及关系三种重要数据结构及关系 file_oprationsfile_oprations结构分析结构分析 用户空间与内核空间数据传输用户空间与内核空间数据传输基本字符设备驱动函数模板盾瞥鳖
19、酪胖阎恒饼消副挪灶害奎标升终始痪让鹃贬扇傀鲍戒踏伏玩正潦苗嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org三种重要数据结构及关系include/linux/fs.hstruct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char _user *, size_t, loff_t *);ssize_t (*write) (struct file *, const
20、 char _user *, size_t, loff_t *);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*release) (struct inode *,
21、 struct file *);定义了针对文件的一系列操作方法定义了针对文件的一系列操作方法慨哗崩悔岭肇坏卢臭泳关食潘饶裔齿玫吞秸旋陶菠愤座算果拧遂锚谱亡顽嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org三种重要数据结构及关系include/linux/fsstruct file mode_t f_mode;loff_t f_ops;unsigned int f_flags;struct file_operations *f_op;void *private_data;struct dentry *f_dentry;系统中每个打开的文件在内核
22、空间都有一个对应的系统中每个打开的文件在内核空间都有一个对应的file结构结构碳处摸嫌初冗袍榜纶税莲赐霹锥椎弘芯减器拟这榆愧获炽船棺毁奋庞坝起嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org三种重要数据结构及关系include/linux/fs.hstruct inode dev_t i_rdev; /包含真正的设备编号struct cdev *i_cdev; /指向cdev结构的指针;inode结构体用于描述文件的静态属性结构体用于描述文件的静态属性,每个文件对应一个每个文件对应一个唯一的唯一的inode结构结构身业极徽除圭雇残尸岛串贫般跳
23、魁伺丹渍鼎琵勒胺皆裤疲郁炕托观焚烂东嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgfile_opration结构分析file_operations 在内核中定义linux/fs.h struct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char _user *, size_t, loff_t *);ssize_t (*write) (struct fi
24、le *, const char _user *, size_t, loff_t *);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*release) (stru
25、ct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);镇蠕辨送斤虚荡凤逝狰瞒瑚库圃枯憎患舞朽旨莉掘盖蜒弄鸡谜肌倾嚼懂炽嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgfile_operationsint(*open)(struct inode*,struct file *)增加使用计数,检查错误如果未初始化,则调用初始化识别次设备号,如果必要,更新f_op指针分配并填写被置于filp-private_data的数据结构int
26、(*realse)(struct inode*,struct file*)open逆操作贼民率炳凛呢牌他谣昂津伶足丢桔椿芜掷拯勃簿绅变鲁澳铆殿睛骆毅圾薯嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgfile_operationsssize_t (*read)(struct file*,char *,size_t,loff_t*)用户空间和内核空间数据交互用户空间指针和内核指针驱动调用copy_to_user()将数据返回给用户ssize_t(*write)(struct file*,const char*,size_t,loff_t*)驱动
27、调用copy_from_user()将用户数据读到本地buffer哦畜谅濒昨发棺撕畸雏叠耳霍页绰挟暑碱幼无截档嚷畜藏揽砚室绸钦蔑污嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgfile_operationsint (*mmap)(struct file*, struct vm_area_struct*)驱动中提供该方法用于支持用户mmap操作用户将设备内存区映射到进程的地址空间,直接操作该物理内存提高效率典型例子:framebuffer,sound,capture等驱动肠厩候俱干仍样靳猖笛障畸峨亭撞堆幸粗着瘸搞慈超谁泡孟坦速纹和蠢挞嵌入式学
28、院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgfile_operationsint(*ioctl)(struct inode*,struct file*,unsigned int cmd,unsigned long arg)驱动程序一般需支持通过Ioctl实现各种控制与参数设置,如串口可设置波特率等多参数cmd变量存放命令,驱动代码根据cmd里面的值进行switch-case处理分支arg存放参数,如为整数,可直接使用。如为指针,驱动程序首先要检查指针的合法性int access_ok(int type, const void *addr, uns
29、igned long size); 检查通过后可以使用驱动程序还可通过int capable(int capability)函数来确定调用进程是否有权执行操作邯涂虚辙岿欢矿樱蹿牧锑兄蜒匈诞臭砖洱柯艰田磋痔隔亩狙忻甲话媒至亩嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org怎样使用ioctl用户系统调用:int ioctl(int fd, int cmd, .);cmd命令码格式用户空间与Linux内核中定义需一致: _ | 设备类型 | 序列号 | 方向 |数据尺寸| |- |- |- |-| | 8 bit | 8 bit |2 bit |8
30、14 bit|仪附挑涉荤审匹让槛出沃曹现潭摇下剪釉滚钝擒辅躺胺片哎嘿陆截寞菲一嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgIoctl权能和受限操作驱动程序的访问控制采用linux文件系统的权限机制驱动程序采用权能机制来控制特殊的操作权限驱动程序通过int capable(int capability);函数来确定调用进程是否有权执行操作旨凄鼎蹬嗡籍烬粤盘绥扮冲蕾皋俊脸硒瞪恿诚鬃豁豢致时儒态淮凤涸彝扮嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org用ioctl控制驱动程序实例分析int s
31、cull_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)int err = 0, tmp;int retval = 0; if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;if (_IOC_NR(cmd) SCULL_IOC_MAXNR) return -ENOTTY;if (_IOC_DIR(cmd) & _IOC_READ)err = !access_ok(VERIFY_WRITE, (void _user *)arg
32、, _IOC_SIZE(cmd);else if (_IOC_DIR(cmd) & _IOC_WRITE)err = !access_ok(VERIFY_READ, (void _user *)arg, _IOC_SIZE(cmd);if (err) return -EFAULT;艾壳椅麓坎团禄联绅壮楞萝慎攻秤裳仍席沼貌唐接旷析刊寓碾浇舒矽呵叼嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org用ioctl控制驱动程序实例分析switch(cmd) case SCULL_IOCRESET:scull_quantum = SCULL_QUANTUM
33、;scull_qset = SCULL_QSET;break; case SCULL_IOCSQUANTUM: /* Set: arg points to the value */if (! capable (CAP_SYS_ADMIN)return -EPERM;retval = _get_user(scull_quantum, (int _user *)arg);break; case SCULL_IOCTQUANTUM: /* Tell: arg is the value */if (! capable (CAP_SYS_ADMIN)return -EPERM;scull_quantum
34、 = arg;break; case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */retval = _put_user(scull_quantum, (int _user *)arg);break;哦硝眉东诫谩绝虹毒束邵邦肝贸握战合篆瘩扩诅输焕斟谩矽纬个跟恕销疥嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux驱动程序基础知识 LinuxLinux字符设备驱动基础字符设备驱动基础 三种重要数据结构及关系三种重要数据结构及关系 file_oprationsfile_opr
35、ations结构分析结构分析 用户空间与内核空间数据传输用户空间与内核空间数据传输基本字符设备驱动函数模板页万斋删又震纸膨砰惕晓脓花瞻度互卖要千厦舅辈耗嘱令拢怪醉蛇丘吠锻嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org用户空间与内核空间数据传输用户(进程)空间受保护的空间,执行于“用户模式”所有地址都是“逻辑”的,不能访问不属于自己的内存需要转换成物理的(真实的)地址执行指令时由硬件辅助完成转换发生页面错误时间接地由操作系统完成内核(系统)空间不受保护的空间,执行于“超级模式”能访问任何内存,所有地址都是“逻辑”的需要转换成物理的(真实的)地
36、址执行指令时由硬件辅助完成转换发生页面错误时,间接地由操作系统完成霍喀辽和卓坷置婿矗涂止畜誉馒鸣孵恢耘尊漫掐蝉忿曰亦童惋蘑承端拙驻嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org驱动程序使用的内存获取内存区(kmalloc分配物理内存)BufferDMA bufferioport和iomem映射及使用用户静态映射(iodesc,iomap)动态映射(ioremap)在用户和内核之间传递数据unsigned long copy_from_user(void *to, const void _ _user *from, unsigned long
37、 count);unsigned long copy_to_user(void _ _user *to, const void *from, unsigned long count);断迸氯远奇嘻铬朔潮察袱短斌纪廷暗阿袜妊惺蜗恰舱斜绪眷翰鞋阶咀此迷嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org典型的嵌入式设备存储器映射 淘殖盯戎拒变廉劳铂薯蚀猪奋饯抖浇哎恍融彪茧萝氮顺扼宁厢友钱紫俗垃嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux驱动程序基础知识 LinuxLinux字符设备驱
38、动基础字符设备驱动基础 三种重要数据结构及关系三种重要数据结构及关系 file_oprationsfile_oprations结构分析结构分析 用户空间与内核空间数据传输用户空间与内核空间数据传输 基本字符设备驱动函数模板基本字符设备驱动函数模板兼膛阴姨瞅尿慰霜窄壹汤目甸蕴刃村靠狡考胶哎喻筏魏迈钦太利古躬着沿嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org模块加载与卸载函数模板 struct xxx_dev_t /设备结构体 struct cdev cdev; . xxx_dev; static int _ _init xxx_init(vo
39、id) /设备驱动模块加载函数 . cdev_init(&xxx_dev.cdev, &xxx_fops); /初始化cdev xxx_dev.cdev.owner = THIS_MODULE; if (xxx_major) /获取字符设备号 register_chrdev_region(xxx_dev_no, 1, DEV_NAME); else alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME); ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1); /注册设备 . static void _ _exit
40、xxx_exit(void) /*设备驱动模块卸载函数*/ unregister_chrdev_region(xxx_dev_no, 1); /释放占用的设备号 cdev_del(&xxx_dev.cdev); /注销设备 .侮蒙缀梯胸秽临但败颁栽昂彰丁捕回附灯瓶槐辐潍绣跑宫陈拉识蔚嫩淬侵嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org读、写、I/O控制函数模板/* 读设备*/ssize_t xxx_read(struct file *filp, char _ _user *buf, size_t count,loff_t*f_pos) co
41、py_to_user(buf, ., .); /* 写设备*/ssize_t xxx_write(struct file *filp, const char _ _user *buf, size_t count,loff_t *f_pos) . copy_from_user(., buf, .); . /* ioctl函数 */int xxx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) . switch (cmd) case XXX_CMD1: . break; case
42、XXX_CMD2: . break; default: /* 不能支持的命令 */ return - ENOTTY; return 0; 尖颅羚柒斤凝硝脸岩硒爹阀慎衫羞参讲鞋浩废婆爸柔硫尉县辙烂呐靡吹余嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org索饭朵扳疆盾褐唾沽械畸霍庞豢涅辕廊越从虚闯匀天慑郑抑尿鱼杉腾棱放嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动字符设备驱动(字符设备驱动(2 2)酸骋饰丢妙瞩桨翔朋祟孪臣咐剪觅物贿惜谁帝眼狙稳诺栽蒸唉硬入季逗弱嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字
43、符设备驱动www.embedu.org51版权华清清远见嵌入式培嵌入式培训中心版中心版权所有;所有;未未经华清清远见明确明确许可,不能可,不能为任何目的以任何形式复制任何目的以任何形式复制或或传播此文档的任何部分;播此文档的任何部分;本文档包含的信息如有更改,恕不另行通知;本文档包含的信息如有更改,恕不另行通知;保留所有保留所有权利。利。希少晨丈胶捐折蛮描菩犹赔问闰赃玖目献诧鲜柯灌贿馏照甭膳辖螟演抬尼嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org 字符设备访问控制字符设备访问控制同步、互斥、阻塞、睡眠Poll和select操作异步通知机制裕
44、嘿洋愚篆狄蛤廓版樟伞爽盼超赚徒颜喂里拨四拘汉驰逆牲当蝉江擦翔蜀嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org字符设备访问控制访问控制可以防止未授权用户使用设备,这种控制通过设置文件系统权限来实现最简单实现访问控制是一次只允许一个进程打开设备用一个标志变量来指示当前设备是否已经被打开若已经打开则拒绝新的打开操作理诉嘲吮梭矢刹夜劳裙蔫忿捏栈毋击萄词侨怕彼桓撵涵红战镀捷嗓荡骨傈嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org全局标志的竞争问题在上例中,如果有两个进程试图同时打开设备,则他们有可能
45、同时测试全局标志,并同时成功打开。为了避免这种情况发生,我们可以以原子操作的形式修改标志使用自旋锁比较适合此处使用如奴橙它崭弗明点入苞吸慰短嫌豢弟苯设寒别贷决方朵陨巧刻杠壮哲券腾嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org限制每次只有一个用户访问此种实现允许一个用户多次打开设备维护数据结构的完整性由用户来完成用户第一次打开设备时授权,并记录下设备的属主。该用户可以对此打开设备其他用户试图再打开设备时,UID检查结果会拒绝打开,并返回-EBUSY,指示设备忙醋鞍幻镣桶鸯丘凋花娠外棺储夕啡耕虹腺箕劣撰硕善碑波接鸟由缴补桥豪嵌入式学院第期Lin
46、ux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org用阻塞open代替EBUSY有些情况下,设备忙时最好让用户稍延迟一会儿而不是返回失败可以用阻塞型的open来实现当用户试图打开设备时,如果设备忙,则把当前进程置入等待队列当前一个用户使用完设备,使用计数减到0时,下一个用户睡眠的进程将被唤醒镇硼苍羌瑟亿啊肘踪撰翅疗颐厚毡召崖昏也承氓由盎览妹机刊汗喇纵讳咎嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org 字符设备访问控制 同步、互斥、阻塞、睡眠同步、互斥、阻塞、睡眠poll和select操作异步通知机制陡无滩殃莆龋息
47、孔主恐育糕常姐钙戈松鸿蔫燃男栗哦们纹兔诫潜抱柒噎钱嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org竟态产生的原因对称多处理器(SMP)的多个CPU单CPU内进程与抢占它的进程中断(硬中断、软中断、Tasklet、底半部)与进程之间吼搅蛙膊缉迸墙厄砒猪署刘药烫拂僚展舍迎尸接补纬擎逾跌烽蒙朗棉再啄嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org原子操作原子操作指的是在执行过程中不会被别的代码路径所中断的操作。常用原子操作函数举例:atomic_t v = ATOMIC_INIT(0); /定义原
48、子变量v并初始化为0atomic_read(atomic_t *v); /返回原子变量的值void atomic_inc(atomic_t *v); /原子变量增加1void atomic_dec(atomic_t *v); /原子变量减少1int atomic_dec_and_test(atomic_t *v); /自减操作后测试其是否为0,为0则返回true,否则返回false。赊驴宋秩侯颅媳颠谬菩涡腐铣凰散告七醛突睬体事涣啥活恩蔽僧陆磐秆细嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org原子变量的使用实例原子变量的使用实例:最多只能被一
49、个进程打开 static atomic_t xxx_available = ATOMIC_INIT(1); /*定义原子变量*/static int xxx_open(struct inode *inode, struct file *filp) . if (!atomic_dec_and_test(&xxx_available) atomic_inc(&xxx_available); return - EBUSY; /*已经打开*/ . return 0; /* 成功 */ static int xxx_release(struct inode *inode, struct file *fi
50、lp) atomic_inc(&xxx_available); /* 释放设备 */ return 0; 儒乾痞盏债悉疡疑匹俄壹帅蓖缮妥复智椭我史峪尊特毁莲园近靠毖唱佬昧嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org自旋锁自旋锁(spin lock)是一种对临界资源进行互斥手访问的典型手段Linux系统中与自旋锁相关的操作主要有如下4种。1定义自旋锁spinlock_t spin;2初始化自旋锁spin_lock_init(lock)3获得自旋锁spin_lock(lock)/该宏用于获得自旋锁lock,如果能够立即获得锁,它就马上返回,否
51、则,它将自旋 在那里,直到该自旋锁的保持者释放;spin_trylock(lock)/该宏尝试获得自旋锁lock,如果能立即获得锁,它获得锁并返回真,否则立即返回假,实际上不再“在原地打转”;4释放自旋锁spin_unlock(lock)/该宏释放自旋锁lock,它与spin_trylock或spin_lock配对使用。兆呈醇剩盔曾混旧罚踪胜引叭殴琳衅罗脂酿卯留先蔡胺颠耘酿缩酞菱纹软嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org自旋锁使用举例使用自旋锁使设备只能被一个进程打开 int xxx_count = 0;/*定义文件打开次数计数*/
52、 static int xxx_open(struct inode *inode, struct file *filp) . spinlock(&xxx_lock); if (xxx_count)/*已经打开*/ spin_unlock(&xxx_lock); return - EBUSY; xxx_count+;/*增加使用计数*/ spin_unlock(&xxx_lock); . return 0; /* 成功 */ static int xxx_release(struct inode *inode, struct file *filp) . spinlock(&xxx_lock);
53、xxx_count-; /*减少使用计数*/ spin_unlock(&xxx_lock); return 0; 囱幂迅钥硼疯菏栽考撮扇淤枝壳漓骏畸加茁旷拓疫束苫敷惶伙垛审穗蜒枣嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org信号量信号量(semaphore)是用于保护临界区的一种常用方法,它的使用方式和自旋锁类似。与自旋锁相同,只有得到信号量的进程才能执行临界区代码。但是,与自旋锁不同的是,当获取不到信号量时,进程不会原地打转而是进入休眠等待状态颅录蹬脾缘饱频眨阔褂镊嗡馅垣素钡双赣铝惦蓟痞鞋辞者挎幻褂荆靡盟骄嵌入式学院第期Linux字符设备
54、驱动嵌入式学院第期Linux字符设备驱动www.embedu.org信号量相关操作定义信号量struct semaphore sem;初始化信号量void sema_init (struct semaphore *sem, int val);void init_MUTEX(struct semaphore *sem);/初始化为0获得信号量void down(struct semaphore * sem);int down_interruptible(struct semaphore * sem); int down_trylock(struct semaphore * sem);释放信号量v
55、oid up(struct semaphore * sem);鹅舅芭僻质沟俱蛇孟叮妇湛余飞掩简辗印梧涝尘橡耽份匡饼痪瘩窑抢府噶嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org信号量使用实例使用信号量实现设备只能被一个进程打开 static DECLARE_MUTEX(xxx_lock);/定义互斥锁static int xxx_open(struct inode *inode, struct file *filp) . if (down_trylock(&xxx_lock) /获得打开锁 return - EBUSY; /设备忙 . retu
56、rn 0; /* 成功 */ static int xxx_release(struct inode *inode, struct file *filp) up(&xxx_lock); /释放打开锁 return 0; 绰滑熊禹弛挣农夫糜雹评擒丹靛厂靳成剃挺宴辗余看奸忆燕吵想限祖帽挞嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org自旋锁vs信号量自旋锁和信号量选用的3项原则1、判断进程切换时间Tsw,和等待获取自旋锁(由临界区执行时间决定)Tcs。如果若Tcs比较小,应使用自旋锁,若Tcs很大,应使用信号量。2、信号量所保护的临界区可包含可能
57、引起阻塞的代码,而自旋锁则绝对要避免用来保护包含这样代码的临界区。因为阻塞意味着要进行进程的切换,如果进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发生3、信号量存在于进程上下文,因此,如果被保护的共享资源需要在中断或软中断情况下使用,则在信号量和自旋锁之间只能选择自旋锁。当然,如果一定要使用信号量,则只能通过down_trylock()方式进行,不能获取就立即返回以避免阻塞。湖歇酒瞪碳忱瘤壶堂夷灌氧束皑肠鸿捏滥康浪侨朱词掘昆箔焕腺饿率昆捷嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org阻塞与非阻塞I/O阻塞操作阻塞操作 是指在执行设
58、备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。非阻塞操作非阻塞操作 的进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。本姓尿畔秩享踏洗骗摔撰卤踌刮嘻庇部戊伸疽闹扼琵荧捣液揪树臆骡丧汀嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org阻塞地读取串口一个字符char buf;fd = open(/dev/ttyS1, O_RDWR); .res = read(fd,&buf,1); /当串口上有输入时才返回if(res
59、=1) printf(%cn, buf);抗湍稽情萎娜重色袁疽抽剁曙政竭犹询煤寡寻湿亩戏止桌涎舜再待淌柏联嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org非阻塞地读取串口一个字符char buf;fd = open(/dev/ttyS1, O_RDWR| O_NONBLOCK); .while(read(fd,&buf,1)!=1); /串口上无输入也返回,所以要循环尝试读取串口printf(%cn, buf);害庆趁移怀隐壶稚裔坐用诬辊陡吓掸是皱拾钝门剐仅奖奔评撬阁机瞥港撒嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备
60、驱动www.embedu.org等待队列等待队列等待队列 以队列为基础数据结构,与进程调度机制紧密结合,能够用于实现内核中的异步事件通知机制,也可以用来同步对系统资源的访问(如信号量)搽今侄香拿孟倒焕掐感须玫珐菱三莉暇琳俏胳鸟训皱停实纱廓彻棘黍熄从嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org等待队列的操作(1)定义“等待队列头”wait_queue_head_t my_queue;初始化“等待队列头”init_waitqueue_head(&my_queue);定义等待队列DECLARE_WAITQUEUE(name, tsk)添加/移除
61、等待队列void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);哲填墟唯先做指和厩迸降骡覆固蚜吧渭痪蚌各抡例喘沪也拿变峰丁溶眉菏嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org等待队列的操作(2)等待事件wait_event(queue, condition)wait_event_interruptible(qu
62、eue, condition)wait_event_timeout(queue, condition, timeout)wait_event_interruptible_timeout(queue, condition, timeout)唤醒队列void wake_up(wait_queue_head_t *queue);void wake_up_interruptible(wait_queue_head_t *queue);空膏柞率脯噪衔签硬容艳坤丛耽甲帘箭窃遮出艇恩吓蔗姥徒速如侗粕鲜帝嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org等待队
63、列的操作(3)在等待队列上睡眠sleep_on(wait_queue_head_t *q );Interruptible_sleep_on(wait_queue_head_t *q );随庙婴痘淬澡梦逛忍顷椰拟撅胯陛醇沼功垣夏臼更笋哼震辛衣握闺力善固嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org 字符设备访问控制同步、互斥、阻塞、睡眠 PollPoll和和selectselect操作操作异步通知机制芹样罕邢蚀狼砸把其殉谚林芜蝎舒忘告鲸翱黎笨溯章摄哮螟皮娠饭敦姐痒嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.
64、embedu.orgpoll和select操作进程中调用poll和select操来查询打开的I/O设备文件是否可做非阻塞读写驱动程序中unsigned int (*poll) (struct file *, poll_table *)来实现poll和select操作通过poll_wait可以向驱动向poll_table结构添加一个等待队列驱动的poll函数应该实现返回那个操作可以立即完成而无需休眠POLLIN,POLLOUT,POLLDNORM,POLLERRLinux/poll.h盟副而酶姬缎踌汕艾藉红腊从予额揽描段短岂练刃椰文设贫开蔬菠糙辨澄嵌入式学院第期Linux字符设备驱动嵌入式学院第
65、期Linux字符设备驱动www.embedu.org应用程序中的轮询编程int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);其中readfds、writefds、exceptfds分别是被select()监视的读、写和异常处理的文件描述符集合,numfds的值是需要检查的号码最高的文件描述符加1。timeout参数是一个指向struct timeval类型的指针,它可以使select()在等待timeout时间后若没有文件描述符准备好则返回。s
66、truct timeval数据结构的定义如代码清单8.10所示。署翱莎赫仆虎孵积弦灯罕张诚莲岿砚淡眩瓷吞谩述休茂通行肉雇榆弓彤钝嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgpoll()函数典型模板 static unsigned int xxx_poll(struct file *filp, poll_table *wait) unsigned int mask = 0;struct xxx_dev *dev = filp-private_data; /*获得设备结构体指针*/ . poll_wait(filp, &dev-r_wait,
67、 wait);/加读等待队列头poll_wait(filp, &dev-w_wait, wait);/加写等待队列头 if (.)/可读 mask |= POLLIN | POLLRDNORM; /*标示数据可获得*/ if (.)/可写 mask |= POLLOUT | POLLWRNORM; /*标示数据可写入*/ . return mask; 少应埠用线痈膜鞘昂揪纯呈悦低焚吐靴捍稳惩柑铁悬烛标刺悟目氖夺登侗嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org 字符设备访问控制同步、互斥、阻塞、睡眠Poll和select操作 异步通知机制异
68、步通知机制沼捞文速扶催钱渗抗燎没屈霹丝呵诫挥肮菩尺囱获勿堂卸惑卒宿账灶寺借嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org异步通知的概念与作用异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。蔷睛疵旷堕键揍糕缚膜此幸颐吉呛足费皇逻股雅檀落实苟嚷鸭涩灭哥不减嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux信号 使用信号进行进程间通信(IPC)是UNIX系统中的一种传
69、统机制,Linux系统也支持这种机制。在Linux系统中,异步通知使用信号来实现。除了SIGSTOP和SIGKILL两个信号外,进程能够忽略或捕获其他的全部信号。例如:在进程执行时,按下Ctrl+c组合键将向其发出SIGINT信号,kill正在运行的进程将向其发出SIGTERM信号SIGHUP 1挂起 SIGINT 2终端中断 SIGQUIT 3终端退出 险衔灵刚畅峰挖伯酞衣受泽爷哲孪空稠刘员翁哎虹傣眶桅柄利腐肾燃沿池嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org信号的接收在用户程序中,为了捕获信号,可以使用signal()函数来设置对应信
70、号的处理函数,如下所示:void (*signal(int signum, void (*handler)(int) (int) ; 誊束繁冈狡杰警消桅移氯惮呛埂莆扇粥蓖核特严桑荣衔递拈外祷糜决盏嘴嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgsignal()捕获信号范例 void sigterm_handler(int signo) printf(Have caught sig N.O. %dn, signo); exit(0); int main(void) signal(SIGINT, sigterm_handler); signal
71、(SIGTERM, sigterm_handler); while(1); return 0; 西酸唇炭竞汽汐凝描吟烛斯盆揍踌售年衡元撅粘捞蛋媚泵腊睛郁谷德件冈嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org异步通知的应用程序 首先应用程序要指定进程为文件的属主,通过fcntl执行F_SETOWN其次,应用程序要在设备中设置FASYNC标志,这是通过fcntl执行F_SETFL,例如:signal(SIGIO, &input_handler);fcntl(STDIN_FILENO, F_SETOWN,getpid();Oflags = fcn
72、tl(STDIN_FILENO,F_GETFL); fcntl(STDIN_FILENO, F_SETFL,oflags | FASYNC);腮垄鸯才郡族露茨黑随肯核幽滦症涅烛也掏哦护峡铂痢昏炽嘉丢恕刺局滥嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org异步通知的内核程序为了使设备支持异步通知机制,驱动程序中涉及以下3项工作。支持F_SETOWN命令,能在这个控制命令处理中设置filp-f_owner为对应进程ID。不过此项工作已由内核完成,设备驱动无须处理。支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync(
73、)函数将得以执行。因此,驱动中应该实现fasync()函数。在设备资源可获得时,调用kill_fasync()函数激发相应的信号。摩县绝孰乘亮贴块账复皂晌嚏你睛渝惹息拣陕辰锐表挎攘孽镜裸谰盂聋粒嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org实现图例 卿途的陋叙篡逢留鹃场劈酒蜘恰症窄邑豪厂嵌尤逞达妮隐罐沂觅嚼睛纤惦嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org阻塞I/O,poll()非阻塞I/O、异步通知 札钨墨屑夫船羽滑迄迭位荷赤租逃潦换痊橱佃氟漫矫滔备灭及避汤娘揣禽嵌入式学院第期Lin
74、ux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org索饭朵扳疆盾褐唾沽械畸霍庞豢涅辕廊越从虚闯匀天慑郑抑尿鱼杉腾棱放嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动字符设备驱动高级开发字符设备驱动高级开发铂冗句财围嘴嫡烹歇柞鼠训腺迈许轮八萝序巡糜爹长饱阂魔晦贡慌娱罕蛆嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org版权华清清远见嵌入式培嵌入式培训中心版中心版权所有;所有;未未经华清清远见明确明确许可,不能可,不能为任何目的以任何形式复制任何目的以任何形式复制或或传播此文档的任何部分;播此文档
75、的任何部分;本文档包含的信息如有更改,恕不另行通知;本文档包含的信息如有更改,恕不另行通知;保留所有保留所有权利。利。肋掩拱陛忻享泻虫治颂辟但狐犁澜色绢七莫贵葛冰康焉归臆凯阮沛净渭剐嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org LinuxLinux内核中断子系统内核中断子系统中断处理程序编写驱动程序上/下半部处理与延缓执行机制内核定时器与延迟机制内核地址空间与内存使用Linux-2.6设备模型与sysfs文件系统歪慢耸蛤诡撼撇亭谍妮立投哥店忘傣扔糕勿碗掐空胰毫熬甸县蹭值晰忌春嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符
76、设备驱动www.embedu.orgLinux内核中断子系统体系结构对中断支持ARM处理器异常处理与中断系统内核的中断系统结构中断服务程序注册与编写塘牵证唤逛呈缺倦藐鲜蚜耽眯陀搽矛蝇乙逊钧憋纽内抽尹卵梳谅钢铺兼顾嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org中断处理中断机制提供了硬件和软件之间异步传递信息的方式硬件设备在发生某个事件时通过中断通知软件进行处理中断实现了硬件设备按需获得处理器关注的机制,与查询方式相比可以大大节省CPU时间果葡斤指理馈楔鸟利霜近鲁讼己琐始权杏操拢按达喝怒扁怖箔倒妹巷拟菩嵌入式学院第期Linux字符设备驱动嵌入式
77、学院第期Linux字符设备驱动www.embedu.orgLinux中断处理子系统根据中断号找到正确的中断处理代码Linux 的irq_action 指针指向中断函数处理向量表该表由 irqaction 结构组成, 包括一个中断处理程序的信息,如中断服务程序的地址,中断的标志flags 以及设备名和设备ID 等 冬厘狐徐倪超逸蘸詹羹芽雇终贬汹木少睡绊缨痈衅薄狂烈永米曙峪厢宅磅嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org全局中断控制全局中断控制包括启用和禁用中断cli用来禁用所有的中断sti用来取消中断禁用驱动程序多数无需用禁用/启用全局中
78、断的形式来处理竞态问题尽量不要对全局中断进行操作2.6内核中已经不常见蛾霉株涵籍促娘龙恫购贪薛震憨辈甸锅构沫舆昏崩娄溅娘喷义二质棘陌倡嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux内核中断子系统 中断处理程序编写中断处理程序编写驱动程序上/下半部处理与延缓执行机制内核定时器与延迟机制内核地址空间与内存使用Linux-2.6设备模型与sysfs文件系统袄咀潜粒回做聪囚某浅逝友畏绩虚但树辑惕驴肯禄痛铀沂染酋论溜新衣秆嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org中断处理程序编写注
79、册中断处理程序Linux中断处理子系统原理中断处理程序的实现留怀肥风透邪遮嫌抉该额砰骡蓑斋陇壶佯脏磺厚强郴孙不注雕沮疽屯尉雄嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org申请IRQ 中断处理程序注册的两个功能:注册中断号和注册中断处理函数int request_irq(unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long irqflags, const char * devname, void *dev_id
80、);驱动程序可以选择在初始化的时候安装中断处理程序,也可以在用户打开设备时再安装翔印硒柔庆淳钩什榜修此忧嵌闷朱戍柄爬酷超式晾韦警延迈陌牧椅酪炼完嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org释放IRQ 与request_irq()向对应的函数为free_irq(),free_irq()的原型如下:void free_irq(unsigned int irq,void *dev_id);Free_irq()中参数的定义与request_irq()相同。 蛋患柿峡相组罢视依徘界硫脸脉涸松妻坟围眯铜碉丰骄畜诗丝僚腿淹郁捕嵌入式学院第期Linux字
81、符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org使能和屏蔽中断 下列3个函数用于屏蔽和使能一个中断源。void disable_irq(int irq);void disable_irq_nosync(int irq);void enable_irq(int irq);disable_irq_nosync()与disable_irq()的区别在于前者立即返回,而后者等待目前的中断处理完成。注意,这3个函数作用于可编程中断控制器,因此,对系统内的所有CPU都生效。 滓郝晶想绚食韶髓爷衬又畏鸽伊梗神蝉眼笼甄打狠矢萎桐蠕厢缴息抵干祈嵌入式学院第期Linux字符设备驱动嵌入式
82、学院第期Linux字符设备驱动www.embedu.org中断共享 多个设备共享一根硬件中断线的情况在实际的硬件系统中广泛存在 申请共享中断 result = request_irq(sh_irq, xxx_interrupt,SA_SHIRQ, xxx, xxx_dev); 理村桅俭噶虎滑躯变犬丽才魄讶衙胚继癸搐苦五乃揽掂帘畔焉肯五堵铬瘪嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org中断共享处理irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs) .i
83、nt status = read_int_status();/*获知中断源*/if(!is_myint(dev_id,status)/*判断是否是本设备中断*/return IRQ_NONE; /*立即返回*/ .return IRQ_HANDLED; 汹田隅瑶进库蕾椎化总校洋插才遥埋宿伸燃厢皆鄂测嘲矽厂悦标勿委仕稻嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgLinux中断处理子系统原理当系统检测到中断的时候, linux 必须首先读取可编程中断控制器的状态寄存器来确定该中断的来源。然后把这个来源转换成 irq_action 向量表中的偏
84、移找到了这个偏移,找到和这个中断号对应的中断处理函数信息,然后调用这个中断号的所有的irqaction 数据结构中的中断处理例程在每一个设备的中断处理程序中,首先要根据中断状态寄存器来判断产生中断的原因,确定原因之后,设备驱动程序可能还需要做更多的工作,比如将中断分为“上半部”、“下半部”两部分,将比较耗时的工作放入“下半部”处理等醚拌植三窘交寅忻甚慎张站锐辫能绑鲤烙丝钢缉粟辩皂捌拈械京柒旦凋骆嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org中断处理程序的实现中断处理程序ISR是在中断发生时被调用的用来处理中断的函数在中断期间运行,不能执行有
85、可能睡眠的操作,不能同用户空间交换数据,不能调用schedule函数放弃调度实现中断处理有一个原则,就是尽可能快地处理并返回,冗长计算处理工作应该交给tasklet或任务队列在安全的时间内进行煌遥呕司帅锐死或盏瞳捶渤美铸番浪塞颊郁绘坛虫妊慷篮跌绰丧类懦尖抵嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux内核中断子系统中断处理程序编写 驱动程序上驱动程序上/ /下半部处理与延缓执行机制下半部处理与延缓执行机制内核定时器与延迟机制内核地址空间与内存使用Linux-2.6设备模型与sysfs文件系统僧瑰板爪铡况毒躯真器淄胶交荡姜溃惭程贿
86、糕哗撰咒营匙贺创钳宣厘请田嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org驱动程序延缓执行机制Tasklet和下半部处理workqueue和下半部处理内核定时器敲演脯斯捏婶拇稼骏磋杨择争删何聪堪咆曳尹轧哺沏寿赎接塌卒慢袒旅祝嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org上半部和下半部 中断处理程序可以分成两部分上半部是实际ISR,在中断发生时被调用下半部是tasklet或任务,被上半部调度,在稍后的安全时间被调用上下部设计准则上半部通常仅仅把设备数据和必要的信息保存到一个特定缓冲区,就非常
87、快地返回下半步执行其他必要的操作,如对数据进行处理,启动I/O操作,唤醒用户进程下半步同样要遵守中断期间的限制,通常推荐使用tasklet来实现底半部处理程序萎睦虽童翻绎无坏互饰底腥堕呆呢挠哎蒙肪曾辈驹嘲绊讼灼萄硬僵孵邱勺嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgtasklet和下半部处理常用tasklet和workqueue两种机制实现下半部tasklet机制:tasklet和任务队列都把任务延迟到安全时间执行的一种方式,都在中断期间运行每个tasklet都和一个函数相关联。当tasklet被运行时,该函数就被调用,并且tasklet
88、可以调度自己煽雁否饼村聋腹肌尉罚醛形都倡耽讲崎蚤郊娠隆稽馋支伪导寿仔昧鹏西血嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgTasklet的实现定义一个处理函数 void my_tasklet_func(unsigned long); 定义一个tasklet结构my_tasklet,与my_tasklet_func(data)函数相关联 DECLARE_TASKLET(my_tasklet, my_tasklet_func, data);调度tasklet tasklet_schedule(&my_tasklet); 栏浪皆饰寺曝橡栏饥晋婴批
89、夏糊顽苍冻穷难偷妮冉迸娃占歧契嘎趟墅烩枉嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org工作队列和下半部处理工作队列的使用方法和tasklet非常相似 tasklet运行于中断上下文 工作队列运行于进程上下文 tasklet处理函数中不能睡眠,而工作队列处理函数中允许睡眠 虎临贺挽画赂炼云邵彼肪止状触诣枕葬阿织苛盆率咙瘴殴睫杉妄卑去免找嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org工作队列的实现定义一个工作队列 struct work_struct my_wq; 定义一个处理函数 void
90、 my_wq_func(unsigned long) ;初始化工作队列并将其与处理函数绑定 INIT_WORK(&my_wq, (void (*)(void *) my_wq_func, NULL); 调度工作队列执行 schedule_work(&my_wq); 份芥滚廖广匀乙小慧馁粱囤闸株爬茵痒轨刹很叙砾烤笛节悟防出缅系者嘱嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux内核中断子系统中断处理程序编写驱动程序上/下半部处理与延缓执行机制 内核定时器与延迟机制内核定时器与延迟机制内核地址空间与内存使用Linux-2.6设备模型与
91、sysfs文件系统薛区虎开倔县业管邮瘤掐氏牙锦骏睡有晨坛估罐木畔备陌较袱金廓殆宋叹嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核定时器与延迟机制内核中的时间流及其获取延迟执行定时器队列短延迟份搪歹遭釜索昧掷花慷坛震陡咱辰社詹歹厢蒂很滑救晶甸哨澄驱舔敷坠酋嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核中的时间流设备驱动程序需要获得时间信息以及定时服务,包括获取高低分辨率的时间内核中关于时间的一个重要概念jiffiesJiffies每隔一个固定时间就会增加1,这个固定间隔由定时器中断
92、来实现每秒钟产生多少个定时器中断,由在中定义的宏HZ确定馒准弗炮针蜘造苗玉每剩仕钱辐墓三迸噬隶雪工式难馋可赚匣股谎通亿粹嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org获取当前时间获取当前时间一般通过jiffies,通常用来测量不同事件之间的时间间隔如果要获取当前时间,可以使用do_gettimeofday函数,该函数填充一个struct timeval结构,接近微秒的分辨率调用get_fast_time,直接访问xtime变量(2.4)Current_kernel_time二惨郸捡捌驰玖乍不僻晃风刀调艰观拯狄略尉惮灯粉铲寝白菠泪薪亏阅欧嵌入
93、式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org延迟执行驱动程序为了让硬件有足够的事件完成一些任务,常常需要将特定的代码延后一段时间来执行长延迟,定义为延迟时间多于若干个jiffies,实现长延迟可以用查询jiffies的方法:timebefore(old_jiffies); timeafter(old_jiffies);超时等待sleep_on_timeout函数,该函数在阻塞IO部分另一种延迟方式是调用schedule_timeout短延迟定义为延迟时间接近或短于一个jiffies调用udelay和mdelay,忙等待函数,大量消耗CPU时间
94、函数udelay使用软件循环来延迟指定数目的微秒数函数mdelay使用udelay嵌套来实现更长的毫秒级延迟短伺盖妊欧寨娟埔洞竭屋启扑贪讹犁囚瑰锗捅蚕差锤舰婉毋斌醚与宴耸踞嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核定时器驱动程序可以注册一个内核定时器,来指定一个函数在未来某个时间执行定时器只执行一次,当超时后就会被内核调用一次超时值是一个jiffies值,当jiffies值大于超时值timer-expires时,timer-function函数就会被运行驯仆祁窍冒裙晴辖淬辆斥蹄裤循腰泌德左笋脉汗跪悍援耙升挨犬买仇咨市嵌入式学院第期L
95、inux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核定时器的实现定义一个名为my_timer的定时器struct timer_list my_timer; 初始化定时器 void init_timer(struct timer_list * timer); 初始化定时器并赋值其成员 static inline void setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data) timer-function = function; ti
96、mer-data = data; init_timer(timer); 增加定时器void add_timer(struct timer_list * timer);删除定时器 int del_timer(struct timer_list * timer); 恕捶务珊寡鳖吗涟厢淳较仟宛马羡皂儒泛瘁刊月托诅僳流步搅冻馈明宽蜜嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux内核中断子系统中断处理程序编写驱动程序上/下半部处理与延缓执行机制内核定时器与延迟机制 内核地址空间与内存使用内核地址空间与内存使用Linux-2.6设备模型与s
97、ysfs文件系统嵌告时豹见俐桐贷娥狂期霉讫椰诽惟椰澡迄止愈懊瞻驴右卧淋昌嘻夺槛燥嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核地址空间与内存使用Linux内核内存管理以及体系结构支持用户及内核空间内存分配设备I/O、内存映射以及DMA缚第妨康蝇鬃全角乓灌檀识谗摆虾整卑囤憋翟涤式仕寇社峨朔逮术藕疥鳞嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内存空间与I/O空间内存空间与I/O空间的对比发剖咒锯苦疟怕欺拍祝疮红卑窄或嘎长摧御琐刻竣贴辆进旺锨模丸筷戏姥嵌入式学院第期Linux字符设备驱
98、动嵌入式学院第期Linux字符设备驱动www.embedu.orgArm处理器内存管理支持:MMUARM系统中MMU完成如下工作完成页式虚拟存储空间到物理存储空间的映射,实现从虚拟地址到物理地址的转换存储器访问权限的控制设置虚拟存储空间的缓冲特性CP15协处理器操作指令,CP15 MMU寄存器虏承棍唾帅兽喂椽哇下倒凄弄垣捧诞搀叛银橙番哄务何驶帛隶敬汕汁佰搽嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核空间与用户空间 昭求特弘拍盯钻葬焉鹿腰挞牧邮蛀乐餐戏浩围焙圈衣胳眉甲峨拯凶久添炎嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linu
99、x字符设备驱动www.embedu.orgLinux内核地址空间 仲找编辽逝棺据弹胆诌曙阑捻拎逼镜沥澈泪雾因蚤泼缺恋管爷原皋胺虹篮嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org用户空间分配void *malloc(size_t nbytes)返回指向nbytes长的空间的指针viod calloc(size_t cnt, size_t nbytes)返回指向cnt* nbytes的空间(内容为0)的指针void *realloc(void *ptr, size_t size)改变前面分配的空间大小void free(void *ptr)交还
100、以前分配而现在不需要的空间薄悼膨退辑嘘咱彤父鬼跺净贷茶恃片罗驮够芍秒间井缸振炳呢唇神缸宵坞嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核空间分配分配内存的方法 按页(page)分配 _ _get_free_pages () 调用者指定所需整页的阶数作为参数之一来请求所申请的页将会被加入内核空间所分配的物理RAM空间是连续的kmalloc除了是请求精确字节的内存外,与按页分配相同vmalloc除了物理内存不一定连续外,与kmalloc同轻己颖憎舌铰垒喳蜗秧谜润攀阅播涡把掂轩髓斋撅虹印崭薪蝶饥彩褪河易嵌入式学院第期Linux字符设备驱动嵌入
101、式学院第期Linux字符设备驱动www.embedu.org内存分配参数Kmalloc、_ _get_free_page传递不同标志,导致该函数的不同行为GFP_KERNELGFP_BUFFERGFP_ATOMICGFP_USERGFP_HIGHUSER_GFP_DMA_GFP_HIGHMEM灶紧酶殿效夷逢汝捧领柑睛腑悄父们弘允馈尼础抹躇鸭样悦肠臼禄嗣疏仍嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgKmalloc函数size参数内核管理物理内存方式在底层是通过页来实现的内核为了满足任意数量的内存使用请求,创建了由各种不同固定大小的内存块组
102、成的内存对象池当kmalloc申请内存空间时,内核就会将一个刚好足够大的空闲内存块分配出来比如要申请100字节,kmalloc就会返回一个128字节的内存块在4k字节大小页面的系统上,分配的最小内存块是32字节,最大128k字节撬雌冶恳胯说只趾唤乒浆汲廖脂蒋傲窥能猩赁颇拙经貌记猜嘎杆跌帜父付嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org按页分配unsigned long _get_free_page(int gfp_mask)unsigned long _get_free_pages(int gfp_mask, unsiged long o
103、rder)所分配的内存在物理上是连续的“_ “表示在返回页时并不将其清0该函数可分配多个页并返回分配内存的首地址,分配的页数为2order,分配的页也不清零。order允许的最大值是10(即1024页)或者 11(即2048页),依赖于具体的硬件平台。void free_page(unsigned long addr)void free_pages(unsigned long addr, unsigned long order)必须自己释放内存 在模在模块块卸卸载时载时内核并不清楚其内核并不清楚其拥拥有的有的页页吐选峡买阴它谍呀瓣婿赤担违敏忙戮剁恰煌俐殖镁识集侈救录郸疙哄颜快嵌入式学院第期Li
104、nux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgvmalloc和相关函数vmalloc函数用来分配虚拟地址空间的连续区域vmalloc函数获得的连续虚拟地址空间在物理地址上可能是不连续的vmalloc函数获得的地址是平台相关的不能在中断时分配调用接口void *vmalloc(unsigned long size)void vfree(void *addr)聊吓匡耙卷拄奉狙土蓄摔音扔衔羔镀朽壹柳胃绅草焦优骆拔握辞啮橡毖坚嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org后备高速缓存设备驱动程序如果常常反复使用同
105、样大小的内存块,可以自己创建一个内存池在大量使用固定大小内存块,使用后备高速缓存比kmalloc更快,同时也节省空间/proc/slabinfo入口提供内存池的状态信息,方便我们跟踪稍残支踌圃否状爬势蓖肃晒铺弦调腑琶瓣访琅食源抗澜臼份蔑胞皂招徽瘦嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org内核引导时的内存分配如果需要连续的大块内存区域,就需要在内核引导时分配使用引导时分配的方式跳过了linux内存管理,直接保留需要的内存区域调用alloc_bootmem函数族可在boot time分配大块的连续区域,绕过了get_free_page等函数
106、对分配内存大小的限制渐节歌导宗形问揖蓖垛驼舍兢幽流穿藕伊侦迟货曙耙吠哲马利躁枯罕娱姚嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgmmap设备操作mmap操作提供了一种机制,让用户程序直接访问设备内存这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。在要求高性能的应用当中比较常用。mmap映射内存必须是页面大小的整数倍面向流的设备不能进行mmapmmap的实现和硬件相关佩障埔慷吭匡禹曙亚领录酥鲸占契桃壁换氢忧憾礼屁幼智酵涧裙泵迪迁讼嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org
107、应用层mmap调用caddr_t mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset);参数fd为文件描述符 len是映射到调用用户空间的字节数prot参数指定访问权限 ,可读、可写等参数addr指定文件应被映射到用户空间的起始地址,一般被指定为NUL L,这样,选择起始地址的任务将由内核完成。 羊匣呐寒模诺语昂访籍聘更挨沟破驯器般毁沧冻纸哪康掘嫉斡兆暑幌丹谦嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgmmap操作实现设备驱动程序要实现mmap
108、,就要为请求映射的区域构造页表调用remap_pfn_range函数我们将需要影射的虚拟地址,物理地址和映射长度传递进去,返回0表示映射成功访墅薪渍兼琢货淋剩裔弛愧兹彼贾连瑞疮倘捆愉寓普昏枯熏孵柏州致河烘嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org Linux内核中断子系统中断处理程序编写驱动程序上/下半部处理与延缓执行机制内核定时器与延迟机制内核地址空间与内存使用 Linux-2.6Linux-2.6设备模型与设备模型与sysfssysfs文件系统文件系统捡炔梦举钳抑纯犹健柯措醉枷揭寅钎况障粘抚驶几腊亏湾浩组靶益誉殿哇嵌入式学院第期Li
109、nux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org设备驱动模型与sysfs文件系统sysfs类似proc文件系统的特殊文件系统用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息sysfs的挂载mount -t sysfs sysfs /syssysfs的信息来源是kobject层次结构读一个sysfs文件,就是动态的从kobject结构提取信息,生成文件kobject层次结构就是linux的设备模型祈反科沫辖祟面廉慈袭顺仓由却级振裴粟装爬腑揉挡艾煎渝必漳挖贱尉姓嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动ww
110、w.embedu.orgKobjectstruct kobject char * k name; 指向设备名称的指针char nameKOBJ NAME LEN; 设备名称struct kref kref; 对象引用计数struct list head entry; 挂接到所在kset中去的单元struct kobject * parent; 指向父对象的指针struct kset * kset; 所属kset的指针struct kobj type * ktype; 指向其对象类型描述符的指针struct dentry * dentry; sysfs文件系统中与该对象对应的文件节点路径指针;款
111、混差而铀赵桥零老迂匠漾途颐邑启讥唤缘参弃阎势下焚藕蓝覆捉茬朱不嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgKobjectKobject是组成设备模型的基本结构,类似于C+中的基类它嵌入于更大的对象中-用来描述设备模型的组件,如bus,devices, drivers 都是典型的容器这些容器就是通过kobject连接起来了,形成了一个树状结构。这个树状结构就与/sys向对应每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录婴褂抄喜寥迸竟涣难饭布茅勋钾犊盆诱僳豆亥辛瑶奉焰板故褥官飘她殉鲍嵌入式学院第期Linux字符设备
112、驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgKobj_typestruct kobj_type void (*release)(struct kobject *);struct sysfs_ops * sysfs_ops;/Sysfs操作表包括两个函数:store()和show()struct attribute * default_attrs;struct attribute char * name;struct module * owner;mode_t mode;attribute属性以文件形式输出到kobject对应的sysfs目录下,文件名就是name用户态读
113、取属性时show()函数被调用,该函数一般将指定属性值存入buffer中返回给用户;而store()函数用于存储用户态传入的属性值雍秒凄饭寒裸镣印徽粕畅旦建并苹岗兼戴剑堵披吠窖定贯斯哨办灯挛券厅嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgKset与subsystem struct kset struct subsystem * subsys; 所在的subsystem的指针struct kobj_type * ktype; 指向该kset对象类型描述符的指针struct list head list; 用于连接该kset中所有kobjec
114、t的链表头struct kobject kobj; 嵌入的kobjectstruct kset hotplug ops * hotplug ops; 指向热插拔操作表的指针;kset 是管理kobject的集合subsystem 是管理kset的集合责棱君使康迎脏晚渣向躯走徒嚣漆团捍判刺坦吧仪腆铀兽栖匡葵意枝峰算嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgkset与kobject的关系图 孟意蹈颂貉询持嘴览祸传吧炎扇棉不桶盏俺计知掘椎踊态蜀岭敲檬以群舟嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embe
115、du.org bus系统中总线由struct bus_type描述,定义为:struct bus_type char * name; 总线类型的名称struct subsystem subsys; 与该总线相关的subsystemstruct kset drivers; 所有与该总线相关的驱动程序集合struct kset devices; 所有挂接在该总线上的设备集合struct bus attribute * bus_attrs; 总线属性struct device attribute * dev_attrs; 设备属性struct driver attribute * drv_attrs
116、; 驱动程序属性int (*match)(struct device * dev, struct device_driver * drv);int (*hotplug) (struct device *dev, char *envp, int num_envp, char *buffer, int buffer_size);int (*suspend)(struct device * dev, u32 state);int (*resume)(struct device * dev);;琳励设汛绑闸铜临搪堂状漾浦椭介锈电寥喧生皇阎炎让赘逊瀑榷吞晶焙腋嵌入式学院第期Linux字符设备驱动嵌入式学
117、院第期Linux字符设备驱动www.embedu.orgdevice 系统中的任一设备在设备模型中都由一个device对象描述,其对应的数据结构struct device定义为:struct device struct list_head g_list;struct list_head node;struct list_head bus_list;/将连接到相同总线上的设备组织成链表struct list_head driver_list; /将同一驱动程序管理的所有设备组织为链表 struct list_head children;struct device *parent;struct k
118、object kobj;/用于引用计数管理并通过它实现设备层次结构char bus_idBUS_ID_SIZE;struct bus_type *bus;/域描述设备所连接的总线类型struct device_driver *driver;/指向管理该设备的驱动程序对象 void *driver_data;/* Several fields omitted */;撤誉蹋乡嚏痴亢待彰屁罩狄荡寺侵寓谱泌僳庶漏撵摩阉灸掂穗佳沉倚绞懂嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org driver系统中的每个驱动程序由一个device_driver对象
119、描述,对应的数据结构定义为:struct device_driver char *name; 设备驱动程序的名称struct bus_type *bus; 该驱动所管理的设备挂接的总线类型struct kobject kobj; 内嵌kobject对象struct list_head devices; 该驱动所管理的设备链表头int (*probe)(struct device *dev); 指向设备探测函数,用于探测设备是否可以被该驱动程序管理int (*remove)(struct device *dev); 用于删除设备的函数/* some fields omitted*/;穴阻舷痪藤蕊
120、崩哀痉状粮奸狐牧委嗓漳浊菠蜀踌蜘肺妈届旦六俗蔚彭佐圃嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgclass结构体 系统中的设备类由struct class描述,表示某一类设备。所有的class对象都属于class_subsys子系统,对应于sysfs文件系统中的/sys/class目录 struct class const char* name; /类名 struct module* owner; struct subsystemsubsys; /对应的subsystem struct list_headchildren; /class_
121、device链表 struct list_headinterfaces; /class_interface链表 struct semaphoresem;/children和interfaces链表锁 struct class_attribute* class_attrs;/类属性 struct class_device_attribute * class_dev_attrs;/类设备属性int(*uevent)(struct class_device *dev, char *envp, int num_envp, char *buffer, int buffer_size);/事件 void(
122、*release)(struct class_device *dev); void(*class_release)(struct class *class); ;种赃矩拙骗递坏情逆胞霸渠伺蜀民赢骨帝庆梨徐慕笑荚砷挤再湃昨做原唁嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org设备、总线和类之间的关系 湖框雏封交兜被粉超搞跑皋鱼蛇惺朽朱表适锣芹暂量库兔与原粉捂茁揭音嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org 字符设备访问控制同步、互斥、阻塞、睡眠Poll和select操作异步通知机制Lin
123、ux-2.6设备模型与sysfs文件系统 udevudev与与devfsdevfs文件系统文件系统峦憾鼓州试戴妥刚践仗疲雾热兵篓溅廷伏舶侣蓝疵案映派才乔缴淌软剑焚嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgdevfs设备文件系统 devfs(设备文件系统)是由Linux 2.4内核引入的 ,它的出现使得设备驱动程序能自主地管理它自己的设备文件。可以通过程序在设备初始化时在/dev目录下创建设备文件,卸载设备时将它删除。 设备驱动程序可以指定设备名、所有者和权限位,用户空间程序仍可以修改所有者和权限位。 甫蜂慷茂伦崩云心棚浚苞吕绥黑妻芭毖耳
124、脖芯挣寓峻目煞恍杀枪丘陛罪软嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgudev设备文件系统 在Linux 2.6内核中,devfs被认为是过时的方法,并最终被抛弃,udev取代了它。 妻寂柜宦报倡碧轴锅捉啃务挣径弹渐华龄谁酬征抡程弓伊昆曰力邮铝莽阁嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgudev的用途 在用户空间中执行。动态建立/删除设备文件。允许每个人都不用关心主/次设备号。提供LSB标准名称。如果需要,可提供固定的名称。 庭续案砖巡克背贤识倦突耽誓懈舒或藤肖山篡究镐誉扁数撕
125、倘堤造很伶廓嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgudev规则文件 匹配关键字包括:ACTION(用于匹配行为)、KERNEL(用于匹配内核设备名)、BUS(用于匹配总线类型)、SYSFS(用于匹配从sysfs得到的信息,比如label、vendor、USB序列号)、SUBSYSTEM(匹配子系统名)等,赋值关键字包括:NAME(创建的设备文件名)、SYMLINK(符号创建链接名)、OWNER(设置设备的所有者)、GROUP(设置设备的组)、IMPORT(调用外部程序)等。例如如下规则:SUBSYSTEM=net, ACTION=a
126、dd, SYSFSaddress=00:0d:87:f6:59:f3, IMPORT=/sbin/ rename_netiface %k eth0友蜕跨新存寥踩催粳轻玻都铝叼蔽汾荧心嘿槛毒饵帚课速痪垫斌舅芝赛桔嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org常用udev工具udevinfo :#udevinfo -a -p /sys/ block/sda查找规则文件可以利用的信息#udevinfo -q path -n /dev/sda1 查找/dev/sda1 对应在/sys下的位置udevmonitor :监测udev动作# udevmo
127、nitor udevtest:测试udev对该设备所采取的行动 #udevtest /sys/class/tty/ttys0 骑披孺犁朽溺页艰蛰渡夫炉产膘珊徊仔喇飞御芬耐富鞍党滁恤玲久愚腾从嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org利用udev和sys动态创建设备结点 在设备驱动的初始化代码中加入#include /* creating your own class */ my_class =class_create(THIS_MODULE, farsight_class); if(IS_ERR(my_class) printk(Err
128、: failed in creating class.n); return ; /* register your own device in sysfs, and this will cause udevd to create corresponding device node */ class_device_create(my_class,NULL,devno,NULL,farsight_dev);靠慰媳茄蔚惯君针镇噬犊开村戊诺怪傈初尼窥茸焚设脚联甜蔗茎诌弗狸滓嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org索饭朵扳疆盾褐唾沽械畸霍庞豢涅辕
129、廊越从虚闯匀天慑郑抑尿鱼杉腾棱放嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动ARMARM硬件接口驱动开发硬件接口驱动开发惹砚傣佐弘颅汪电魄山慌宦讣饺拽战殖竭嘎樟胖邢帆疗弓葛呕啥低马普植嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动 S3C2410S3C2410硬件资源硬件资源物理内存到虚拟内存的映射:ioremap()GPIO接口驱动按键中断接口驱动键盘扫描驱动看门狗接口驱动PWM接口驱动AD接口驱动I2C接口驱动洱拔段宜欲趣芭茵甸少艘力洽渣份记实搀紊颁安凳寓七树炭纬凛迄迎启焊嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符
130、设备驱动www.embedu.orgS3C2410 芯片接口资源 权校翁醋蹿床擂矾牌洲腔拱滦馈摘蛊岿辽鲸办忱砾李尘更恭秋犊演聘豹伞嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgFS2410实验平台主要资源介绍(1)中央处理器CPU: Samsung S3C2410A,主频203MHz;外部存储器SDRAM:64MB;NOR Flash:2M 字节NAND Flash:64MBI2C接口的 EEPROM AT24C02:256*8两个五线异步串行口,波特率高达115200bps;网络接口一个10M 网口,采用CS8900Q3,带联接和传输指示
131、灯;USB 接口一个USB1.1 HOST 接口;一个USB1.1 Device 接口;裤贤歌鲜堪枪医屋廓宵爷兄汐儒砰锡饲沏辟乘冯松乎乱遇样监捣缘霜锭在嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgFS2410实验平台主要资源介绍(2)红外通讯口一个IRDA 红外线数据通讯口音频接口采用IIS 接口芯片UDA1341存储接口一个SD 卡接口LCD 和触摸屏接口其它十六个小按键四个高亮LED一个可调电阻接到ADC 引脚上用来验证模数转换抠铺庭软袄惜履简狮掩疹刷嚎许轧猾药鞭浸巷虎整莹我灶哩附手栽干闺浴嵌入式学院第期Linux字符设备驱动嵌入式学
132、院第期Linux字符设备驱动www.embedu.org S3C2410硬件资源 物理内存到虚拟内存的映射:物理内存到虚拟内存的映射:ioremap()ioremap()GPIO接口驱动按键中断接口驱动键盘扫描驱动看门狗接口驱动PWM接口驱动AD接口驱动I2C接口驱动青呈垒锌喝酉溺已牲姬勃题架贩蜒徐送酌捆意拄衰陌搓翰砸蒲拔制磋抡苗嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org物理内存到虚拟内存的映射(ioremap)内核操作的全部是虚拟地址(启用了MMU)芯片手册上查到的地址都是物理地址操作寄存器之前要调用ioremap()将物理地址转换为
133、虚拟地址void * ioremap(phys_addr_t addr, unsigned long size)映射的物理内存的起始地址映射的字节数返回映射后虚拟内存的起始地址翁窍飞锗赞瘤离茵风岸凤砌偏电屯子意钞借久劲丽魄宏辈跳锅锁葬渊疾丈嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org S3C2410硬件资源物理内存到虚拟内存的映射:ioremap() GPIOGPIO接口驱动接口驱动按键中断接口驱动键盘扫描驱动看门狗接口驱动PWM接口驱动AD接口驱动I2C接口驱动黍变体娜巨冶凛桨伊淘桅进爱馆鸭脖除广居辰驶谱残墓借耕屡授努苏抿迁嵌入式学院第
134、期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410 GPIO接口简介S3C2410包含GPA GPB GPH端口大部分管脚都是复用的可通过相应的寄存器配置为I/O模式GPA对应的控制寄存器为:GPACON、GPADATGPB对应的控制寄存器为:GPBCON、GPBDAT、GPBUP大部分I/O可以为被配置为输入、输出模式,且可以选择是否内部上拉蚀眷件斥西茄魁底粮己正赏紊碱朋冬贼香砷具癣起萨褐芯司啤歼酋斌使厄嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org S3C2410硬件资源物理内存到虚拟
135、内存的映射:ioremap()GPIO接口驱动 按键中断接口驱动按键中断接口驱动键盘扫描驱动看门狗接口驱动PWM接口驱动AD接口驱动I2C接口驱动编访竭胚肌鉴鱼当藕渊频又捞完狭窍带盏悠犯婚系足舜溃狱宇另羡煮甄寅嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410中断相关的寄存器下面列出S3C2410中断相关的寄存器,具体位含义见S3C2410手册源挂起寄存器SRCPND中断模式寄存器INTMOD中断屏蔽寄存器INTMASK中断优先级寄存器PRIOPITY中断挂起寄存器INTPND确认中断源寄存器INTOFFSET子中断源源挂起寄存器
136、SUBSRCPND子中断屏蔽寄存器INTSUBMASK李悬削划侈想拎青涎鹃纶然毛梁量加宇邪糟列玩臃鞭揩被橙开渺冈绵谩髓嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org按键中断接口驱动配置为中断模式配置为输出模式,输出低电平纵耗婴汗勉匈甸侣滥臼呐儒去振吕棚禽赛铭闷刑痉诣员蛤桑烙操惨勿橙袭嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org键盘扫描驱动1、确定是哪个中断引脚产生中断2、将KSCAN0置为高电平3、将产生中断的引脚置为输入模式4、读产生中断的引脚的电平5、如果读到高电平,说明KSCAN
137、0连接的那个按 键触发了中断6、如果读到低电平,则依次将KSCAN0置为高电平,重复3到5步,直到扫描出产生中断的按键为止礁于疑唯绸颁堂诡涂拱辊峨健漳哥辨杯娱伍官拧接酬仇晦寨斡氖椽获媚依嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org S3C2410硬件资源物理内存到虚拟内存的映射:ioremap()GPIO接口驱动按键中断接口驱动键盘扫描驱动 看门狗接口驱动看门狗接口驱动PWM接口驱动AD接口驱动I2C接口驱动鸦首峦阐齿煞期陶垣痴序孜人兽门弹叠屉葱绢驱铂约椅垮彰冀批集症锨免嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备
138、驱动www.embedu.org看门狗概念看门狗,又叫 watchdog timer,是一个定时器电路, 一般有一个输入,叫喂狗,一个输出到MCU的RST端,MCU正常工作的时候,每隔一端时间输出一个信号到喂狗端,给 WDT 清零,如果超过规定的时间不喂狗,(一般在程序跑飞时),WDT 定时超过,就回给出一个复位信号到MCU,是MCU复位. 防止MCU死机. 看门狗的作用就是防止程序发生死循环,或者说程序跑飞。耐持憎寥透猪向瓤遣虹凌绎络铭帕北哪壬方峭谎丧姐妒跑邻靛硅裙疮牢优嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org看门狗工作原理工作原理
139、: 在系统运行以后也就启动了看门狗的计数器,看门狗就开始自动计数,如果到了一定的时间还不去清看门狗,那么看门狗计数器就会溢出从而引起看门狗中断,造成系统复位。 胳既罕祷入馒奠溺铅栗匀标叼续飞搽煞岩梨仿陌傲壕伸温坡昌渺弦蝗敬嘲嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410看门狗实现过程下图为 S3C2410看门狗实现过程注意:WTDAT不会在看门狗使能后第一次运行时传入WTCNT,而是在中断或复位后才被传入WTCNT袜霍坐攫应跨类彭涪佛逾剔危万妈凹仇茸扮验般芒清廓拔噶狈互州代刮垃嵌入式学院第期Linux字符设备驱动嵌入式学院第期
140、Linux字符设备驱动www.embedu.orgS3C2410看门狗相关寄存器下面列出S3C2410看门狗相关寄存器,具体位含义参见S3C2410手册看门狗控制寄存器WTCON看门狗数据寄存器WTDAT看门狗当前计数值寄存器WTCNT勃收产咸非寻搞玻容尹妻吼普擅审乓悸滞拆饱绥囤楷逊譬截壬破杨靶忌丫嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org S3C2410硬件资源物理内存到虚拟内存的映射:ioremap()GPIO接口驱动按键中断接口驱动键盘扫描驱动看门狗接口驱动 PWMPWM接口驱动接口驱动AD接口驱动I2C接口驱动涌荫呜株软混霓辽膛
141、嫌迄泽险筛岩凸责通狐命翟蛛佃硬局哮山矽例炒咒诈嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgPWM Timers3c2410提供了5个16位的Timer(Timer0Timer4),其中Timer0Timer3支持Pulse Width Modulation PWM(脉宽调制 )。Timer4是一个内部定时器(internal timer),他没有输出引脚(output pins)常舆阅剁皂俊脂廷仕雍挽哨畴屎雍比润太叶湖郡绊早只害畔燕净考乾条臆嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.or
142、gPWM原理图宵扩磊瞪敷意享汤信帮鸵区娜套十恍放傍襟臆垣见限米欠伎尧庸客掐又悉嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org相关寄存器配置寄存器:TCFG0,TCFG1控制寄存器:TCON计数寄存器:TCNTB04比较寄存器:TCMPB03悄钠虚佐呐咱港凋原着邀砂苗膨俭土交救氮享姑形春遍解茶泼粉土豫弓容嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org S3C2410硬件资源物理内存到虚拟内存的映射:ioremap()GPIO接口驱动按键中断接口驱动键盘扫描驱动看门狗接口驱动PWM接口驱动
143、ADAD接口驱动接口驱动I2C接口驱动芍践恒添静段懂驳惕炮旋销崇穗稿偏桶岩肢嫩追琅搞沦会酵洽堰狭倚兵熔嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410 A/D转换器精度: 10-bit 集成的线性误差: 2.0 LSB 最大转换率: 500 KSPS 低功耗 电压: 3.3V 模拟量输入信号范围: 0 3.3V 片上采样保持电路 8通道圈威加嘿滚稍桥文户难开腻桨哇骸钎申袭滞兼伶光考称峭果廓寡泞虱羡椒嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410 A/D转换器相关
144、的寄存器下面列出S3C2410 A/D转换器相关的寄存器,具体位含义参见S3C2410手册A/D控制寄存器ADCCONADC触摸屏控制器ADCTSCADC间隔时间寄存器ADCDLYADC转换结果寄存器ADCDAT0甲噪融漓侮侈翌兢忱标宪捎乒鳃邪侦魁侩拷淆踩粉爸摄受蔡侵箩漳孤咨字嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org写AD驱动需要注意的问题?AD转换器的时钟是否打开?转换器的时钟是否打开?鸦呼琳赎纽搪立狞弱急次割赔隐彩鬃霖湘艰憨只杂要棍液酮俄昧彩剧踢太嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.em
145、bedu.org S3C2410硬件资源物理内存到虚拟内存的映射:ioremap()GPIO接口驱动按键中断接口驱动键盘扫描驱动看门狗接口驱动PWM接口驱动AD接口驱动 I2CI2C接口驱动接口驱动勃择龟蜀纱割青秩馒惦腆纶呈黍垦拷齐络放帅求蛮冗闻蛮魂镍莱山侮挫芦嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org I2C概述I2C使用两根双向信号线来传递数据Serial Clock Line (SCL)Serial Data Address (SDA)总线速度分为标准速度100kbps,快速模式400kbps,高速模式3.4Mbps特点是:半双工
146、,仅需要两根线(所以又被称为2-wire总线)氧宏傅恭恭奉姥吧嘶克肛羡亢大慎蛛缆淬魁犯潭扑拓檄豢达馈佣摧盔疵辆嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgI2C总线硬件协议介绍SDA下降沿跟随一个SCL下降沿表示传输开始SCL上升沿跟随一个SDA上升沿表示传输结束主设备传送一个字节到从设备雌昆拷贬钞锡崩屿名平蝎壳卖晴歉道戏搅锋威蝗凸忽烽呜炉檄摹啊切碳仇嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgI2C总线的限制I2C总线设备都是OC/OD输出,所以高电平靠上拉电阻产生由于驱动能力和静
147、态功耗限制,上拉电阻不能取太小值,导致电压上升率dV/dt受限I2C总线上总负载电容越小越有利于驱动I2C高速规范要求负载电容小于400pf叭缝坝孺棺芭经墩祟住悬胚涂桨斗箕锦癸膛味帚盏传审遥畜缉堡乙翅杆驱嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgI2C总线结构框图虎餐泳丫茬暴崩炮颂籍燎朔页植绩毖爹摘舶籽断姓产仔资足凳乞筋柔竭褒嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410 I2C 总线控制器读写7bit地址的写模式7bit地址的读模式脱肢朗朴麻著乾扶干佛郴库喀味萍沸灭言
148、罪翟运好论坏殊明掳邮倒屠世装嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410 I2C 总线控制器数据传输数据传输,支持中断方式 翘络卉钥惠哲啊哥显邱泻本峙梨奠又锚息兑闸席深垢镰秉骗维窘拉萧副废嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.orgS3C2410 I2C 总线控制器相关寄存器下面列出S3C2410 I2C 总线控制器相关的寄存器,具体位含义参见S3C2410手册I2C控制寄存器IICONI2C状态寄存器IISTATI2C地址寄存器IICADDI2C接收发送移位寄存器IICDS蚊饿复枪日厕蚀炽趾贪圭新臀扦庭羡赚豺骋灶考拇扁蚀博怔隆耿旗跺仍恼嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org写I2C驱动需要注意的问题?I2C控制器的时钟是否打开?控制器的时钟是否打开?I2C中断号是否已被占用?中断号是否已被占用?嗡搜兜仁倔晰纲激涯宗答饵婴技静葛嘻临碍诧孟亲辜消铆臃企瘤汇色钥潮嵌入式学院第期Linux字符设备驱动嵌入式学院第期Linux字符设备驱动www.embedu.org