在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. Your name ?

    序言 才发觉自己有许多名字 ··································································· 言归正传 今天才发现,自己在不同地方 ...

  2. webpack 之loader

      webpack的作用: 是 用来处理我们写的js代码.并且会自动处理js之间相关的依赖. 但是,开发中我们不仅仅有基本的js代码处理,还需要加载css,图片,也包括一些高级的 将ES6转成ES5代 ...

  3. KMP小扩展,找出子串在主串中出现的所有位置

    KMP算法能够高效地匹配字符串,找出子串(T串)在主串(S串)中出现的首个位置的原算法网上已经有很多优秀的博文进行详细讲解,这里就不多赘述. 这篇博文主要是对KMP原算法稍作改动,使其能够在主串中把所 ...

  4. Django | Unable to get repr for <class 'django.db.models.query.QuerySet'>

    问题:在mysql中查询数据时,代码如下: skus = category.sku_set.filter(is_launched=True).order_by(sort_field) skus 取不到 ...

  5. php设计模式之适配器模式实例代码

    <?php header("Content-type:text/html;charset=utf-8"); // 适配器模式 /** * 查看天气接口 */ class Ti ...

  6. 《深入理解Java虚拟机》读书笔记二

    第三章 垃圾收集器与内存分配策略 1.判断对象是否已死 引用计数法: 给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,每当引用失效时,计数器值就减1. 任何时刻计数器为0的对象就是不 ...

  7. VC++编译选项

    -优化- /O1 最小化空间 minimize space /Op[-] 改善浮点数一致性 improve floating-pt consistency /O2 最大化速度 maximize spe ...

  8. 快速排序 QuickSort (C++迭代,递归)

    /* * QuickSort.h * 快速排序(将每一个元素转换为轴点元素) * Created on: 2020年2月12日 * Author: LuYonglei */ #ifndef SRC_Q ...

  9. wamp修改MySQL密码

    wamp默认密码为空 用户名为root: 左击wamp绿色小图标,打开phpMyAdmin ->执行 ->账号 ->找到用户名为root的修改权限&&点击修改权限 - ...

  10. 题解【洛谷P2323】 [HNOI2006]公路修建问题

    题面 题解 跑两遍\(Kruskal\),第一次找出\(k\)条一级公路,第二次找出\(n - k - 1\)条二级公路,直接计算\(MST\)的权值之和即可. 代码 #include <ios ...