16_misc驱动

一、MISC驱动简介

​ MISC 驱动叫杂项驱动,当外设无法分类时,可以使用 MISC 驱动。
​ 所有的 MISC 驱动的主设备号都是 10,不同的设备使用不同的次设备号。MISC设备会自动创建 cdev。只需要注册 MISC 结构体就能完成驱动的设备号处理到自动创建设备节点。

1、miscdevice结构体

struct miscdevice { 
    int minor; /* 子设备号 */ 
    const char *name; /* 设备名字,在/dev目录下的设备名字 */ 
    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 这三个成员。

linux 系统预设了一些 MISC 设备的次设备号,定义在 include/linux/miscdevice.h文件

2、misc_register函数

​ 设置好 miscdevice 结构体以后就要使用 misc_register 函数来注册 MISC 设备,函数原型如下:

int misc_register(struct miscdevice * misc)

misc:要注册的 miscdevice 结构体。

返回值:负值,失败;0,成功。

3、misc_deregister函数

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

int misc_deregister(struct miscdevice *misc)

misc:要注销的 miscdevice 结构体。

返回值:负值,失败;0,成功。

二、MISC驱动实验

1、添加设备树节点

dtsbeep {
		compatible = "beep_test";
		status = "okay";
		pinctrl-names = "default";
		pinctrl-0 = <&beep>;
		gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
	};

beep: beepgrp {
			fsl,pins = <
				MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01   0x10b0
			>;
		};

2、添加设备结构体

/* 设备结构体 */
typedef struct {
	int beep_gpio;	//gpio编号
	struct device_node *nd;	//设备树节点
}beep_dev;
beep_dev beep;

3、编写加载和卸载注册函数

/* 模块注册函数 */
module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LZK");

入口函数:

/* 入口函数 */
static int __init beep_init(void)
{
	int ret = 0;
	ret = platform_driver_register(&platform_beep);
	return 0;
}

出口函数:

/* 出口函数 */
static void __exit beep_exit(void)
{
	platform_driver_unregister(&platform_beep);
}

4、编写操作函数

/* open函数 */
static int beep_open(struct inode *inode, struct file *filp)
{
	return 0;
}

/* write函数 */
static ssize_t beep_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	int ret = 0;
	int beep_state = BEEP_OFF;

	ret = copy_from_user(&beep_state, buf, count);
	if(beep_state == BEEP_ON)
		beep_switch(BEEP_ON);
	if(beep_state == BEEP_OFF)
		beep_switch(BEEP_OFF);

	return 0;
}

/* 操作函数集合 */
static const struct file_operations beep_fops = {
	.owner = THIS_MODULE,
	.open  = beep_open,
	.write = beep_write,
};

5、添加头文件

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/of_irq.h> 
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>

#define DEVICE_NAME "beep"
#define BEEP_ON 1
#define BEEP_OFF 0

6、编写BEEP切换函数

/* beep状态切换函数 */
void beep_switch(int state)
{
	if(state == BEEP_ON)
		gpio_set_value(beep.beep_gpio, 0);
	if(state == BEEP_OFF)
		gpio_set_value(beep.beep_gpio, 1);
}

7、添加MISC驱动结构体

/* misc结构体 */
static struct miscdevice misc_beep = {
	.name = DEVICE_NAME,
	.minor = 144,
	.fops = &beep_fops,
};

8、编写probe函数

/* probe函数 */
static int beep_probe(struct platform_device *dev)
{
	int ret = 0;
	printk("device and driver match\r\n");

	/* 注册misc驱动 */
	ret = misc_register(&misc_beep);

	/* 查找设备树节点 */
	beep.nd = of_find_node_by_name(NULL, "dtsbeep");

	/* 读取gpio编号 */
	beep.beep_gpio = of_get_named_gpio(beep.nd, "gpios", 0);

	/* 注册gpio */
	ret = gpio_request(beep.beep_gpio, "beep_gpio");

	/* 设置gpio输出 */
	ret = gpio_direction_output(beep.beep_gpio, 1);
	beep_switch(BEEP_OFF);

	return 0;
}

9、编写remove函数

/* remove函数 */
static int beep_remove(struct platform_device *dev)
{
	int ret = 0;
	beep_switch(BEEP_OFF);
	gpio_free(beep.beep_gpio);
	/* 注销misc驱动 */
	ret = misc_deregister(&misc_beep);
	return 0;
}

10、编写匹配列表

/* 匹配列表 */
const struct of_device_id beep_match_table[] = {
	{ .compatible = "beep_test" },
	{ /* 保留 */ },
};

11、添加platform驱动结构体

/* platform驱动结构体 */
static struct platform_driver platform_beep = {
	.driver = {
		.name = "beep",
		.of_match_table = beep_match_table,
	},
	.probe = beep_probe,
	.remove = beep_remove,
};

12、编写测试应用

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "linux/ioctl.h"
#include "poll.h"
#include "sys/select.h"
#include "signal.h"
#include "fcntl.h"

static int fd = 0;

int main(int argc, char *argv[])
{
    int flags = 0;
    char *filename;
    int beep_state = 0;

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

    filename = argv[1];
    fd = open(filename, O_RDWR);   //阻塞方式打开驱动
    if(fd < 0){
        printf("open file %s failed\r\n", filename);
        return -1;
    }

    if(atoi(argv[2]) == 1){
        beep_state = 1;
        write(fd, &beep_state, sizeof(beep_state));
    }else{
        beep_state = 0;
        write(fd, &beep_state, sizeof(beep_state));
    }

    close(fd);

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值