RV1126 进一步的驱动程序

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


  在本章中,我们将编写一个可以接受两个int型参数和一个char型参数的驱动,并根据char的类型——+或者-——来计算结果,并最终可以通过read返回这一结果。

一、驱动程序

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

#define DEVICE_NAME "my_calc"

static int result;

static ssize_t my_driver_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    char result_str[16];
    int len;

    if (*ppos > 0)
        return 0;

    len = snprintf(result_str, sizeof(result_str), "%d\n", result);

    if (count < len)
        return -EINVAL;

    if (copy_to_user(buf, result_str, len))
        return -EFAULT;

    *ppos = len;
    return len;
}

static ssize_t my_driver_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    uint32_t a, b;
    uint8_t symbol;

    if (count != sizeof(uint32_t) * 2 + sizeof(uint8_t))
        return -EINVAL;

    if (copy_from_user(&a, buf, sizeof(uint32_t)))
        return -EFAULT;

    if (copy_from_user(&b, buf + sizeof(uint32_t), sizeof(uint32_t)))
        return -EFAULT;

    if (copy_from_user(&symbol, buf + 2 * sizeof(uint32_t), sizeof(uint8_t)))
        return -EFAULT;

    switch (symbol) {
        case '+':
            result = a + b;
            break;
        case '-':
            result = a - b;
            break;
        default:
            return -EINVAL;
    }

    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("Author");
MODULE_DESCRIPTION("A simple calculator driver");

二、应用程序

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

#define DEVICE_PATH "/dev/my_calc"

int main(int argc, char *argv[])
{
    int fd;
    int a, b, result;
    char symbol;
    char buffer[16];
    char write_buffer[9];

    if (argc != 4) {
        fprintf(stderr, "Usage: %s <a> <b> <symbol>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    a = atoi(argv[1]);
    b = atoi(argv[2]);

    symbol = argv[3][0];

    if (symbol != '+' && symbol != '-') {
        fprintf(stderr, "Invalid symbol. Use '+' or '-'.\n");
        exit(EXIT_FAILURE);
    }

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

    // 将数据打包到 write_buffer 中
    memcpy(write_buffer, &a, sizeof(int));
    memcpy(write_buffer + sizeof(int), &b, sizeof(int));
    memcpy(write_buffer + 2 * sizeof(int), &symbol, sizeof(char));

    // 一次性写入所有数据
    if (write(fd, write_buffer, sizeof(write_buffer)) != sizeof(write_buffer)) {
        perror("Failed to write data to device");
        close(fd);
        exit(EXIT_FAILURE);
    }

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

    result = atoi(buffer);

    printf("%d %c %d = %d\n", a, symbol, b, result);

    close(fd);
    return 0;
}