在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. ASP.NET MVC 给Action的参数赋值的方式

    Action指的是Controller类中的方法,如上文中的Index. Action参数的三种常见类型:Model类型.普通参数.FormCollection Model类型 我们可以直接在地址栏后 ...

  2. Nginx实现前端访问后端本地接口

    Nginx配置两个地方就行: 先是配置好自己项目的服务,确保自己的项目能运行: location / { root /web/xiangmu/public; // 本地项目的路径 index inde ...

  3. WebService 之 SoapHeader

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  4. 还不错的Table样式和form表单样式

    作为一个后台开发人员而言,拥有一套属于自己的前台样式是比较重要的,这里分享一下自己感觉还不错的样式,以后遇到好的,还会陆续添加 上图: 带鼠标滑动效果的table样式看起来比较清爽 样式 <he ...

  5. centos下配置mongodb定期备份

    https://brickyang.github.io/2017/03/02/Linux-%E8%87%AA%E5%8A%A8%E5%A4%87%E4%BB%BD-MongoDB/ 1.创建备份脚本 ...

  6. FPGA设计的注意事项

    设计文档 一个完整的软件是由程序. 数据和文档三部分组成的. 在FPGA电路设计中, 撰写完善的设计文档是非常重要的. 对于一个比较复杂的设计来说, 各个子单元的功能各不相同, 实现的方法也不一样,各 ...

  7. Linux 查看是否安装 oracle

    查看是否用 oracle 的进程 ps -ef | grep ora 一般安装 oracle ,默认会有 oracle 的用户. id oracle

  8. 终极教程【zhong】

    just for a better future! 资源教程               aiim                   综合类 前端知识体系 前端知识结构 Web前端开发大系概览 We ...

  9. python hashlib 详解

    1.概述 摘要算法简介 Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定 ...

  10. Activiti+Shiro实战

    有人曾说:人的差距都在业余时间拉开的……嗯,我现在深刻理解着这句话,作为一个程序员,技术男,就得不断学习新的技术,跟上时代步伐,才会让自己更有价值~~~~以下这个项目是个人利用业余时间学习并实践的~如 ...