栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

3. Linux驱动 -HelloWorld Final

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

3. Linux驱动 -HelloWorld Final

一个完善的驱动模块

包含模块参数在内的hello world驱动:(hello.c)

#include 
#include 
#include 
#include 
#include 

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("Fist Test Module!");
MODULE_VERSION("1.0");

// 模块参数
// 加载时,使用中 都可以进行修改值
// su 权限修改有问题,需要切换到root账户修改 /sys/module/hello/parameters/paramx
int param1 = 10;
unsigned char param2 = 20;
char* param3 = "<7>";
int param4[4] = {1,3,1,4};

module_param(param1,int,0755);
module_param(param2,byte,0750);
module_param(param3,charp,0644);
module_param_array(param4, int, NULL, 0700);


#define MYMAJOR  200
#define MYCNT    2
#define MYNAME   "helloCHR"
static struct cdev hello_cdev;
static struct class* hello_class;
static struct device* hello_class_dev[2];

static int helloOpen(struct inode *inode, struct file *filp)
{
    printk(	KERN_ERR"hello_openn");
    printk("open: p1=%d, p2=%d, p3=%s, p4=[%d,%d,%d,%d]n", param1, param2, param3, param4[0],param4[1],param4[2],param4[3]);
    return 0;
}
//构建file_operations结构体
static struct file_operations hello_fops = {
    .owner = THIS_MODULE,
    .open = helloOpen,  // 就是这个.open对应的函数
    // .release    = test_chrdev_release,        
    // .write         = test_chrdev_write,
    // .read        = test_chrdev_read,
};

static int helloInit(void)
{
    int i;
    dev_t devid = MKDEV(MYMAJOR, 0);
    printk(	KERN_ERR "Hello, kernel!n");
    printk("init: p1=%d, p2=%d, p3=%s, p4=[%d,%d,%d,%d]n", param1, param2, param3, param4[0],param4[1],param4[2],param4[3]);
    // int register_chrdev_region(dev_t from, unsigned count, const char *name)
    register_chrdev_region(devid, MYCNT, MYNAME);
    // 绑定
    cdev_init(&hello_cdev, &hello_fops);
    // 注册
    cdev_add(&hello_cdev, devid, MYCNT);

    // 创建user space设备
    hello_class = class_create(THIS_MODULE, "helloCls");
    for(i=0;i
        hello_class_dev[i] = device_create(hello_class,NULL,MKDEV(MYMAJOR,i),NULL,"helloDev%d", i);
    }
    return 0;
}

static void helloExit(void)
{
    int i;
    printk(	KERN_ERR "hello exit!");
    // rm dev
    cdev_del(&hello_cdev);
    unregister_chrdev_region(MKDEV(MYMAJOR, 0), MYCNT);

    // del user space device
    for(i=0;i
        device_destroy(hello_class, MKDEV(MYMAJOR,i));
    }
    class_destroy(hello_class);
}


module_init(helloInit);
module_exit(helloExit);

// kernel default print level => /proc/sys/kernel/printk
// 4  4  1  7 => 内核默认打印级别   printk默认级别   xxx  xxxx
// echo 5 > /proc/sys/kernel/printk   // 修改内核默认级别,高于5的log才能打印 <= 重启失效,并且有权限问题
// 修改uboot环境变量, set bootargs xxx=yy ... loglevel=8

注意:printk(“…n”)一定要带上换行符,否则 tail -f /var/log/kern.log不能及时输出日志。

Makefile

# ifneq ($(KERNELRELEASE),)
# mymodule-bojs := hello.o
PWD := $(shell pwd)
KERNELDIR = /lib/modules/$(shell uname -r)/build

obj-m := hello.o

build: all

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

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c

注意参数的权限问题:

  • 只有设置了其他权限的能够被其他账户访问或修改,如果使用sudo insmod在0750以及以上权限会提示权限问题。建议切换到root账户进行测试
  • 如果sudo修改权限时遇到问题,切换到root账户修改

测试文件:(hello_call.c)

#include 
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    int fd = open(argv[1],O_RDWR);
    if(-1==fd)
    {
        printf("Can't open!n");
        return ;
    }
    printf("Open OK!n");
    return 0;
}

编译为可执行文件使用,并且使用sudo或者root进行测试。

导出函数、符号

并不是所有的模块都需要导出函数/符号,只有需要的时候导出给其他模块使用。

symbol.c

#include 
#include 

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("Fist Test symbol export Module!");
MODULE_VERSION("1.0");

int add (int a, int b){
    return a+b;
}

int mul(int a, int b){
    return a*b;
}

EXPORT_SYMBOL(add);  // 普通导出,所有模块都能访问
EXPORT_SYMBOL_GPL(mul); // GPL导出,只有遵循GPL的模块可以使用

symbol_call.c

#include 
#include 

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("Fist Test call symbol export Module!");
MODULE_VERSION("1.0");

// symbol.c 导出函数, 一般是提供头文件的
// 只有模块能调用模块的导出参数
extern int add(int a, int b);
extern int mul(int a, int b);

// call
static int symbol_call_init(void)
{
    printk("Call symbol function add = %dn", add(2,3));
    return 0;
}

static void symbol_call_exit(void)
{
    printk("Call symbol function mul = %dn", mul(2,3));
}

module_init(symbol_call_init);
module_exit(symbol_call_exit);

Makefile

# ifneq ($(KERNELRELEASE),)
# mymodule-bojs := hello.o
PWD := $(shell pwd)
KERNELDIR = /lib/modules/$(shell uname -r)/build

obj-m := symbol_call.o symbol.o

build: all

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

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c

使用:

  • make clean & make
  • sudo tail -f /var/log/kern.log
  • sudo insmod symbol.ko
  • sudo insmod symbol_call.ko
  • sudo rmmod symbol_call
  • sudo rmmod symbol

所以symbol模块只有导出功能,symbol_call模块引用symbol的导出函数使用。

至此,一个驱动模块所缺的所有功能都已经完备,只有虚拟设备/dev/helloDev0的open函数提供了接口,其他函数需要继续完善。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/941239.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号