ZYNQ学习笔记-MISC设备驱动开发

MISC杂项设备,是Linux中用于归类ADC、蜂鸣器等不好分类的设备。其特点为共用一个主设备号10,不同设备使用不同设备号,同时会自动创建cdev和创建节点,大大简化字符设备的编写。

MISC设备简介

MISC设备由一个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;
};

这里我们需要关注minor,name,fops变量。minor为从设备号,需要用户自己指定,在miscdevice.h中定义了一些预定的设备号,但是一般我们只需要关注一个值:

#define MISC_DYNAMIC_MINOR 255

将minor设置为这个值,系统将会将动态分配设备号。

name就是模块名字,注册设备后将会在dev/下生成该名字的文件。

MISC与传统字符驱动的不同

普通字符设备进行注册需要进行以下步骤:

alloc_chrdev_region(); /* 申请设备号 */
cdev_init(); /* 初始化 cdev */
cdev_add(); /* 添加 cdev */
class_create(); /* 创建类 */
device_create(); /* 创建设备 */

在MISC设备中,直接调用一个函数即可:

int misc_register(struct miscdevice * misc)

同样的,对于注销,字符设备需要执行以下步骤:

cdev_del(); /* 删除 cdev */
unregister_chrdev_region(); /* 注销设备号 */
device_destroy(); /* 删除设备 */
class_destroy(); /* 删除类 */

在MISC中,只需要一个函数:

int misc_deregister(struct miscdevice *misc)

可见MISC设备大大简化了字符设备的创建过程,同时还节约了设备号,不用手动创建节点。

一个例子

以PIR红外传感器驱动为例:

#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/time.h>
#include <asm/uaccess.h>

/* 驱动名称 */
#define DEVICE_NAME "ccd_pir"
/* gpio 寄存器虚拟地址 */
static void __iomem *gpio_add_minor_pir;
//static void __iomem *gpio_add_minor_led;

/* gpio 寄存器物理基地址 */
#define GPIO_BASE_PIR 0x41210000
//#define GPIO_BASE_LED 0x41200000

unsigned int GPIO_TRI_Offset = 0x4;
unsigned int GPIO_DATA_Offset = 0x0;

static volatile long pir[1] = {0};
void PIR(void);
int label_pir, state_pir;

/*打开函数,当打开驱动设备节点时,执行此函数,相当于初始化设备文件*/

static int pir_open(struct inode *inode,struct file *filp)
{
	gpio_add_minor_pir = (unsigned int)ioremap(GPIO_BASE_PIR, 32);
	//gpio_add_minor_led = (unsigned int)ioremap(GPIO_BASE_LED, 32);	
	return 0;
}

/* write 函数实现, 对应到 Linux 系统调用函数的 write 函数 */
static ssize_t pir_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)
{
	return 0;
}

/* release 函数实现, 对应到 Linux 系统调用函数的 close 函数 */
static int pir_release(struct inode *inode_p, struct file *file_p)
{
	iounmap((unsigned int *)gpio_add_minor_pir);
	//iounmap((unsigned int *)gpio_add_minor_led);
	return 0;
}

/* 控 制 函 数 , 相 当 于 给 ult 发 送 控 制 命 令*/
static int pir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
/*
	if(arg == 0)
	{
		int state = 0;
		if(ioread32(gpio_add_minor_pir))
		{
			mdelay(2);
			if(ioread32(gpio_add_minor_pir))
				state =1;
		}
		if(state)
		{
			iowrite32(4, gpio_add_minor_led);
			mdelay(1000);
			iowrite32(0, gpio_add_minor_led);
		}
	}	
	else 
		iowrite32(2, gpio_add_minor_led);
*/
	return 0;
}

/* 读函数*/
static int pir_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
	pir[0] = 0;
	PIR();
	pir[0] = state_pir;

	printk(KERN_DEBUG"state_pir: %d\n", state_pir);

	unsigned long err;
	err = copy_to_user(buff, (const void *)pir, min(sizeof(pir), count));
	return err ? -EFAULT : min(sizeof(pir), count);
}

/*struct file_operations 结构体 , 指 向 对 应 的 驱 动 操 作 函 数*/
struct file_operations pir_fops=
{
 .owner = THIS_MODULE,
 .open = pir_open,
 .unlocked_ioctl = pir_ioctl,
 .read = pir_read,
 .write = pir_write,
 .release = pir_release,
};
/*注册模块*/
static struct miscdevice misc = 
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &pir_fops,
};

/*led 驱 动 加 载函数*/
static int __init pir_init(void)
{
int ret;
ret = misc_register(&misc);//注册设备, 混合设备驱动类,此时不需要手动分配主从设备号
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
/*led 驱 动 卸 载 函 数*/
static void __exit pir_exit(void)
{
misc_deregister(&misc);//卸载设备
}

void PIR(void)
{
	//label_pir = 0;
	state_pir = 0;
	if(ioread32(gpio_add_minor_pir))
	{
		mdelay(2);
		if(ioread32(gpio_add_minor_pir))
			state_pir = 1;		
	}
}

module_init(pir_init);
module_exit(pir_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ccd");

posted @ 2026-08-22 12:34  LO_StacNet  阅读(1)  评论(0)    收藏  举报