驅動程式 - Linux Device Driver (LDD) - 使用範例 - C/C++ (PocketBeagle) - Char Device - File Read/Write



參考資訊:
https://www.aps-web.jp/en/ca-en/21578/#anchor2

User Application可以透過read()、write()傳送資料給驅動程式,但是需要注意的地方是,在Linux Kernel中,如果要存取User Application傳送過來的資料時,必須使用copy_to_user()、copy_from_user(),而不是一般的memcpy()或者直接指標操作,否則會導致驅動程式崩潰,這是因為Linux Kernel和User Application是位於不同保護空間,因此,在存取User Application資料時,必須確保該資料已經被Map且位於記憶體

使用方式:

1. copy_to_user()
2. copy_from_user()

main.c

#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steward Fu");
MODULE_DESCRIPTION("Linux Driver");

static int base = 0;
static struct cdev mycdev;
static char mybuf[255] = {0};
static struct class *myclass = NULL;

static int myopen(struct inode *inode, struct file *file)
{
    printk("%s\n", __func__);
    return 0;
}

static int myclose(struct inode *inode, struct file *file)
{
    printk("%s\n", __func__);
    return 0;
}

static ssize_t myread(struct file *flip, char __user *buf, size_t len, loff_t *off)
{
    int r = 0;
  
    r = copy_to_user(buf, mybuf, strlen(mybuf));
    printk("%s, %s\n", __func__, mybuf);
    return r;
}

static ssize_t mywrite(struct file *flip, const char __user *buf, size_t len, loff_t *off)
{
    int r = 0;

    r = copy_from_user(mybuf, buf, len);
    printk("%s, %s\n", __func__, mybuf);
    return r;
}

static const struct file_operations myfops = {
    .owner = THIS_MODULE,
    .open = myopen,
    .read = myread,
    .write = mywrite,
    .release = myclose,
};

int ldd_init(void)
{
    alloc_chrdev_region(&base, 0, 1, "myfile");
    myclass = class_create(THIS_MODULE, "myfile");
    device_create(myclass, NULL, base, NULL, "myfile");
    cdev_init(&mycdev, &myfops);
    cdev_add(&mycdev, base, 1);
    return 0;
}
 
void ldd_exit(void)
{
    device_destroy(myclass, base);
    cdev_del(&mycdev);
    class_destroy(myclass);
    unregister_chrdev_region(base, 1);
}
 
module_init(ldd_init);
module_exit(ldd_exit);

ldd_init: 建立字元驅動程式
myopen: 僅列印字串
mywrite: 儲存並且列印User Application傳送的字串
myread: 複製儲存的字串給User Application並且列印出來
myclose: 僅列印字串
ldd_exit: 刪除字元驅動程式

寫入字串

# echo "test" > /dev/myfile
    mywrite, test

P.S. 按下Ctrl+C停止

讀取字串

# cat /dev/myfile
    myopen
    myread, test
    myclose