简单的驱动移植2.0

要求

        使用三个线程完成任务

        1、一个线程让三个LED实现跑马灯

        2、一个线程让蜂鸣器周期蜂鸣

        3、一个线程根据输入的值控制风扇的开关

        4、使用ioctl进行驱动控制

        5、实现设备文件的自动创建

        6、使用设备树对设备的管理

简述

        本次是上次的升级版,上次在实现的过程中需要自己手动创建设备文件 ,在这次的实现中,我们可以使用class_create和class_destroy进行一类设备的创建,在使用device_create和device_destroy进行对应设备的设备文件创建

//所需头文件
#include<linux/device.h>

struct class *class_create(struct module *owner,const char *name)

    功能:向上提交设备类信息,创建一个struct class类型的结构体对象
    参数:
        owner:指向当前模块自身的指针,我们填写THIS_MODULE即可
        name:向上提交的设备类名
    返回值:成功返回申请到的结构体变量首地址,失败返回错误码指针

void class_destroy(struct class *cls)
    功能:设备类的销毁
    参数:
        cls:创建的class对象指针
    返回值:无

struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
    功能:向上提交设备信息
    参数:
        class:创建的class对象指针
        parent:父设备对象指针,填NULL即可
        devt:要创建的设备文件对应的设备号
        drvdata:当前设备对象的私有数据,填NULL
        fmt:要创建的设备文件的名字,名字里面可以包含格式控制符
        ...:当上一个参数中包含格式控制符的时候,这个参数需要填写格式控制符对应的目标值
    返回值:成功返回创建成功的struct device对象指针,失败返回错误码指针

void device_destroy(struct class *class, dev_t devt)
    功能:销毁设备信息
    参数:
        class:创建的class对象指针
        devt:向上提交设备信息时填写的设备号
    返回值:无

        使用设备树对设备的管理,这样我们就不用进行内存映射,这要的效率会大大提升,但是我们需要对系统内核的设备树文件进行编辑添加我们的设备,所以我们要回写设备树文件的语法,这里不展开,下面是要用到的设备树节点解析的API

//所需头文件
#include<linux/of.h>

struct device_node *of_find_node_by_name(struct device_node *from, const char *name)
    功能:根据设备树节点的名字来解析指定的设备树节点
    参数:
        from:当前要解析的设备树节点所在子树的根节点路径,不知道就填NULL,默认从根节点/进行解析
        name:要解析的设备树节点的名字(名字是@之前的名字  mynode)
    返回值:成功返回解析到的设备树节点指针,失败返回NULL

struct device_node *of_find_node_by_path(const char *path)
    功能:根据设备树节点的路径解析指定设备树节点
    参数:
        path:要解析的设备树节点的路径   /mynode@0X12345678
    返回值:成功返回解析到的设备树节点的指针,失败返回NULL

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compat);
    功能:根据设备树节点的compatible值对设备树节点信息进行解析
    参数:
        from:当前要解析的设备树节点所在子树的根节点路径,不知道就填NULL,默认从根节点/进行解析
        type:设备树节点填写的设备类型,默认填NULL
        compat:要解析的设备树节点的compatible值
    返回值:成功返回解析到的设备树节点的指针,失败返回NULL
    
__u32 __be32_to_cpup(const __be32 *p)
    功能:将大端字节序32位的数据转换成主机字节序
    参数:要转换的数据指针
    返回值:返回转换后的主机字节序的数据

其次,我们需要对芯片的GPIO接口进行调用解析和操作,下面是GPIO子系统的相关API

//所需的头文件
#include<linux/of.h>

struct device_node *of_find_node_by_path(const char *path)
    功能:获取设备树节点信息通过路径
    参数:
        path:节点路径("/mynode@0x12345678")
    返回值:成功返回目标节点的信息结构体地址,失败返回NULL

还可以通过设备树节点的名字或者设备树节点的compatible值解析相关的设备信息

//所需的头文件
#include<linux/of_gpio.h>

int of_get_named_gpio(struct device_node *np, const char *propname, int index)
    功能:根据gpio管脚设备树节点解析获取GPIO编号
    参数:
        np:节点结构体首地址
        proname:键名
        index:索引号
    返回值:成功返回GPIO编号,失败返回错误码

