嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动

上传人:E**** 文档编号:89494343 上传时间:2019-05-25 格式:PPT 页数:17 大小:990KB
返回 下载 相关 举报
嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动_第1页
第1页 / 共17页
嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动_第2页
第2页 / 共17页
嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动_第3页
第3页 / 共17页
嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动_第4页
第4页 / 共17页
嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动》由会员分享,可在线阅读,更多相关《嵌入式Linux系统应用及项目实践 教学课件 ppt 作者 丰海 第6章_字符型驱动(17页珍藏版)》请在金锄头文库上搜索。

1、1,第六章 字符型驱动,丰海,2,驱动程序: 将底层硬件的操作写成供应用程序可以调用的函数集合。 设备文件: 为了让应用程序方便地控制硬件设备,驱动程序将硬件映射成一个设备文件,这样应用程序通过读写这个设备文件就可以控制硬件设备了。Linux设备分为二类:字符设备和块设备,本书只讲解字符型设备的驱动编写。 应用程序: 应用程序通过读写设备文件,并调用驱动程序里的函数来控制硬件设备。 硬件接口:所有的开发板都会把GPIO接口引出来。,3,4,驱动程序与应用程序之间的区别,1.应用程序有一个main主函数,从头到尾执行一个任务; 驱动程序却没有main函数。 2.应用程序可以和GLIBC库连接,因

2、此可以包含标准的头文件,比如, 在驱动程序中是不能使用标准C库的,比如输出打印函数只能使用内核的printk函数,包含的头文件只能是内核的头文件,比如。,5,一个字符型驱动的标准框架如下: 1 头文件和宏定义 2 ioctl函数:定义了供应用程序调用的ioctl函数的实体 3 结构体:将所有供应用程序调用的函数名注册在这个结构体中 4 初始化函数模块hello_init:调用register_chrdev()函数为这份 驱动注册主设备号,如; ret = register_chrdev(0, DEVICE_NAME, 6 模块说明:说明那些函数是初始化函数;那些函数是退出函数,6,1. 实例1

3、驱动的功能说明 我们先编写一个最简单的HELLO 驱动,这个驱动的功能就是用insmod加载时显示: Hello! Welcome to study character driver! 用rmmod卸载模块时显示: Goodbye! Character driver is easy!,7,/*第1部分开始*声明包含所需要的头文件*/ #include #include /*第2部分开始* hello_init()初始化函数的具体定义*/ static int _init hello_init(void) printk(KERN_NOTICE “Hello!nWelcome to study c

4、haracter driver!n“); return 0; /*第3部分开始* hello_exit()退出函数的具体定义*/ void _exit hello_exit(void) printk(KERN_NOTICE “Goodbye!nCharacter driver is easy!n“); /*第4部分开始* 驱动的有关声明*/ module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE(“Dual BSD/GPL“);,8,Makefile文件,# 指定内核源代码的路径 KERNELDIR ?= /opt/Em

5、bedSky/linux-2.6.30.4/ # 指定编译好的驱动放在当前路径 PWD := $(shell pwd) all: modules modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.o * core .depend .*.cmd *.ko *.order *.mod.c *.symvers .tmp_versions obj-m := hello_driver.o # 生成hello_driver.ko驱动,9,输入make编译驱动,fhfh:/my_experiment/hello$ make m

6、ake -C /opt/EmbedSky/linux-2.6.30.4/ M=/home/fh/my_experiment/hello modules make1: 正在进入目录 /opt/EmbedSky/linux-2.6.30.4 CC M /home/fh/my_experiment/hello/hello_driver.o Building modules, stage 2. MODPOST 1 modules CC /home/fh/my_experiment/hello/hello_driver.mod.o LD M /home/fh/my_experiment/hello/he

7、llo_driver.ko make1:正在离开目录 /opt/EmbedSky/linux-2.6.30.4,10,下载到开发板并运行,rootEmbedSky sky# insmod hello_driver.ko Hello! Welcome to study character driver! rootEmbedSky sky# rmmod hello_driver.ko Goodbye! Character driver is easy! rootEmbedSky sky#,注意:以上信息是通过串口连接到开发板时,才会出现的信息。如果是使用telnet登录到开发板上的话,控制台式不会

