root hub usb设备和驱动的匹配(五)

本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记

注册driver的函数是driver_register,device_driver传参如下:

new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
new_udriver->drvwrap.driver.probe = usb_probe_device;
new_udriver->drvwrap.driver.remove = usb_unbind_device;
new_udriver->drvwrap.driver.owner = owner;

注册device的函数是device_add,device传参如下:

dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.groups = usb_device_groups;

driver和device的总线都是usb_bus_type,device的设备类型是usb_device_type,driver的probe函数是usb_probe_device。
那么注册设备的时候,会自动遍历总线上的所有驱动,看看哪个驱动能匹配上;
注册驱动的时候,也会遍历总线上的所有设备,看看哪个设备能匹配上;
usb_bus_type的定义如下:

struct bus_type usb_bus_type = {
	.name =		"usb",
	.match =	usb_device_match,
	.uevent =	usb_uevent,
};

usb_device_match是他们的匹配函数

static int usb_device_match(struct device *dev, struct device_driver *drv)
{
	/* devices and interfaces are handled separately */
	//如果是USB设备
	if (is_usb_device(dev)) {

		/* interface drivers never match devices */
		//是匹配USB设备的驱动,USB接口的驱动不能匹配
		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 */
		//usb接口在注册driver时将for_devices设置为0,for_devices =1,表示设备驱动,for_devices = 0,表示接口驱动
		if (is_usb_device_driver(drv))
			return 0;

		intf = to_usb_interface(dev);
		usb_drv = to_usb_driver(drv);
		//匹配id table
		id = usb_match_id(intf, usb_drv->id_table);
		if (id)
			return 1;
		//匹配动态id table
		id = usb_match_dynamic_id(intf, usb_drv);
		if (id)
			return 1;
	}

	return 0;
}

匹配规则是:
usb 设备device和usb 设备driver任意匹配;
usb device和usb 接口driver不能匹配;
usb 接口device和usb设备driver不能匹配;
usb接口device和usb接口driver根据driver的id_table进行匹配;

现在是root hub的usb设备device和usb设备driver进行匹配,所以直接就匹配上了,调用usb_probe_device函数。

static int usb_probe_device(struct device *dev)
{
    ……
	error = udriver->probe(udev);
	return error;
}

usb_probe_device函数直接调用usb_device_driver的probe函数。
usb_device_driver只在usb_init函数中调用usb_register_device_driver传进来的。

static int __init usb_init(void)
{
    ……
    retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
}

看一下usb_generic_driver这个全局变量。

struct usb_device_driver usb_generic_driver = {
	.name =	"usb",
	.probe = generic_probe,
	.disconnect = generic_disconnect,
#ifdef	CONFIG_PM
	.suspend = generic_suspend,
	.resume = generic_resume,
#endif
	.supports_autosuspend = 1,
};

usb_generic_driver的probe函数是generic_probe,所以root hub的usb设备device和usb设备driver进行匹配最终调用的是generic_probe函数。

static int generic_probe(struct usb_device *udev)
{
	int err, c;

	/* Choose and set the configuration.  This registers the interfaces
	 * with the driver core and lets interface drivers bind to them.
	 */
	if (usb_device_is_owned(udev))
		;		/* Don't configure if the device is owned */
	else if (udev->authorized == 0)
		dev_err(&udev->dev, "Device is not authorized for usage\n");
	else {
		//选择一个合适的设置
		c = usb_choose_configuration(udev);
		if (c >= 0) {
			//设置
			err = usb_set_configuration(udev, c);
			if (err) {
				dev_err(&udev->dev, "can't set config #%d, error %d\n",
					c, err);
				/* This need not be fatal.  The user can try to
				 * set other configurations. */
			}
		}
	}
	/* USB device state == configured ... usable */
	usb_notify_add_device(udev);

	return 0;
}

主要是为root hub选择一个合适的配置,然后配置root hub。但是root hub只有一个配置,其实也没得选。
看一下usb_choose_configuration函数。

int usb_choose_configuration(struct usb_device *udev)
{
	……
    /* Rule out configs that draw too much bus current */
    if (c->desc.bMaxPower * 2 > udev->bus_mA) {
        insufficient_power++;
        continue;
    }
    
    /* From the remaining configs, choose the first one whose
    * first interface is for a non-vendor-specific class.
    * Reason: Linux is more likely to have a class driver
    * than a vendor-specific driver. */
    else if (udev->descriptor.bDeviceClass !=
    USB_CLASS_VENDOR_SPEC &&
    (!desc || desc->bInterfaceClass !=
    USB_CLASS_VENDOR_SPEC)) {
        best = c;
        break;
    }

    /* If all the remaining configs are vendor-specific,
    * choose the first one. */
    else if (!best)
        best = c;
}

