驱动开发 使用ioctl,GPIO子系统控制LED灯

华清远见上海中心22071班

使用ioctl,GPIO子系统控制LED灯

#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "linux_6led.h"

#define CNAME "myled"
int major;
int minor = 0;
int count = 6;
struct cdev *cdev;
struct class *cls;
struct device *dvc;
struct device_node *node;
struct gpio_desc *topled1;
struct gpio_desc *topled2;
struct gpio_desc *topled3;
struct gpio_desc *baseled1;
struct gpio_desc *baseled2;
struct gpio_desc *baseled3;
// myleds
// {
//     topled1 = <&gpioe 10 0>;
//     topled2 = <&gpiof 10 0>;
//     topled3 = <&gpioe 8 0>;
//     baseled1 = <&gpioz 5 0>;
//     baseled2 = <&gpioz 6 0>;
//     baseled3 = <&gpioz 7 0>;
// };
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("打开成功\n");
    return 0;
}
int mycdev_release(struct inode *inode, struct file *file)
{
    printk("关闭成功\n");
    return 0;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd)
    {
    case TOPLED1_ON:
        gpiod_set_value(topled1, 1);
        break;
    case TOPLED1_OFF:
        gpiod_set_value(topled1, 0);
        break;
    case TOPLED2_ON:
        gpiod_set_value(topled2, 1);
        break;
    case TOPLED2_OFF:
        gpiod_set_value(topled2, 0);
        break;
    case TOPLED3_ON:
        gpiod_set_value(topled3, 1);
        break;
    case TOPLED3_OFF:
        gpiod_set_value(topled3, 0);
        break;
    case BASELED1_ON:
        gpiod_set_value(baseled1, 1);
        break;
    case BASELED1_OFF:
        gpiod_set_value(baseled1, 0);
        break;
    case BASELED2_ON:
        gpiod_set_value(baseled2, 1);
        break;
    case BASELED2_OFF:
        gpiod_set_value(baseled2, 0);
        break;
    case BASELED3_ON:
        gpiod_set_value(baseled3, 1);
        break;
    case BASELED3_OFF:
        gpiod_set_value(baseled3, 0);
        break;
    }
    return 0;
}

struct file_operations fops = {
    .open = mycdev_open,
    .release = mycdev_release,
    .unlocked_ioctl = mycdev_ioctl};