//所需的头文件
#include<linux/gpio.h>

int gpio_request(unsigned gpio, const char *label)
    作用:申请指定GPIO编号的使用权
    参数:gpio:目标GPIO编号
        label:一般填写NULL
    成功返回0,失败返回错误码

void gpio_free(unsigned gpio)
    作用:释放申请的GPIO编号
    参数:目标GPIO编号

int gpio_direction_output(unsigned gpio, int value)
    作用:设置GPIO为输出
    参数:
        gpio:GPIO编号
        value:1:高电平 0:低电平
    返回值:成功返回0,失败返回错误码

int gpio_direction_input(unsigned gpio)
    作用:设置GPIO为输入
    参数:
        gpio:GPIO编号
    返回值:成功返回0,失败返回错误码

int gpio_get_value(unsigned int gpio)
    功能:获取GPIO电平状态
    参数:
        GPIO编号
    返回值:1:高电平 0:低电平

void gpio_set_value(unsigned int gpio, int value)
    作用:让GPIO输出高低电平
    参数:
        gpio:GPIO编号
        value:1:高电平 0:低电平
    返回值:无

设备树文件所需添加内容 

leds{
   led-gpio = <&gpioe 10 0>, <&gpiof 10 0>, <&gpioe 8 0>;
};
fans{
   fan-gpio = <&gpioe 9 0>;
};
buzzers{
   buzzer-gpio = <&gpiob 6 0>;
};

驱动文件

led.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)

unsigned int major;//全局保存主设备号
char kbuf[128] = {};
struct device_node *np;
int led_gpio[3];

// leds{
//     led-gpio = <&gpioe 10 0>, <&gpiof 10 0>, <&gpioe 8 0>;
//  };

struct device *dev;
struct class *cls;

int mydev_open(struct inode *inode, struct file* file){
    unsigned int minor;
    minor = MINOR(inode->i_rdev);
    file->private_data = (void*)minor;

    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mydev_read(struct file* file, char __user *ubuf, size_t size, loff_t *lft){
    unsigned long ret = copy_to_user(ubuf, kbuf, size);
    if(ret)
    {
        printk("copy_to_user filad\n");
        return -ret;
    }
    return 0;
}
ssize_t mydev_write(struct file* file, const char __user *ubuf, size_t size, loff_t *lft){
    unsigned long ret = copy_from_user(kbuf, ubuf, size);
    if(ret)
    {
        printk("copy_from_user filad\n");
        return -ret;
    }
    return 0;
}
int mydev_close(struct inode *inode, struct file* file){
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long mydev_iocrl(struct file *file, unsigned int cmd, unsigned long arg){
    switch (cmd)
    {
    case LED_ON:
        switch ((unsigned int)file->private_data) 
        {
        case 0:
            gpio_set_value(led_gpio[0], 1);
            break;
        case 1:
            gpio_set_value(led_gpio[1], 1);
            break;
        case 2:
            gpio_set_value(led_gpio[2], 1);
            break;
        default:
            break;
        }
        break;
    case LED_OFF:
        switch ((unsigned int)file->private_data)
        {
        case 0:
            gpio_set_value(led_gpio[0], 0);
            break;
        case 1:
            gpio_set_value(led_gpio[1], 0);
            break;
        case 2:
            gpio_set_value(led_gpio[2], 0);
            break;
        
        default:
            break;
        }
        break;
    
    default:
        break;
    }
    return 0;
}

struct file_operations fops={
    .open = mydev_open,
    .read = mydev_read,
    .write = mydev_write,
    .unlocked_ioctl = mydev_iocrl,
    .release = mydev_close,
};

int all_led_init(void){
    int i;
    np = of_find_node_by_name(NULL, "leds");
    if (np == NULL)
    {
        printk("leds not found\n");
        return -1;
    }
    printk("find leds\n");
    
    for (i = 0; i < 3; i++)
    {
        led_gpio[i] = of_get_named_gpio(np, "led-gpio", i);
        if (led_gpio[i] < 0)
        {
            printk("get gpio failed\n");
            return -1;
        }
        printk("gpio[%d] = %d\n", i, led_gpio[i]);
        if(gpio_request(led_gpio[i], NULL) < 0){
            printk("gpio_request failed\n");
            return -1;
        }
        gpio_direction_output(led_gpio[i], 0);
    }
    return 0;
}

int all_dev_create(void){
    int i;

    cls = class_create(THIS_MODULE, "myled");
    if(IS_ERR(cls)){
        printk("class_create filed\n");
        return PTR_ERR(cls);
    }

    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
        if(IS_ERR(dev)){
            printk("device_create filed\n");
            class_destroy(cls);
            return PTR_ERR(dev);
        }
        printk("device_create myled%d success\n", i);
    }
    
    return 0;
}
int all_dev_destroy(void){
    int i;
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);
    return 0;
}

