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

📄 hub.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
		maxp = sizeof(*hub->buffer);

	hub->urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!hub->urb) {
		message = "couldn't allocate interrupt urb";
		ret = -ENOMEM;
		goto fail;
	}

	usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq,
		hub, endpoint->bInterval);
	hub->urb->transfer_dma = hub->buffer_dma;
	hub->urb->transfer_flags |= URB_NO_DMA_MAP;
	ret = usb_submit_urb(hub->urb, GFP_KERNEL);
	if (ret) {
		message = "couldn't submit status urb";
		goto fail;
	}

	/* Wake up khubd */
	wake_up(&khubd_wait);
	printk("hub_thread should woke up\n");

	hub_power_on(hub);

	return 0;

fail:
	dev_err (&hub->intf->dev, "config failed, %s (err %d)\n",
			message, ret);
	/* hub_disconnect() frees urb and descriptor */
	return ret;
}

static void hub_disconnect(struct usb_interface *intf)
{
	struct usb_hub *hub = usb_get_intfdata (intf);
	unsigned long flags;

	if (!hub)
		return;

	usb_set_intfdata (intf, NULL);
	spin_lock_irqsave(&hub_event_lock, flags);

	/* Delete it and then reset it */
	list_del(&hub->event_list);
	INIT_LIST_HEAD(&hub->event_list);
	list_del(&hub->hub_list);
	INIT_LIST_HEAD(&hub->hub_list);

	spin_unlock_irqrestore(&hub_event_lock, flags);

	down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
	up(&hub->khubd_sem);

	/* assuming we used keventd, it must quiesce too */
	if (hub->tt.hub)
		flush_scheduled_work ();

	if (hub->urb) {
		usb_unlink_urb(hub->urb);
		usb_free_urb(hub->urb);
		hub->urb = NULL;
	}

	if (hub->descriptor) {
		kfree(hub->descriptor);
		hub->descriptor = NULL;
	}

	if (hub->status) {
		kfree(hub->status);
		hub->status = NULL;
	}

	if (hub->buffer) {
		usb_buffer_free(interface_to_usbdev(intf),
				sizeof(*hub->buffer), hub->buffer,
				hub->buffer_dma);
		hub->buffer = NULL;
	}

	/* Free the memory */
	kfree(hub);
}

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_host_interface *desc;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_device *dev;
	struct usb_hub *hub;
	unsigned long flags;

	desc = intf->altsetting + intf->act_altsetting;
	dev = interface_to_usbdev(intf);

	/* Some hubs have a subclass of 1, which AFAICT according to the */
	/*  specs is not defined, but it works */
	if ((desc->desc.bInterfaceSubClass != 0) &&
	    (desc->desc.bInterfaceSubClass != 1)) {
//descriptor_error:
		desc->desc.bInterfaceSubClass =0;
		dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
		//return -EIO;
	}

	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
	if (desc->desc.bNumEndpoints != 1) {
		desc->desc.bNumEndpoints = 1;
		//goto descriptor_error;
	}

	endpoint = &desc->endpoint[0].desc;

	/* Output endpoint? Curiouser and curiouser.. */
	if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {
		//goto descriptor_error;
		endpoint->bEndpointAddress |= USB_DIR_IN;
	}

	/* If it's not an interrupt endpoint, we'd better punt! */
	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
			!= USB_ENDPOINT_XFER_INT) {
			endpoint->bmAttributes	|= USB_ENDPOINT_XFER_INT;
		//goto descriptor_error;
		//return -EIO;
	}

	/* We found a hub */
	dev_info (hubdev (dev), "USB hub found\n");

	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
	if (!hub) {
		err("couldn't kmalloc hub struct");
		return -ENOMEM;
	}

	memset(hub, 0, sizeof(*hub));

	hub->RestCounter = 0;

	INIT_LIST_HEAD(&hub->event_list);
	hub->intf = intf;
	init_MUTEX(&hub->khubd_sem);

	/* Record the new hub's existence */
	spin_lock_irqsave(&hub_event_lock, flags);
	INIT_LIST_HEAD(&hub->hub_list);
	list_add(&hub->hub_list, &hub_list);
	spin_unlock_irqrestore(&hub_event_lock, flags);

	usb_set_intfdata (intf, hub);

	if (hub_configure(hub, endpoint) >= 0)
	{
		strcpy (intf->dev.name, "Hub");
		return 0;
	}

	//hub_disconnect (intf);
	return -ENODEV;
}

