⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hub.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		} else			return -EOPNOTSUPP;		if (status == 0) {			/* TRSMRCY = 10 msec */			msleep(10);		}	}	hub_activate(hub);	/* REVISIT:  this recursion probably shouldn't exist.  Remove	 * this code sometime, after retesting with different root and	 * external hubs.	 */#ifdef	CONFIG_USB_SUSPEND	{	unsigned		port1;	for (port1 = 1; port1 <= hdev->maxchild; port1++) {		struct usb_device	*udev;		u16			portstat, portchange;		udev = hdev->children [port1-1];		status = hub_port_status(hub, port1, &portstat, &portchange);		if (status == 0) {			if (portchange & USB_PORT_STAT_C_SUSPEND) {				clear_port_feature(hdev, port1,					USB_PORT_FEAT_C_SUSPEND);				portchange &= ~USB_PORT_STAT_C_SUSPEND;			}			/* let khubd handle disconnects etc */			if (portchange)				continue;		}		if (!udev || status < 0)			continue;		down (&udev->serialize);		if (portstat & USB_PORT_STAT_SUSPEND)			status = hub_port_resume(hub, port1, udev);		else {			status = finish_device_resume(udev);			if (status < 0) {				dev_dbg(&intf->dev, "resume port %d --> %d\n",					port1, status);				hub_port_logical_disconnect(hub, port1);			}		}		up(&udev->serialize);	}	}#endif	return 0;}void usb_suspend_root_hub(struct usb_device *hdev){	struct usb_hub *hub = hdev_to_hub(hdev);	/* This also makes any led blinker stop retriggering.  We're called	 * from irq, so the blinker might still be scheduled.  Caller promises	 * that the root hub status URB will be canceled.	 */	__hub_quiesce(hub);	mark_quiesced(to_usb_interface(hub->intfdev));}void usb_resume_root_hub(struct usb_device *hdev){	struct usb_hub *hub = hdev_to_hub(hdev);	hub->resume_root_hub = 1;	kick_khubd(hub);}/* USB 2.0 spec, 7.1.7.3 / fig 7-29: * * Between connect detection and reset signaling there must be a delay * of 100ms at least for debounce and power-settling.  The corresponding * timer shall restart whenever the downstream port detects a disconnect. *  * Apparently there are some bluetooth and irda-dongles and a number of * low-speed devices for which this debounce period may last over a second. * Not covered by the spec - but easy to deal with. * * This implementation uses a 1500ms total debounce timeout; if the * connection isn't stable by then it returns -ETIMEDOUT.  It checks * every 25ms for transient disconnects.  When the port status has been * unchanged for 100ms it returns the port status. */#define HUB_DEBOUNCE_TIMEOUT	1500#define HUB_DEBOUNCE_STEP	  25#define HUB_DEBOUNCE_STABLE	 100static int hub_port_debounce(struct usb_hub *hub, int port1){	int ret;	int total_time, stable_time = 0;	u16 portchange, portstatus;	unsigned connection = 0xffff;	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {		ret = hub_port_status(hub, port1, &portstatus, &portchange);		if (ret < 0)			return ret;		if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&		     (portstatus & USB_PORT_STAT_CONNECTION) == connection) {			stable_time += HUB_DEBOUNCE_STEP;			if (stable_time >= HUB_DEBOUNCE_STABLE)				break;		} else {			stable_time = 0;			connection = portstatus & USB_PORT_STAT_CONNECTION;		}		if (portchange & USB_PORT_STAT_C_CONNECTION) {			clear_port_feature(hub->hdev, port1,					USB_PORT_FEAT_C_CONNECTION);		}		if (total_time >= HUB_DEBOUNCE_TIMEOUT)			break;		msleep(HUB_DEBOUNCE_STEP);	}	dev_dbg (hub->intfdev,		"debounce: port %d: total %dms stable %dms status 0x%x\n",		port1, total_time, stable_time, portstatus);	if (stable_time < HUB_DEBOUNCE_STABLE)		return -ETIMEDOUT;	return portstatus;}static void ep0_reinit(struct usb_device *udev){	usb_disable_endpoint(udev, 0 + USB_DIR_IN);	usb_disable_endpoint(udev, 0 + USB_DIR_OUT);	udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;}#define usb_sndaddr0pipe()	(PIPE_CONTROL << 30)#define usb_rcvaddr0pipe()	((PIPE_CONTROL << 30) | USB_DIR_IN)static int hub_set_address(struct usb_device *udev){	int retval;	if (udev->devnum == 0)		return -EINVAL;	if (udev->state == USB_STATE_ADDRESS)		return 0;	if (udev->state != USB_STATE_DEFAULT)		return -EINVAL;	retval = usb_control_msg(udev, usb_sndaddr0pipe(),		USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,		NULL, 0, USB_CTRL_SET_TIMEOUT);	if (retval == 0) {		usb_set_device_state(udev, USB_STATE_ADDRESS);		ep0_reinit(udev);	}	return retval;}/* Reset device, (re)assign address, get device descriptor. * Device connection must be stable, no more debouncing needed. * Returns device in USB_STATE_ADDRESS, except on error. * * If this is called for an already-existing device (as part of * usb_reset_device), the caller must own the device lock.  For a * newly detected device that is not accessible through any global * pointers, it's not necessary to lock the device. */static inthub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,		int retry_counter){	static DECLARE_MUTEX(usb_address0_sem);	struct usb_device	*hdev = hub->hdev;	int			i, j, retval;	unsigned		delay = HUB_SHORT_RESET_TIME;	enum usb_device_speed	oldspeed = udev->speed;	/* root hub ports have a slightly longer reset period	 * (from USB 2.0 spec, section 7.1.7.5)	 */	if (!hdev->parent) {		delay = HUB_ROOT_RESET_TIME;		if (port1 == hdev->bus->otg_port)			hdev->bus->b_hnp_enable = 0;	}	/* Some low speed devices have problems with the quick delay, so */	/*  be a bit pessimistic with those devices. RHbug #23670 */	if (oldspeed == USB_SPEED_LOW)		delay = HUB_LONG_RESET_TIME;	down(&usb_address0_sem);	/* Reset the device; full speed may morph to high speed */	retval = hub_port_reset(hub, port1, udev, delay);	if (retval < 0)		/* error or disconnect */		goto fail;				/* success, speed is known */	retval = -ENODEV;	if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {		dev_dbg(&udev->dev, "device reset changed speed!\n");		goto fail;	}	oldspeed = udev->speed;  	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...	 * it's fixed size except for full speed devices.	 */	switch (udev->speed) {	case USB_SPEED_HIGH:		/* fixed at 64 */		udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);		break;	case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */		/* to determine the ep0 maxpacket size, try to read		 * the device descriptor to get bMaxPacketSize0 and		 * then correct our initial guess.		 */		udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);		break;	case USB_SPEED_LOW:		/* fixed at 8 */		udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(8);		break;	default:		goto fail;	} 	dev_info (&udev->dev,			"%s %s speed USB device using %s and address %d\n",			(udev->config) ? "reset" : "new",			({ char *speed; switch (udev->speed) {			case USB_SPEED_LOW:	speed = "low";	break;			case USB_SPEED_FULL:	speed = "full";	break;			case USB_SPEED_HIGH:	speed = "high";	break;			default: 		speed = "?";	break;			}; speed;}),			udev->bus->controller->driver->name,			udev->devnum);	/* Set up TT records, if needed  */	if (hdev->tt) {		udev->tt = hdev->tt;		udev->ttport = hdev->ttport;	} else if (udev->speed != USB_SPEED_HIGH			&& hdev->speed == USB_SPEED_HIGH) {		udev->tt = &hub->tt;		udev->ttport = port1;	} 	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?	 * Because device hardware and firmware is sometimes buggy in	 * this area, and this is how Linux has done it for ages.	 * Change it cautiously.	 *	 * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing	 * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,	 * so it may help with some non-standards-compliant devices.	 * Otherwise we start with SET_ADDRESS and then try to read the	 * first 8 bytes of the device descriptor to get the ep0 maxpacket	 * value.	 */	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {		if (USE_NEW_SCHEME(retry_counter)) {			struct usb_device_descriptor *buf;			int r = 0;#define GET_DESCRIPTOR_BUFSIZE	64			buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);			if (!buf) {				retval = -ENOMEM;				continue;			}			/* Use a short timeout the first time through,			 * so that recalcitrant full-speed devices with			 * 8- or 16-byte ep0-maxpackets won't slow things			 * down tremendously by NAKing the unexpectedly			 * early status stage.  Also, retry on all errors;			 * some devices are flakey.			 */			for (j = 0; j < 3; ++j) {				buf->bMaxPacketSize0 = 0;				r = usb_control_msg(udev, usb_rcvaddr0pipe(),					USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,					USB_DT_DEVICE << 8, 0,					buf, GET_DESCRIPTOR_BUFSIZE,					(i ? USB_CTRL_GET_TIMEOUT : 1000));				switch (buf->bMaxPacketSize0) {				case 8: case 16: case 32: case 64:					if (buf->bDescriptorType ==							USB_DT_DEVICE) {						r = 0;						break;					}					/* FALL THROUGH */				default:					if (r == 0)						r = -EPROTO;					break;				}				if (r == 0)					break;			}			udev->descriptor.bMaxPacketSize0 =					buf->bMaxPacketSize0;			kfree(buf);			retval = hub_port_reset(hub, port1, udev, delay);			if (retval < 0)		/* error or disconnect */				goto fail;			if (oldspeed != udev->speed) {				dev_dbg(&udev->dev,					"device reset changed speed!\n");				retval = -ENODEV;				goto fail;			}			if (r) {				dev_err(&udev->dev, "device descriptor "						"read/%s, error %d\n",						"64", r);				retval = -EMSGSIZE;				continue;			}#undef GET_DESCRIPTOR_BUFSIZE		}		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {			retval = hub_set_address(udev);			if (retval >= 0)				break;			msleep(200);		}		if (retval < 0) {			dev_err(&udev->dev,				"device not accepting address %d, error %d\n",				udev->devnum, retval);			goto fail;		} 		/* cope with hardware quirkiness:		 *  - let SET_ADDRESS settle, some device hardware wants it		 *  - read ep0 maxpacket even for high and low speed,  		 */		msleep(10);		if (USE_NEW_SCHEME(retry_counter))			break;		retval = usb_get_device_descriptor(udev, 8);		if (retval < 8) {			dev_err(&udev->dev, "device descriptor "					"read/%s, error %d\n",					"8", retval);			if (retval >= 0)				retval = -EMSGSIZE;		} else {			retval = 0;			break;		}	}	if (retval)		goto fail;	i = udev->descriptor.bMaxPacketSize0;	if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {		if (udev->speed != USB_SPEED_FULL ||				!(i == 8 || i == 16 || i == 32 || i == 64)) {			dev_err(&udev->dev, "ep0 maxpacket = %d\n", i);			retval = -EMSGSIZE;			goto fail;		}		dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);		ep0_reinit(udev);	}  	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);	if (retval < (signed)sizeof(udev->descriptor)) {		dev_err(&udev->dev, "device descriptor read/%s, error %d\n",			"all", retval);		if (retval >= 0)			retval = -ENOMSG;		goto fail;	}	retval = 0;fail:	if (retval)		hub_port_disable(hub, port1, 0);	up(&usb_address0_sem);	return retval;}static voidcheck_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1){	struct usb_qualifier_descriptor	*qual;	int				status;	qual = kmalloc (sizeof *qual, SLAB_KERNEL);	if (qual == NULL)		return;	status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0,			qual, sizeof *qual);	if (status == sizeof *qual) {		dev_info(&udev->dev, "not running at top speed; "			"connect to a high speed hub\n");		/* hub LEDs are probably harder to miss than syslog */		if (hub->has_indicators) {			hub->indicator[port1-1] = INDICATOR_GREEN_BLINK;			schedule_work (&hub->leds);		}	}	kfree(qual);}static unsignedhub_power_remaining (struct usb_hub *hub){	struct usb_device *hdev = hub->hdev;	int remaining;	unsigned i;	remaining = hub->power_budget;	if (!remaining)		/* self-powered */		return 0;	for (i = 0; i < hdev->maxchild; i++) {		struct usb_device	*udev = hdev->children[i];		int			delta, ceiling;		if (!udev)			continue;		/* 100mA per-port ceiling, or 8mA for OTG ports */		if (i != (udev->bus->otg_port - 1) || hdev->parent)			ceiling = 50;		else			ceiling = 4;		if (udev->actconfig)			delta = udev->actconfig->desc.bMaxPower;		else			delta = ceiling;		// dev_dbg(&udev->dev, "budgeted %dmA\n", 2 * delta);		if (delta > ceiling)			dev_warn(&udev->dev, "%dmA over %dmA budget!\n",				2 * (delta - ceiling), 2 * ceiling);		remaining -= delta;	}	if (remaining < 0) {		dev_warn(hub->intfdev,			"%dmA over power budget!\n",			-2 * remaining);		remaining = 0;	}	return remaining;}/* Handle physical or logical connection change events. * This routine is called when: * 	a port connection-change occurs; *	a port enable-change occurs (often caused by EMI); *	usb_reset_device() encounters changed descriptors (as from *		a firmware download) * caller already locked the hub */static void hub_port_connect_change(struct

⌨️ 快捷键说明

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