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

📄 ehci-hcd.c

📁 硬实时linux补丁rtai下usb协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
		temp = pci_find_capability (pdev, 0x0a);		if (temp) {			pci_read_config_dword(pdev, temp, &temp);			temp >>= 16;			if ((temp & (3 << 13)) == (1 << 13)) {				temp &= 0x1fff;				ehci->debug = hcd->regs + temp;				temp = readl (&ehci->debug->control);				ehci_info (ehci, "debug port %d%s\n",					HCS_DEBUG_PORT(ehci->hcs_params),					(temp & DBGP_ENABLED)						? " IN USE"						: "");				if (!(temp & DBGP_ENABLED))					ehci->debug = NULL;			}		}		temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));	} else		temp = 0;	/* EHCI 0.96 and later may have "extended capabilities" */	while (temp && count--) {		u32		cap;		pci_read_config_dword (to_pci_dev(hcd->self.controller),				temp, &cap);		ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);		switch (cap & 0xff) {		case 1:			/* BIOS/SMM/... handoff */			if (bios_handoff (ehci, temp, cap) != 0)				return -EOPNOTSUPP;			break;		case 0:			/* illegal reserved capability */			ehci_warn (ehci, "illegal capability!\n");			cap = 0;			/* FALLTHROUGH */		default:		/* unknown */			break;		}		temp = (cap >> 8) & 0xff;	}	if (!count) {		ehci_err (ehci, "bogus capabilities ... PCI problems!\n");		return -EIO;	}	if (ehci_is_TDI(ehci))		ehci_reset (ehci);#endif	ehci_port_power (ehci, 0);	/* at least the Genesys GL880S needs fixup here */	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);	temp &= 0x0f;	if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {		ehci_dbg (ehci, "bogus port configuration: "			"cc=%d x pcc=%d < ports=%d\n",			HCS_N_CC(ehci->hcs_params),			HCS_N_PCC(ehci->hcs_params),			HCS_N_PORTS(ehci->hcs_params));#ifdef	CONFIG_PCI		if (hcd->self.controller->bus == &pci_bus_type) {			struct pci_dev	*pdev;			pdev = to_pci_dev(hcd->self.controller);			switch (pdev->vendor) {			case 0x17a0:		/* GENESYS */				/* GL880S: should be PORTS=2 */				temp |= (ehci->hcs_params & ~0xf);				ehci->hcs_params = temp;				break;			case PCI_VENDOR_ID_NVIDIA:				/* NF4: should be PCC=10 */				break;			}		}#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;	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;		pdev = to_pci_dev(hcd->self.controller);		/* Serial Bus Release Number is at PCI 0x60 offset */		pci_read_config_byte(pdev, 0x60, &sbrn);		/* help hc dma work well with cachelines */		retval = pci_set_mwi(pdev);		if (retval)			ehci_dbg(ehci, "unable to enable MWI - not fatal.\n");	}#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 (!dma_set_mask (hcd->self.controller, DMA_64BIT_MASK))			ehci_info (ehci, "enabled 64bit 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 ... ? */	/*	 * 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 = HC_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);	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */	return 0;}/* always called by thread; normally rmmod */static void ehci_stop (struct usb_hcd *hcd){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	unsigned long		context;		ehci_dbg (ehci, "stop\n");	/* Turn off port power on all root hub ports. */	ehci_port_power (ehci, 0);	/* no more interrupts ... */	del_timer_sync (&ehci->watchdog);	rtdm_lock_get_irqsave(&ehci->rt_lock, context);	if (HC_IS_RUNNING (hcd->state))		ehci_quiesce (ehci);	ehci_reset (ehci);	writel (0, &ehci->regs->intr_enable);	rtdm_lock_put_irqrestore(&ehci->rt_lock, context);	/* let companion controllers work when we aren't */	writel (0, &ehci->regs->configured_flag);	unregister_reboot_notifier (&ehci->reboot_notifier);	/* root hub is shut down separately (first, when possible) */	rtdm_lock_get_irqsave(&ehci->rt_lock, context);	if (ehci->async)		ehci_work (ehci);	rtdm_lock_put_irqrestore(&ehci->rt_lock, context);	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, pm_message_t message){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	if (time_before (jiffies, ehci->next_statechange)){		if(rtdm_in_rt_context())			rtdm_task_sleep(1000000 * 100);		else			msleep (100);	}	rtdm_usb_lock_device (hcd->self.root_hub);	(void) ehci_hub_suspend (hcd);	rtdm_usb_unlock_device (hcd->self.root_hub);	// 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 rtdm_usb_device	*root = hcd->self.root_hub;	int			retval = -EINVAL;	unsigned long 		context;	// maybe restore (PCI) FLADJ	if (time_before (jiffies, ehci->next_statechange)){		if(rtdm_in_rt_context())			rtdm_task_sleep(1000000 * 100);		else			msleep (100);	}	/* If any port is suspended (or owned by the companion),	 * we know we can/must resume the HC (and mustn't reset it).	 */	for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {		u32	status;		port--;		status = readl (&ehci->regs->port_status [port]);		if (!(status & PORT_POWER))			continue;		if (status & (PORT_SUSPEND | PORT_OWNER)) {//			rtdm_sem_down (&hcd->self.root_hub->rt_serialize);			retval = ehci_hub_resume (hcd);//			rtdm_sem_up (&hcd->self.root_hub->rt_serialize);			break;		}		if (!root->children [port])			continue;		dbg_port (ehci, __FUNCTION__, port + 1, status);		rtdm_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 */		rtdm_lock_get_irqsave(&ehci->rt_lock, context);		if (ehci->reclaim)			ehci->reclaim_ready = 1;		ehci_work (ehci);		rtdm_lock_put_irqrestore(&ehci->rt_lock, context);		/* restart; khubd will disconnect devices */		retval = ehci_start (hcd);		/* here we "know" root ports should always stay powered;		 * but some controllers may lose all power.		 */		ehci_port_power (ehci, 1);	}	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){	timer_action_done (ehci, TIMER_IO_WATCHDOG);	if (ehci->reclaim_ready)

⌨️ 快捷键说明

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