message.c

来自「linux 内核源代码」· C语言 代码 · 共 1,699 行 · 第 1/4 页

C
1,699
字号
 * * Returns zero on success, else a negative error code. */int usb_reset_configuration(struct usb_device *dev){	int			i, retval;	struct usb_host_config	*config;	if (dev->state == USB_STATE_SUSPENDED)		return -EHOSTUNREACH;	/* caller must have locked the device and must own	 * the usb bus readlock (so driver bindings are stable);	 * calls during probe() are fine	 */	for (i = 1; i < 16; ++i) {		usb_disable_endpoint(dev, i);		usb_disable_endpoint(dev, i + USB_DIR_IN);	}	config = dev->actconfig;	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),			USB_REQ_SET_CONFIGURATION, 0,			config->desc.bConfigurationValue, 0,			NULL, 0, USB_CTRL_SET_TIMEOUT);	if (retval < 0)		return retval;	dev->toggle[0] = dev->toggle[1] = 0;	/* re-init hc/hcd interface/endpoint state */	for (i = 0; i < config->desc.bNumInterfaces; i++) {		struct usb_interface *intf = config->interface[i];		struct usb_host_interface *alt;		if (device_is_registered(&intf->dev))			usb_remove_sysfs_intf_files(intf);		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.		 */		if (!alt)			alt = &intf->altsetting[0];		intf->cur_altsetting = alt;		usb_enable_interface(dev, intf);		if (device_is_registered(&intf->dev))			usb_create_sysfs_intf_files(intf);	}	return 0;}static void usb_release_interface(struct device *dev){	struct usb_interface *intf = to_usb_interface(dev);	struct usb_interface_cache *intfc =			altsetting_to_usb_interface_cache(intf->altsetting);	kref_put(&intfc->ref, usb_release_interface_cache);	kfree(intf);}#ifdef	CONFIG_HOTPLUGstatic int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env){	struct usb_device *usb_dev;	struct usb_interface *intf;	struct usb_host_interface *alt;	intf = to_usb_interface(dev);	usb_dev = interface_to_usbdev(intf);	alt = intf->cur_altsetting;	if (add_uevent_var(env, "INTERFACE=%d/%d/%d",		   alt->desc.bInterfaceClass,		   alt->desc.bInterfaceSubClass,		   alt->desc.bInterfaceProtocol))		return -ENOMEM;	if (add_uevent_var(env,		   "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",		   le16_to_cpu(usb_dev->descriptor.idVendor),		   le16_to_cpu(usb_dev->descriptor.idProduct),		   le16_to_cpu(usb_dev->descriptor.bcdDevice),		   usb_dev->descriptor.bDeviceClass,		   usb_dev->descriptor.bDeviceSubClass,		   usb_dev->descriptor.bDeviceProtocol,		   alt->desc.bInterfaceClass,		   alt->desc.bInterfaceSubClass,		   alt->desc.bInterfaceProtocol))		return -ENOMEM;	return 0;}#elsestatic int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env){	return -ENODEV;}#endif	/* CONFIG_HOTPLUG */struct device_type usb_if_device_type = {	.name =		"usb_interface",	.release =	usb_release_interface,	.uevent =	usb_if_uevent,};static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,						       struct usb_host_config *config,						       u8 inum){	struct usb_interface_assoc_descriptor *retval = NULL;	struct usb_interface_assoc_descriptor *intf_assoc;	int first_intf;	int last_intf;	int i;	for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {		intf_assoc = config->intf_assoc[i];		if (intf_assoc->bInterfaceCount == 0)			continue;		first_intf = intf_assoc->bFirstInterface;		last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);		if (inum >= first_intf && inum <= last_intf) {			if (!retval)				retval = intf_assoc;			else				dev_err(&dev->dev, "Interface #%d referenced"					" by multiple IADs\n", inum);		}	}	return retval;}/* * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. * Context: !in_interrupt(), caller owns the device lock * * This is used to enable non-default device modes.  Not all devices * use this kind of configurability; many devices only have one * configuration. * * @configuration is the value of the configuration to be installed. * According to the USB spec (e.g. section 9.1.1.5), configuration values * must be non-zero; a value of zero indicates that the device in * unconfigured.  However some devices erroneously use 0 as one of their * configuration values.  To help manage such devices, this routine will * accept @configuration = -1 as indicating the device should be put in * an unconfigured state. * * USB device configurations may affect Linux interoperability, * power consumption and the functionality available.  For example, * the default configuration is limited to using 100mA of bus power, * so that when certain device functionality requires more power, * and the device is bus powered, that functionality should be in some * non-default device configuration.  Other device modes may also be * reflected as configuration options, such as whether two ISDN * channels are available independently; and choosing between open * standard device protocols (like CDC) or proprietary ones. * * Note that a non-authorized device (dev->authorized == 0) will only * be put in unconfigured mode. * * Note that USB has an additional level of device configurability, * associated with interfaces.  That configurability is accessed using * usb_set_interface(). * * This call is synchronous. The calling context must be able to sleep, * must own the device lock, and must not hold the driver model's USB * bus mutex; usb device driver probe() methods cannot use this routine. * * Returns zero on success, or else the status code returned by the * underlying call that failed.  On successful completion, each interface * in the original device configuration has been destroyed, and each one * in the new configuration has been probed by all relevant usb device * drivers currently known to the kernel. */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;	if (dev->authorized == 0 || configuration == -1)		configuration = 0;	else {		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;		}		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;	/* if it's already configured, clear out old state first.	 * getting rid of old interfaces means unbinding their drivers.	 */	if (dev->state != USB_STATE_ADDRESS)		usb_disable_device (dev, 1);	// Skip ep0	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,			NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {		/* All the old state is gone, so what else can we do?		 * The device is probably useless now anyway.		 */		cp = NULL;	}	dev->actconfig = cp;	if (!cp) {		usb_set_device_state(dev, USB_STATE_ADDRESS);		usb_autosuspend_device(dev);		goto free_interfaces;	}	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);		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.		 */		if (!alt)			alt = &intf->altsetting[0];		intf->cur_altsetting = alt;		usb_enable_interface(dev, intf);		intf->dev.parent = &dev->dev;		intf->dev.driver = NULL;		intf->dev.bus = &usb_bus_type;		intf->dev.type = &usb_if_device_type;		intf->dev.dma_mask = dev->dev.dma_mask;		device_initialize (&intf->dev);		mark_quiesced(intf);		sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",			 dev->bus->busnum, dev->devpath,			 configuration, alt->desc.bInterfaceNumber);	}	kfree(new_interfaces);	if (cp->string == NULL)		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 (i = 0; i < nintf; ++i) {		struct usb_interface *intf = cp->interface[i];		dev_dbg (&dev->dev,			"adding %s (config #%d, interface %d)\n",			intf->dev.bus_id, configuration,			intf->cur_altsetting->desc.bInterfaceNumber);		ret = device_add (&intf->dev);		if (ret != 0) {			dev_err(&dev->dev, "device_add(%s) --> %d\n",				intf->dev.bus_id, ret);			continue;		}		usb_create_sysfs_intf_files(intf);	}	usb_autosuspend_device(dev);	return 0;}struct set_config_request {	struct usb_device	*udev;	int			config;	struct work_struct	work;};/* Worker routine for usb_driver_set_configuration() */static void driver_set_config_work(struct work_struct *work){	struct set_config_request *req =		container_of(work, struct set_config_request, work);	usb_lock_device(req->udev);	usb_set_configuration(req->udev, req->config);	usb_unlock_device(req->udev);	usb_put_dev(req->udev);	kfree(req);}/** * usb_driver_set_configuration - Provide a way for drivers to change device configurations * @udev: the device whose configuration is being updated * @config: the configuration being chosen. * Context: In process context, must be able to sleep * * Device interface drivers are not allowed to change device configurations. * This is because changing configurations will destroy the interface the * driver is bound to and create new ones; it would be like a floppy-disk * driver telling the computer to replace the floppy-disk drive with a * tape drive! * * Still, in certain specialized circumstances the need may arise.  This * routine gets around the normal restrictions by using a work thread to * submit the change-config request. * * Returns 0 if the request was succesfully queued, error code otherwise. * The caller has no way to know whether the queued request will eventually * succeed. */int usb_driver_set_configuration(struct usb_device *udev, int config){	struct set_config_request *req;	req = kmalloc(sizeof(*req), GFP_KERNEL);	if (!req)		return -ENOMEM;	req->udev = udev;	req->config = config;	INIT_WORK(&req->work, driver_set_config_work);	usb_get_dev(udev);	schedule_work(&req->work);	return 0;}EXPORT_SYMBOL_GPL(usb_driver_set_configuration);// synchronous request completion modelEXPORT_SYMBOL(usb_control_msg);EXPORT_SYMBOL(usb_bulk_msg);EXPORT_SYMBOL(usb_sg_init);EXPORT_SYMBOL(usb_sg_cancel);EXPORT_SYMBOL(usb_sg_wait);// synchronous control message convenience routinesEXPORT_SYMBOL(usb_get_descriptor);EXPORT_SYMBOL(usb_get_status);EXPORT_SYMBOL(usb_string);// synchronous calls that also maintain usbcore stateEXPORT_SYMBOL(usb_clear_halt);EXPORT_SYMBOL(usb_reset_configuration);EXPORT_SYMBOL(usb_set_interface);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?