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

📄 hub.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
static int hub_hub_status(struct usb_hub *hub,		u16 *status, u16 *change){	int ret;	ret = get_hub_status(hub->hdev, &hub->status->hub);	if (ret < 0)		dev_err (hub->intfdev,			"%s failed (err = %d)\n", __FUNCTION__, ret);	else {		*status = le16_to_cpu(hub->status->hub.wHubStatus);		*change = le16_to_cpu(hub->status->hub.wHubChange); 		ret = 0;	}	return ret;}static int hub_port_disable(struct usb_hub *hub, int port1, int set_state){	struct usb_device *hdev = hub->hdev;	int ret;	if (hdev->children[port1-1] && set_state) {		usb_set_device_state(hdev->children[port1-1],				USB_STATE_NOTATTACHED);	}	ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);	if (ret)		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",			port1, ret);	return ret;}static int hub_configure(struct usb_hub *hub,	struct usb_endpoint_descriptor *endpoint){	struct usb_device *hdev = hub->hdev;	struct device *hub_dev = hub->intfdev;	u16 hubstatus, hubchange;	u16 wHubCharacteristics;	unsigned int pipe;	int maxp, ret;	char *message;	hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,			&hub->buffer_dma);	if (!hub->buffer) {		message = "can't allocate hub irq buffer";		ret = -ENOMEM;		goto fail;	}	hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);	if (!hub->status) {		message = "can't kmalloc hub status buffer";		ret = -ENOMEM;		goto fail;	}	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);	if (!hub->descriptor) {		message = "can't kmalloc hub descriptor";		ret = -ENOMEM;		goto fail;	}	/* Request the entire hub descriptor.	 * hub->descriptor can handle USB_MAXCHILDREN ports,	 * but the hub can/will return fewer bytes here.	 */	ret = get_hub_descriptor(hdev, hub->descriptor,			sizeof(*hub->descriptor));	if (ret < 0) {		message = "can't read hub descriptor";		goto fail;	} else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {		message = "hub has too many ports!";		ret = -ENODEV;		goto fail;	}	hdev->maxchild = hub->descriptor->bNbrPorts;	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,		(hdev->maxchild == 1) ? "" : "s");	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);	if (wHubCharacteristics & HUB_CHAR_COMPOUND) {		int	i;		char	portstr [USB_MAXCHILDREN + 1];		for (i = 0; i < hdev->maxchild; i++)			portstr[i] = hub->descriptor->DeviceRemovable				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))				? 'F' : 'R';		portstr[hdev->maxchild] = 0;		dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);	} else		dev_dbg(hub_dev, "standalone hub\n");	switch (wHubCharacteristics & HUB_CHAR_LPSM) {		case 0x00:			dev_dbg(hub_dev, "ganged power switching\n");			break;		case 0x01:			dev_dbg(hub_dev, "individual port power switching\n");			break;		case 0x02:		case 0x03:			dev_dbg(hub_dev, "no power switching (usb 1.0)\n");			break;	}	switch (wHubCharacteristics & HUB_CHAR_OCPM) {		case 0x00:			dev_dbg(hub_dev, "global over-current protection\n");			break;		case 0x08:			dev_dbg(hub_dev, "individual port over-current protection\n");			break;		case 0x10:		case 0x18:			dev_dbg(hub_dev, "no over-current protection\n");                        break;	}	spin_lock_init (&hub->tt.lock);	INIT_LIST_HEAD (&hub->tt.clear_list);	INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub);	switch (hdev->descriptor.bDeviceProtocol) {		case 0:			break;		case 1:			dev_dbg(hub_dev, "Single TT\n");			hub->tt.hub = hdev;			break;		case 2:			ret = usb_set_interface(hdev, 0, 1);			if (ret == 0) {				dev_dbg(hub_dev, "TT per port\n");				hub->tt.multi = 1;			} else				dev_err(hub_dev, "Using single TT (err %d)\n",					ret);			hub->tt.hub = hdev;			break;		default:			dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",				hdev->descriptor.bDeviceProtocol);			break;	}	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */	switch (wHubCharacteristics & HUB_CHAR_TTTT) {		case HUB_TTTT_8_BITS:			if (hdev->descriptor.bDeviceProtocol != 0) {				hub->tt.think_time = 666;				dev_dbg(hub_dev, "TT requires at most %d "						"FS bit times (%d ns)\n",					8, hub->tt.think_time);			}			break;		case HUB_TTTT_16_BITS:			hub->tt.think_time = 666 * 2;			dev_dbg(hub_dev, "TT requires at most %d "					"FS bit times (%d ns)\n",				16, hub->tt.think_time);			break;		case HUB_TTTT_24_BITS:			hub->tt.think_time = 666 * 3;			dev_dbg(hub_dev, "TT requires at most %d "					"FS bit times (%d ns)\n",				24, hub->tt.think_time);			break;		case HUB_TTTT_32_BITS:			hub->tt.think_time = 666 * 4;			dev_dbg(hub_dev, "TT requires at most %d "					"FS bit times (%d ns)\n",				32, hub->tt.think_time);			break;	}	/* probe() zeroes hub->indicator[] */	if (wHubCharacteristics & HUB_CHAR_PORTIND) {		hub->has_indicators = 1;		dev_dbg(hub_dev, "Port indicators are supported\n");	}	dev_dbg(hub_dev, "power on to power good time: %dms\n",		hub->descriptor->bPwrOn2PwrGood * 2);	/* power budgeting mostly matters with bus-powered hubs,	 * and battery-powered root hubs (may provide just 8 mA).	 */	ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);	if (ret < 0) {		message = "can't get hub status";		goto fail;	}	le16_to_cpus(&hubstatus);	if (hdev == hdev->bus->root_hub) {		struct usb_hcd *hcd =				container_of(hdev->bus, struct usb_hcd, self);		hub->power_budget = min(500u, hcd->power_budget) / 2;	} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {		dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",			hub->descriptor->bHubContrCurrent);		hub->power_budget = (501 - hub->descriptor->bHubContrCurrent)					/ 2;	}	if (hub->power_budget)		dev_dbg(hub_dev, "%dmA bus power budget for children\n",			hub->power_budget * 2);	ret = hub_hub_status(hub, &hubstatus, &hubchange);	if (ret < 0) {		message = "can't get hub status";		goto fail;	}	/* local power status reports aren't always correct */	if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)		dev_dbg(hub_dev, "local power source is %s\n",			(hubstatus & HUB_STATUS_LOCAL_POWER)			? "lost (inactive)" : "good");	if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)		dev_dbg(hub_dev, "%sover-current condition exists\n",			(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");	/* set up the interrupt endpoint */	pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);	maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));	if (maxp > sizeof(*hub->buffer))		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, hdev, pipe, *hub->buffer, maxp, hub_irq,		hub, endpoint->bInterval);	hub->urb->transfer_dma = hub->buffer_dma;	hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;	/* maybe cycle the hub leds */	if (hub->has_indicators && blinkenlights)		hub->indicator [0] = INDICATOR_CYCLE;	hub_power_on(hub);	hub_activate(hub);	return 0;fail:	dev_err (hub_dev, "config failed, %s (err %d)\n",			message, ret);	/* hub_disconnect() frees urb and descriptor */	return ret;}static unsigned highspeed_hubs;/* Called after the hub driver is unbound from a hub with children */static void hub_remove_children_work(void *__hub){	struct usb_hub		*hub = __hub;	struct usb_device	*hdev = hub->hdev;	int			i;	kfree(hub);	usb_lock_device(hdev);	for (i = 0; i < hdev->maxchild; ++i) {		if (hdev->children[i])			usb_disconnect(&hdev->children[i]);	}	usb_unlock_device(hdev);	usb_put_dev(hdev);}static void hub_disconnect(struct usb_interface *intf){	struct usb_hub *hub = usb_get_intfdata (intf);	struct usb_device *hdev;	int n, port1;	usb_set_intfdata (intf, NULL);	hdev = hub->hdev;	if (hdev->speed == USB_SPEED_HIGH)		highspeed_hubs--;	hub_quiesce(hub);	usb_free_urb(hub->urb);	hub->urb = NULL;	spin_lock_irq(&hub_event_lock);	list_del_init(&hub->event_list);	spin_unlock_irq(&hub_event_lock);	kfree(hub->descriptor);	hub->descriptor = NULL;	kfree(hub->status);	hub->status = NULL;	if (hub->buffer) {		usb_buffer_free(hdev, sizeof(*hub->buffer), hub->buffer,				hub->buffer_dma);		hub->buffer = NULL;	}	/* If there are any children then this is an unbind only, not a	 * physical disconnection.  The active ports must be disabled	 * and later on we must call usb_disconnect().  We can't call	 * it now because we may not hold the hub's device lock.	 */	n = 0;	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {		if (hdev->children[port1 - 1]) {			++n;			hub_port_disable(hub, port1, 1);		}	}	if (n == 0)		kfree(hub);	else {		/* Reuse the hub->leds work_struct for our own purposes */		INIT_WORK(&hub->leds, hub_remove_children_work, hub);		schedule_work(&hub->leds);		usb_get_dev(hdev);	}}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 *hdev;	struct usb_hub *hub;	desc = intf->cur_altsetting;	hdev = 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:		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)		goto descriptor_error;	endpoint = &desc->endpoint[0].desc;	/* Output endpoint? Curiouser and curiouser.. */	if (!(endpoint->bEndpointAddress & USB_DIR_IN))		goto descriptor_error;	/* If it's not an interrupt endpoint, we'd better punt! */	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)			!= USB_ENDPOINT_XFER_INT)		goto descriptor_error;	/* We found a hub */	dev_info (&intf->dev, "USB hub found\n");	hub = kzalloc(sizeof(*hub), GFP_KERNEL);	if (!hub) {		dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");		return -ENOMEM;	}	INIT_LIST_HEAD(&hub->event_list);	hub->intfdev = &intf->dev;	hub->hdev = hdev;	INIT_WORK(&hub->leds, led_work, hub);	usb_set_intfdata (intf, hub);	if (hdev->speed == USB_SPEED_HIGH)		highspeed_hubs++;	if (hub_configure(hub, endpoint) >= 0)		return 0;	hub_disconnect (intf);	return -ENODEV;}static inthub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data){	struct usb_device *hdev = interface_to_usbdev (intf);	/* assert ifno == 0 (part of hub spec) */	switch (code) {	case USBDEVFS_HUB_PORTINFO: {		struct usbdevfs_hub_portinfo *info = user_data;		int i;		spin_lock_irq(&device_state_lock);		if (hdev->devnum <= 0)			info->nports = 0;		else {			info->nports = hdev->maxchild;			for (i = 0; i < info->nports; i++) {				if (hdev->children[i] == NULL)					info->port[i] = 0;				else					info->port[i] =						hdev->children[i]->devnum;			}		}		spin_unlock_irq(&device_state_lock);		return info->nports + 1;		}	default:		return -ENOSYS;	}}/* caller has locked the hub device */static void hub_pre_reset(struct usb_hub *hub){	struct usb_device *hdev = hub->hdev;	int i;	for (i = 0; i < hdev->maxchild; ++i) {		if (hdev->children[i])			usb_disconnect(&hdev->children[i]);	}	hub_quiesce(hub);}/* caller has locked the hub device */static void hub_post_reset(struct usb_hub *hub){	hub_activate(hub);	hub_power_on(hub);}/* grab device/port lock, returning index of that port (zero based). * protects the upstream link used by this device from concurrent * tree operations like suspend, resume, reset, and disconnect, which * apply to everything downstream of a given port. */static int locktree(struct usb_device *udev){	int			t;	struct usb_device	*hdev;	if (!udev)		return -ENODEV;	/* root hub is always the first lock in the series */	hdev = udev->parent;	if (!hdev) {		usb_lock_device(udev);		return 0;	}	/* on the path from root to us, lock everything from	 * top down, dropping parent locks when not needed	 */	t = locktree(hdev);

⌨️ 快捷键说明

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