linux驱动hello入门

首先内核编程从一个hello开始

  1 /*********************************************************************************
  2 *       Copyright: (C) 2013 Guo Wenxue<guowenxue@gmail.com>
  3 *                   All rights reserved.
  4 *
  5 *        Filename: kernel_hello.c
  6 *     Description: This file is the linux kernel module sample
  7 *
  8 *         Version: 1.0.0(03/16/2013~)
  9 *          Author: Guo Wenxue <guowenxue@gmail.com>
 10 *       ChangeLog: 1, Release initial version on "03/16/2013 10:50:26 AM"
 11 *
 12 ********************************************************************************/
 13 #include <linux/init.h>
 14 #include <linux/module.h>
 15 #include <linux/kernel.h> 
 16 
 17 static __init int hello_init(void)
 18 {       
 19         printk(KERN_ALERT "Hello, LingYun IoT Studio!\n");
 20         return 0;
 21 }
 22 
 23 static __exit void hello_exit(void)
 24 {       
 25         printk(KERN_ALERT "Goodbye, I have found a good job!\n");
 26 }
 27 
 28 module_init(hello_init);
 29 module_exit(hello_exit);
 30 MODULE_AUTHOR("GuoWenxue <guowenxue@gmail.com>");
 31 MODULE_DESCRIPTION("Linux Kernel hello module (C) LingYun IoT Studio");
 32 MODULE_LICENSE("Dual BSD/GPL");

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
这三个内核头文件时内核编译时必须带的。

__init __exit属性:
#define __init __attribute__ ((__section__ (".init.text"))) __cold
#define __exit __attribute__ (( __section__ (".exit.text"))) __cold
模块初始化的时候不同的属性函数会被放入目标文件如.init.text中,这一过程是通过编译内核时为相关目标平台提供了xxx.lds链接脚本来指导ld完成的。 对编译成module的代码和数据来说,当模块加载时,__init属性的函数就被执行;当模块去除时,__exit属性的函数就会被执行。

module_init module_exit:
就是一个宏定义,分别用来注册模块在内核的初始化和退出。详细的定义很复杂,他有很多层的定义module_init(fn)—> __initcall(fn) —> device_initcall(fn) —> __define_initcall(fn, 6)

MODULE_LICENSE宏的说明:
从2.4.10版本内核开始,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时,会收到内核被污染 “kernel tainted” 的警告。从linux/module.h文件中可以看到,被内核接受的有意义的许可证有 “GPL”,“GPL v2”,“GPL and additional rights”,“Dual BSD/GPL”,“Dual MPL/GPL”,“Proprietary”。

打印函数printk:
printk 函数在 Linux 内核中定义并且对模块可用,它与标准 C 库函数 printf 的行为相似。内核需要它自己的打印函数, 因为它靠自己运行, 没有 C 库的帮助. 模块能够调用 printk 是因为在 insmod加载了它之后, 模块被链接到内核并且可存取内核的公用符号. 字串 KERN_ALERT 是消息的优先级。printk支持分级别打印调试,这些级别定义在linux-3.0/include/linux/printk.h文件中:
#define KERN_EMERG “<0>” /* system is unusable */
#define KERN_ALERT “<1>” /* action must be taken immediately */
#define KERN_CRIT “<2>” /* critical conditions */
#define KERN_ERR “<3>” /* error conditions */
#define KERN_WARNING “<4>” /* warning conditions */
#define KERN_NOTICE “<5>” /* normal but significant condition */
#define KERN_INFO “<6>” /* informational */
#define KERN_DEBUG “<7>” /* debug-level messages */
/* Use the default kernel loglevel */
#define KERN_DEFAULT “<d>”
Linux内核中printk()的语句是否打印到串口终端上,与u-boot里的bootargs参数中的 loglelve=7相关,只有低于loglevel级别的信息才会打印到控制终端上,否则不会在控制终端上输出。这时我们只能通过dmesg命令查看。 linux下的dmesg命令的可以查看linux内核所有的打印信息,它们记录在/var/log/messages系统日志文件中。linux内核中的打印信息很多,我们可以使用 dmesg -c命令清除之前的打印信息。

