Chinaunix首页 | 论坛 | 博客
  • 博客访问: 587987
  • 博文数量: 165
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1554
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-23 22:57
个人简介

我本仁慈,奈何苍天不许

文章分类

全部博文(165)

文章存档

2018年(1)

2016年(33)

2015年(5)

2014年(34)

2013年(92)

分类: LINUX

2013-12-18 18:37:00

说明:以下实验室的实验条件为:Ubuntu12.04   s5pc100(Cortex-A8)

因为模块和内核之间必须是一一对应关系才行的,即是同一模块和不同版本的内核是不匹配的,假设我的模块代码放在hello目录下.

1、先进入hello目录,编译,make(这里编译是不会通过的,但是还必须的有这一步,因为这里虽然通不过,但是在内核中会产生一些文件)

2、先编译内核。Make  zImage

3、在编译模块,代码如下:

Hello.c代码:

   #include   

#include 

#include 

#include 

#include   //字符设备头文件

MODULE_LICENSE ("GPL");    

#define DEVICE_MAJOR 250

#define DEVICE_MINOR 0

#define DEVICE_NUM 1

#define DEVICE_NAME "hello"

struct cdev *cdev;  //定义字符设备指针

struct file_operations hello_fops = {  //文件操作

 .owner = THIS_MODULE

};

static int __init hello_init (void)

{     

  int ret;

  dev_t dev_id = 0;

  dev_id = MKDEV (DEVICE_MAJOR , DEVICE_MINOR);

  ret = register_chrdev_region (dev_id, DEVICE_NUM, DEVICE_NAME);  

  if (ret<0) {

    printk (" can't get major number %d\n", DEVICE_MAJOR);

    goto err_reg_cdev;

  }        

  cdev = cdev_alloc();  //分配空间给字符设备

  if(NULL == cdev)

  {

    printk (" cdev_alloc fail\n");

    goto err_cdev_alloc;

  }

  cdev_init(cdev,&hello_fops); //字符设备初始化

  cdev->owner = THIS_MODULE;   //THIS_MODULE 相当于c++this ,表示该字符设备为本模块所有

  cdev->ops = &hello_fops;     //字符设备相关的文件操作

  ret = cdev_add(cdev,dev_id,DEVICE_NUM); //添加字符设备到系统中

  if(ret)

  {

      printk("cdev_add fail %d\n",ret);

      goto err_cdev_add;

  }

  printk("char device register ok\n");     

  return 0;

//---goto 出错处理, 顺序申请,逆序释放,避免资源回收不完全(如内存泄露,这种做法很经典,这中倒序的处理错误,使上面调用时,不用写多个函数调用却能执行多个资源释放。类似于switch  case函数中,只是在最后写一个break,同样的道理。

err_cdev_add:

  cdev_del(cdev);

err_cdev_alloc:

  unregister_chrdev_region(dev_id,DEVICE_NUM);

err_reg_cdev:

  return  ret;

}

static void __exit hello_exit (void)    

{

  dev_t dev_id = 0;

  dev_id = MKDEV (DEVICE_MAJOR , DEVICE_MINOR);

  if (cdev)

    cdev_del (cdev);

   unregister_chrdev_region (dev_id, DEVICE_NUM);

   printk("char unregister ok\n");   

}

module_init (hello_init);

module_exit (hello_exit);

}

Makefile代码:

ifeq ($(KERNELRELEASE),)

#KERNELDIR ?= /lib/modules/$(shell uname -r)/build  //这是用于PC机上测试的

KERNELDIR ?= /home/farsight/kernel/linux-2.6.35-farsight //这是用于开发板测试的,注意这个目录是你编译开发板内核的目录

PWD := $(shell pwd)

modules:

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

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules* a.out

else

    obj-m := hello.o

endif

4、然后把刚才编译的内核烧进开发板,文件系统通过NFS挂载

5、把测试代码编译arm-none-linux-gnueabi-gcc  test.c

代码如下:

#include 

#include 

#include 

#include 

#include 

#include 

int main (void) 

{

  int fd;

  fd = open ("/dev/hello",O_RDWR); 

  if (fd < 0) {

      printf("open /dev/hello fail\n");

      return -1;

  }

  close (fd);

  printf("main exit\n");

  return 0;

6、a.outhello.ko拷贝进NFS

7、把模块加载进内核,insmod hello.ko

8、配置设备节点,mknod /dev/hello c 250   0  (在代码里面设置的主设备号是250)

9、最后运行a.out,如下图:

还可以用dmesg命令查看相关信息,如下图:

这些打印信息可以参照源码查看。

阅读(505) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~