Driver development 5 blocking IO instances, IO multiplexing

1 blocking IO

Process 1

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int a,b;
    int fd = open("/dev/myled0",O_RDWR);
    if(fd < 0)
    {
        printf("Failed to open device file\
");
        exit(-1);
    }
    while(1)
    {
        memset(buf,0,sizeof(buf));
        read(fd,buf,sizeof(buf));
        printf("buf:%s\
",buf);
    }
}

Process 2

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char buf[128] = "hello world";
    int a,b;
    int fd = open("/dev/myled0",O_RDWR);
    if(fd < 0)
    {
        printf("Failed to open device file\
");
        exit(-1);
    }
    write(fd,buf,sizeof(buf));
}

Driver

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/uaccess.h>

int major;
char kbuf[128] = {0};

unsigned int *vir_rcc;
struct class *cls;
struct device *dev;
//Define waiting queue
wait_queue_head_t wq_head;
unsigned int condition=0;
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    return 0;
}

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size,loff_t *lof)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    if(file->f_flags & amp;O_NONBLOCK)//User program reads and writes data in a non-blocking manner
    {}
    else{
        wait_event_interruptible(wq_head,condition);//Judge the value of condition, if it is false, the process will sleep
    }
    //Copy the obtained hardware data to the user
    int ret = copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filed\
");
        return -EIO;
    }
    condition = 0; //Indicates that the next data is not ready
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    int ret;
    ret = copy_from_user(kbuf,ubuf,size);
    if (ret)
    {
        printk("copy_from_user filed\
");
        return -EIO;
    }
    condition = 1;//Indicates that the hardware data is ready
    wake_up_interruptible( & amp;wq_head);//Wake up the dormant process
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    return 0;
}

//Define operation method structure variables and assign values
struct file_operations fops={

    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};
static int __init mycdev_init(void)
{
    //Initialize the waiting queue
    init_waitqueue_head( & amp;wq_head);
    //Character device driver
    major = register_chrdev(0,"mychrdev", & amp;fops);
    if(major < 0)
    {
        printk("Character device driver registration failed\
");
        return major;
    }
    printk("Character device driver registration successful: major=%d\
",major);

    //Submit directory upward class_create
    cls = class_create(THIS_MODULE,"mychrdev");
    if(IS_ERR(cls))
    {
        printk("Failed to submit directory upward\
");
        return -PTR_ERR(cls);
    }
    printk("Submit directory upward successfully\
");

    //Submit device node information upward device_create
    int i;
    for(i=0;i<3;i + + )
    {
        dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("Failed to submit device node upward\
");
            return -PTR_ERR(dev);
        }
    }
    printk("Submit device node information upward successfully\
");
    return 0;
}
static void __exit mycdev_exit(void)
{
    //1. Destroy device node information
    int i;
    for(i=0;i<3;i + + )
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //2. Destroy the directory
    class_destroy(cls);
    //3. Unregister the character device driver
    unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

Makefile

modname ?= demo
arch ?= arm
ifeq ($(arch),arm) #The architecture passed from the command line determines how to compile
#KERBELDIR Save the development board kernel source code path
KERNELDIR := /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
else
#Save UBUNTU kernel source code path
KERNELDIR := /lib/modules/$(shell uname -r)/build
endif

#PWD saves the path of the current kernel module
PWD := $(shell pwd)
all:
#make modules is a modular compilation command
#make -C $(KERNLEDIR) Switch to the path corresponding to KERNELDIR before executing make
#M=$(PWD) means that the path for modular compilation is the path saved by PWD
make -C $(KERNELDIR) M=$(PWD) modules
clean:
#Compile clear
make -C $(KERNELDIR) M=$(PWD) clean
#Link the files saved by obj-m separately as kernel modules
obj-m := $(modname).o

Effect demonstration

2 IO multiplexing

Driver

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/poll.h>

int major;
char kbuf[128] = {0};

unsigned int *vir_rcc;
struct class *cls;
struct device *dev;
//Define waiting queue
wait_queue_head_t wq_head;
unsigned int condition=0;
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    return 0;
}

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size,loff_t *lof)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    if(file->f_flags & amp;O_NONBLOCK)//User program reads and writes data in a non-blocking manner
    {}
    else{
        //wait_event_interruptible(wq_head,condition);//Judge the value of condition, if it is false, the process sleeps
    }
    //Copy the obtained hardware data to the user
    int ret = copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filed\