8、有显示信息,要输入dmesg才能看到如下信息。,11,应用程序调用驱动中的ioctl 函数完成特定的功能 驱动程序中ioctl 函数如下: static int hello_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg) 应用程序中是这样调用驱动里的ioctl函数的: ioctl(fd,0,NULL); 应用程序的文件描述符fd对应于驱动的inode 和 file两个指针,fd是打开设备文件的文件描述符。 应用程序中的cmd直接传递给驱动程序中的cmd,可选的参数arg我们没有使

9、用,就用NULL代替。驱动中的ioctl函数一般是一个基于switch语句的,用户程序传递不同的cmd值就执行驱动中switch语句所对应的cmd值的语句。,12,驱动中的ioctl函数一般是一个基于switch语句的,用户程序传递不同的cmd值就执行驱动中switch语句所对应的cmd值的语句。,static int hello_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg) switch(cmd) case 0: printk(“command 0 is run!n“); b

10、reak; case 1: printk(“command 1 is run!n“); break; default: printk(“error n“); break; return 0; ,13,设备号包含主设备号和次设备号两个部分,Linux内核需要一对称作主次设备号的参数,才能唯一标识一个设备。主设备号相同的设备使用相同的驱动程序,次设备号用于区分具体设备的实例。对于查看/dev目录下的设备的主次设备号可以使用 ls /dev/ -l命令查看:,rootEmbedSky sky# ls /dev/ -l crw-rw- 1 root root 10, 62 Jan 1 00:00 GP

11、IO-Control crw-rw- 1 root root 204, 64 Jan 1 00:00 tq2440_serial0 crw-rw- 1 root root 204, 65 Jan 1 00:00 tq2440_serial1 crw-rw- 1 root root 204, 66 Jan 1 00:00 tq2440_serial2 crw-rw- 1 root root 10, 130 Jan 1 00:00 watchdog,我们看到tq2440_serial0、tq2440_serial1、tq2440_serial2这三个设备文件都是串口的设备文件,他们使用的是同样地主

12、设备号204,这表明这三个设备文件使用同一个驱动程序,而次设备分别为64、65、66,以示区分这三个设备。,14,用register_chrdev函数注册一个字符型设备的主设备号 register_chrdev函数原型如下: int register_chrdev(unsigned int major, const char *name, struct file_operations *fops); 其中: 第一个参数major是向系统申请的主设备号,如果major为0,则系统会为此驱动程序动 态地分配一个主设备号,在本书中我们均使用动态分配主设备号,第一个参数都为0; 第二个参数name是设

13、备名, 如果 register_chrdev操作成功,设备名就会出现在 /proc/devices文件里; 第三个参数fops是驱动的结构体,类型为file_operations。 在以下的实例中,主设备号的分配如下: ret = register_chrdev(0, “/dev/hello“, /dev/hello是这个设备文件的名称,只是我为了将方便将设备文件的路径作为设备文件的名称。&hello_fops是这个驱动结构体的入口地址。,15,用unregister_chrdev函数来注销字符型设备所取得的设备号 unregister_chrdev的函数原型为: int unregister

14、_chrdev(unsigned int major, const char *name); major是驱动的主设备号,name是驱动的设备名称,major和name这2个参数必须与前面传递给register_chrdev函数中的值保持一致,否则该调用会失败。 在实例中注销语句如下: unregister_chrdev(demoMajor, “/dev/hello“);,16,write与read函数的编写 内核函数copy_to_user是将数据从驱动中拷贝到应用程序中,而copy_from_user是将数据从应用程序中拷贝到驱动中。 这两个专门的内核函数copy_to_user()和co

15、py_from_user()的原型如下: unsigned long copy_to_user (void *to,const void *from,unsigned long count); unsigned long copy_from_user(void *to,const void *from,unsigned long count);,17,驱动的调试 最简单的方法是使用printk函数,printk函数中可以使用附加不同的日志级别或消息优先级,如在hello_driver.ko的驱动中的例子: printk(KERN_NOTICE “Hello!nWelcome to study character driver!n“); printk(KERN_NOTICE “Goodbye!nCharacter driver is easy!n“); 上述例子中消息级别为KERN_NOTICE,在头文件中定义了8种可用的日志级别字符串: KERN_EMERG “” /* 用于突发消息,常在系统崩溃之前报告此类消息。 KERN_ALERT “ /* 在需要立即操作的情况下使用此消息。 KERN_CRIT “ /* 通常遇到严重的硬软件错误时使用此消息。 KE

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号