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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

本文(国嵌驱动笔记.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

国嵌驱动笔记.docx

1、国嵌驱动笔记知识结构:1. Linux驱动程序设计模式(40%) 2.内核相关知识(30%)3. 硬件相关知识(30%)驱动分类:字符,网络,块字符设备:以字节为最小单位块设备,一次传送一个整体数据(512字节),Linux可以以字节访问块设备(仅仅是驱动与内核的接口不同,访问的顺序的不同(字符只可顺序访问,块驱动可随机访问)网络接口:硬件(eth0),纯软件(lo)驱动的安装:模块,编译进内核(Linux启动的时候会自动加载init段)使用驱动程序:字符设备文件字符设备驱动字符设备 文件系统块设备文件块设备驱动块设备 套接字协议栈网络设备驱动网络接口设备主设备号用来标示与设备文件相连的驱动程

2、序,次编号被驱动程序用来辨别操作哪个设备主设备号反映设备类型,此设备号区分同类型的设备dev_t 高12位为主设备号,低20位为次设备号MAJOR(dev_t dev)从dev_t分解出主设备号MINOR(dev_t dev)从dev_t分解出此设备号MKDEV(major,minor) 构造设备号;静态申请:1.根据Documentation/devices.txt驱动没有使用的主设备号 2. 使用register_chrdev_region(dev_t form, unsigned count ,const char *name)函数注册(容易冲突)From希望使用的设备号,count希望

3、申请使用设备号的数目,name设备名(体现在/proc/devices)2. 动态分配 alloc_chardev_region(安装驱动前无法创建设备文件)创建设备文件后,通过/proc/devices 察看alloc_chardev_region(dev_t *dev,unsigned baseminor, unsigned count, const char *name)dev分配的设配号,baseminor起始的此设备号,count要分配的设备数目,name设备名主要设备号:unregister_chrdev_region(dev_t dev, unsigned baseminor)M

4、knod filename type major minor type是字符或块 mknod serial0 c 100 0Linux字符设备驱动3个重要数据结构Struct file每打开一次都有一个关联的struct file 重要结构loff_t f_pos文件读写位置 struct file_operations *f_opStruct inode 记录文件的物理上的信息(设备号等),一个文件可以有多个file,但只有一个inodeStruct file_operation *f_op函数指针的集合struct file_operations mem_fops = .owner = T

5、HIS_MODULE, .llseek = mem_seek, .read = mem_read .读内核代码应用程序怎样访问驱动程序(read_write,c)系统条用read找到vfs_read根据file结构中找到file_operations中的read字符设备使用 struct cdev 来描述字符设备注册可分为如下3个部分:1.分配cdev struct cdev *cdev_alloc(void)2.初始化cdev cdev_init(struct cedev *p, const struct file_operations *fops) 3. 添加cdev cdev_add(s

6、truct cdev *p ,dev_t dev ,unsigned count ) dev设备号 设备号的数目字符设备的注销:cdev_dev(struct cdev *p)设备操作int (*open)(struct *inode , struct file *)如果该项为NULL,设备打开永远成功void(*release)(struct *inode , struct file *)ssize_t (*read)(struct file *, char _user *buff , size_t , loff_t *)ssize_t (*write)(struct file *, cha

7、r _user *, size_t , loff_t *)file是文件指针(来与内核),*buff是数据缓冲(用户空间),count传输的数据量(用户空间),offp访问位置(来与内核)*buff是用户空间的,不能直接使用 int copy_from_user(void *to , const void _user *from, int n)int copy_to_user(void _user *to ,const void *to , int n)loff_t llseek(struct *file ,loff_t offset , int whence)open方法主要完成如下工作:1

8、. 初始化设备 2. 标明此设备号在open(struct inode *inode, struct file *filp) 函数可使用 MINOR(inode-i_rdev; 获取此设备号 filp-private_data = dev; 将设备描述指针赋值给私有文件指针 ,区分出了那种设备在read()函数使用struct mem_dev *dev = filp-private_data 可根据私有文件指针指定找到具体的设备,read函数参数没有inode,无法获取此设备号。kmalloc分配内存,返回地址,根据其返回的地址就可操作内存中的数据copy_to_user(buf,(void*

9、)(dev-data+p),count) 这里的(dev-data+p)为什么要用(void *)强制转换呢?copy_to_user是这么定义的int copy_to_user(void _user *to ,const void *to , int n),但还是不理解。驱动程序调试分类:打印调试,调试器调试(kgdb),查询调试(proc文件系统)合理的使用printk可以全局的打开或关闭它们。并发:多个执行单元同时被执行竟态:并发的执行单元对共享资源(硬件资源或全局变量等)的共享访问通过semaphore机制和spin_lock机制实现获取信号量不成功 该阻塞或者睡眠1. 定义信号量 s

10、truct semaphore sem;2. 初始化信号量 void sema_init(struct semaphore *sem ,int val) 初始化信号量的初值为val3. void init_MUTEX(struct semaphore *sem)初始化一个互斥锁,把sem的值设为14. void init_MUTEX_LOCKED(struct semaphore *sem) 初始化一个互斥锁,把sem的值设为0定义与初始化工作可由如下宏一步完成DECLARE_MUTEX(name)定义一个信号量,并初始化为1DECLARE_MUTEX_LOCK(name)定义一个信号量,并初

11、始化为0,为已锁状态5. 获取信号量void down(struct semaphore *sem)可能会导致进程睡眠,故不能在中断上下文中使用,如果sem非负直接返回,否则挂起(TASK_UNINTERRUPTIBLE),不建议使用 6. void down_interrruptible(struct semaphore *sem)信号量不可用 ,置为TASK_INTERRUPTIBLE7. void down_killable(struct semaphore *sem)信号量不可用 ,置为TASK_KILLABLE8. void up(struct semaphore *sem) 释放信

12、号量自旋锁不会引起调用者的睡眠,线程会移植忙循环,移植等待下去1. spin_lock_init(x)初始化自旋锁2. spin_lock(lock)获取自旋锁,不成功自旋在那3. spin_trylock(lock)不会一直等待4. spin_unlock信号量可以有多个持有者(1个互斥信号量),自旋锁只有一个持有者信号量适合保持时间较长,自旋锁适合保持时间较短Ioctl对硬件进行控制(改变波特率,报告错误信息)用户使用方法:int ioctl(int fd, unsigned long cmd, ) 点表示可选参数int(*ioctl)(struct inode *inode, struc

13、t file *filp, unsigned int cmd, unsigned long arg)cmd用户空间传下来的,arg用户传下来的参数ioctl命令实现方法:1.定义命令 2.实现命令Documentation/ioctl-number.txt定义了使用的幻数ioctl被划分为几个位段,include/asm/ioctl.h定义了这些字段:1. 类型(幻数):8位宽,属于哪一类设备2. 序号:表明设备命令的第几个3. 传送方向:可能的值是_IOC_NONE , _IOC_READ, _IOC_WRITE是从应用程序的观点来看的4 .参数的大小(数据的类型)内核提供下列宏来帮助定义命

14、令_IO(type,nr)没有参数传递_IOR(type, nr, datatype)从驱动中读数据_I0W(type, nr, datatype)从数据到驱动_IOWR(type, nr, datatype)type和number成员作为参数被传递Ioctl函数的实现 1. 返回值 2. 参数使用 3. 命令操作通常是个switch语句,不支持的返回 EINVAL使用ioctl中的参数:整数可以直接使用, 指针则使用前需进行正确的检查参数检查不需要检测的函数:copy_from_user, copy_to_user, get_user, put_user需要检测的函数:_get_user,

15、_put_userint access_ok(int type, const void *addr, unsingned long size)第一参数是VERIFY_READ或者VERIFY_WRITE, addr是要操作的用户内存的地址,size是操作的长度。access_ok返回一个布尔值:1.存取没问题 0. 失败,如果返回失败,则ioctl应当返回-EFAULT. 等待队列:实现进程的阻塞,保存进程的容器,阻塞时放入等待队列,唤醒时,取出进程1 定义等待队列 wait_queue_head_t my_queue2 初始化等待队列 wait_waitqueue_head(&my_queu

16、e)3 定义并初始化等待队列 DECLARE_WAIT_QUEUE_HEAD(my_queue)有条件睡眠wait_event(queue, condition)当condition为真,返回。当condition为假,进入TASK_UNINTERRUTIBLE睡眠,并挂在queue指定的等待队列上wait_event_interruptible(queue, condition)wait_event_killable(queue, conditon)无条件睡眠(老版本,不建议使用)sleep_on(wait_queue_head_t *q) interruptible_sleep_on(wa

17、it_queue_head_t *q) 等待队列中唤醒进程Wake_up(wait_queue_t *q)唤醒等待队列中的所有进程都唤醒Wake_up_interruptible(wait_queue_t *q)唤醒为TASK_INTERRUPTIBLE进程阻塞方式是文件读写的默认方式,应用程序可以使用O_NONBLOCK标志非阻塞的设置了O_NONBLOCK,系统只是简单的返回-EAGAINSelect系统调用对应于pollSelect用于多路监控,如没有一个文件满足要求,select将阻塞进程Int select(int maxfd, fd_set *reedfds, fd_set *wr

18、itefds, fd_set *exceptfds, const struct timeval *timeout)maxfd:文件描述符的范围,比检测的最大文件描述符大1Readfds:被读监控的文件描述符Writefds:被写监控的Exceptfds:被异常监控的Timeout:定时器 Timeout 1. 为0时不管有没有文件满足要求,立即返回,无文件满足,返回02. 为NULL时,select将阻塞进程,直到文件满足要求为止3. 为正整数的时候,等待的最长时间,即select在timeout时间内阻塞进程Select返回值1. 正常返回满足要求的文件描述符个数2. 没有满足的返回03.

19、select被某个信号打断,返回-1 , errno为EINTRSelect系统调用:1. 将要监控的文件添加到文件描述符集2. 调用select开始监控3. 判断文件是否满足要求Void FD_SET(int fd, fd_set *fdset) 将fd添加到fdset中Void FD_CLR(int fd, fd_set *fdset) 在fdset中清楚fdVoid FD_ZERO(fd_set *fdset) 清空fdsetVoid FD_ISSET(int fd, fd_set *fdset) 检测文件描述集中的需判断的fd发生变化驱动通常由poll实现Unsigned int(*p

20、oll)(struct file *filp, poll_table *wait)负责完成:1. 使用poll_wait将等待队列添加到poll_table中2. 返回描述设备是否可读可写的掩码位掩码:POLLIN设备可读,POLLRDNORM数据可读,POLLOUT设备可写,POLLWRNORM数据可写设备可读通常返回(POLLIN | POLLRDNORM)设备可写通常返回(POLLOUT | POLLWRNORM)Poll方法只是做一个登记,真正的阻塞发生在select.c中的do_select函数(分析了do_select函数)自动创建设备文件2.4内核使用devfs_register

21、(devfs_handle_t dir, const char *name, unsigned int flags, unsigned int major unsigned int minor, umode_t mode, void *ops, void *info)Dir:目录名,name:文件名;flags:创建标志;major:主设备号;minor此设备号;mode:创建模式;ops:操作函数集;info:通常为空从2.6.13开始,devfs不复存在,udev成为替代使用1. class_create为设备创建一个class,2. 使用device_create创建对应的设备例:str

22、uct class *myclass = class_create(THIS_MODULE, “my_device_driver”); Device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”)void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)负责把文件内容映射到进程的虚拟内存空间,通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read,write等操作。addr: 映射的起始地址,通常为NU

23、LL,由系统指定length:映射文件的长度prot:映射区的保护方式 PROT_EXEC:映射区可被执行,PROT_READ:映射区可被读取,PROT_WRITE:映射区可被写入flags:映射区的特性 MAP_SHARED:写入映射区的数据会复制回文件,且允许其他映射该文件的进程共享。 MAP_PRIVATE:对映射区的写入操作会产生一个映射区的复制(copy-on-write),对此区域的修改不会写回源文件。fd:由open返回的文件描述符,代表要映射的文件offset:以文件开始处的偏移量,必须是分页大小的整数倍,通常为0,表示从文件头开始映射。注意mmap不能映像原有文件的长度int

24、 munmap(void *start, size_t length)成功返回0,失败返回-1. start的取值一般是mmap返回的地址虚拟内存区域:是虚拟地址空间的一个同质区间,即有同样特性的连续地址范围。一个进程的内存映像由以下几部分组成:程序代码,数据,BSS和栈区域,以及内存映射区域一个进程的内存区域可以通过查看 /proc/pid/maps每一行的域为:start_end perm offset major:minor inodelinux内核使用结构vm_area_struct来描述虚拟内存区域,其中主要成员如下:unsigned long vm_start 虚拟内存区域起始地址

25、unsigned long vm_end 虚拟内存区域结束地址unsigned long vm_flags映射一个设备是指把用户空间的一段地址关联到设备内存上。mmap做了三件事:1.找到用户空间地址(内核完成) 2.找到设备的物理地址(原理图) 3.关联(通过页式管理)mmap设备方法需要做的就是建立虚拟地址到物理地址的页表。int(*mmap)(struct file *, struct vm_area_struct *) 建立页表有两种方法:1.使用remap_pfn_range一次建立所有页表;2.使用nopage VMA方法每次建立一个也表。int remap_pfn_range(s

26、truct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t prot)vma:虚拟内存区域指针 virt_addr:虚拟地址的起始值 pfn:要映射的物理地址所在的物理页祯号,可将物理地址PAGE_SHIFT得到(PAGE_SHIFT为12,相当于除以4KB)size:要映射的区域的大小 prot:VMA的保护属性硬件访问寄存器和内存的区别:寄存器和RAM主要不同在于寄存器操作由副作用(sideeffect或边际效果):读取某刻地址可能导致该地址内容变化,读中断状态

27、寄存器,便自动清零内存与IO在X86存在IO空间(串口 并口等),在32为x86IO空间是64K,内存空间是4G,ARM,PowerPC只有内存地址空间的IO端口:一个寄存器或内存位于IO空间时,称为IO端口IO内存:一个寄存器或内存位于内存空间时,称为IO内存对IO端口的操作需要按如下步骤完成:1,申请 2,访问 3,释放申请:struct resource *request_region(unsigned long first, unsigned long n,const char *name) 从first开始的n个端口,name设备名字系统中端口的分配情况记录在/proc/ioport

28、s中 访问:intb outb intw outw intl outl 释放:void release_region(unsigned long start, unsigned long n)IO内存有4步:1.申请 2,映射 3,访问 4,释放申请:struct resource *request_mem_region(unsigned long start, unsigned longlen,char*name)从start开始,长度为len字节的内存区。成功,返回非NULL,否则返回NULL。可在/proc/iomem中列出访问:在访问IO内存之前,必须进行物理地址到虚拟地址的转化,使用

29、下面函数void *ioremap(unsigned long phys_addr, unsigned long size)访问:ioread8(void *addr) iowrite8(u8 value, void *addr) 老版本 使用readb writeb释放: 1,void iounmap(void *addr) 2,void release_mem_region(unsigned longstart, unsigned long len)混杂设备驱动:共享一个主设备号10,成为混杂设备Linux内核使用struct miscdevice描述混杂设备struct miscdevi

30、ce int minor; const char *name; const struct file_operations *fops; struct list_head list; struct device *parent; struct device *this_device;使用misc_register函数来注册一个混杂设备驱动 misc_register(struct miscdevice *misc)使用上拉下拉避免悬浮Linux总线设备驱动模型(2.6内核难点)Sysfs文件系统(基于内存,展示内核数据结构属性,关系),与proc同类别的文件系统同类别的文件系统,sysfs把连接

31、在系统上的设备和总线组织成分级的文件,使其从用户空间可以访问到sysfs在/sys/目录下block目录:块设备信息 bus:总线(ide pci scsi sbpcmcia)里边还有devices和drivers目录,devices目录下都是软链接class目录:按照功能进行分类(网络)devices:包含系统所有的设备 kernel:内核中的配置参数 Module:系统中所有模块信息firmware:系统中的固件 fs:描述系统中的文件系统 power:系统电源选项Kobject实现了基本的面向对象管理机制,与sysfs文件系统紧密相连,在内核中注册的每个kobject对象对应sysfs文件系统中的一个目录(作用:在sys下创建一个目录)类似于C+中的基类。void kobject_init(struct kobject *kobj) 初始化kobject结构int kobject_add(strut kobject *kobj)将kobject对象注册到Linux系统int kobject_init_and_add(stru

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1