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

转载 2012年03月27日 14:11:13

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


相关文章推荐

Linux设备驱动之——serio总线

什么是总线            总线是处理器与一个或者多个设备之间的通道。在设备模型中所有的设备都是通过总线相连的。甚至那些内部的虚拟"平台"总线。总线可以互相插入,比如一个 USB 控制器通...

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

Eric Fang  2010-01-20--------------------------------------------------------------本站分析linux内核源码,版本号...

深入浅出linux之总线之上的总线(serio总线)

从前文驱动的层次分析中,我们知道驱动可以分为几个层次,驱动之间可以嵌套。而总线也可以分为几个层次,一种总线可以架构在另一种总线之上。   上节在platform总线的分析中,在驱动提供的probe函...

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

serio总线也是kernel中的一种虚拟的串行输入输出总线,源码\drivers\input\serio目录下有很多与之相关的驱动程序。 一.serio初始化 和之前分析platform总线一样...

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

ric Fang  2010-01-19--------------------------------------------------------------本站分析linux内核源码,版本号为...

Linux设备驱动之——serio总线

什么是总线            总线是处理器与一个或者多个设备之间的通道。在设备模型中所有的设备都是通过总线相连的。甚至那些内部的虚拟"平台"总线。总线可以互相插入,比如一个 USB 控制器通常...
  • ccbuluo
  • ccbuluo
  • 2014年02月24日 16:28
  • 431

Linux SPI总线和设备驱动架构之二:SPI通用接口层

通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了...

Linux SPI总线和设备驱动架构之二:SPI通用接口层

版权声明:本文为博主原创文章,未经博主允许不得转载。 通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口...
  • yedushu
  • yedushu
  • 2017年07月03日 17:34
  • 152

Linux I2C核心、总线与设备驱动(二)

从上面的分析可知,虽然I2C硬件体系结构比较简单,但是I2C体系结构在Linux中的实现却相当复杂。当工程师拿到实际的电路板,面对复杂的 Linux I2C子系统,应该如何下手写驱动呢?究竟有哪些...

Linux下DM644x设备驱动I2C之总线驱动(二)详解

本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。 欢迎和大家交流。qq:1037701636 email:200803090209@zjut.com,gzzaigcn2012@gmail.com...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:·LINUX设备驱动之serio总线(二)
举报原因:
原因补充:

(最多只允许输入30个字)