linux 平台总线的实现有三大块  , platform bus , platform device , platform drvice

平台类型结构体:

 /**
* struct bus_type - The bus type of the device
*
* @name: The name of the bus.
* @bus_attrs: Default attributes of the bus.
* @dev_attrs: Default attributes of the devices on the bus.
* @drv_attrs: Default attributes of the device drivers on the bus.
* @match: Called, perhaps multiple times, whenever a new device or driver
* is added for this bus. It should return a nonzero value if the
* given device can be handled by the given driver.
* @uevent: Called when a device is added, removed, or a few other things
* that generate uevents to add the environment variables.
* @probe: Called when a new device or driver add to this bus, and callback
* the specific driver's probe to initial the matched device.
* @remove: Called when a device removed from this bus.
* @shutdown: Called at shut-down time to quiesce the device.
* @suspend: Called when a device on this bus wants to go to sleep mode.
* @resume: Called to bring a device on this bus out of sleep mode.
* @pm: Power management operations of this bus, callback the specific
* device driver's pm-ops.
* @p: The private data of the driver core, only the driver core can
* touch this.
*
* A bus is a channel between the processor and one or more devices. For the
* purposes of the device model, all devices are connected via a bus, even if
* it is an internal, virtual, "platform" bus. Buses can plug into each other.
* A USB controller is usually a PCI device, for example. The device model
* represents the actual connections between buses and the devices they control.
* A bus is represented by the bus_type structure. It contains the name, the
* default attributes, the bus' methods, PM operations, and the driver core's
* private data.
*/
 struct bus_type {
const char *name;
struct bus_attribute *bus_attrs; // 总线属性
struct device_attribute *dev_attrs; // 设备属性
struct driver_attribute *drv_attrs; // 驱动性
int (*match)(struct device *dev, struct device_driver *drv); //匹配平台设备与平台驱动的函数
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev); const struct dev_pm_ops *pm; struct subsys_private *p;
};

参考: http://blog.chinaunix.net/uid-25622207-id-2778126.html

在kernel中 , 首先是有platform bus被kernel 注册

有以下流程:

init/main.c

 static int __init kernel_init(void * unused)
{
......
do_basic_setup();
......
} //再到
static void __init do_basic_setup(void)
{
cpuset_init_smp();
usermodehelper_init();
init_tmpfs();
driver_init();
init_irq_proc();
do_ctors();
do_initcalls();
}

再进 driver_init()

 void __init driver_init(void)
{
/* These are the core pieces */
devtmpfs_init();
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init(); /* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init(); //平台总线初始化
system_bus_init();
cpu_dev_init();
memory_dev_init();
}

再进平台总线初始化

 struct device platform_bus = {
.init_name = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);
//... struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
EXPORT_SYMBOL_GPL(platform_bus_type); //...
int __init platform_bus_init(void)
{
int error; early_platform_cleanup(); error = device_register(&platform_bus); //将平台总线作为一个设备注册
if (error)
return error;
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}

match 函数是等下匹配platform device 和 platform driver 的函数

 1 /**
2 * platform_match - bind platform device to platform driver.
3 * @dev: device.
4 * @drv: driver.
5 *
6 * Platform device IDs are assumed to be encoded like this:
7 * "<name><instance>", where <name> is a short description of the type of
8 * device, like "pci" or "floppy", and <instance> is the enumerated
9 * instance of the device, like '0' or '42'. Driver IDs are simply
10 * "<name>". So, extract the <name> from the platform_device structure,
11 * and compare it against the name of the driver. Return whether they match
12 * or not.
13 */
14
15 static int platform_match(struct device *dev, struct device_driver *drv)
16 {
17 struct platform_device *pdev = to_platform_device(dev);
18 struct platform_driver *pdrv = to_platform_driver(drv);
19
20 /* Attempt an OF style match first */
21 if (of_driver_match_device(dev, drv))
22 return 1;
23
24 /* Then try to match against the id table */
25 if (pdrv->id_table)
26 return platform_match_id(pdrv->id_table, pdev) != NULL;
27
28 /* fall-back to driver name match */
29 return (strcmp(pdev->name, drv->name) == 0);
30 }
 //通过id_table 来匹配
1 static const struct platform_device_id *platform_match_id(
2 const struct platform_device_id *id,
3 struct platform_device *pdev)
4 {
5 while (id->name[0]) {
6 if (strcmp(pdev->name, id->name) == 0) {
7 pdev->id_entry = id;
8 return id;
9 }
10 id++;
11 }
12 return NULL;
13 }
 int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}

