环境
- Linux Kernel 5.0
- Source Insight 3.5
- USB Spec 2.0
前言
- USB驱动分析(一)中,初始化并注册USB xHCI Host, 初始化并注册Root Hub, 最终调用hub_driver的
hub_probe()
函数,所以我们这里来分析该函数。
1 hub_probe()函数
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_host_interface *desc;
struct usb_device *hdev;
struct usb_hub *hub;
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
hub = kzalloc(sizeof(*hub), GFP_KERNEL);
hub->intfdev = &intf->dev;
hub->hdev = hdev;
INIT_WORK(&hub->events, hub_event);
//intf->dev->driver_data = hub;
usb_set_intfdata(intf, hub);
hub_configure(hub, &desc->endpoint[0].desc)
}
- 获取usb_host_interface类型的desc, 然后初始化hub, 初始化
hub->events
work,接下来调用hub_configure(). - 初始化hub->events
1.1 hub_configure()函数
static int hub_configure(struct usb_hub *hub,struct usb_endpoint_descriptor *endpoint)
{
struct usb_hcd *hcd;
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
u16 hubstatus, hubchange;
u16 wHubCharacteristics;
unsigned int pipe;
int maxp, ret, i;
unsigned maxchild;
hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL);
ret = get_hub_descriptor(hdev, hub->descriptor);
maxchild = hub->descriptor->bNbrPorts;
hub->ports = kcalloc(maxchild, sizeof(struct usb_port *), GFP_KERNEL);
INIT_WORK(&hub->tt.clear_work, hub_tt_work);
hcd = bus_to_hcd(hdev->bus);
ret = hub_hub_status(hub, &hubstatus, &hubchange);
pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
hub->urb = usb_alloc_urb(0, GFP_KERNEL);
usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);
for (i = 0; i < maxchild; i++) {
ret = usb_hub_create_port_device(hub, i + 1);
}
hdev->maxchild = i;
hub_activate(hub, HUB_INIT);
}
- 获取hub device descriptor,获取hub status。
- 初始化hub->urb为中断类型urb, 当产生中断后,就会调用
hub_irq
。 - 调用usb_hub_create_port_device()创建并初始化usb_port。
- 调用hub_activate();
1.1.1 usb_hub_create_port_device()函数
struct device_type usb_port_device_type = {
.name = "usb_port",
.release = usb_port_device_release,
.pm = &usb_port_pm_ops,
};
static struct device_driver usb_port_driver = {
.name = "usb",
.owner = THIS_MODULE,
};
int usb_hub_create_port_device(struct usb_hub *hub, int port1)
{
struct usb_port *port_dev;
struct usb_device *hdev = hub->hdev;
int retval;
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
port_dev->req = kzalloc(sizeof(*(port_dev->req)), GFP_KERNEL);
hub->ports[port1 - 1] = port_dev;
port_dev->portnum = port1;
port_dev->dev.type = &usb_port_device_type;
port_dev->dev.driver = &usb_port_driver;
dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),port1);
retval = device_register(&port_dev->dev);
}
1.1.2 hub_activate()函数
static void hub_init_func2(struct work_struct *ws){
struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
hub_activate(hub, HUB_INIT2);
}
static void hub_init_func3(struct work_struct *ws){
struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
hub_activate(hub, HUB_INIT3);
}
static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
{
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd;
int ret;
int port1;
int status;
bool need_debounce_delay = false;
unsigned delay;
if (type == HUB_INIT2 || type == HUB_INIT3) {
if (type == HUB_INIT2)
goto init2;
goto init3;
}
if (type != HUB_RESUME) {
if (type == HUB_INIT) {
delay = hub_power_on_good_delay(hub);
hub_power_on(hub, false);
INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
queue_delayed_work(system_power_efficient_wq, &hub->init_work, msecs_to_jiffies(delay));
return;
}
}
init2:
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
struct usb_port *port_dev = hub->ports[port1 - 1];
struct usb_device *udev = port_dev->child;
u16 portstatus, portchange;
portstatus = portchange = 0;
status = hub_port_status(hub, port1, &portstatus, &portchange);
if (portchange & USB_PORT_STAT_C_CONNECTION) {
need_debounce_delay = true;
usb_clear_port_feature(hub->hdev, port1,SB_PORT_FEAT_C_CONNECTION);
}
...
set_bit(port1, hub->change_bits);
...
}
if (need_debounce_delay) {
delay = HUB_DEBOUNCE_STABLE;
if (type == HUB_INIT2) {
INIT_DELAYED_WORK(&hub->init_work, hub_init_func3);
queue_delayed_work(system_power_efficient_wq, &hub->init_work, msecs_to_jiffies(delay));
return;
}
}
init3:
status = usb_submit_urb(hub->urb, GFP_NOIO);
//queue_work(hub_wq, &hub->events);
kick_hub_wq(hub);
}
- 首先HUB_INIT, 使能hub;其次HUB_INIT2, 获取hub port 状态,然后设置状态;最后HUB_INIT3 提交hub->urb;然后提交
hub->events
工作至hub_wq
队列中. 其中hub_wq
是在usb_hub_init()
函数中初始化的
hub_probe()函数总结:
- 初始化hub.
- 初始化并注册hub->urb.
- 初始化并注册hub->events.