作者: baron

    由于一直从事驱动开发, 一直想对整体流程有个了解, 刚好看到这篇文章 AndroidQ 从app到驱动 第一章 编写Linux内核驱动程序. 于是参考这篇文章在 rk3566 上面完成了从驱动到 app 的实验验证. 文章记录用到的知识点以及遇到的问题和解决方法.

     整体框架大致分为如下 5 层.

rk3566-Android11 从驱动到 app 第一章添加驱动程序-LMLPHP

一、添加 kernel 驱动

1. 驱动编写

    驱动部分写一个 misc 设备就行了, 提供简单的读写功能. 由于只是简单的验证功能所以没有越界处理和错误处理.

#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "hello"
static char my_data[100] = "Hello, this is my_misc_device!\n";

static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    if (copy_to_user(buf, my_data, count))
        return -EFAULT;

    return count;
}

static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    if (copy_from_user(my_data, buf, count))
        return -EFAULT;

    return count;
}

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .read = my_read,
    .write = my_write,
};

static struct miscdevice my_misc_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &my_fops,
};

static int __init my_init(void)
{
    int ret = misc_register(&my_misc_device);
    if (ret) {
        pr_err("Failed to register misc device\n");
        return ret;
    }

    return 0;
}

static void __exit my_exit(void)
{
    misc_deregister(&my_misc_device);
}

module_init(my_init);
module_exit(my_exit);

对应的 makefile 部分直接将驱动编进内核.

obj-y += hello.o

修改的文件如下所示

rk3566-Android11 从驱动到 app 第一章添加驱动程序-LMLPHP

编译下载查看成功创建节点

rk3566_rgo:/ # ls /dev/hello
/dev/hello

2. 验证驱动

编写一个简单的应用程序验证驱动是 ok 的, 创建 external/test/test.c, 应用程序的内容如下.

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

int main(int argc, char* argv[])
{

    char* buff = (char*)malloc(100);
    int fd = -1;

    buff[99] = '\0';

    if(argc < 2)
        return 0;

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

    if(!strcmp("write", argv[1])){
        write(fd, argv[2], strlen(argv[2]));
        printf("write %s to /dev/hello buf\n\n", argv[2]);
    }else if(!strcmp("read", argv[1])){
        read(fd, buff, 99);
        printf("read data form /dev/hello : %s\n\n", buff);
    }else {
        printf("please use write or read cmd\n");
    }

    close(fd);

    return 0;
}

添加 external/test/Android.bp内容如下, 用来编译 bin 文件.

cc_binary {
    name: "mytest",
    srcs: ["test.c"],
    shared_libs: [
        "libbase",
        "libcutils",
        "liblog",
        "libutils",
    ],
}

添加完成之后进入 external/test/运行 mmm .编译. 编译完成之后如图, 得到 my_test

rk3566-Android11 从驱动到 app 第一章添加驱动程序-LMLPHP

将其 push 到机器的 cache/目录. 验证结果如图所示, 驱动正常运行.

rk3566-Android11 从驱动到 app 第一章添加驱动程序-LMLPHP
01-19 15:50