Register three device files for the three LED lights of the development board, one-to-one correspondence. Use the built-in struct inode structure and struct file structure in the kernel for development.

1. Driver code, install the LED light driver and register the device file, complete the mapping of the register address, and control the light on and off

#include "head.h"
#include "cdev.h"

int mycdev_open(struct inode *inode, struct file *file)
{
    //1. Find the device number through struct inode
    //2. Use the MINOR function to find the secondary device number according to the device number
    //3. Put the secondary device number into private_date in the struct file
    led_minor=MINOR(inode->i_rdev);
    file->private_data=(void *)led_minor;
    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__);
    
    // read copy to user space
    if (size > sizeof(kbuf)) // The size that the user space expects to read cannot be satisfied by the kernel, then give the maximum size supported by the kernel
        size = sizeof(kbuf);
    ret = copy_to_user(ubuf, kbuf, size);
    if (ret) // copy failed
    {
        printk("copy_to_user filed\\
");
        return ret;
    }
    return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    //Get the secondary device number stored in the private_data of the struct file
    led_x=(unsigned int)file->private_data;
    //Judge the device file of which LED light
    switch(led_x)
    {
        //LED1 light
        case 0:
            switch(cmd)
            {
                case LED_ON:
                    vir_led1->ODR |=(1<<10);
                break;
                case LED_OFF:
                    vir_led1->ODR & amp;=(~(1<<10));
                break;
            }
        break;
        //LED2 lights
        case 1:
            switch(cmd)
            {
                case LED_ON:
                vir_led2->ODR |=(1<<10);
                break;
                case LED_OFF:
                vir_led2->ODR & amp;=(~(1<<10));
                break;
            }
        break;
        //LED3 lights
        case 2:
            switch(cmd)
            {
                case LED_ON:
                vir_led3->ODR |=(1<<8);
                break;
                case LED_OFF:
                vir_led3->ODR |=(~(1<<8));
                break;
            }
        break;
    }
    return 0;
}

int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\\
", __FILE__, __func__, __LINE__);
    return 0;
}