此时platform bus 已经作为一个设备挂到内核上

看完平台总线, 下面看平台设备的注册流程:

还是得把一开始的platform device 结构体放到这里来:

 struct platform_device {
const char * name; //平台设备名字
int id;
struct device dev; //设备结构体
u32 num_resources; //资源个数
struct resource * resource; //资源 const struct platform_device_id *id_entry; /* MFD cell pointer */
struct mfd_cell *mfd_cell; /* arch specific additions */
struct pdev_archdata archdata;
}; #define platform_get_device_id(pdev) ((pdev)->id_entry)
//通过device 找到对应的platform_device 结构体
#define to_platform_device(x) container_of((x), struct platform_device, dev)

 其实这里边还有个设备结构体 , 他是依附在平台设备里面

  /**
2 * struct device - The basic device structure
3 * @parent: The device's "parent" device, the device to which it is attached.
4 * In most cases, a parent device is some sort of bus or host
5 * controller. If parent is NULL, the device, is a top-level device,
6 * which is not usually what you want.
7 * @p: Holds the private data of the driver core portions of the device.
8 * See the comment of the struct device_private for detail.
9 * @kobj: A top-level, abstract class from which other classes are derived.
10 * @init_name: Initial name of the device.
11 * @type: The type of device.
12 * This identifies the device type and carries type-specific
13 * information.
14 * @mutex: Mutex to synchronize calls to its driver.
15 * @bus: Type of bus device is on.
16 * @driver: Which driver has allocated this
17 * @platform_data: Platform data specific to the device.
18 * Example: For devices on custom boards, as typical of embedded
19 * and SOC based hardware, Linux often uses platform_data to point
20 * to board-specific structures describing devices and how they
21 * are wired. That can include what ports are available, chip
22 * variants, which GPIO pins act in what additional roles, and so
23 * on. This shrinks the "Board Support Packages" (BSPs) and
24 * minimizes board-specific #ifdefs in drivers.
25 * @power: For device power management.
26 * See Documentation/power/devices.txt for details.
27 * @pwr_domain: Provide callbacks that are executed during system suspend,
28 * hibernation, system resume and during runtime PM transitions
29 * along with subsystem-level and driver-level callbacks.
30 * @numa_node: NUMA node this device is close to.
31 * @dma_mask: Dma mask (if dma'ble device).
32 * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
33 * hardware supports 64-bit addresses for consistent allocations
34 * such descriptors.
35 * @dma_parms: A low level driver may set these to teach IOMMU code about
36 * segment limitations.
37 * @dma_pools: Dma pools (if dma'ble device).
38 * @dma_mem: Internal for coherent mem override.
39 * @archdata: For arch-specific additions.
40 * @of_node: Associated device tree node.
41 * @devt: For creating the sysfs "dev".
42 * @devres_lock: Spinlock to protect the resource of the device.
43 * @devres_head: The resources list of the device.
44 * @knode_class: The node used to add the device to the class list.
45 * @class: The class of the device.
46 * @groups: Optional attribute groups.
47 * @release: Callback to free the device after all references have
48 * gone away. This should be set by the allocator of the
49 * device (i.e. the bus driver that discovered the device).
50 *
51 * At the lowest level, every device in a Linux system is represented by an
52 * instance of struct device. The device structure contains the information
53 * that the device model core needs to model the system. Most subsystems,
54 * however, track additional information about the devices they host. As a
55 * result, it is rare for devices to be represented by bare device structures;
56 * instead, that structure, like kobject structures, is usually embedded within
57 * a higher-level representation of the device.
58 */ struct device {
struct device *parent; // 设备的父类 struct device_private *p; //设备的私有数据 struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type; struct mutex mutex; /* mutex to synchronize calls to
11 * its driver.
12 */
//表示该设备是属于哪一条总线
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
16 device */ // 哪个驱动调用了这个设备
void *platform_data; /* Platform specific data, device
18 core doesn't touch it ***********/
struct dev_pm_info power;
struct dev_power_domain *pwr_domain; #ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
27 alloc_coherent mappings as
28 not all hardware supports
29 64 bit addresses for consistent
30 allocations such descriptors. */ struct device_dma_parameters *dma_parms; struct list_head dma_pools; /* dma pools (if dma'ble) */ struct dma_coherent_mem *dma_mem; /* internal for coherent mem
37 override */
/* arch specific additions */
struct dev_archdata archdata; struct device_node *of_node; /* associated device tree node */ dev_t devt; /* dev_t, creates the sysfs "dev" */ //主次设备号的>结合体 spinlock_t devres_lock;
struct list_head devres_head; struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */ void (*release)(struct device *dev);
};
 //平台设备注册函数
