Linux MISC驱动(杂项驱动)

        所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。随着 Linux 字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号,MISC 设备驱动就用于解 决此问题。MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用 MISC 设 备驱动可以简化字符设备驱动的编写。我们需要向 Linux 注册一个 miscdevice 设备,miscdevice 是一个结构体,内容如下:

struct miscdevice {
 int minor; /* 子设备号 */
 const char *name; /* 设备名字 */ 
 const struct file_operations *fops; /* 设备操作集 */
 struct list_head list;
 struct device *parent;
 struct device *this_device;
 const struct attribute_group **groups;
 const char *nodename;
 umode_t mode;
 };

         定义一个 MISC 设备(miscdevice 类型)以后我们需要设置 minor、name 和 fops 这三个成员 变量。minor 表示子设备号,MISC 设备的主设备号为 10,这个是固定的,需要用户指定子设备 号,Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号如下所示:

 #define PSMOUSE_MINOR 1
 #define MS_BUSMOUSE_MINOR 2 /* unused */
 #define ATIXL_BUSMOUSE_MINOR 3 /* unused */
 /*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */
 #define ATARIMOUSE_MINOR 5 /* unused */
 #define SUN_MOUSE_MINOR 6 /* unused */
......
 #define MISC_DYNAMIC_MINOR 255

         我们在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口。

        name 就是此 MISC 设备名字,当此设备注册成功以后就会在/dev 目录下生成一个名为 name 的设备文件。

        fops 就是字符设备的操作集合,MISC 设备驱动最终是需要使用用户提供的 fops 操作集合。

        当设置好 miscdevice 以后就需要使用 misc_register 函数向系统中注册一个 MISC 设备,此函数原型如下:

int misc_register(struct miscdevice * misc)

misc:要注册的MISC设备

返回值:负数失败,0成功

        当我 们卸载设备驱动模块的时候需要调用 misc_deregister 函数来注销掉 MISC 设备,函数原型如下:

int misc_deregister(struct miscdevice *misc)

misc:要注销的MISC设备

返回值:负数失败,0成功

以蜂鸣器驱动为例,驱动代码如下:

// #include <linux/types.h>
// #include <linux/kernel.h>
// #include <linux/delay.h>
// #include <linux/ide.h>
// #include <linux/init.h>
// #include <linux/module.h>
// #include <linux/errno.h>
// #include <linux/gpio.h>
// #include <linux/of_gpio.h>
// #include <linux/cdev.h>
// #include <linux/device.h>
// #include <linux/of.h>
// #include <linux/of_address.h>
// #include <asm/mach/map.h>
// #include <asm/uaccess.h>
// #include <asm/io.h>
// #include<linux/atomic.h>
// #include<linux/string.h>
// #include<linux/interrupt.h>
// #include<linux/fcntl.h>
// #include<linux/poll.h>
// #include<linux/ide.h>
// #include<linux/platform_device.h>
// #include <linux/major.h>

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define MISCBEEP_NAME "miscbeep"
#define MISCBEEP_MINOR 144
#define BEEP_OFF 0
#define BEEP_ON 1



/* miscbeep设备结构体 */
struct miscbeep_dev{
    struct device_node *nd;
    int beep_gpio;      //beep gpio
};

struct miscbeep_dev miscbeep;

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

static int miscbeep_release(struct inode *inode, struct file *filp)
{
	
	return 0;
}

static ssize_t miscbeep_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{

	int retvalue;
	unsigned char databuf[1];
	unsigned char beepstat;
	struct miscbeep_dev *dev = filp->private_data;

	retvalue = copy_from_user(databuf, buf, cnt);
	if(retvalue < 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;
}

/* 字符设备操作集 */
struct file_operations miscbeep_fops ={
    .owner = THIS_MODULE,
    .open = miscbeep_open,
    .write = miscbeep_write,
    .release = miscbeep_release,
};


/* miscdevice结构体 */
static struct miscdevice beep_miscdev = {
    .minor = MISCBEEP_MINOR,
    .name = MISCBEEP_NAME,
    .fops = &miscbeep_fops,
};



/* probe函数 */
static int miscbeep_probe(struct platform_device *dev)
{
    int ret = 0;
    /* 初始化峰鸣器IO */
    miscbeep.nd = dev->dev.of_node;
    miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd,"beep-gpios",0);
    if(miscbeep.beep_gpio < 0){
        ret = -EINVAL;
        goto fail_findgpio;
    }
    ret = gpio_request(miscbeep.beep_gpio,"beep-gpio");
    if(ret){
        printk("can't request %d gpio\r\n",miscbeep.beep_gpio);
        ret = -EINVAL;
        goto fail_findgpio;
    }

    ret = gpio_direction_output(miscbeep.beep_gpio,1);  //输出,默认高电平
    if(ret < 0){
        goto fail_setoutput;
    }

    /* misc注册驱动 */
    ret = misc_register(&beep_miscdev);
    if(ret < 0){
        goto fail_setoutput;
    }


    return 0;


fail_setoutput:
    gpio_free(miscbeep.beep_gpio);
fail_findgpio:
    return ret;


}

/* remove函数 */
static int miscbeep_remove(struct platform_device *dev)
{
    gpio_set_value(miscbeep.beep_gpio,1);   //拉高,关闭BEEP

    gpio_free(miscbeep.beep_gpio);
    misc_deregister(&beep_miscdev);
    return 0;
}


/* platform匹配表 */
static const struct of_device_id beep_of_match[] = {
    { .compatible = "alientek,beep" },
    {/* Sentinel */},
};

/* platform */
static struct platform_driver miscbeep_driver = {
    .driver = {
        .name = "imx6ul-beep",
        .of_match_table = beep_of_match,        //设备树匹配表
    },
    .probe = miscbeep_probe,
    .remove = miscbeep_remove,
};



/* 驱动入口函数 */
static int __init miscbeep_init(void)
{
    return platform_driver_register(&miscbeep_driver);
}

/* 驱动出口函数 */
static void __exit miscbeep_exit(void)
{
    platform_driver_unregister(&miscbeep_driver);
}

module_init(miscbeep_init);
module_exit(miscbeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wzh");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值