首页 > 其他分享 >MISC杂项驱动实验

MISC杂项驱动实验

时间:2023-02-07 00:55:04浏览次数:42  
标签:return struct MISC beep miscbeep 驱动 杂项 设备

一、简介

  MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 platform 总线驱动中,实现复杂的驱动。当我们板子上的某

些外设无法进行分类的时候就可以使用 MISC 驱动。   所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号,MISC 设备驱动就用于解决此问题。MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写。   对于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;
};

在miscdevice结构体的众多成员变量中,我们定义一个 MISC 设备(miscdevice 类型)只需要关注minornamefops 这三个成员
变量。

  minor 表示子设备号,MISC 设备的主设备号为 10,这个是固定的,需要用户指定子设备号,Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号定义在include/linux/miscdevice.h 文件中。我们在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口。

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

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

二、实验内容

  以蜂鸣器为例,最终实现蜂鸣器驱动的安装并使得蜂鸣器鸣叫。 a.实验步骤 (1)修改设备树文件(linux/arch/arm/boot/dts/imx6ull-alientek-emmc.dts)
/*测试节点 beep*/
beep{
	#address-cells = <1>;
	#size-cells =<1>;
	compatible = "alientek-beep";
	pinctrl-names ="default";
	pinctrl-0 =  <&pinctrl_beep>;
	beep-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
	status = "okay";
};

(2)编写驱动入口、出口函数,注册platform驱动 

