解释linux下应用层调用驱动(hello)

创建一个hello的设备来举例应用层如何调用kernel驱动,kernel驱动部分为转载,仅对部分语句做解释。

init函数

Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

register_chrdev用于从内核中为字符设备申请一个主设备号。

创建"hello_class"以及"hello"设备,这两个设备分别挂载在如下路径:

/sys/class/hello_class

/dev/hello

/* 5. kernel启动时initcall(module_init)会调用这个入口函数         */
static int __init hello_init(void)
{
    int err;
    
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    major = register_chrdev(0, "hello", &hello_drv);  /* /dev/hello */

    /* 7. 其他完善:提供设备信息,自动创建设备节点                                 */
    hello_class = class_create(THIS_MODULE, "hello_class");
    err = PTR_ERR(hello_class);
    if (IS_ERR(hello_class)) {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        unregister_chrdev(major, "hello");
        return -1;
    }    
    device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
    
    return 0;
}
/* 指定驱动的入口和出口,以及声明自己的驱动遵循GPL协议(不声明的话无法把驱动加载进内核) */
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

我们来总结一下file_operations模式的驱动模型,file_operations是内核提供用来操作文件的操作集合,我们示例中只使用到了下面四个函数,因此示例中的hello_drv只实现了这四个函数。

struct file_operations {
    ...
    struct module *owner;
    int (*open) (struct inode *, struct file *);
    int (*release) (struct inode *, struct file *);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ...
}

实现了file_operations数据结构后,然后通过module_init/xxx_initcall等方式,调用register_chrdev(仅以字符设备为例),将hello_drv注册到"/dev/"下,例如:

major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */
即将设备注册到/dev/hello

再通过class_create/device_create创建设备的总线信息及设备节点。

将驱动编译进kernel内核后,我们来写一个app打开该设备,调用设备驱动的接口。

注意一下open函数的设备名称为:"/dev/hello"

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

static char databuf[1024];
static char writebuf[1024];

int main(int argc,char *argv[])
{
    int fd;
    int ret;
    
    fd = open("/dev/hello", O_RDWR);
    
    if(fd < 0){
        printf("open fail! \n");
        printf("error  number: %d \n",fd);
        return -1;
    }
    
    memset(databuf,0x0,1024);
    ret = read(fd, databuf, sizeof(databuf));
    
    memset(writebuf,0x0,1024);
    ret = write(fd, writebuf, sizeof(writebuf));
    
    printf("write over \n");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值