RV1126 为Linux添加一个驱动

发布于 2024-07-24  76 次阅读


  在本章中,我们试图在kernel/driver/misc下添加一个自己的驱动程序,并将其build-in到系统中。

  我们在kernel/driver/misc下创建一个文件夹my_driver,并添加.cMakefileKconfig

一、hello.c

  我们这个应用程序是一个最简单的驱动,它可以从用户空间读取字符串、向用户空间发送字符串,除此之外它没有其他的功能。这个驱动的文件名是hello.c,设备名是my_driver

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

#define DEVICE_NAME "my_driver"

static ssize_t my_driver_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    const char *hello_world = "Hello world";
    size_t len = strlen(hello_world);

    if (*ppos >= len)
        return 0;

    if (count > len - *ppos)
        count = len - *ppos;

    if (copy_to_user(buf, hello_world + *ppos, count))
        return -EFAULT;

    *ppos += count;
    return count;
}

static ssize_t my_driver_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    char input_str[256];

    if (count > sizeof(input_str) - 1)
        count = sizeof(input_str) - 1;

    if (copy_from_user(input_str, buf, count))
        return -EFAULT;

    input_str[count] = '\0';
    pr_info("Received string: %s\n", input_str);

    return count;
}

static const struct file_operations my_driver_fops = {
    .owner = THIS_MODULE,
    .read = my_driver_read,
    .write = my_driver_write,
};

static struct miscdevice my_driver_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &my_driver_fops,
};

static int __init my_driver_init(void)
{
    int ret;

    ret = misc_register(&my_driver_device);
    if (ret)
        pr_err("Failed to register misc device\n");

    return ret;
}

static void __exit my_driver_exit(void)
{
    misc_deregister(&my_driver_device);
}

module_init(my_driver_init);
module_exit(my_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple driver example");

二、Makefile & Kconfig

  我们在Makefile中添加如下内容:

obj-$(CONFIG_MYDRIVER) += hello.o

Kconfig内容如下:

config ChooseMyDriver
    tristate "description"
    select MYDRIVER
    default y
    help
      Enable support for the my_driver device.

三、其他配置

  我们在misc/Kconfig中添加:

config MYDRIVER
    tristate "description"
    default y
    help
      Say Sth.

和:

source "drivers/misc/my_driver/Kconfig"

同时,我们在misc/Makefile中添加:

obj-$(CONFIG_MYDRIVER)      += my_driver/

我们还需要在kernel.config文件(这里用的是rv1126_defconfig)中添加:

CONFIG_ChooseMyDriver=y

  完成之后,我们可以编译系统。我们可以在/dev/下发现dev/my_driver设备,证明其被加载成功。

四、验证程序

  我们写一个应用程序来验证驱动,文件目录如下:

.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp

其中,我们在./build中构建程序;src用来存放源码。

  在./CMakeLists.txt中,其内容如下:

PROJECT(Test_Driver_Application)

CMAKE_MINIMUM_REQUIRED(VERSION 3.5)

SET(COMPILER_PATH "/home/xjt/_Workspace_/RV1126/RV1126_RV1109_LINUX_SDK_V2.2.5.1_20230530/buildroot/output/rockchip_rv1126_rv1109/host/bin/")

SET(CMAKE_C_COMPILER ${COMPILER_PATH}arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER ${COMPILER_PATH}arm-linux-gnueabihf-g++)

SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s -O3 -lrt")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s -O3 -lrt")

ADD_SUBDIRECTORY(src bin)

  在./src/CMakeLists.txt内容如下:

FILE(
    GLOB_RECURSE SRC_LIST 
    ./*.c
    ./*.cpp
)

# Exe output path
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR/bin})

ADD_EXECUTABLE(demo ${SRC_LIST})

# Link lib and so
TARGET_LINK_LIBRARIES(
    demo
)

  main.c内容如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

#define DEVICE_PATH "/dev/my_driver"

int main(void)
{
    int fd;
    char buffer[256];
    ssize_t bytes_read, bytes_written;

    fd = open(DEVICE_PATH, O_RDWR);
    if (fd == -1) {
        perror("Failed to open device");
        exit(EXIT_FAILURE);
    }

    bytes_read = read(fd, buffer, sizeof(buffer));
    if (bytes_read == -1) {
        perror("Failed to read from device");
        close(fd);
        exit(EXIT_FAILURE);
    }

    printf("Read from device: %.*s\n", (int)bytes_read, buffer);

    strcpy(buffer, "Hello from user space");
    bytes_written = write(fd, buffer, strlen(buffer));
    if (bytes_written == -1) {
        perror("Failed to write to device");
        close(fd);
        exit(EXIT_FAILURE);
    }

    close(fd);
    return 0;
}

  我们在./build下执行cmake ..,之后再直接make。即可在./build/bin下找到最终的程序demo