Linux usb hub阅读
可以阅读usb-skeleton.c文件,简单的一个usb设备驱动程序的框架
ROOT_HUB:
usb设备的初始化都是hub这边发起的,我们写一个usb设备驱动是已经在得到一个struct usb_interface指针的情况下开始probe工作的
通常芯片会把host controller和root hub集成在一起
从usb子系统的初始化开始,core/usb.c:
subsys_initcall(usb_init);
module_exit(usb_exit);
使用subsys_initcall宏是因为这块代码比较核心,看作一个子系统,代表一类设备,这里是这模块真正的初始化函数
usb_hub_init:
1、向usb core注册一个usb hub驱动
2、起一个线程或者workqueue,khubd
IS_ERR():
判断指针的,每次调用kthread_run之后使用IS_ERR来判断指针是否有效,不然有可能会发生缺页异常
内核空间:所有驱动程序都运行在内核空间,最后一个page专门保留的,不可以使用,是用来放linux内核中的错误码的,所以使用IS_ERR来判断指针是否出错,可以用PTR_ERR宏接口来返回错误码
子进程hub_thread:
LIST_HEAD:
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
struct list_head {
struct list_head *next, *prev;
};
定义了一个struct list_head的结构体,hub_event_list,而且两个指针next和prev分别指向自己,就是建立了一个双向链表并做了初始化,初始化成一个空队列,对于这个队列有很多函数可以操作,比如:list_empty、list_add_tail等等;
#define list_entry(ptr, type, member) container_of(ptr, type, member)
一个struct usb_hub代表一个hub,每个usb_hub都有一个event_list事件链表,但hub驱动只有一个,所以所有的event_list都要挂接到全局的hub_event_list中,所以判断hub_event_list是否为空,不为空就去hub_events函数,那如何确定具体是哪个hub出发了事件呢:list_entry来从event_list中得到它所对应的usb_hub结构体变量
struct list_head *tmp; 一个list
struct usb_hub *hub; 一个hub
tmp = hub_event_list.next; 一个list
hub = list_entry(tmp, struct usb_hub, event_list); 从全局链表hub_event_list中取出一个list来,叫做tmp,然后通过tmp获得它对应的struct usb_hub变量
总分总思想:
总:设置一个总的函数hub_events。一个链表 hub_event_list
分:每一个hub都有一个event_list,每当一个hub的event_list发生了变化,就插入到hub_event_list
总:触发函数hub_events
分:hub_events函数中根据event_list来确定是哪个hub有事情,并处理
try_to_freeze:
检测TIF_FREEZE这个flag有没有被设置,TF就是thread info
hub_events:
kzalloc:是kmalloc和memset函数的结合体
对于root_hub,在host控制器HC启动时它会初始化并调用probe进入hub_events
对于普通hub,要建立并初始化一个usb设备的struct usb_interface,至于probe何时调用,继续:
INIT_WORK schedule_work、INIT_DELAY_WORK schedule_delayed_work:工作队列
关于工作队列