一: spidev_init注册spidev
   1:  static int __init spidev_init(void)
   2:  {
   3:      int status;
   4:   
   5:      /* Claim our 256 reserved device numbers.  Then register a class
   6:       * that will key udev/mdev to add/remove /dev nodes.  Last, register
   7:       * the driver which manages those device numbers.
   8:       */
   9:      BUILD_BUG_ON(N_SPI_MINORS > 256);
  10:      /* 注册spi字符设备 */
  11:      status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); 
  12:      if (status < 0) {
  13:          return status;
  14:      }
  15:      /* 为该设备创建一个class spidev */
  16:      spidev_class = class_create(THIS_MODULE, "spidev"); 
  17:      if (IS_ERR(spidev_class)) {
  18:          unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
  19:          return PTR_ERR(spidev_class);
  20:      }
  21:      /* register匹配到device ,最终调用prob函数 */
  22:      status = spi_register_driver(&spidev_spi_driver); 
  23:      if (status < 0) {
  24:          class_destroy(spidev_class);
  25:          unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
  26:      }
  27:      return status;
  28:  }
  29:  module_init(spidev_init);
  30:   
  31:  static void __exit spidev_exit(void)
  32:  {
  33:      spi_unregister_driver(&spidev_spi_driver);
  34:      class_destroy(spidev_class);
  35:      unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
  36:  }
  37:  module_exit(spidev_exit);
  38:   
  39:  MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
  40:  MODULE_DESCRIPTION("User mode SPI device interface");
  41:  MODULE_LICENSE("GPL");
  42:  MODULE_ALIAS("spi:spidev");

总结:

1)注册一个字符设备,cat /proc/device 会查看到“153 spi”主设备号位153的设备

2) 创建一个class spidev ,”/sys/class/spidev/”

3) spi_register_driver 注册spi driver。

二:spidev_probe 函数

   1:  static int __devinit spidev_probe(struct spi_device *spi)
   2:  {
   3:      struct spidev_data    *spidev;
   4:      int            status;
   5:      unsigned long        minor;
   6:      
   7:      /* Allocate driver data */
   8:      spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
   9:      if (!spidev)
  10:          return -ENOMEM;
  11:   
  12:      /* Initialize the driver data */
  13:      spidev->spi = spi;
  14:      spin_lock_init(&spidev->spi_lock);
  15:      mutex_init(&spidev->buf_lock);
  16:   
  17:      INIT_LIST_HEAD(&spidev->device_entry);
  18:   
  19:      /* If we can allocate a minor number, hook up this device.
  20:       * Reusing minors is fine so long as udev or mdev is working.
  21:       */
  22:      mutex_lock(&device_list_lock);
  23:   
  24:      minor = find_first_zero_bit(minors, N_SPI_MINORS);
  25:      if (minor < N_SPI_MINORS) {
  26:          struct device *dev;
  27:   
  28:          spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
  29:          dev = device_create(spidev_class, &spi->dev, spidev->devt,
  30:                      spidev, "spidev%d.%d",
  31:                      spi->master->bus_num, spi->chip_select);
  32:          status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
  33:      } else {
  34:          dev_dbg(&spi->dev, "no minor number available!\n");
  35:          status = -ENODEV;
  36:      }
  37:      if (status == 0) {
  38:          set_bit(minor, minors);
  39:          list_add(&spidev->device_entry, &device_list);
  40:      }
  41:      
  42:      mutex_unlock(&device_list_lock);
  43:   
  44:      if (status == 0)
  45:          spi_set_drvdata(spi, spidev);
  46:      else
  47:          kfree(spidev);
  48:   
  49:      return status;
  50:  }

总结: 1. spidev_prob函数很简单,调用device_create创界字符设备的结点名为"spidev%d.%d" 2. 将spidev作为spi->dev->p->driver_data 的data
 