int all_led_init(void)
{
    // Mapping of register addresses
    vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
    if (vir_led1 == NULL)
    {
        printk("ioremap filed:%d\\
", __LINE__);
        return -ENOMEM;
    }
    vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));
    if (vir_led2 == NULL)
    {
        printk("ioremap filed:%d\\
", __LINE__);
        return -ENOMEM;
    }
    vir_led3 = vir_led1;
    vir_rcc = ioremap(PHY_RCC_ADDR, 4);
    if (vir_rcc == NULL)
    {
        printk("ioremap filed:%d\\
", __LINE__);
        return -ENOMEM;
    }
    printk("Physical address mapping successful\\
");
    // register initialization
    // rcc
    (*vir_rcc) |= (3 << 4);
    //led1
    vir_led1->MODER & amp;= (~(3 << 20));
    vir_led1->MODER |= (1 << 20);
    vir_led1->ODR &= (~(1 << 10));
    // led2
    vir_led2->MODER & amp;= (~(3 << 20));
    vir_led2->MODER |= (1 << 20);
    vir_led2->ODR &= (~(1 << 10));
    // led3
    vir_led3->MODER & amp;= (~(3 << 16));
    vir_led1->MODER |= (1 << 16);
    vir_led1->ODR &= (~(1 << 8));

    return 0;
}



ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    unsigned long ret;
    // read data from user space
    if (size > sizeof(kbuf)) // The size that the user space expects to read cannot be satisfied by the kernel, then give the maximum size supported by the kernel
        size = sizeof(kbuf);
    ret = copy_from_user( & amp; sum, ubuf, size);
    if (ret) // copy failed
    {
        printk("copy_to_user filed\\
");
        return ret;
    }


    return 0;
}
// Define the operation method structure variable and assign it
struct file_operations fops = {

    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
    .unlocked_ioctl = mycdev_ioctl,
};
static int __init mycdev_init(void)
{
    int i=-1;
    /*****LED lamp driver installation process*****/
    //1. Install the driver to obtain the mojor device number
    printk("LED light driver installation\\
");
    major=register_chrdev(0,"mychrdev", & amp;fops); //The system dynamically applies for the major equipment number
    if(major<0)
    {
        printk("Major device number application failed\\
");
        return major;
    }
    printk("Major device number application is successful: major=%d\\
",major);

    //3. Submit directory up
    cls=class_create(THIS_MODULE,"mychrdev");
    if(IS_ERR(cls))
    {
        printk("Failed to submit directory up\\
");
        return PTR_ERR(cls);
    }
    printk("submit directory successfully\\
");
    /*
    cls=class_create(THIS_MODULE,"mychrdev1");
    cls=class_create(THIS_MODULE,"mychrdev2");
    */
    
    //4. Submit device node information upwards, and create device files for each lamp
    
    for(i=0;i<3;i ++ )
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i);
        if(IS_ERR(dev))
        {
            printk("Upward submission of device information mychrdev%d failed\\
",i);
            return PTR_ERR(dev);
        }
        printk("submit device information mychrdev%d successfully",i);
    }

    //Initialization of the LED lights
    all_led_init();
    return 0;
}

static void __exit mycdev_exit(void)
{
    // Cancel address mapping
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);
 
    // Destroy device information
    device_destroy(cls, MKDEV(major, 0));
    device_destroy(cls, MKDEV(major, 1));
    device_destroy(cls, MKDEV(major, 2));
    // destroy directory
    class_destroy(cls);
    // Unregister the character device driver
    unregister_chrdev(major, "mychrdev");
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

2. Apply the code, open different device files, and control the corresponding LED lights to flash

#include "user.h"
#include "head.h"

int main(int argc, char const *argv[])
{

    while (1)
    {
        my_select = -1;
        key = -1;
        fd = -1;
        printf("Please choose the operation you want to perform 1<light on>, 2<light off>: ");
        scanf("%d", &my_select);
        switch (my_select)
        {
        // light up
        case 1:
            printf("Select the indicator light you want to operate 1<LED1>, 2<LED2>, 3<LED3>: ");
            scanf("%d", & key);
            switch (key)
            {
            // Operation LED1 lights up
            case 1:
                // Open the device file for the LED light
                fd = open("/dev/mychrdev0", O_RDWR);
                if (fd < 0)
                {
                    printf("Failed to open device file\\
");
                    exit(-1);
                }
                ioctl(fd, LED_ON);
                break;
            // Operation LED2 lights up
            case 2:
                fd = open("/dev/mychrdev1", O_RDWR);
                if (fd < 0)
                {
                    printf("Failed to open device file\\
");
                    exit(-1);
                }
                ioctl(fd, LED_ON);
                break;
            // Operation LED3 lights up
            case 3:
                fd = open("/dev/mychrdev2", O_RDWR);
                if (fd < 0)
                {
                    printf("Failed to open device file\\
");
                    exit(-1);
                }
                ioctl(fd, LED_ON);
                break;
            }

            break;

        // lights out
        case 2:
            printf("Select the indicator light you want to operate 1<LED1>, 2<LED2>, 3<LED3>: ");
            scanf("%d", & key);
            switch (key)
            {
            // Operation LED1 lights off
            case 1:
                // Open the device file for the LED light
                fd = open("/dev/mychrdev0", O_RDWR);
                if (fd < 0)
                {
                    printf("Failed to open device file\\
");
                    exit(-1);
                }
                ioctl(fd, LED_OFF);
                break;
            // Operation LED2 lights off
            case 2:
                fd = open("/dev/mychrdev1", O_RDWR);
                if (fd < 0)
                {
                    printf("Failed to open device file\\
");
                    exit(-1);
                }
                ioctl(fd, LED_OFF);
                break;
            // Operation LED3 lights off
            case 3:
                fd = open("/dev/mychrdev2", O_RDWR);
                if (fd < 0)
                {
                    printf("Failed to open device file\\
");
                    exit(-1);
                }
                ioctl(fd, LED_OFF);
                break;
            }
            break;

        default:
            break;
        }
    }
    close(fd);

    return 0;
}