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

📄 ehci-hcd.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif	}	/* force HC to halt state */	return ehci_halt (ehci);}static int ehci_start (struct usb_hcd *hcd){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	u32			temp;	struct usb_device	*udev;	struct usb_bus		*bus;	int			retval;	u32			hcc_params;	u8                      sbrn = 0;	int			first;	/* skip some things on restart paths */	first = (ehci->watchdog.data == 0);	if (first) {		init_timer (&ehci->watchdog);		ehci->watchdog.function = ehci_watchdog;		ehci->watchdog.data = (unsigned long) ehci;	}	/*	 * hw default: 1K periodic list heads, one per frame.	 * periodic_size can shrink by USBCMD update if hcc_params allows.	 */	ehci->periodic_size = DEFAULT_I_TDPS;	if (first && (retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0)		return retval;	/* controllers may cache some of the periodic schedule ... */	hcc_params = readl (&ehci->caps->hcc_params);	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache		ehci->i_thresh = 8;	else					// N microframes cached		ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);	ehci->reclaim = NULL;	ehci->reclaim_ready = 0;	ehci->next_uframe = -1;	/* controller state:  unknown --> reset */	/* EHCI spec section 4.1 */	if ((retval = ehci_reset (ehci)) != 0) {		ehci_mem_cleanup (ehci);		return retval;	}	writel (ehci->periodic_dma, &ehci->regs->frame_list);#ifdef	CONFIG_PCI	if (hcd->self.controller->bus == &pci_bus_type) {		struct pci_dev		*pdev;		u16			port_wake;		pdev = to_pci_dev(hcd->self.controller);		/* Serial Bus Release Number is at PCI 0x60 offset */		pci_read_config_byte(pdev, 0x60, &sbrn);		/* port wake capability, reported by boot firmware */		pci_read_config_word(pdev, 0x62, &port_wake);		hcd->can_wakeup = (port_wake & 1) != 0;		/* help hc dma work well with cachelines */		pci_set_mwi (pdev);		/* chip-specific init */		switch (pdev->vendor) {		case PCI_VENDOR_ID_ARC:			if (pdev->device == PCI_DEVICE_ID_ARC_EHCI)				ehci->is_arc_rh_tt = 1;			break;		}	}#endif	/*	 * dedicate a qh for the async ring head, since we couldn't unlink	 * a 'real' qh without stopping the async schedule [4.8].  use it	 * as the 'reclamation list head' too.	 * its dummy is used in hw_alt_next of many tds, to prevent the qh	 * from automatically advancing to the next td after short reads.	 */	if (first) {		ehci->async->qh_next.qh = NULL;		ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma);		ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD);		ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT);		ehci->async->hw_qtd_next = EHCI_LIST_END;		ehci->async->qh_state = QH_STATE_LINKED;		ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma);	}	writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);	/*	 * hcc_params controls whether ehci->regs->segment must (!!!)	 * be used; it constrains QH/ITD/SITD and QTD locations.	 * pci_pool consistent memory always uses segment zero.	 * streaming mappings for I/O buffers, like pci_map_single(),	 * can return segments above 4GB, if the device allows.	 *	 * NOTE:  the dma mask is visible through dma_supported(), so	 * drivers can pass this info along ... like NETIF_F_HIGHDMA,	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all	 * host side drivers though.	 */	if (HCC_64BIT_ADDR (hcc_params)) {		writel (0, &ehci->regs->segment);#if 0// this is deeply broken on almost all architectures		if (!pci_set_dma_mask (to_pci_dev(hcd->self.controller), 0xffffffffffffffffULL))			ehci_info (ehci, "enabled 64bit PCI DMA\n");#endif	}	/* clear interrupt enables, set irq latency */	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)		log2_irq_thresh = 0;	temp = 1 << (16 + log2_irq_thresh);	if (HCC_CANPARK(hcc_params)) {		/* HW default park == 3, on hardware that supports it (like		 * NVidia and ALI silicon), maximizes throughput on the async		 * schedule by avoiding QH fetches between transfers.		 *		 * With fast usb storage devices and NForce2, "park" seems to		 * make problems:  throughput reduction (!), data errors...		 */		if (park) {			park = min (park, (unsigned) 3);			temp |= CMD_PARK;			temp |= park << 8;		}		ehci_info (ehci, "park %d\n", park);	}	if (HCC_PGM_FRAMELISTLEN (hcc_params)) {		/* periodic schedule size can be smaller than default */		temp &= ~(3 << 2);		temp |= (EHCI_TUNE_FLS << 2);		switch (EHCI_TUNE_FLS) {		case 0: ehci->periodic_size = 1024; break;		case 1: ehci->periodic_size = 512; break;		case 2: ehci->periodic_size = 256; break;		default:	BUG ();		}	}	// Philips, Intel, and maybe others need CMD_RUN before the	// root hub will detect new devices (why?); NEC doesn't	temp |= CMD_RUN;	writel (temp, &ehci->regs->command);	dbg_cmd (ehci, "init", temp);	/* set async sleep time = 10 us ... ? */	/* wire up the root hub */	bus = hcd_to_bus (hcd);	udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;	if (!udev) {done2:		ehci_mem_cleanup (ehci);		return -ENOMEM;	}	udev->speed = USB_SPEED_HIGH;	udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;	/*	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices	 * are explicitly handed to companion controller(s), so no TT is	 * involved with the root hub.  (Except where one is integrated,	 * and there's no companion controller unless maybe for USB OTG.)	 */	if (first) {		ehci->reboot_notifier.notifier_call = ehci_reboot;		register_reboot_notifier (&ehci->reboot_notifier);	}	hcd->state = USB_STATE_RUNNING;	writel (FLAG_CF, &ehci->regs->configured_flag);	readl (&ehci->regs->command);	/* unblock posted write */	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));	ehci_info (ehci,		"USB %x.%x %s, EHCI %x.%02x, driver %s\n",		((sbrn & 0xf0)>>4), (sbrn & 0x0f),		first ? "initialized" : "restarted",		temp >> 8, temp & 0xff, DRIVER_VERSION);	/*	 * From here on, khubd concurrently accesses the root	 * hub; drivers will be talking to enumerated devices.	 * (On restart paths, khubd already knows about the root	 * hub and could find work as soon as we wrote FLAG_CF.)	 *	 * Before this point the HC was idle/ready.  After, khubd	 * and device drivers may start it running.	 */	if (first && hcd_register_root (udev, hcd) != 0) {		if (hcd->state == USB_STATE_RUNNING)			ehci_quiesce (ehci);		ehci_reset (ehci);		usb_put_dev (udev); 		retval = -ENODEV;		goto done2;	}	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */	if (first)		create_debug_files (ehci);	return 0;}/* always called by thread; normally rmmod */static void ehci_stop (struct usb_hcd *hcd){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	u8			rh_ports, port;	ehci_dbg (ehci, "stop\n");	/* Turn off port power on all root hub ports. */	rh_ports = HCS_N_PORTS (ehci->hcs_params);	for (port = 1; port <= rh_ports; port++)		(void) ehci_hub_control(hcd,			ClearPortFeature, USB_PORT_FEAT_POWER,			port, NULL, 0);	/* no more interrupts ... */	del_timer_sync (&ehci->watchdog);	spin_lock_irq(&ehci->lock);	if (HCD_IS_RUNNING (hcd->state))		ehci_quiesce (ehci);	ehci_reset (ehci);	writel (0, &ehci->regs->intr_enable);	spin_unlock_irq(&ehci->lock);	/* let companion controllers work when we aren't */	writel (0, &ehci->regs->configured_flag);	unregister_reboot_notifier (&ehci->reboot_notifier);	remove_debug_files (ehci);	/* root hub is shut down separately (first, when possible) */	spin_lock_irq (&ehci->lock);	if (ehci->async)		ehci_work (ehci, NULL);	spin_unlock_irq (&ehci->lock);	ehci_mem_cleanup (ehci);#ifdef	EHCI_STATS	ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,		ehci->stats.lost_iaa);	ehci_dbg (ehci, "complete %ld unlink %ld\n",		ehci->stats.complete, ehci->stats.unlink);#endif	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));}static int ehci_get_frame (struct usb_hcd *hcd){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;}/*-------------------------------------------------------------------------*/#ifdef	CONFIG_PM/* suspend/resume, section 4.3 *//* These routines rely on the bus (pci, platform, etc) * to handle powerdown and wakeup, and currently also on * transceivers that don't need any software attention to set up * the right sort of wakeup.   */static int ehci_suspend (struct usb_hcd *hcd, u32 state){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	if (time_before (jiffies, ehci->next_statechange))		msleep (100);#ifdef	CONFIG_USB_SUSPEND	(void) usb_suspend_device (hcd->self.root_hub, state);#else	usb_lock_device (hcd->self.root_hub);	(void) ehci_hub_suspend (hcd);	usb_unlock_device (hcd->self.root_hub);#endif	// save (PCI) FLADJ in case of Vaux power loss	// ... we'd only use it to handle clock skew	return 0;}static int ehci_resume (struct usb_hcd *hcd){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	unsigned		port;	struct usb_device	*root = hcd->self.root_hub;	int			retval = -EINVAL;	int			powerup = 0;	// maybe restore (PCI) FLADJ	if (time_before (jiffies, ehci->next_statechange))		msleep (100);	/* If any port is suspended, we know we can/must resume the HC. */	for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {		u32	status;		port--;		status = readl (&ehci->regs->port_status [port]);		if (status & PORT_SUSPEND) {			down (&hcd->self.root_hub->serialize);			retval = ehci_hub_resume (hcd);			up (&hcd->self.root_hub->serialize);			break;		}		if ((status & PORT_POWER) == 0)			powerup = 1;		if (!root->children [port])			continue;		dbg_port (ehci, __FUNCTION__, port + 1, status);		usb_set_device_state (root->children[port],					USB_STATE_NOTATTACHED);	}	/* Else reset, to cope with power loss or flush-to-storage	 * style "resume" having activated BIOS during reboot.	 */	if (port == 0) {		(void) ehci_halt (ehci);		(void) ehci_reset (ehci);		(void) ehci_hc_reset (hcd);		/* emptying the schedule aborts any urbs */		spin_lock_irq (&ehci->lock);		if (ehci->reclaim)			ehci->reclaim_ready = 1;		ehci_work (ehci, NULL);		spin_unlock_irq (&ehci->lock);		/* restart; khubd will disconnect devices */		retval = ehci_start (hcd);		/* here we "know" root ports should always stay powered;		 * but some controllers may lost all power.		 */		if (powerup) {			ehci_dbg (ehci, "...powerup ports...\n");			for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )				(void) ehci_hub_control(hcd,					SetPortFeature, USB_PORT_FEAT_POWER,						port--, NULL, 0);			msleep(20);		}	}	return retval;}#endif/*-------------------------------------------------------------------------*//* * ehci_work is called from some interrupts, timers, and so on. * it calls driver completion functions, after dropping ehci->lock. */static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs){	timer_action_done (ehci, TIMER_IO_WATCHDOG);	if (ehci->reclaim_ready)		end_unlink_async (ehci, regs);	/* another CPU may drop ehci->lock during a schedule scan while	 * it reports urb completions.  this flag guards against bogus	 * attempts at re-entrant schedule scanning.	 */	if (ehci->scanning)		return;	ehci->scanning = 1;	scan_async (ehci, regs);	if (ehci->next_uframe != -1)		scan_periodic (ehci, regs);	ehci->scanning = 0;	/* the IO watchdog guards against hardware or driver bugs that	 * misplace IRQs, and should let us run completely without IRQs.	 * such lossage has been observed on both VT6202 and VT8235. 	 */	if (HCD_IS_RUNNING (ehci_to_hcd(ehci)->state) &&			(ehci->async->qh_next.ptr != NULL ||			 ehci->periodic_sched != 0))		timer_action (ehci, TIMER_IO_WATCHDOG);}/*-------------------------------------------------------------------------*/

⌨️ 快捷键说明

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