Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14480
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2017-10-17 16:13
文章分类
文章存档

2017年(7)

我的朋友

分类: LINUX

2017-10-31 19:18:37

引自帖子 

--
谁能说一下当一个设备插入系统后的过程,产生热插拔,udev,NETLINK,中断? 思路很乱,谁能完整说一下流程啊?从插入设备到在/dev下创建设备结点!

比如都说热插拔是在插入设备时产生的,那么这个热插拔是在创建kobject时产生的还是...希望能说一下流程!

--
USB插入,中断,处理,uevent上报事件 kernel部分完毕(驱动版块有参考)

发现有uevent事件,多了个device设备,创建设备节点,使用者user部分完毕,继续等待其他uevent事件这(该程序在嵌入式版块有参考)

--
没有从源码上仔细看,仅凭“臆测”,来说一下个人的理解;
首先要分清角色,这里有:
① 可插拔外设;
② 总线,如usb;
③ sysfs;
④ netlink;
⑤ udev;
⑥ devfs(对应/dev目录);
分下类,
① 外设驱动、总线驱动、sysfs在内核空间;
② udev运行在用户空间,根据/sys目录的变化来在/dev目录下动态创建设备文件;
③ netlink是用户空间和内核空间通信的方式,其他通信方式还有system call, ioctl, proc filesystem;

至于流程,大致如下:
① 外设插入;
② 总线发现(中断?)新设备,并调用总线驱动查找驱动程序;[“Find a driver that can handle the device” =》 “Bind a driver to that device” =》 “Tell other subsystems to configure the new device.”(参见document/usb/hotplug.txt)]
③ 找到合适的驱动后,会调用device_add,添加新设备到设备管理系统;
④ device_add中会调用kobject_uevent(, KOBJ_ADD),向userspace广播新设备加入event通知;这里发出通知的方式,就是netlink;
⑤ 用户空间运行的daemon(udevd ?或者khubd等转发给udevd?)收到event事件广播;
⑥ udevd根据消息和环境变量,查询/sys的变化,在/dev目录下自动创建设备节点;


>比如都说热插拔是在插入设备时产生的,那么这个热插拔是在创建kobject时产生的还是...
热插拔事件有很多种:

  1. enum kobject_action {
  2.         KOBJ_ADD,
  3.         KOBJ_REMOVE,
  4.         KOBJ_CHANGE,
  5.         KOBJ_MOVE,
  6.         KOBJ_ONLINE,
  7.         KOBJ_OFFLINE,
  8.         KOBJ_MAX
  9. };

--
>⑤ 用户空间运行的daemon(udevd ?或者khubd等转发给udevd?)收到event事件广播;
根据udev(7) manpage:


