2017-2018-1 20155201 实验四 外设驱动程序设计

it2022-05-09  40

2017-2018-1 20155201 实验四 外设驱动程序设计

一、学习笔记:

本章内容: Linux设备驱动的基本概念 Linux设备驱动程序的基本功能 linux设备驱动的运作过程 常见设备驱动接口函数 掌握LCD设备驱动程序编写步骤 掌握键盘设备驱动程序编写步骤

设备驱动简介 设备驱动程序是内核的一部分。OS通过各种驱动程序来操作硬件设备,设备驱动程序是内核的一部分,硬件驱动程序是OS最基本的组成部分。Linux将最基本的核心代码编译在内核当中,其他代码编译到内核或者内核的模块文件,需要时再加载。常见的内核模块驱动程序比如声卡和网卡,linux基础驱动包括CPU,PCI总线,TCP/IP协议,APM(高级电源管理)等。加载驱动就是加载内核模块。lsmod列出当前系统中加载的模块设备驱动程序与外界的接口

设备驱动程序必须为内核或者其子系统提供一个标准接口。设备驱动编程 设备驱动程序以模块的方式动态加载到内核中。在驱动开发时没有main()函数,模块在调用insmod命令时被加载,在该函数中完成设备的注册。调用rmmod命令时被卸载。设备完成注册加载后,用户的应用程序可以对该设备进行一定的操作,如open()、read()、write()等。字符设备的注册 在内核中使用struct cdev结构来描述字符设备,我们在驱动设备中将已分配到的设备号以及设备操作接口(struct file_operations结构)赋予struct cdev结构变量。使用cdev_alloc()函数向系统申请分配struct cdev结构,再用cdev_init()函数初始化已分配到的结构与file_operations结构关联。调用cdev_add()函数将设备号与struct cdev结构进行关联并向内核正式报告新设备的注册,新设备可以使用了。设备驱动结构函数 打开设备的函数接口open()释放设备的函数接口realease()读写设备read() write()函数#include <linux/fs.h> ssize_t (*read) (struct file *filp, char *buff, size_t count, loff_t *offp) ssize_t (*write) (struct file *filp, const char *buff, size_tc count, loff_t *offp) //*filep文件指针,buff指向用户缓冲区,count传入数据长度,offp用户在文件中的位置 //返回值:写入的数据长度 实现用户空间与内核空间数据交换的函数copy_to_user()和copy_from_user(),同时检查用户空间指针是否有效,如无效,不进行复制。#include <asm/uaccess.h> 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) //to数据目的缓冲区,from数据源缓冲区,count数据长度 //返回值:写入的数据长度。失败:EFAULT 硬件配置和控制,ioctl()函数接口给用户提供对设备的非读写操作机制。#include <linux/fs.h> int (*ioctl) (sturct inode *inode, sturct file *filp,unsigned int cmd, unsigned long arg) //inode:文件的内核内部结构指针,filp:文件描述符,cmd命令类型,arg命令相关参数 以字节为单位分配内存的函数kmalloc()#include <linux/malloc.h> void *kmalloc(unsigned int len, int flags) //len:希望申请的字节数 //flags:GFP_KERNEL,GFP_BUFFER,GFP_ATOMIC,GFP_USER,GFP_HIGHUSER,__GFP_DMA,__GFP_HIGHMEN //成功:写入的数据长度。 //失败:-EFAULT 以页面为单位分配内存的函数:get_free_page()#include <linux/malloc.h> unsigned long get zeroed_page(int flags) unsigned long __get_free_page(int flags) unsigned long __get_free_page(int flags, unsigned long order) unsigned long __get_dma_page(int flags, unsigned long order) //order:要请求的页面数,以2为底的对数 //成功:返回指向新分配的页面的指针 //失败:-EFAULT 打印信息printk()与printf()类似。#include <linux/kernel> int printk(const char *fmt,……) //fmt:日志级别 //……:同printf,比如%d,%x //成功:0 //失败:-1

二、嵌入式Linux应用程序开发标准教程第十一章test实验

编写Makefile ifeq ($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname -r)/build /*内核代码编译路径*/ PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions .PHONY: modules modules_install clean else obj-m := test_drv.o /* 将生成的模块为 test_drv.ko*/ endif

需要注意的问题是比如clean:后面一行必须tab键开头。 运行截图:

加载模块的脚本: #!/bin/sh # 驱动模块名称 module="test_drv" # 设备名称。在/proc/devices 中出现 device="test_dev" # 设备文件的属性 mode="664" group="david" # 删除已存在的设备节点 rm -f /dev/${device} # 加载驱动模块 /sbin/insmod -f ./$module.ko $* || exit 1 # 查到创建设备的主设备号 major=`cat /proc/devices | awk "\\$2==\"$device\" {print \\$1}"` # 创建设备文件节点 mknod /dev/${device} c $major 0 # 设置设备文件属性 chgrp $group /dev/${device} chmod $mode /dev/${device}

编译test.c并执行

卸载模块

#!/bin/sh module="test_drv" device="test_dev" # 卸载驱动模块 /sbin/rmmod $module $* || exit 1 # 删除设备文件 rm -f /dev/${device} exit 0

三、实验代码调试中遇到的问题及解决方案

问题1:Makefile失败问题1解决方案: 失败可能有以下原因:未按Makefile标准格式书写文件,比如tab键分隔符内核编译路径未找准cd /usr/src ls //可以看到内核路径 -

转载于:https://www.cnblogs.com/zhuohua/p/7918529.html


最新回复(0)