ARM-驱动

基于STM32MP157--GPIO子系统点灯

myled.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/*mynode@0x12345678{
        compatible = "hqyj,mynode";
        astring="hello 22121";
        uint  =<0xaabbccdd 0x11223344>;
        binarry=[00 0c 29 7b f9 be];
        mixed ="hello",[11 22],<0x12345678>;
     };
*/

struct property *pr;
struct device_node *dnode;
struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
struct class *cls;
struct device *dev;

int gpiono1;
int gpiono2;
int gpiono3;
int lenth;
int ret, i;
char kbuf[128] = {0};

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

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    if (size > sizeof(kbuf))
        size = sizeof(kbuf);
    ret = copy_to_user(ubuf, kbuf, size);
    if (ret)
    {
        printk("copy from user filed\n");
        return -EIO;
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    if (size > sizeof(kbuf))
        size = sizeof(kbuf);
    ret = copy_from_user(kbuf, ubuf, size);
    if (ret)
    {
        printk("copy from user filed\n");
        return -EIO;
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);

    if (strcmp(kbuf, "ON") == 0)
    {
        switch (kbuf[0])
        {
        case 1:
            // 设置gpio高电平
            gpio_set_value(gpiono1, 1);
            break;
        case 2:
            gpio_set_value(gpiono2, 1);
            break;
        case 3:
            gpio_set_value(gpiono3, 1);
            break;
        default:
            printk("输入错误请重新输入\n");
            break;
        }
    }
    else if (strcmp(kbuf, "OFF") == 0)
    {
        switch (kbuf[0])
        {
        case 1:
            // 设置gpio高电平
            gpio_set_value(gpiono1, 0);
            break;
        case 2:
            gpio_set_value(gpiono2, 0);
            break;
        case 3:
            gpio_set_value(gpiono3, 0);
            break;
        default:
            printk("输入错误请重新输入\n");
            break;
        }
    }
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

// 定义一个操作方法结构体变量并且初始化
// 将上面封装的各个操作方法赋值给结构体变量成员
struct file_operations fops = {
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};

static int __init myled_init(void)
{
    int ret;
    // 1.分配对象空间
    cdev = cdev_alloc();
    if (cdev == NULL)
    {
        printk("分配字符设备驱动对象失败\n");
        ret = -ENOMEM;
        goto OUT1;
    }
    printk("分配对象空间成功\n");
    // 2.初始化对象
    cdev_init(cdev, &fops);
    // 3.申请设备号
    if (major > 0) // 静态指定设备号
    {
        ret = register_chrdev_region(MKDEV(major, minor), 3, "myleds");
        if (ret)
        {
            printk("静态指定设备号失败\n");
            goto OUT2;
        }
    }
    else if (major == 0) // 动态申请设备号
    {
        ret = alloc_chrdev_region(&devno, minor, 3, "myleds0");
        if (ret)
        {
            printk("动态申请设备号失败\n");
            goto OUT2;
        }
        // 获取主设备号和次设备号
        major = MAJOR(devno);
        minor = MINOR(devno);
    }
    printk("申请设备号成功\n");
    // 4.注册字符设备驱动对象
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto OUT3;
    }
    printk("注册字符设备驱动对象成功\n");
    // 向上提交目录
    cls = class_create(THIS_MODULE, "myleds0");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = -PTR_ERR(cls);
        goto OUT4;
    }
    printk("向上提交目录成功\n");
    // 向上提交设备节点信息
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myleds%d", i);
        if (IS_ERR(dev))
        {
            ret = -PTR_ERR(dev);
            goto OUT5;
        }
    }
    printk("向上提交设备节点成功\n");

    // 解析设备树节点信息通过名字
    dnode = of_find_node_by_name(NULL, "myleds");
    if (dnode == NULL)
    {
        printk("设备树节点解析失败\n");
    }
    // printk("name=%s,value=%s\n", dnode->properties->name, (char *)dnode->properties->value);
    // printk("name=%s,value=%s\n", dnode->properties->next->name, (char *)dnode->properties->next->value);
    // printk("name=%s,value=%x %x\n", dnode->properties->next->next->name, __be32_to_cpup((unsigned int *)dnode->properties->next->next->value), __be32_to_cpup(((unsigned int *)dnode->properties->next->next->value + 1)));

    // 根据设备树节点解析出gpio编号
    gpiono1 = of_get_named_gpio(dnode, "led1", 0);
    if (gpiono1 < 0)
    {
        printk("解析设备号失败\n");
        return -EIO;
    }
    // 申请gpio编号
    ret = gpio_request(gpiono1, NULL);
    if (ret)
    {
        printk("GPIO1编号申请失败\n");
        return -EIO;
    }
    printk("申请gpio1编号成功%d\n", gpiono1);
    // 设置gpio为输出
    gpio_direction_output(gpiono1, 0);

    // 根据设备树节点解析出gpio编号
    gpiono2 = of_get_named_gpio(dnode, "led2", 0);
    if (gpiono2 < 0)
    {
        printk("解析设备号失败\n");
        return -EIO;
    }
    // 申请gpio编号
    ret = gpio_request(gpiono2, NULL);
    if (ret)
    {
        printk("GPIO2编号申请失败\n");
        return -EIO;
    }
    printk("申请gpio2编号成功%d\n", gpiono2);
    // 设置gpio为输出
    gpio_direction_output(gpiono2, 0);

    // 根据设备树节点解析出gpio编号
    gpiono3 = of_get_named_gpio(dnode, "led3", 0);
    if (gpiono3 < 0)
    {
        printk("解析设备号失败\n");
        return -EIO;
    }
    // 申请gpio编号
    ret = gpio_request(gpiono3, NULL);
    if (ret)
    {
        printk("GPIO3编号申请失败\n");
        return -EIO;
    }
    printk("申请gpio3编号成功%d\n", gpiono3);
    // 设置gpio为输出
    gpio_direction_output(gpiono3, 0);

    return 0;
