字符设备驱动之Hello World

         时间差不多该开始学驱动编程了, 本节开始记录学习驱动的过程。Linux设备驱动会以内核模块的形式出现,因此,在进行学习驱动编程之前,首先要有关于模块和内核编程的概念.。开发这样的专门技术对任何类型的模块化的驱动都是重要的基础.。但是,处于学习驱动编写的目的, 一个标准内核是最好的。不管你的内核来源,,建立 2.6.x 的模块需要你有一个配置好并建立好的内核树在你的系统中(如果是交叉测试,应该和你的板子跑的是一样的内核)。因为我们稍后会见到的原因,生活通常是最容易的如果当你建立模块时真正运行目标内核,尽管这不是需要的。

一、Linux内核模块简介

       Linux 内核的整体结构非常庞大,其包含的组件也非常多。我们怎样把需要的部分都包含在内核中呢?

       一种方法是把所有需要的功能都编译到Linux内核。这会导致两个问题,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核。有没有一种机制使得编译出的内核本身并不需要包含所有功能,而在这些功能需要被使用的时候,其对应的代码可被动态加载到内核中呢?Linux提供了这样的一种机制,这种机制被称为模块(Module),可以实现以上效果。模块具有以下特点:

(1)模块本身不被编译入内核映像,从而控制了内核的大小;

(2)模块一旦被加载,它就和内核中的其它部分完全一样。

 

二、 配置编译好一个可执行的内核,并跑到你的板子上

在这里我使用的是Linux2.6.22.6的内核,通过打补丁的方式编译生成uImage。

(1)解压,并打补丁

$tar xjf linux-2.6.22.6.tar.bz2

$cd Linux2.6.22.6

$patch -p1 < ../linux-2.6.22.6_jz2440.patch

(2)配置内核

2.1使用厂家提供的配置文件(在这里我使用的)
    cp config_ok   .config
    make menuconfig(记得把dm9000去掉,选上cs89x0)

2.2使用内核里面默认的配置文件, 在它的基础上配置
    find -name "*defconfig" | grep "2410"
    make s3c2410_defconfig
    make menuconfig

2.3从头开始,自己配置
    make menuconfig

注意:如果make menuconfig出错,说是找不到ncurse.h,要安装ncurse开发包:(apt-get install ncurses-dev)

(3)修改Makefile

 186 ARCH        ?= arm
 187 CROSS_COMPILE   ?= arm-linux-gnu-

(4) 编译内核:make,  make uImage

$make uImage
如果最后说 mkimage not found,从u-boot的tools目录下把mkimage复制到/bin目录去,再执行 make uImage

        到这里就已经配置编译了一个可以使用的内核了,把uImage拷贝到你的/tftpboot目录下让你的板子尝尝。这个编译过的内核我是放在/home/kernel/linux2.6.22.6下,后面写驱动都会用到这个。

三、字符设备驱动Hello World

       首先在主机端操作,在NFS文件系统中,我的在/rootfs/filesystem中创建一个/work/hello目录,在里面创建hello.c驱动程序,test.c测试程序,Makefile文件。然后启动开发板挂载网络文件系统就可以直接测试我们的Hello World啦!

字符设备程序:hello.c

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/io.h>


/* 在开发板执行 cat /proc/devices 查看空项设备号 */
static int major = 100;


int hello_open(struct inode *inode, struct file *file)
{
 printk("hello_open ***\n");
 return 0;
}

ssize_t hello_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
 printk("hello_read ***\n");
 return 0; 
}

ssize_t hello_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
 printk("hello_write ***\n");
 return 0; 
}

static const struct file_operations hello_fops = {
 .owner = THIS_MODULE,
 .write = hello_write,
 .read = hello_read,
 .open = hello_open
};


int hello_init(void)
{

printk(KERN_INFO "hello_init!\n");(KERN_INFO为printk的优先级)
register_chrdev(major, "hello", &hello_fops);(如果major为0,则是让系统自动分配)
 return 0;
}

void hello_exit(void)
{

printk(KERN_INFO "hello_exit!\n");
 unregister_chrdev(major, "hello");
}

/*宏定义, 声明一个模块的初始化和清理函数*/
module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("Dual BSD/GPL");

 

测试程序:test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
     int fd;
     char buf[10];
     int ret;

     fd = open("/dev/hello", O_RDWR);
 if (fd < 0)
 {
     printf("can't open /dev/hello\n");
     return -1;
 }

     ret = read(fd, buf, 10);
     printf("ret = %d\n", ret);
 
     return 0;
}

Makefile文件

obj-m += hello.o

KDIR := /home/kernel/linux-2.6.22.6(刚才编译好的内核,你换成你主机上存放的路径,其中uImage跑在板子上)

build:
      make -C $(KDIR) M=$(CURDIR) modules
clean:
      make -C $(KDIR) M=$(CURDIR) clean

现在开始编译我们的第一个字符设备驱动程序-hello.c

$make

$ls

hello.c   hello.mod.c  hello.o       Makefile     

hello.ko  hello.mod.o  test.c  Module.symvers

再来交叉编译我们的测试程序

$arm-linux-gnu-gcc test.c -o test

$ls

hello.c   hello.mod.c  hello.o       Makefile     test

hello.ko  hello.mod.o  test.c  Module.symvers

打开putty终端,把上面编译好的hello程序包

#cd /work/hello

#ls

hello.c   hello.mod.c  hello.o       Makefile     test

hello.ko  hello.mod.o  test.c  Module.symvers

#insmod hello.ko

#hello_init!

# lsmod
Module                  Size  Used by    Not tainted
hello                   1920  0

#cat /proc/devices
 99 ppdev
100 hello
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
204 s3c2410_serial
253 usb_endpoint
254 rtc
测试我们的hello程序,首先得手动创建设备节点

当我们没创建时

# ./test
can't open /dev/hello

(/dev/hello为设备节点,c 代表字符设备,100 为主设备号,0 次设备号)
# mknod /dev/hello c 100 0
# ls /dev/hello
/dev/hello
# ./test
hello_open ***
hello_read ***
ret = 0
#

卸载设备驱动程序模块
# rmmod hello

#hello_exit!

 

 


 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值