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

📄 hub.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* tell keventd to clear state for this TT */	spin_lock_irqsave (&tt->lock, flags);	list_add_tail (&clear->clear_list, &tt->clear_list);	schedule_work (&tt->kevent);	spin_unlock_irqrestore (&tt->lock, flags);}static void hub_power_on(struct usb_hub *hub){	int port1;	unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;	u16 wHubCharacteristics =			le16_to_cpu(hub->descriptor->wHubCharacteristics);	/* Enable power on each port.  Some hubs have reserved values	 * of LPSM (> 2) in their descriptors, even though they are	 * USB 2.0 hubs.  Some hubs do not implement port-power switching	 * but only emulate it.  In all cases, the ports won't work	 * unless we send these messages to the hub.	 */	if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2)		dev_dbg(hub->intfdev, "enabling power on all ports\n");	else		dev_dbg(hub->intfdev, "trying to enable port power on "				"non-switchable hub\n");	for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)		set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);	/* Wait at least 100 msec for power to become stable */	msleep(max(pgood_delay, (unsigned) 100));}static void hub_quiesce(struct usb_hub *hub){	/* (nonblocking) khubd and related activity won't re-trigger */	hub->quiescing = 1;	hub->activating = 0;	/* (blocking) stop khubd and related activity */	usb_kill_urb(hub->urb);	if (hub->has_indicators)		cancel_delayed_work(&hub->leds);	if (hub->has_indicators || hub->tt.hub)		flush_scheduled_work();}static void hub_activate(struct usb_hub *hub){	int	status;	hub->quiescing = 0;	hub->activating = 1;	status = usb_submit_urb(hub->urb, GFP_NOIO);	if (status < 0)		dev_err(hub->intfdev, "activate --> %d\n", status);	if (hub->has_indicators && blinkenlights)		schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);	/* scan all ports ASAP */	kick_khubd(hub);}static int hub_hub_status(struct usb_hub *hub,		u16 *status, u16 *change){	int ret;	mutex_lock(&hub->status_mutex);	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;	}	mutex_unlock(&hub->status_mutex);	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;}/* caller has locked the hub device */static void hub_pre_reset(struct usb_interface *intf){	struct usb_hub *hub = usb_get_intfdata(intf);	struct usb_device *hdev = hub->hdev;	int port1;	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {		if (hdev->children[port1 - 1]) {			usb_disconnect(&hdev->children[port1 - 1]);			if (hub->error == 0)				hub_port_disable(hub, port1, 0);		}	}	hub_quiesce(hub);}/* caller has locked the hub device */static void hub_post_reset(struct usb_interface *intf){	struct usb_hub *hub = usb_get_intfdata(intf);	hub_activate(hub);	hub_power_on(hub);}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;	}	mutex_init(&hub->status_mutex);	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);	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 < 2) {		message = "can't get hub status";		goto fail;	}	le16_to_cpus(&hubstatus);	if (hdev == hdev->bus->root_hub) {		if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)			hub->mA_per_port = 500;		else {			hub->mA_per_port = hdev->bus_mA;			hub->limited_power = 1;		}	} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {		dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",			hub->descriptor->bHubContrCurrent);		hub->limited_power = 1;		if (hdev->maxchild > 0) {			int remaining = hdev->bus_mA -					hub->descriptor->bHubContrCurrent;			if (remaining < hdev->maxchild * 100)				dev_warn(hub_dev,					"insufficient power available "					"to use all downstream ports\n");			hub->mA_per_port = 100;		/* 7.2.1.1 */		}	} else {	/* Self-powered external hub */		/* FIXME: What about battery-powered external hubs that		 * provide less current per port? */		hub->mA_per_port = 500;	}	if (hub->mA_per_port < 500)		dev_dbg(hub_dev, "%umA bus power budget for each child\n",				hub->mA_per_port);	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	 * We use the EP's maxpacket size instead of (PORTS+1+7)/8	 * bytes as USB2.0[11.12.3] says because some hubs are known	 * to send more data (and thus cause overflow). For root hubs,	 * maxpktsize is defined in hcd.c's fake endpoint descriptors	 * to be big enough for at least USB_MAXCHILDREN ports. */	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;static void hub_disconnect(struct usb_interface *intf){	struct usb_hub *hub = usb_get_intfdata (intf);	struct usb_device *hdev;	/* Disconnect all children and quiesce the hub */	hub->error = 0;	hub_pre_reset(intf);	usb_set_intfdata (intf, NULL);	hdev = hub->hdev;	if (hdev->speed == USB_SPEED_HIGH)		highspeed_hubs--;	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;	}	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 *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;	/* If it's not an interrupt in endpoint, we'd better punt! */	if (!usb_endpoint_is_int_in(endpoint))		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_DELAYED_WORK(&hub->leds, led_work);	usb_set_intfdata (intf, hub);	intf->needs_remote_wakeup = 1;	if (hdev->speed == USB_SPEED_HIGH)		highspeed_hubs++;	if (hub_configure(hub, endpoint) >= 0)

⌨️ 快捷键说明

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