如何编译linux第一个模块 hellomod.ko
Linux下的驱动程序也没有听上去的那么难实现,我们可以看一下helloworld这个例子就完全可以了解它的编写的方式!
我们还是先看一个这个例子,helloworld
1. [代码]helloworld.c
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include <linux/module.h>//与module相关的信息#include <linux/kernel.h>#include <linux/init.h> //与init相关的函数static int __init hellokernel_init(void){ printk(KERN_INFO "Hello kernel!\n"); return 0;}static void __exit hellokernel_exit(void){ printk(KERN_INFO "Exit kernel!\n");}module_init(hellokernel_init);module_exit(hellokernel_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("xxxx"); |
2. [代码]Makefile
|
1
2
3
4
5
6
7
8
9
|
obj-m := helloworld.oPWD := $(shell pwd)all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules #TAB not spaceclean: rm -rf *.o *~ core .*.cmd *.mod.c ./tmp_version |
3. [代码]执行与运行结果 跳至 [1] [2] [3] [全屏预览]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
3)执行make编译成功之后会生成相应有ko文件,也就是我们想要的驱动了4)驱动程序的相关操作 a)查看ko模块的信息 modinfo b)插入模块 insmod helloworld.ko c)卸载模块 rmmod helloworld d)还有一个modprobe功能,以后介绍!5)查看驱动的打印信息 使用dmesg可以查看在驱动的相关打印信息! 现在有例子是会有如下的打印内容:---------------------log start----------------------------[27520.195551] Exit kernel![27948.531569] Hello kernel!---------------------log end---------------------------- |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(1)驱动程序Hello.c的源代码:
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/device.h>
MODULE_LICENSE("Dual BSD/GPL");
int Hello_read(struct inode *inode, struct file *filp)
{
printk("enter cdd_open!\n");
return 0;
}
int Hello_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)
{
printk("enter cdd_write!\n");
return 0;
}
static struct file_operations io_dev_fops = {
.owner = THIS_MODULE,
.read = Hello_read,
.write = Hello_write,
};
int __init hello_init(void)
{
register_chrdev(123, "Hello",&io_dev_fops);
printk("Ralink gpio driver initialized\n");
return 0;
}
void __exit hello_exit(void)
{
unregister_chrdev(123, "Hello");
printk("Ralink hello driver exited\n");
}
module_init(hello_init);
module_exit(hello_exit);
驱动是靠近底层,与硬件和内核打交道的。内核通过驱动将请求转化为命令操作硬件设备。因此驱动程序向上要给内核提供接口,向下要能够读写硬件的寄存器,能够控制硬件。驱动首先要告诉内核它的存在,也就是注册。代码中的注册函数在下面这个函数中,同时这个函数就是这个驱动的入口,当我们利用insmod命令挂在驱动的时候,首先会进入到这个函数中:
int __init hello_init(void)
{
register_chrdev(123, "Hello",&io_dev_fops);
printk("Ralink gpio driver initialized\n");
return 0;
}
register_chrdev(123, "Hello",&io_dev_fops);123为主设备号“Hello”是在/proc/devices下面显示的该驱动的名称,io_dev_fops是一个file_operations结构体
static struct file_operations io_dev_fops = {
.owner = THIS_MODULE,
.read = Hello_read,
.write = Hello_write,
};
这个结构体相当于一个连接,通过它可以找到在这个驱动中的其他的函数Hello_read、Hello_write(这两个函数分别对应着应用层程序中的函数write、read,当在应用层调用这两个函数,就会通过一系列的动作找到对应的驱动程序中的Hello_read、Hello_write函数),这函数里面就可以写一些对于硬件的操作,因为我写的是最简单的驱动程序,因此没有对于写硬件的操作。
下面是出口函数,当使用rmmod卸载函数时会进入到下面这个函数中
void __exit hello_exit(void)
{
unregister_chrdev(123, "Hello");
printk("Ralink hello driver exited\n");
}
unregister_chrdev(123, "Hello");是注销驱动程序的注册信息的。
每个设备文件对应有两个设备号:一个是主设备号,标识该设备的种类,也标识了该设备所使用的驱动程序;另一个是次设备号,标识使用同一设备驱动程序的不同硬件设备。设备文件的主设备号必须与设备驱动程序在登录该设备时申请的主设备号一致,否则用户进程将无法访问到设备驱动程序。
一般说来,PCI卡通常都属于字符设备
(2)测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
int value=1;
fd=open("/dev/hello",O_RDWR);
if (fd<0)
{
printf("open led_driver error");
exit(1);
}
write(fd,&value,4);
return 0;
}
(3)测试
1、利用tftp将文件下载到开发板上

后面的IP地址是tftp服务器的地址。
2、查看一下/proc/devices,没有此驱动程序要申请的主设备号123

3、利用insmod命令安装驱动后再次查看,有主设备号123 Hello,说明驱动安装成功,并且输出Ralink gpio driver initialized,说明进入到驱动的初始化函数中。

4、测试驱动
运行test发现出现错误:

