Linux MISC 驱动实验-基于正点原子IMX6ULL开发板
misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 platform 总线驱动中,实现复杂的驱动,本实验我们就来学习一下 MISC 驱动的编写。
1 MISC 设备驱动简介
所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号,MISC 设备驱动就用于解决此问题。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;
};
定义一个 MISC 设备(miscdevice 类型)以后我们需要设置 minor、name 和 fops 这三个成员变量。minor 表示子设备号,MISC 设备的主设备号为 10,这个是固定的,需要用户指定子设备号,Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号定义在include/linux/miscdevice.h 文件中,如下所示:
#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
#define HPET_MINOR 228
#define FUSE_MINOR 229
#define KVM_MINOR 232
#define BTRFS_MINOR 234
#define AUTOFS_MINOR 235
#define MAPPER_CTRL_MINOR 236
#define LOOP_CTRL_MINOR 237
#define VHOST_NET_MINOR 238
#define UHID_MINOR 239
#define MISC_DYNAMIC_MINOR 255
我们在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口。
name 就是此 MISC 设备名字,当此设备注册成功以后就会在/dev 目录下生成一个名为 name的设备文件。fops 就是字符设备的操作集合,MISC 设备驱动最终是需要使用用户提供的 fops操作集合。
当设置好 miscdevice 以后就需要使用 misc_register 函数向系统中注册一个 MISC 设备,此函数原型如下:
int misc_register(struct miscdevice * misc)
函数参数和返回值含义如下:
misc:要注册的 MISC 设备。
返回值:负数,失败;0,成功。
以前我们需要自己调用一堆的函数去创建设备,比如在以前的字符设备驱动中我们会使用如下几个函数完成设备创建过程:
1 alloc_chrdev_region(); /* 申请设备号 */
2 cdev_init(); /* 初始化 cdev */
3 cdev_add(); /* 添加 cdev */
4 class_create(); /* 创建类 */
5 device_create(); /* 创建设备 */
现在我们可以直接使用 misc_register 一个函数来完成示例代码 中的这些步骤。当我们卸载设备驱动模块的时候需要调用 misc_deregister 函数来注销掉 MISC 设备,函数原型如下:
int misc_deregister(struct miscdevice *misc)
函数参数和返回值含义如下:
misc:要注销的 MISC 设备。
返回值:负数,失败;0,成功。
以前注销设备驱动的时候,我们需要调用一堆的函数去删除此前创建的 cdev、设备等等内容,如下所示:
1 cdev_del(); /* 删除 cdev */
2 unregister_chrdev_region(); /* 注销设备号 */
3 device_destroy(); /* 删除设备 */
4 class_destroy(); /* 删除类 */
现在我们只需要一个 misc_deregister 函数即可完成示例代码中的这些工作。关于MISC 设备驱动就讲解到这里,接下来我们就使用 platform 加 MISC 驱动框架来编写 beep 蜂鸣器驱动。
2 硬件原理图分析
3 实验程序编写
3.1 修改设备树
1、添加 pinctrl 节点
在设备树 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_beep”的子节点
pinctrl_beep: beepprp{fsl,pins = <MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10b0>;
2、添加 BEEP 设备节点
在设备树根节点“/”下创建 BEEP 节点,节点名为“beep”,节点内容如下:
beep{compatible = "alientek,beep";pinctrl-names = "default";pinctrl-0 = <&pinctrl_beep>;beep-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;status= "okay";
};
3.2 蜂鸣器驱动程序编写
新建工程,在 beep.c 驱动文件里面输入如下内容
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/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/gpio.h>
#include <linux/of_gpio.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/ide.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>#define MISCBEEP_NAME "miscbeep"
#define MISCBEEP_MINOR 144
#define BEEPOFF 0
#define BEEPON 1/* miscbeep设备结构体 */
struct miscbeep_dev
{struct device_node *nd; /* 设备节点 */int beep_gpio; /* beep gpio */
};struct miscbeep_dev miscbeep;static int miscbeep_open(struct inode *inode, struct file *filp)
{filp->private_data = &miscbeep;return 0;
}static int miscbeep_release(struct inode *inode, struct file *filp)
{return 0;
}static ssize_t miscbeep_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)
{int ret;unsigned char databuf[1];struct miscbeep_dev *dev = filp->private_data;ret = copy_from_user(databuf, buf, count);if (ret < 0){return -EINVAL;}if (databuf[0] == BEEPON){gpio_set_value(dev->beep_gpio, 0); /* 打开锋鸣器 */}else if (databuf[0] == BEEPOFF){gpio_set_value(dev->beep_gpio, 1); /* 关闭锋鸣器 */}return 0;
}/* 设备操作函数 */
struct file_operations miscbeep_fops = {.owner = THIS_MODULE,.open = miscbeep_open,.release = miscbeep_release,.write = miscbeep_write,
};/* miscdevice结构体 */
static struct miscdevice beep_miscdev = {.minor = MISCBEEP_MINOR,.name = MISCBEEP_NAME,.fops = &miscbeep_fops,
};/* probe函数 */
static int miscbeep_probe(struct platform_device *dev)
{int ret = 0;/* 1、初始化锋鸣器IO */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!\r\n", miscbeep.beep_gpio);ret = -EINVAL;goto fail_findgpio;}ret = gpio_direction_output(miscbeep.beep_gpio, 1); /* 输出,默认高电平 */if (ret < 0){goto fail_setoutput;}/* 2、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); /* 拉高,关闭BEEP */gpio_free(miscbeep.beep_gpio); /* 释放GPIO */misc_deregister(&beep_miscdev);return 0;
}/* platform匹配表 */
static const struct of_device_id beep_of_match[] = {{.compatible = "alientek,beep"},{/* Sentinel */},
};/* platform */
static struct platform_driver miscbeep_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(&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("supersmart");
测试程序beepApp.c程序如下所示
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>/**argc:应用程序参数个数*argv[]:具体的参数内容,字符串形式 *./beepAPP <filename> <0:1> 0表示关闭蜂鸣器,1表示打开蜂鸣器* ./beepAPP /dev/miscbeep 0 关蜂鸣器* ./beepAPP /dev/miscbeep 1 开蜂鸣器*/#define BEEPOFF 0
#define BEEPON 1int 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);if(fd < 0) {printf("file %s open failed!\r\n", filename);return -1;}databuf[0] = atoi(argv[2]); /* 将字符转换为数字 */retvalue = write(fd, databuf, sizeof(databuf));if(retvalue < 0) {printf("LED Control Failed!\r\n");close(fd);return -1;}close(fd);return 0;
}
4 运行测试
4.1编译驱动程序和测试 APP
略
4.2 运行测试
将上一小节编译出来 miscbeep.ko 和 miscbeepApp 这 两 个 文 件 拷 贝 到rootfs/lib/modules/4.1.15 目录中,重启开发板,进入到目录 lib/modules/4.1.15 中,加载 miscbeep.ko 这个驱动模块。
输入如下命令测试beep是否符合我们的预期
Linux MISC 驱动实验-基于正点原子IMX6ULL开发板相关推荐
- Linux platform 设备驱动实验-基于正点原子IMX6ULL开发板
我们以前的设备驱动都非常的简单,都是对IO进行最简单的读写操作.像I2C. SPI.LCD 这些复杂外设的驱动就不能这么去写了,Linux 系统要考虑到驱动的可重用性,因此提出了驱动的分离与分层这样的 ...
- Linux 设备树下的 platform 驱动实验基于正点原子IMX6ULL开发板
1 设备树下的 platform 驱动简介 platform 驱动框架分为总线.设备和驱动,其中总线不需要我们这些驱动程序员去管理,这个是 Linux 内核提供的,我们在编写驱动的时候只要关注于设备和 ...
- stm32f407 6路串口dma如何配置_stm32cubeMX学习十、扫码模块程序开发(基于正点原子STM32F407开发板)...
本程序编写基于正点原子STM32F407开发板. 本文使用的扫码模块是下面这个品牌. 扫码模块的应用场景非常广泛,我们可以上百度搜索一下: 等等. 今天就来说说如何在开发板上实现控制它吧,打开数据手册 ...
- 正点原子IMX6ULL开发板禁用出厂QT界面
正点原子IMX6ULL开发板出厂时自动开启QT的GUI界面,在测试时如果需要关闭GUI界面可以采用如下操作. 1.vi /etc/rc.local 2.将以下三行加#屏蔽,需要开启时,去除#即可 #/ ...
- 正点原子IMX6ULL开发板设置静态IP
正点原子IMX6ULL开发板出厂时每次都会自动获取IP,需要启动时使用固定的ip,可以采用下述方法设置静态ip. 1.vi /etc/rc.local 2.在下面位置添加以下内容,ip需要根据自己的路 ...
- 基于Qt的智能车载系统嵌入式项目(正点原子IMX6ULL开发板)
基于正点原子的IMX6ULL开发板的智能车载系统(Qt) 提示:该项目借鉴了不少大佬的代码,我没有自己造轮子(代码在文章末尾,同时附上参考链接 ) 本人其他项目链接基于linux的智能仓储项目 基于Q ...
- 正点原子imx6ull开发板视频监控项目实战系列5: 摄像头(V4L2)和声卡(ALSA)接口简介
1.摄像头: 1).对于不同的摄像头,有不同的接口方式,eg:USB,CMOS等,但是他们都遵循同样的标准-V4L2. 所以,不同的APP可以使用同样的API访问不同硬件接口的摄像头. 2).摄像头参 ...
- 基于正点原子F103精英板和CubeIDE的Hal库LCD驱动移植(从零开始)
最近在学习王维波老师的<STM32Cube高效开发教程>,王老师移植的是普中科技的驱动,而我手动移植了一下正点原子的lcd驱动,看了网上的诸多教程,有的博客存在一些bug,于是乎手动整理了 ...
- 基于Stm32f407 的贪吃蛇小游戏【正点原子-探索者开发板】
基于单片机stm32f407的单机小游戏----贪吃蛇小游戏 1.介绍 这是我花一个星期完成的一个简单地单机贪吃蛇小游戏项目,芯片是stm32f407,项目是基于正点原子-探索者开发板完成的,有需要的 ...
最新文章
- Python 之 matplotlib (九)contours等高线
- Windows下Python添加MySQLdb扩展模块
- python文件流习题解析
- hdu 2570 迷障(贪心)
- cannot create employee - HR check BP_BUPA_CHECK_HR_IS_ACTIVE
- LeetCode 468. 验证IP地址
- MATLAB imshow之后在四周加上边框
- 信息学奥赛一本通(1262:【例9.6】挖地雷)
- 常用CSS代码片段常见css bug
- MMO游戏数值框架概述(偏模拟方向)
- 概率论:假设检验、极大似然估计、无偏估计
- 本体论:Gene Ontology (基因本体)
- Exception in thread main java.lang.NoClassDefFoundError: org/w3c/dom/Eleme
- BUUCTF pwn rootersctf_2019_xsh
- Android 4.0 源代码结构
- Between Worlds 3 太阳与地球
- call()和appy()的区别及常用场景
- 七天学会NodeJS——第一天
- 一个手机游戏服务器的架构
- SQL语句 合并列值 将一列的多个值合并成一行