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

    技术2025-09-14  109

    ric Fang  2010-01-19

    --------------------------------------------------------------

    本站分析linux内核源码,版本号为2.6.32.3

    转载请注明出处:http://ericfang.cublog.cn/

    --------------------------------------------------------------

     

    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;

    };

    该结构包含了writeopenclosestartstop函数,这些函数将会在事件处理中用到。

    我们接着看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内存空间,并用输入参数初始化它的typeobjectowner字段,并将其加到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函数,我们在编写具体的设备驱动时要编写这些对应的函数,还有另外三个函数writeopenclose,还后面会分析到。

    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的子孙后代存在,则对它们做相同的操作。

     

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

     

    接下一篇文章分析。

    最新回复(0)