三:spidev_probe 函数是如何被调用的,以及什么时候被调用的追踪 status = spi_register_driver(&spidev_spi_driver)调用
   1:  int spi_register_driver(struct spi_driver *sdrv)
   2:  {
   3:      sdrv->driver.bus = &spi_bus_type;
   4:      if (sdrv->probe)
   5:          sdrv->driver.probe = spi_drv_probe;
   6:      if (sdrv->remove)
   7:          sdrv->driver.remove = spi_drv_remove;
   8:      if (sdrv->shutdown)
   9:          sdrv->driver.shutdown = spi_drv_shutdown;
  10:      return driver_register(&sdrv->driver);
  11:  }

//sdrv->driver.probe = spi_drv_probe; 函数
   1:  static int spi_drv_probe(struct device *dev)
   2:  {
   3:      const struct spi_driver        *sdrv = to_spi_driver(dev->driver);
   4:   
   5:      return sdrv->probe(to_spi_device(dev));
   6:  }



可以看出调用spi_drv_prob就是调用sdrv->probe,即spidev_probe 函数

 

2)追踪driver_register(&sdrv->driver);

   1:  int driver_register(struct device_driver *drv)
   2:  {
   3:      int ret;
   4:      struct device_driver *other;
   5:   
   6:      BUG_ON(!drv->bus->p);
   7:   
   8:      if ((drv->bus->probe && drv->probe) ||
   9:          (drv->bus->remove && drv->remove) ||
  10:          (drv->bus->shutdown && drv->shutdown))
  11:          printk(KERN_WARNING "Driver '%s' needs updating - please use "
  12:              "bus_type methods\n", drv->name);
  13:   
  14:      other = driver_find(drv->name, drv->bus);
  15:      if (other) {
  16:          put_driver(other);
  17:          printk(KERN_ERR "Error: Driver '%s' is already registered, "
  18:              "aborting...\n", drv->name);
  19:          return -EBUSY;
  20:      }
  21:   
  22:      ret = bus_add_driver(drv);
  23:      if (ret)
  24:          return ret;
  25:      ret = driver_add_groups(drv, drv->groups);
  26:      if (ret)
  27:          bus_remove_driver(drv);
  28:      return ret;
  29:  }

查看bus_add_driver(drv)函数调用,有一段代码

1: if (drv->bus->p->drivers_autoprobe) {
2:       error = driver_attach(drv);
3:       if (error) 4: goto out_unregister;
5: }

 

再看一下driver_attach函数

   1:  int driver_attach(struct device_driver *drv)
   2:  {
   3:      return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
   4:  }


 
   1:  int bus_for_each_dev(struct bus_type *bus, struct device *start,
   2:               void *data, int (*fn)(struct device *, void *))
   3:  {
   4:      struct klist_iter i;
   5:      struct device *dev;
   6:      int error = 0;
   7:   
   8:      if (!bus)
   9:          return -EINVAL;
  10:   
  11:      klist_iter_init_node(&bus->p->klist_devices, &i,
  12:                   (start ? &start->p->knode_bus : NULL));
  13:      while ((dev = next_device(&i)) && !error)
  14:          error = fn(dev, data);
  15:      klist_iter_exit(&i);
  16:      return error;
  17:  }

从上面两段代码可以看出bus_for_each_dev会遍历总线上所有设备并设用__driver_attach。我们再看一下__driver_attach所做的工作:
1.driver_match_device(drv, dev);device与driver name时候strncmp
2.driver_probe_device(drv, dev); 函数调用prob
   1:  static int __driver_attach(struct device *dev, void *data)
   2:  {
   3:      struct device_driver *drv = data;
   4:   
   5:   
   6:      if (!driver_match_device(drv, dev))
   7:          return 0;
   8:   
   9:      if (dev->parent)    /* Needed for USB */
  10:          device_lock(dev->parent);
  11:      device_lock(dev);
  12:      if (!dev->driver)
  13:          driver_probe_device(drv, dev);
  14:      device_unlock(dev);
  15:      if (dev->parent)
  16:          device_unlock(dev->parent);
  17:   
  18:      return 0;
  19:  }

 