QUOTE:
The udev daemon udevd( receives device uevents directly from the kernel whenever a device is added or removed
       from the system, or it changes its state.



又khubd属于内核线程,运行在内核空间:
  1. wjcdx@lj:/etc/udev/rules.d$ ps aux | grep khubd
  2. root        29  0.0  0.0      0     0 ?        S    Nov16   0:00 [khubd]
  3. wjcdx     3779  0.0  0.3   4016   768 pts/6    S+   20:05   0:00 grep --color=auto khubd
  4. wjcdx@lj:/etc/udev/rules.d$ 
  5. wjcdx@lj:/etc/udev/rules.d$ 
  6. wjcdx@lj:/etc/udev/rules.d$ 
  7. wjcdx@lj:/etc/udev/rules.d$ ps aux | grep udev
  8. root       263  0.0  0.0   2396   172 ?        S    Nov16   0:00 upstart-udev-bridge --daemon
  9. root       268  0.0  0.0   2628   144 ?        S
  10. root       390  0.0  0.0   2624   148 ?        S<   Nov16   0:00 udevd --daemon
  11. root       407  0.0  0.0   2624   152 ?        S<   Nov16   0:00 udevd --daemon
  12. wjcdx     3781  0.0  0.3   4012   768 pts/6    S+   20:05   0:00 grep --color=auto udev
复制代码
可以看出khubd的进程好是0,而udevd的进程号则不是0;

根据中说:


QUOTE:
在系统初始化的时候在usb_init函数中调用usb_hub_init函数,就进入了hub的初始化。

  在usb_hub_init函数中完成了注册hub驱动,并且利用函数kthread_run创建一个内核线程。该线程用来管理监视hub的状态,所有的情况都通过该线程来报告。


可以猜测,khubd内核线程负责向udevd报告usb hub的所有状态改变;

证诸内核代码:
  1. int usb_hub_init(void)
  2. {
  3. ***
  4.         khubd_task = kthread_run(hub_thread, NULL, "khubd");
  5. ***        
  6. }
复制代码
hub_thread()->hub_events()->hub_port_connect_change()->usb_new_device()->device_add()->kobject_uevent();

--
QUOTE:
Usually, when you run ps -aux and look at the khubd process,
you see that it is sleeping, denoted by the letter S. When we plug a USB device
into the USB port, the hardware layer initiates an interrupt; we reach the hub_irq() method.
The hub data, represented by struct usb_hub, is passed to the hub_irq() method
as part of the URB, the context member of struct urb.

A global list of hub events, called hub_event_list, is available. If
this list is empty, we add an event to this list, so that the khubd thread
can handle it. We also call wake_up(&khubd_wait), as khubd is in waiting status.
Waking up causes us to call hub_events().


From

还剩下一个问题,就是如果设备的驱动是在设备插入时动态加载的,那这个加载过程,处在这一个过程的哪一个位置?

--
回复  wangjianchangdx 

device_add():
  1. kobject_uevent(&dev->kobj, KOBJ_ADD);
  2.         bus_probe_device(dev);
复制代码
可以看出是先发出event事件,后为device probe driver;
细细想来,udev的功能与驱动没必然关系:udev可以probe driver,也可以不加载,看udev规则高兴;调用udev之前可以有driver,反之亦可;

udev的功能,引自udev(7) manpage:

QUOTE:
      udev provides a dynamic device directory containing only the files for actually present devices. It creates or removes device node files in the /dev directory, or it renames network interfaces.

       Usually udev runs as udevd(8) and receives uevents directly from the kernel if a device is added or removed from the system.

       If udev receives a device event, it matches its configured rules against the available device attributes provided in sysfs to identify the device. Rules that match may provide additional device information or specify a device node name and multiple symlink names and instruct udev to run additional programs as part of the device event handling.


没有明显的说明是否probe driver,但它的主要功能如上面粗体部分,而不是probe driver;
没有找到驱动的设备,就不能创建设备文件了吗?答案当然是可以。

所以,上面所说的过程可以去除driver部分,简化如下:
① 外设插入;
② 总线发现(中断? usb有中断hub_irq,pci的中断没找到)新设备,调用device_add,添加新设备到设备管理系统;
③ device_add中调用kobject_uevent(, KOBJ_ADD),向userspace广播新设备加入event通知;这里发出通知的方式,就是netlink;
④ 用户空间运行的daemon(udevd)收到event事件广播;
⑤ udevd根据消息和环境变量,查询/sys的变化,按照规则(/etc/udev/rules.d/*),在/dev目录下自动创建设备节点;

以上,多所臆测,还望知者指教!

--
同时可以总结,设备插入系统时,相应驱动的关联情况:
① 若直接编译进内核或在启动时加载,则无需在udev中加载驱动模块,在bus_probe_device()中会为其找到相应的驱动;
② 若驱动需要动态加载,则需要在udev(目前的情况是这样,以前也有其他方式如/sbin/hotplug,cardmgr等)中,动态加载其驱动,在驱动的register函数中,找到该device进行关联;

--
现在的devtmpfs又变回去了,device_add的时只要有major number就会为其生成一个结点。不知道跟udev是怎么配合的。


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