版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Linux设备驱动设备驱动广州嵌入式软件公共技术支持中心梁老师2007年07月设备驱动概述设备驱动概述l操作系统是通过各种驱动程序来驾驭硬件设备,它为操作系统是通过各种驱动程序来驾驭硬件设备,它为用户屏蔽了各种各样的设备用户屏蔽了各种各样的设备,硬件设备的抽象。硬件设备的抽象。l设备驱动程序设备驱动程序: :处理和管理硬件控制器的软件。处理和管理硬件控制器的软件。l设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动概述设备驱动概述l设备由两局部组成,一个是被称为控制器的电器局部,设备由两局部组成,一个是被称为控制器的电器局部,另一个是机械局
2、部。另一个是机械局部。 l一组存放器组被赋予到各个控制器。一组存放器组被赋予到各个控制器。I/O端口包含端口包含4组存组存放器,即状态存放器,控制存放器,数据输入存放器,放器,即状态存放器,控制存放器,数据输入存放器,数据输出存放器。数据输出存放器。l状态存放器拥有可以被状态存放器拥有可以被CPU读取的读取的(状态状态)位,用来位,用来 指指示当前命令是否执行完毕,或者字节是否可以被读出示当前命令是否执行完毕,或者字节是否可以被读出或写入,以及任何错误提示。或写入,以及任何错误提示。l控制存放器那么用于启动一条命令指令或者改变控制存放器那么用于启动一条命令指令或者改变设备的设备的(工作工作)模
3、式。模式。l数据输入存放器用于获取输入的数据。数据输入存放器用于获取输入的数据。l数据输出存放器那么向数据输出存放器那么向CPU发送结果。发送结果。l处理器和设备之间的根本界面是控制和状态存放器。处理器和设备之间的根本界面是控制和状态存放器。 设备驱动概述设备驱动概述l存放器拥有在存放器拥有在I/O空间明确定义的地址范围。空间明确定义的地址范围。l通常这些地址在启动时被分配。通常这些地址在启动时被分配。l如果设备是静态加载的如果设备是静态加载的,各个设备的地址范围可能各个设备的地址范围可能被预分配。这意味内核包含了已存在设备的驱动被预分配。这意味内核包含了已存在设备的驱动 程序。通过运行程序。
4、通过运行“cat /proc/ioports 命令检查命令检查其所使用的地址范围。第一列输出显示了端口的其所使用的地址范围。第一列输出显示了端口的范围而第二列那么是拥用这些端口的设备。范围而第二列那么是拥用这些端口的设备。 设备驱动概述设备驱动概述l设备驱动的概念是非常抽象的并且处于一台计算设备驱动的概念是非常抽象的并且处于一台计算上所运行软件的最低层。上所运行软件的最低层。l由于直接到设备的硬件特性的限由于直接到设备的硬件特性的限 制。每个设备驱制。每个设备驱动都只管理一种单一类型的设备。动都只管理一种单一类型的设备。l如果一个应用如果一个应用 程序向设备提出操作要求。内程序向设备提出操作要
5、求。内核会联系到对应的设备驱动,设备驱动接着向特核会联系到对应的设备驱动,设备驱动接着向特定的设备发出命令。定的设备发出命令。l设备驱设备驱 动是一个函数集合:包含了许多调用入口,动是一个函数集合:包含了许多调用入口,类似于类似于open,close,read,write,ioctl,llseek 等。等。设备驱动概述设备驱动概述lLinuxLinux操作系统把设备纳入文件系统的范畴来管理。操作系统把设备纳入文件系统的范畴来管理。l文件操作是对设备操作的组织和抽象。设备操作那么文件操作是对设备操作的组织和抽象。设备操作那么是对文件操作的最终实现。是对文件操作的最终实现。 l每个设备都对应一个文
6、件名,在内核中也就对应一个每个设备都对应一个文件名,在内核中也就对应一个索引节点。索引节点。 l对文件操作的系统调用大都适用于设备文件。对文件操作的系统调用大都适用于设备文件。 l从应用程序的角度看,设备文件逻辑上的空间是一个从应用程序的角度看,设备文件逻辑上的空间是一个线性空间起始地址为线性空间起始地址为0 0,每读取一个字节加,每读取一个字节加1 1。从。从这个逻辑空间到具体设备物理空间如磁盘的磁道、这个逻辑空间到具体设备物理空间如磁盘的磁道、扇区的映射那么是由内核提供,并被划分为文件操扇区的映射那么是由内核提供,并被划分为文件操作和设备驱动两个层次。作和设备驱动两个层次。设备驱动概述设备
7、驱动概述lLinuxLinux将设备分成两大类。将设备分成两大类。l一类像键盘那样以字符字节为单位,逐个字符进一类像键盘那样以字符字节为单位,逐个字符进行输入输出的设备,称为字符设备。行输入输出的设备,称为字符设备。l一类是像磁盘那样以块或扇区为单位,成块进行输入一类是像磁盘那样以块或扇区为单位,成块进行输入输出的设备,称为块设备。输出的设备,称为块设备。l文件系统通常都建立在块设备上。文件系统通常都建立在块设备上。设备驱动概述设备驱动概述l文件操作和设备驱动是对一个具体的设备操作的不同层文件操作和设备驱动是对一个具体的设备操作的不同层次。从这种观点出发,从概念上可以把一个系统划分为次。从这种
8、观点出发,从概念上可以把一个系统划分为应用、文件系统和设备驱动三个层次。应用、文件系统和设备驱动三个层次。将请求加入请求队列 请求提交操作readsys_readfile- f_op- readdo_generic_file_read用户空间函数内核系统调用文件系统读操作通用文件系统读操作readsys_readfile-f_op-readdo_generic_file_read用户空间函数内核系统调用文件系统读操作submit_bhsubmit_bhadd_requstadd_requst设备驱动概述设备驱动概述设备驱动概述设备驱动概述l要使一项设备可以被应用程序访问,首先要在系统中要使一项
9、设备可以被应用程序访问,首先要在系统中建立一个代表此设备的设备文件,这是通过系统调用建立一个代表此设备的设备文件,这是通过系统调用mknode()mknode()实现的。此外,更重要的是在设备驱动层要实现的。此外,更重要的是在设备驱动层要有这种设备的驱动程序。有这种设备的驱动程序。设备驱动概述设备驱动概述l设备文件:设备文件:l任何设备都被当作路径任何设备都被当作路径/dev /dev 的设备文件处理,并通过的设备文件处理,并通过这些设备文件提供访问硬件的方法。这些设备文件提供访问硬件的方法。l每个设备文件除了设备名外,还有类型、主设备号、每个设备文件除了设备名外,还有类型、主设备号、次设备号
10、这三个属性。次设备号这三个属性。l设备文件是通过设备文件是通过mknodmknod系统调用创立的。其原型为:系统调用创立的。其原型为:mknod(const char mknod(const char * * filename, int mode, dev_t filename, int mode, dev_t dev)dev)lmknod /dev/led0 c 253 0 mknod /dev/led0 c 253 0 设备驱动概述设备驱动概述l主设备号和次设备号:主设备号和次设备号:l主设备号标识设备对应的驱动程序。一般主设备号标识设备对应的驱动程序。一般“一个主设一个主设备号对应一个驱
11、动程序备号对应一个驱动程序l次设备号用于确定设备文件所指的设备。次设备号用于确定设备文件所指的设备。l可通过可通过ls l “ls l “设备文件名命令查看设备的主次设设备文件名命令查看设备的主次设备号,以及设备的类型。备号,以及设备的类型。设备驱动概述设备驱动概述l主设备号和次设备号的内部表达:主设备号和次设备号的内部表达:Dev_t类型用于保存设备号,称为设备编号。类型用于保存设备号,称为设备编号。/linux/types.h文件中定义。文件中定义。目前设备编号目前设备编号dev_t是一个是一个32位的整数,其中位的整数,其中12位位表示主设备号,表示主设备号,20位表示次设备号。位表示次
12、设备号。通过设备编号获取主次设备号:通过设备编号获取主次设备号:MAJOR(dev_t dev);MINOR(dev_t dev);通过主次设备号合成设备编号:通过主次设备号合成设备编号:MKDEV(int major, int minor);Dev_t格式以后可能会发生变化,但只要使用这些格式以后可能会发生变化,但只要使用这些宏,就可保证设备驱动程序的正确性。宏,就可保证设备驱动程序的正确性。一些重要的数据结构一些重要的数据结构l大局部驱动程序涉及三个重要的内核数据结构:大局部驱动程序涉及三个重要的内核数据结构:l文件操作文件操作file_operationsfile_operations结
13、构体结构体l文件对象文件对象filefile结构体结构体l索引节点索引节点inodeinode结构体结构体一些重要的数据结构一些重要的数据结构l文件操作结构体文件操作结构体file_operations结构体结构体file_operations在头文件在头文件 linux/fs.h中定义,中定义,用来存储驱动内核模块提供的用来存储驱动内核模块提供的对设备进行各种操作对设备进行各种操作的函数的指针的函数的指针。结构体的每个域都对应着驱动模块用来处理某个被结构体的每个域都对应着驱动模块用来处理某个被请求的事务的函数的地址。请求的事务的函数的地址。struct file_operations str
14、uct 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 char _user *, size_t, loff_t *);。 一些重要的数据结构一些重要的数据结构lfile_operations重要的成员重要的成员Struct module *owner ,指向拥有该结构体的模,指向拥有该结构体的模块的指针。块的指针。方法
15、方法llseek用来修改文件的当前读写位置,把新位用来修改文件的当前读写位置,把新位置作为返回值返回。置作为返回值返回。方法方法read用来从设备中读取数据。非负返回值表示用来从设备中读取数据。非负返回值表示成功读取的直接数。成功读取的直接数。方法方法write向设备发送数据。向设备发送数据。方法方法ioctl提供一种执行设备特定命令的方法。提供一种执行设备特定命令的方法。一些重要的数据结构一些重要的数据结构lfile_operations重要的成员重要的成员驱动内核模块是不需要实现每个函数的。相对应的驱动内核模块是不需要实现每个函数的。相对应的file_operations的项就为的项就为
16、NULL。Gcc的语法扩展,使得可以定义该结构体:的语法扩展,使得可以定义该结构体:struct file_operations fops = read: device_read, write: device_write, open: device_open, release: device_release ; 这种语法清晰,没有显示声明的结构体成员都被这种语法清晰,没有显示声明的结构体成员都被gcc初始化为初始化为NULL。 一些重要的数据结构一些重要的数据结构lfile_operations重要的成员重要的成员标准标准C的标记化结构体的初始化方法:的标记化结构体的初始化方法:struct
17、file_operations fops = .read = device_read,.write = device_write, .open = device_open, .release = device_release; 推荐使用该方法,提高移植性,方法允许对结构体成员进行重推荐使用该方法,提高移植性,方法允许对结构体成员进行重新排列。新排列。没有显示声明的结构体成员同样都被没有显示声明的结构体成员同样都被gcc初始化为初始化为NULL。指向结构体指向结构体file_operations的指针通常命名为的指针通常命名为fops。 一些重要的数据结构一些重要的数据结构l文件对象文件对象fi
18、le结构体结构体l文件对象文件对象file代表着一个翻开的文件。进程通过文件描代表着一个翻开的文件。进程通过文件描述符述符fd与已翻开文件的与已翻开文件的file结构相联系。进程通过它对结构相联系。进程通过它对文件的线性逻辑空间进行操作。例如:文件的线性逻辑空间进行操作。例如:file-f_op-read();lStruct file 在在中定义。中定义。l指向结构体指向结构体struct file的指针通常命名为的指针通常命名为filp,或者,或者file。建议使用文件指针建议使用文件指针filp。一些重要的数据结构一些重要的数据结构l文件对象文件对象file结构体的成员结构体的成员lStr
19、uct file_operations *f_op;l与文件相关的操作结构体指针。与文件相关与文件相关的操作结构体指针。与文件相关的操作是在翻开文件的时候确定下来的,也就的操作是在翻开文件的时候确定下来的,也就是确定该指针的值。可在需要的时候,改变指是确定该指针的值。可在需要的时候,改变指针所指向的文件操作结构体。用针所指向的文件操作结构体。用C语言实现面语言实现面向对象编程的方法重载。向对象编程的方法重载。l其他成员可先忽略,后面具体实例分析。因为其他成员可先忽略,后面具体实例分析。因为设备驱动模块并不自己直接填充结构体设备驱动模块并不自己直接填充结构体 file,只是使用只是使用file中
20、的数据。中的数据。 一些重要的数据结构一些重要的数据结构l索引节点索引节点inode结构结构l文件翻开,在内存建立副本后,由唯一的索引文件翻开,在内存建立副本后,由唯一的索引节点节点inode描述。描述。l与与file结构不同。结构不同。lfile结构是进程使用的结构,进程每翻开一个文结构是进程使用的结构,进程每翻开一个文件,就建立一个件,就建立一个file结构。不同的进程翻开同一结构。不同的进程翻开同一个文件,建立不同的个文件,建立不同的file结构。结构。lInode结构是内核使用的结构,文件在内存建结构是内核使用的结构,文件在内存建立副本,就建立一个立副本,就建立一个inode结构来描述
21、。一个结构来描述。一个文件在内存里面只有一个文件在内存里面只有一个inode结构对应。结构对应。一些重要的数据结构一些重要的数据结构l索引节点索引节点inode结构结构Inode结构包含大量描述文件信息的成员变量。结构包含大量描述文件信息的成员变量。但是对于描述设备文件的但是对于描述设备文件的inode,跟设备驱动有关,跟设备驱动有关的成员只有两个。的成员只有两个。Dev_t i_rdev; 包含真正的设备编号。包含真正的设备编号。Struct cdev *i_cdev; 指向指向cdev结构体的指针。结构体的指针。cdev是表示字符设备的内核数据结构。是表示字符设备的内核数据结构。从从ino
22、de中获得主设备号和次设备号的宏:中获得主设备号和次设备号的宏:Unsigned int iminor(struct inode *inode);Unsigned int imajor(struct inode *inode);驱动程序中的内存分配驱动程序中的内存分配l在在Linux内核模式下,不能使用用户态的内核模式下,不能使用用户态的malloc()和和free()函数申请和释放内存。函数申请和释放内存。l内核编程最常用的内存申请和释放函数为内核编程最常用的内存申请和释放函数为kmalloc()和和kfree(),其原型为:,其原型为:linclude/linux/kernel.hlvoi
23、d *kmalloc(unsigned int len, int priority);lvoid kfree(void *_ptr);lpriority参数参数:l通常设置为通常设置为GFP_KERNEL,可能会引起睡眠,可能会引起睡眠.l如果在中断效劳程序里申请内存那么要用如果在中断效劳程序里申请内存那么要用GFP_ATOMIC参数,在中断中是不允许睡眠的。参数,在中断中是不允许睡眠的。初始化和卸载函数初始化和卸载函数l驱动程序是内核的一局部,因此我们需要给其添驱动程序是内核的一局部,因此我们需要给其添加模块初始化函数,该函数用来完成对所控设备加模块初始化函数,该函数用来完成对所控设备的初始
24、化工作,并调用的初始化工作,并调用register_chrdev() 函数函数注册字符设备注册字符设备.lint register_chrdev(unsigned int major, const char *name, struct file_operations *fops);lmajor 是给定的主设备号。为是给定的主设备号。为0代表什么?代表什么?lname 是驱动的名字是驱动的名字(将出现在将出现在 /proc/devices), lfops 是设备驱动的是设备驱动的file_operations 结构。结构。lregister_chrdev 将给设备分配将给设备分配 0 - 255
25、 的次设的次设备号备号, 并且为每一个建立一个缺省的并且为每一个建立一个缺省的 cdev 结构。结构。l与模块初始化函数对应的就是模块卸载函数,需与模块初始化函数对应的就是模块卸载函数,需要调用要调用register_chrdev()的的反函数反函数设备操作函数集的定义设备操作函数集的定义lfile_operations结构体,驱动程序只是利用其中结构体,驱动程序只是利用其中的一局部。的一局部。l对于字符设备来说,要提供的主要入口有:对于字符设备来说,要提供的主要入口有:open ()、release ()、read ()、write ()、ioctl ()等。等。设备操作函数集的定义设备操作
26、函数集的定义lopen()函数函数对设备特殊文件进行对设备特殊文件进行open()系统调用时,将调用驱动系统调用时,将调用驱动程序的程序的open () 函数:函数:int (int (* *open)(struct inode open)(struct inode * * ,struct file ,struct file * *););参数参数inode为设备特殊文件的为设备特殊文件的inode (索引结点索引结点) 结结构的指针,构的指针,参数参数file是指向这一设备的文件结构的指针。是指向这一设备的文件结构的指针。open()的主要任务是确定硬件处在就绪状态、验证次的主要任务是确定硬
27、件处在就绪状态、验证次设备号的合法性设备号的合法性(次设备号可以用次设备号可以用MINOR(inode- i - rdev) 取得取得)、控制使用设备的进程数、根据执行情况、控制使用设备的进程数、根据执行情况返回状态码返回状态码(0表示成功,负数表示存在错误表示成功,负数表示存在错误) 等;等;设备操作函数集的定义设备操作函数集的定义lrelease()函数函数l当最后一个翻开设备的用户进程执行当最后一个翻开设备的用户进程执行close ()系系统调用时,内核将调用驱动程序的统调用时,内核将调用驱动程序的release () 函函数:数:lvoid (*release) (struct ino
28、de * ,struct file *) ;lrelease 函数的主要任务是清理未结束的输入函数的主要任务是清理未结束的输入/输输出操作、释放资源、用户自定义排他标志的复位出操作、释放资源、用户自定义排他标志的复位等等.设备操作函数集的定义设备操作函数集的定义lread()函数函数lRead的任务的任务, 就是从设备拷贝数据到用户空间。就是从设备拷贝数据到用户空间。l当对设备特殊文件进行当对设备特殊文件进行read() 系统调用时,将调系统调用时,将调用驱动程序用驱动程序read() 函数:函数:lssize_t read(struct file *filp, char _user *buf
29、f, size_t count, loff_t *offp);lfilp 是文件对象指针是文件对象指针, lcount 是请求的传输数据大小是请求的传输数据大小. lbuff 参数对参数对write来说是指向持有被写入数据的来说是指向持有被写入数据的缓存缓存, 对对read那么是放入新数据的空缓存那么是放入新数据的空缓存. loffp 是指向一个是指向一个“long offset type的指针的指针, 它它指出用户正在存取的文件位置指出用户正在存取的文件位置. l返回值是返回值是“signed size type类型类型;设备操作函数集的定义设备操作函数集的定义lwrite( ) 函数函数l
30、Write的任务,那么从用户空间拷贝数据到设备。的任务,那么从用户空间拷贝数据到设备。l当设备特殊文件进行当设备特殊文件进行write () 系统调用时,将调系统调用时,将调用驱动程序的用驱动程序的write () 函数:函数:lssize_t write(struct file *filp, const char _user *buff, size_t count, loff_t *offp);lfilp 是文件对象指针是文件对象指针, lcount 是请求的传输数据大小是请求的传输数据大小. lbuff 参数对参数对write来说是指向持有被写入数据的来说是指向持有被写入数据的缓存缓存,
31、对对read那么是放入新数据的空缓存那么是放入新数据的空缓存. loffp 是指向一个是指向一个“long offset type的指针的指针, 它它指出用户正在存取的文件位置指出用户正在存取的文件位置. l返回值是返回值是“signed size type类型类型;设备操作函数集的定义设备操作函数集的定义lread 和和 write 方法的方法的 buff 参数是用户空间指针,参数是用户空间指针,不能被内核代码直接解引用。不能被内核代码直接解引用。_user字符串只是字符串只是形式上的说明,说明是用户空间地址。形式上的说明,说明是用户空间地址。l驱动必须能够存取用户空间缓存以完成它的工作。驱
32、动必须能够存取用户空间缓存以完成它的工作。内核如何解决这个问题?内核如何解决这个问题?l为平安起见,内核提供专用的函数来完成对用户为平安起见,内核提供专用的函数来完成对用户空间的存取。这些专用函数在空间的存取。这些专用函数在中声明。中声明。lunsigned long copy_to_user(void _user *to,const void *from,unsigned long count);lunsigned long copy_from_user(void *to,const void _user *from,unsigned long count);l大多数读写函数都会调用这两个函
33、数,用于跟应大多数读写函数都会调用这两个函数,用于跟应用程序空间交流信息。用程序空间交流信息。Read和和Write方法方法l典型的典型的Read函数对参数的使用。函数对参数的使用。S3C2410 的I/O 介绍lS3C2410 有117 个复用功能输入输出端口引脚,这些引脚是:lPortA(GPA):32 个输入/输出端口lPortB(GPB):11 个输入/输出端口lPortC(GPC):16 个输入/输出端口lPortD(GPD):16 个输入/输出端口lPortE(GPE):16 个输入/输出端口lPortF(GPF):8 个输入/输出端口lPortG(GPG):16 个输入/输出端口
34、lPortH(GPH):11 个输入/输出端口S3C2410 的I/O 介绍l端口控制说明l端口配置存放器GPACONGPHCONl大局部的引脚是复用的,所以必须对于每个引脚要求定义一个功能,端口配置存放器定义了每个引脚的功能。l端口数据存放器GPADATGPHDATl如果端口配置成输出端口,数据能够被写到端口数据存放器的对应位,然后通过管脚输出。如果端口配置成输入端口,能从端口数据存放器对应的位中读出管脚上的电平l端口上拉存放器GPBUPGPHUPl端口上拉存放器控制着每个端口组的上拉存放器的使能或禁止,当对应位为0,这个引脚的上拉存放器是允许的,当为1 时,上拉存放器是禁止的。MIZI提供
35、的提供的S3C2410.Hl使用一个使用一个32位的数来表示端口的使用情况。位的数来表示端口的使用情况。l模式模式 |上拉上拉 |端口端口 | 端口引脚端口引脚lMODE | PULLUP | PORT | OFSl不需要自己手动组合,通过宏定义以及不需要自己手动组合,通过宏定义以及SHIFT和和MASK组合。见程序组合。见程序MIZI提供的提供的S3C2410.Hl端口的表示端口的表示l#define PORTA_OFS0l#define PORTB_OFS1l#define PORTC_OFS2l#define PORTD_OFS3l#define PORTE_OFS4l#define P
36、ORTF_OFS5l#define PORTG_OFS6l#define PORTH_OFS7MIZI提供的提供的S3C2410.Hl端口引脚的表示端口引脚的表示l#define GPIO_A0MAKE_GPIO_NUM(PORTA_OFS, 0)l#define GPIO_A1MAKE_GPIO_NUM(PORTA_OFS, 1)l#define GPIO_A2MAKE_GPIO_NUM(PORTA_OFS, 2)l#define GPIO_A3MAKE_GPIO_NUM(PORTA_OFS, 3)l。l#define MAKE_GPIO_NUM(p, o)(p GPIO_PORT_SHIF
37、TT) | (o GPIO_OFS_SHIFT)MIZI提供的提供的S3C2410.Hlset_gpio_ctrl(x) l功能:配置端口引脚的功能,设置功能:配置端口引脚的功能,设置IO口控制存放口控制存放器和上拉存放器器和上拉存放器l用法:用法:set_gpio_ctrl(模式模式|上拉上拉?|IO脚脚) l模式模式|是否上拉是否上拉|IO脚,在脚,在S3C2410.h中都有其定义中都有其定义好的名字。好的名字。l lset_gpio_ctrl(GPIO_E11 | GPIO_PULLUP_DIS |GPIO_MODE_OUT);MIZI提供的提供的S3C2410.Hlwrite_gpio
38、_bit(x, v) l功能:把端口功能:把端口 对应的端口数据存放器对应的端口数据存放器x位设置为位设置为vlwrite_gpio_bit(GPIO_E11, 0); lread_gpio_bit(x) l功能:把端口数据存放器功能:把端口数据存放器x位的状态位的状态 读入,函数读入,函数返回值既是其状态返回值既是其状态lread_gpio_bit(GPIO_G11); MIZI提供的提供的S3C2410.Hlwrite_gpio_reg(x, v) l功能:把端口数据存放器功能:把端口数据存放器x 设置为设置为v lread_gpio_reg(x) l功能:读取端口数据存放器功能:读取端口
39、数据存放器x,函数返回值既是,函数返回值既是其数据其数据 l按驱动的框架写好驱动,实现初始化、卸载函数,按驱动的框架写好驱动,实现初始化、卸载函数,以及以及file_opertation操作集。操作集。l对于对于led使用的使用的gpio函数,内核没有输出作为公函数,内核没有输出作为公开符号,所以需要手动修改内核代码,代码放在开符号,所以需要手动修改内核代码,代码放在arch/arm/march-s3c2410/gpio.c,输出符号:,输出符号:EXPORT_SYMBOL(s3c2410_gpio_setpin);EXPORT_SYMBOL(s3c2410_gpio_cfgpin);EXPO
40、RT_SYMBOL(s3c2410_gpio_pullup);l编写驱动模块的编写驱动模块的Makefile。l交叉编译驱动模块交叉编译驱动模块lNFS加载驱动模块,进行测试。加载驱动模块,进行测试。嵌入式键盘驱动广州嵌入式软件公共技术支持中心广州嵌入式软件公共技术支持中心梁老师2007年7月注册中断效劳例程注册中断效劳例程 l中断线是一个珍贵且常常有限的资源中断线是一个珍贵且常常有限的资源, , 特别当它特别当它们只有们只有1515个时。内核维护一个中断线的注册表。个时。内核维护一个中断线的注册表。l要使用中断线,就要进行中断线的申请,也就是要使用中断线,就要进行中断线的申请,也就是IRQ(
41、Interrupt ReQuirement)IRQ(Interrupt ReQuirement),因此我们也常把,因此我们也常把申请一条中断线称为申请一个申请一条中断线称为申请一个IRQIRQ或者是申请一或者是申请一个中断号。个中断号。lIRQIRQ线是从线是从0 0开始顺序编号的;第一条开始顺序编号的;第一条IRQIRQ线通常线通常表示成表示成IRQ0IRQ0。IRQnIRQn的缺省向量是的缺省向量是n+32n+32。注册中断效劳例程注册中断效劳例程 l并不是每个设备都可以向中断线上发中断信号的,并不是每个设备都可以向中断线上发中断信号的,只有对某一条确定的中断线拥有了控制权,才可只有对某一
42、条确定的中断线拥有了控制权,才可以向这条中断线上发送信号。以向这条中断线上发送信号。l计算机的外部设备越来越多,所以计算机的外部设备越来越多,所以1515条中断线已条中断线已经不够用了,中断线是非常珍贵的资源。经不够用了,中断线是非常珍贵的资源。l只有当设备需要中断的时候才申请占用一个只有当设备需要中断的时候才申请占用一个IRQIRQ,或者是在申请或者是在申请IRQIRQ时采用共享中断的方式,这样时采用共享中断的方式,这样可以让更多的设备使用中断。可以让更多的设备使用中断。注册中断效劳例程注册中断效劳例程 l在在 实现中断注册接口实现中断注册接口:int request_irq(unsigne
43、d int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),unsigned long flags,const char *dev_name, void *dev_id);void free_irq(unsigned int irq, void *dev_id);lrequest_irq 的返回值是的返回值是 0 指示申请成功,为负指示申请成功,为负值时表示错误码。函数返回值时表示错误码。函数返回 -EBUSY 表示已经有表示已经有另一个驱动占用了所要申请的中断线。另一个驱动占用了所要申请的中断线。注册中断效劳例程注册中断效
44、劳例程 lrequest_irq的参数说明:的参数说明:unsigned int irq, 要申请的中断号。要申请的中断号。对某些设备,如传统对某些设备,如传统PC设备上的系统时钟或键盘,设备上的系统时钟或键盘,这个值通常是预先确定的。这个值通常是预先确定的。而对于大多数其它设备来说,这个值要么可以通过而对于大多数其它设备来说,这个值要么可以通过探测获取,要么可以动态确定。探测获取,要么可以动态确定。irqreturn_t (*handler)(int, void *, struct pt_regs *),要安装的中断处理函数指针。后面介绍。注册中断效劳例程注册中断效劳例程 lrequest_
45、irq的参数说明:的参数说明:lunsigned long flags,l与中断管理相关的位掩码选项。与中断管理相关的位掩码选项。lconst char *dev_name, l用在用在 /proc/interrupts 中显示中断的拥有者。中显示中断的拥有者。lvoid *dev_idl这个指针用于共享的中断线。做为驱动程序的这个指针用于共享的中断线。做为驱动程序的私有数据区可用来识别那个设备产生的中断。私有数据区可用来识别那个设备产生的中断。不使用共享中断线方式时,可设置为不使用共享中断线方式时,可设置为NULL。注册中断效劳例程注册中断效劳例程 lflags参数的详细说明:lFlags的
46、每个位有不同含义lSA_INTERRUPTl当该位被设置时, 表示这是一个“快速中断。快速中断处理例程运行时,屏蔽中断。lSA_SHIRQl这个位表示中断可以在设备间共享。proc 文件系统中的中断信息文件系统中的中断信息l/proc/interrupts反映系统的中断信息反映系统的中断信息第一列是 IRQ 号给出每个中断线发生中断的次数。给出每个中断线发生中断的次数。给出处理中断的可编程中断控制器。给出处理中断的可编程中断控制器。给出在该中断号上注册中断处理例程的设备名称。给出在该中断号上注册中断处理例程的设备名称。实现中断处理例程实现中断处理例程l首先中断处理例程也是普通的首先中断处理例程
47、也是普通的C程序。程序。l特别之处:特别之处:在中断时间内运行,不能向用户空间发送或者接收数在中断时间内运行,不能向用户空间发送或者接收数据。据。不能做任何导致休眠的操作。不能做任何导致休眠的操作。不能调用不能调用schedule函数。函数。无论快速还是慢速中断处理例程,都应该设计成执行无论快速还是慢速中断处理例程,都应该设计成执行时间尽可能短。时间尽可能短。实现中断处理例程实现中断处理例程l中断处理函数的参数和返回值中断处理函数的参数和返回值lirqreturn_t (*handler)(int, void *, struct pt_regs *)lirqreturn_t short_int
48、errupt(int irq, void *dev_id, struct pt_regs *regs)lIrq 中断号中断号lDev_id 驱动程序可用的数据区,通常可传递指驱动程序可用的数据区,通常可传递指向描述设备的数据结构指针。向描述设备的数据结构指针。lstruct pt_regs *regs,保存了处理器进入中断,保存了处理器进入中断代码之前的代码之前的cpu存放器的值。一般驱动可不要。存放器的值。一般驱动可不要。矩阵式键盘原理矩阵式键盘原理l矩阵式键盘一般适用于按键数量较多的场合,它由行线矩阵式键盘一般适用于按键数量较多的场合,它由行线和列线组成,按键位于行、列的交叉点上。和列线组
49、成,按键位于行、列的交叉点上。l如下图,一个如下图,一个44的行、列结构可以构成一个有的行、列结构可以构成一个有16个按个按键的键盘。键的键盘。矩阵式键盘原理矩阵式键盘原理l按键设置在行、列交叉点上,行、列分别连接到按键设置在行、列交叉点上,行、列分别连接到按键开关的两端。行线通过上拉电阻接到十按键开关的两端。行线通过上拉电阻接到十5 V上。上。l平时无按键动作时,行线处于高电平状态平时无按键动作时,行线处于高电平状态;而当有而当有健按下时,行线电平状态将由通过此按键的列线健按下时,行线电平状态将由通过此按键的列线电平决定电平决定:列线电平如果为低,行线电平为低列线电平如果为低,行线电平为低;列列线电平如果为高,那么行线电平亦为高。这一点线电平如果为高,那么行线电平亦为高。这一点是识别矩阵式键盘是否被按下的关键所在。是识别矩阵式键盘是否被按下的关键所在。矩阵式键盘原理矩阵式键盘原理l矩阵键盘按键的识别方法分两步进行矩阵键盘按键的识别方法分两步进行:l识别键盘哪一行的键被按下。让所有列线均为识别键盘哪一行的键被按下。让所有列线均为低电平,检查各行线电平是否为低。如果有行线低电平,检查各行线电平是否为低。如果有行线为低,那么说明该行有键被按下,否那么说明无为低,那么说明该行有键被按下,否那么说明无键被按下
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 青岛理工大学公差与技术测量期末复习题及参考答案
- 21个领导力法则
- 业务新员工年终总结
- 组成意义心电图波的和
- 做六有青年活动
- 社区护理基础-1729734559038
- 言语治疗技术失语症的分类
- 剖腹产后护理查房
- 北京市顺义区2021届高三下学期第二次统练化学试题
- 医疗垃圾整顿
- 医学院《急诊医学》教学大纲
- 戏剧艺术概论-中央戏剧学院中国大学mooc课后章节答案期末考试题库2023年
- 巯基乙醇化学品安全技术说明书
- 小学道德与法治课评分表
- 汽修厂搞个优惠活动
- 幼儿园教研五大领域主题30篇
- 2023年民俗博物馆防火、防盗、防恐应急预案
- 七年级劳动技能课全册教案
- 法学英语论文
- 如何培养一支高素质的班干部演示文稿
- 2023年西安国际港务区招聘笔试参考题库附带答案详解
评论
0/150
提交评论