选择配置的选择就是耗电量太大的不选,厂商特殊定义的DeviceClass不选,都是厂商特殊定义的DeviceClass,选择第一个。

然后看一下配置函数。

int usb_set_configuration(struct usb_device *dev, int configuration)
{
	int i, ret;
	struct usb_host_config *cp = NULL;
	struct usb_interface **new_interfaces = NULL;
	int n, nintf;
	//configuration是前边儿choose_configuration()那里返回回来的
	//当configuration为-1也就是没有发现满意的配置时,设备不能进入Configured,
	//所以要把configuration的值改为0,以便满足SET_CONFIGURATION请求的要求
	if (dev->authorized == 0 || configuration == -1)
		configuration = 0;
	else {
		//从设备struct usb_device结构体的config数组里将相应配置的描述信息,也就是struct usb_host_config结构体给取出来
		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
			if (dev->config[i].desc.bConfigurationValue ==
					configuration) {
				cp = &dev->config[i];
				break;
			}
		}
	}
	if ((!cp && configuration != 0))
		return -EINVAL;

	/* The USB spec says configuration 0 means unconfigured.
	 * But if a device includes a configuration numbered 0,
	 * we will accept it as a correctly configured state.
	 * Use -1 if you really want to unconfigure the device.
	 */
	if (cp && configuration == 0)
		dev_warn(&dev->dev, "config 0 descriptor??\n");

	/* Allocate memory for new interfaces before doing anything else,
	 * so that if we run out then nothing will have changed. */
	n = nintf = 0;
	if (cp) {
		nintf = cp->desc.bNumInterfaces;
		//申请指针数组的内存
		new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
				GFP_KERNEL);
		if (!new_interfaces) {
			dev_err(&dev->dev, "Out of memory\n");
			return -ENOMEM;
		}
		//申请每一项new_interfaces[n]的内存
		for (; n < nintf; ++n) {
			new_interfaces[n] = kzalloc(
					sizeof(struct usb_interface),
					GFP_KERNEL);
			if (!new_interfaces[n]) {
				dev_err(&dev->dev, "Out of memory\n");
				ret = -ENOMEM;
free_interfaces:
				while (--n >= 0)
					kfree(new_interfaces[n]);
				kfree(new_interfaces);
				return ret;
			}
		}

		i = dev->bus_mA - cp->desc.bMaxPower * 2;
		if (i < 0)
			dev_warn(&dev->dev, "new config #%d exceeds power "
					"limit by %dmA\n",
					configuration, -i);
	}

	/* Wake up the device so we can send it the Set-Config request */
	ret = usb_autoresume_device(dev);
	if (ret)
		goto free_interfaces;

	/* Make sure we have bandwidth (and available HCD resources) for this
	 * configuration.  Remove endpoints from the schedule if we're dropping
	 * this configuration to set configuration 0.  After this point, the
	 * host controller will not allow submissions to dropped endpoints.  If
	 * this call fails, the device state is unchanged.
	 */
	if (cp)
		ret = usb_hcd_check_bandwidth(dev, cp, NULL);
	else
		ret = usb_hcd_check_bandwidth(dev, NULL, NULL);
	if (ret < 0) {
		usb_autosuspend_device(dev);
		goto free_interfaces;
	}

	/* if it's already configured, clear out old state first.
	 * getting rid of old interfaces means unbinding their drivers.
	 */
	 //不disable ep0
	if (dev->state != USB_STATE_ADDRESS)
		usb_disable_device(dev, 1);	/* Skip ep0 */

	/* Get rid of pending async Set-Config requests for this device */
	cancel_async_set_config(dev);
	//发送命令,设置configuration
	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
			      USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
			      NULL, 0, USB_CTRL_SET_TIMEOUT);
	if (ret < 0) {
		/* All the old state is gone, so what else can we do?
		 * The device is probably useless now anyway.
		 */
		cp = NULL;
	}
	//将激活的那个配置的地址赋给actconfig
	dev->actconfig = cp;
	//如果cp为空,重新设置设备的状态为Address,并将之前
	//准备的那些struct usb_interface结构体和new_interfaces释放掉,然后返回
	if (!cp) {
		usb_set_device_state(dev, USB_STATE_ADDRESS);
		usb_hcd_check_bandwidth(dev, NULL, NULL);
		usb_autosuspend_device(dev);
		goto free_interfaces;
	}
	//设置设备的状态为configured
	usb_set_device_state(dev, USB_STATE_CONFIGURED);

	/* Initialize the new interface structures and the
	 * hc/hcd/usbcore interface/endpoint state.
	 */
	for (i = 0; i < nintf; ++i) {
		struct usb_interface_cache *intfc;
		struct usb_interface *intf;
		struct usb_host_interface *alt;

		cp->interface[i] = intf = new_interfaces[i];
		intfc = cp->intf_cache[i];
		intf->altsetting = intfc->altsetting;
		intf->num_altsetting = intfc->num_altsetting;
		intf->intf_assoc = find_iad(dev, cp, i);
		kref_get(&intfc->ref);
		//获得这个接口的0号设置,接口的默认设置总是0号设置
		alt = usb_altnum_to_altsetting(intf, 0);

		/* No altsetting 0?  We'll assume the first altsetting.
		 * We could use a GetInterface call, but if a device is
		 * so non-compliant that it doesn't have altsetting 0
		 * then I wouldn't trust its reply anyway.
		 */
		//拿altsetting数组里的第一项来充数
		if (!alt)
			alt = &intf->altsetting[0];
		//指定刚刚拿到的设置为当前要使用的设置
		intf->cur_altsetting = alt;
		//轮询前面获得的那个接口设置使用到的每个端点,将它们统统enable
		usb_enable_interface(dev, intf, true);
		intf->dev.parent = &dev->dev;
		intf->dev.driver = NULL;
		intf->dev.bus = &usb_bus_type;
		intf->dev.type = &usb_if_device_type;
		intf->dev.groups = usb_interface_groups;
		intf->dev.dma_mask = dev->dev.dma_mask;
		INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
		device_initialize(&intf->dev);
		mark_quiesced(intf);
		dev_set_name(&intf->dev, "%d-%s:%d.%d",
			dev->bus->busnum, dev->devpath,
			configuration, alt->desc.bInterfaceNumber);
	}
	kfree(new_interfaces);

	if (cp->string == NULL &&
			!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
		cp->string = usb_cache_string(dev, cp->desc.iConfiguration);

	/* Now that all the interfaces are set up, register them
	 * to trigger binding of drivers to interfaces.  probe()
	 * routines may install different altsettings and may
	 * claim() any interfaces not yet bound.  Many class drivers
	 * need that: CDC, audio, video, etc.
	 */
	//将前面那个for循环准备好的每个接口送给设备模型
	for (i = 0; i < nintf; ++i) {
		struct usb_interface *intf = cp->interface[i];

		dev_dbg(&dev->dev,
			"adding %s (config #%d, interface %d)\n",
			dev_name(&intf->dev), configuration,
			intf->cur_altsetting->desc.bInterfaceNumber);
		ret = device_add(&intf->dev);
		if (ret != 0) {
			dev_err(&dev->dev, "device_add(%s) --> %d\n",
				dev_name(&intf->dev), ret);
			continue;
		}
		create_intf_ep_devs(intf);
	}

	usb_autosuspend_device(dev);
	return 0;
}

代码非常长,主要做的事情就是:
参数检查,申请内存;
发送命令,设置configuration编号,因为我们上一步选择了一个合适的配置;
设置设备的状态为configured;
将解析阶段usb_host_config.intf_cache中保存的数据保存在usb_host_config.interface,usb_host_config.intf_cache的数据只在设备为配置状态之前有效,设备处于配置状态后,使用usb_host_config.interface里面的数据;
根据configured可以知道有多少个接口,对每个接口进行初始化,初始化dev设备,初始化它的设置,指定每个接口当前活跃的设置为0号设置;

intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.groups = usb_interface_groups;

将每个接口注册成usb接口设备;

我们的root hub只有一种配置,一种接口,一种设置和一个端口,上面的usb接口设备的总线是usb_bus_type,设备类型是usb_if_device_type,这个后面就会用到。

文章参考:https://blog.youkuaiyun.com/fudan_abc/article/category/325189

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值