五、从usb的插入开始

当usb设备插入接口,电压变化会通知到usb主控器,

触发主控器中断,如果主控器不支持中断,那么会使用rh_timer方法,轮询接口

其结果都是调用usb_hcd_poll_rh_status

void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
{
	struct urb	*urb;
	int		length;
	unsigned long	flags;
	char		buffer[6];	/* Any root hubs with > 31 ports? */

	if (unlikely(!hcd->rh_pollable))
		return;
	if (!hcd->uses_new_polling && !hcd->status_urb)
		return;

	length = hcd->driver->hub_status_data(hcd, buffer);	//获取urb数据长度
	if (length > 0) {

		/* try to complete the status urb */
		spin_lock_irqsave(&hcd_root_hub_lock, flags);
		urb = hcd->status_urb;	//获取要处理的urb
		if (urb) {
			clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);	//清除urb主控器poll标志
			hcd->status_urb = NULL;	//清空待处理urb
			urb->actual_length = length;	//获取urb数据长度
			memcpy(urb->transfer_buffer, buffer, length);	//复制urb缓冲区

			usb_hcd_unlink_urb_from_ep(hcd, urb);	//从主控器的端点上解绑urb
			spin_unlock(&hcd_root_hub_lock);
			usb_hcd_giveback_urb(hcd, urb, 0);	//处理urb并回传urb给设备
			spin_lock(&hcd_root_hub_lock);
		} else {
			length = 0;
			set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
		}
		spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
	}
	if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :
			(length == 0 && hcd->status_urb != NULL))
		mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
}

usb_hcd_giveback_urb函数

void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
	urb->hcpriv = NULL;
	if (unlikely(urb->unlinked))
		status = urb->unlinked;
	else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
			urb->actual_length < urb->transfer_buffer_length &&
			!status))
		status = -EREMOTEIO;

	unmap_urb_for_dma(hcd, urb);
	usbmon_urb_complete(&hcd->self, urb, status);
	usb_unanchor_urb(urb);

	/* pass ownership to the completion handler */
	urb->status = status;
	urb->complete (urb);		//执行urb回调函数,就是hub_irq
	atomic_dec (&urb->use_count);
	if (unlikely(atomic_read(&urb->reject)))
		wake_up (&usb_kill_urb_queue);
	usb_put_urb (urb);
}

hub_irq函数

static void hub_irq(struct urb *urb)
{
	struct usb_hub *hub = urb->context;
	int status = urb->status;
	unsigned i;
	unsigned long bits;

	switch (status) {
	case -ENOENT:
	case -ECONNRESET:
	case -ESHUTDOWN:
		return;
	default:	//错误
		dev_dbg (hub->intfdev, "transfer --> %d\n", status);
		if ((++hub->nerrors < 10) || hub->error)
			goto resubmit;
		hub->error = status;
	case 0:	//端口状态有变化
		bits = 0;
		for (i = 0; i < urb->actual_length; ++i)
			bits |= ((unsigned long) ((*hub->buffer)[i]))<< (i*8);
		hub->event_bits[0] = bits;	//填充hub->event_bit数组
		break;
	}

	hub->nerrors = 0;
	kick_khubd(hub);	//调用kick_khubd函数
resubmit:
	if (hub->quiescing)
		return;
	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0&& status != -ENODEV && status != -EPERM)
		dev_err (hub->intfdev, "resubmit --> %d\n", status);
}

kick_khubd函数

static void kick_khubd(struct usb_hub *hub)
{
	unsigned long	flags;
	spin_lock_irqsave(&hub_event_lock, flags);
	if (!hub->disconnected && list_empty(&hub->event_list)) {
		list_add_tail(&hub->event_list, &hub_event_list);
		usb_autopm_get_interface_no_resume(to_usb_interface(hub->intfdev));
		wake_up(&khubd_wait);	//唤醒khubd_wait相关的等待队列
	}
	spin_unlock_irqrestore(&hub_event_lock, flags);
}

这里会触发hub_events函数,原因如下

	do {
		hub_events();
		wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) ||kthread_should_stop());
	} while (!kthread_should_stop() || !list_empty(&hub_event_list));

hub_events函数

static void hub_events(void)
{
	struct list_head *tmp;
	struct usb_device *hdev;
	struct usb_interface *intf;
	struct usb_hub *hub;
	struct device *hub_dev;
	u16 hubstatus;
	u16 hubchange;
	u16 portstatus;
	u16 portchange;
	int i, ret;
	int connect_change;
	//hcd usb主控器的状态由usb主控器的中断例程根据具体硬件状态去设置
	while (1) {
		spin_lock_irq(&hub_event_lock);
		//这次执行假设usb主控器已经注册
		if (list_empty(&hub_event_list)) {	//usb事件链表不为为空
			spin_unlock_irq(&hub_event_lock);
			break;	
		}
		tmp = hub_event_list.next;	//拿出hub_event链表项	
		list_del_init(tmp);	//从hub_event_list删除其
		hub = list_entry(tmp, struct usb_hub, event_list);	//根据链表项获取usb_hub	
		kref_get(&hub->kref);	//引用计数
		spin_unlock_irq(&hub_event_lock);
		hdev = hub->hdev;		//获取hub usb设备
		hub_dev = hub->intfdev;	//获取hub 设备文件
		intf = to_usb_interface(hub_dev);	//获取hub usb接口
		usb_lock_device(hdev);
		if (unlikely(hub->disconnected))
			goto loop_disconnected;
		if (hdev->state == USB_STATE_NOTATTACHED) {	//判断是否为USB_STATE_NOTATTACHED状态
			hub->error = -ENODEV;
			hub_quiesce(hub, HUB_DISCONNECT);
			goto loop;
		}
		ret = usb_autopm_get_interface(intf);
		if (ret) {
			dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
			goto loop;
		}
		if (hub->quiescing)
			goto loop_autopm;
		if (hub->error) {
			dev_dbg (hub_dev, "resetting for error %d\n",hub->error);
			ret = usb_reset_device(hdev);	
			if (ret) {
				dev_dbg (hub_dev,"error resetting hub: %d\n", ret);
				goto loop_autopm;
			}
			hub->nerrors = 0;
			hub->error = 0;
		}
		for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
			if (test_bit(i, hub->busy_bits))
				continue;
			connect_change = test_bit(i, hub->change_bits);	//判断是否hub口状态变化
	
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值