zoukankan      html  css  js  c++  java
  • 设备驱动基础学习--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 ", 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 ");
          printk("val:%d, size: %d, str: %s ", devp->data.val, devp->data.size, devp->data.str);
        break;
        case FELLOW_MISC_IOC_SET:
          printk("FELLOW_MISC_IOC_SET ");
          ret = copy_from_user((unsigned char*)&(devp->data), (unsigned char *)arg, sizeof(struct miscdata));
          printk("set val:%d, size: %d, str: %s ", devp->data.val, devp->data.size, devp->data.str);
        break;
        case FELLOW_MISC_IOC_GET:
          printk("FELLOW_MISC_IOC_GET ");
          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 ");
      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 ", 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 ", strerror(errno));
      }
      struct miscdata getdata;
      if ((ret = ioctl(fd, FELLOW_MISC_IOC_GET, &getdata)) < 0)
      {
        printf("ioctl get fail:%s ", strerror(errno));
      }
      printf("get val:%d, str:%s, size: %d ", getdata.val, getdata.str, getdata.size);
      if ((ret = ioctl(fd, FELLOW_MISC_IOC_PRINT, NULL)) < 0)
      {
        printf("ioctl print fail:%s ", strerror(errno));
      }
      close(fd);
      return ret;
    }

  • 相关阅读:
    [译]ABP vNext微服务演示,项目状态和路线图
    [译]初试C# 8.0
    [译]ABP vNext介绍
    ViewModel从未如此清爽
    python 函数基础及装饰器
    python 基础一
    scrapy基础二
    scrapy 基础
    python 基础技巧
    pandas 基础
  • 原文地址:https://www.cnblogs.com/fellow1988/p/6235080.html
Copyright © 2011-2022 走看看