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
发表评论
-
2011年春季消费者行为分析1
2012-01-20 11:28 15862011年春季消费者行为分析1 2011年04月21日 ... -
八年级英语外研版下第二学期英语阶段测试卷(Module 5)
2012-01-20 11:28 657八年级英语外研版下第二学期英语阶段测试卷(Module 5) ... -
关于……留着以后用
2012-01-20 11:28 548关于……留着以后用 57 ... -
Hypertable 简介 (一个 C++ 的Bigtable开源实现)
2012-01-20 11:28 737Hypertable 简介 (一个 C++ 的Bigtable ... -
[转载]生命科学谁领风骚?刘实世界第一的重大发现
2012-01-20 11:27 568[转载]生命科学谁领风骚?刘实世界第一的重大发现 12小时前 ... -
【转】 (原创)用PHP和MySQL编一个网页计数器
2012-01-19 16:07 970【转】 (原创)用PHP和MySQL编一个网页计数器 201 ... -
Memcached 协议 中英文对照(一)
2012-01-19 16:07 551Memcached 协议 中英文对 ... -
herve leger sale grj lkh rndm eba
2012-01-19 16:07 500herve leger sale grj lkh rndm e ... -
爪哇版的加解密小程序
2012-01-19 16:07 607爪哇版的加解密小程序 2012年01月16日 //要先安 ... -
2011-9-7
2012-01-17 05:58 5182011-9-7 2011年09月07日 国税总局:9月 ... -
贾樟柯赵涛宣布结婚:8月已领证 威尼斯拍婚照
2012-01-17 05:58 608贾樟柯赵涛宣布结婚:8 ... -
2011-9-12
2012-01-17 05:58 6882011-9-12 2011年09月12日 THUGST ... -
男子应聘被老板骗至医院迷昏割肾1
2012-01-17 05:58 608男子应聘被老板骗至医院迷昏割肾1 2011年09月21日 ... -
男子应聘被老板骗至医院迷昏割肾2
2012-01-17 05:58 485男子应聘被老板骗至医 ... -
中秋节
2012-01-16 04:45 503中秋节 2011年12月06日 中秋 ... -
外仁内圣,以借得天下,以情御英雄
2012-01-16 04:45 940外仁内圣,以借得天下,以情御英雄 2011年12月09日 ... -
说"书"
2012-01-16 04:45 425说"书" 2011年12月11日 ... -
春秋战国时期私学的发展
2012-01-16 04:45 1336春秋战国时期私学的发展 2011年12月08日 ... -
子微枯稿
2012-01-16 04:45 558子微枯稿 2011年11月28日 《愁何》 其一 ...
相关推荐
pcf8563_i2c1_r8_ruoge_ov2640通过给RTC驱动增加设备节点读取秒钟成功+直接读取I2C1获取秒钟值20160626_2201.7z http://blog.csdn.net/21cnbao/article/details/7919055 在Android源码树中添加userspace I2C读写...
本文描述I2C协议,包含I2C位传输, I2C开始和结束信号,I2C应答信号,I2C写流程,I2C读流程。进阶介绍PowerPC的I2C实现,I2CADR 地址寄存器及PPC-Linux中I2C的实现
包括U-boot在PowerPC 中的使用、Embeded Linux 编译与移植、网络设备驱动程序等6个实验。 附录……………………………… 附录I Freescale PowerPC处理器概述 附录II Micetek开发板介绍 附录III Jediview 安装与...
MPC8245集成PowerPC处理器适用于那些对成本、空间、功耗和性能都有很高要求的应用领域。该器件有较高的集成度,它集5个芯片... 业界标准I2C 接口,支持链接 带有多个定时器和计数器的可编程中断控制器 16550 DUART
考虑到框架更强的兼容性,字符设备、块设备、TTY设备、I2C设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等驱动的体系结构都变得愈发复杂,框架成为Linux设备驱动学习上的绊脚石。 因此,读者极需这样一本书...
车辆显控系统的控制主板选用高性能PowerPC MPC8548E处理器,扩展了显示器、内存、Flash存储器和接口设备。以此主板为平台,实现了...本文重点阐述了在PowerPC上用软件实现I2C控制以及通过PCI总线实现设备间通信的方法。
本章首先对Windows驱动程序的两个重要数据结构进行介绍,分别是驱动对象和设备对象数据结构。另 外还要介绍NT驱动程序和WDM驱动程序的入口函数、卸载例程、各种IRP派遣上函数等。 4.1 Windows驱动程序中重要的...
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 ...
本书共分23章,内容涵盖了Windows操作系统的基本原理、NT驱动程序与WDM驱动程序的构造、驱动程序中的同步异步处理方法、驱动程序中即插即用功能、驱动程序的各种调试技巧等。同时,还针对流行的PCI驱动程序、USB驱动...
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
3、设备管理中常见的未知设备一般为ACPI电源管理器和TPM安全芯片,如果出现未知设备,请首先尝试安装其驱动。 4、GHOST安装的系统有可能存在驱动无法安装的情况,建议不要使用GHOST安装系统。 5、使用GHOST安装...
Fedora 是一个独立的操作系统,是Linux的一个发行版,可运行的体系结构包括 x86(即i386-i686), x86_64 和 PowerPC。 Fedora Core(自第七版直接更名为 Fedora)是众多 Linux 发行套件之一。它是一套从Red Hat ...
- USB转I2C/SPI/UART/I2S/GPIO桥接器端点支持 - USB转内部集线器寄存器的读写 • 经USB-IF认证——TID 1212。测试包括: - 支持BC1.2的USB3.1 Gen1集线器 - 使用UPD350 PD收发器的PD 2.0(TID 330000077) - 支持...
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的通信系统设计与实现 摘要: 介绍了嵌入式系统的构成、 技术特点, 结合具体的设计实例, 论迷了以 M o t o rl a...MP C 8 2 6 0和 L i n u x嵌入式操作系统为基础的嵌入式通信系统设计实现方法。
platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data绝大多数纯属垃圾冗余代码 为了解决这一问题,ARM内核版本3.x之后引入了原先在Power PC等其他体系架构已经使用的Flattened ...
维权之R16平台配置Makefile: W:\tinav2.5\lichee\linux-3.4\drivers\net\wireless\rtl8188fu\Makefile ########################## WIFI IC ############################ CONFIG_MULTIDRV = n (可选增加) CONFIG...
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 复用...
一、移植过程 1、架构移植 2、SOC移植 3、板级移植 二、3种移植的区别 1、架构移植:Cortex-A8、... 2、SOC移植 :同一系列,不同型号间的外设(如I2C)的区别 3、板级移植:EVM(删减模块,驱动)的SDK到目标板SDK