static int __init mydev_init(void){
    major = register_chrdev(0, "myled", &fops);
    if(major < 0){
        printk("register_myled faile\n");
    }else{
        printk("register_myled success, major = %d\n", major);
    }

    if(all_dev_create()){
        return 0;
    }
    if(all_led_init()){
        return 0;
    }
    
    return 0;
}

static void __exit mydev_exit(void){
    int i;
    for (i = 0; i < 3; i++)
    {
        gpio_free(led_gpio[i]);
    }
    printk("free led_gpio success\n");

    unregister_chrdev(major, "myled");
    all_dev_destroy();
}

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");

fan.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#define FAN_ON _IO('f', 1)
#define FAN_OFF _IO('f', 0)

unsigned int major; // 全局保存主设备号
char kbuf[128] = {};

struct device_node *np;
int fan_gpio;

// fans{
//     fan_gpio = <&gpioe 9 0>;
//  };

struct device *dev;
struct class *cls;

int myled_open(struct inode *inode, struct file *file)
{
    unsigned int minor;
    minor = MINOR(inode->i_rdev);
    file->private_data = (void *)minor;

    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t myled_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft)
{
    // printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    unsigned long ret = copy_to_user(ubuf, kbuf, size);
    if (ret)
    {
        printk("copy_to_user filad\n");
        return -ret;
    }
    return 0;
}
ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft)
{
    // printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    unsigned long ret = copy_from_user(kbuf, ubuf, size);
    if (ret)
    {
        printk("copy_from_user filad\n");
        return -ret;
    }
    return 0;
}
int myled_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long mydev_iocrl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd)
    {
    case FAN_ON:
        gpio_set_value(fan_gpio, 1);
        break;
    case FAN_OFF:
        gpio_set_value(fan_gpio, 0);
        break;

    default:
        break;
    }
    return 0;
}

struct file_operations fops = {
    .open = myled_open,
    .read = myled_read,
    .write = myled_write,
    .unlocked_ioctl = mydev_iocrl,
    .release = myled_close,
};

int all_fan_init(void)
{
    np = of_find_node_by_name(NULL, "fans");
    if (np == NULL)
    {
        printk("fans not found\n");
        return -1;
    }
    printk("find fans\n");


    fan_gpio = of_get_named_gpio(np, "fan-gpio", 0);
    if (fan_gpio < 0)
    {
        printk("get gpio failed\n");
        return -1;
    }
    printk("fan_gpio = %d\n", fan_gpio);
    if (gpio_request(fan_gpio, NULL) < 0)
    {
        printk("gpio_request failed\n");
        return -1;
    }
    gpio_direction_output(fan_gpio, 0);

    return 0;
}

int all_dev_create(void)
{
    cls = class_create(THIS_MODULE, "myfan");
    if (IS_ERR(cls))
    {
        printk("class_create filed\n");
        return PTR_ERR(cls);
    }
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "myfan");
    if (IS_ERR(dev))
    {
        printk("device_create filed\n");
        class_destroy(cls);
        return PTR_ERR(dev);
    }
    printk("device_create myfan success\n");

    return 0;
}
int all_dev_destroy(void)
{
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    return 0;
}

static int __init mydev_init(void)
{
    major = register_chrdev(0, "myfan", &fops);
    if (major < 0)
    {
        printk("register_myfan faile\n");
    }
    else
    {
        printk("register_myfan success, major = %d\n", major);
    }

    if (all_dev_create())
    {
        return 0;
    }
    if (all_fan_init())
    {
        return 0;
    }

    return 0;
}

