收藏 分销(赏)

第11章Linux设备驱动.ppt

上传人:仙人****88 文档编号:13324218 上传时间:2026-03-01 格式:PPT 页数:123 大小:1.66MB 下载积分:10 金币
下载 相关 举报
第11章Linux设备驱动.ppt_第1页
第1页 / 共123页
第11章Linux设备驱动.ppt_第2页
第2页 / 共123页


点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第,11,章,Linux,设备驱动,设备驱动概述,字符设备驱动编程,LED,驱动程序实例,中断编程,按键驱动程序实例,块设备驱动编程,实验,设备驱动概述,设备驱动程序简介,设备分类,设备号,驱动程序层次结构,应用程序,底层驱动程序,(,初始化、读写等操作、中断,),LEDdrive,硬件,LED,LCD,8LED,LCDdrive,8LEDdrive,嵌入式系统软件结构,(,无操作系统,),前,/,后台结构,单任务结构,大循环结构,例,LED,LED1,LED2,PB9,PB10,VDD33,44B0X,#define,rPCONB,(*(volatile unsigned*)0 x1d20008),#define,rPDATB,(*(volatile unsigned*)0 x1d2000c),将,PB10,、,PB9,功能配置为输出,rPCONB,=rPCONB&B1010,;,B10=0,rPCONB,=rPCONB&B99,;,B9=0,void,leds_on,(),Led_Display(0 x3);,void,leds_off,(),Led_Display(0 x0);,void led1_on(),led_state=led_state|0 x1;,Led_Display(led_state);,void,Led_Display(int,LedStatus,),led_state=,LedStatus,;,if(LedStatus&0 x01)=0 x01),rPDATB,=rPDATB,else,rPDATB,=rPDATB|0 x200;,if(LedStatus&0 x02)=0 x02),rPDATB,=rPDATB,else,rPDATB,=rPDATB|0 x400;,例,LED,rPDATB,=rPDATB&0 x1FF,rPDATB,=rPDATB|0 x600,void led1_off(),led_state,=,led_state,Led_Display(led_state,);,void led2_on(),void led2_off(),void,main(void,),while(1),leds_off,();,Delay(1000);,led1_on();,Delay(1000);,led1_off();,led2_on();,Delay(1000);,leds_on,();,.,应用程序,底层驱动程序,(,初始化、读写等操作、中断,),LEDdrive,硬件,LED,LCD,8LED,LCDdrive,8LEDdrive,底层驱动,(,初始化、读写等操作、中断,),LEDdrive,硬件,LED,LCD,8LED,LCDdrive,8LEDdrive,嵌入式系统软件结构,(,有操作系统,),Key,open(),read(),write(),ioctl,(),close(),设备驱动中独立于设备的接口,struct,file_operations,操作系统,应用程序,操作系统,API,static,struct,file_operations,s3c24xx_leds_fops,=,.owner =THIS_MODULE,.open =s3c24xx_leds_open,.,ioctl,=s3c24xx_leds_ioctl,.,;,static,int,s3c24xx_leds_open,(struct,inode,*,inode,struct,file*,file,),int,i;,/,设置,GPIO,引脚的功能,本驱动中,LED,所涉及的,GPIO,引脚 设为输出功能,for(i=0;i 2;i+),s3c2410_gpio_cfgpin(led_tablei,led_cfg_tablei,);,return 0;,应用程序对设备文件,/dev/,leds,执行,open(.),时,就会调用,s3c24xx_leds_open,函数,rPCONB,=rPCONB&B1010,;,B10=0,rPCONB,=rPCONB&B9 4)return-EINVAL;,switch(cmd,),case IOCTL_LED_ON:/,设置指定引脚的输出电平为,0,s3c2410_gpio_setpin(led_tablearg,0);,return 0;,case IOCTL_LED_OFF:/,设置指定引脚的输出电平为,1,s3c2410_gpio_setpin(led_tablearg,1);,return 0;,default:,return-EINVAL;,应用程序对设备文件,/dev/,leds,执行,ioclt,(.),时,就会调用此函数,leds_on,()or led1_on()or led2_on(),leds_off,()or led1_off()or led2_off(),/*,led_test.c,*/,int,main(int,argc,char*,argv,),fd,=open(“/dev/,leds,”,0);/,打开设备,.,if(!strcmp(argv2,on),ioctl(fd,IOCTL_LED_ON,led_no,);,else if(!strcmp(argv2,off),ioctl(fd,IOCTL_LED_OFF,led_no,);,else,goto,err;,close(fd,);,return 0;,底层驱动,(,初始化、读写等操作、中断,),LEDdrive,硬件,LED,LCD,8LED,LCDdrive,8LEDdrive,Key,open(),read(),write(),ioctl,(),close(),设备驱动中独立于设备的接口,struct,file_operations,应用程序,设备驱动程序简介,设备驱动程序是操作系统中直接控制硬件设备的程序,是内核的一部分,约占,Linux,内核源程序的,60%80%,。,Linux,内核采用可加载的模块化设计(,LKMs,,,Loadable Kernel Modules,)。将最基本的核心代码编译在内核中,其他的代码则往往编译为内核模块,在需要时才动态加载到内核中。,通常,CPU,、,PCI,、,TCP/IP,、,APM,、,VFS,等的驱动直接编译在内核文件中,其它驱动(声卡、网卡等)则作为模块动态加载。,设备驱动程序简介,insmod,和,modprobe,用于加载当前模块。两者略有不同:,insmod,不会自动解决依存关系,即如果要加载的模块引用了当前内核符号表中不存在的符号,则无法加载,也不会去查在其他尚未加载的模块中是否定义了该符号;,modprobe,可以根据模块间依存关系以及,/etc/,modules.conf,文件中的内容自动加载其他有依赖关系的模块。,设备驱动程序简介,lsmod,列出当前系统中加载的模块,其中左边第一列是模块名,第二列是该模块大小,第三列则是使用该模块的对象数目(参见,P332),。,rmmod,用于将当前模块卸载。,Hello,模块,/*,hello.c,*/,#include /,所有模块都需要的头文件,#include /,init&exit,相关宏,MODULE_LICENSE(GPL);,static,int,_init,hello_init,(void),printk(Hello,module initn);,return 0;,static void _exit,hello_exit,(void),printk(Hello,module exitn);,module_init(hello_init,);,module_exit(hello_exit,);,Hello,模块,gcc,D_KERNEL_-DMODULE DLINUX I/usr/local/src/linux2.4/include-c o,hello.o,hello.c,下列命令将可加载,hello,模块:,$,insmod,./,hello.o,Hello module init,$,下列命令完成相反过程:,$,rmmod,hello,Hello module exit,$,设备分类(,1,),Linux,系统的设备分为三类:字符设备、块设备和网络设备。,字符设备通常指像普通文件或字节流一样,以字节为单位顺序读写的设备,如并口设备、虚拟控制台等。字符设备可以通过设备文件节点访问,它与普通文件之间的区别在于普通文件可以被随机访问(可以前后移动访问指针),而大多数字符设备只能提供顺序访问,因为对它们的访问不会被系统所缓存。但也有例外,例如帧缓存,(,framebuffer,),是一个可以被随机访问的字符设备。,设备分类(,2,),块设备,通常指一些需要以块为单位随机读写的设备,如,IDE,硬盘、,SCSI,硬盘、光驱等。块设备也是通过文件节点来访问,它不仅可以提供随机访问,而且可以容纳文件系统(例如硬盘、闪存等)。,Linux,可以使用户态程序像访问字符设备一样每次进行任意字节的操作,只是在内核态内部中的管理方式和内核提供的驱动接口上不同。,$,ls,l/dev,c,rw-rw,-1 root,uucp,4,64 08-30 22:58 ttyS0/*,串口设备,,c,表示字符设备*,/,b,rw-r,-1 root floppy 2,0 08-30 22:58 fd0/*,软盘设备,,b,表示块设备*,/,设备分类(,3,),网络设备,通常是指通过网络能够与其他主机进行数据通信的设备,如网卡等。内核和网络设备驱动程序之间的通信调用一套数据包处理函数,它们完全不同于内核和字符以及块设备驱动程序之间的通信(,read(),write(),等函数)。,Linux,网络设备不是面向流的设备,因此不会将网络设备的名字(例如,eth0,)映射到文件系统中去。,设备号,设备号是设备的标识,由,主设备号,和,次设备号,组成。主设备号表明设备的类型(例如串口设备、,SCSI,硬盘),与一个确定的驱动程序对应;次设备号通常用于标明不同的属性,例如不同的使用方法,不同的位置,不同的操作等,它标志着某个具体的物理设备。,$,ls,l/dev,c,rw-rw,-1 root,uucp,4,64 08-30 22:58 ttyS0,主设备号,次设备号,设备驱动程序与外界的接口,第,11,章,Linux,设备驱动,设备驱动概述,字符设备驱动编程,驱动程序实例,中断编程,按键驱动程序实例,块设备驱动编程,实验,字符设备驱动编程,字符设备驱动编写流程,重要数据结构与函数,1.,字符设备驱动编写流程,(,1,)查看原理图、数据手册,了解设备的操作方法。,(,2,)找相近的驱动程序,以它为模,板,进行开发(有时需要从零开始)。,(,3,)设计内核注册驱动程序。这样应用程序传入文件名时,内核才能找到相应的驱动程序。,(,4,)设计,open,、,close,、,read,、,write,等操作函数。,(,5,)实现中断服务(中断并不是每个设备驱动所必须的)。,(,6,)编译该驱动程序到内核中或者用,insmod,命令加载。,(,7,)测试驱动程序。,2.,重要数据结构与函数,重要数据结构,早期版本的字符设备注册,设备号相关函数,最新版本的字符设备注册,设备操作方法,重要数据结构,file_operaions,结构,(1),struct,file_operations,loff_t,(*,llseek,)(,struct,file*,loff_t,int,);,ssize_t,(*read)(,struct,file*,filp,char*buff,size_t,count,loff_t,*,offp,);,ssize_t,(*write)(,struct,file*,filp,const char*buff,size_t,count,loff_t,*,offp,);,int,(*,readdir,)(,struct,file*,void*,filldir_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,(*flush)(,struct,file*);,int,(*release)(,struct,inode,*,struct,file*);,int,(*,fsync,)(,struct,file*,struct,dentry,*);,int(*fasync)(int,struct file*,int);,int(*check_media_change)(kdev_t dev);,int(*revalidate)(kdev_t dev);,int,(*lock)(,struct,file*,int,struct,file_lock,*);,;,重要数据结构,file_operaions,结构,(2),重要数据结构,-file,结构,(1),struct,file,mode_t,f_mode,;/*,标识文件是否可读或可写,*,/,dev_t,f_rdev,;/*,用于,/dev/,tty,*/,off_t,f_pos,;/*,当前文件位移*,/,unsigned short,f_flags,;/*,文件标志,如,O_RDONLY,、,O_NONBLOCK,和,O_SYNC*/,unsigned short,f_count,;/*,打开的文件数目*,/,unsigned short,f_reada,;,struct,inode,*,f_inode,;/*,指向,inode,的结构指针*,/,struct,file_operations,*,f_op,;/*,文件索引指针*,/,;,srtuct,inode,.,重要数据结构,-file,结构,(2),2.,重要数据结构与函数,重要数据结构,早期版本的字符设备注册,设备号相关函数,最新版本的字符设备注册,设备操作方法,早期版本的字符设备注册(,1,),register_chrdev,(),注册设备,若成功,设备名就会出现在,/proc/devices,文件里。,unregister_chrdev,(),关闭设备,设备名就会从,/proc/devices,里消失。,static,int,_init s3c24xx_leds_init(void),int,ret;,ret=,register_chrdev,(,LED_MAJOR,DEVICE_NAME,&,s3c24xx_leds_fops,);,早期版本的字符设备注册(,2,),static void _exit s3c24xx_leds_exit(void),unregister_chrdev(LED_MAJOR,DEVICE_NAME);,2.,重要数据结构与函数,重要数据结构,早期版本的字符设备注册,设备号相关函数,最新版本的字符设备注册,设备操作方法,设备号相关函数(,1,),在,linux2.6,的版本中,用,dev_t,类型来描述设备号(,dev_t,是,32,位数值类型,其中高,12,位表示主设备号,低,20,位表示次设备号)。,MAJOR,和,MINOR,宏分别获得,dev_t,设备号中的主设备号和次设备号,MKDEV,宏组合主设备号和次设备号以获得,dev_t,类型设备号。,例:,dev_t,dev,;,dev=MKDEV(major,0);,major=,MAJOR(dev,);,设备号相关函数(,2,),分配设备号有静态和动态的两种方法,register_chrdev_region,(),。,静态分配是指在事先知道主设备号的情况下,通过指定,第一个主设备号,(次设备号通常为,0,)而向系统申请分配一定数目的设备号。,alloc_chrdev_region,(),。,动态分配是指事先不知道主设备号的情况下仅设置,第一个次设备号,(通常为,0,)和要分配的设备数目而系统动态分配所需的设备号。,unregister_chrdev_region,(),函数释放已分配的(无论是静态的还是动态的)设备号,保存动态分配的第一个设备号,dev_t,dev=,MKDEV(major,0);,if(major),result=,register_chrdev_region,(dev,1,GPIO_DEVICE_NAME);,else,result=,alloc_chrdev_region,(&dev,0,1,GPIO_DEVICE_NAME);,2.,重要数据结构与函数,重要数据结构,早期版本的字符设备注册,设备号相关函数,最新版本的字符设备注册,设备操作方法,最新版本的字符设备注册(,1,),struct,cdev,struct,kobject,kobj,;/*,内嵌的,kobject,对象*,/,struct,module*owner;,struct,file_operations,*ops;,struct,list_head,list;,dev_t,dev;/*,设备号*,/,unsigned,int,count;,用,struct,cdev,结构变量描述字符设备,在驱动程序中必须将已分配到的设备号以及设备操作接口(,struct,file_operations,结构)赋予该结构变量。,最新版本的字符设备注册(,2,),cdev_alloc,(),:,申请分配,struct,cdev,结构体,cdev_init,(),:,初始化已分配到的结构并与,file_operations,结构关联起来。,cdev_add,(),:,将设备号与,struct,cdev,结构进行关联并向内核正式报告新设备的注册,这样新设备可以被用起来了!。,cdev_del,(),:,从系统中删除一个设备。,最新版本的字符设备注册(,3,),最新版本的字符设备注册(,4,),static void,gpio_setup_cdev(struct,cdev,*,dev,int,minor,struct,file_operations,*fops),int,err,devno,=,MKDEV(major,minor);,cdev_init,(dev,fops);,dev-owner=THIS_MODULE;,dev-ops=fops;,err=,cdev_add,(dev,devno,1);,if(err),printk,(KERN_NOTICE Error%d adding,gpio,%d,err,minor);,2.,重要数据结构与函数,重要数据结构,早期版本的字符设备注册,设备号相关函数,最新版本的字符设备注册,设备操作方法,打开设备,open(),打开设备的函数接口是,open,,根据设备的不同,,open,函数接口完成的功能也有所不同,但通常情况下在,open,函数接口中要完成如下工作。,递增计数器,检查错误。,如果未初始化,则进行初始化。,识别次设备号,如果必要,更新,f_op,指针。,分配并填写被置于,filp,-,private_data,的数据结构。,释放设备,release(),释放设备的函数接口是,release(),。,释放设备与关闭设备不同。当一个进程释放设备时,其他进程还能继续使用该设备,只是该进程暂时停止对该设备的使用;而当一个进程关闭设备时,其他进程必须重新打开此设备才能使用它。,释放设备时要完成的工作如下。,递减计数器,MOD_DEC_USE_COUNT,(最新版本已经不再使用)。,释放打开设备时系统所分配的内存空间(包括,filp,-,private_data,指向的内存空间)。,在最后一次释放设备操作时关闭设备。,读写设备,read()/write(),读写设备的主要任务就是把内核空间的数据复制到用户空间,或者从用户空间复制到内核空间,也就是将内核空间缓冲区里的数据复制到用户空间的缓冲区中或者相反。,内核空间和用户空间的数据交换,内核态和用户态使用不同的内存定义,二者之间不能直接访问对方的内存。不能使用诸如,memcpy,(),之类的函数来完成这样的操作。,只能用,copy_to_user,(),或,copy_from_user,(),来实现用户空间和内核空间的数据交换的。,非读写操作,ioctl,(),大部分设备除了读写操作,还需要硬件配置和控制(例如,设置串口设备的波特率)等很多其他操作。在字符设备驱动中,ioctl,函数接口给用户提供对设备的非读写操作机制。,获取内存(,1,),kmalloc,(),:,在设备驱动程序中申请内存(不用,malloc,(),,其返回线性虚拟地址),返回物理地址,申请的空间大小有限制,长度应为,2,的整次方,不会对所获取的内存空间清零。,get_zeroed_page,(),:获得一个已清零页面。,get_free_page,(),:获得一个或几个连续页面,get_dma_pages,(),:获得用于,DMA,传输的页面,kfree,(),或,free_page,:释放内存函数。,获取内存(,2,),获取内存(,3,),获取内存(,4,),第,11,章,Linux,设备驱动,设备驱动概述,字符设备驱动编程,LED,驱动程序实例,中断编程,按键驱动程序实例,块设备驱动编程,实验,用旧版注册函数,#include,#include,#include,#include,#include,#include,#include,#include,#define DEVICE_NAME “,leds,”/*,加载模式后,执行”,cat/proc/devices”,命令看到的设备名称,*,/#define LED_MAJOR 231 /*,主设备号*,/,#define IOCTL_LED_ON 0,#define IOCTL_LED_OFF 1,/*s3c24xx_leds.c*/,/*,用来指定,LED,所用的,GPIO,引脚*,/,static unsigned long,led_table,=,S3C2410_GPB5,S3C2410_GPB6,S3C2410_GPB7,S3C2410_GPB8,;,/*,用来指定,GPIO,引脚的功能:输出*,/,static unsigned,int,led_cfg_table,=,S3C2410_GPB5_OUTP,S3C2410_GPB6_OUTP,S3C2410_GPB7_OUTP,S3C2410_GPB8_OUTP,;,/*,执行“,insmod,s3c24xx_leds.ko”,命令时就会调用这个函数*,/,static,int,_init s3c24xx_leds_init(void),int,ret;,ret=,register_chrdev,(,LED_MAJOR,DEVICE_NAME,&,s3c24xx_leds_fops,);,if(ret 0),printk(DEVICE_NAME,cant register major numbern);,return ret;,printk(DEVICE_NAME,initializedn);,return 0;,/*,执行”,rmmod,s3c24xx_leds.ko”,命令时就会调用这个函数 *,/,static void _exit s3c24xx_leds_exit(void),unregister_chrdev(LED_MAJOR,DEVICE_NAME);,/*,这两行指定驱动程序的初始化函数和卸载函数*,/,module_init(s3c24xx_leds_init);,module_exit(s3c24xx_leds_exit);,/*,描述驱动程序的一些信息,不是必须的*,/,MODULE_AUTHOR(“”);,MODULE_DESCRIPTION(“S3C2410/S3C2440 LED Driver”);,MODULE_LICENSE(GPL);,/,遵循的协议,static,struct,file_operations,s3c24xx_leds_fops=,.owner =THIS_MODULE,.open =s3c24xx_leds_open,.,ioctl,=s3c24xx_leds_ioctl,;,/*,应用程序对设备文件,/dev/,leds,执行,open(.),时,,*就会调用,s3c24xx_leds_open,函数*,/,static,int,s3c24xx_leds_open(struct,inode,*,inode,struct,file*,file,),int,i;,/,设置,GPIO,引脚的功能,本驱动中,LED,所涉及的,GPIO,引脚 设为输出功能,for(i=0;i 4)return-EINVAL;,switch(cmd,),case IOCTL_LED_ON:/,设置指定引脚的输出电平为,0,s3c2410_gpio_setpin(led_tablearg,0);,return 0;,case IOCTL_LED_OFF:/,设置指定引脚的输出电平为,1,s3c2410_gpio_setpin(led_tablearg,1);,return 0;,default:,return-EINVAL;,#include,#include,#include,#include,#define IOCTL_LED_ON 0,#define IOCTL_LED_OFF 1,void,usage(char,*,exename,),printf(Usage:n,);,printf,(%s n,exename,);,printf,(,led_no,=1,2,3 or 4n);,/*,led_test.c,*/,int,main(int,argc,char*,argv,),unsigned,int,led_no,;,int,fd,;,if(,argc,!=3),goto,err;,fd,=open(“/dev/,leds,”,0);/,打开设备,if(,fd,3),goto,err;,if(!strcmp(argv2,on),ioctl(fd,IOCTL_LED_ON,led_no,);,else if(!strcmp(argv2,off),ioctl(fd,IOCTL_LED_OFF,led_no,);,else,goto,err;,close(fd,);,return 0;,err:,if(,fd,0),close(fd,);,usage(argv0);,return-1;,实验箱,LEDs,驱动,改写上述驱动程序驱动实验箱的,3,个,LED,实验箱,LEDs,驱动,用新版注册函数,#,ifndef,FS2410_GPIO_SET_H,#define FS2410_GPIO_SET_H,#include,#defineGPIO_DEVICE_NAME ,gpio,“,#define,GPIO_DEVICE_FILENAME /dev/,gpio,“,#defineLED_NUM 4,#define GPIO_IOCTL_MAGIC G,#define LED_D09_SWT_IOW(GPIO_IOCTL_MAGIC,0,unsigned,int,),#define LED_D10_SWT_IOW(GPIO_IOCTL_MAGIC,1,unsigned,int,),#define LED_D11_SWT_IOW(GPIO_IOCTL_MAGIC,2,unsigned,int,),#define LED_D12_SWT_IOW(GPIO_IOCTL_MAGIC,3,unsigned,int,),#define BEEP_SWT_IOW(GPIO_IOCTL_MAGIC,4,unsigned,int,),#defineLED_SWT_ON 0,#defineLED_SWT_OFF 1,#defineBEEP_SWT_ON 1,#defineBEEP_SWT_OFF 0,#endif /*FS2410_GPIO_SET_H*/,/*,gpio_drv.h,*/,#include,#include,#include,#include,#include /*,printk,()*/,#include/*,kmalloc,()*/,#include /*everything.*/,#include /*error codes*/,#include /*,size_t,*/,#include,#include,#include,#include,#include,#include,#include,#include,#include,gpio_drv.h,/*,gpio_drv.c,*/,static,int,major=0;,module_param(major,int,0);,void s3c2410_gpio_cfgpin(unsigned,int,pin,unsigned,int,function),unsigned long base=S3C2410_GPIO_BASE(pin);,unsigned long shift=1;,unsigned long mask=0 x03;,unsigned long con;,unsigned long flags;,if(pin S3C2410_GPIO_BANKB),shift=0;,mask =0 x01;,mask=(S3C2410_GPIO_OFFSET(pin)shift);,local_irq_save(flags,);,con=_,raw_readl(base,+0 x00);,con,con|=function;,_,raw_writel(con,base+0 x00);,local_irq_restore(flags,);,配置管脚功能,void s3c2410_gpio_pullup(unsigned,int,pin,unsigned,int,to),unsigned long base=S3C2410_GPIO_BASE(pin);,unsigned long offs=S3C2410_GPIO_OFFSET(pin);,unsigned long flags;,unsigned long up;,if(pin S3C2410_GPIO_BANKB),return;,local_irq_save(flags,);,up=_,raw_readl(base,+0 x08);,up,up|=to offs;,_,raw_writel(up,base+0 x08);,local_irq_restore(flags,);,配置管脚上拉电阻,void s3c2410_gpio_setpin(unsigned,int,pin,unsigned,int,to),unsigned long base=S3C2410_GPIO_BASE(pin);,unsigned long offs=S3C2410_GPIO_OFFSET(pin);,unsigned long flags;,unsigned long,dat,;,local_irq_save(flags,);,dat,=_,raw_readl(base,+0 x04);,dat,dat,|=to offs;,_,raw_writel(dat,base+0 x04);,local_irq_restore(flags,);,向某个管脚进行输出,static,int,gpio_init,(void,),int,result;,dev_t,dev=,MKDEV(major,0);,if(major),result=,register_chrdev_region,(dev,1,GPIO_DEVICE_NAME);,else,result=,alloc_chrdev_region,(&dev,0,1,GPIO_DEVICE_NAME);,major=,MAJOR(dev,);,if(result owner=THIS_MODULE;,dev-ops=fops;,err=,cdev_add,(dev,devno,1);,if(err),printk,(KERN_NOTICE Error%d adding,gpio,%d,err,minor);,static,struct,cdev,gpio_devs,;,static void,gpio_cleanup,(void,),cdev_del(&gpio_devs,);,unregister_chrdev_region(MKDEV(major,0),1);,printk(Gpio,device uninstalledn);,module_init(gpio_init,);,module_exit(gpio_cleanup,);,MODULE_AUTHOR(David,);,MODULE_LICENSE(Dual,BSD/GPL);,static,struct,file_operations,gpio_fops,=,.owner =THIS_MODULE,.open =,gpio_open,.release=,gpio_release,.read =,gpio_read,.write =,gpio_write,.,ioctl,=,gpio_ioctl,;,int,gpio_open,(,struct,inode,*,inode,struct,file*,filp,),s3c2410_gpio_pullup(S3C2410_GPB0,1);/*BEEP*/,s3c2410_gpio_pullup(S3C2410_GPF4,1);/*LED D12*/,s3c2410_gpio_pullup(S3C2410_GPF5,1);/*LED D11*/,s3c2410_gpio_pullup(S3C2410_GPF6,1);/*LED D10*/,s3c2410_gpio_pullup(S3C2410_GPF7,1);/*LED D9*/,s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_OUTP);,s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF4_OUTP);,s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF5_OUTP);,s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF6_OUTP);,s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF7_OUTP);,return 0;,Open,函数,设置管脚功能,ssize_t,gpio_read,(struct,file*,file,char _user*buff,size_t,count,loff_t,*,offp,),return 0;,ssize_t,gpio_write,(struct,file*,file,const char _user*buff,size_t,count,loff_t,*,offp,),return 0;,/*,向,5,个端口中的一个输出,ON/OFF,值*,/,int,switch_gpio(unsigned,int,pi
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 教育专区 > 小学其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服