设备驱动基础学习--misc device简单实现
在Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述)。miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同。 所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。
miscdevice的API实现在drivers/char/misc.c中。
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也是作为一个模块被加载到内核的,只不过是静态模块。misc_init是misc静态模块加载时的初始化函数。
static const struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.llseek = noop_llseek,
};
static int __init misc_init(void)
{
int err;
struct proc_dir_entry *ret;
ret = proc_create("misc", 0, NULL, &misc_proc_fops);
misc_class = class_create(THIS_MODULE, "misc");//创建misc设备节点
err = PTR_ERR(misc_class);
if (IS_ERR(misc_class))
goto fail_remove;
err = -EIO;
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))//注册名字为misc的字符设备,主设备号为MISC_MAJOR(10)
goto fail_printk;
misc_class->devnode = misc_devnode;
return 0;
fail_printk:
printk("unable to get major %d for misc devices\n", MISC_MAJOR);
class_destroy(misc_class);
fail_remove:
if (ret)
remove_proc_entry("misc", NULL);
return err;
}
subsys_initcall(misc_init);//静态加载,开机时加载
注册miscdevice:
int misc_register(struct miscdevice * misc)
{
dev_t dev;
int err = 0;
bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);//是否是动态分配minor
INIT_LIST_HEAD(&misc->list);
mutex_lock(&misc_mtx);
if (is_dynamic) {
int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
if (i >= DYNAMIC_MINORS) {
err = -EBUSY;
goto out;
}
misc->minor = DYNAMIC_MINORS - i - 1;
set_bit(i, misc_minors);
} else {
struct miscdevice *c;
list_for_each_entry(c, &misc_list, list) {//如果misc_list中存在和当前设备相同的minor返回错误
if (c->minor == misc->minor) {
err = -EBUSY;
goto out;
}
}
}
dev = MKDEV(MISC_MAJOR, misc->minor);
misc->this_device =device_create_with_groups(misc_class, misc->parent, dev,misc, misc->groups, "%s", misc->name);
if (IS_ERR(misc->this_device)) {
if (is_dynamic) {
int i = DYNAMIC_MINORS - misc->minor - 1;
if (i < DYNAMIC_MINORS && i >= 0)
clear_bit(i, misc_minors);
misc->minor = MISC_DYNAMIC_MINOR;
}
err = PTR_ERR(misc->this_device);
goto out;
}
/*
* Add it to the front, so that later devices can "override"
* earlier defaults
*/
list_add(&misc->list, &misc_list);//将miscdevice加到misc_list中。
out:
mutex_unlock(&misc_mtx);
return err;
}
当我们在open miscdevice时, misc_open将被调用到。
static int misc_open(struct inode * inode, struct file * file)
{
int minor = iminor(inode);//从inode获取minor
struct miscdevice *c;
int err = -ENODEV;
const struct file_operations *new_fops = NULL;
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {//在misc_list中搜索minor,并获取fops
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
if (!new_fops) {
mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
if (!new_fops)
goto fail;
}
/*
* Place the miscdevice in the file's
* private_data so it can be used by the
* file operations, including f_op->open below
*/
file->private_data = c;
err = 0;
replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode,file);//调用实际miscdevice的open函数。
fail:
mutex_unlock(&misc_mtx);
return err;
}
miscdevice实现的简单sample
fellowmisc.h
#ifndef _FELLOW_MISC_H_
#define _FELLOW_MISC_H_
#include <linux/ioctl.h>
struct miscdata {
int val;
char *str;
unsigned int size;
};
#define FELLOW_MISC_IOC_MAGIC 'f'
#define FELLOW_MISC_IOC_PRINT _IO(FELLOW_MISC_IOC_MAGIC, 1)
#define FELLOW_MISC_IOC_GET _IOR(FELLOW_MISC_IOC_MAGIC, 2, struct miscdata)
#define FELLOW_MISC_IOC_SET _IOW(FELLOW_MISC_IOC_MAGIC, 3, struct miscdata)
#define FELLOW_MISC_IOC_MAXNR 3
#endif
fellowmisc.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "fellowmisc.h"
struct fellowmisc_dev{
struct miscdevice misc;
struct miscdata data;
};
struct fellowmisc_dev *fellowmisc_devp;
int fellowmisc_open(struct inode *inode, struct file *filep)
{
filep->private_data = fellowmisc_devp;
return 0;
}
int fellowmisc_release(struct inode *inode, struct file *filep)
{
return 0;
}
long fellowmisc_ioctl(struct file *filep,unsigned int cmd,unsigned long arg)
{
int ret = 0;
struct fellowmisc_dev *devp = (struct fellowmisc_dev *)(filep->private_data);
if (_IOC_TYPE(cmd) != FELLOW_MISC_IOC_MAGIC)
return -EINVAL;
if (_IOC_NR(cmd) > FELLOW_MISC_IOC_MAXNR)
return -EINVAL;
switch(cmd)
{
case FELLOW_MISC_IOC_PRINT:
printk("FELLOW_MISC_IOC_PRINT\n");
printk("val:%d, size: %d, str: %s\n", devp->data.val, devp->data.size, devp->data.str);
break;
case FELLOW_MISC_IOC_SET:
printk("FELLOW_MISC_IOC_SET\n");
ret = copy_from_user((unsigned char*)&(devp->data), (unsigned char *)arg, sizeof(struct miscdata));
printk("set val:%d, size: %d, str: %s\n", devp->data.val, devp->data.size, devp->data.str);
break;
case FELLOW_MISC_IOC_GET:
printk("FELLOW_MISC_IOC_GET\n");
ret = copy_to_user((unsigned char*)arg,(unsigned char*)&(devp->data), sizeof(struct miscdata));
break;
default:
return -EINVAL;
}
return ret;
}
static const struct file_operations fellowmisc_fops ={
.owner = THIS_MODULE,
.open = fellowmisc_open,
.release = fellowmisc_release,
.unlocked_ioctl = fellowmisc_ioctl,
};
static struct miscdevice fellow_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "fellowmisc",
.fops = &fellowmisc_fops,
};
static int fellowmisc_init(void)
{
int ret = 0;
printk("fellowmisc_init\n");
fellowmisc_devp = kmalloc(sizeof(struct fellowmisc_dev), GFP_KERNEL);
if (!fellowmisc_devp)
{
ret = -ENOMEM;
goto fail;
}
memset(&(fellowmisc_devp->data), 0, sizeof(fellowmisc_devp->data));
fellowmisc_devp->misc = fellow_misc;
return misc_register(&(fellowmisc_devp->misc));
fail:
return ret;
}
static void fellowmisc_exit(void)
{
misc_deregister(&(fellowmisc_devp->misc));
kfree(fellowmisc_devp);
}
MODULE_AUTHOR("fellow");
MODULE_LICENSE("GPL");
module_init(fellowmisc_init);
module_exit(fellowmisc_exit);
app.c
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "fellowmisc.h"
int main(void)
{
int fd = open("/dev/fellowmisc", O_RDWR);
if (fd < 0)
{
printf("open fail:%s\n", strerror(errno));
return -1;
}
int ret = 0;
struct miscdata data;
data.val = 18;
data.str = "fellowmisc";
data.size = sizeof("fellowmisc");
if ((ret = ioctl(fd, FELLOW_MISC_IOC_SET, &data)) < 0)
{
printf("ioctl set fail:%s\n", strerror(errno));
}
struct miscdata getdata;
if ((ret = ioctl(fd, FELLOW_MISC_IOC_GET, &getdata)) < 0)
{
printf("ioctl get fail:%s\n", strerror(errno));
}
printf("get val:%d, str:%s, size: %d\n", getdata.val, getdata.str, getdata.size);
if ((ret = ioctl(fd, FELLOW_MISC_IOC_PRINT, NULL)) < 0)
{
printf("ioctl print fail:%s\n", strerror(errno));
}
close(fd);
return ret;
}
设备驱动基础学习--misc device简单实现的更多相关文章
- 设备驱动基础学习--platform driver简单实现
platform是一条虚拟的总线.设备用platform_device表示,驱动用platform_driver进行注册,Linux platform driver机制和传统的device drive ...
- 设备驱动基础学习--poll
使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行,所以我们的问题就集中到了如何编 ...
- 设备驱动基础学习--/proc下增加节点
在需要创建一个由一系列数据顺序组合而成的/proc虚拟文件或一个较大的/proc虚拟文件时,推荐使用seq_file接口. 数据结构struct seq_fille定义在include/linux/s ...
- Hasen的linux设备驱动开发学习之旅--时钟
/** * Author:hasen * 參考 :<linux设备驱动开发具体解释> * 简单介绍:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:时钟 * Date ...
- 【驱动】Flash设备驱动基础·NOR·NAND
Flash存储器 ——>Flash存储器是近几年来发展最快的存储设备,通常也称作闪存.Flash属于EEPROM(电可擦除可编程只读存储器),是一类存取速度很高的存储器. ——>它既有RO ...
- Introduction the naive“scull” 《linux设备驱动》 学习笔记
Introduction the naive "scull" 首先.什么是scull? scull (Simple Character Utility for Loading Lo ...
- Java基础学习-- 继承 的简单总结
代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...
- 【jQuery基础学习】10 简单了解jQuery Mobile及jQuery各个级别版本的变化
关于 jQuery Mobile jQuery Mobile是为了填补jQuery在移动设备应用上的一个新项目.它应用了HTML5和CSS3. 主要特性 基于jQuery构建. 采用与jQuery一致 ...
- salesforce lightning零基础学习(一) lightning简单介绍以及org开启lightning
lightning对于开发salesforce人员来说并不陌生,即使没有做过lightning开发,这个名字肯定也是耳熟能详.原来的博客基本都是基于classic基于配置以及开发,后期博客会以ligh ...
随机推荐
- [CF859C] Pie Rules - dp,博弈论
有一个长度为n的序列,Alice和Bob在玩游戏.Bob先手掌握决策权. 他们从左向右扫整个序列,在任意时刻,拥有决策权的人有如下两个选择: 将当前的数加到自己的得分中,并将决策权给对方,对方将获得下 ...
- nodejs使用promise实现sleep
个人博客 地址:http://www.wenhaofan.com/article/20181120180225 let sleep = function (delay) { return new Pr ...
- Linux C++ 直接选择排序,冒泡排序,快速排序
选择排序的思想是:每次从待排序中选择最小(大)的元素插入已经排好的序列中. /*直接选择排序*/ #include <iostream> using namespace std; void ...
- BFS-八数码问题与状态图搜索
在一个3*3的棋盘上放置编号为1~8的八个方块,每个占一格,另外还有一个空格.与空格相邻的数字方块可以移动到空格里.任务1:指定的初始棋局和目标棋局,计算出最少的移动步数:任务2:数出数码的移动序列. ...
- jdk8-》stream⾥的map和filter函数使⽤
map函数 将流中的每⼀个元素 T(入参) 映射为 R(返回值)(类似类型转换) 类似遍历集合,对集合的每个对象做处理.场景:转换对象,如javaweb开发中集合⾥⾯的DO对象转换为DTO对象 ...
- pve apt-get update error 升级报错-文章未完工和验证
pve: apt-get update error 升级报错 提示如下报错 Hit: http://security.debian.org buster/updates InRelease Hit: ...
- U盘拷贝目标文件过大无法复制时的解决方法
在cmd下输入:convert U盘符:/fs:ntfs ---> 回车 转换完成后可以看到U盘属性为NTFS了 这时就可以复制大文件到U盘了
- 大数据-sparkSQL
SparkSQL采用Spark on Hive模式,hive只负责数据存储,Spark负责对sql命令解析执行. SparkSQL基于Dataset实现,Dataset是一个分布式数据容器,Datas ...
- python之路之线程,进程,协程2
一.线程 1.创建线程 2.主线程是否等待子线程 t.setDaemon(Ture/False):默认是false,等待子线程完成,ture,表示不等待子线程结束 3.主线程等待,子线程执行 join ...
- spring(三):BeanFactory