static void __exit mydev_exit(void)
{
    gpio_free(fan_gpio);
    printk("free fan_gpio success\n");
    
    unregister_chrdev(major, "myfan");
    all_dev_destroy();
}

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");

buzzer.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#define BUZZER_ON _IO('b', 1)
#define BUZZER_OFF _IO('b', 0)

unsigned int major;//全局保存主设备号
char kbuf[128] = {};

// buzzers{
//     buzzer-gpio = <&gpiob 6 0>;
// };
 
struct device_node *np;
int buzzer_gpio;

struct device *dev;
struct class *cls;

int myled_open(struct inode *inode, struct file* file){
    unsigned int minor;
    minor = MINOR(inode->i_rdev);
    file->private_data = (void *)minor;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t myled_read(struct file* file, char __user *ubuf, size_t size, loff_t *lft){
    //printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    unsigned long ret = copy_to_user(ubuf, kbuf, size);
    if(ret)
    {
        printk("copy_to_user filad\n");
        return -ret;
    }
    return 0;
}
ssize_t myled_write(struct file* file, const char __user *ubuf, size_t size, loff_t *lft){
    //printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    unsigned long ret = copy_from_user(kbuf, ubuf, size);
    if(ret)
    {
        printk("copy_from_user filad\n");
        return -ret;
    }
    return 0;
}
int myled_close(struct inode *inode, struct file* file){
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long mydev_iocrl(struct file *file, unsigned int cmd, unsigned long arg){
    switch (cmd)
    {
    case BUZZER_ON:
        gpio_set_value(buzzer_gpio, 1);
        break;
    case BUZZER_OFF:
        gpio_set_value(buzzer_gpio, 0);
        break;
    default:
        break;
    }
    return 0;
}

struct file_operations fops={
    .open = myled_open,
    .read = myled_read,
    .write = myled_write,
    .unlocked_ioctl = mydev_iocrl,
    .release = myled_close,
};

int all_buzzer_init(void){
    np = of_find_node_by_name(NULL, "buzzers");
    if (np == NULL)
    {
        printk("buzzers not found\n");
        return -1;
    }
    printk("find buzzers\n");


    buzzer_gpio = of_get_named_gpio(np, "buzzer-gpio", 0);
    if (buzzer_gpio < 0)
    {
        printk("get gpio failed\n");
        return -1;
    }
    printk("fan_gpio = %d\n", buzzer_gpio);
    if (gpio_request(buzzer_gpio, NULL) < 0)
    {
        printk("gpio_request failed\n");
        return -1;
    }
    gpio_direction_output(buzzer_gpio, 0);
    return 0;
}
int all_dev_create(void)
{
    cls = class_create(THIS_MODULE, "mybuzzer");
    if (IS_ERR(cls))
    {
        printk("class_create filed\n");
        return PTR_ERR(cls);
    }
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mybuzzer");
    if (IS_ERR(dev))
    {
        printk("device_create filed\n");
        class_destroy(cls);
        return PTR_ERR(dev);
    }
    printk("device_create mybuzzer success\n");

    return 0;
}

int all_dev_destroy(void)
{
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    return 0;
}

static int __init mydev_init(void){
    major = register_chrdev(0, "mybuzzer", &fops);
    if(major < 0){
        printk("register_mybuzzer faile\n");
    }else{
        printk("register_mybuzzer success, major = %d\n", major);
    }

    if(all_buzzer_init()){
        return 0;
    }
    if(all_dev_create()){
        return 0;
    }


    return 0;
}

static void __exit mydev_exit(void){
    gpio_free(buzzer_gpio);
    printk("free buzzer_gpio success\n");
    
    unregister_chrdev(major, "mybuzzer");
    all_dev_destroy();
}


module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");

程序文件

app.c

#include <stdio.h>      // 标准输入输出库
#include <stdlib.h>     // 标准库
#include <sys/types.h>  // 系统数据类型库
#include <sys/stat.h>   // 文件状态库
#include <fcntl.h>      // 文件控制库
#include <unistd.h>     // UNIX 标准库
#include <string.h>     // 字符串操作库
#include <pthread.h>    // 线程库
#include <sys/ioctl.h>  // IO 控制库

#define FAN_ON _IO('f', 1)
#define FAN_OFF _IO('f', 0)

#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)

#define BUZZER_ON _IO('b', 1)
#define BUZZER_OFF _IO('b', 0)

void* flowing_led_thread(void *arg){
    int *led_fd = (int*)arg;
    int count = 0;
    while (1)
    {   
        count %= 3;
        if(count == 0){
            ioctl(led_fd[0], LED_ON);
            ioctl(led_fd[1], LED_OFF);
            ioctl(led_fd[2], LED_OFF);
        }else if(count == 1){
            ioctl(led_fd[0], LED_OFF);
            ioctl(led_fd[1], LED_ON);
            ioctl(led_fd[2], LED_OFF);
        }else if(count ==2){
            ioctl(led_fd[0], LED_OFF);
            ioctl(led_fd[1], LED_OFF);
            ioctl(led_fd[2], LED_ON);
        }
        count++;
        sleep(1);
    }
    pthread_exit(NULL);
}
void* buzzer_thread(void *arg){
    int buzzer_fd = *((int*)arg);
    int count = 0;
    while (1)
    {
        count %= 2;
        if(count == 0){
            ioctl(buzzer_fd, BUZZER_ON);
        }else if(count == 1){
            ioctl(buzzer_fd, BUZZER_OFF);
        }
        count++;
        sleep(1);
    }
    pthread_exit(NULL);
}

void* fan_thread(void *arg){
    int fan_fd = *((int*)arg);
    char cmd_buf[32] = {0};
    while (1)
    {
        scanf("%s", cmd_buf);
        if(strcmp(cmd_buf, "FAN_ON") == 0){
            ioctl(fan_fd, FAN_ON);
        }else if(strcmp(cmd_buf, "FAN_OFF") == 0){
            ioctl(fan_fd, FAN_OFF);
        }
    }
    pthread_exit(NULL);
}

int main(int argc, char const *argv[])
{
    int led0_fd = open("/dev/myled0", O_RDWR);
    if(led0_fd < 0)
    {
        printf("filed in open myled0\n");
        return led0_fd;
    }
    
    int led1_fd = open("/dev/myled1", O_RDWR);
    if(led1_fd < 0)
    {
        printf("filed in open myled1\n");
        return led1_fd;
    }

    int led2_fd = open("/dev/myled2", O_RDWR);
    if(led2_fd < 0)
    {
        printf("filed in open myled2\n");
        return led2_fd;
    }

    int fan_fd = open("/dev/myfan", O_RDWR);
    if(fan_fd < 0)
    {
        printf("filed in open myfan\n");
        return fan_fd;
    }
    int buzzer_fd = open("/dev/mybuzzer", O_RDWR);
    if(buzzer_fd < 0)
    {
        printf("filed in open mybuzzer\n");
        return buzzer_fd;
    }

    int led_fd[3] = {led0_fd, led1_fd, led2_fd};
    pthread_t flowing_led_tid;
    pthread_t buzzer_tid;
    pthread_t fan_tid;
    int led_thread_creat_res = pthread_create(&flowing_led_tid, NULL, flowing_led_thread, (void*)led_fd);
    if(led_thread_creat_res != 0){
        printf("create led thread filed\n");
    }
    int buzzer_thread_creat_res = pthread_create(&buzzer_tid, NULL, buzzer_thread, (void*)&buzzer_fd);
    if(led_thread_creat_res != 0){
        printf("create led thread filed\n");
    }
    int fan_thread_creat_res = pthread_create(&fan_tid, NULL, fan_thread, (void*)&fan_fd);
    if(fan_thread_creat_res != 0){
        printf("create fan thread filed\n");
    }

    pthread_join(flowing_led_tid, NULL);
    pthread_join(buzzer_tid, NULL);
    pthread_join(fan_tid, NULL);

    close(led0_fd);
    close(led2_fd);
    close(led2_fd);
    close(fan_fd);
    close(buzzer_fd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值