Linux USB驱动分析(二)

环境

  • 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->eventswork,接下来调用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.
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值