extern int platform_device_register(struct platform_device *);
extern void platform_device_unregister(struct platform_device *);
//平台设备解注册函数

这两个函数对外发布

i2c 设备就用到了这个 函数进行 platform device 的 register

在arch/arm/mach-mx6/board-mx6q_sabresd.c 中

 MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")    /* Maintainer: Freescale Semiconductor, Inc. */
.boot_params = MX6_PHYS_OFFSET + 0x100,
.fixup = fixup_mxc_board,
.map_io = mx6_map_io,
.init_irq = mx6_init_irq,
.init_machine = mx6_sabresd_board_init, // 板级的初始化
.timer = &mx6_sabresd_timer, // 时钟的初始化
.reserve = mx6q_sabresd_reserve,
MACHINE_END

时钟的话跟过去得到 i2c 的   CLK  的速度是400KB/s

在mx6_sabresd_board_init 中

平台设备内设备的平台数据进行赋值

 static struct i2c_gpio_platform_data i2c_bus_gpio_data = {
.sda_pin = SABRESD_I2C4_SDA_GPIO,
.scl_pin = SABRESD_I2C4_SCL_GPIO,
.udelay = , //10Khz
.timeout = ,
//.sda_is_open_drain = 1, //在当前板子上不能加
//.scl_is_open_drain = 1, //在当前板子上不能加
};

平台设备结构体的赋值

 static struct platform_device i2c_bus_gpio_device = {
.name = "i2c-gpio", //这个名字是必须这样,主要是为了和i2c-gpio驱动对应
//由于板子已经用掉了0,1,2号,这里使用3
.id = , /* bus have 0,1,2, so start at 3 */
.dev = {
.platform_data = &i2c_bus_gpio_data,
}
};

板级的初始化:

 static void __init mx6_sabresd_board_init(void)
{ //。。。。。。 /**
* register gpio i2c bus write by zengjf
* 注册i2c-gpio设备,相当于注册一个I2C控制器
*/
platform_device_register(&i2c_bus_gpio_device); i2c_register_board_info(, mxc_i2c0_board_info,
ARRAY_SIZE(mxc_i2c0_board_info));
i2c_register_board_info(, mxc_i2c1_board_info,
ARRAY_SIZE(mxc_i2c1_board_info));
i2c_register_board_info(, mxc_i2c2_board_info,
ARRAY_SIZE(mxc_i2c2_board_info));
/**
* register gpio i2c device write by zengjf
* 在I2C控制器3上注册I2C设备,这里的控制器3就是前面注册的I2C控制器,
* 主要是因为前面注册的I2C控制器的id是3
*/
i2c_register_board_info(, gpio_i2c_devices, ARRAY_SIZE(gpio_i2c_devices)); //。。。。。。 }

在mx6这块板子身上 , i2c 0 , 1 , 2 是比较正常的i2c 总线, 但是i2c 3 是用的两个GPIO口模拟的 i2c 的SCL和 SDA线

下面 , 跟进

    platform_device_register(&i2c_bus_gpio_device);       

/drivers/base/platform.c

 /**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*/
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev); //初始化设备
return platform_device_add(pdev); //平台设备添加
}
EXPORT_SYMBOL_GPL(platform_device_register);

