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

来源:互联网 发布:端口号的目的是什么 编辑:程序博客网 时间:2024/06/11 21:01

三.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设备的一些实际例子。


原创粉丝点击