最近实习,公司项目搞的是平板开发,而我分配的任务是将驱动加载到内核中。

  准备工作,必要知识了解:加载有两种方式,一种是动态加载和卸载即模块加载,另一种是直接编译进入内核;Linux内核把驱动程序划分为3种类型:字符设备、块设备和网络设备。字符设备和块设备可以像文件一样被访问。它们的主要区别不在于能否seek,而是 在于系统对于这两种类型设备的管理方式。应用程序对于字符设备的每一个I/O操作,都会直接传递给系统内核对应的驱动程序;而应用程序对于块设备的操作, 要经过系统的缓冲区管理,间接传递给驱动程序处理。块设备的这种管理方式是为存储提供优化的;而字符设备的管理方式是为操作提供优化的。至于网络设备,它 在Linux系统中是一类比较特殊的设备它不像字符设备或块设备那样通过对应的设备文件节点去访问,内核也不再通过read和write等调用去访问网络 设备。Linux的网络系统主要是基于BSD UNIX的套接字机制,在系统和驱动程序之间有专门的数据结构进行数据传输,系统支持对数据发送和数据接收缓存,提供流量控制机制,提供更多的协议支持。

作为小白一个,从最简单的HelloWorld开始。

HelloWorld源程序:

#ifndef MODULE
#define MODULE
#endif

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENCE("GPL");

static int hello_init(void)  
{     
        printk("Hello world\n");
        return 0;
}   
    
static void hello_exit(void)
{   
        printk("Goodbye World\n");
}   
    
module_init(hello_init);
module_exit(hello_exit);

此程序非常简单,但需注意的是对于一个驱动程序,有一个入口函数hello_init(),相当于main函数,此处两个头文件问题比较大,后面在说!

建立好源程序之后,需要一个makefile文件,来执行此程序:

obj-m := HelloWorld.o
KDIR  := /lib/modules/$(shell uname -r)/build
PWD   := $(shell pwd)
default:
    【tab】make -C $(KDIR) M=$(PWD) modules
在Helloworld源文件和Makefile文件所在目录下直接make,这是以上一般网上教程的做法,但我这却无法编译通过,报的错误是:无法找到该文件或目录,经过一番努力,发现问题在内核源码树上。

为什么要装内核源码树呢?原因是源码树中有相应的头文件和函数的实现,没有源码树,自己写的应用程序就没办法执行起来。驱动程序中自己写的要包含哪些头文件,都是在源码树下的文件夹里,这个都包含在内核里了。

驱动程序作为一个模块连接到内核模块并运行在内核空间里。引用LDD上的一句话“因为2.6内核的模块要和内核源代码树中的目标文件连接,通过这种方式, 可得到一个更加健壮的模块加载器,但是需要这些目标文件存在于内核目录树中”。这里提到的内核目录树就是我们在运行我们自己构造的模块前,需要在我们的系统中已经配置好内核源代码树,然后在把构造好的目标模块和内核树连接起来再运行。

查看自己的系统里有没有配置好内核树的方法:在/lib/modules/2.6.35-30-generic目录下面,看看有没有build文件夹,如果有的话,说明我们的系统里已经有内核树了,如果没有的话,就需要自己构建一个内核树了。

  构造内核树的步骤如下:

1、安装编译内核所需的软件(要用 make menuconfig命令的话得安装,用make oldconfig的话就不用安装)。

sudo apt-get install build-essential kernel-package libncurses5-dev fakeroot

2、下载内核源码

apt-cache search linux-source

执行用这条命令系统会提示你安装适合你内核版本的内核源码

 apt-get install Linux-source-2.6.35

执行这条命令就会自动下载并安装适合我系统内核的Linux-source-2.6.35这个内核源码

3、解压内核源码包
进入/usr/src/,能找到linux-source-2.6.35.tar.bz2,用解压命令解压之。

tar jxvf linux-source-2.6.32.tar.bz2

4、拷贝/boot目录下的config-2.6.35-30-generic到刚才解压好的目录下并改名为.config

 sudo cp /boot/config-2.6.35-30-generic /usr/src/linux-source-2.6.35/.config

5、切换到root用户,进行内核配置

sudo -i
      cd /usr/src/linux-source-2.6.35
      make menuconfig

接着会出现一个配置界面,选择最后面的两个选项:
load an Alternate configuration File 和 save an Alternate configuration File
分别保存并退出,再退出配置环境。
6、编译内核
这个内核的编译要在管理员账号下运行

#cd /usr/src/linux-source-2.6.35
      #make

如果电脑是双核的话可以在make后面加个参数,例如:

make -j4

make的过程时间比较长,我在虚拟机里编译用了2小时左右。。。

再执行

#make bzImage

结束后,可以看到在当前目录下产生一个vmlinux文件。

7、编译模块
在编译模块时候可能会出现如下问题:
(ld: /ubuntu/omnibook/sections.lds: No such file: No such file or directory)

解决方法是:
在/usr/src/linux-source-2.6.35/ubuntu/omnibook/Makefile中的ifeq($(KERNELRELEASE),)的前面增加一句:

 PWD=$(shell pwd)

然后再开始编译模块

#make modules

再执行

make modules_install

命令后在/lib/modules目录下面产生一个目录

后再测试HelloWorld模块:

1、加载模块到内核中:

#insmod ./HelloWorld.ko

2、lsmod 这个命令可以查看当前所有的驱动模块,结果应该显示hello 692 0