static int __init
led_init(void)
{
    int res, i;
    dev_t devt;

    //分配cdev结构
    cdev = cdev_alloc();
    if (NULL == cdev)
    {
        printk("申请空间失败\n");
        res = -EIO;
        goto ERR1;
    }

    //初始化cdev结构体
    cdev_init(cdev, &fops);

    //动态注册字符设备编号
    res = alloc_chrdev_region(&devt, 0, count, CNAME);
    if (res)
    {
        printk("动态注册字符设备编号失败(err %d)\n", -res);
        goto ERR2;
    }
    major = MAJOR(devt);
    minor = MINOR(devt);

    //向系统中添加字符设备
    res = cdev_add(cdev, devt, count);
    if (res)
    {
        printk("系统添加字符设备失败(err %d)\n", -res);
        goto ERR3;
    }

    //上传目录
    cls = class_create(THIS_MODULE, CNAME);
    if (IS_ERR(cls))
    {
        printk("上传目录失败 (err %ld)\n", PTR_ERR(cls));
        res = PTR_ERR(cls);
        goto ERR4;
    }

    //上传节点
    for (i = 0; i < count; i++)
    {
        dvc = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
        if (IS_ERR(dvc))
        {
            printk("节点上传失败 (err %ld)\n", PTR_ERR(dvc));
            res = PTR_ERR(dvc);
            goto ERR5;
        }
    }

    node = of_find_node_by_path("/myleds");
    if (NULL == node)
    {
        printk("寻找设备树节点失败\n");
        res = -EFAULT;
        goto ERR5;
    }

    //申请GPIO号
    topled1 = gpiod_get_from_of_node(node, "topled1", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(topled1))
    {
        printk("topled1 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled1));
        res = PTR_ERR(topled1);
        goto ERR5;
    }

    topled2 = gpiod_get_from_of_node(node, "topled2", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(topled2))
    {
        printk("topled2 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled2));
        res = PTR_ERR(topled2);
        goto ERR5;
    }

    topled3 = gpiod_get_from_of_node(node, "topled3", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(topled3))
    {
        printk("topled3 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled3));
        res = PTR_ERR(topled3);
        goto ERR5;
    }

    baseled1 = gpiod_get_from_of_node(node, "baseled1", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(baseled1))
    {
        printk("baseled1 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(baseled1));
        res = PTR_ERR(baseled1);
        goto ERR5;
    }

    baseled2 = gpiod_get_from_of_node(node, "baseled2", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(baseled2))
    {
        printk("baseled2 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(baseled2));
        res = PTR_ERR(baseled2);
        goto ERR5;
    }

    baseled3 = gpiod_get_from_of_node(node, "baseled3", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(topled3))
    {
        printk("baseled3 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(baseled3));
        res = PTR_ERR(baseled3);
        goto ERR5;
    }

    //设置相对应的gpio引脚为输出模式
    gpiod_direction_output(topled1, 0);
    gpiod_direction_output(topled2, 0);
    gpiod_direction_output(topled3, 0);
    gpiod_direction_output(baseled1, 0);
    gpiod_direction_output(baseled2, 0);
    gpiod_direction_output(baseled3, 0);
    return 0;
ERR5:
    for (--i; i >= 0; i--)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(devt, count);
ERR2:
    kfree(cdev);
ERR1:
    return res;
}

static void __exit led_exit(void)
{
    int i;
    gpiod_set_value(topled1, 0);
    gpiod_set_value(topled2, 0);
    gpiod_set_value(topled3, 0);
    gpiod_set_value(baseled1, 0);
    gpiod_set_value(baseled2, 0);
    gpiod_set_value(baseled3, 0);

    gpiod_put(topled1);
    gpiod_put(topled2);
    gpiod_put(topled3);
    gpiod_put(baseled1);
    gpiod_put(baseled2);
    gpiod_put(baseled3);

    for (i = 0; i < count; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

    cdev_del(cdev);

    unregister_chrdev_region(MKDEV(major, minor), count);

    kfree(cdev);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "linux_6led.h"

int main(int argc, const char *argv[])
{
    int fd1 = open("/dev/myled0", O_RDWR);
    if (-1 == fd1)
    {
        perror("open");
        return -1;
    }

    int fd2 = open("/dev/myled1", O_RDWR);
    if (-1 == fd2)
    {
        perror("open");
        return -1;
    }

    int fd3 = open("/dev/myled2", O_RDWR);
    if (-1 == fd3)
    {
        perror("open");
        return -1;
    }

    int fd4 = open("/dev/myled3", O_RDWR);
    if (-1 == fd4)
    {
        perror("open");
        return -1;
    }

    int fd5 = open("/dev/myled4", O_RDWR);
    if (-1 == fd5)
    {
        perror("open");
        return -1;
    }

    int fd6 = open("/dev/myled5", O_RDWR);
    if (-1 == fd6)
    {
        perror("open");
        return -1;
    }

    while (1)
    {
        ioctl(fd1, TOPLED1_ON);
        sleep(1);
        ioctl(fd1, TOPLED1_OFF);
        sleep(1);
        ioctl(fd2, TOPLED2_ON);
        sleep(1);
        ioctl(fd2, TOPLED2_OFF);
        sleep(1);
        ioctl(fd3, TOPLED3_ON);
        sleep(1);
        ioctl(fd3, TOPLED3_OFF);
        sleep(1);
        ioctl(fd4, BASELED1_ON);
        sleep(1);
        ioctl(fd4, BASELED1_OFF);
        sleep(1);
        ioctl(fd5, BASELED2_ON);
        sleep(1);
        ioctl(fd5, BASELED2_OFF);
        sleep(1);
        ioctl(fd6, BASELED3_ON);
        sleep(1);
        ioctl(fd6, BASELED3_OFF);
    }

    return 0;
}
#ifndef __LINUX_6LED_H__
#define __LINUX_6LED_H__

#define TOPLED1_ON _IOW('a', 1, int)
#define TOPLED1_OFF _IOW('a', 0, int)
#define TOPLED2_ON _IOW('b', 1, int)
#define TOPLED2_OFF _IOW('b', 0, int)
#define TOPLED3_ON _IOW('c', 1, int)
#define TOPLED3_OFF _IOW('c', 0, int)
#define BASELED1_ON _IOW('d', 1, int)
#define BASELED1_OFF _IOW('d', 0, int)
#define BASELED2_ON _IOW('e', 1, int)
#define BASELED2_OFF _IOW('e', 0, int)
#define BASELED3_ON _IOW('f', 1, int)
#define BASELED3_OFF _IOW('f', 0, int)

#endif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值