欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linux驱动开发 | misc驱动

程序员文章站 2022-06-09 08:42:33
...

一、基础知识

misc驱动是用来代替字符设备驱动的手动申请设备号、初始化cdev、添加、创建类、创建设备等等步骤的,只需要用misc_register函数就可以完成以上操作,卸载也是只需要misc_deregister函数即可完成一键卸载

想要使用misc驱动的话,要包含miscdevice.h,使用结构体struct miscdevice。
misc驱动的主设备号都是10

二、驱动程序

#include <linux/ide.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>

/********************************************************************
 * miscbeep.c
 * 作者:张亚胜
 * 版本:V1.0
 * 描述:采用MISX的beep驱动程序
 * 其他:无
 * 网站:www.s123.xyz
 * 日志:出版V1.0 2020/8/12 张亚胜创建
 * ******************************************************************/
#define MISCBEEP_NAME  "miscbeep"   /* 设备名字 */
#define MISCBEEP_MINOR  144          /* 子设备号 */
#define BEEP_OFF        0            /* 关 */
#define BEEP_ON         1            /* 开 */

/* miscbeep设备结构体 */
struct miscbeep_dev{
    dev_t dev_id;           /* 设备号 */
    struct cdev cdev;       /* 字符设备 */
    struct class *class;    /* mdev 自动节点文件使用 */
    struct device *device;  /* class使用 */
    struct device_node *nd; /* 设备节点 */
    int beep_gpio;          /* beep gpio 编号 */
};

struct miscbeep_dev miscbeep;   /* beep设备 */

static int beep_open(struct inode *inode,struct file *filp)
{
    filp->private_data = &miscbeep;    /* 设置私有数据 */
    return 0;
}


static ssize_t beep_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt)
{
    int retval = 0;
    unsigned char databuf[1];
    unsigned char beepstat;
    struct miscbeep_dev *dev = filp->private_data;

    retval = copy_from_user(databuf,buf,cnt);
    if(retval<0){
        printk("kernel write failed!\r\n");
        return -EFAULT;
    }
    beepstat = databuf[0];
    if(beepstat == BEEP_ON){
        gpio_set_value(dev->beep_gpio,0);
    }
    else if(beepstat == BEEP_OFF)
    {
        gpio_set_value(dev->beep_gpio,1);
    }
    
    return 0;
}


static struct file_operations miscbeep_fops = {
    .owner = THIS_MODULE,
    .open = beep_open,
    .write = beep_write,
};

static struct miscdevice beep_miscdev = {
    .minor = MISCBEEP_MINOR,//子设备号
    .name = MISCBEEP_NAME,//字符设备名称 会在/dev/生成文件
    .fops = &miscbeep_fops,
};

/* 当驱动和设备匹配成功后此函数就会执行 */
static int miscbeep_probe(struct platform_device *dev)
{
    int ret = 0;
    printk("beep driver and device was matched!\r\n");
    /* 设置beep所用的gpio */
    //获取设备节点
    miscbeep.nd = of_find_node_by_path("/gpiobeep");
    if(miscbeep.nd == NULL){
        printk("neep node not find!\r\n");
        return -EINVAL;
    }
    /* 获取设备树中的gpio属性 得到gpio编号 */
    miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd,"beep-gpio",0);
    if(miscbeep.beep_gpio < 0){
        printk("can't get beep-gpio!\r\n");
        return -EINVAL;
    }
    /* 设置引脚为输出 默认输出高电平 关闭beep */    
    ret = gpio_direction_output(miscbeep.beep_gpio,1);
    if(ret < 0){
        printk("can't set gpio!\r\n");
    }

    /* 使用misc注册字符设备 */
    ret = misc_register(&beep_miscdev);
    if(ret < 0){
        printk("misc device register failed!\r\n");
        return -EFAULT;
    }
    return 0;
}

static int miscbeep_remove(struct platform_device *dev)
{
    /* 注销设备的时候关闭beep */
    gpio_set_value(miscbeep.beep_gpio,1);

    /* 注销misc设备驱动 */
    misc_deregister(&beep_miscdev);

    return 0;
}

/* 匹配列表 */
static const struct of_device_id beep_of_match[] = {
    {.compatible = "atkalpha-gpiobeep"},
    { /* Sentinel */ },
};

/* platform驱动结构体 */
static struct platform_driver beep_driver = {
    .driver = {
        .name = "imx6ul-beep",  /* 驱动名称 不采用设备树的匹配方式*/
        .of_match_table = beep_of_match,    /* 设备树匹配表 */
    },
    .probe = miscbeep_probe,
    .remove = miscbeep_remove,
};

static int __init beep_init(void)
{
    return platform_driver_register(&beep_driver);
}

static void __exit beep_exit(void)
{
    platform_driver_unregister(&beep_driver);
}

module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zys");

三、测试程序

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
/********************************************************************
 * 文件名:miscbeepApp.c
 * 作者:张亚胜
 * 版本:V1.0
 * 描述:miscbeep测试文件
 * 其他:使用方法:./miscbeepApp /dev/miscbeep 0 //写0 关
 *                ./miscbeepApp /dev/miscbeep 1 //写1 开
 * 网站:www.s123.xyz
 * 日志:出版V1.0 2020/8/12 张亚胜创建
 * ******************************************************************/

/*
* @description : main 主程序
* @param - argc : argv 数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
    int fd,retval;
    char *filename;
    char buf[100];

    if(argc != 3){
        printf("params err!\r\n");
        return -1;
    }

    filename = argv[1];

    fd = open(filename,O_RDWR);
    if(fd<0){
        printf("file %s open failed!\r\n", argv[1]);
        return -1;
    }
    buf[0] = atoi(argv[2]);
    retval = write(fd,buf,1);
    if(retval < 0){
        printf("BEEP Control Failed!\r\n");
        close(fd);
        return -retval;
    }
    retval = close(fd);
    if(retval<0){
        printf("file %s close failed!\r\n", argv[1]);
        return -retval;
    }
    return 0;
}

四、测试

linux驱动开发 | misc驱动
linux驱动开发 | misc驱动
linux驱动开发 | misc驱动

相关标签: Linux驱动