linux MISC设备驱动

系列文章

I.MX6ULL 手册查找使用方法 实战点亮LED(寄存器版)
I.MX6ULL 手册查找使用方法 实战点亮LED(固件库版本)
linux 字符设备驱动实战
linux LED设备驱动文件
linux 设备树(.dts)实战解析
linux 使用设备树点亮LED 实战
linux 驱动中并发与竞争
linux 内核定时器
linux 内核中断理解
linux 驱动阻塞和非阻塞
linux 内核异步通知
linux platform驱动框架
linux 内核自带的LED灯驱动

前言

misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 platform 总线驱动中,实现复杂的驱动。

MISC 设备驱动简介

所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写需要向 Linux 注册一个 miscdevice 设备,miscdevice是一个结构体,定义在文件 include/linux/miscdevice.h 中

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;
};

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

子设备号

#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 APOLLO_MOUSE_MINOR      7       /* unused */
#define PC110PAD_MINOR          9       /* unused */
/*#define ADB_MOUSE_MINOR       10      FIXME OBSOLETE */
#define WATCHDOG_MINOR          130     /* Watchdog timer     */
#define TEMP_MINOR              131     /* Temperature Sensor */
#define RTC_MINOR               135
#define EFI_RTC_MINOR           136     /* EFI Time services */
#define VHCI_MINOR              137
#define SUN_OPENPROM_MINOR      139
#define DMAPI_MINOR             140     /* unused */
#define NVRAM_MINOR             144
#define SGI_MMTIMER             153
#define STORE_QUEUE_MINOR       155     /* unused */
#define I2O_MINOR               166
#define MICROCODE_MINOR         184
#define VFIO_MINOR              196
#define TUN_MINOR               200
#define CUSE_MINOR              203
#define MWAVE_MINOR             219     /* ACP/Mwave Modem */
#define MPT_MINOR               220
#define MPT2SAS_MINOR           221
#define MPT3SAS_MINOR           222
#define UINPUT_MINOR            223
#define MISC_MCELOG_MINOR       227

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

注册MISC 设备

int misc_register(struct miscdevice * misc)

注销 MISC 设备

int misc_deregister(struct miscdevice *misc)

蜂鸣器驱动实验

1、设备树
添加 pinctrl 节点,imx6ull-alientek-emmc.dts 文件中,在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_beep”的子节点

pinctrl_beep: beepgrp {
	fsl,pins = <
	MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10B0 /* beep */ 
	>;
};

添加 BEEP 设备节点
在根节点“/”下创建 BEEP 节点,节点名为“beep”

beep {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "atkalpha-beep";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_beep>;
	beep-gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>;
	status = "okay";
};

2、驱动程序

#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"	/*dev目录下的名字 	*/
#define MISCBEEP_MINOR		144			/* 子设备号 */
#define BEEPOFF 			0			/* 关蜂鸣器 */
#define BEEPON 				1			/* 开蜂鸣器 */

/* miscbeep设备结构体 */
struct miscbeep_dev{
	dev_t devid;			/* 设备号 	 */
	struct cdev cdev;		/* cdev 	*/
	struct class *class;	/* 类 		*/
	struct device *device;	/* 设备 	 */
	struct device_node	*nd; /* 设备节点 */
	int beep_gpio;			/* beep所使用的GPIO编号		*/
};

struct miscbeep_dev miscbeep;		/* beep设备 */

static int miscbeep_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &miscbeep; /* 设置私有数据 */
	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 == BEEPON) {	
		gpio_set_value(dev->beep_gpio, 0);	/* 打开蜂鸣器 */
	} else if(beepstat == BEEPOFF) {
		gpio_set_value(dev->beep_gpio, 1);	/* 关闭蜂鸣器 */
	}
	return 0;
}

/* 设备操作函数 */
static struct file_operations miscbeep_fops = {
	.owner = THIS_MODULE,
	.open = miscbeep_open,
	.write = miscbeep_write,
};

