platform_driver就是驱动的核心,而probe函数又是核心中的核心,接上一节对platform_driver的probe函数做一个解析.
gpio_led_probe()函数是gpio_led_driver驱动的probe函数,probe函数在驱动匹配到platform_device时执行,调用过程如下:
static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
.remove = __devexit_p(gpio_led_remove),
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
.of_match_table = of_gpio_leds_match,
},
};
static int __init gpio_led_init(void)
{
return platform_driver_register(&gpio_led_driver);
}
int platform_driver_register(struct platform_driver *drv)
{
......
return driver_register(&drv->driver);
}
int driver_register(struct device_driver *drv)
{
.....
ret = bus_add_driver(drv);
.....
}
int bus_add_driver(struct device_driver *drv)
{
......
if (drv->bus->p->drivers_autoprobe) {
//搜寻总线的设备列表,如果和驱动匹配,则把设备添加到驱动的klist_devices列表
error = driver_attach(drv);
if (error)
goto out_unregister;
}
......
}
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __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 0; // 匹配失败返回0
// 匹配成功
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 0;
}
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
..........
ret = really_probe(dev, drv);
.........
}
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;
}
// 执行probe函数
if (dev->bus->probe) { // 优先执行bus的probe
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {// 执行驱动的probe
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
// 添加设备到驱动的klist_devices列表
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);
} else {
pr_debug("%s: probe of %s rejects match %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;
}
gpio_led_driver驱动的probe函数定义如下:
static int __devinit gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
int i, ret = 0;
if (pdata && pdata->num_leds) {
priv = kzalloc(sizeof_gpio_leds_priv(pdata->num_leds),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->num_leds = pdata->num_leds;
for (i = 0; i < priv->num_leds; i++) {
ret = create_gpio_led(&pdata->leds[i],
&priv->leds[i],
&pdev->dev, pdata->gpio_blink_set);
if (ret < 0) {
/* On failure: unwind the led creations */
for (i = i - 1; i >= 0; i--)
delete_gpio_led(&priv->leds[i]);
kfree(priv);
return ret;
}
}
} else {
priv = gpio_leds_create_of(pdev);
if (!priv)
return -ENODEV;
}
platform_set_drvdata(pdev, priv);
return 0;
}
@struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
gpio_led_platform_data 是platform_device设备的硬件资源,比如这里是这样定义的
static struct gpio_led_platform_data gpio_led_info = {
.leds = gpio_leds, // led灯的数组
.num_leds = ARRAY_SIZE(gpio_leds), // led灯的个数
};
该结构定义了platform_device对应的led灯个数和led灯数组,也就是驱动要处理的硬件对象;
@struct gpio_leds_priv *priv;
定义如下
struct led_classdev {
const char *name; // led灯名称,如"heartbeat"
int brightness;// led灯亮度
int max_brightness;
int flags;
/* Lower 16 bits reflect status */
#define LED_SUSPENDED (1 << 0)
/* Upper 16 bits reflect control information */
#define LED_CORE_SUSPENDRESUME (1 << 16)
/* Set LED brightness level */ // 设置led灯的亮度:关闭,一般亮度,全亮
/* Must not sleep, use a workqueue if needed */
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
/* Get LED brightness level */// 读取led灯的亮度
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
/*
* Activate hardware accelerated blink, delays are in milliseconds
* and if both are zero then a sensible default should be chosen.
* The call should adjust the timings in that case and if it can't
* match the values specified exactly.
* Deactivate blinking again when the brightness is set to a fixed
* value via the brightness_set() callback.
*/
int (*blink_set)(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off);
struct device *dev;
struct list_head node; /* LED Device list */
const char *default_trigger; /* Trigger to use */// 字符串?"heartbeat"
unsigned long blink_delay_on, blink_delay_off;
struct timer_list blink_timer;
int blink_brightness;
#ifdef CONFIG_LEDS_TRIGGERS
/* Protects the trigger data below */
struct rw_semaphore trigger_lock;
struct led_trigger *trigger;
struct list_head trig_list;
void *trigger_data;
#endif
};
struct gpio_led_data {
struct led_classdev cdev;
unsigned gpio;
struct work_struct work;
u8 new_level;
u8 can_sleep;
u8 active_low;
u8 blinking;
int (*platform_gpio_blink_set)(unsigned gpio, int state,
unsigned long *delay_on, unsigned long *delay_off);
};
struct gpio_leds_priv {
int num_leds;// led灯个数
struct gpio_led_data leds[];//led灯
};
@create_gpio_led函数
ret = create_gpio_led(&pdata->leds[i],
&priv->leds[i],
&pdev->dev, pdata->gpio_blink_set);
参数:
pdata->leds[i]:platform_device.platform_data.leds
priv->leds[i]:gpio_leds_priv .leds
pdev->dev:platform_device.dev
pdata->gpio_blink_set:platform_device.platform_data.gpio_blink_set
功能:
该函数最后调用led_classdev_register,为每个led创建目录:如/sys/devices/platform/leds-gpio/leds/heartbeat,具体就不继续了,阅读起来也不难;
小结:
platform_device,platform_driver,platform_bus之间的关系可以这样来理解:
platform_device提供设备的硬件资源
platform_driver根据设备提供的资源编写驱动
platform_bus管理platform_device和platform_driver,一旦两者匹配成功,应用程序就可以访问了.