2010年(15)
分类: LINUX
2010-01-20 14:00:52
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_bind为0则产生一个SERIO_ATTACH_DRIVER类型事件,内核线程将会进行一次设备驱动匹配。按照linux的思想,应该是设置manual_bind为1,等到需要的时候再进行设备驱动绑定,这样做的好处是可以节省系统资源。
在设备驱动的匹配过程中会调用总线上的match和probe接口函数,这两个函数为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设备的一些实际例子。