/* MISC设备结构体 */
static struct miscdevice beep_miscdev = {
	.minor = MISCBEEP_MINOR,
	.name = MISCBEEP_NAME,
	.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 */
	/* 1、获取设备节点:beep */
	miscbeep.nd = of_find_node_by_path("/beep");
	if(miscbeep.nd == NULL) {
		printk("beep node not find!\r\n");
		return -EINVAL;
	} 

	/* 2、 获取设备树中的gpio属性,得到BEEP所使用的BEEP编号 */
	miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpio", 0);
	if(miscbeep.beep_gpio < 0) {
		printk("can't get beep-gpio");
		return -EINVAL;
	}

	/* 3、设置GPIO5_IO01为输出,并且输出高电平,默认关闭BEEP */
	ret = gpio_direction_output(miscbeep.beep_gpio, 1);
	if(ret < 0) {
		printk("can't set gpio!\r\n");
	}
	
	/* 一般情况下会注册对应的字符设备,但是这里我们使用MISC设备
  	 * 所以我们不需要自己注册字符设备驱动,只需要注册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)
{
	/* 注销设备的时候关闭LED灯 */
	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-beep" },
     { /* 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 miscbeep_init(void)
{
	return platform_driver_register(&beep_driver);
}

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

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

3、应用程序APP

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"

#define BEEPOFF	0
#define BEEPON 	1

int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	unsigned char databuf[1];
	
	if(argc != 3){
		printf("Error Usage!\r\n");
		return -1;
	}

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

	databuf[0] = atoi(argv[2]);	/* 要执行的操作:打开或关闭 */
	retvalue = write(fd, databuf, sizeof(databuf));
	if(retvalue < 0){
		printf("BEEP Control Failed!\r\n");
		close(fd);
		return -1;
	}

	retvalue = close(fd); /* 关闭文件 */
	if(retvalue < 0){
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	return 0;
}

加载驱动

modprobe miscbeep.ko

输入如下命令打开 BEEP:

./miscbeepApp /dev/miscbeep 1 //打开 BEEP

在输入如下命令关闭 LED 灯:

./miscbeepApp /dev/miscbeep 0 //关闭 BEEP
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Linux 中的 misc 是一种杂项设备类型,它可以用来创建一些没有特定驱动程序的设备文件,例如 /dev/null 和 /dev/random。 要创建一个 misc 设备,可以使用 misc_register() 函数,该函数需要一个 miscdevice 结构体作为参数,其中包含设备的名称、设备号等信息。然后,可以使用 misc_deregister() 函数来注销设备。 下面是一个简单的示例程序,用于创建一个名为 mymiscmisc 设备: ```c #include <linux/module.h> #include <linux/miscdevice.h> static int mymisc_open(struct inode *inode, struct file *file) { printk(KERN_INFO "mymisc: device opened\n"); return 0; } static int mymisc_release(struct inode *inode, struct file *file) { printk(KERN_INFO "mymisc: device closed\n"); return 0; } static const struct file_operations mymisc_fops = { .owner = THIS_MODULE, .open = mymisc_open, .release = mymisc_release, }; static struct miscdevice mymisc_device = { .minor = MISC_DYNAMIC_MINOR, .name = "mymisc", .fops = &mymisc_fops, }; static int __init mymisc_init(void) { int ret; ret = misc_register(&mymisc_device); if (ret) { printk(KERN_ERR "mymisc: unable to register device\n"); return ret; } printk(KERN_INFO "mymisc: device registered\n"); return 0; } static void __exit mymisc_exit(void) { misc_deregister(&mymisc_device); printk(KERN_INFO "mymisc: device unregistered\n"); } module_init(mymisc_init); module_exit(mymisc_exit); MODULE_LICENSE("GPL"); ``` 编译并安装模块后,可以使用以下命令来查看设备文件: ``` $ ls -l /dev/mymisc crw------- 1 root root 10, 58 May 22 15:08 /dev/mymisc ``` 可以使用 cat 命令来测试设备: ``` $ cat /dev/mymisc mymisc: device opened mymisc: device closed ``` 这里的输出是由 mymisc_open() 和 mymisc_release() 函数生成的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值