精华内容
下载资源
问答
  • USB HUB简述

    千次阅读 2021-03-23 16:01:19
    一般来说,一块hub桥接芯片可扩展4个usb接口,而市面上的一拖七hub,其实使用了两块hub桥接芯片,其中一块hub桥接芯片的上行端口连接到另一块hub桥接芯片的下行端口。 hub的上行端口面向host,下行端口面向device。...

    概述

    在这里插入图片描述
    hub,集线器,连接在host与device之间的一种用于usb接口扩展的usb设备。可以将一个usb上行接口扩展为多个下行接口,使得一个host可以同时与多个device连接。

    一般来说,一块hub桥接芯片可扩展4个usb接口,而市面上的一拖七hub,其实使用了两块hub桥接芯片,其中一块hub桥接芯片的上行端口连接到另一块hub桥接芯片的下行端口。
    在这里插入图片描述
    hub的上行端口面向host,下行端口面向device。在下行端口上,hub提供了设备接入检测和设备移除检测的能力,并给下行端口供电。hub可单独使能各下行端口。不同的端口可工作在不同的速度(H/F/L)。

    数据传输

    在这里插入图片描述
    在这里插入图片描述
    host与hub之间使用的还是high speed bus,而hub与device之间使用的是full/low speed bus。

    host-hub间的数据流:
    在这里插入图片描述
    hub-device间的数据流:
    在这里插入图片描述
    需要注意的是,host与hub之间的IN数据流,在complete split阶段的data0之后,是没有handshake的,但hub与device之间还是有handshake的。

    SPLIT-分离传输

    分离传输仅在host和hub之间执行,通过分离传输,可以允许全速/低速设备连接到高速主机。

    分离传输对于device来说是透明的不可见的。

    分离传输:将一次完整的事务传输,拆分成两个事务传输。其出发点是高速传输和全速/低速传输的速度不相等,如果使用一次完整的事务来传输,势必会造成比较长的等待时间,从而降低了高速USB总线的利用率。通过将一次传输分成两次,将令牌(和数据)的传输与响应数据(和握手)的传输分开,这样可以在中间插入其他高速传输,从而提高总线的利用率

    在这里插入图片描述
    分离传输将一次完整的IN请求事务拆分为两次事务传输,分别为发送令牌包的SSPLIT事务传输、接收数据包的CSPLIT事务传输。
    在SSPLIT与CSPLIT之间,可以插入了一次其他device的IN请求。也就是说,分离传输允许在不超过最大响应时间的前提下,分离传输的两次事务之间可以适当插入其他的传输事务,提高总线利用率。

    1)SSPLIT-start split
    在这里插入图片描述
    PID:0~3 bit为包标识字段的包类型,4~7 bit为包类型字段的校验补码。
    在这里插入图片描述
    Hub address:支持指定的全速/低速设备的hub的设备地址,用于全速/低速事务。
    SC:start/complete,为0时表示SPLIT传输事务的SSPLIT。为1时,表示SPLIT传输事务的CSPLIT。
    Hub port:全速/低速事务所针对的目标中心的端口号,即对应hub的端口号。
    S:speed,此中断或控制事务的速度。S为1时,低速。S为0时,全速。
    E:在块传输、中断传输和控制传输中,无须传输方向,所以E置为“0”。对于同步传输,如果是IN传输则E=0,如果是OUT传输,则按下表进行选择。
    在这里插入图片描述
    ET:Endpoint type,当前端点的传输类型,不同值代表的如下。

    在这里插入图片描述
    CRC-5:循环冗余校验。

    2)CSPLIT-complete split

    在这里插入图片描述
    U字段:值固定为“0”,保留。其他字段同上。

    控制传输(SPLIT)

    SPLIT的控制传输事务根据数据流方向分为两种,OUT传输事务和IN传输事务。
    在这里插入图片描述
    SPLIT控制传输OUT事务示意:
    在这里插入图片描述
    SPLIT控制传输IN事务示意:
    在这里插入图片描述

    中断传输(SPLIT)

    在这里插入图片描述
    SPLIT中断传输事务示意:
    在这里插入图片描述
    host发送IN请求后,device没有准备好数据时,给host回复NAK。当device已经准备好数据,IN请求后,device上传数据给host,host接收后回复ACK。

    块传输(SPLIT)

    同步传输(SPLIT)

    展开全文
  • 枚举 USB HUB 设备

    2017-08-11 18:55:57
    枚举所有的USB设备,多层枚举
  • USB HUB芯片

    2014-12-01 10:15:32
    美国SMSC的USB HUB解决方案,功耗低,价格低,但是很好用。
  • USB Hub原理图

    2015-10-24 18:25:00
    USB 2.0 USB Hub原理图,外围物料精简。免晶体。
  • usbhub2.0万能驱动是一个驱动的usb驱动程序,基本匹配usb2.0hub系列的配件所需要安装的驱动,支持xp/win7/win8等操作系统,安装后可以让电脑快速的识别usbhub2.0设备,欢迎下载使用。什么是usb2.0USB...
  • USB HUB 4层板经典布局

    2018-06-14 17:28:14
    布局合理,也充分考虑了差分线的阻抗匹配等问题,很有参考价值
  • USBhub芯片

    2018-06-02 18:10:24
    USB hub芯片,需要多USB设备连接的可以开发自己的USB hub
  • USB HUB FE1.1 数据手册

    2018-06-06 14:55:27
    USB扩展接口USB HUB FE1.1 芯片资料,网上不好找,大家可以看看
  • USB3803 carplay usb hub

    2018-09-30 11:36:16
    USB 2.0 High-Speed Hub Controller Optimized for Portable Applications
  • FE2.1 ,USB HUB资料

    热门讨论 2014-07-21 15:05:31
    usb hub fe2.1 的资料,不仅仅是datasheet ,还包括参考原理图,可以直接参考使用,可不是百度文库里的烂资料
  • UsbHub_FE1.1s_Sch_Pcb(USB2.0Hub量产FE1.1s含原理图PCB图).rar 量产的电路图资料(含原理图PCB图),欢迎下载。
  • usbhub原理图

    2017-09-14 10:04:41
    usbhub原理图。USB集线器是解决电脑USB口不够而设计。1个USB口扩展出4个。支持所有操作系统。电路简单,可以参考一下。容易DIY。无需固件。
  • GL850 4端口USBHUB板ALTIUM设计硬件原理图PCB工程文件,包括完整的原理图PCB文件,板子大小为85x40mm,2层板。可用Altium Designer(AD)软件打开或修改,已经制板验证使用,可作为你产品设计的参考。
  • USB_HUB硬件电路引脚原理解析,与个人博文一致,这是word版本。 USB_HUB硬件电路引脚原理解析,与个人博文一致,这是word版本。
  • USB2422 USB HUB

    2018-09-30 11:37:37
    The Microchip USB2422 hub is a low-power, single transaction translator, hub controller IC with two downstream ports for embedded USB solutions. The hub controller can attach to an upstream port as a ...
  • VL822主控方案 USB HUB 1拖4原理图,高清pdf格式。HUB可以用来扩展USB接口数量,解决USB接口不够用的情况。
  • 文件内包含了几个厂商的USB hub的电路原理图,同时也有在网上收集的。 文件内包含了几个厂商的USB hub的电路原理图,同时也有在网上收集的。
  • 1拖7 USB HUB设计原理图

    2013-07-23 18:59:59
    如题,用于USB扩展设计,电路原理图经过调试、制成应用电路板,使用正常。
  • USB 2.0 HUB集线器设计

    2020-10-14 14:11:45
    USB 2.0 HUB集线器设计
  • USB HUB芯片型号汇总及主要参数 USB HUB的设计思路和解决方案
  • USB2514i USB HUB及其应用

    2021-02-01 04:09:23
    介绍了USB2514i的主要特性、内部结构和功能。采用USB2514i设计了一款具有1个USB上行端口、4个USB下行端口的工业级USB2.0 集线器,该集线器可支持USB2.0协议的USB设备的扩展,并给出了硬件电路和PCB设计。
  • USB2.0 HUB原理图+PCB文件,一扩7口的USB 2.0 HUB,分享资源。
  • usb hub驱动

    千次阅读 2018-03-25 00:32:29
    hub驱动初始化 retval = usb_hub_init(); int usb_hub_init(void) { if (usb_register(&hub_driver) < 0) { //注册hub驱动到usb子系统总线上 printk(KERN_ERR "%s: can't register hub ...

    1. hub驱动流程图


    2. hub驱动初始化

    	retval = usb_hub_init(); 
    int usb_hub_init(void)
    {
    	if (usb_register(&hub_driver) < 0) { //注册hub驱动到usb子系统总线上
    		printk(KERN_ERR "%s: can't register hub driver\n",
    			usbcore_name);
    		return -1;
    	}
    
    	khubd_task = kthread_run(hub_thread, NULL, "khubd"); //创建hub内核线程
    	if (!IS_ERR(khubd_task))
    		return 0;
    
    	/* Fall through if kernel_thread failed */
    	usb_deregister(&hub_driver);
    	printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
    
    	return -1;
    }

    usb_hub_init()函数主要包括两个方面,1. hub驱动注册, 2. hub线程创建,接下来将主要围绕他俩进行分析。

    3. hub驱动注册

    if (usb_register(&hub_driver) < 0) { //注册hub驱动到usb子系统总线上

    在分析usb_register()函数前先看下hub_driver结构体:

    static struct usb_driver hub_driver = {
    	.name =		"hub",
    	.probe =	hub_probe, //hub探测接口,重要,待分析!
    	.disconnect =	hub_disconnect,
    	.suspend =	hub_suspend, //hub挂起,涉及到PM电源管理驱动控制
    	.resume =	hub_resume, //hub恢复,
    	.reset_resume =	hub_reset_resume, //通过对hub复位来引发复位
    	.pre_reset =	hub_pre_reset, //与PM电源管理系统相关
    	.post_reset =	hub_post_reset, //与PM电源管理系统相关
    	.unlocked_ioctl = hub_ioctl,
    	.id_table =	hub_id_table, //hub id表,重要,待分析!!
    	.supports_autosuspend =	1,
    };
    

    hub_id_table 对应结构体 struct usb_device_id:

    struct usb_device_id {
    	/*表示下面哪些字段(产品、设备类别、接口类)可以进行匹配*/
    	/* which fields to match against? */
    	__u16		match_flags; 
    
    	/*用于产品的匹配*/
    	/* Used for product specific matches; range is inclusive */
    	__u16		idVendor;
    	__u16		idProduct;
    	__u16		bcdDevice_lo;
    	__u16		bcdDevice_hi;
    
    	/*用于设备类别的匹配*/
    	/* Used for device class matches */
    	__u8		bDeviceClass;
    	__u8		bDeviceSubClass;
    	__u8		bDeviceProtocol;
    
    	/*用于接口类别的匹配*/
    	/* Used for interface class matches */
    	__u8		bInterfaceClass;
    	__u8		bInterfaceSubClass;
    	__u8		bInterfaceProtocol;
    
    	/* Used for vendor-specific interface matches */
    	__u8		bInterfaceNumber;
    
    	/* not matched against */
    	kernel_ulong_t	driver_info
    		__attribute__((aligned(sizeof(kernel_ulong_t))));
    }

    而hub_id_table 分别初始化了三个usb_device_id结构体:

    static const struct usb_device_id hub_id_table[] = {
        { .match_flags = USB_DEVICE_ID_MATCH_VENDOR  //
    	           | USB_DEVICE_ID_MATCH_INT_CLASS,
          .idVendor = USB_VENDOR_GENESYS_LOGIC,
          .bInterfaceClass = USB_CLASS_HUB,
          .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
        { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
          .bDeviceClass = USB_CLASS_HUB},
        { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
          .bInterfaceClass = USB_CLASS_HUB},
        { }						/* Terminating entry */
    };

    第1个结构体成员

    .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS, //表示需匹配的字段 

     .idVendor = USB_VENDOR_GENESYS_LOGIC, //匹配的字段
     .bInterfaceClass = USB_CLASS_HUB //匹配的字段


    第2个结构体成员

    .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, //表示需匹配的字段

    .bDeviceClass = USB_CLASS_HUB //匹配的字段

    第3个结构体成员

    .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,  //表示需匹配的字段
    .bInterfaceClass = USB_CLASS_HUB //匹配的字段

    综上所述,match_flags 表示哪些字段匹配,而对应匹配的字段就是idVendor 、bInterfaceClass ,bDeviceClass ,bInterfaceClass ,这里在下面会分析如何使用。

    hub_probe()函数内容太多,我将它放到第4.节分析函数内部细节。

    现在我们继续回到hub驱动注册:

    #define usb_register(driver) \
    	usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
    int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
    			const char *mod_name)
    {
    	int retval = 0;
    
    	if (usb_disabled())
    		return -ENODEV;
    
    	//对drvwrap USB驱动包初始化
    	new_driver->drvwrap.for_devices = 0;
    	new_driver->drvwrap.driver.name = (char *) new_driver->name; //初始化驱动名称为“hub”
    	new_driver->drvwrap.driver.bus = &usb_bus_type; //绑定总线类型为子系统usb
    	new_driver->drvwrap.driver.probe = usb_probe_interface; //重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
    	new_driver->drvwrap.driver.remove = usb_unbind_interface;
    	new_driver->drvwrap.driver.owner = owner;
    	new_driver->drvwrap.driver.mod_name = mod_name;
    	spin_lock_init(&new_driver->dynids.lock);
    	INIT_LIST_HEAD(&new_driver->dynids.list);
    
    	retval = driver_register(&new_driver->drvwrap.driver); //驱动注册
    	if (retval)
    		goto out;
    
    	retval = usb_create_newid_files(new_driver);
    	if (retval)
    		goto out_newid;
    
    	pr_info("%s: registered new interface driver %s\n",
    			usbcore_name, new_driver->name);
    
    out:
    	return retval;
    
    out_newid:
    	driver_unregister(&new_driver->drvwrap.driver);
    
    	printk(KERN_ERR "%s: error %d registering interface "
    			"	driver %s\n",
    			usbcore_name, retval, new_driver->name);
    	goto out;
    }
    EXPORT_SYMBOL_GPL(usb_register_driver);

    usb_register_driver()函数内部主要涉及到两个函数,驱动注册driver_register()和newid文件创建usb_create_newid_files(),接下来将逐个分析:

    driver_register():

    int driver_register(struct device_driver *drv)
    {
    	int ret;
    	struct device_driver *other;
    
    	BUG_ON(!drv->bus->p);
    
    	if ((drv->bus->probe && drv->probe) ||
    	    (drv->bus->remove && drv->remove) ||
    	    (drv->bus->shutdown && drv->shutdown))
    		printk(KERN_WARNING "Driver '%s' needs updating - please use "
    			"bus_type methods\n", drv->name);
    
    	other = driver_find(drv->name, drv->bus); //这里查找drv->name="hub"驱动是否已经在drv->bus总线上注册。
    	if (other) {
    		printk(KERN_ERR "Error: Driver '%s' is already registered, "
    			"aborting...\n", drv->name);
    		return -EBUSY;
    	}
    
    	ret = bus_add_driver(drv); //bus总线上注册驱动
    	if (ret)
    		return ret;
    	ret = driver_add_groups(drv, drv->groups);
    	if (ret) {
    		bus_remove_driver(drv);
    		return ret;
    	}
    	kobject_uevent(&drv->p->kobj, KOBJ_ADD);
    
    	return ret;
    }
    EXPORT_SYMBOL_GPL(driver_register);

    bus_add_driver() usb总线上添加hub驱动:

    int bus_add_driver(struct device_driver *drv)
    {
    	struct bus_type *bus;
    	struct driver_private *priv;
    	int error = 0;
    
    	bus = bus_get(drv->bus); //drv->bus=&usb_bus_type, bus为usb_bus_type
    	if (!bus)
    		return -EINVAL;
    
    	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
    
    	priv = kzalloc(sizeof(*priv), GFP_KERNEL); //分配一个驱动私有数据driver_private
    	if (!priv) {
    		error = -ENOMEM;
    		goto out_put_bus;
    	}
    	klist_init(&priv->klist_devices, NULL, NULL); //初始化设备链表
    	//以下相互绑定
    	priv->driver = drv; //私有驱动数据绑定drv
    	drv->p = priv; //drv->p驱动绑定priv
    	priv->kobj.kset = bus->p->drivers_kset; //将priv->kobj.kset当前内核集合指向bus->p->drivers_kset内核集合(该集合在usb总线注册bus_register()描述)
    	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
    				     "%s", drv->name);
    	if (error)
    		goto out_unregister;
    
    	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将当前注册的priv->knode_bus节点加入到全局bus->p->klist_drivers链表中
    	if (drv->bus->p->drivers_autoprobe) { //在usb总线注册时对该变量drivers_autoprobe初始化为1了
    		error = driver_attach(drv); //见下面,按照内核启动的流程分析,这个时候usb总线上只有hub这个驱动,没有设备,所以driver_attach函数将返回失败
    		if (error)
    			goto out_unregister;
    	}
    	module_add_driver(drv->owner, drv); //见下面,从该函数这开始,本次hub驱动将不会执行下面的函数了,不过为了分析函数内部的功能,我们继续,因为在其他驱动模块注册时会用到
    
    	error = driver_create_file(drv, &driver_attr_uevent);
    	if (error) {
    		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
    			__func__, drv->name);
    	}
    	error = driver_add_attrs(bus, drv);
    	if (error) {
    		/* How the hell do we get out of this pickle? Give up */
    		printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
    			__func__, drv->name);
    	}
    
    	if (!drv->suppress_bind_attrs) {
    		error = add_bind_files(drv);
    		if (error) {
    			/* Ditto */
    			printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
    				__func__, drv->name);
    		}
    	}
    
    	return 0;
    
    out_unregister:
    	kobject_put(&priv->kobj);
    	kfree(drv->p);
    	drv->p = NULL;
    out_put_bus:
    	bus_put(bus);
    	return error;
    }

    3.1 hub内核对象初始化

    这里重点分析下内核对象初始化的内部细节,

    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
    				     "%s", drv->name);

    其中,driver_ktype为驱动的内核集合类型,主要用来对内核对象的操作

    static struct kobj_type driver_ktype = {
    	.sysfs_ops	= &driver_sysfs_ops,
    	.release	= driver_release,
    };
    static const struct sysfs_ops driver_sysfs_ops = {
    	.show	= drv_attr_show,
    	.store	= drv_attr_store,
    };
    static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
    			     char *buf)
    {
    	struct driver_attribute *drv_attr = to_drv_attr(attr); //获取驱动的属性结构体
    	struct driver_private *drv_priv = to_driver(kobj); //获取驱动的私有数据
    	ssize_t ret = -EIO;
    
    	if (drv_attr->show) //驱动属性文件是否不为NULL
    		ret = drv_attr->show(drv_priv->driver, buf); //显示驱动
    	return ret;
    }
    
    static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
    			      const char *buf, size_t count)
    {
    	struct driver_attribute *drv_attr = to_drv_attr(attr);
    	struct driver_private *drv_priv = to_driver(kobj);
    	ssize_t ret = -EIO;
    
    	if (drv_attr->store)
    		ret = drv_attr->store(drv_priv->driver, buf, count); //存储
    	return ret;
    }

    分析完了驱动内核对象类型操作,再回到内核对象的初始化

    int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
    			 struct kobject *parent, const char *fmt, ...)
    {
    	va_list args;
    	int retval;
    
    	kobject_init(kobj, ktype); //初始化内核对象(绑定内核对象kobject的内核对象类型接口为ktype)
    
    	va_start(args, fmt);
    	retval = kobject_add_varg(kobj, parent, fmt, args); //内核对象增加,即创建hub目录
    	va_end(args);
    
    	return retval;
    }
    EXPORT_SYMBOL_GPL(kobject_init_and_add);
    void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
    {
    	char *err_str;
    
    	if (!kobj) {
    		err_str = "invalid kobject pointer!";
    		goto error;
    	}
    	if (!ktype) {
    		err_str = "must have a ktype to be initialized properly!\n";
    		goto error;
    	}
    	if (kobj->state_initialized) {
    		/* do not error out as sometimes we can recover */
    		printk(KERN_ERR "kobject (%p): tried to init an initialized "
    		       "object, something is seriously wrong.\n", kobj);
    		dump_stack();
    	}
    
    	kobject_init_internal(kobj);
    	kobj->ktype = ktype; //绑定内核对象的内核类型(内核对象的操作接口)
    	return;
    
    error:
    	printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
    	dump_stack();
    }
    EXPORT_SYMBOL(kobject_init);
    static void kobject_init_internal(struct kobject *kobj)
    {
    	if (!kobj)
    		return;
    	kref_init(&kobj->kref);
    	INIT_LIST_HEAD(&kobj->entry); //表示父内核对象下挂接的子内核对象
    	kobj->state_in_sysfs = 0; //sysfs没有初始化(涉及到sysfs文件系统)
    	kobj->state_add_uevent_sent = 0; //用户层事件是否发送
    	kobj->state_remove_uevent_sent = 0; //用户层事件是否移除
    	kobj->state_initialized = 1; //kobj对象初始化完成标识
    }
    

    kobject_init_and_add()->kobject_add_varg():

    static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
    			    const char *fmt, va_list vargs)
    {
    	int retval;
    
    	retval = kobject_set_name_vargs(kobj, fmt, vargs); //设置内核对象的名称为hub
    	if (retval) {
    		printk(KERN_ERR "kobject: can not set name properly!\n");
    		return retval;
    	}
    	kobj->parent = parent;
    	return kobject_add_internal(kobj); //内核对象增加,在sys文件系统下创建目录hub,绝对路径/sys/bus/usb/drivers/hub
    }
    static int kobject_add_internal(struct kobject *kobj)
    {
    	int error = 0;
    	struct kobject *parent;
    
    	if (!kobj)
    		return -ENOENT;
    
    	if (!kobj->name || !kobj->name[0]) {
    		WARN(1, "kobject: (%p): attempted to be registered with empty "
    			 "name!\n", kobj);
    		return -EINVAL;
    	}
    
    	parent = kobject_get(kobj->parent);
    
    	/* join kset if set, use it as parent if we do not already have one */
    	if (kobj->kset) { //kset为usb集合(因为kset集合是被内核对象绑定,所以下面可以获取内核对象)
    		if (!parent)
    			parent = kobject_get(&kobj->kset->kobj); //即为usb内核对象
    		kobj_kset_join(kobj);
    		kobj->parent = parent;
    	}
    
    	pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
    		 kobject_name(kobj), kobj, __func__,
    		 parent ? kobject_name(parent) : "<NULL>",
    		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
    
    	error = create_dir(kobj);
    	if (error) {
    		kobj_kset_leave(kobj);
    		kobject_put(parent);
    		kobj->parent = NULL;
    
    		/* be noisy on error issues */
    		if (error == -EEXIST)
    			WARN(1, "%s failed for %s with "
    			     "-EEXIST, don't try to register things with "
    			     "the same name in the same directory.\n",
    			     __func__, kobject_name(kobj));
    		else
    			WARN(1, "%s failed for %s (error: %d parent: %s)\n",
    			     __func__, kobject_name(kobj), error,
    			     parent ? kobject_name(parent) : "'none'");
    	} else
    		kobj->state_in_sysfs = 1; //表示kobject对象在sysfs中的状态
    
    	return error;
    }
    

    小节,到这里完成了hub内核对象的初始化和添加,并将该节点添加到了usb总线的bus->p->klist_drivers驱动链表中,同时创建目录hub,绝对路径为/sys/bus/usb/hub;接下来将分析driver_attach()

    3.2 驱动绑定driver_attach()

    路径:bus_add_driver()-->driver_attach(drv)

    int driver_attach(struct device_driver *drv)
    {
    	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //__driver_attach见下分析
    }
    int bus_for_each_dev(struct bus_type *bus, struct device *start,
    		     void *data, int (*fn)(struct device *, void *))
    {
    	struct klist_iter i;
    	struct device *dev;
    	int error = 0;
    
    	if (!bus || !bus->p)
    		return -EINVAL;
    
    	klist_iter_init_node(&bus->p->klist_devices, &i,//设备通过bus_add_device(...)添加时,最终会将设备加入到bus->p->klist_devices设备链表中
    			     (start ? &start->p->knode_bus : NULL));
    	while ((dev = next_device(&i)) && !error) 
    		error = fn(dev, data); //回调接口函数__driver_attach
    	klist_iter_exit(&i);
    	return error;
    }

    bus_for_each_dev()函数内部主要是遍历usb总线的设备链表(由于本次注册的是hub驱动),需找与本次注册的hub驱动相匹配;

    static int __driver_attach(struct device *dev, void *data)
    {
    	struct device_driver *drv = data;
    
    	/*
    	 * Lock device and try to bind to it. We drop the error
    	 * here and always return 0, because we need to keep trying
    	 * to bind to devices and some drivers will return an error
    	 * simply if it didn't support the device.
    	 *
    	 * driver_probe_device() will spit a warning if there
    	 * is an error.
    	 */
    
    	if (!driver_match_device(drv, dev)) //驱动和设备是否匹配,不匹配将退出,bus_for_each_dev函数继续下一个设备来匹配...
    		return 0;
    
    	if (dev->parent)	/* Needed for USB */
    		device_lock(dev->parent);
    	device_lock(dev);
    	if (!dev->driver) 
    		driver_probe_device(drv, dev); //探测函数
    	device_unlock(dev);
    	if (dev->parent)
    		device_unlock(dev->parent);
    
    	return 0;
    }

    driver_match_device():

    static inline int driver_match_device(struct device_driver *drv, struct device *dev)
    {
    	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
    }

    通过上面的usb_register_driver()函数分析,得知这里的drv为new_driver->drvwrap.driver,再次贴上该代码

    	new_driver->drvwrap.driver.name = (char *) new_driver->name; //初始化驱动名称为“hub”
    	new_driver->drvwrap.driver.bus = &usb_bus_type; //绑定总线类型为子系统usb
    	new_driver->drvwrap.driver.probe = usb_probe_interface; //重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
    	new_driver->drvwrap.driver.remove = usb_unbind_interface;
    	new_driver->drvwrap.driver.owner = owner;
    	new_driver->drvwrap.driver.mod_name = mod_name;

    所以driver_match_device()函数内部drv->bus=&usb_bus_type,即会调用 drv->bus->match(dev, drv)

    struct bus_type usb_bus_type = {
    	.name =		"usb",
    	.match =	usb_device_match, //见下
    	.uevent =	usb_uevent,
    };
    static int usb_device_match(struct device *dev, struct device_driver *drv)
    {
    	/* devices and interfaces are handled separately */
    	if (is_usb_device(dev)) { //是否是usb设备
    
    		/* interface drivers never match devices */
    		if (!is_usb_device_driver(drv))
    			return 0;
    
    		/* TODO: Add real matching code */
    		return 1;
    
    	} else if (is_usb_interface(dev)) { //是否是usb接口
    		struct usb_interface *intf;
    		struct usb_driver *usb_drv;
    		const struct usb_device_id *id;
    
    		/* device drivers never match interfaces */
    		if (is_usb_device_driver(drv))
    			return 0;
    
    		intf = to_usb_interface(dev);
    		usb_drv = to_usb_driver(drv);
    
    		id = usb_match_id(intf, usb_drv->id_table);
    		if (id)
    			return 1;
    
    		id = usb_match_dynamic_id(intf, usb_drv);
    		if (id)
    			return 1;
    	}
    
    	return 0;
    }

    在usb_device_match函数内部是usb设备或接口将执行不同的操作,我们在usb_register()函数注册时并未绑定类型,所以这里直接返回0,也就不会执行相应的probe探测函数了。那么这里就有疑问,usb设备和接口是什么时候被调用呢?在接下来的章节中将详细分析, intf->dev.type = &usb_if_device_type 将在usb_set_configuration()内部初始化,dev->dev.type = &usb_device_type将在usb_alloc_dev()内部初始化,这里先留个悬疑.....

    3.3 module_add_driver()驱动模块增加

          Hub驱动注册到usb总线上,并且这个时候usb总线上只有hub一个驱动,所以上面调用usb_device_match函数时将无法在对应的usb总线上匹配到设备,即该函数module_add_driver将不会被执行!不过为了后续再调用到该函数时不解,这里继续分析

    module_add_driver(drv->owner, drv);
    void module_add_driver(struct module *mod, struct device_driver *drv)
    {
    	char *driver_name;
    	int no_warn;
    	struct module_kobject *mk = NULL;
    
    	if (!drv)
    		return;
    
    	if (mod) //mod为真
    		mk = &mod->mkobj;
    	else if (drv->mod_name) { //驱动名称,假设是usb主机控制器"ehci_hcd"
    		struct kobject *mkobj;
    
    		/* Lookup built-in module entry in /sys/modules */
    		mkobj = kset_find_obj(module_kset, drv->mod_name); //根据mod_name,在module_kset内核集合上查找是否有相同的驱动
    		if (mkobj) {
    			mk = container_of(mkobj, struct module_kobject, kobj); //通过结构体成员mkobj,获取对应的module_kobject结构体指针
    			/* remember our module structure */
    			drv->p->mkobj = mk;
    			/* kset_find_obj took a reference */
    			kobject_put(mkobj);
    		}
    	}
    
    	if (!mk)
    		return;
    
    	/* Don't check return codes; these calls are idempotent */
    	no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); //创建module符号链接,即/sys/bus/usb/drivers/hub/module
    	driver_name = make_driver_name(drv); //driver_name ="usb:hub"
    	if (driver_name) {
    		module_create_drivers_dir(mk); //创建目录/sys/bus/usb/drivers/hub/module/usb:hub
    		no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
    					    driver_name);
    		kfree(driver_name);
    	}
    }

    3.5 驱动属性文件绑定

    路径:linux-3.10.x\include\linux\device.h

    #define DRIVER_ATTR(_name, _mode, _show, _store)	\
    struct driver_attribute driver_attr_##_name =		\
    	__ATTR(_name, _mode, _show, _store)
    static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
    static ssize_t driver_uevent_store(struct device_driver *drv,
    				   const char *buf, size_t count)
    {
    	enum kobject_action action;
    
    	if (kobject_action_type(buf, count, &action) == 0)
    		kobject_uevent(&drv->p->kobj, action);
    	return count;
    }
    所以上面创建了驱动属性文件结构体driver_attr_uevent
    error = driver_create_file(drv, &driver_attr_uevent); //创建驱动的属性文件操作
    error = driver_add_attrs(bus, drv); //总线上增加属性文件操作
    error = add_bind_files(drv);

    4. hub_probe()

    hub_probe()是被主机控制器ehci注册hub root时调用,详见:点击打开链接

    5. hub_thread()

    当usb主机控制器检测到设备接入时,通过等待队列唤醒hub_thread线程,执行usb设备的枚举,最终调用hub_probe(),关于hub_thread()分析,详见:点击打开链接

    6. 总结:

    usb hub初始化换号usb_hub_init()主要完成两个工作,

    1. 注册hub驱动到usb总线上,其中最重要的就是hub_probe()函数;

    2. 创建hub_thread()内核线程,用来处理usb主机控制器插入设备时的枚举操作。




    展开全文
  • USB HUB 方案

    千次阅读 2018-06-20 10:50:01
    MA8608USB 2.0 High Speed 4-Port Hub Controller ( USB 2.0高速端口集线器控制器)描述:MA8608是USB 2.0高速端口集线器控制器的高性能解决方案,与通用串行总线规范2.0完全兼容。当4个DS(下游)端口同时作用时,...

    MA8608

    USB 2.0 High Speed 4-Port Hub Controller

         ( USB 2.0高速端口集线器控制器)

    描述:

    MA8608USB 2.0高速端口集线器控制器的高性能解决方案,与通用串行总线规范2.0完全兼容。当4DS(下游)端口同时作用时,控制器继承先进串行接口技术以消耗最小功率。

    MA8608是一种集成功能以符合USB的创新,如果“电池充电MA8608成为USB充电中心”的通用充电解决方案,(UCS)兼容的电池基础规范修订版1.2,它支持便携式设备的快速充电功能。这一特点是由GSMA推动的可移植设备。MA8608中专用端口可在下游端口检测到符合BC兼容的便携式设备时处理充电请求。并且,在握手完成之后,MA860允许便携式设备从900V(高速)绘制;I5A(低/全速)从专用充电端口(DCP)从下游端口(CDP)或I5A充电。MA8608支持苹果iPad快速充电模式

    MA8608适用于单事务转换器(STT)和联动电源管理,以达到高效的目的。用户还可以通过外部EEPROM来实现多个集线器配置选项

    MA860支持QFN24包装目标的主流立场沿4港口枢纽市场。

     

    特征

    1符合USB规范修订版2

    上游端口支持高速(480MHz)和全速(12MHz)业务。

    可配置的4/32下游端口支持高速、全速和低速。

    向后兼容USB规范修订版1.1

    2符合USB电池充电规范修订版1.2

    3支持苹果电阻模式快速充电

    4集成快速8051微处理器

    512MHz振荡器时钟输入

    6、集成上游1.5KΩ上拉下游1.5KΩ下拉电阻

    7单事务翻译程序(单TT

    8下行端口的联动功率控制与全局过电流检测

    9领先的小功耗USB2.0集线器

    10片上5V3.3V/1.2V稳压器

    11自动供电和总线供电模式之间的自动重新计数

    12用于定制信息存储的外部EEPROM接口

    定制的VID,PID

    下游港口数量

    产品标识

    序列号

    13LED端口指示器模式

        下游端口LED(启用绿色)和一个主动/暂停LED(红色)

    一个联合下游端口引导4个端口(启用绿色)和一个激活/暂停LED(红色)

    包装类型:QFN24

    更多资讯请详询:捷寰昌 


    联系电话:135 6074 9177 韦先生


    展开全文
  • USB hub 进行USB扩展

    2015-06-01 14:50:54
    USB hub 进行USB扩展,方法方便、快捷且功耗小,发热量对比其他同类产品具有很大优势
  • 基于GL850G的USB HUB 芯片,一拖4功能, 原理图和pcb设计资料
  • USB hub 部分知识汇总

    2021-04-12 15:09:00
    USB 2.0HUB 识别high/full/low speed 设备 流程 https://blog.csdn.net/am_111/article/details/6066556 USB 2.0 hub TT 工作原理 https://www.docin.com/p-1360779091.html USB 2.0 hub mTT sTT区别 ...

    USB 2.0HUB 识别high/full/low speed 设备 流程
    https://blog.csdn.net/am_111/article/details/6066556

    USB 2.0 hub TT 工作原理
    https://www.docin.com/p-1360779091.html

    USB 2.0 hub mTT sTT区别
    https://blog.csdn.net/u010783226/article/details/113136018

    展开全文
  • USB转多路串口 USB hub USB扩展

    千次阅读 2020-05-03 10:08:41
    其中常用的是USB转串口,有时调试产品会用到好几个,会占用多个口。这个小工具质量一般,用用就坏。除了需要通信以外,有时需要提供5V或者3.3V,市面上的USB转串口有些能供电,有些不能。再有就是接口,各种接口定义...
  • USB hub MTT STT 区别

    千次阅读 2021-01-25 20:12:06
    MTT : Multiple Transaction translator Port1=Port2=Port3=Port4=12Mbps STT : Single Transaction translator Port1+Port2+Port3+Port4=12Mbps
  • usb hub

    千次阅读 2018-06-07 07:55:39
    (1)特别的爱给特别的Root Hub 通常做芯片的人把usb主机控制器和root hub集成在一起。 (2)一样的精灵不一样的API usb_init()---&gt;usb_hub_in...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,118
精华内容 6,447
关键字:

usbhub是什么