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

📄 dwc_otg_cil.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 5 页
字号:
	hcchar.b.lspddev = (_hc->speed == DWC_OTG_EP_SPEED_LOW);	hcchar.b.eptype = _hc->ep_type;	hcchar.b.mps = _hc->max_packet;	dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);	DWC_DEBUGPL(DBG_HCDV, "	 Dev Addr: %d\n", hcchar.b.devaddr);	DWC_DEBUGPL(DBG_HCDV, "	 Ep Num: %d\n", hcchar.b.epnum);	DWC_DEBUGPL(DBG_HCDV, "	 Is In: %d\n", hcchar.b.epdir);	DWC_DEBUGPL(DBG_HCDV, "	 Is Low Speed: %d\n", hcchar.b.lspddev);	DWC_DEBUGPL(DBG_HCDV, "	 Ep Type: %d\n", hcchar.b.eptype);	DWC_DEBUGPL(DBG_HCDV, "	 Max Pkt: %d\n", hcchar.b.mps);	DWC_DEBUGPL(DBG_HCDV, "	 Multi Cnt: %d\n", hcchar.b.multicnt);	/*	 * Program the HCSPLIT register for SPLITs	 */	hcsplt.d32 = 0;	if (_hc->do_split) {		DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", _hc->hc_num,			    _hc->complete_split ? "CSPLIT" : "SSPLIT");		hcsplt.b.compsplt = _hc->complete_split;		hcsplt.b.xactpos = _hc->xact_pos;		hcsplt.b.hubaddr = _hc->hub_addr;		hcsplt.b.prtaddr = _hc->port_addr;		DWC_DEBUGPL(DBG_HCDV, "	  comp split %d\n", _hc->complete_split);		DWC_DEBUGPL(DBG_HCDV, "	  xact pos %d\n", _hc->xact_pos);		DWC_DEBUGPL(DBG_HCDV, "	  hub addr %d\n", _hc->hub_addr);		DWC_DEBUGPL(DBG_HCDV, "	  port addr %d\n", _hc->port_addr);		DWC_DEBUGPL(DBG_HCDV, "	  is_in %d\n", _hc->ep_is_in);		DWC_DEBUGPL(DBG_HCDV, "	  Max Pkt: %d\n", hcchar.b.mps);		DWC_DEBUGPL(DBG_HCDV, "	  xferlen: %d\n", _hc->xfer_len);	}	dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);}/** * Attempts to halt a host channel. This function should only be called in * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under * normal circumstances in DMA mode, the controller halts the channel when the * transfer is complete or a condition occurs that requires application * intervention. * * In slave mode, checks for a free request queue entry, then sets the Channel * Enable and Channel Disable bits of the Host Channel Characteristics * register of the specified channel to intiate the halt. If there is no free * request queue entry, sets only the Channel Disable bit of the HCCHARn * register to flush requests for this channel. In the latter case, sets a * flag to indicate that the host channel needs to be halted when a request * queue slot is open. * * In DMA mode, always sets the Channel Enable and Channel Disable bits of the * HCCHARn register. The controller ensures there is space in the request * queue before submitting the halt request. * * Some time may elapse before the core flushes any posted requests for this * host channel and halts. The Channel Halted interrupt handler completes the * deactivation of the host channel. * * @param _core_if Controller register interface. * @param _hc Host channel to halt. * @param _halt_status Reason for halting the channel. */void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,		     dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status){	gnptxsts_data_t nptxsts;	hptxsts_data_t hptxsts;	hcchar_data_t hcchar;	dwc_otg_hc_regs_t *hc_regs;	dwc_otg_core_global_regs_t *global_regs;	dwc_otg_host_global_regs_t *host_global_regs;	hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];	global_regs = _core_if->core_global_regs;	host_global_regs = _core_if->host_if->host_global_regs;	WARN_ON(_halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS);	if (_halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || _halt_status == DWC_OTG_HC_XFER_AHB_ERR) {		/*		 * Disable all channel interrupts except Ch Halted. The QTD		 * and QH state associated with this transfer has been cleared		 * (in the case of URB_DEQUEUE), so the channel needs to be		 * shut down carefully to prevent crashes.		 */		hcintmsk_data_t hcintmsk;		hcintmsk.d32 = 0;		hcintmsk.b.chhltd = 1;		dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32);		/*		 * Make sure no other interrupts besides halt are currently		 * pending. Handling another interrupt could cause a crash due		 * to the QTD and QH state.		 */		dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32);		/*		 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR		 * even if the channel was already halted for some other		 * reason.		 */		_hc->halt_status = _halt_status;		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);		if (hcchar.b.chen == 0) {			/*			 * The channel is either already halted or it hasn't			 * started yet. In DMA mode, the transfer may halt if			 * it finishes normally or a condition occurs that			 * requires driver intervention. Don't want to halt			 * the channel again. In either Slave or DMA mode,			 * it's possible that the transfer has been assigned			 * to a channel, but not started yet when an URB is			 * dequeued. Don't want to halt a channel that hasn't			 * started yet.			 */			return;		}	}	if (_hc->halt_pending) {		/*		 * A halt has already been issued for this channel. This might		 * happen when a transfer is aborted by a higher level in		 * the stack.		 */#ifdef DEBUG		DWC_PRINT("*** %s: Channel %d, _hc->halt_pending already set ***\n",			  __func__, _hc->hc_num);/*		dwc_otg_dump_global_registers(_core_if); *//*		dwc_otg_dump_host_registers(_core_if); */#endif		return;	}	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);	hcchar.b.chen = 1;	hcchar.b.chdis = 1;	if (!_core_if->dma_enable) {		/* Check for space in the request queue to issue the halt. */		if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || _hc->ep_type == DWC_OTG_EP_TYPE_BULK) {			nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts);			if (nptxsts.b.nptxqspcavail == 0) {				hcchar.b.chen = 0;			}		} else {			hptxsts.d32 = dwc_read_reg32(&host_global_regs->hptxsts);			if ((hptxsts.b.ptxqspcavail == 0) || (_core_if->queuing_high_bandwidth)) {				hcchar.b.chen = 0;			}		}	}	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);	_hc->halt_status = _halt_status;	if (hcchar.b.chen) {		_hc->halt_pending = 1;		_hc->halt_on_queue = 0;	} else {		_hc->halt_on_queue = 1;	}	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);	DWC_DEBUGPL(DBG_HCDV, "	 hcchar: 0x%08x\n", hcchar.d32);	DWC_DEBUGPL(DBG_HCDV, "	 halt_pending: %d\n", _hc->halt_pending);	DWC_DEBUGPL(DBG_HCDV, "	 halt_on_queue: %d\n", _hc->halt_on_queue);	DWC_DEBUGPL(DBG_HCDV, "	 halt_status: %d\n", _hc->halt_status);	return;}/** * Clears the transfer state for a host channel. This function is normally * called after a transfer is done and the host channel is being released. * * @param _core_if Programming view of DWC_otg controller. * @param _hc Identifies the host channel to clean up. */void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc){	dwc_otg_hc_regs_t *hc_regs;	_hc->xfer_started = 0;	/*	 * Clear channel interrupt enables and any unhandled channel interrupt	 * conditions.	 */	hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];	dwc_write_reg32(&hc_regs->hcintmsk, 0);	dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF);#ifdef DEBUG	del_timer(&_core_if->hc_xfer_timer[_hc->hc_num]);	{		hcchar_data_t hcchar;		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);		if (hcchar.b.chdis) {			DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",				 __func__, _hc->hc_num, hcchar.d32);		}	}#endif}/** * Sets the channel property that indicates in which frame a periodic transfer * should occur. This is always set to the _next_ frame. This function has no * effect on non-periodic transfers. * * @param _core_if Programming view of DWC_otg controller. * @param _hc Identifies the host channel to set up and its properties. * @param _hcchar Current value of the HCCHAR register for the specified host * channel. */static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * _core_if,					 dwc_hc_t * _hc, hcchar_data_t * _hcchar){	if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {		hfnum_data_t hfnum;		hfnum.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hfnum);		/* 1 if _next_ frame is odd, 0 if it's even */		_hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;#ifdef DEBUG		if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR && _hc->do_split && !_hc->complete_split) {			switch (hfnum.b.frnum & 0x7) {			case 7:				_core_if->hfnum_7_samples++;				_core_if->hfnum_7_frrem_accum += hfnum.b.frrem;				break;			case 0:				_core_if->hfnum_0_samples++;				_core_if->hfnum_0_frrem_accum += hfnum.b.frrem;				break;			default:				_core_if->hfnum_other_samples++;				_core_if->hfnum_other_frrem_accum += hfnum.b.frrem;				break;			}		}#endif	}}#ifdef DEBUGstatic void hc_xfer_timeout(unsigned long _ptr){	hc_xfer_info_t *xfer_info = (hc_xfer_info_t *) _ptr;	int hc_num = xfer_info->hc->hc_num;	DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);	DWC_WARN("	start_hcchar_val 0x%08x\n", xfer_info->core_if->start_hcchar_val[hc_num]);}#endif/* * This function does the setup for a data transfer for a host channel and * starts the transfer. May be called in either Slave mode or DMA mode. In * Slave mode, the caller must ensure that there is sufficient space in the * request queue and Tx Data FIFO. * * For an OUT transfer in Slave mode, it loads a data packet into the * appropriate FIFO. If necessary, additional data packets will be loaded in * the Host ISR. * * For an IN transfer in Slave mode, a data packet is requested. The data * packets are unloaded from the Rx FIFO in the Host ISR. If necessary, * additional data packets are requested in the Host ISR. * * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ * register along with a packet count of 1 and the channel is enabled. This * causes a single PING transaction to occur. Other fields in HCTSIZ are * simply set to 0 since no data transfer occurs in this case. * * For a PING transfer in DMA mode, the HCTSIZ register is initialized with * all the information required to perform the subsequent data transfer. In * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the * controller performs the entire PING protocol, then starts the data * transfer. * * @param _core_if Programming view of DWC_otg controller. * @param _hc Information needed to initialize the host channel. The xfer_len * value may be reduced to accommodate the max widths of the XferSize and * PktCnt fields in the HCTSIZn register. The multi_count value may be changed * to reflect the final xfer_len value. */void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc){	hcchar_data_t hcchar;	hctsiz_data_t hctsiz;	uint16_t num_packets;	uint32_t max_hc_xfer_size = _core_if->core_params->max_transfer_size;	uint16_t max_hc_pkt_count = _core_if->core_params->max_packet_count;	dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];	hctsiz.d32 = 0;#if 0 // orig	if (_hc->do_ping) {		if (!_core_if->dma_enable) {			dwc_otg_hc_do_ping(_core_if, _hc);			_hc->xfer_started = 1;			return;		} else {			hctsiz.b.dopng = 1;		}	}#else	if (_hc->do_ping) {		if (likely(_core_if->dma_enable)) {			hctsiz.b.dopng = 1;		} else {			dwc_otg_hc_do_ping(_core_if, _hc);			_hc->xfer_started = 1;			return;		}	}#endif	/*	 * split attribute is generally used in USB 1.1 spec	 * When you want to use USB 2.0 HIGH speed this is unnecessary.	 * by scsuh	 */	if (unlikely(_hc->do_split)) {		num_packets = 1;		if (_hc->complete_split && !_hc->ep_is_in) {			/* For CSPLIT OUT Transfer, set the size to 0 so the			 * core doesn't expect any data written to the FIFO */			_hc->xfer_len = 0;		} else if (_hc->ep_is_in || (_hc->xfer_len > _hc->max_packet)) {			_hc->xfer_len = _hc->max_packet;		} else if (!_hc->ep_is_in && (_hc->xfer_len > 188)) {			_hc->xfer_len = 188;		}		hctsiz.b.xfersize = _hc->xfer_len;	} else {		/*		 * Ensure that the transfer length and packet count will fit		 * in the widths allocated for them in the HCTSIZn register.		 */		if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {			/*			 * Make sure the transfer size is no larger than one			 * (micro)frame's worth of data. (A check was done			 * when the periodic transfer was accepted to ensure			 * that a (micro)frame's worth of data can be			 * programmed into a channel.)			 */			uint32_t max_periodic_len = _hc->multi_count * _hc->max_packet;			if (_hc->xfer_len > max_periodic_len) {				_hc->xfer_len = max_periodic_len;			} else {			}		} else if (_hc->xfer_len > max_hc_xfer_size) {			/* Make sure that xfer_len is a multiple of max packet size. */			_hc->xfer_len = max_hc_xfer_size - _hc->max_packet + 1;		}		if (_hc->xfer_len > 0) {			num_packets = (_hc->xfer_len + _hc->max_packet - 1) / _hc->max_packet;			if (num_packets > max_hc_pkt_count) {				num_packets = max_hc_pkt_count;				_hc->xfer_len = num_packets * _hc->max_packet;			}		} else {			/* Need 1 packet for transfer length of 0. */			num_packets = 1;		}		if (_hc->ep_is_in) {			/* Always program an integral # of max packets for IN transfers. */			_hc->xfer_len = num_packets * _hc->max_packet;		}		if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {			/*			 * Make sure that the multi_count field matches the			 * actual transfer length.			 */			_hc->multi_count = num_packets;		}		if (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {			/* Set up the initial PID for the transfer. */			if (_hc->speed == DWC_OTG_EP_SPEED_HIGH) {				if (_hc->ep_is_in) {					if (_hc->multi_count == 1) {						_hc->data_pid_start = DWC_OTG_HC_PID_DATA0;					} else if (_hc->multi_count == 2) {						_hc->data_pid_start = DWC_OTG_HC_PID_DATA1;					} else {						_hc->data_pid_start = DWC_OTG_HC_PID_DATA2;					}				} else {					if (_hc->multi_count == 1) {						_hc->data_pid_start = DWC_OTG_HC_PID_DATA0;					} else {

⌨️ 快捷键说明

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