ubuntu 10.04编译安装linux内核,ubuntu 10.04驱动程序的编译与加载

这篇博客详细介绍了在Ubuntu 10.04上编译和加载驱动程序的步骤,包括检查内核源码包、安装必要工具、编写驱动程序代码、创建Makefile文件、编译驱动为.ko模块、加载驱动以及创建设备文件。此外,还提到了测试程序的编译和执行,确保驱动程序正常工作。
摘要由CSDN通过智能技术生成

ubuntu 10.04驱动程序的编译与加载

第1步:查看自己OS是否已安装好内核源码包

使用命令查看自己系统的源码包型号

# ls /usr/src

blog_1319b67910102wsh4.html

如果存在类似的目录,说明已安装。

第2步:查看自己OS是否已安装libncurses5-dev工具包

如果没有安装使用命令:

# apt-get install build-essential

libncurses5-dev是库函数工具,编译内核必须使用。

第3步:编辑驱动程序char.c

这是书中P129程序,书中有不足之处,要改动。下面的程序已编译通过。

执行命令: $ vi char.c

程序内容如下:

#include

#include

#include

#include

#include

#include

#include

#include

MODULE_LICENSE("GPL v2");

MODULE_AUTHOR("Bob

Geng");

MODULE_DESCRIPTION("a simple driver");

#define N

128

int major  = 250;

int minor  = 0;

struct cdev mycdev; //字符型结构体

char buf[N] ={"hello world !!"};

int char_open (struct inode * myinode, struct file *fp)

{

printk("char

is opened\n");

return

0;

}

int char_release (struct inode *myinode, struct file

*fp)

{

printk("char

is closeed\n");

return

0;

}

static ssize_t char_read (struct file *filep, char __user

*user_buf, size_t count, loff_t * off)

{//1.

ssize_t

:ssize_t是signed

size_t;size_t:

unsigned int

//2. Off:当前文件的偏移量

ssize_t

ret =0;

long

num =0;

printk("char_read

is called\n");

printk("count

is %d\n",count);

num

= copy_to_user(user_buf,buf,count);

if(num

< 0 )

{

printk("copy_to_user

is failed\n");

return

ret;

}

return

ret;

}

ssize_t char_write (struct file *filep, const char __user *from,

size_t count, loff_t *off)

{

ssize_t

ret =0;

long

num =0;

printk("char_write

is called \n");

printk("count

is %d\n",count);

//  if(count

> N )  return -ENOMEM;

if(count

> N )  count = N ;

num

= copy_from_user(buf,from,count);

if(num

< 0 )

{

printk("copy_to_user

is failed\n");

return

ret;

}

printk("from

user is  %s\n",buf);

return

ret;

}

struct file_operations fops={

.owner

= THIS_MODULE,

.open

= char_open,

.release

= char_release,

.read

= char_read,

.write

= char_write,

};

static int __initchar_init(void)

{

int

ret;

dev_t

devno = MKDEV(major,minor);

ret

= register_chrdev_region(devno,1,"char");//静态申请设备号

if(ret

< 0 )

{

printk("fail

to get devno\n");

return

ret;

}

mycdev.owner

= THIS_MODULE;

cdev_init(&mycdev,&fops);

ret

= cdev_add(&mycdev,devno,1);

if(ret

< 0 )

{

printk("cdev_add

fail to system\n");

return

ret;

}

printk("init_module\n");

return

0;

}

static void __exit char_exit(void)

{

dev_t

devno = MKDEV(major,minor);

cdev_del(&mycdev);

unregister_chrdev_region(devno,

1);

printk("cleanup_module\n");

}

module_init(char_init);

module_exit(char_exit);

测试程序test.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define  N

128

char buf[N] ;

int main()

{

int

fd;

if

(  (fd = open("/dev/mychar",O_RDWR)) <

0)

{

perror("open");

exit(-1);

}

if(read(fd,buf,N

) < 0 )

{

perror("read");

exit(-1);

}

printf("read

from mychar is %s\n",buf);

//

memset(buf,0,sizeof(buf));

//strcpy(buf,"goddbye\0");

printf("please input second buf:\n");

scanf("%s",buf);

if(write(fd,buf,N+1)

< 0)

{

perror("write");

exit(-1);

}

if(read(fd,buf,N

) < 0 )

{

perror("read");

exit(-1);

}

printf("second read from mychar is

%s\n",buf);

getchar();

printf("mychar

is opened\n");

close(fd);

}

第4步:编译驱动程序char.c成char.o

说明:

①2.6版本以前的内核编译采用GCC工具,也就是书中P130的方式。

②2.6版本以后的内核编译都是如下方式。

③驱动程序编译一般采用make

工具进行,所以必须要会写makefile文件。

④经实验证明,驱动程序的Makefile文件名(m必须是大写M)否则会出错。

char.c对应的驱动程序Makefile文件内容如下:(可通用)

华清远见嵌入式培训编写的Makefile内容如下显示:(测试通过,可通用)

ifeq ($(KERNELRELEASE),)

KERNELDIR ?= /lib/modules/$(shell uname

-r)/build

#KERNELDIR ?= /home/linux/workdir/source-pack/linux-3.2-net/

(交叉编译)

M=$(PWD) modules

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

Module* modules*

.PHONY: modules modules_install clean

else

obj-m :=char.o

endif

注解:

①ifneq

...else

...endif:选择结构。ifneq和ifeq分别是一个自定函数(某lib中的),根据名字来推断应该是一个是否equal(相等)的判断,第一个值$("xx")应该是获取名为xx的对象引用,至于第二个参数,应该会有默认值的,或者允许空值(NULL)。

②Ifeq...else...endif

选择结构。

③在当前目录下输入make

后,会执行当前目录下的Makefile,执行分三步执行:

a)Makefile:1:

KERNELRELEASE=

//KERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义。

b)KERNELDIR

?= /lib/modules/$(shell uname -r)/build  (本地开发)

等于

c)/lib/modules/3.2.0-29-generic-pae/build

这个目录存放的是编译内核必须的一些头文件和库

d)#KERNELDIR

?= /home/linux/workdir/source-pack/linux-3.2-net/

(交叉开发)

e)PWD

获取用户的当前目录。

f)在输入make后默认会执行第一个目标,第一目标:modules:

g)进而执行:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

h)$(MAKE)

= make

i)-C

$(KERNELDIR) : 指明跳转到内核源码目录下读取那里的Makefile

j)

本题具体分析:进入子目录(/usr/src/linux-headers-3.5.0-23-generic)

下,去执行子目录下的Makefile

k)M=$(PWD):

表明然后返回到当前目录继续读入、执行当前的Makefile

l)

本题具体分析:/home/linux/linux-driver/01-day/02-char-module_init(具体分析)

m)modules

: 告诉内核我要编译模块

n)Makefile:2:

