Linux模块文件如何编译到内核和独立编译成模块

1. 编译成独立模块

假定我们有以下驱动程序,要编译成可以加载到开发板的独立ko文件

hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
//#include <io/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>

static int major = 237;
static int minor = 0;
static dev_t devno;
struct device *class_dev = NULL;
struct class *cls;


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

 return 0;
}

#define KMAX_LEN 32
char kbuf[KMAX_LEN+1] = "kernel";


//read(fd,buff,40);

static ssize_t hello_read (struct file *filep, char __user *buf, size_t size, loff_t *pos)
{
 int error;

 
 if(size > strlen(kbuf))
 {
  size = strlen(kbuf);
 }

 if(copy_to_user(buf,kbuf, size))
 {
  error = -EFAULT;
  return error;
 }

 return size;
}
//write(fd,buff,40);
static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
 int error;

 if(size > KMAX_LEN)
 {
  size = KMAX_LEN;
 }
 memset(kbuf,0,sizeof(kbuf));
 if(copy_from_user(kbuf, buf, size))
 {
  error = -EFAULT;
  return error;
 }
 printk("%s\n",kbuf);
 return size;
}


static struct file_operations hello_ops = 
{
 .open = hello_open,
 .release = hello_release,
 .read = hello_read,
 .write = hello_write,
};
static int hello_init(void)
{
 int result;
 
 printk("hello_init \n");
 result = register_chrdev( major, "hello", &hello_ops);
 if(result < 0)
 {
  printk("register_chrdev fail \n");
  return result;
 }
 cls = class_create(THIS_MODULE, "hellocls");
 if (IS_ERR(cls)) {
  printk(KERN_ERR "class_create() failed for cls\n");
  result = PTR_ERR(cls);
  goto out_err_1;
 }
 devno = MKDEV(major, minor);
 
 class_dev = device_create(cls, NULL, devno, NULL, "hellodev");
 if (IS_ERR(class_dev)) {
  result = PTR_ERR(class_dev);
  goto out_err_2;
 }
 
 return 0;

out_err_2:
 class_destroy(cls);
out_err_1:
 unregister_chrdev(major,"hello");
 return  result;
}
static void hello_exit(void)
{
 printk("hello_exit \n");
 device_destroy(cls, devno);
 class_destroy(cls);
 unregister_chrdev(major,"hello");
 return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
//proc/devices

注意我们需要编写Makefile如下:

ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
else
KDIR :=/home/peng/linux-3.14
PWD  :=$(shell pwd)
all:
 make -C $(KDIR) M=$(PWD) modules
clean:
 rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order
endif

这里的内核源码的路径:

KDIR :=/home/peng/linux-3.14

编译时,程序可以放到其他目录下:

2. 编译到内核

步骤:

  • 1)拷贝文件 如果要将刚才的驱动程序直接编译到内核,那么我们必须把hello.c拷贝到内核的某个目录下。

字符设备可以考虑放到以下目录:

linux-3.14/drivers/char

  • 2)修改Makefile

root@ubuntu:/home/peng/linux-3.14/drivers/char# vim Makefile 

修改如下:

该行内容是根据Kconfig文件中的宏CONFIG_HELLO来决定是否编译hello.c这个文件()。

  • 3)修改Kconfig

7 HELLO 取前面步骤CONFIG_HELLO下划线后面的字符串,也就是HELLO

8 tristate  表示该模块最终有3个选项:空 、*、M

9 表示该模块依赖的模块,如果ARCH_EXYNOS4模块没有被选中,那么HELLO模块也不会被编译到内核

10 帮助信息

  • 4) 重新配置 执行

make menuconfig

进入配置页面,

输入 / 可以根据关键字查找模块所在位置。

我们添加的模块文件的位置:

根据路径

-> Device Drivers 
   -> Character devices

找到我们刚才的模块配置路径

此处是尖括号,因为我们设置的属性是tristate
移动到Help处,可以看到前面我们填充的帮助信息

我们可以按下空格键设置为*,编译到内核中。

选择Save,

然后再点击2次Exit,就可以退出。

  • 5)重新编译内核

root@ubuntu:/home/peng/linux-3.14# make uImage

这样,我们的模块编译到了新生成的内核模块文件中。

3. 补充

前面一节其实最终目的是生成CONFIG_HELLO=y 这个定义信息,并把该信息保存到内核根目录的.config文件中。

其实我们如果不修改Kconfig,直接在.config中增加这个宏定义也是可以的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值