博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux驱动----1、最简单的驱动hello.ko
阅读量:3705 次
发布时间:2019-05-21

本文共 2781 字,大约阅读时间需要 9 分钟。

    

    驱动程序应该处理如何使硬件可用、而将怎样使用硬件留给上层应用程序。设备分类:字符设备、块设备、网络设备。
    字符设备驱动程序至少实现open、close、read、write系统调用。字符设备可以通过文件系统节点来访问。这些设备文件和普通文件之间的唯一差别在于普通文件的访问可以前后移动访问位置,而大多字符设备是一个只能顺序访问的数据通道。
    块设备上能容纳文件系统,一个文件系统决定了如何在块设备上组织数据,以及表示目录和文件形成的树。文件系统不是设备驱动程序,它没有实际物理设备同这种信息组织方式相关联。它只是个软件驱动程序,将低层数据结构映射到高层数据结构。
    模块能调用的函数仅仅是由内核导出的那些函数,而不存在任何可连接的库函数。Linux内核代码必须是可重入的,它必须能同时运行在多个上下文。

hello.c源文件

  • module.h包含可装载模块需要的大量符号和函数定义
  • init.h指定初始化和清除函数
  • MODULE_LICENSE宏告诉内核,该模块采用的协议
  • printk可能不会将信息打印在终端上,可用dmesg命令查看(dmsg | tail -5只读最后5行)
  • module_init该宏在模块目标代码中增加一个特殊的段,用于说明内核初始化函数所在的位置。
#include 
#include
MODULE_LICENSE("Dual BSD/GPL");static int hello_init(void){ printk(KERN_ALERT "Hello, world\n"); return 0;}static void hello_exit(void){ printk(KERN_ALERT "Goodbye, world\n");}module_init(hello_init);module_exit(hello_exit);

编译生成hello.ko模块

方法一、Makefile+命令行

Makefile

obj-m := hello.o

命令行

  • make modules 忽略中间参数是编译模块的意思
  • -C $(KDIR)指明跳转到内核源码目录下读取那里的Makefile
  • M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile
make -C /usr/src/linux-headers-4.13.0-16-generic M=`pwd` modules//这里4.13.0-16-generic=uname -r

方法二、完整的Makefile

obj-m := hello.o    KERNELBUILD := /lib/modules/$(shell uname -r)/builddefaule:    make -C $(KERNELBUILD) M=$(shell pwd) modulesclean:    rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers

    make会在Makefile中的第一个不是以.开头的目标作为默认的目标执行。KERNELRELEASE定义在内核Makefile中,所以执行else后面的KERNELDIE, PWD赋值,执行default:-C指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被定义,**kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。**else之前的内容为kbuild语法的语句,指明模块源码中各文件的依赖关系,以及要生成的目标模块名

# Comment/uncomment the following line to disable/enable debugging#DEBUG = y# Add your debugging flag (or not) to CFLAGSifeq ($(DEBUG),y)  DEBFLAGS = -O -g # "-O" is needed to expand inlineselse  DEBFLAGS = -O2endifEXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINCDIR)ifneq ($(KERNELRELEASE),)# call from kernel build systemobj-m   := hello.oelseKERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD       := $(shell pwd)default:    $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINCDIR=$(PWD)/../include modulesendifclean:    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions//make depend = make .depend = make depdepend .depend dep:    $(CC) $(EXTRA_CFLAGS) -M *.c > .dependifeq (.depend,$(wildcard .depend))include .dependendif

安装、卸载模块

  • sudo insmod hello.ko安装之后,调用dmesg可以看到hello,world
  • 也可以通过tail /var/log/kern.log查看
  • sudo rmmod hello 卸载后,调用dmesg可以看到goodbye,world
  • lsmod 通过读取/proc/modules虚拟文件获得已安装模块
  • 以装载的模块可以在/sys/module下找到

内核编译的注意事项

  1. 内核使用非常小的栈,可能只有4096B(一页),自己编写的驱动函数必须和整个内核空间共享这个一栈。因此需要大的结构,使用动态分配kmalloc。
  2. “_ ”双下划綫前缀的函数通常是接口的底层组件。 _ init标记表示,模块装载之后将扔掉初始化函数。 _ _exit标记表示该代码用于模块卸载,如果模块直接编译进内核或不允许卸载,这该函数被丢弃。
  3. 用户空间的驱动程序可以实现为一个服务器进程,其任务是代替内核作为硬件控制的唯一代理,客户应用程序可连接到该服务器并和设备执行实际通信。

转载地址:http://wcujn.baihongyu.com/

你可能感兴趣的文章
C++ 知识要点
查看>>
C/C++课程设计 新生入学管理系统(二)
查看>>
Java 获取本地IP地址
查看>>
Java练习题(一) 自定义多个字符和数字,求出6位随机数的组合
查看>>
Java练习题(二)求出一个文件的目录名以及目录总个数
查看>>
Java类名.方法和变量
查看>>
Java小案例(二) 用数组实现增删查改排序
查看>>
Java小案例(一) 用数组实现登录注册、增加职工并查看信息
查看>>
有趣的一行代码
查看>>
Java函数式编程和面向对象编程
查看>>
Java中List、Map、Set三个接口,存取元素时,各有什么特点?
查看>>
客户端与服务器(C/S架构与B/S架构)、AJax学习
查看>>
jsp中String path = request.getContextPath()的作用
查看>>
登录界面验证码的实现
查看>>
EL表达式
查看>>
Javaweb MVC设计模式、Modle发展史、项目分层和三层架构
查看>>
HTML表格和HTML表单
查看>>
JSP访问数据库,Session对象和九大内置对象
查看>>
Springboot分层图解
查看>>
并查集(Disjiont Set)
查看>>