KERNELRELEASE==3.5.0-23-generic

o)第二次:

执行子目录下的Makefile后,会再次调用当前目录下的Makefile在执行子目录(/usr/src/linux-headers-3.5.0-23-generic)下的Makefile后会对KERNELRELEASE

进行赋值KERNELRELEASE=3.5.0-23-generic

p)ifeq

($(KERNELRELEASE),)条件为假

q)执行else分支

r)obj-m

:= char.o(obj-m

表示的要编译成模块所依赖的*.o文件)(动态编译)

s)obj-y

:静态编译

t)执行后会把char.c编译程char.o文件

u)Makefile:3:

第3次 :

会把char.o

生成char.ko文件

第5步:执行make命令,开始编译

执行命令:# make

(以root用户执行)

本程序的编译结果如下显示:

blog_1319b67910102wsh4.html

说明:

①.ko

是Linux 2.6内核使用的动态编译的后缀名,也就是模块文件,用来在Linux系统启动时加载内核模块。

②.o

是目标文件,相当于windows中的.obj文件。

第6步:驱动程序的加载

使用命令:

# insmod  char.ko  (针对此程序,加载.ko文件,而不是.o文件)

查看是否成功加载命令:# lsmod

第7步:设备文件的创建

使用命令: 针对此程序。

#mknod /dev/mychar c 250 0

在/dev目录下创建设备文件。

1.命令中的数字要和驱动程序定义的major,minor保持一致。

2.Mychar文件名与测试程序

blog_1319b67910102wsh4.html中的名字一致。

第8步:test.c生成可执行程序

如果在x86平台下测试,则使用如下命令:

# gcc test.c -o test

如果在ARM平台下测试,则使用如下命令:

# arm-linux-gcc test.c -o test

或用其它交叉编译工具也行。(编译工具根据自己安装的自定)

第9步:执行测试程序,验证驱动程序

针对此程序,执行如下命令:

# ./test

运行如下:

blog_1319b67910102wsh4.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值