首页 » 嵌入式笔记 » 正文

简单Linux 内核中申请物理地址方式

添加设备自动注册

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/cdev.h>

static struct device *my_device;
static struct cdev my_cdev;    // 字符设备结构
static struct class *my_class; // 设备类
static dev_t my_dev;           // 设备号

static void *cma_area;
static dma_addr_t dma_handle;
static size_t size_of_cma = 4 * 1024; // CMA内存大小

#define MY_IOCTL_CMD _IOR('M', 1, dma_addr_t *)

static long my_driver_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd)
    {
    case MY_IOCTL_CMD:
        if (copy_to_user((dma_addr_t __user *)arg, &dma_handle, sizeof(dma_handle)))
            return -EFAULT;
        break;
    default:
        return -EINVAL;
    }
    return 0;
}

static const struct file_operations my_driver_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = my_driver_ioctl,
    // 其他file_operations成员...
};

static int __init my_driver_init(void)
{
    int ret;

    // 分配和注册设备号
    ret = alloc_chrdev_region(&my_dev, 0, 1, "my_device");
    if (ret < 0)
    {
        pr_err("Unable to allocate major number\n");
        return ret;
    }

    // 创建设备类
    my_class = class_create(THIS_MODULE, "my_class");
    if (IS_ERR(my_class))
    {
        unregister_chrdev_region(my_dev, 1);
        return PTR_ERR(my_class);
    }

    // 初始化字符设备
    cdev_init(&my_cdev, &my_driver_fops);
    my_cdev.owner = THIS_MODULE;

    // 添加字符设备
    ret = cdev_add(&my_cdev, my_dev, 1);
    if (ret < 0)
    {
        class_destroy(my_class);
        unregister_chrdev_region(my_dev, 1);
        return ret;
    }

    // 创建设备节点
    my_device = device_create(my_class, NULL, my_dev, NULL, "my_device");
    if (IS_ERR(my_device))
    {
        cdev_del(&my_cdev);
        class_destroy(my_class);
        unregister_chrdev_region(my_dev, 1);
        return PTR_ERR(my_device);
    }

    // 为设备申请CMA内存
    cma_area = dma_alloc_coherent(my_device, size_of_cma, &dma_handle, GFP_KERNEL);
    if (!cma_area)
    {
        pr_err("CMA memory allocation failed\n");
        device_destroy(my_class, my_dev);
        cdev_del(&my_cdev);
        class_destroy(my_class);
        unregister_chrdev_region(my_dev, 1);
        return -ENOMEM;
    }

    char *tABC = (char *)cma_area;
    tABC[0] = 'F';
    tABC[1] = 'U';
    tABC[2] = 'C';
    tABC[3] = 'K';
    pr_info("CMA Memory allocated. Physical Address = %pad\n", &dma_handle);
    return 0;
}

static void __exit my_driver_exit(void)
{
    if (cma_area)
    {
        dma_free_coherent(my_device, size_of_cma, cma_area, dma_handle);
    }

    device_destroy(my_class, my_dev);
    cdev_del(&my_cdev);
    class_destroy(my_class);
    unregister_chrdev_region(my_dev, 1);

    pr_info("CMA Memory and device freed\n");
}

module_init(my_driver_init);
module_exit(my_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux driver for CMA memory allocation");
MODULE_VERSION("0.1");

最简版本

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>

static struct device *my_device;
static void *cma_area;
static dma_addr_t dma_handle;
static size_t size_of_cma = 4*1024; // CMA内存大小,例如1KB

#define MY_IOCTL_CMD _IOR('M', 1, dma_addr_t *)

static long my_driver_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    switch (cmd) {
        case MY_IOCTL_CMD:
            if (copy_to_user((dma_addr_t __user *)arg, &dma_handle, sizeof(dma_handle)))
                return -EFAULT;
            break;
        default:
            return -EINVAL;
    }
    return 0;
}

static const struct file_operations my_driver_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = my_driver_ioctl,
    // 其他file_operations成员...
};

static int __init my_driver_init(void) {
    int ret;

    // 创建并注册设备
    my_device = kzalloc(sizeof(*my_device), GFP_KERNEL);
    if (!my_device) {
        pr_err("Failed to allocate memory for device\n");
        return -ENOMEM;
    }

    dev_set_name(my_device, "my_device");
    ret = device_register(my_device);
    if (ret) {
        pr_err("Failed to register device\n");
        kfree(my_device);
        return ret;
    }

    // 为设备申请CMA内存
    cma_area = dma_alloc_coherent(my_device, size_of_cma, &dma_handle, GFP_KERNEL);
    if (!cma_area) {
        pr_err("CMA memory allocation failed\n");
        device_unregister(my_device);
        kfree(my_device);
        return -ENOMEM;
    }

    char* tABC = (char*)cma_area;
    tABC[0] = 'F';
    tABC[1] = 'U';
    tABC[2] = 'C';
    tABC[3] = 'K';
    pr_info("CMA Memory allocated. Physical Address = %pad\n", &dma_handle);
    return 0;
}

static void __exit my_driver_exit(void) {
    dma_free_coherent(my_device, size_of_cma, cma_area, dma_handle);
    device_unregister(my_device);
    kfree(my_device);
    pr_info("CMA Memory and device freed\n");
}

module_init(my_driver_init);
module_exit(my_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux driver for CMA memory allocation");
MODULE_VERSION("0.1");

发表评论