




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第7章 嵌入式Linux设备驱动程序开发 第第7 7章章 嵌入式嵌入式LinuxLinux设备驱动程序开发设备驱动程序开发 7.1 嵌入式嵌入式Linux的设备管理的设备管理7.2 设备驱动模块化编程设备驱动模块化编程7.3 GPIO字符设备驱动程序设计字符设备驱动程序设计7.4 A/D转换器驱动程序设计转换器驱动程序设计7.5 IC卡驱动程序设计卡驱动程序设计7.6 内核驱动程序设计内核驱动程序设计触摸屏驱动程序触摸屏驱动程序第7章 嵌入式Linux设备驱动程序开发 第第7章章 嵌入式嵌入式Linux设备驱动程序开发设备驱动程序开发 7.1 嵌入式嵌入式Linux的设备管理的设备管理设备驱动
2、程序实际是处理和操作硬件控制器的软件,从本质上设备驱动程序实际是处理和操作硬件控制器的软件,从本质上讲,是内核中具有最高特权级的、驻留内存的、可共享的底层讲,是内核中具有最高特权级的、驻留内存的、可共享的底层硬件处理例程。完成以下功能:硬件处理例程。完成以下功能: 对设备初始化和释放;对设备初始化和释放; 对设备进行管理,包括实时参数设置,以及提供对设备的操对设备进行管理,包括实时参数设置,以及提供对设备的操作接口;作接口; 读取应用程序传送给设备文件的数据或者回送应用程序请求读取应用程序传送给设备文件的数据或者回送应用程序请求的数据;的数据; 检测和处理设备出现的错误。检测和处理设备出现的错
3、误。第7章 嵌入式Linux设备驱动程序开发 整个设备管理子系统的结构如图整个设备管理子系统的结构如图7.1 所示。所示。 图图7.1设备管理系统结构设备管理系统结构 第7章 嵌入式Linux设备驱动程序开发 7.1.1 设备驱动和文件系统的关系设备驱动和文件系统的关系 open 打开设备准备打开设备准备I/O操作。操作。 其调用格式为其调用格式为: :int open(char *filename, int access); 第7章 嵌入式Linux设备驱动程序开发 close close() close close()函数的作用是关闭由函数的作用是关闭由open()open()函数打开的函
4、数打开的文件文件, , 其调用格式为其调用格式为: :int close(int handle);int close(int handle);该函数关闭文件描述字该函数关闭文件描述字handle handle 相连的文件。相连的文件。 read 从设备上读数据。对于有缓冲区的从设备上读数据。对于有缓冲区的I/O 操作,一般操作,一般是从缓冲区里读数据。是从缓冲区里读数据。 write write 往设备上写数据,对于有缓冲区的往设备上写数据,对于有缓冲区的I/O I/O 操作,一操作,一般是把数据写入缓冲区里。般是把数据写入缓冲区里。write()write()函数的调用格式为:函数的调用格式
5、为:int write(int handle, void int write(int handle, void * *buf, int count);buf, int count);write()write()函数把函数把count count 个字节从个字节从buf buf 指向的缓冲区写入与指向的缓冲区写入与handle handle 相连的文件中,返回值为实际写入的字节数。相连的文件中,返回值为实际写入的字节数。 第7章 嵌入式Linux设备驱动程序开发 ioctl ioctl主要用于对设备进行读写之外的其他控制。主要用于对设备进行读写之外的其他控制。用户空间的用户空间的ioctl io
6、ctl 函数的原型为:函数的原型为:int ioctl(inf fd,int cmd,)int ioctl(inf fd,int cmd,)其中的其中的代表可变数目的参数表,实际中是一个可选参数,一般定代表可变数目的参数表,实际中是一个可选参数,一般定义为义为: :int ioctl(inf fd,int cmd,char int ioctl(inf fd,int cmd,char * *argp)argp)驱动程序中定义的驱动程序中定义的ioctl ioctl 方法原型为:方法原型为:int (int (* *ioctl) (struct inode ioctl) (struct inode
7、 * *inode, struct file inode, struct file * *file,unsigned int cmd, unsigned long arg)file,unsigned int cmd, unsigned long arg)inode inode 和和filp filp 两个指针对应应用程序传递的文件描述符两个指针对应应用程序传递的文件描述符fdfd、cmd cmd 不会被修改地传递给驱动程序,可选的参数不会被修改地传递给驱动程序,可选的参数arg arg 则无论用户应用程则无论用户应用程序使用的是指针还是其他类型值,都以序使用的是指针还是其他类型值,都以unsi
8、gned long unsigned long 的形式传递的形式传递给驱动。给驱动。第7章 嵌入式Linux设备驱动程序开发 7.1.2 设备类型设备类型 Linux 中的设备可以分为三类:中的设备可以分为三类: 字符设备字符设备 块设备块设备 网络设备网络设备。 一个运行的一个运行的linux linux 系统,当前使用的设系统,当前使用的设备可以通过文件备可以通过文件/proc/devices/proc/devices 查看。查看。 第7章 嵌入式Linux设备驱动程序开发 7.1.3 设备号设备号 linux/uclinux linux/uclinux 内核还需要内核还需要 : :主设备
9、号主设备号标识设备对应的驱动程序。系统中不同标识设备对应的驱动程序。系统中不同的设备可以有相同的主设备号,主设备号相同的的设备可以有相同的主设备号,主设备号相同的设备使用相同的驱动程序。设备使用相同的驱动程序。 次设备号次设备号用来区分具体驱动程序的实例。一个主用来区分具体驱动程序的实例。一个主设备号可能有多个设备与之对应,这多个设备正设备号可能有多个设备与之对应,这多个设备正是在驱动程序内通过次设备号来进一步区分的。是在驱动程序内通过次设备号来进一步区分的。次设备号只能由设备驱动程序使用,内核的其他次设备号只能由设备驱动程序使用,内核的其他部分仅将它作为参数传递给驱动程序。部分仅将它作为参数
10、传递给驱动程序。第7章 嵌入式Linux设备驱动程序开发 字符型设备主设备号的添加和注销字符型设备主设备号的添加和注销 字符型设备主设备号的添加和注销分别通过调用函数字符型设备主设备号的添加和注销分别通过调用函数register_chrdev()register_chrdev()和和unregister_chrdev()unregister_chrdev()实现,这两实现,这两个函数原型在个函数原型在文件说明。文件说明。extern int register_chrdev(unsigned int major, extern int register_chrdev(unsigned int m
11、ajor, const char const char * *name, struct file_operations name, struct file_operations * *fops);fops);extern int unregister_chrdev(unsigned int major, extern int unregister_chrdev(unsigned int major, const char const char * *name);name);第7章 嵌入式Linux设备驱动程序开发 7.1.4 设备驱动中关键数据结构设备驱动中关键数据结构 在在linuxlinu
12、x系统中,设备驱动程序所提供系统中,设备驱动程序所提供的这组入口点由一个文件操作结构进行说的这组入口点由一个文件操作结构进行说明,分别是明,分别是: : file_operationsfile_operations数据结构数据结构 inodeinode数据结构数据结构 filefile数据结构数据结构, 它们定义于它们定义于Linux/fs.hLinux/fs.h文件中。文件中。 第7章 嵌入式Linux设备驱动程序开发 1. file_operations数据结构数据结构 struct file_operations struct file_operations struct module
13、struct module * *owner;owner;loff_t (loff_t (* *llseek) (struct file llseek) (struct file * *, loff_t, int);, loff_t, int);ssize_t (ssize_t (* *read) (struct file read) (struct file * *, char , char * *, size_t, loff_t , size_t, loff_t * *););ssize_t (ssize_t (* *write) (struct file write) (struct f
14、ile * *, const char , const char * *, size_t, loff_t , size_t, loff_t * *););int (int (* *readdir) (struct file readdir) (struct file * *, void , void * *, filldir_t);, filldir_t);unsigned int (unsigned int (* *poll) (struct file poll) (struct file * *, struct poll_table_struct , struct poll_table_s
15、truct * *););int (int (* *ioctl) (struct inode ioctl) (struct inode * *, struct file , struct file * *, unsigned int, unsigned , unsigned int, unsigned long);long);int (int (* *mmap) (struct file mmap) (struct file * *, struct vm_area_struct , struct vm_area_struct * *););int (int (* *open) (struct
16、inode open) (struct inode * *, struct file , struct file * *););int (int (* *flush) (struct file flush) (struct file * *););第7章 嵌入式Linux设备驱动程序开发 int (int (* *release) (struct inode release) (struct inode * *, struct file , struct file * *););int (int (* *fsync) (struct file fsync) (struct file * *,
17、struct dentry , struct dentry * *, int datasync);, int datasync);int (int (* *fasync) (int, struct file fasync) (int, struct file * *, int);, int);int (int (* *lock) (struct file lock) (struct file * *, int, struct file_lock , int, struct file_lock * *););ssize_t (ssize_t (* *readv) (struct file rea
18、dv) (struct file * *, const struct iovec , const struct iovec * *, unsigned long, , unsigned long, loff_t loff_t * *););ssize_t (ssize_t (* *writev) (struct file writev) (struct file * *, const struct iovec , const struct iovec * *, unsigned long, , unsigned long, loff_t loff_t * *););ssize_t (ssize
19、_t (* *sendpage) (struct file sendpage) (struct file * *, struct page , struct page * *, int, size_t, , int, size_t, loff_t loff_t * *, int);, int);unsigned long (unsigned long (* *get_unmapped_area)(struct file get_unmapped_area)(struct file * *,unsigned ,unsigned long,unsigned long,unsigned long,
20、unsigned long);long,unsigned long,unsigned long, unsigned long);第7章 嵌入式Linux设备驱动程序开发 在在file_operationsfile_operations数据结构中,指出了设备驱动程序所提供的入数据结构中,指出了设备驱动程序所提供的入口点位置,分别是:口点位置,分别是:owner module owner module 的拥有者。的拥有者。lseeklseek移动文件指针的位置,只能用于可以随机存取的设备。移动文件指针的位置,只能用于可以随机存取的设备。readread进行读操作,进行读操作,bufbuf为存放读取
21、结果的缓冲区,为存放读取结果的缓冲区,countcount为所要为所要读取的数据长度。读取的数据长度。writewrite进行写操作,与进行写操作,与readread类似。类似。readdirreaddir只用于文件系统,对设备无用。只用于文件系统,对设备无用。selectselect进行选择操作。进行选择操作。ioctlioctl进行读、写以外的其他操作。进行读、写以外的其他操作。第7章 嵌入式Linux设备驱动程序开发 mmapmmap用于把设备的内容映射到地址空间,一般只有块设备驱用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用。动程序使用。openopen打开设备进行打开设备
22、进行I/OI/O操作。返回操作。返回0 0表示成功,返回负数表示表示成功,返回负数表示失败。失败。releaserelease关闭设备并释放资源。即关闭设备并释放资源。即close close 操作。操作。 flushflush清除内容,一般只用于网络文件系统中。清除内容,一般只用于网络文件系统中。fsyncfsync实现内存与设备的同步,如将内存数据写入硬盘。实现内存与设备的同步,如将内存数据写入硬盘。fasyncfasync实现内存与设备之间的异步通讯。实现内存与设备之间的异步通讯。locklock文件锁定,用于文件共享时的互斥访问。文件锁定,用于文件共享时的互斥访问。readvreadv
23、在进行读操作前要验证地址是否可读。在进行读操作前要验证地址是否可读。writevwritev在进行写操作前要验证地址是否可写。在进行写操作前要验证地址是否可写。第7章 嵌入式Linux设备驱动程序开发 2 2 inodeinode数据结构数据结构文件系统处理的文件所需要的信息在文件系统处理的文件所需要的信息在inodeinode(索引结点)数据结构中。(索引结点)数据结构中。InodeInode数数据结构提供了关于特殊设备文件据结构提供了关于特殊设备文件/dev/DriverName/dev/DriverName的信息,定义如下:的信息,定义如下: struct inodestruct ino
24、de称做索引节点数据结构,称做索引节点数据结构,inodeinode(索引结点)数据结构定义如下:(索引结点)数据结构定义如下:struct inode struct inode struct list_headstruct list_headi_hash; /i_hash; /指向哈希链表的指针指向哈希链表的指针struct list_headstruct list_headi_list; /i_list; /指向索引结点链表的指针指向索引结点链表的指针struct list_headstruct list_headi_dentry; /i_dentry; /指向目录项链表的指针指向目录项链
25、表的指针struct list_headstruct list_headi_dirty_buffers; /i_dirty_buffers; /指向指向“脏脏”缓冲区链表的指针缓冲区链表的指针struct list_headstruct list_headi_dirty_data_buffers; i_dirty_data_buffers; unsigned longunsigned longi_ino; /i_ino; /描述索引结点描述索引结点atomic_tatomic_ti_count; /i_count; /当前使用该结点的进程数当前使用该结点的进程数第7章 嵌入式Linux设备驱动
26、程序开发 kdev_tkdev_ti_dev; /i_dev; /设备类型设备类型umode_tumode_ti_mode; /i_mode; /文件类型文件类型nlink_tnlink_ti_nlink; /i_nlink; /与该结点建立链接的文件数与该结点建立链接的文件数uid_tuid_ti_uid; /i_uid; /文件拥有者的标识号文件拥有者的标识号gid_tgid_ti_gid; /i_gid; /文件拥有者的所在组的标识号文件拥有者的所在组的标识号kdev_tkdev_ti_rdev; /i_rdev; /实际设备标识号实际设备标识号loff_tloff_ti_size; /
27、i_size; /文件大小文件大小time_ttime_ti_atime; /i_atime; /文件最后访问的时间文件最后访问的时间time_ttime_ti_mtime; /i_mtime; /文件最后修改的时间文件最后修改的时间time_ttime_ti_ctime; /i_ctime; /结点最后修改的时间结点最后修改的时间unsigned intunsigned inti_blkbits; /i_blkbits; /位数位数unsigned longunsigned long i_blksize; /i_blksize; /块大小块大小unsigned longunsigned lo
28、ng i_blocks; /i_blocks; /文件所占用的块数文件所占用的块数unsigned longunsigned long i_version; /i_version; /版本号版本号struct semaphorestruct semaphorei_sem; /i_sem; /用于同步操作的信号量结构用于同步操作的信号量结构第7章 嵌入式Linux设备驱动程序开发 struct semaphorestruct semaphorei_zombie; /i_zombie; /索引结点的信号量索引结点的信号量struct inode_operationsstruct inode_ope
29、rations* *i_op; /i_op; /索引结点操作索引结点操作struct file_operationsstruct file_operations* *i_fop; /i_fop; /指向文件操作的指针指向文件操作的指针struct super_blockstruct super_block* *i_sb; /i_sb; /指向读文件系统超级块指针指向读文件系统超级块指针wait_queue_head_twait_queue_head_ti_wait;i_wait; /指向索引结点等待队列的指针指向索引结点等待队列的指针struct file_lockstruct file_lo
30、ck* *i_flock; /i_flock; /指向文件加锁链表的指针指向文件加锁链表的指针struct address_spacestruct address_space * *i_mapping; /i_mapping; /把所有可交换的页面管理起来把所有可交换的页面管理起来struct address_spacestruct address_space i_data; /i_data; /数据数据struct dquotstruct dquot* *i_dquotMAXQUOTAS; /i_dquotMAXQUOTAS; /索引结点的磁盘限额索引结点的磁盘限额struct list_h
31、eadstruct list_headi_devices; /i_devices; /设备文件形成的链表设备文件形成的链表struct pipe_inode_infostruct pipe_inode_info* *i_pipe; /i_pipe; /指向管道文件指向管道文件struct block_devicestruct block_device* *i_bdev; /i_bdev; /指向块设备文件的指针指向块设备文件的指针struct char_devicestruct char_device * *i_cdev; /i_cdev; /指向字符设备文件的指针指向字符设备文件的指针uns
32、igned longunsigned longi_dnotify_mask; i_dnotify_mask; 第7章 嵌入式Linux设备驱动程序开发 struct dnotify_structstruct dnotify_struct* *i_dnotify; i_dnotify; unsigned longunsigned longi_state; /i_state; /索引结点状态标志索引结点状态标志unsigned intunsigned inti_flags; /i_flags; /文件系统的安装标志文件系统的安装标志unsigned charunsigned chari_sock;
33、 /i_sock; /是否是套接字文件是否是套接字文件atomic_tatomic_ti_writecount; /i_writecount; /写进程的引用计数写进程的引用计数unsigned intunsigned inti_attr_flags; /i_attr_flags; /文件创建标志文件创建标志u32u32i_generation; /i_generation; /保留保留union union struct minix_inode_info struct minix_inode_infominix_i;minix_i; struct jffs2_inode_info struc
34、t jffs2_inode_infojffs2_i;jffs2_i; void void* *generic_ip;generic_ip; u; u; ; 第7章 嵌入式Linux设备驱动程序开发 3file数据结构数据结构 struct file struct file struct list_headstruct list_headf_list; /f_list; /打开的文件形成一个列表打开的文件形成一个列表 struct dentrystruct dentry* *f_dentry; /f_dentry; /指向相关目录项的指针指向相关目录项的指针struct vfsmount str
35、uct vfsmount * *f_vfsmnt; /f_vfsmnt; /执行执行VFSVFS挂载点的指针挂载点的指针struct file_operationsstruct file_operations* *f_op; /f_op; /执行文件操作的指针执行文件操作的指针atomic_tatomic_tf_count; /f_count; /使用该结构的进程数使用该结构的进程数unsigned int unsigned int f_flags;/f_flags;/文件打开的标志,如读写等文件打开的标志,如读写等mode_tmode_tf_mode; /f_mode; /文件打开的模式文件
36、打开的模式第7章 嵌入式Linux设备驱动程序开发 loff_tloff_tf_pos; /f_pos; /文件的当前位置文件的当前位置unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; / /* *预读标志、要预读的最多页面数、上次预读后的文件指针、预预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及预读的页面数读的字节数以及预读的页面数* */ /struct fown_structstru
37、ct fown_structf_owner; /f_owner; /文件的所有者文件的所有者unsigned intunsigned intf_uid, f_gid; /f_uid, f_gid; /用户的用户的UIDUID和和GIDGIDintint f_error; /f_error; /网络写操作错误码网络写操作错误码unsigned longunsigned longf_version; /f_version; /版本号版本号voidvoid * *private_data; /ttyprivate_data; /tty驱动程序使用驱动程序使用struct kiobufstruct k
38、iobuf* *f_iobuf;f_iobuf;longlong f_iobuf_lock; f_iobuf_lock;第7章 嵌入式Linux设备驱动程序开发 FileFile结构中与驱动相关的成员如下:结构中与驱动相关的成员如下:f_modef_mode标识文件的读写权限标识文件的读写权限f_posf_pos当前读写位置,类型为当前读写位置,类型为loff_t loff_t 是是64 64 位的数,只能读不位的数,只能读不能写能写; ;f_flagf_flag文件标志,主要用于进行阻塞文件标志,主要用于进行阻塞/ /非阻塞型操作时检查非阻塞型操作时检查f_opf_op文件操作的结构指针,内
39、核在文件操作的结构指针,内核在OPEN OPEN 时对此指针赋值。时对此指针赋值。private_data Openprivate_data Open系统调用在调用驱动程序的系统调用在调用驱动程序的open open 方法前,方法前,将此指针值将此指针值NULLNULL,驱动程序可以将这个字段用于任何目的,一般,驱动程序可以将这个字段用于任何目的,一般用它指向已经分配的数据,但在内核销毁用它指向已经分配的数据,但在内核销毁file file 结构前要在结构前要在release release 方法中释放内存。方法中释放内存。f_dentryf_dentry文件对应的目录项结构,一般在驱动中用文
40、件对应的目录项结构,一般在驱动中用filp-filp-f_dentry-d_inode f_dentry-d_inode 访问索引节点时用到它。访问索引节点时用到它。第7章 嵌入式Linux设备驱动程序开发 7.1.5 设备驱动开发中基本函数设备驱动开发中基本函数 1I/O口函数口函数 1)int check_region(unsigned int from, unsigned int extent); 2)void request_region(unsigned int from, unsigned int extent,const char *name);3 3)void release_
41、region(unsigned int from, unsigned int extent);void release_region(unsigned int from, unsigned int extent);在申请了在申请了I/OI/O端口之后,可以借助端口之后,可以借助asm/io.hasm/io.h中的如下几个函数来访问中的如下几个函数来访问I/OI/O端口:端口:inline unsigned int inb(unsigned short port); /inline unsigned int inb(unsigned short port); /读取某个端口的值读取某个端口的值i
42、nline unsigned int inb_p(unsigned short port);inline unsigned int inb_p(unsigned short port);inline void outb(char value, unsigned short port);/inline void outb(char value, unsigned short port);/向某个端口赋值向某个端口赋值inline void outb_p(char value, unsigned short port);inline void outb_p(char value, unsigned
43、 short port);其中其中inb_pinb_p和和outb_poutb_p插入了一定的延时以适应某些慢速的插入了一定的延时以适应某些慢速的I/OI/O端口。端口。 可以查询可以查询/proc/ioports文件获得当前已经分配的文件获得当前已经分配的I/O地址。地址。 第7章 嵌入式Linux设备驱动程序开发 2时钟函数时钟函数 与时钟有关的系统调用有:与时钟有关的系统调用有:#include #include #include #include struct timer_list struct timer_list struct timer_list struct timer_lis
44、t * *next;next;struct timer_list struct timer_list * *prev;prev;unsigned long expires;unsigned long expires;unsigned long data;unsigned long data;void (void (* *function)(unsigned long);function)(unsigned long);void add_timer(struct timer_list void add_timer(struct timer_list * * timer); timer);int
45、del_timer(struct timer_list int del_timer(struct timer_list * * timer); timer);inline void init_timer(struct timer_list inline void init_timer(struct timer_list * * timer); timer);第7章 嵌入式Linux设备驱动程序开发 3 3内存操作函数内存操作函数#include /linux/kernel.h#include /linux/kernel.h里声明了里声明了kmalloc()kmalloc()和和kfree()k
46、free(),用于在,用于在内核模式下申请和释放内存。内核模式下申请和释放内存。void void * * kmalloc(unsigned int len, int priority); kmalloc(unsigned int len, int priority);void kfree(void void kfree(void * * obj); obj);其中其中lenlen为申请的字节数,为申请的字节数,objobj为要释放的内存指针。为要释放的内存指针。prioritypriority为分为分配内存操作的优先级。配内存操作的优先级。与用户模式下的与用户模式下的malloc()mall
47、oc()不同,不同,kmalloc()kmalloc()申请空间有大小限制。申请空间有大小限制。长度是长度是2 2的整次方。可以申请的最大长度也有限制。另外的整次方。可以申请的最大长度也有限制。另外prioritypriority参数,通常使用时可以为参数,通常使用时可以为GFP_KERNELGFP_KERNEL,如果在中断里调用,则用,如果在中断里调用,则用GFP_ATOMICGFP_ATOMIC参数,因为使用参数,因为使用GFP_KERNELGFP_KERNEL则调用者可能进入则调用者可能进入sleepsleep状状态,在处理中断时是不允许的。态,在处理中断时是不允许的。kfree()kf
48、ree()释放的内存必须是释放的内存必须是kmalloc()kmalloc()申请的。如果知道内存的大小,也可以用申请的。如果知道内存的大小,也可以用kfree_s()kfree_s()释放。释放。第7章 嵌入式Linux设备驱动程序开发 4 4复制函数复制函数在用户程序调用在用户程序调用readread、writewrite时,因为进程的运行状态由用户态变为核心态,地时,因为进程的运行状态由用户态变为核心态,地址空间也变为核心地址空间。由于址空间也变为核心地址空间。由于readread、writewrite中参数中参数bufbuf是指向用户程序的私有是指向用户程序的私有地址空间的,所以不能直
49、接访问,必须通过下面两个系统函数来访问用户程序的地址空间的,所以不能直接访问,必须通过下面两个系统函数来访问用户程序的私有地址空间。私有地址空间。# include # include void memcpy_fromfs(void void memcpy_fromfs(void * * to,const void to,const void * * from,unsigned long n); from,unsigned long n);void memcpy_tofs(void void memcpy_tofs(void * * to,const void to,const void *
50、* from,unsigned long n); from,unsigned long n);memcpy_fromfsmemcpy_fromfs由用户程序地址空间往核心地址空间复制,由用户程序地址空间往核心地址空间复制,memcpy_tofsmemcpy_tofs则反之。则反之。参数参数toto为复制的目的指针,为复制的目的指针,fromfrom为源指针,为源指针,n n为要复制的字节数。为要复制的字节数。在设备驱动程序里,可以调用在设备驱动程序里,可以调用printkprintk来打印一些调试信息,来打印一些调试信息,printkprintk的用法与的用法与printfprintf类似。类
51、似。printkprintk打印的信息不仅出现在屏幕上,同时还记录在文件打印的信息不仅出现在屏幕上,同时还记录在文件syslogsyslog里。里。第7章 嵌入式Linux设备驱动程序开发 7.2 设备驱动模块化编程设备驱动模块化编程 7.2.1 设备驱动程序的开发流程设备驱动程序的开发流程 (1 1)硬件接口设计或使用嵌入式处理器的生产商提供参考接口电)硬件接口设计或使用嵌入式处理器的生产商提供参考接口电路。路。(2 2)定义设备号。)定义设备号。(3 3)实现初始化函数。在驱动程序中实现驱动的注册和卸载。)实现初始化函数。在驱动程序中实现驱动的注册和卸载。(4 4)设计所要实现的文件操作,
52、定义)设计所要实现的文件操作,定义file_operationsfile_operations结构。结构。(5 5)实现所需的文件操作调用,如)实现所需的文件操作调用,如readread、writewrite等。等。(6 6)实现中断服务,并用)实现中断服务,并用request_irqrequest_irq向内核注册。向内核注册。(7 7)编译该驱动程序到内核中,或者用)编译该驱动程序到内核中,或者用insmodinsmod命令加载模块。命令加载模块。(8)测试该设备,编写应用程序,对驱动程序进行测试。)测试该设备,编写应用程序,对驱动程序进行测试。 第7章 嵌入式Linux设备驱动程序开发
53、7.2.2 内核空间和用户空间内核空间和用户空间 系统态系统态: :在在Linux系统中,内核在最高级执行,也称为系统中,内核在最高级执行,也称为“系统态系统态”,在这一级任何操作都可以执行。,在这一级任何操作都可以执行。 用户态:用户态:而应用程序则用户态执行在最低级,所谓的而应用程序则用户态执行在最低级,所谓的“用户态用户态”,在这一级处理器禁止对硬件的直接访问和对,在这一级处理器禁止对硬件的直接访问和对内存的未授权访问。内存的未授权访问。 内核空间:内核空间:模块运行的空间是在所谓的模块运行的空间是在所谓的“内核空间内核空间”; 用户空间:用户空间:应用程序运行的空间是在应用程序运行的空
54、间是在“用户空间用户空间” ” 。 它们分别引用不同的内存映射,也就是程序代码使用它们分别引用不同的内存映射,也就是程序代码使用不同的不同的“地址空间地址空间”。第7章 嵌入式Linux设备驱动程序开发 7.2.3 7.2.3 设备注册和初始化设备注册和初始化 int register_chrdev(unsigned int major, const char *name, struct file_ operations *fops); 注册成功,设备名就会出现在注册成功,设备名就会出现在/proc/dvices文件中。文件中。LinuxLinux在在/dev/dev目录中为每个设备建立一个文
55、件,用目录中为每个设备建立一个文件,用ls lls l命令列出函数返回值,命令列出函数返回值,若小于若小于0 0,则表示注册失败;返回,则表示注册失败;返回0 0或者大于或者大于0 0的值表示注册成功。的值表示注册成功。 int unregister_chrdev(unsigned int major, const char int unregister_chrdev(unsigned int major, const char * *name);name); 此函数的参数为主设备号此函数的参数为主设备号majormajor和设备名和设备名namename。LinuxLinux内核把内核把na
56、mename和和majormajor在内核注册的名称对比,如果不相等,卸载失败,并返回在内核注册的名称对比,如果不相等,卸载失败,并返回EINVALEINVAL;如果;如果majormajor大于最大的设备号,也返回大于最大的设备号,也返回EINVALEINVAL。 第7章 嵌入式Linux设备驱动程序开发 设备驱动的初始化函数主要完成的功能是有以下设备驱动的初始化函数主要完成的功能是有以下5 5项:项:(1 1)对驱动程序管理的硬件进行必要的初始化。如:)对驱动程序管理的硬件进行必要的初始化。如:S3C2410XS3C2410X的的硬件寄存器设置。硬件寄存器设置。(2 2)初始化设备驱动相关
57、的参数。如:设备变量及设备相关的参)初始化设备驱动相关的参数。如:设备变量及设备相关的参数。数。(3 3)在内核注册设备。调用)在内核注册设备。调用register_chrdev()register_chrdev()函数来注册设备。函数来注册设备。(4 4)注册中断。如果设备需要)注册中断。如果设备需要IRQIRQ支持,则要使用支持,则要使用request_irq()request_irq()函数注册中断。函数注册中断。(5 5)其他初始化工作。主要包括给设备驱动程序申请包括内存、)其他初始化工作。主要包括给设备驱动程序申请包括内存、时钟、时钟、I/OI/O端口等在内的系统资源,这些资源也可以
58、在端口等在内的系统资源,这些资源也可以在openopen子程序子程序或者其他地方申请。这些资源不用时,应该释放,以利于资源的共或者其他地方申请。这些资源不用时,应该释放,以利于资源的共享。享。第7章 嵌入式Linux设备驱动程序开发 内核中驱动程序的初始化函数如下方式声明:内核中驱动程序的初始化函数如下方式声明:int _init chr_driver_init(void);int _init chr_driver_init(void);其中其中_init_init是必不可少的,在系统启动时会由内核调用是必不可少的,在系统启动时会由内核调用chr_driver_initchr_driver_i
59、nit,完成驱动程序的初始化。,完成驱动程序的初始化。以模块的形式编写驱动程序时,则要按照如下方式声明:以模块的形式编写驱动程序时,则要按照如下方式声明:int init_module(void)int init_module(void)当运行后面介绍的当运行后面介绍的insmodinsmod命令插入模块时,会调用命令插入模块时,会调用init_moduleinit_module函数完成初始化工作。函数完成初始化工作。 第7章 嵌入式Linux设备驱动程序开发 7.2.4 中断管理中断管理 设备驱动程序通过调用设备驱动程序通过调用request_irq函数来申请中断,通过函数来申请中断,通过f
60、ree_irq来释放中断。来释放中断。它们在它们在linux/sched.h中的定义如下:中的定义如下:int request_irq(unsigned int irq, void (*handler)(int irq,void dev_id,struct pt_regs *regs), unsigned long flags, const char *device, void *dev_id );void free_irq(unsigned int irq, void *dev_id);从从request_irq函数返回的值为函数返回的值为0时,表示申请成功;负值表示出现错误。时,表示申请成
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论