在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简单实现的更多相关文章

  1. 设备驱动基础学习--platform driver简单实现

    platform是一条虚拟的总线.设备用platform_device表示,驱动用platform_driver进行注册,Linux platform driver机制和传统的device drive ...

  2. 设备驱动基础学习--poll

    使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行,所以我们的问题就集中到了如何编 ...

  3. 设备驱动基础学习--/proc下增加节点

    在需要创建一个由一系列数据顺序组合而成的/proc虚拟文件或一个较大的/proc虚拟文件时,推荐使用seq_file接口. 数据结构struct seq_fille定义在include/linux/s ...

  4. Hasen的linux设备驱动开发学习之旅--时钟

    /** * Author:hasen * 參考 :<linux设备驱动开发具体解释> * 简单介绍:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:时钟 * Date ...

  5. 【驱动】Flash设备驱动基础·NOR·NAND

    Flash存储器 ——>Flash存储器是近几年来发展最快的存储设备,通常也称作闪存.Flash属于EEPROM(电可擦除可编程只读存储器),是一类存取速度很高的存储器. ——>它既有RO ...

  6. Introduction the naive“scull” 《linux设备驱动》 学习笔记

    Introduction the naive "scull" 首先.什么是scull? scull (Simple Character Utility for Loading Lo ...

  7. Java基础学习-- 继承 的简单总结

    代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...

  8. 【jQuery基础学习】10 简单了解jQuery Mobile及jQuery各个级别版本的变化

    关于 jQuery Mobile jQuery Mobile是为了填补jQuery在移动设备应用上的一个新项目.它应用了HTML5和CSS3. 主要特性 基于jQuery构建. 采用与jQuery一致 ...

  9. salesforce lightning零基础学习(一) lightning简单介绍以及org开启lightning

    lightning对于开发salesforce人员来说并不陌生,即使没有做过lightning开发,这个名字肯定也是耳熟能详.原来的博客基本都是基于classic基于配置以及开发,后期博客会以ligh ...

随机推荐

  1. [CF859C] Pie Rules - dp,博弈论

    有一个长度为n的序列,Alice和Bob在玩游戏.Bob先手掌握决策权. 他们从左向右扫整个序列,在任意时刻,拥有决策权的人有如下两个选择: 将当前的数加到自己的得分中,并将决策权给对方,对方将获得下 ...

  2. nodejs使用promise实现sleep

    个人博客 地址:http://www.wenhaofan.com/article/20181120180225 let sleep = function (delay) { return new Pr ...

  3. Linux C++ 直接选择排序,冒泡排序,快速排序

    选择排序的思想是:每次从待排序中选择最小(大)的元素插入已经排好的序列中. /*直接选择排序*/ #include <iostream> using namespace std; void ...

  4. BFS-八数码问题与状态图搜索

    在一个3*3的棋盘上放置编号为1~8的八个方块,每个占一格,另外还有一个空格.与空格相邻的数字方块可以移动到空格里.任务1:指定的初始棋局和目标棋局,计算出最少的移动步数:任务2:数出数码的移动序列. ...

  5. jdk8-》stream⾥的map和filter函数使⽤

    map函数 将流中的每⼀个元素 T(入参) 映射为 R(返回值)(类似类型转换)    类似遍历集合,对集合的每个对象做处理.场景:转换对象,如javaweb开发中集合⾥⾯的DO对象转换为DTO对象 ...

  6. pve apt-get update error 升级报错-文章未完工和验证

    pve: apt-get update error 升级报错 提示如下报错 Hit: http://security.debian.org buster/updates InRelease Hit: ...

  7. U盘拷贝目标文件过大无法复制时的解决方法

    在cmd下输入:convert U盘符:/fs:ntfs    --->  回车 转换完成后可以看到U盘属性为NTFS了 这时就可以复制大文件到U盘了

  8. 大数据-sparkSQL

    SparkSQL采用Spark on Hive模式,hive只负责数据存储,Spark负责对sql命令解析执行. SparkSQL基于Dataset实现,Dataset是一个分布式数据容器,Datas ...

  9. python之路之线程,进程,协程2

    一.线程 1.创建线程 2.主线程是否等待子线程 t.setDaemon(Ture/False):默认是false,等待子线程完成,ture,表示不等待子线程结束 3.主线程等待,子线程执行 join ...

  10. spring(三):BeanFactory