展讯android LEDS模块分析----四大路径

来源:互联网 发布:jsp 是js吗 编辑:程序博客网 时间:2024/05/23 17:56
        但是,作为一名有责任的男人,我怎么能就这么浅尝则止了呢?当年我不顾老大反对,来做驱动不就是为了让事情更明了么,希望知其然而且也知其所以然么?但是说来惭愧,做了一年驱动,知其然都没学会。看来智商的确是硬伤啊!为什么会有leds这个目录呢?它是怎么注册为leds class的呢?为什么操作这个目录就会控制我们的灯亮灭呢?他们两个究竟有什么不可告人的秘密呢?唉,不知道什么时候章子怡能够出现在小撒的今日说法里面。
        
        我想来谈谈, 驱动设备模型--sys文件系统。
        题目好大,让我想起来一个大四的毕业生的毕业论文是“如何制造原子弹”一样。但是,毛主席说了:心有多大,舞台就有多大。千里之行,始于足下,我们从那里开始呢?我不喜欢漫无目的的旅游,先去看几个疑问吧!
        我们知道,在Linux中,驱动程序无非就是 设备和驱动,我先把所有关于led的东西在目录中翻出来!
        /sys/class/leds/keyboard-backlight
        /sys/bus/platform/devices/keyboard-backlight
        /sys/devices/platform/keyboard-backlight/leds/keyboard-backlight

        /sys/bus/platform/drivers/keyboard-backlight
        
其实,用ll命令就可以看出来,前面两个都是链接,链接到了/sys/devices/platform/keyboard-backlight,而非真正的文件。好的,那我们就从/sys/devices/platform/keyboard-backlight这个目录开始吧。

        作为一名合格的驱动工程师,就必须得知道有platform这个东西吧,就像作为一名合格的屌丝必须会玩dota一样。冤有头,债有主,leds-sc8810-kb.c现在就是这个世界的根源。而看一个module的开始必然是去寻找init函数--sprd_kb_led_init()->platform_driver_register(&sprd_kb_led_driver)
贴出来
static struct platform_driver sprd_kb_led_driver = {
.driver = {
.name = "keyboard-backlight",
.owner = THIS_MODULE,
   },
.probe = sprd_kb_led_probe,
.remove = sprd_kb_led_remove,
.shutdown = sprd_kb_led_shutdown,
};
其他都是浮云,现在只想让大家先记住.name。当然,单单记住简单的.name现在来说是毫无意义的,因为,sprd_kb_led_init()函数已然结束了。卖糕的,就调用了一个函数?让我想起了我的上一次恋爱,约会了一次,连手都没碰呢,却被告知,你被甩了!好吧,那么,platform_driver_register这个函数里面必然有好多故事。

int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;

return driver_register(&drv->driver);
}

struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs= platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};

考验你的记忆力的时候到了,这里又出现了platform_bus_type.name = "platform"一些赋值以后,调用了
driver_register(&drv->driver)->bus_add_driver(drv),其实,我z真想把这个函数全部都贴出来,但是他太大了,就像大街上有很多美女,并不是我不喜欢,只是感觉上去搭讪并不会得到什么好结果。不过还是有些时候还是会被荷尔蒙冲昏了头脑

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:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}


        迈克尔杰克逊说过一句话:磨刀不误打柴工。我想花点时间说说 kobject、kset、ktype,之间的关系。虽然,在网上一搜就一大堆,但是,他们的三角恋关系还是让我等智商暗暗得揣摩了好久好久。该不该把他们的这些结构体也贴上呢?我想了想,还是算了吧。霍金都知道,每贴一段代码都会吓走一半读者,呵呵,咱虽然不是名人,但是还是很注重读者的感受的。我就说一句话:以我现在的理解,我们的 sysfs 系统中出现的结构层次是由 kobject 所决定的,每一个kobject就对应了一层目录,kobject 以及 kobject->parent的树状结构就构成了我们在/sys目录下看到的层次结构。当然,按照LDD大神的话就是,kobject虽然起着最关键的作用,但是,boss通常是不自己出面的,kobject可以理解为一个基类,嵌入到devices 以及 device_driver中。把 kset 理解为 kobject 的一个容器类,人为得制造kset来帮助kobject 以及 kobject->parent完善强健的目录树,以及管理整个驱动。ktype则是表示对这个目录的一些属性操作。说好了一句呢,就这吧!其他的都在实践中慢慢理解。
原创粉丝点击