Linux MISC 驱动实验

文章介绍了如何使用MISC驱动来控制蜂鸣器,通过注册miscdevice结构体,简化了字符设备的注册过程,包括打开设备、向设备写数据等操作。在平台设备驱动框架下,结合GPIO接口,实现了蜂鸣器的开启和关闭功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        当有些外设无法进行分类的时候就可以使用MISC驱动。MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 platform 总线驱动中来实现字符设备的驱动。

        本实验使用MISC驱动来实现蜂鸣器的输出功能,驱动程序使用的是MISC驱动。

        MISC驱动程序:

#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/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/mach/map.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_gpio.h>
#include <linux/timer.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>


#define MISCBEEP_NAME		"miscbeep"	/* 名字 	*/
#define MISCBEEP_MINOR		144			/* 子设备号 */
#define BEEPOFF 			0			/* 关蜂鸣器 */
#define BEEPON 				1			/* 开蜂鸣器 */


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;


/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int miscbeep_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &miscbeep; /* 设置私有数据 */
	return 0;
}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
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,
};


static struct miscdevice beep_miscdevices={
	.minor=MISCBEEP_MINOR,
	.name=MISCBEEP_NAME,
	.fops=&miscbeep_fops,
};


static int miscbeep_probe(struct platform_device *dev){
	int ret=0;
	/* 设置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, "cd-gpio", 0);
	if(miscbeep.beep_gpio < 0) {
		printk("can't get beep-gpio\r\n");
		return -EINVAL;
	}


	ret= gpio_request(miscbeep.beep_gpio,"cd-gpio");
	if(ret){
		ret=-EINVAL;
		return ret;
	}


	/* 3、设置GPIO5_IO01为输出,并且输出高电平,默认关闭BEEP */
	ret = gpio_direction_output(miscbeep.beep_gpio, 1);
	if(ret < 0) {
		printk("can't set gpio!\r\n");
		return ret;
	}

	/*注册misc*/
	ret=misc_register(&beep_miscdevices);
/*beep_miscdevices是miscdevice结构体类型的变量,在使用misc_register函数之前要进行初始化*/
	if(ret<0){
		printk("misc_register failed\r\n");
		return ret;
	}

	return 0;

}

static int miscbeep_remove(struct platform_device *dev){
	gpio_free(miscbeep.beep_gpio);
	misc_deregister(&beep_miscdevices);
	return 0;

}

static const struct of_device_id beep_of_match[]={
	{.compatible="atkalpha-key"},
	{}
};		 

static struct platform_driver beep={

	.driver={
		.name="beep",
		.of_match_table=beep_of_match,
	},
	.probe=miscbeep_probe,
	.remove=miscbeep_remove,
};		 

static int __init miscbeep_init(void)
{

	return platform_driver_register(&beep);
}



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


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

程序说明:
1、使用MISC注册字符设备驱动,其本质依然是platform设备驱动。区别在于MISC驱动将字符设备的注册使用了ret=misc_register(&beep_miscdevices);进行代替。代替的函数:
  alloc_chrdev_region(); /* 申请设备号 */

cdev_init(); /* 初始化 cdev */

cdev_add(); /* 添加 cdev */

class_create(); /* 创建类 */

device_create(); /* 创建设备 */

beep_miscdevices这个变量是struct miscdevice结构体类型,使用之前要对其进行定义并初始化static struct miscdevice beep_miscdevices={
    .minor=MISCBEEP_MINOR,
    .name=MISCBEEP_NAME,
    .fops=&miscbeep_fops,
};

2、misc_deregister(&beep_miscdevices);注销MISC驱动。代替的函数:
 cdev_del(); /* 删除 cdev */

 unregister_chrdev_region(); /* 注销设备号 */

 device_destroy(); /* 删除设备 */

 class_destroy(); /* 删除类 */

3、MISC驱动其本质依然是platform设备驱动,只是在对设备进行进行注册与注销时,借用了misc_register()misc_deregister()函数。

        理解:MISC驱动其本质依然是platform设备驱动,在platform驱动框架里完成了操作以后,使用struct miscdevice结构体来完成字符设备在Linux内核里的注册。省略了之前申请设备号、初始化cdev、添加cdev、创建类、创建设备的步骤。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值