driver development platform

Task: Complete the writing of the LED driver based on the platform driver model to realize the lighting of three lamps

Application layer program

#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>

#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)
int main(int argc, char const *argv[])
{
//Open the first device file
int fd1 = open("/dev/myled0", O_RDWR);
if (fd1 < 0)
{
printf("Failed to open device file\
");
exit(-1);
}
//Open the second device file
int fd2 = open("/dev/myled1", O_RDWR);
if (fd2 < 0)
{
printf("Failed to open device file\
");
exit(-1);
}
//Open the third device file
int fd3 = open("/dev/myled2", O_RDWR);
if (fd3 < 0)
{
printf("Failed to open device file\
");
exit(-1);
}

while (1)
{
int a, b;
//Read from terminal
printf("Please enter characters\
");
printf("First character: 1(LED1) 2(LED2) 3(LED3)\
");
scanf("%d", & amp;a);
printf("Second character: 0 (lights off) 1 (lights on)\
");
printf("Please enter >");
scanf("%d", & amp;b);
//Write to device file
switch (b)
{
case 1:
switch (a)
{
case 1: //LED1
printf("LED1_ON\
");
ioctl(fd1, LED_ON, & amp;a);
break;
case 2: //LED2
printf("LED2_ON\
");
ioctl(fd2, LED_ON, & amp;a);
break;
case 3: //LED3
printf("LED3_ON\
");
ioctl(fd3, LED_ON, & amp;a);
break;
}
break;
case 0:
switch (a)
{
case 1: //LED1
printf("LED1_OFF\
");
ioctl(fd1, LED_OFF, & amp;a);
break;
case 2: //LED2
printf("LED2_OFF\
");
ioctl(fd2, LED_OFF, & amp;a);
break;
case 3: //LED3
printf("LED3_OFF\
");
ioctl(fd3, LED_OFF, & amp;a);
break;
}
break;
}
}

close(fd1);
close(fd2);
close(fd3);

return 0;
}

driver code

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/device.h>

#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)
struct resource *res;
int irqnum;
struct gpio_desc *gpionum1;
struct gpio_desc *gpionum2;
struct gpio_desc *gpionum3;
struct device *dev;

int major;
struct class *cls;

struct of_device_id of_tab[] =
    {
        {
            .compatible = "hqyj,myplatform",
        },
        {
            .compatible = "hqyj,myplatform1",
        },
        {},
};
//Open file function
int myopen(struct inode *inode, struct file *file)
{

    return 0;
}
//Close file function
int myclose(struct inode *inode, struct file *file)
{
int i;
for(i = 0;i < 3;i + + )
{
device_destroy(cls,MKDEV(major,i));
}
class_destroy(cls);
unregister_chrdev(major,"mychrdev");
    return 0;
}

// io control function
long myioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
printk("__ioctrl__");
    int which;
    int ret = copy_from_user( & amp;which, (void *)arg, 4);
    if (ret)
    {
        printk("copy_from_user failed\
");
        return -EIO;
    }
    printk("copy_from_user success : [%d]\
",which);
    switch(cmd)
    {
    case LED_ON:
        switch (which)
        {
        case 1:
printk("[1] : LED_ON\
");
            gpiod_set_value(gpionum1, 1);
            break;
        case 2:
printk("[2] : LED_ON\
");
            gpiod_set_value(gpionum2, 1);
            break;
        case 3:
printk("[3] : LED_ON\
");
            gpiod_set_value(gpionum3, 1);
            break;
        }
        break;
    case LED_OFF:
        switch (which)
        {
        case 1:
printk("[1] : LED_OFF\
");
            gpiod_set_value(gpionum1, 0);
            break;
        case 2:
printk("[2] : LED_OFF\
");
            gpiod_set_value(gpionum2, 0);
            break;
        case 3:
printk("[3] : LED_OFF\
");
            gpiod_set_value(gpionum3, 0);
            break;
        }
        break;
    }
    return 0;
}

// Operation method structure
struct file_operations fops = {
    .open = myopen,
    .unlocked_ioctl = myioctl,
    .release = myclose,
};

//Matching success function
int pdri_probe(struct platform_device *pdev)
{
    printk("%s : %s : %d\
", __FILE__, __func__, __LINE__);

    //Character device registration
    major = register_chrdev(0, "mychrdev", & amp;fops);
    if (major < 0)
    {
        printk("register_chrdev failed\
");
        return -1;
    }
    printk("register_chrdev success\
");

    //Submit the superior directory
    cls = class_create(THIS_MODULE, "mychrdev");
    if (IS_ERR(cls))
    {
        printk("class_create failed\
");
        return -PTR_ERR(cls);
    }
    printk("class_create success\
");

    // Submit node information upward three times
    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("[%d] : device_create failed\
", i);
            return -PTR_ERR(dev);
        }
    }
    printk("device_create success\
");

    // Get device information
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res == NULL)
    {
        printk("MEM : platform_get_resource failed\
");
        return -1;
    }
    printk("MEN : %x\
", res->start);

    // Get interrupt number information
    irqnum = platform_get_irq(pdev, 0);
    if (irqnum < 0)
    {
        printk("IRQ : platform_get_irq failed\
");
        return -1;
    }
    printk("IRQ : %d\
", irqnum);

    // Get LED1gpio information
    gpionum1 = gpiod_get_from_of_node(pdev->dev.of_node, "led1-gpioe", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpionum1))
    {
        printk("gpiod_get_from_of_node failed\
");
        return PTR_ERR(gpionum1);
    }
    printk("gpiod_get_from_of_node success\
");

    // Get LED2gpio information
    gpionum2 = gpiod_get_from_of_node(pdev->dev.of_node, "led2-gpiof", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpionum2))
    {
        printk("gpiod_get_from_of_node failed\
");
        return PTR_ERR(gpionum2);
    }
    printk("gpiod_get_from_of_node success\
");

    // Get LED3gpio information
    gpionum3 = gpiod_get_from_of_node(pdev->dev.of_node, "led3-gpioe", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpionum3))
    {
        printk("gpiod_get_from_of_node failed\
");
        return PTR_ERR(gpionum3);
    }
    printk("gpiod_get_from_of_node success\
");

    return 0;
}

// separate function
int pdri_remove(struct platform_device *pdev)
{
    gpiod_set_value(gpionum1, 0);
    gpiod_set_value(gpionum2, 0);
    gpiod_set_value(gpionum3, 0);
    gpiod_put(gpionum1);
    gpiod_put(gpionum2);
    gpiod_put(gpionum3);
    printk("%s : %s : %d\
", __FILE__, __func__, __LINE__);
    return 0;
}

// Allocate space to the driver object
struct platform_driver pdri = {
    .probe = pdri_probe,
    .remove = pdri_remove,
    .driver.name = "a",
    .driver.of_match_table = of_tab,
};

module_platform_driver(pdri);

MODULE_LICENSE("GPL");