跟进 platform_device_add(pdev)

 /**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
*
* This is part 2 of platform_device_register(), though may be called
* separately _iff_ pdev was allocated by platform_device_alloc().
*/
int platform_device_add(struct platform_device *pdev)
{
int i, ret = ; if (!pdev)
return -EINVAL; if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus; //属于平台总线, pdev->dev.bus = &platform_bus_type; // 在platform_bus_init()的时候已经注册了平台总线类型 if (pdev->id != -)
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); //pdev->dev 只有一个platform_data , pdev->name == i2c-gpio , pdev->id == 3
else
dev_set_name(&pdev->dev, "%s", pdev->name); for (i = ; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i]; if (r->name == NULL)
r->name = dev_name(&pdev->dev); p = r->parent;
if (!p) {
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
} if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
} pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent)); ret = device_add(&pdev->dev); //最终通过这里将设备挂到设备链表上
if (ret == )
return ret; failed:
while (--i >= ) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
} return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);

最终 ,通过上面那个函数 注册一个平台设备 , 我们自己也可以利用这个函数(platform_device_add)   去注册一个我们自己的平台设备 与我们自己本身的平台设备的驱动相匹配

相对应的 , 有平台设备的注册就必然有平台设备的解除注册

 /**
* platform_device_unregister - unregister a platform-level device
* @pdev: platform device we're unregistering
*
* Unregistration is done in 2 steps. First we release all resources
* and remove it from the subsystem, then we drop reference count by
* calling platform_device_put().
*/
void platform_device_unregister(struct platform_device *pdev)
{
platform_device_del(pdev);
platform_device_put(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_unregister);

从而得到我们平台设备的接触注册是调用了platform_device_del()

 /**
* platform_device_del - remove a platform-level device
* @pdev: platform device we're removing
*
* Note that this function will also release all memory- and port-based
* resources owned by the device (@dev->resource). This function must
* _only_ be externally called in error cases. All other usage is a bug.
*/
void platform_device_del(struct platform_device *pdev)
{
int i; if (pdev) {
device_del(&pdev->dev); //对应的是device_add , 该函数是设备删除 for (i = ; i < pdev->num_resources; i++) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
}
}
EXPORT_SYMBOL_GPL(platform_device_del);

我们可以用这个函数对平台设备解除注册

下面就分析一下 , i2c3 总线上 eeprom 这个设备驱动 , 并分析他是怎么通过一系列相关的匹配 将平台总线 , 平台设备, 平台设备驱动相关联(匹配)。

老样子 , 先上两个结构体

平台驱动结构体:

 struct platform_driver {
int (*probe)(struct platform_device *); //这个函数是一个真正的入口函数 , 等下会分析
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver; //设备驱动结构体
const struct platform_device_id *id_table; //平台设备id表
};

设备驱动结构体:

 1
2 /**
3 * struct device_driver - The basic device driver structure
4 * @name: Name of the device driver.
5 * @bus: The bus which the device of this driver belongs to.
6 * @owner: The module owner.
7 * @mod_name: Used for built-in modules.
8 * @suppress_bind_attrs: Disables bind/unbind via sysfs.
9 * @of_match_table: The open firmware table.
10 * @probe: Called to query the existence of a specific device,
11 * whether this driver can work with it, and bind the driver
12 * to a specific device.
13 * @remove: Called when the device is removed from the system to
14 * unbind a device from this driver.
15 * @shutdown: Called at shut-down time to quiesce the device.
16 * @suspend: Called to put the device to sleep mode. Usually to a
17 * low power state.
18 * @resume: Called to bring a device from sleep mode.
19 * @groups: Default attributes that get created by the driver core
20 * automatically.
21 * @pm: Power management operations of the device which matched
22 * this driver.
23 * @p: Driver core's private data, no one other than the driver
24 * core can touch this.
25 *
26 * The device driver-model tracks all of the drivers known to the system.
27 * The main reason for this tracking is to enable the driver core to match
28 * up drivers with new devices. Once drivers are known objects within the
29 * system, however, a number of other things become possible. Device drivers
30 * can export information and configuration variables that are independent
31 * of any specific device.
32 */
 1 struct device_driver {
2 const char *name; /* 设备驱动的名字 */
3 struct bus_type *bus; /* belong which bus (chenfl)*/
4
5 struct module *owner;
6 const char *mod_name; /* used for built-in modules */
7
8 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
9
10 const struct of_device_id *of_match_table;
11
12 int (*probe) (struct device *dev);
13 int (*remove) (struct device *dev);
14 void (*shutdown) (struct device *dev);
15 int (*suspend) (struct device *dev, pm_message_t state);
16 int (*resume) (struct device *dev);
17 const struct attribute_group **groups;
18
19 const struct dev_pm_ops *pm;
20
21
22 struct driver_private *p;
23 };

再介绍一个两个函数:

 //平台设备驱动的注册函数
extern int platform_driver_register(struct platform_driver *);
extern void platform_driver_unregister(struct platform_driver *);
//平台设备驱动解除注册函数

等下会对这两个函数进行分析

了解完这两个结构体后来跟一个epprom 这个设备的驱动

如果是借鉴的就随意找一个平台设备驱动与之同理

drivers/misc/eeprom/at24.c:

 static struct i2c_driver at24_driver = {
.driver = {
.name = "at24",
.owner = THIS_MODULE,
},
.probe = at24_probe,
.remove = __devexit_p(at24_remove),
.id_table = at24_ids,
};
 static int __init at24_init(void)
{
if (!io_limit) {
pr_err("at24: io_limit must not be 0!\n");
return -EINVAL;
} io_limit = rounddown_pow_of_two(io_limit);
return i2c_add_driver(&at24_driver);
}
module_init(at24_init);
 static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
 struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
 /*
* An i2c_driver is used with one or more i2c_client (device) nodes to access
* i2c slave chips, on a bus instance associated with some i2c_adapter.
*/ 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; /* add the driver to the list of i2c drivers in the driver core */
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.
*///这里边有一个匹配成功并执行probe的过程
res = driver_register(&driver->driver); //drvier->driver == {.name = .name = "at24", .owner = THIS_MODULE, }
                                            .owner = owner ,
                                            .bus = &i2c_bus_type }