static int
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
{
	struct usb_device *hub = interface_to_usbdev (intf);

	/* assert ifno == 0 (part of hub spec) */
	switch (code) {
	case USBDEVFS_HUB_PORTINFO: {
		struct usbdevfs_hub_portinfo *info = user_data;
		unsigned long flags;
		int i;

		spin_lock_irqsave(&hub_event_lock, flags);
		if (hub->devnum <= 0)
			info->nports = 0;
		else {
			info->nports = hub->maxchild;
			for (i = 0; i < info->nports; i++) {
				if (hub->children[i] == NULL)
					info->port[i] = 0;
				else
					info->port[i] =
						hub->children[i]->devnum;
			}
		}
		spin_unlock_irqrestore(&hub_event_lock, flags);

		return info->nports + 1;
		}

	default:
		return -ENOSYS;
	}
}

static int hub_reset(struct usb_hub *hub)
{
	struct usb_device *dev = interface_to_usbdev(hub->intf);
	int i;

	/* Disconnect any attached devices */
	for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
		if (dev->children[i])
			usb_disconnect(&dev->children[i]);
	}

	/* Attempt to reset the hub */
	if (hub->urb)
		usb_unlink_urb(hub->urb);
	else
		return -1;

	if (usb_reset_device(dev))
		return -1;

	hub->urb->dev = dev;                                                    
	if (usb_submit_urb(hub->urb, GFP_KERNEL))
		return -1;

	hub_power_on(hub);

	return 0;
}

static void hub_start_disconnect(struct usb_device *dev)
{
	struct usb_device *parent = dev->parent;
	int i;

	/* Find the device pointer to disconnect */
	if (parent) {
		for (i = 0; i < parent->maxchild; i++) {
			if (parent->children[i] == dev) {
				usb_disconnect(&parent->children[i]);
				return;
			}
		}
	}

	err("cannot disconnect hub %s", dev->devpath);
}

static int hub_port_status(struct usb_device *dev, int port,
			       u16 *status, u16 *change)
{
	struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface);
	int ret;

	if (!hub)
		return -ENODEV;

	ret = get_port_status(dev, port + 1, &hub->status->port);
        if (ret < 0) {
		dev_err (hubdev (dev),
			"%s failed (err = %d)\n", __FUNCTION__, ret);
        }
	else {
		*status = le16_to_cpu(hub->status->port.wPortStatus);
		*change = le16_to_cpu(hub->status->port.wPortChange); 
		ret = 0;
	}
	return ret;
}

#define HUB_RESET_TRIES		5
#define HUB_PROBE_TRIES		5
#define HUB_ROOT_RESET_TIME	40
#define HUB_SHORT_RESET_TIME	10
#define HUB_LONG_RESET_TIME	70
#define HUB_RESET_TIMEOUT	500

/* return: -1 on error, 0 on success, 1 on disconnect.  */
static int hub_port_wait_reset(struct usb_device *hub, int port,
				struct usb_device *dev, unsigned int delay)
{
	int delay_time, ret;
	u16 portstatus;
	u16 portchange;

	for (delay_time = 0;
			delay_time < HUB_RESET_TIMEOUT;
			delay_time += delay) {
		/* wait to give the device a chance to reset */
		wait_ms(delay);

		/* read and decode port status */
		ret = hub_port_status(hub, port, &portstatus, &portchange);
		if (ret < 0) {
			return -1;
		}

		/* Device went away? */
		if (!(portstatus & USB_PORT_STAT_CONNECTION))
			return 1;

		/* bomb out completely if something weird happened */
		if ((portchange & USB_PORT_STAT_C_CONNECTION))
			return -1;

		/* if we`ve finished resetting, then break out of the loop */
		if (!(portstatus & USB_PORT_STAT_RESET) &&
		    (portstatus & USB_PORT_STAT_ENABLE)) {
			if (portstatus & USB_PORT_STAT_HIGH_SPEED)
				dev->speed = USB_SPEED_HIGH;
			else if (portstatus & USB_PORT_STAT_LOW_SPEED)
				dev->speed = USB_SPEED_LOW;
			else
				dev->speed = USB_SPEED_FULL;
			return 0;
		}

		/* switch to the long delay after two short delay failures */
		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
			delay = HUB_LONG_RESET_TIME;

		dev_dbg (hubdev (hub),
			"port %d not reset yet, waiting %dms\n",
			port + 1, delay);
	}

	return -1;
}

/* return: -1 on error, 0 on success, 1 on disconnect.  */
static int hub_port_reset(struct usb_device *hub, int port,
				struct usb_device *dev, unsigned int delay)
{
	int i, status;

