Chinaunix首页 | 论坛 | 博客
  • 博客访问: 976784
  • 博文数量: 109
  • 博客积分: 554
  • 博客等级: 中士
  • 技术积分: 2577
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 12:49
文章分类

全部博文(109)

文章存档

2019年(5)

2016年(7)

2015年(9)

2014年(1)

2013年(71)

2012年(16)

分类: 嵌入式

2013-08-08 15:25:24

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);

 

       /*

         * Note that we handle only one event here to give swsusp

         * a chance to freeze kseriod thread. Serio events should

         * be pretty rare so we are not concerned about taking

         * performance hit.

         */

       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;      /* port has been fully registered with driver core */

 

       struct serio_device_id id;

 

       spinlock_t lock;             /* protects critical sections from port's interrupt handler */

 

       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;        /* level of nesting in serio hierarchy */

 

       struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */

       struct mutex drv_mutex;              /* protects serio->drv so attributes can pin driver */

 

       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);

 

       /*

         * Scan event list for the other events for the same serio port,

         * starting with the most recent one. If event is the same we

         * do not need add new one. If event is of different type we

         * need to add this event and should not look further because

         * we need to preseve sequence of distinct events.

         */

       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) {

              /*

                * Children ports should be disconnected and destroyed

                * first, staring with the leaf one, since we don't want

                * to do recursion

                */

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

                     /* empty */;

 

              do {

                     parent = s->parent;

 

                     device_release_driver(&s->dev);

                     serio_destroy_port(s);

              } while ((s = parent) != serio);

       }

 

       /*

         * Ok, no children left, now disconnect this port

         */

       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)) {

                     /* Ok, old children are now gone, we are done */

                     break;

              }

              serio = serio->child;

       } while (serio);

}

扩充了 SERIO_RECONNECT_PORT 事件,如果 serio 的子孙后代存在,则对它们做相同的操作。

 

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

 

接下一篇文章分析。

阅读(6241) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~