");
        return -EIO;
    }
    condition = 0; //Indicates that the next data is not ready
    return 0;
}

__poll_t mycdev_poll(struct file *file, struct poll_table_struct *wait)
{
    __poll_t mask = 0;
    // Submit the head of the waiting queue upwards
    poll_wait(file, & amp;wq_head, wait);
    //Give an appropriate return value based on whether the data is ready
    if(condition)
        mask = POLLIN;
    return mask;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    int ret = copy_from_user(kbuf,ubuf,size);
    if (ret)
    {
        printk("copy_from_user filed\
");
        return -EIO;
    }
    condition = 1;//Indicates that the hardware data is ready
    wake_up_interruptible( & amp;wq_head);//Wake up the dormant process
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\
",__FILE__,__func__,__LINE__);
    return 0;
}

//Define operation method structure variables and assign values
struct file_operations fops={
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .poll = mycdev_poll,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    //Initialize the waiting queue
    init_waitqueue_head( & amp;wq_head);
    //Character device driver
    major = register_chrdev(0,"mychrdev", & amp;fops);
    if(major < 0)
    {
        printk("Character device driver registration failed\
");
        return major;
    }
    printk("Character device driver registration successful: major=%d\
",major);

    //Submit directory upward class_create
    cls = class_create(THIS_MODULE,"mychrdev");
    if(IS_ERR(cls))
    {
        printk("Failed to submit directory upward\
");
        return -PTR_ERR(cls);
    }
    printk("Submit directory upward successfully\
");

    //Submit device node information upward device_create
    int i;
    for(i=0;i<3;i + + )
    {
        dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("Failed to submit device node upward\
");
            return -PTR_ERR(dev);
        }
    }
    printk("Submit device node information upward successfully\
");
    return 0;
}
static void __exit mycdev_exit(void)
{
    //1. Destroy device node information
    int i;
    for(i=0;i<3;i + + )
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //2. Destroy the directory
    class_destroy(cls);
    //3. Unregister the character device driver
    unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

Process 1: Listening to multiple events

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>

int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int fd1,fd2;
    fd1 = open("/dev/input/mouse0",O_RDWR);
    if(fd1 < 0)
    {
        printf("Failed to open mouse device\
");
        return -1;
    }
    fd2 = open("/dev/myled0",O_RDWR);
    if(fd2 < 0)
    {
        printf("Failed to open device\
");
        return -1;
    }
    //Define read event collection
    fd_set readfds;
    while(1)
    {
        // Clear the collection
        FD_ZERO( &readfds);
        //Add events to be listened to into the collection
        FD_SET(fd1, & amp;readfds);
        FD_SET(fd2, & amp;readfds);
        //Block listening events
        int ret;
        ret = select(fd2 + 1, & readfds, NULL, NULL, NULL);
        if(ret < 0)
        {
            printf("select call failed\
");
            return -1;
        }
        // Determine whether the event occurs
        if(FD_ISSET(fd1, & amp;readfds));
        {
            memset(buf, 0, sizeof(buf));
            read(fd1, buf, sizeof(buf));
            printf("Mouse event occurred buf:%s\
", buf);
        }
        if(FD_ISSET(fd2, & amp;readfds))
        {
            memset(buf,0,sizeof(buf));
            read(fd2,buf,sizeof(buf));
            printf("Event occurred buf:%s\
",buf);
        }
    }
    //Close file descriptor
    close(fd1);
    close(fd2);
    return 0;
}

Process 2: Simulate custom event ready

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char buf[128] = "hello world";
    int a,b;
    int fd = open("/dev/myled0",O_RDWR);
    if(fd < 0)
    {
        printf("Failed to open device file\
");
        exit(-1);
    }
    write(fd,buf,sizeof(buf));
}

Effect demonstration

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. CS entry skill treeLinux introductionFirst introduction to Linux 37644 people are learning the system