	/* Reset the port */
	for (i = 0; i < HUB_RESET_TRIES; i++) {
		set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);

		/* return on disconnect or reset */
		status = hub_port_wait_reset(hub, port, dev, delay);
		if (status != -1) {
			clear_port_feature(hub,
				port + 1, USB_PORT_FEAT_C_RESET);
			dev->state = status
					? USB_STATE_NOTATTACHED
					: USB_STATE_DEFAULT;
			return status;
		}

		dev_dbg (hubdev (hub),
			"port %d not enabled, trying reset again...\n",
			port + 1);
		delay = HUB_LONG_RESET_TIME;
	}

	dev_err (hubdev (hub),
		"Cannot enable port %i.  Maybe the USB cable is bad?\n",
		port + 1);

	return -1;
}

int hub_port_disable(struct usb_device *hub, int port)
{
	int ret;

	ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
	if (ret)
		dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",
			port + 1, ret);

	return ret;
}

/* 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 which require longer delays of about 200-400ms.
 * Not covered by the spec - but easy to deal with.
 *
 * This implementation uses 400ms minimum debounce timeout and checks
 * every 25ms for transient disconnects to restart the delay.
 */

#define HUB_DEBOUNCE_TIMEOUT	400
#define HUB_DEBOUNCE_STEP	 5
#define HUB_DEBOUNCE_STABLE	  3

/* return: -1 on error, 0 on success, 1 on disconnect.  */
static int hub_port_debounce(struct usb_device *hub, int port)
{
	int ret;
	int delay_time, stable_count;
	u16 portchange, portstatus;
	unsigned connection;

	connection = 0;
	stable_count = 0;
	for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
		wait_ms(HUB_DEBOUNCE_STEP);

		ret = hub_port_status(hub, port, &portstatus, &portchange);
		if (ret < 0)
			return -1;

		if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) {
			if (connection) {
				if (++stable_count == HUB_DEBOUNCE_STABLE)
					break;
			}
		} else {
			stable_count = 0;
		}
		connection = portstatus & USB_PORT_STAT_CONNECTION;

		if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
			clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);
		}
	}

	/* XXX Replace this with dbg() when 2.6 is about to ship. */
	dev_dbg (hubdev (hub),
		"debounce: port %d: delay %dms stable %d status 0x%x\n",
		port + 1, delay_time, stable_count, portstatus);

	return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
}

static void hub_port_connect_change(struct usb_hub *hubstate, int port,
					u16 portstatus, u16 portchange)
{
	struct usb_device *hub = interface_to_usbdev(hubstate->intf);
	struct usb_device *dev;
	unsigned int delay = HUB_SHORT_RESET_TIME;
	int i;
	int DevcoosenAdress = 0;
	
	//printe("port %d, status %x, change %x,\n",port + 1, portstatus, portchange);
		
		
	dev_dbg (&hubstate->intf->dev,
		"port %d, status %x, change %x, %s\n",
		port + 1, portstatus, portchange, portspeed (portstatus));

	/* Clear the connection change status */
	clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);

	/* Disconnect any existing devices under this port */
	if (hub->children[port])
		usb_disconnect(&hub->children[port]);

	/* Return now if nothing is connected */
	if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
		if (portstatus & USB_PORT_STAT_ENABLE)
			hub_port_disable(hub, port);

		return;
	}

	if (hub_port_debounce(hub, port)) {
		dev_err (&hubstate->intf->dev,
			"connect-debounce failed, port %d disabled\n",
			port+1);
		//printe("connect-debounce failed, port %d disabled\n",	port+1);
		hub_port_disable(hub, port);
		return;
	}

	/* root hub ports have a slightly longer reset period
	 * (from USB 2.0 spec, section 7.1.7.5)
	 */
	if (!hub->parent)
		delay = HUB_ROOT_RESET_TIME;
		
	/* Some low speed devices have problems with the quick delay, so */
	/*  be a bit pessimistic with those devices. RHbug #23670 */
	if (portstatus & USB_PORT_STAT_LOW_SPEED)
		delay = HUB_LONG_RESET_TIME;

	down(&usb_address0_sem);

	for (i = 0; i < HUB_PROBE_TRIES; i++) {
		struct usb_device *pdev;
		int	len;

		/* Allocate a new device struct */
		dev = usb_alloc_dev(hub, hub->bus);
		if (!dev) {
			dev_err (&hubstate->intf->dev,
				"couldn't allocate usb_device\n");
			break;
		}

		
		dev->state = USB_STATE_POWERED;

⌨️ 快捷键说明

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