USB 设备驱动之设备接入梳理(一)

hub_event()的前世今生

缘起 usb_hub_init()

主要是注册hub驱动和创建工作队列

注册hub驱动:

if (usb_register(&hub_driver) < 0) {

        printk(KERN_ERR "%s: can't register hub driver\n",

            usbcore_name);

        return -1;

    }

这里引入usb_driver 结构体,先看看hub是如何初始化的

static struct usb_driver hub_driver = {
	.name =		"hub",
	.probe =	hub_probe,
	.disconnect =	hub_disconnect,
	.suspend =	hub_suspend,
	.resume =	hub_resume,
	.reset_resume =	hub_reset_resume,
	.pre_reset =	hub_pre_reset,
	.post_reset =	hub_post_reset,
	.unlocked_ioctl = hub_ioctl,
	.id_table =	hub_id_table,
	.supports_autosuspend =	1,
};

创建hub工作队列

hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);
	if (hub_wq)
		return 0;

probe函数促使其修成正果

hub_probe函数:简单来说如果是支持的hub,则对其进行分配内存、初始化和初始化。对于hub_event部分,就一句,但对以后有着深远的影响,因为这里是hub接入其他设备的入口。

	INIT_WORK(&hub->events, hub_event);

而hub_irq()函数则是决定是否能进入到该入口。且看下面一 一道来

if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
		return 0;

配置整个hub的同时,也在向host注册一些信息,比如,发生中断传输就找他——hub_irq()

usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
		hub, endpoint->bInterval);

Hub 也疯狂

经过以上的注册、porb、config,hub算是能正常的工作了。如果一个设备接入hub,又该如何run起来呢?刚才也说明了irq是入口,看看为啥这么认为

参数是urb,中断哪里的urb?肯定是host过来的,将中断信息保存到urb的buffer中传递过来,irq整合数据后唤醒hub workqueue

for (i = 0; i < urb->actual_length; ++i)
			bits |= ((unsigned long) ((*hub->buffer)[i]))
					<< (i*8);
		hub->event_bits[0] = bits;
/* Something happened, let hub_wq figure it out */
	kick_hub_wq(hub);

kick_hub_wq唤醒hub_event

if (queue_work(hub_wq, &hub->events))
		return;

踏平坎坷成大道

斗罢艰险又出发,又出发!hub_event() 函数,首先是一系列的判断,作为运行在各大平台的操作系统,必须严谨,先判断是否是自身hub引发的中断,是不是电压不稳引起的异常,当然还判断该hub是否是正常工作的。如果都不是其他因素引起的异常,那就遍历hub端口,找到发生状态改变的端口,进行处理。在hub_irq中就将状态都装入event_bits中,所以这里遍历找到对应的事件。

/* deal with port status changes */
	for (i = 1; i <= hdev->maxchild; i++) {
		struct usb_port *port_dev = hub->ports[i - 1];

		if (test_bit(i, hub->event_bits)
				|| test_bit(i, hub->change_bits)
				|| test_bit(i, hub->wakeup_bits)) {
			/*
			 * The get_noresume and barrier ensure that if
			 * the port was in the process of resuming, we
			 * flush that work and keep the port active for
			 * the duration of the port_event().  However,
			 * if the port is runtime pm suspended
			 * (powered-off), we leave it in that state, run
			 * an abbreviated port_event(), and move on.
			 */
			pm_runtime_get_noresume(&port_dev->dev);
			pm_runtime_barrier(&port_dev->dev);
			usb_lock_port(port_dev);
			port_event(hub, i);
			usb_unlock_port(port_dev);
			pm_runtime_put_sync(&port_dev->dev);
		}
	}

从这个for循环可以得出:

1.event_bits 、change_bits、wakeup_bits中的每一个bits对应一个port的状态,针对这点,hub的spec中有描述

2. hub最多支持8个port

 

找到有变化的端口后,进行电源设置,然后进入port_event()函数,下一节继续梳理port_event。

 

 

 

 

 

 

 

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值