查找原因是因为在/dev下没有设备节点/dev/Hello

利用mknod新建设备节点并再次查看/dev,有设备节点hello

再次运行test:

测试程序调用驱动成功,输出enter cdd_write,说明成功进入调用到Hello_write函数!
5、卸载驱动

到此为止,第一个驱动程序编写成功!
如何编译linux第一个模块 hellomod.ko的更多相关文章
- 简单实例讲解linux的module模块编译步骤
注:原博文地址http://blog.sina.com.cn/s/blog_4ba5b45e0102v25h.html ---------------------------------------- ...
- Linux内核-模块编译和安装
我安装Ubuntu的时候是没有安装源码的,在没有安装源码前 /usr/src/ 目录下是只有两个包含内核的头文件的文件夹的: 我的内核版本是: 所以接下来就是先安装内核源码: 执行后,/usr/src ...
- Linux操作系统内核编译之NTFS文件系统模块支持案例
Linux操作系统内核编译之NTFS文件系统模块支持案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.内核编译概述 单内核体系设计.但充分借鉴了微内核设计体系的优点,为内核引 ...
- Linux下编译安装Apache及模块
Apache是时下最流行的Webserver软件之中的一个,支持多平台,可高速搭建web服务,并且稳定可靠.并可通过简单的API扩充.就能够集成PHP/Python等语言解释器. 文章这里解说怎样在l ...
- linux内核裁剪及编译可加载模块
一:linux内核裁剪: 1:编译内核源码: 今天的重点内容是内核驱动的编写,在编写驱动之前首先的了解linux内核源码,linux主要是由五个子系统组成:进程调度,内存管理,文件系统,网络接口以及进 ...
- 编译linux kernel及制作initrd ( by quqi99 )
编译linux kernel及制作initrd ( by quqi99 ) 作者:张华 发表于:2013-01-27 ( http://blog.csdn.net/quqi99 ) 运行一个l ...
- 编译linux内核以及depmod的使用
转载:http://blog.lmtw.com/b/18215/archives/2010/71074.html depmod(depend module) 功能说明:分析可载入模块的相依性. 语 法 ...
- 如何解决编译linux内核(解决声卡问题),遭遇fatal error: linux/limits.h: 没有那个文件或目录
最近帮一位上海的朋友搞一块小板,在ubuntu15.04 vivid上已经加载了对应了.ko驱动包 但关键是系统根本就枚举不到该声卡ALC5640,试了OpenSUSE也是一样的结果,看来是内核漏加载 ...
- linux中pam模块
https://www.cnblogs.com/ilinuxer/p/5087447.html linux中pam模块 一.pam简介 Linux-PAM(linux可插入认证模块)是一套共享库,使本 ...
随机推荐
- ABP官方文档翻译 2.3 缓存
缓存 介绍 ICacheManager 警告:GetCache方法 ICache ITypedCache 配置 实体缓存 实体缓存如何工作 Redis缓存集成 介绍 ABP为缓存提供了一个抽象接口,它 ...
- Java对正则表达式的支持(一)
Java对正则表达式的支持主要体现在String.Pattern.Matcher和Scanner类. 1.Pattern.Matcher 先看一个Pattern和Matcher类使用正则表达式的例子. ...
- 《Thinking in Java》学习笔记(二)
1.Java方法的重载 如果几个方法都有相同的名字,区分它们就需要重载来完成. 构成重载的种类: 1)形参的个数不同 2) 形参的类型不同 3) 形参的顺序不同 注意,返回值.抛出的异常和修饰符的不 ...
- HDU 4825 Xor sum
trie树的异或和问题 本题是一道经典题,使用trie树维护所给出的集合,我们知道等比数列前n项的和比第n+1项小,所以本题可以使用贪心策略,对于每一个询问,我们从高位向低位匹配,寻找最大异或值,向下 ...
- BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]
4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...
- BZOJ 4765: 普通计算姬 [分块 树状数组 DFS序]
传送门 题意: 一棵树,支持单点修改和询问以$[l,r]$为根的子树的权值和的和 只有我这种不会分块的沙茶不会做这道题吗? 说一点总结: 子树和当然上$dfs$序了,询问原序列一段区间所有子树和,对原 ...
- POJ 3182 The Grove [DP(spfa) 射线法]
题意: 给一个地图,给定起点和一块连续图形,走一圈围住这个图形求最小步数 本来是要做课件上一道$CF$题,先做一个简化版 只要保证图形有一个点在走出的多边形内就可以了 $hzc:$动态化静态的思想,假 ...
- WPF项目学习.一
WPF项目搭建 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 使用MVVM的优点是 数据和视图分离,双向绑定,低耦合,可重用行,相对独立 ...
- qt安装--this Qt version uses an unsupported makefile
解决办法: Run regedit. Hop to HKEY_CURRENT_USER\Software\Trolltech\Versions或HKEY_CURRENT_USER\Software\D ...
- WPF项目学习.三
工具代码记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 分页控件的制作,邮件发送,日志代码,excel导入导出等代码的实现过程: 二 ...