写一个makefile

  1 KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
  2 PWD := $(shell pwd)
  3 obj-m := kernel_hello.o
  4 
  5 modules: 
  6     $(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules 
  7     @make clear
  8 
  9 clear: 
 10     @rm -f *.o *.cmd *.mod.c
 11     @rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f
 12     @rm -f .*ko.cmd .*.o.cmd .*.o.d
 13     @rm -f *.unsigned
 14 
 15 clean:
 16     @rm -f hello.ko

刚好学习驱动时候把makefile学习一下
KERNEL_DIR、PWD是变量,这里表示内核路径和当前目录路径
obj-m是把指定代码编译成模块,与其对应的是obj-y。
modules就是目标 动作-C在指定路径下去编译并在M=指定的路径下生成相应的文件,然后删除相关文件,clear、clean是伪目标,执行伪目标是,敲make {伪目标名}。

这里写make一直错误,一只编译显示遗漏分隔符,然后又找不到原因,的确是一个tab的距离,然后检查了好多遍,真的是弱小又无助

最后解决了就是,发现是一个tab是四个空格组成的,这样即使一个tab键跳四格,实质还是空格,然后在vimrc文件中配置autocmd FileType make set noexpandtab这句话就好了,就是一个宽度为四的空格。

make之后就会产生我们的.ko文件,也就是内核模块文件
关于内核的操作都需要sudo权限
dmesg查看Linux内核的打印信息,dmesg -c将会清除之前Linux内核的打印信息
insmod是用来安装模块的,所以sudo insmod kernel_hello.ko就可以安装我们的hello模块了

xiaobaicai@xiaobaicai:~/fl2440/driver/x86$ sudo insmod kernel_hello.ko
xiaobaicai@xiaobaicai:~/fl2440/driver/x86$ dmesg
[521924.615161] Hello, LingYun IoT Studio!
xiaobaicai@xiaobaicai:~/fl2440/driver/x86$ sudo rmmod kernel_hello    
xiaobaicai@xiaobaicai:~/fl2440/driver/x86$ dmesg
[521924.615161] Hello, LingYun IoT Studio!
[521951.191626] Goodbye, I have found a good job!

安装模块时初始化代码执行打印 Hello, LingYun IoT Studio!
卸载模块时卸载代码执行打印Goodbye, I have found a good job!

然后我们在我们的arm开发板上测试一下这个驱动
另写一个makefile用我们的交叉编译器来编译,而且他依赖我们内核源码路径,内核一定是已经编译过的,因为模块之间相互依赖。

LINUX_SRC = ${shell pwd}/../linux/linux-3.0/
CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linuxINST_PATH=/tftp
PWD := $(shell pwd)
EXTRA_CFLAGS+=-DMODULE
obj-m += kernel_hello.o

modules:
	@make -C $(LINUX_SRC) M=$(PWD) modules
	@make clear

uninstall:
rm -f ${INST_PATH}/*.ko

install: uninstall
	cp -af *.ko ${INST_PATH}

clear:
	@rm -f *.o *.cmd *.mod.c
	@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f
	@rm -f .*ko.cmd .*.o.cmd .*.o.d

clean: clear
	@rm -f *.ko

编译完成后通过windows转发到开发板上。

~ >: tftp -gr kernel_hello.ko 192.168.1.251
kernel_hello.ko      100% |*******************************| 23706   0:00:00 ETA
~ >: ls
:                etc              linuxrc          sys
apps             info             mnt              tmp
bin              init             proc             usr
data             kernel_hello.ko  root             var
dev              lib              sbin
~ >: insmod kernel_hello.ko
Hello, LingYun IoT Studio!
~ >: lsmod
kernel_hello 561 0 - Live 0xbf000000
~ >: rmmod kernel_hello
Goodbye, I have found a good job!

开发板测试没有问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值