static int __init miscbeep_init(void)
{
  return platform_driver_register(&miscbeep_driver);//向内核注册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("dongdong");

(3)我们需要查找到设备树里面的beep相关属性

  我们采用OF类型匹配来匹配驱动和设备。编写platform_driver 结构体,其中主要是设置of_match_table匹配表。

of_match_table保存着驱动的compatible匹配表。设备树中的每个设备节点的 compatible 属性会和 of_match_table 表中的所有成员比较,查看是否有相同的条目,如果有的话就表示设备和此驱动匹配,设备和驱动匹配成功以后 probe 函数

就会执行。每个of_match_table 匹配表都为of_device_id结构体类型,为结构体数组。
/*platform匹配表*/
static const struct of_device_id beep_of_match[]={
	{.compatible = "alientek-beep"},//主要是根据compatible属性查找

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

 (4)当驱动和设备匹配成功以后就会执行 probe 函数、当注销驱动模块的时候 remove 函数就会执行。接下来编写probe、remove函数。前面我们查找到了设备树里面的beep设备,现在我们要为beep设备创建节点,获取beep设备硬件IO,设置IO输出,至此我们成功利用platform驱动注册了名为miscbeep的设备驱动。此时我们可以安装和卸载miscbeep驱动了!MISC驱动注册很简单,只需要使用misc_register函数就可以了。

 

可以观察到主设备号为10。

 

/*MISC驱动 mcsidevice结构体变量 以及 file_operations操作结构体*/

struct file_operations miscbeep_fops ={
	.owner = THIS_MODULE,
	.open = miscbeep_open,
	.release = miscbeep_release,
	.read = miscbeep_read,
	.write =miscbeep_write,
};

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

 /*beep结点相关属性*/ 

struct miscbeep_dev{
struct device_node *nd;
int beep_gpio;

};

struct miscbeep_dev miscbeep;

/*probe函数*/ static int miscbeep_probe(struct platform_device *dev) { int ret=0; /*gpio*/ 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",miscbeep.beep_gpio); 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); gpio_free(miscbeep.beep_gpio); misc_deregister(&beep_miscdev); return 0; }

(5)接下来编写设备的具体操作函数。file_operations 结构体就是设备的具体操作函数。这是内核里面与用户对接的函数。比如write函数可以接收来自用户的数据。

/*
 * @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_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	struct miscbeep *dev = (struct miscbeep *)filp->private_data;

	int retvalue = 0;

	/* 向用户空间发送数据 */
	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)
{
	struct miscbeep *dev = (struct miscbeep *)filp->private_data;

	int retvalue = 0;
	unsigned char state;
	unsigned char databuf[1]; //存储beep开关的数据
	/* 接收用户空间传递给内核的数据并且打印出来 */
	retvalue = copy_from_user(databuf, buf, cnt);
	if (retvalue < 0)
	{
		return -EFAULT;
	}
	if(databuf[0]==BEEP_ON)
	{
		gpio_set_value(miscbeep.beep_gpio,0);
	}else if(databuf[0]==BEEP_OFF)
	{
		gpio_set_value(miscbeep.beep_gpio,1);
	}


	return 0;
}
/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int miscbeep_release(struct inode *inode, struct file *filp)
{
	struct miscbeep *dev = (struct miscbeep *)filp->private_data;
	return 0;
}

 (6)编写应用APP,安装驱动,运行APP,测试beep。

#include "stdio.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "stdlib.h"
#include "string.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: miscbeepAPP.c
作者	  	: study from 正点原子
版本	   	: V1.0
描述	   	: led驱测试APP。
其他	   	: 使用方法:./miscbeepAPP/dev/miscbeep   <0>|<1>

			 0:open

			 1:close
***************************************************************/
#define BEEP_OFF 1
#define BEEP_ON 0
/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd;
	char *filename;
	if(argc != 3) //检查传入参数个数是否正确
	{
		printf("useage error\r\n");
      	return -1;
	}
	int ret = 0;
	char readbuf[100];
	char writebuf[1];
	/*打开文件*/
	filename = argv[1];
	fd = open(filename, O_RDWR);
	if (fd < 0)
	{
		printf("can't open file %s\r\n", filename);
		return -1;
	}
	/*写文件*/
	writebuf[0] = atoi(argv[2]);//将字符转换成数字 
	ret = write(fd, writebuf, sizeof(writebuf)); /* 要执行的操作:打开或关闭 */
	if (ret < 0)
	{
		printf("can't write file %s\r\n", filename);
		return -1;
	}
	else
{ ret = close(fd); if (ret < 0) { printf("can't close file %s\r\n", filename); return -1; } } return 0; //表示返回成功 }

实验结果

 

 

 

 

 

 

标签:return,struct,MISC,beep,miscbeep,驱动,杂项,设备
From: https://www.cnblogs.com/DongdongAa/p/17096813.html

相关文章

  • 树莓派 - L298N模块 驱动直流电机
    单片机或树莓派一般使用L298n模块来驱动电机。L298N的实物图如下。注意的地方:1.5v电源可以不用2.同一侧写代码的时候必须是一高一低,如果是相同的话是走不了的,这里每......
  • 树莓派 - L298N模块 驱动直流电机
    单片机或树莓派一般使用L298n模块来驱动电机。L298N的实物图如下。[img]http://dl2.iteye.com/upload/attachment/0129/1777/c59d5e4a-32e0-3e73-......
  • 触摸屏驱动程序框架分析
    触摸屏驱动程序,用于人机交互lcd上的独立的一个屏,这里指的是电阻屏。下面来分析一下内核自带的触摸屏驱动框架,便于我们自已编写触摸屏驱动程序触摸屏驱动使用的是Input_sub......
  • 事件驱动及其设计模式
    在GUI编程中,事件是非常常见的。比如,用户在界面点击了按钮,就会发送一个“点击”事件,而相应的会有一个处理“点击”事件的事件处理器会来处理该事件。因此,所谓事件驱动,简单地......
  • 一文搞懂 USB 设备端驱动框架
    hello大家好,今天带领大家学习一下USB设备端驱动 内核版本:4.4.94https://www.cnblogs.com/sky-heaven/1.LinuxUSB子系统在介绍设备端驱动前,我们先来看看Linux......
  • Linux ALSA驱动之五:Linux ALSA驱动之Platform源码分析(基于Linux 5.18)
    1、Platform概述ASoC被分为Machine,Platform和Codec三大部件,Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DA〉把音频数据传送给Codec进行处理,最终......
  • stm32 PWM驱动步进电机
    项目:stm32PWM驱动步进电机代码:StepperMotor.c#include"stm32f10x.h"#include"PWM.h"//PA4(AIN1),PA5(AIN2)步进电机GPIO端口初始化voidStepperMotor_Init(vo......
  • 外设驱动库开发笔记51:SDP800差压传感器驱动
      检测流量数据的方法有很多种,这一次我们就是使用SDP800差压传感器来测量流量数据。所以在这一篇中,我们将讨论如何实现SDP800差压传感器的驱动,并使用它实现流量数据的检......
  • 第五届“强网”拟态防御国际精英挑战赛初赛——Web Misc
    之前团队参加了第五届“强网”拟态防御国际精英挑战赛初赛,又是收获满满的一次,和全国很多大佬们一块同台竞争,最重要的是,通过比赛我们学到了很多新的方法和技能,下面让我们一块......
  • Day1-arm汇编led灯控制驱动并从sd卡加载运行
    关键知识点:arm汇编/程序存储地址/运行地址/程序启动 arm汇编:因为Cortex-A芯片一上电SP指针还没初始化,C环境还没准备好,所以肯定不能运行C代码,必须先用汇编语言......