#lsmod|grep HelloWorld

3、把hello这个模块移除掉

#rmmod HelloWorld

4、由于printk不会把结果输出到终端中,所以用如下命令查看结果:

dmesg |grep world

编译通过,会产生HelloWorld.ko文件

但出现的另一个问题是可以加载,但无法卸载,待解决,返回的错误是ERROR: Removing 'HelloWorld': Device or resource busy。

网上资料说,这种加载驱动的做法是临时的,当电脑重启时,驱动会自动卸载,试了一次,果然如此。

linux驱动开发之HelloWorld的更多相关文章

  1. 嵌入式linux驱动开发之给linux系统添加温度传感器模块

    忙了几天,终于可以让ds18b20在自己的开发板的linux系统上跑了!虽然ds18b20不是什么新鲜玩意,但是想想知己可以给linux系统添加模块了还是有点小鸡冻呢! 虽然说现在硬件的资源非常丰富而 ...

  2. 嵌入式Linux驱动开发之helloword心得

    自从选择了物联网这个专业,智能XX的字样牵动着每一个学习这个专业的孩子. 大家兴致勃勃的来到了学校,结果一切想象和自己的设想并不一样.想象中的各种智能般梦幻的场景变成了真实的高数/电路/模电等等诸如此 ...

  3. linux驱动开发之GCC问题

    最近正在学习驱动开发,进展到字符设备驱动开发阶段. 先不多说,首先把刚看的一篇学习驱动步骤的帖子记录如下: 1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. ...

  4. Linux驱动开发之LED驱动

    首先讲下字符设备控制技术 : 大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力.比如: 改变波特率. 在用户空间,使用ioctl系统调用来控制设备,原型如下:int ioctl(i ...

  5. (56)Linux驱动开发之二

                                                                                             内核基础   1.li ...

  6. Linux内核驱动开发之KGDB原理介绍及kgdboe方式配置

    接博文<Linux内核驱动开发之KGDB单步调试内核(kgdboc方式)>.上篇博文中,仅简单介绍使用串口的Kgbd的流程(kgdboc方式),本文将重点介绍KGDB调试Linux内核的原 ...

  7. Android驱动开发之Hello实例

    Android驱动开发之Hello实例:   驱动部分 modified:   kernel/arch/arm/configs/msm8909-1gb_w100_hd720p-perf_defconf ...

  8. 基于msm8909高通平台Android驱动开发之hello程序

    本文转载自:http://www.itwendao.com/article/detail/227839.html Android驱动开发之Hello实例:   驱动部分 modified:   ker ...

  9. 【转】Android驱动开发之earlysuspend睡眠模式编程总结

    原文网址:http://blog.csdn.net/bigapple88/article/details/8669537 (1)添加头文件: #include <linux/earlysuspe ...

随机推荐

  1. jQuery HTML CSS 方法

    jQuery HTML / CSS 方法 下面的表格列出了所有用于处理 HTML 和 CSS 的 jQuery 方法. 下面的方法适用于 HTML 和 XML 文档.除了:html() 方法. 方法 ...

  2. javascript 用函数实现“继承”

    一.知识储备: 1.枚举属性名称的函数: (1)for...in:可以在循环体中遍历对象中所有可枚举的属性(包括自有属性和继承属性) (2)Object.keys():返回数组(可枚举的自有属性) ( ...

  3. Eclipse中文乱码解决汇总(应该比较全):

    Eclipse中文乱码解决汇总(应该比较全,欢迎补充): 方法一: 把GBK改成utf-8. 方法二: Window->preference->general->content ty ...

  4. oracle简单两个操作

    sqlplus sys/密码 as sysdba ALTER USER 账号 IDENTIFIED BY 新密码; select *  from (select rownum 别名 ,表名.* fro ...

  5. js键盘控制div移动,解决停顿问题

    问题版本代码如下: 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 27 28 <html> &l ...

  6. 异步调用backgroudworker

    先看一个小例子:C#客户端打开一个控件,控件中加载了好多数据大约要用5秒中,如果我们直接打开控件,那么这个控件就要5秒中才能弹出来,当然这个时候用户已经把他Kill了.这个时候我们就需要先给用户把控件 ...

  7. 从Image Caption Generation理解深度学习

    0. 前面的话 建丁让我写一篇深度学习相关小文章,目标读者是国内的开发者.刚接到这个任务时我是颇为忐忑的,写文章要讲究厚积薄发,如果“水之积也不厚”,“则其负大舟也无力”.因为我自知水平很有限,又不是 ...

  8. C#Winform开发平台企业版V4.0功能表

    企业版V4.0 - 功能列表及模板窗体 C/S系统开发框架-企业版 V4.0 (Enterprise Edition) 简介: http://www.csframework.com/cs-framew ...

  9. Sharepoint 问题集锦 - 外部列表(external list) - 读取当前用户上下文或用户名作为筛选参数

    在创建外部列表过程中,往往需要添加筛选参数,而较多开发用户,会关心如何在外部列表中,只显示当前用户相关的行.本例子中,我们以任务数据表来做例子,看看如何实现这个需求. 1)数据表tbl_task: t ...

  10. 学习Swift -- 数组(Array) - 持续更新

    集合类型--数组 Array是Swift中的一种集合类型:数组,数组是使用有序列表储存同一类型的多个值,与OC的NSArray的最大不同是,Swift的数组是值类型,OC的数组是引用类型 声明数组的方 ...