我们再继续查看一下driver_probe_device函数的调用:

   1:  int driver_probe_device(struct device_driver *drv, struct device *dev)
   2:  {
   3:      int ret = 0;
   4:   
   5:      if (!device_is_registered(dev))
   6:          return -ENODEV;
   7:   
   8:      pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
   9:           drv->bus->name, __func__, dev_name(dev), drv->name);
  10:   
  11:      pm_runtime_get_noresume(dev);
  12:      pm_runtime_barrier(dev);
  13:      

ret = really_probe(dev, drv);

  14:      pm_runtime_put_sync(dev);
  15:   
  16:      return ret;
  17:  }

 
总结 : 通过代码最终我们最终看到了spidev_prob函数是怎样被调用的
 
 




linux SPI驱动——spidev之driver(六)的更多相关文章

  1. linux SPI驱动——spidev之deive(五)

    1.定义board设备 1: struct spi_board_info { 2: /* the device name and module name are coupled, like platf ...

  2. linux驱动基础系列--linux spi驱动框架分析

    前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...

  3. Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)

    一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...

  4. linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-100005.html linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet x ...

  5. linux设备驱动归纳总结(六):2.分享中断号【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-90837.html xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  6. linux设备驱动归纳总结(六):1.中断的实现【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-90740.html linux设备驱动归纳总结(六):1.中断的实现 xxxxxxxxxxxxxxxx ...

  7. linux驱动基础系列--linux spi驱动框架分析(续)

    前言 这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容. spi设备树相关信息 如之前的文章里所述,控制器的device和s ...

  8. linux设备驱动归纳总结(六):1.中断的实现

    linux设备驱动归纳总结(六):1.中断的实现 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  9. 【Linux开发】linux设备驱动归纳总结(六):3.中断的上半部和下半部——工作队列

    linux设备驱动归纳总结(六):3.中断的上半部和下半部--工作队列 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

随机推荐

  1. 【HDOJ5975】Aninteresting game(BIT原理)

    题意:给定n个区间,第i个区间的范围是[i-lowbit(i)+1,i].一共有q组询问,询问有两种: 1 x y:询问sigma lowbit(i) (x<=i<=y) 2.x:询问有几 ...

  2. jquery bind event, use on. $(document).on("click","#a",function(){alert(1)}) [#document]

    $(document).on("click","#a",function(){alert(1)}) [#document] as a replacement o ...

  3. js 数组知识复习

    2.Array类型 2.1 创建数组 两种方式: 1.new Array(); //创建一个空数组 var arr1 = new Array(); //创建一个长度为10的空数组, var arr2 ...

  4. poj 2778 DNA Sequence 状态及状态转移 AC自动机 矩阵快速幂

    题目链接 题意 给定\(m\)个字符串,问长度为\(n\)的字符串中有多少个不包含那\(m\)个字符串. (字符集为\(A,T,C,G\),\(m\leq 10\),长度\(\leq 10\),\(n ...

  5. linux多线程学习笔记五--线程安全【转】

    转自:http://blog.csdn.net/kkxgx/article/details/7506085 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,线程安全基础 一个函数被称为线程安 ...

  6. python日期时间相关

    参考: http://www.coder4.com/archives/2239 http://www.cnblogs.com/lhj588/archive/2012/04/23/2466653.htm ...

  7. webview reload 错误 Error Domain=WebKitErrorDomain Code=102 "Frame load interrupted"

    在某个特定的场合先需要对WKWebView进行一次reload,但是直接回走到失败的代理方法中并报如下的错误 Error Domain=WebKitErrorDomain Code=102 " ...

  8. shell高级-----创建函数

    基本脚本函数 1.创建函数 有两种格式可以用来在bash shell脚本中创建函数.第一种采用关键字function.后跟分配给该代码的函数名. function name { commands } ...

  9. 在typescript中import第三方类库clipboard报错

    一.问题 在实际开发项目中就遇到了这样的问题,需要在Vue+Typescript项目中添加复制文本的功能,就找了clipboard插件,先是新建了一个新的项目用来实验看看是否好用,都写好了以后发给别人 ...

  10. [转] 使用SVN进行源码管理

    原文地址:gyzhao's, 使用SVN进行源码管理(下) 软件下载 1. Viusal SVN, Download(官网),安装该软件之前,请先安装TortoiseSVN,Download. 2. ...