linux 串口总线,linux中的serio(虚拟串行输入输出)总线

serio

总线也是

kernel

中的一种虚拟的串行输入输出总线,源码

/drivers/input/serio

目录下有很多与之相关的驱动程序。

一. serio

初始化

和之前分析 platform

总线一样,在系统启动时初始化时也创建了

serio_bus

总线:

static int __init

serio_init(void)

{

int

error;

error =

bus_register(&serio_bus);

if (error)

{

printk(KERN_ERR "serio: failed to

register serio bus, error: %d/n",

error);

return

error;

}

serio_task =

kthread_run(serio_thread, NULL,

"kseriod");

if (IS_ERR(serio_task))

{

bus_unregister(&serio_bus);

error =

PTR_ERR(serio_task);

printk(KERN_ERR "serio: Failed to

start kseriod, error: %d/n",

error);

return

error;

}

return

0;

}

serio_bus

定义如下:

static struct bus_type serio_bus

= {

.name

=

"serio",

.dev_attrs

=

serio_device_attrs,

.drv_attrs

=

serio_driver_attrs,

.match

=

serio_bus_match,

.uevent

=

serio_uevent,

.probe

=

serio_driver_probe,

.remove

=

serio_driver_remove,

.shutdown

=

serio_shutdown,

#ifdef

CONFIG_PM

.pm

=

&serio_pm_ops,

#endif

};

其中的各个函数将在使用到的地方再作分析。

初始化函数 serio_init()

首先注册了

serio_bus

总线,然后创建了一个内核线程

serio_thread

,这个内核线程做什么用的呢?之前分析

platform

总线并没有这个线程,这里为什么要用它?我们先看看

serio_thread

内核线程的内容:

static int serio_thread(void

*nothing)