OUT5:
    // 释放已经申请的设备节点信息
    for (--i; i >= 0; i--)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    // 释放目录空间
    class_destroy(cls);
OUT4:
    // 注销字符设备驱动对象
    cdev_del(cdev);
OUT3:
    // 释放设备号
    unregister_chrdev_region(MKDEV(major, minor), 3);
OUT2:
    // 释放对象空间
    kfree(cdev);
OUT1:
    return ret;
}

static void __exit myled_exit(void)
{
    // 灭灯
    gpio_set_value(gpiono1, 0);
    gpio_set_value(gpiono2, 0);
    gpio_set_value(gpiono3, 0);
    // 释放gpio号
    gpio_free(gpiono1);
    gpio_free(gpiono2);
    gpio_free(gpiono3);
    // 销毁设备节点
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    // 释放目录空间
    class_destroy(cls);
    // 1.注销字符设备驱动对象
    cdev_del(cdev);
    // 2.释放设备号
    unregister_chrdev_region(MKDEV(major, minor), 3);
    // 3.释放对象空间
    kfree(cdev);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");

test.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char const *argv[])
{
    int a, b;
    char buf[128] = {0};
    int fd = open("/dev/myleds0", O_RDWR);
    if (fd < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        printf("请输入要实现的功能:ON(开灯) OFF(关灯)>>");
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf) - 1] = '\0';
        getchar();
        write(fd, buf, sizeof(buf));
        
        if (strcmp(buf, "ON") == 0) // 开灯
        {
            printf("请输入要操作的灯:1(LED1) 2(LED2) 3(LED3)>>");
            fgets(buf, sizeof(buf), stdin);
            write(fd, buf, sizeof(buf));
        }
        else if (strcmp(buf, "OFF") == 0) // 关灯
        {
            printf("请输入要操作的灯:1(LED1) 2(LED2) 3(LED3)>>");
            fgets(buf, sizeof(buf), stdin);
            write(fd, buf, sizeof(buf));
        }
    }
    close(fd);
    return 0;
}

你可能感兴趣的:(单片机,c语言)