驅動程式 - Linux Device Driver (LDD) - 使用範例 - C/C++ (PocketBeagle) - Char Device - Device I/O Control



User Application除了透過read()、write()跟驅動程式傳送資料之外,也可以使用以控制為主的ioctl()去跟驅動程式溝通

main.c

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

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

static int base = 0;
static struct cdev mycdev;
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 long myioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    printk("%s, 0x%x\n", __func__, cmd);
    return 0;
}

static const struct file_operations myfops = {
    .owner = THIS_MODULE,
    .open = myopen,
    .release = myclose,
    .unlocked_ioctl = myioctl,
};

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)
{
    cdev_del(&mycdev);
    device_destroy(myclass, base);
    class_destroy(myclass);
    unregister_chrdev_region(base, 1);
}
 
module_init(ldd_init);
module_exit(ldd_exit);

ldd_init: 建立字元驅動程式
myopen: 僅列印字串
myioctl: 僅列印字串
myclose: 僅列印字串
ldd_exit: 刪除字元驅動程式

app.c

#include <stdio.h>
#include <stdint.h>
#include <sys/fcntl.h> 
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/ioctl.h>

#define MY_IOCTL _IOWR(0x100, 0, unsigned long)

int main(int argc, char **argv)
{
    int fd = 0;

    fd = open("/dev/myfile", O_RDWR);
    ioctl(fd, MY_IOCTL, 0);
    close(fd);
    return 0;
}

編譯App

$ arm-linux-gnueabihf-gcc app.c -o app -static

測試

# insmod /boot/main.ko
# /boot/app
    myopen
    myioctl, 0xc0050000
    myclose