{

set_freezable();

do

{

serio_handle_event();

wait_event_freezable(serio_wait,

kthread_should_stop() ||

!list_empty(&serio_event_list));

} while

(!kthread_should_stop());

printk(KERN_DEBUG "serio: kseriod

exiting/n");

return

0;

}

该线程首先执行 serio_handle_event()

函数,然后在

serio_wait

等待队列上休眠,如果

kthread_should_stop()

返回

0

的时候也即模块移除调用

kthread_stop(serio_task)

时,

serio_thread

线程返回。我们猜想:在某个时候往

serio_event_list

链表上添加成员时唤醒或等到下一时钟周期唤醒

serio_wait

工作队列,这时候就会去执行

serio_handle_event()

函数,这个函数将会对

serio_event_list

进行操作,为什么要把事件的处理放在内核线程中呢?因为在产生事件时是在关中断状态,同时需要同步,要获得锁,在后面的分析中我们会看到这个锁是

serio_event_lock

,而不能让事件长时间处在关中断状态并且占有着锁,所以延后了事件的处理,先释放该锁并恢复中断状态。在后面的代码分析中我们将看到这点。

serio_handle_event()

函数如下:

static void

serio_handle_event(void)

{

struct serio_event

*event;

mutex_lock(&serio_mutex);

if ((event = serio_get_event()))

{

switch (event->type)

{

case

SERIO_REGISTER_PORT:

serio_add_port(event->object);

break;

case

SERIO_RECONNECT_PORT:

serio_reconnect_port(event->object);

break;

case

SERIO_RESCAN_PORT:

serio_disconnect_port(event->object);

serio_find_driver(event->object);

break;

case

SERIO_RECONNECT_CHAIN:

serio_reconnect_chain(event->object);

break;

case

SERIO_ATTACH_DRIVER:

serio_attach_driver(event->object);

break;

default:

break;

}

serio_remove_duplicate_events(event);

serio_free_event(event);

}

mutex_unlock(&serio_mutex);

}

没错它就是在 serio_event_list

上获得事件,并将其在

serio_event_list

上删除,看下面这个函数:

static struct serio_event

*serio_get_event(void)

{

struct serio_event

*event;

struct list_head

*node;

unsigned long

flags;

spin_lock_irqsave(&serio_event_lock,

flags);

if

(list_empty(&serio_event_list))

{

spin_unlock_irqrestore(&serio_event_lock,

flags);

return

NULL;

}

node =

serio_event_list.next;

event = list_entry(node, struct

serio_event, node);

list_del_init(node);

spin_unlock_irqrestore(&serio_event_lock,

flags);

return

event;

}

获得事件后根据事件的类型作相应的事件处理,一共有五种事件,看下面定义:

enum serio_event_type

{

SERIO_RESCAN_PORT,

SERIO_RECONNECT_PORT,

SERIO_RECONNECT_CHAIN,

SERIO_REGISTER_PORT,

SERIO_ATTACH_DRIVER,

};

对于这些事件我们在用到时再作分析。

处理完事件后调用 serio_remove_duplicate_events(event)

删除链表上具有相同请求的事件,因为在事件被处理前有可能已经多次请求该事件。然后调用

serio_free_event(event)

减少相应的计数,释放其内存空间。

二. serio

设备的注册

先看看 serio

的数据结构:

struct serio

{

void

*port_data;

char

name[32];

char

phys[32];

bool

manual_bind;

bool registered;

struct serio_device_id

id;

spinlock_t lock;

int (*write)(struct serio *, unsigned

char);

int (*open)(struct serio

*);

void (*close)(struct serio

*);

int (*start)(struct serio

*);

void (*stop)(struct serio

*);

struct serio *parent,

*child;

unsigned int

depth;

struct serio_driver

*drv;

struct mutex

drv_mutex;

struct device

dev;

struct list_head

node;

};

该结构包含了 write

open

close

start

stop

函数,这些函数将会在事件处理中用到。

我们接着看 serio

设备的注册函数:

static inline void

serio_register_port(struct serio

*serio)

{

__serio_register_port(serio,

THIS_MODULE);

}

转入 __serio_register_port(serio,

THIS_MODULE) :

void __serio_register_port(struct

serio *serio, struct module *owner)

{

serio_init_port(serio);

serio_queue_event(serio, owner,

SERIO_REGISTER_PORT);

}

先调用 serio_init_port(serio)

进行初始化:

static void

serio_init_port(struct serio

*serio)

{

static atomic_t serio_no =

ATOMIC_INIT(0);

__module_get(THIS_MODULE);

INIT_LIST_HEAD(&serio->node);

spin_lock_init(&serio->lock);

mutex_init(&serio->drv_mutex);

device_initialize(&serio->dev);

dev_set_name(&serio->dev,

"serio%ld",

(long)atomic_inc_return(&serio_no) -

1);

serio->dev.bus =

&serio_bus;

serio->dev.release =

serio_release_port;

if (serio->parent)

{

serio->dev.parent =

&serio->parent->dev;

serio->depth =

serio->parent->depth +

1;

}

else

serio->depth =

0;

lockdep_set_subclass(&serio->lock,

serio->depth);

}

对 serio

的大部分字段初始化以及初始化其内嵌的

dev

,从对

depth

的初始化中可以看出它表示该设备是第几代孩子,如果是第

0

代,其

sysfs

将会在

sys/devices

下。

__serio_register_port()

函数接着调用

serio_queue_event(serio,

owner, SERIO_REGISTER_PORT)

看下这个函数:

static int serio_queue_event(void

*object, struct module *owner,

enum serio_event_type

event_type)

{

unsigned long

flags;

struct serio_event

*event;

int retval =

0;

spin_lock_irqsave(&serio_event_lock,

flags);

list_for_each_entry_reverse(event,

&serio_event_list, node)

{

if (event->object == object)

{

if (event->type ==

event_type)

goto

out;

break;

}

}

event = kmalloc(sizeof(struct

serio_event), GFP_ATOMIC);

if (!event)

{

printk(KERN_ERR

"serio: Not enough memory to queue

event %d/n",

event_type);

retval =

-ENOMEM;

goto

out;

}

if (!try_module_get(owner))

{

printk(KERN_WARNING

"serio: Can't get module reference,

dropping event %d/n",

event_type);

kfree(event);

retval =

-EINVAL;

goto

out;

}

event-> type =

event_type;

event->object =

object;

event->owner =

owner;

list_add_tail(&event->node,

& serio_event_list);

wake_up(&serio_wait);

out:

spin_unlock_irqrestore(&serio_event_lock,

flags);

return

retval;

}

从这个函数首先保存中断状态,关中断并获得

serio_event_lock

自旋锁,接着检查参数

object

代表的

event

是否在链表

serio_event_list

上已经存在,如果存在则退出,否则分配一个

serio_event

内存空间,并用输入参数初始化它的

type

object

owner

字段,并将其加到

serio_event_list

链表尾部,然后唤醒等待列表

serio_wait

,恢复中断和释放锁,这里我们看到,和前面的分析一致。

serio_event

结构体定义如下:

struct serio_event

{

enum serio_event_type

type;

void

*object;

struct module

*owner;

struct list_head

node;

};

对于 serio

设备的注册,在调用

serio_queue_event()

是事件的类型参数为

SERIO_REGISTER_PORT

,我们看看

serio_thread

内核线程中相应的处理:

.

.

switch (event->type)

{

case

SERIO_REGISTER_PORT:

serio_add_port(event->object);

break;

.

.

它将调用 serio_add_port(event->object)

,看一下这个函数:

static void serio_add_port(struct

serio *serio)

{

int

error;

if (serio ->parent)

{

serio_pause_rx(serio->parent);

serio->parent->child =

serio;

serio_continue_rx(serio->parent);

}

list_add_tail(&serio->node,

&serio_list);

if

(serio->start)

serio->start(serio);

error =

device_add(&serio->dev);

if

(error)

printk(KERN_ERR

"serio: device_add() failed for %s

(%s), error: %d/n",

serio->phys, serio->name,

error);

else

{

serio->registered =

true;

error =

sysfs_create_group(&serio->dev.kobj,

&serio_id_attr_group);

if

(error)

printk(KERN_ERR

"serio: sysfs_create_group() failed

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

serio->phys, serio->name,

error);

}

}

如果 serio->

存在,则设置其父子关系,接着调用

list_add_tail(&serio->node,

&serio_list) 将 serio

插入到

serio_list

链表尾部,如果

serio->start

存在,则调用它,然后调用

device_add(&serio->dev)

将其注册到相应的总线上。

删除总线上已注册的 serio

设备要调用

serio_unregister_port

(),函数代码如下:

void serio_unregister_port(struct

serio *serio)

{

mutex_lock(&serio_mutex);

serio_disconnect_port(serio);

serio_destroy_port(serio);

mutex_unlock(&serio_mutex);

}

删除其后代子孙及他们的驱动

关联

,看下相应的函数:

static void

serio_disconnect_port(struct serio

*serio)

{

struct serio *s,

*parent;

if (serio->child)

{

for (s = serio; s->child; s =

s->child)

;

do

{

parent =

s->parent;

device_release_driver(&s->dev);

serio_destroy_port(s);

} while ((s = parent) !=

serio);

}

device_release_driver(&serio->dev);

}

找到最末代的子孙,然后一次往上代删除其驱动

关联

和设备,最后删除

serio

本身驱动

关联

和设备。

device_release_driver()

函数将删除它和

driver

以及

bus

关联

,请参考本站设备模型部分内容。

serio_destroy_port()

函数如下:

static void

serio_destroy_port(struct serio

*serio)

{

struct serio

*child;

child =

serio_get_pending_child(serio);

if (child)

{

serio_remove_pending_events(child);

put_device(&child->dev);

}

if

(serio->stop)

serio->stop(serio);

if (serio->parent)

{

serio_pause_rx(serio->parent);

serio->parent->child =

NULL;

serio_continue_rx(serio->parent);

serio->parent =

NULL;

}

if (serio->registered)

{

sysfs_remove_group(&serio->dev.kobj,

&serio_id_attr_group);

device_del(&serio->dev);

serio->registered =

false;

}

list_del_init(&serio->node);

serio_remove_pending_events(serio);

put_device(&serio->dev);

}

如果 serio_event_list

链表上存在未完成注册的该

serio

的孩子,则先删除它,看下面两个函数:

static struct serio

*serio_get_pending_child(struct serio

*parent)

{

struct serio_event

*event;

struct serio *serio, *child =

NULL;

unsigned long

flags;

spin_lock_irqsave(&serio_event_lock,

flags);

list_for_each_entry(event,

&serio_event_list, node)

{

if (event->type ==

SERIO_REGISTER_PORT) {

serio =

event->object;

if (serio->parent == parent)

{

child =

serio;

break;

}

}

}

spin_unlock_irqrestore(&serio_event_lock,

flags);

return

child;

}

static void

serio_remove_pending_events(void

*object)

{

struct list_head *node,

*next;

struct serio_event

*event;

unsigned long

flags;

spin_lock_irqsave(&serio_event_lock,

flags);

list_for_each_safe(node, next,

&serio_event_list) {

event = list_entry(node, struct

serio_event, node);

if (event->object == object)

{

list_del_init(node);

serio_free_event(event);

}

}

spin_unlock_irqrestore(&serio_event_lock,

flags);

}

这两个函数很容易就看懂,不再分析,接着继续

serio_destroy_port()

,如果

serio->stop

存在,则调用它,也即在设备删除时会调用它,痛上面的

start

函数,我们在编写具体的设备驱动时要编写这些对应的函数,还有另外三个函数

write

open

close

,还后面会分析到。

serio_destroy_port()

接着

serio

断开与它的父设备的关系,删除

group

调用

device_del()

删除内嵌的

device

,清

registered

标志,然后在链表

serio_list

上删除

serio->node

,删除

serio_event_list

链表上与它相关的所有事件请求,最后调用

put_device(&serio->dev)

减少其计数,如果计数为

0

则释放其内存空间。

serio_unregister_port()

分析完了。

接着看 serio_thread

内核线程中对另外四种类型事件的处理,首先看

SERIO_ATTACH_DRIVER

对应的操作:

case

SERIO_ATTACH_DRIVER:

serio_attach_driver(event->object);

break;

serio_attach_driver()

函数如下:

static void

serio_attach_driver(struct serio_driver

*drv)

{

int

error;

error =

driver_attach(&drv->driver);

if

(error)

printk(KERN_WARNING

"serio: driver_attach() failed for %s

with error %d/n",

drv->driver.name,

error);

}

进行一次设备驱动, driver_attach()

将扫面总线上所有的设备,如果和

drv->driver

匹配则将它们关联。

接着看 SERIO_RESCAN_PORT

对应的操作:

case

SERIO_RESCAN_PORT:

serio_disconnect_port(event->object);

serio_find_driver(event->object);

break;

serio_disconnect_port

函数在上面分析

serio_unregister_port()

已经分析,这里不再累赘。

serio_find_driver()

函数如下:

static void

serio_find_driver(struct serio

*serio)

{

int

error;

error =

device_attach(&serio->dev);

if (error <

0)

printk(KERN_WARNING

"serio: device_attach() failed for %s

(%s), error: %d/n",

serio->phys, serio->name,

error);

}

它调用 device_attach()

去匹配总线上的驱动,如果找到合适的驱动就将它们关联,这个函数在本站设备驱动模型的文章中已经详述。

接着看 SERIO_RECONNECT_PORT

对应的操作:

case

SERIO_RECONNECT_PORT:

serio_reconnect_port(event->object);

break;

serio_reconnect_port

() 函数如下:

static int

serio_reconnect_port(struct serio

*serio)

{

int error =

serio_reconnect_driver(serio);

if (error)

{

serio_disconnect_port(serio);

serio_find_driver(serio);

}

return

error;

}

断开 关联 重新匹配驱动。

接着看 SERIO_RECONNECT_CHAIN

对应的操作:

case

SERIO_RECONNECT_CHAIN:

serio_reconnect_chain(event->object);

break;

serio_reconnect_chain

() 函数如下:

static void

serio_reconnect_chain(struct serio

*serio)

{

do

{

if (serio_reconnect_port(serio))

{

break;

}

serio =

serio->child;

} while

(serio);

}

扩充了 SERIO_RECONNECT_PORT

事件,如果

serio

的子孙后代存在,则对它们做相同的操作。

至此,所有的事件处理都分析完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值