if (res)
return res; /* Drivers should switch to dev_pm_ops instead. */
if (driver->suspend)
pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
driver->driver.name);
if (driver->resume)
pr_warn("i2c-core: driver [%s] using legacy resume method\n",
driver->driver.name); pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver); return ;
}
EXPORT_SYMBOL(i2c_register_driver);

再进driver_register(struct device_driver *drv)

 /**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*/
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;
}
EXPORT_SYMBOL_GPL(driver_register);

再进bus_add_driver(drv)

 /**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = ; 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);
//初始化设备链表,每一个与该驱动匹配的device都会添加到该链表下
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
//指向该驱动所属的kset
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
//初始化kobject 并将kobject添加到其对应的kset 集合中
if (error)
goto out_unregister; if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv); // 这里是即将要 绑定设备 与 驱动 并调用probe 地方
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 ; out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
 /**
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*/
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
// __将driver_atttach 传去进
//将每一个查找得到的device进行驱动匹配
}
EXPORT_SYMBOL_GPL(driver_attach);
 /**
* bus_for_each_dev - device iterator.
* @bus: bus type.
* @start: device to start iterating from.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @bus's list of devices, and call @fn for each,
* passing it @data. If @start is not NULL, we use that device to
* begin iterating from.
*
* We check the return of @fn each time. If it returns anything
* other than 0, we break out and return that value.
*
* NOTE: The device that returns a non-zero value is not retained
* in any way, nor is its refcount incremented. If the caller needs
* to retain this data, it should do so, and increment the reference
* count in the supplied callback.
*/
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = ; if (!bus)
return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data); // 就是这个东西!!!
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);

这里边 , 调用了fn这个函数 , fn 就是上面传进去的__driver_attach 函数

然后 , 便有了

 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 ; if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev); //如果此时设备上所挂的驱动为空 , 就进去
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent); return ;
}

