`
sit379vt
  • 浏览: 14404 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

Linux PowerPC I2C驱动之 I2C设备层的注册过程

 
阅读更多

Linux PowerPC I2C驱动之 I2C设备层的注册过程
2011年10月26日
  Linux下i2c驱动的加载过程,分为i2c设备层、i2c adapter层与i2c核心层
  i2c设备驱动层也就是我们为特定i2c设备编写的驱动,下面是我自己理解的i2c驱动的注册过程
  在我们写的i2c设备驱动中,我们会调用i2c_add_driver()开始i2c设备驱动的注册,该函数调用i2c_register_driver完成所有注册操作
  static inline int i2c_add_driver(struct i2c_driver *driver)
  {
  return i2c_register_driver(THIS_MODULE, driver);
  }
  i2c_register_driver会调用driver_register() 来将设备驱动添加到总线的设备驱动链表中:
  int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
  {
  int res;
  /* Can't register until after driver model init */
  if (unlikely(WARN_ON(!i2c_bus_type.p)))
  return -EAGAIN;
  driver->driver.owner = owner;
  driver->driver.bus = &i2c_bus_type;
  /* When registration returns, the driver core
  * will have called probe() for all matching-but-unbound devices.
  */
  res = driver_register(&driver->driver);
  if (res)
  return res;
  pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
  INIT_LIST_HEAD(&driver->clients);
  /* Walk the adapters that are already present */
  mutex_lock(&core_lock);
  bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
  mutex_unlock(&core_lock);
  return 0;
  }
  在driver_register中,通过driver_find来判断驱动是否已经注册,然后会调用
  bus_add_drive
  将设备驱动添加到总线上
  int driver_register(struct device_driver *drv)
  {
  int ret;
  struct device_driver *other;
  BUG_ON(!drv->bus->p);
  if ((drv->bus->probe && drv->probe) ||
  (drv->bus->remove && drv->remove) ||
  (drv->bus->shutdown && drv->shutdown))
  printk(KERN_WARNING "Driver '%s' needs updating - please use "
  "bus_type methods\n", drv->name);
  other = driver_find(drv->name, drv->bus);
  if (other) {
  put_driver(other);
  printk(KERN_ERR "Error: Driver '%s' is already registered, "
  "aborting...\n", drv->name);
  return -EBUSY;
  }
  ret = bus_add_driver(drv);
  if (ret)
  return ret;
  ret = driver_add_groups(drv, drv->groups);
  if (ret)
  bus_remove_driver(drv);
  return ret;
  }
  在bus_add_driver中初始化priv->klist_devices的值,并将priv赋值给drv->p
  通过调用klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers)将驱动信息保存到总线结构中,在此之前将调用driver_attach()
  int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus); if (!bus) return -EINVAL; pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL); priv->driver = drv; drv->p = priv; priv->kobj.kset = bus->p->drivers_kset; error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,      "%s", drv->name); if (error) goto out_unregister; if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); if (error) { printk(KERN_ERR "%s: uevent attr (%s) failed\n", __func__, drv->name); } error = driver_add_attrs(bus, drv); if (error) { /* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", __func__, drv->name); } if (!drv->suppress_bind_attrs) { error = add_bind_files(drv); if (error) { /* Ditto */ printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name); } } kobject_uevent(&priv->kobj, KOBJ_ADD); return 0; out_unregister: kfree(drv->p); drv->p = NULL; kobject_put(&priv->kobj); out_put_bus: bus_put(bus); return error; } 在driver_attach中,通过调用bus_for_each_dev,遍历在总线上挂载的所有设备,并对每个设备(dev)调用__driver_attach()
  int driver_attach(struct device_driver *drv)
  {
  return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
  }
  在__driver_attach里会调用driver_match_device()来判断dev与driv的id是否相同,在i2c驱动里就会调用i2c_bus_type->match程序进行判断,
  当id相同时,将会调用driver_probe_device()
  static int __driver_attach(struct device *dev, void *data)
  {
  struct device_driver *drv = data;
  /*
  * Lock device and try to bind to it. We drop the error
  * here and always return 0, because we need to keep trying
  * to bind to devices and some drivers will return an error
  * simply if it didn't support the device.
  *
  * driver_probe_device() will spit a warning if there
  * is an error.
  */
  if (!driver_match_device(drv, dev))
  return 0;
  if (dev->parent) /* Needed for USB */
  down(&dev->parent->sem);
  down(&dev->sem);
  if (!dev->driver)
  driver_probe_device(drv, dev);
  up(&dev->sem);
  if (dev->parent)
  up(&dev->parent->sem);
  return 0;
  }
  在driver_probe_device(),首先会调用device_is_registered()判断dev是否注册,若没注册则返回;若已经注册,则调用really_probe
  int driver_probe_device(struct device_driver *drv, struct device *dev)
  {
  int ret = 0;
  if (!device_is_registered(dev))
  return -ENODEV;
  pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
  drv->bus->name, __func__, dev_name(dev), drv->name);
  pm_runtime_get_noresume(dev);
  pm_runtime_barrier(dev);
  ret = really_probe(dev, drv);
  pm_runtime_put_sync(dev);
  return ret;
  }
  在really_probe()里,首先将drv赋值给dev->driver,然后会调用总线的probe函数,在i2c驱动里,
  此时将会调用i2c总线的probe函数:i2c_device_probe
  static int really_probe(struct device *dev, struct device_driver *drv)
  {
  int ret = 0;
  atomic_inc(&probe_count);
  pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
  drv->bus->name, __func__, drv->name, dev_name(dev));
  WARN_ON(!list_empty(&dev->devres_head));
  dev->driver = drv;
  if (driver_sysfs_add(dev)) {
  printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
  __func__, dev_name(dev));
  goto probe_failed;
  } if (dev->bus->probe) {//此处调用i2c总线的probe函数
  ret = dev->bus->probe(dev);
  if (ret)
  goto probe_failed;
  } else if (drv->probe) {
  ret = drv->probe(dev);
  if (ret)
  goto probe_failed;
  }
  driver_bound(dev);
  ret = 1;
  pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
  drv->bus->name, __func__, dev_name(dev), drv->name);
  goto done;
  probe_failed:
  devres_release_all(dev);
  driver_sysfs_remove(dev);
  dev->driver = NULL;
  if (ret != -ENODEV && ret != -ENXIO) {
  /* driver matched but the probe failed */
  printk(KERN_WARNING
  "%s: probe of %s failed with error %d\n",
  drv->name, dev_name(dev), ret);
  }
  /*
  * Ignore errors returned by ->probe so that the next driver can try
  * its luck.
  */
  ret = 0;
  done:
  atomic_dec(&probe_count);
  wake_up(&probe_waitqueue);
  return ret;
  }
  在i2c_device_probe()里,会根据to_i2c_driver(dev->driver)获取i2c驱动,也就是我们编写的具体的i2c设备驱动的结构体i2c_driver,即
  static struct i2c_driver XXX_driver = {
  .driver = {
  .name = "XXXX_name",
  .owner = THIS_MODULE,
  },
  .probe = XXX_probe,
  .remove = XXX_remove,
  .id_table = XXX_id,
  };
  这样就调用了我们驱动的probe()了,这就是我们在驱动里调用i2c_add_driver(),通过driver_register()的一系列调用,最后执行我们所写的probe()
  static int i2c_device_probe(struct device *dev)
  {
  struct i2c_client *client = i2c_verify_client(dev);
  struct i2c_driver *driver;
  int status;
  if (!client)
  return 0;
  driver = to_i2c_driver(dev->driver);
  if (!driver->probe || !driver->id_table)
  return -ENODEV;
  client->driver = driver;
  if (!device_can_wakeup(&client->dev))
  device_init_wakeup(&client->dev,
  client->flags & I2C_CLIENT_WAKE);
  dev_dbg(dev, "probe\n"); status = driver->probe(client, i2c_match_id(driver->id_table, client));//执行我们写的probe函数
  if (status)
  client->driver = NULL;
  return status;
  }
  本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-08/41104p3.htm
  本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-08/41104p2.htm
  本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-08/41104.htm
分享到:
评论

相关推荐

    pcf8563_i2c1_r8_ruoge_ov2640通过给RTC驱动增加设备节点读取秒钟成功+直接读取I2C1获取秒钟值20160626_2201.7z

    pcf8563_i2c1_r8_ruoge_ov2640通过给RTC驱动增加设备节点读取秒钟成功+直接读取I2C1获取秒钟值20160626_2201.7z http://blog.csdn.net/21cnbao/article/details/7919055 在Android源码树中添加userspace I2C读写...

    I2C总线协议 .docx

    本文描述I2C协议,包含I2C位传输, I2C开始和结束信号,I2C应答信号,I2C写流程,I2C读流程。进阶介绍PowerPC的I2C实现,I2CADR 地址寄存器及PPC-Linux中I2C的实现

    POWERPC实验教程(解密)-----各种MPC8349基础实验、综合实验详细教程

    包括U-boot在PowerPC 中的使用、Embeded Linux 编译与移植、网络设备驱动程序等6个实验。 附录……………………………… 附录I Freescale PowerPC处理器概述 附录II Micetek开发板介绍 附录III Jediview 安装与...

    MPC8245集成PowerPC处理器

    MPC8245集成PowerPC处理器适用于那些对成本、空间、功耗和性能都有很高要求的应用领域。该器件有较高的集成度,它集5个芯片... 业界标准I2C 接口,支持链接 带有多个定时器和计数器的可编程中断控制器 16550 DUART

    linxu设备驱动开发详解

    考虑到框架更强的兼容性,字符设备、块设备、TTY设备、I2C设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等驱动的体系结构都变得愈发复杂,框架成为Linux设备驱动学习上的绊脚石。 因此,读者极需这样一本书...

    PowerPC在车辆显控系统中的应用

    车辆显控系统的控制主板选用高性能PowerPC MPC8548E处理器,扩展了显示器、内存、Flash存储器和接口设备。以此主板为平台,实现了...本文重点阐述了在PowerPC上用软件实现I2C控制以及通过PCI总线实现设备间通信的方法。

    windows驱动开发技术详解-part2

     本章首先对Windows驱动程序的两个重要数据结构进行介绍,分别是驱动对象和设备对象数据结构。另 外还要介绍NT驱动程序和WDM驱动程序的入口函数、卸载例程、各种IRP派遣上函数等。  4.1 Windows驱动程序中重要的...

    power PC 8315E 原理图

    MCU & I2C DEVICES PLC MODULE CONNECTOR POWER SUPPLIES eTSEC PHYS 8315 DDR CONTROLLER & DDR2 8315 eTSEC & USB ULPI 8315 SATA & PCIe 8315 USB & USB HUB 8315 TDM & DUAL SLIC 8315 POWER 8315 LBIU & FLASH ...

    Windows驱动开发技术详解的光盘-part1

    本书共分23章,内容涵盖了Windows操作系统的基本原理、NT驱动程序与WDM驱动程序的构造、驱动程序中的同步异步处理方法、驱动程序中即插即用功能、驱动程序的各种调试技巧等。同时,还针对流行的PCI驱动程序、USB驱动...

    SN6505,TI6505,PC6505低噪声隔离驱动变压芯片

    FEATURES • Push-Pull Driver for Small ...• Isolated Interface Power Supply for CAN, RS-485, RS-422, RS-232, SPI, I2C, Low-Power LAN • Industrial Automation • Process Control • Medical Equi

    Thinkpad Z61T 驱动下载及安装方法 for windows XP

    3、设备管理中常见的未知设备一般为ACPI电源管理器和TPM安全芯片,如果出现未知设备,请首先尝试安装其驱动。 4、GHOST安装的系统有可能存在驱动无法安装的情况,建议不要使用GHOST安装系统。 5、使用GHOST安装...

    [Fedora.Linux.宝典.2010版.PDF].Fedora.Bible.2010.Edition-Featuring.Fedora.Linux.12.pdf

     Fedora 是一个独立的操作系统,是Linux的一个发行版,可运行的体系结构包括 x86(即i386-i686), x86_64 和 PowerPC。  Fedora Core(自第七版直接更名为 Fedora)是众多 Linux 发行套件之一。它是一套从Red Hat ...

    USB7002中文数据手册.pdf

    - USB转I2C/SPI/UART/I2S/GPIO桥接器端点支持 - USB转内部集线器寄存器的读写 • 经USB-IF认证——TID 1212。测试包括: - 支持BC1.2的USB3.1 Gen1集线器 - 使用UPD350 PD收发器的PD 2.0(TID 330000077) - 支持...

    ELDK使用与开发手册

    bootstrap – program the I2C bootstrap EEPROM bootvx – Boot vxWorks from an ELF image cmp – memory compare coninfo – print console devices and information cp – memory copy crc32 – checksum ...

    基于P o w e r P C的通信系统设计与实现

    基于P o w e r P C的通信系统设计与实现 摘要: 介绍了嵌入式系统的构成、 技术特点, 结合具体的设计实例, 论迷了以 M o t o rl a...MP C 8 2 6 0和 L i n u x嵌入式操作系统为基础的嵌入式通信系统设计实现方法。

    基于Xilinx平台的嵌入式软件开发流程

    platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data绝大多数纯属垃圾冗余代码 为了解决这一问题,ARM内核版本3.x之后引入了原先在Power PC等其他体系架构已经使用的Flattened ...

    rtl8188FU_linux_v5.2.11.1_22924.20170703.tar.gz

    维权之R16平台配置Makefile: W:\tinav2.5\lichee\linux-3.4\drivers\net\wireless\rtl8188fu\Makefile ########################## WIFI IC ############################ CONFIG_MULTIDRV = n (可选增加) CONFIG...

    STM32F10xxx参考手册

    8.3.9 I2C1复用功能重映射 120 8.3.10 SPI 1复用功能重映射 120 8.3.11 SPI3复用功能重映射 120 8.3.12 以太网复用功能重映射 121 8.4 AFIO寄存器描述 121 8.4.1 事件控制寄存器(AFIO_EVCR) 121 8.4.2 复用...

    AM335x UBOOT移植记录

    一、移植过程 1、架构移植 2、SOC移植 3、板级移植 二、3种移植的区别 1、架构移植:Cortex-A8、... 2、SOC移植 :同一系列,不同型号间的外设(如I2C)的区别 3、板级移植:EVM(删减模块,驱动)的SDK到目标板SDK

Global site tag (gtag.js) - Google Analytics