LINUX设备驱动之serio总线(二)

    技术2025-09-24  115

    Eric Fang  2010-01-20

    --------------------------------------------------------------

    本站分析linux内核源码,版本号为2.6.32.3

    转载请注明出处:http://ericfang.cublog.cn/

    --------------------------------------------------------------

     

    接上一篇文章继续分析。

    三.serio驱动的注册

    serio驱动注册的函数为serio_register_driver()

    static inline int __must_check serio_register_driver(struct serio_driver *drv)

    {

           return __serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME);

    }

    转如__serio_register_driver()

    int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)

    {

           bool manual_bind = drv->manual_bind;

           int error;

     

           drv->driver.bus = &serio_bus;

           drv->driver.owner = owner;

           drv->driver.mod_name = mod_name;

     

           /*

            * Temporarily disable automatic binding because probing

            * takes long time and we are better off doing it in kseriod

            */

           drv->manual_bind = true;

     

           error = driver_register(&drv->driver);

           if (error) {

                  printk(KERN_ERR

                         "serio: driver_register() failed for %s, error: %d/n",

                         drv->driver.name, error);

                  return error;

           }

     

           /*

            * Restore original bind mode and let kseriod bind the

            * driver to free ports

            */

           if (!manual_bind) {

                  drv->manual_bind = false;

                  error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER);

                  if (error) {

                         driver_unregister(&drv->driver);

                         return error;

                  }

           }

     

           return 0;

    }

    有了上面的分析,这个函数就很好理解了,它根据输入参数和一些默认值进行部分字段的初始化,然后调用driver_register()注册内嵌的driver,如果manual_bind0则产生一个SERIO_ATTACH_DRIVER类型事件,内核线程将会进行一次设备驱动匹配。按照linux的思想,应该是设置manual_bind1,等到需要的时候再进行设备驱动绑定,这样做的好处是可以节省系统资源。

    在设备驱动的匹配过程中会调用总线上的matchprobe接口函数,这两个函数为serio_bus_match()serio_driver_probe(),分别进行分析:

    static int serio_bus_match(struct device *dev, struct device_driver *drv)

    {

           struct serio *serio = to_serio_port(dev);

           struct serio_driver *serio_drv = to_serio_driver(drv);

     

           if (serio->manual_bind || serio_drv->manual_bind)

                  return 0;

     

           return serio_match_port(serio_drv->id_table, serio);

    }

    如果对应的设备和驱动有一个指定为手动绑定,则直接退出,否则调用serio_match_port(serio_drv->id_table, serio)进行匹配:

    static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)

    {

           while (ids->type || ids->proto) {

                  if ((ids->type == SERIO_ANY || ids->type == serio->id.type) &&

                      (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) &&

                      (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) &&

                      (ids->id == SERIO_ANY || ids->id == serio->id.id))

                         return 1;

                  ids++;

           }

           return 0;

    }

    由此看出如果驱动的id_table中包含了设备的id字段中的信息,则会匹配成功。

    接着看serio_driver_probe()函数:

    static int serio_driver_probe(struct device *dev)

    {

           struct serio *serio = to_serio_port(dev);

           struct serio_driver *drv = to_serio_driver(dev->driver);

     

           return serio_connect_driver(serio, drv);

    }

    static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)

    {

           int retval;

     

           mutex_lock(&serio->drv_mutex);

           retval = drv->connect(serio, drv);

           mutex_unlock(&serio->drv_mutex);

     

           return retval;

    }

    最终会调用驱动的connect()函数,这个函数在具体的驱动程序实现,以后我们会分析到。

     

    四.serio驱动的中断处理

    Serio设备的中断都会流入serio_interrupt()中:

    irqreturn_t serio_interrupt(struct serio *serio,

                  unsigned char data, unsigned int dfl)

    {

           unsigned long flags;

           irqreturn_t ret = IRQ_NONE;

     

           spin_lock_irqsave(&serio->lock, flags);

     

            if (likely(serio->drv)) {

                    ret = serio->drv->interrupt(serio, data, dfl);

           } else if (!dfl && serio->registered) {

                  serio_rescan(serio);

                  ret = IRQ_HANDLED;

           }

     

           spin_unlock_irqrestore(&serio->lock, flags);

     

           return ret;

    }

    先判断serio->drv是否存在,这里的likely()为了进行代码的优化,提高系统执行速度。如果serio->drv存在,则调用它;如果不存在则会进一步判断dfl参数和serio->registered标志,并调用serio_rescan(serio)函数,这个函数如下:

    void serio_rescan(struct serio *serio)

    {

           serio_queue_event(serio, NULL, SERIO_RESCAN_PORT);

    }

    产生一个SERIO_RESCAN_PORT类型事件,断开设备驱动的关联(实际上这里还没关联),再重新匹配驱动。

     

    到此,serio总线基本分析完了,后面将分析serio设备的一些实际例子。

    最新回复(0)