然后就有了

 /**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
* This function returns -ENODEV if the device is not registered,
* 1 if the device is bound successfully and 0 otherwise.
*
* This function must be called with @dev lock held. When called for a
* USB interface, @dev->parent lock must be held as well.
*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = ; 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;
}

bind device and driver , run probe

 static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = ; 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; //设备上的驱动设置为driver
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) {
ret = dev->bus->probe(dev); //如果总线上有probe , 就运行这个
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev); //这里边在driver 注册的时候 , 已经给i2c_driver 里面的driver 结构体里边的bus 进行初始化赋值
if (ret)
goto probe_failed;
} driver_bound(dev);
ret = ;
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 = ;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}

上面22 行 , 有如下分析代码:

 struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
 int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
......
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
......
}

所以 , 驱动与设备绑定之后 , 运行的probe 是i2c_device_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 ; 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));
if (status) {
client->driver = NULL;
i2c_set_clientdata(client, NULL);
}
return status;
}

linux kernel 平台总线实例分析的更多相关文章

  1. linux kernel内存映射实例分析

    作者:JHJ(jianghuijun211@gmail.com)日期:2012/08/24 欢迎转载,请注明出处 引子 现在android智能手机市场异常火热,硬件升级非常迅猛,arm cortex ...

  2. linux内核SPI总线驱动分析(一)(转)

    linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...

  3. Linux系统网络性能实例分析

    由于TCP/IP是使用最普遍的Internet协议,下面只集中讨论TCP/IP 栈和以太网(Ethernet).术语 LinuxTCP/IP栈和 Linux网络栈可互换使用,因为 TCP/IP栈是 L ...

  4. Linux platform平台总线、平台设备、平台驱动

    平台总线(platform_bus)的需求来源? 随着soc的升级,S3C2440->S3C6410->S5PV210->4412,以前的程序就得重新写一遍,做着大量的重复工作, 人 ...

  5. 蓝牙学习(3) Linux kernel部分Bluetooth HCI分析

    在上文,https://blog.csdn.net/feiwatson/article/details/81712933中主要理解了在Kernel中USB adapter是如何实现USB设备驱动,以及 ...

  6. linux内核SPI总线驱动分析(二)(转)

    简而言之,SPI驱动的编写分为: 1.spi_device就构建并注册  在板文件中添加spi_board_info,并在板文件的init函数中调用spi_register_board_info(s3 ...

  7. linux kernel make构建分析

    前言 之前对uboot的构建进行了分析,现在再对linux kernel的构建进行分析.几年前的确也分析过,但是只是停留在笔记层面,没有转为文章,这次下定决定来完善它. 环境 同样,采用的还是zynq ...

  8. Linux下 USB设备驱动分析(原创)

    之前做过STM32的usb HID复合设备,闲来看看linux下USB设备驱动是怎么一回事, 参考资料基于韦东山JZ2440开发板,以下,有错误欢迎指出. 1.准备知识 1.1USB相关概念: USB ...

  9. Linux Kernel PANIC(三)--Soft Panic/Oops调试及实例分析【转】

    转自:https://blog.csdn.net/gatieme/article/details/73715860 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原 ...

随机推荐

  1. TEXshade教程- 多重比对着色软件包

    多重比对着色软件包 TEXshade 图解安装教程   [絮语]: TEXshade 是 Latex 的一个宏包,可以对 MSF或 ALN 格式的多重比对文件以不同的方式进行着色美化,并可以对重要的位 ...

  2. PasswordHasher

    namespace Microsoft.AspNet.Identity { public class PasswordHasher : IPasswordHasher { public virtual ...

  3. sqlmap写文件为空之谜

    恰逢有一个SQL注入可以通过sqlmap进行,而且权限高得离谱,直接就是root权限.既然是root权限当然是想直接getshell咯.可是只是sqlmap -u xxx --os-shell的时候却 ...

  4. oracle union 注入工具

    '***********************************************************************************************'ora ...

  5. TCSQL实时列表缓存数据库帮助文档

    [文章作者:张宴 本文版本:v1.1 最后修改:2010.09.03 转载请注明原文链接:http://blog.zyan.cc/tcsql/] 曾经有人提出,一般数据库缓存分为四种.第一种:单个对象 ...

  6. 【8-22】java学习笔记04

    java基础类库 Scanner类(java.util.scanner) Scanner对象.hasNextXxx(),hasNext()默认方法为字符串://Returns true if this ...

  7. JQ分页功能

    HTML <div id='page'></div> <div id='con'></div> CSS span{width: 60px;height: ...

  8. GOF业务场景的设计模式-----策略模式

    定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 策略模式代码实现 interface IStrategy { public void doSomething(); } class ...

  9. [转]Informatica vs SSIS

    转自 http://blog.csdn.net/thy822/article/details/8489779 这篇文章, 我不能同意更多, 所以转在这里. Here is my thinking af ...

  10. EF-联合查询-结果集-Group by-统计数目

    EF框架用着痛并且快乐着··· 毕竟用习惯了SQL语句直接硬查的··· SELECT C0.ID,C_C.Name,C_C.C_COUNT FROM article_type C0 INNER JOI ...