驱动:gpio子系统

通过GPIO子系统接口完成LED驱动的编写,编写应用程序控制灯亮灭(流水灯)

 驱动程序

#include 
#include 
#include 
#include 
#include 
#include "led.h"

unsigned int major;//主设备号
struct class *cls;//类指针
struct device *dev;//设备指针
struct device_node *np; // 设备树节点指针
// struct property *pp;//属性指针
int gpiono[3]; // gpio编号
char kbuf[128] = {};

/*************************************封装各种操作方法*******************************************/
int mycdev_open(struct inode *inode, struct file *file)
{
    unsigned int minor;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    minor = MINOR(inode->i_rdev);
    file->private_data = (void *)minor;
    return 0;
}

ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{
    unsigned long ret;
    if (size > sizeof(kbuf))
        size = sizeof(kbuf);
    ret = copy_to_user(ubuf, kbuf, size);
    if (ret)
    {
        printk("copy_to_user filad\n");
        return ret;
    }
    return 0;
}

ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
    unsigned long ret;
    if (size > sizeof(kbuf))
        size = sizeof(kbuf);
    ret = copy_from_user(kbuf, ubuf, size);
    if (ret)
    {
        printk("copy_from_user filad\n");
        return ret;
    }

    return 0;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd)
    {
    case LED_ON:
        switch ((unsigned int)file->private_data)
        {
        case 0: // LED1控制
            gpio_set_value(gpiono[0], 1);
            break;
        case 1: // LED2控制
            gpio_set_value(gpiono[1], 1);
            break;
        case 2: // LED3控制
            gpio_set_value(gpiono[2], 1);
            break;
        default:
            break;
        }
        break;
    case LED_OFF:
        switch ((unsigned int)file->private_data)
        {
        case 0: // LED1控制
            gpio_set_value(gpiono[0], 0);
            break;
        case 1: // LED2控制
            gpio_set_value(gpiono[1], 0);
            break;
        case 2: // LED3控制
            gpio_set_value(gpiono[2], 0);
            break;
        default:
            break;
        }
        break;
    default:
        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,
    .unlocked_ioctl = mycdev_ioctl,
    .release = mycdev_close,
};

int all_led_init(void)
{
    int i;
    for (i = 0; i < 3; i++)
    {
        gpiono[i] = of_get_named_gpio(np, "led-gpios", i); // 通过属性名字获取gpio编号
        if (gpiono[i] < 0)
        {
            printk("get gpio failed\n");
            return -1;
        }
        printk("get gpio success,gpio=%d\n", gpiono[i]);

        // 申请解析到的gpio编号
        if (gpio_request(gpiono[i], NULL) < 0)
        {
            printk("request gpio failed\n");
            return -1;
        }
        // 设置gpio为输出模式,默认输出低电平
        if (gpio_direction_output(gpiono[i], 0))
        {
            printk("set gpio output failed\n");
            return -1;
        }
        printk("set gpio output success\n");
    }
    return 0;
}

static int __init mycdev_init(void)
{
    // int i,len;
    // np = of_find_node_by_name(NULL,"mynode");
    /**********字符设备驱动注册**********/
    int i;
    major = register_chrdev(0, "led", &fops);
    if (major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功 major=%d\n", major);
    // 向上提交设备类
    cls = class_create(THIS_MODULE, "led");
    if (IS_ERR(cls))
    {
        printk("class_create falie\n");
        unregister_chrdev(major, "led");
        return PTR_ERR(cls);
    }
    printk("class_create success\n");
    // 向上提交设备信息
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "led%d", i);
        if (IS_ERR(dev))
        {
            printk("device_create filed\n");
            class_destroy(cls);
            unregister_chrdev(major, "led");
            return PTR_ERR(dev);
        }
        printk("device_create success\n");
    }
    // 通过路径查找设备树节点
    np = of_find_node_by_path("/leds"); 
    if (np == NULL)
    {
        printk("find node failed\n");
        return -1;
    }
    printk("find node success\n");
    all_led_init();

    return 0;
}

static void __exit mycdev_exit(void)
{
    int i;
    for (i = 0; i < 3; i++)
    {
        gpio_free(gpiono[i]); // 释放gpio
        device_destroy(cls, MKDEV(major, i));//注销设备
    }
    // 将设备类注销
    class_destroy(cls);
    /*注销设备驱动*/
    unregister_chrdev(major, "led");
    printk("unregister_chrdev success\n");
}

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

应用程序

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "led.h"

int stop_thread = 0; // 全局变量,用于控制线程停止
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *led_ctl(void *arg)
{
    int *fd = (int *)arg;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        if (stop_thread)
        {
            pthread_mutex_unlock(&mutex);
            break;
        }
        pthread_mutex_unlock(&mutex);
        ioctl(fd[0], LED_ON);
        ioctl(fd[1], LED_OFF);
        ioctl(fd[2], LED_OFF);
        sleep(1);
        ioctl(fd[0], LED_OFF);
        ioctl(fd[1], LED_ON);
        ioctl(fd[2], LED_OFF);
        sleep(1);
        ioctl(fd[0], LED_OFF);
        ioctl(fd[1], LED_OFF);
        ioctl(fd[2], LED_ON);
        sleep(1);
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    int a,i;
    int fd[3];
    pthread_t tid;
    fd[0] = open("/dev/led0", O_RDWR);
    if (fd[0] < 0)
    {
        perror("open");
        exit(1);
    }
    fd[1] = open("/dev/led1", O_RDWR);
    if (fd[1] < 0)
    {
        perror("open");
        exit(1);
    }
    fd[2] = open("/dev/led2", O_RDWR);
    if (fd[2] < 0)
    {
        perror("open");
        exit(1);
    }
    printf("open success\n");

    while (1)
    {
        printf("请输入控制操作:0(关闭) 1(打开)\n");
        printf("请输入:");
        scanf("%d", &a);
        switch (a)
        {
        case 0:
        {
            pthread_mutex_lock(&mutex);
            stop_thread = 1; // 设置全局变量,通知线程停止
            pthread_mutex_unlock(&mutex);
            
            pthread_join(tid, NULL);
            for(i=0;i<3;i++)
            {
                ioctl(fd[i], LED_OFF);
                printf("i=%d\n",i);
            }
        }
        break;
        case 1:
        {
            pthread_mutex_lock(&mutex);
            stop_thread = 0; // 重置全局变量
            pthread_mutex_unlock(&mutex);
            if (pthread_create(&tid, NULL, led_ctl, fd) != 0)
            {
                perror("pthread_create");
                exit(1);
            }
        }
        break;
        default:
            break;
        }
    }

    for(i=0;i<3;i++)
    {
        close(fd[i]);
    }
    return 0;
}

你可能感兴趣的:(c++,驱动开发,嵌入式硬件)