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

📄 dwc_otg_cil.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 5 页
字号:
						_hc->data_pid_start = DWC_OTG_HC_PID_MDATA;					}				}			} else {				_hc->data_pid_start = DWC_OTG_HC_PID_DATA0;			}		}		hctsiz.b.xfersize = _hc->xfer_len;	}	_hc->start_pkt_count = num_packets;	hctsiz.b.pktcnt = num_packets;	hctsiz.b.pid = _hc->data_pid_start;	dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);	dbg_otg("%s: Channel %d\n", __func__, _hc->hc_num);	dbg_otg("	 Xfer Size: %d\n", hctsiz.b.xfersize);	dbg_otg("	 Num Pkts: %d\n", hctsiz.b.pktcnt);	dbg_otg("	 Start PID: %d\n", hctsiz.b.pid);	if (_core_if->dma_enable) {		dwc_write_reg32(&hc_regs->hcdma, (uint32_t) _hc->xfer_buff);	}	/* Start the split */	if (unlikely(_hc->do_split)) {		hcsplt_data_t hcsplt;		hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);		hcsplt.b.spltena = 1;		dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32);	}	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);	hcchar.b.multicnt = _hc->multi_count;	hc_set_even_odd_frame(_core_if, _hc, &hcchar);#ifdef DEBUG	_core_if->start_hcchar_val[_hc->hc_num] = hcchar.d32;	if (hcchar.b.chdis) {		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",			 __func__, _hc->hc_num, hcchar.d32);	}#endif	/* Set host channel enable after all other setup is complete. */	hcchar.b.chen = 1;	hcchar.b.chdis = 0;	printk("%s() - %08x\n", __FUNCTION__, hcchar.d32);	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);	_hc->xfer_started = 1;	_hc->requests++;	if (unlikely(!_core_if->dma_enable && !_hc->ep_is_in && _hc->xfer_len > 0)) {		/* Load OUT packet into the appropriate Tx FIFO. */		dwc_otg_hc_write_packet(_core_if, _hc);	}#ifdef DEBUG	/* Start a timer for this transfer. */	_core_if->hc_xfer_timer[_hc->hc_num].function = hc_xfer_timeout;	_core_if->hc_xfer_info[_hc->hc_num].core_if = _core_if;	_core_if->hc_xfer_info[_hc->hc_num].hc = _hc;	_core_if->hc_xfer_timer[_hc->hc_num].data =		(unsigned long) (&_core_if->hc_xfer_info[_hc->hc_num]);	_core_if->hc_xfer_timer[_hc->hc_num].expires = jiffies + (HZ * 10);	add_timer(&_core_if->hc_xfer_timer[_hc->hc_num]);#endif}/** * This function continues a data transfer that was started by previous call * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is * sufficient space in the request queue and Tx Data FIFO. This function * should only be called in Slave mode. In DMA mode, the controller acts * autonomously to complete transfers programmed to a host channel. * * For an OUT transfer, a new data packet is loaded into the appropriate FIFO * if there is any data remaining to be queued. For an IN transfer, another * data packet is always requested. For the SETUP phase of a control transfer, * this function does nothing. * * @return 1 if a new request is queued, 0 if no more requests are required * for this transfer. */int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc){	dbg_otg("%s: Channel %d\n", __func__, _hc->hc_num);	if (_hc->do_split) {		/* SPLITs always queue just once per channel */		return 0;	} else if (_hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {		/* SETUPs are queued only once since they can't be NAKed. */		return 0;	} else if (_hc->ep_is_in) {		/*		 * Always queue another request for other IN transfers. If		 * back-to-back INs are issued and NAKs are received for both,		 * the driver may still be processing the first NAK when the		 * second NAK is received. When the interrupt handler clears		 * the NAK interrupt for the first NAK, the second NAK will		 * not be seen. So we can't depend on the NAK interrupt		 * handler to requeue a NAKed request. Instead, IN requests		 * are issued each time this function is called. When the		 * transfer completes, the extra requests for the channel will		 * be flushed.		 */		hcchar_data_t hcchar;		dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);		hc_set_even_odd_frame(_core_if, _hc, &hcchar);		hcchar.b.chen = 1;		hcchar.b.chdis = 0;		DWC_DEBUGPL(DBG_HCDV, "	 IN xfer: hcchar = 0x%08x\n", hcchar.d32);		dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);		_hc->requests++;		return 1;	} else {		/* OUT transfers. */		if (_hc->xfer_count < _hc->xfer_len) {			if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||			    _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {				hcchar_data_t hcchar;				dwc_otg_hc_regs_t *hc_regs;				hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];				hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);				hc_set_even_odd_frame(_core_if, _hc, &hcchar);			}			/* Load OUT packet into the appropriate Tx FIFO. */			dwc_otg_hc_write_packet(_core_if, _hc);			_hc->requests++;			return 1;		} else {			return 0;		}	}}/** * Starts a PING transfer. This function should only be called in Slave mode. * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled. */void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc){	hcchar_data_t hcchar;	hctsiz_data_t hctsiz;	dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);	hctsiz.d32 = 0;	hctsiz.b.dopng = 1;	hctsiz.b.pktcnt = 1;	dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);	hcchar.b.chen = 1;	hcchar.b.chdis = 0;	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);}/* * This function writes a packet into the Tx FIFO associated with the Host * Channel. For a channel associated with a non-periodic EP, the non-periodic * Tx FIFO is written. For a channel associated with a periodic EP, the * periodic Tx FIFO is written. This function should only be called in Slave * mode. * * Upon return the xfer_buff and xfer_count fields in _hc are incremented by * then number of bytes written to the Tx FIFO. */void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc){	uint32_t i;	uint32_t remaining_count;	uint32_t byte_count;	uint32_t dword_count;	uint32_t *data_buff = (uint32_t *) (_hc->xfer_buff);	uint32_t *data_fifo = _core_if->data_fifo[_hc->hc_num];	remaining_count = _hc->xfer_len - _hc->xfer_count;	if (remaining_count > _hc->max_packet) {		byte_count = _hc->max_packet;	} else {		byte_count = remaining_count;	}	dword_count = (byte_count + 3) / 4;	if ((((unsigned long) data_buff) & 0x3) == 0) {		/* xfer_buff is DWORD aligned. */		for (i = 0; i < dword_count; i++, data_buff++) {			dwc_write_reg32(data_fifo, *data_buff);		}	} else {		/* xfer_buff is not DWORD aligned. */		for (i = 0; i < dword_count; i++, data_buff++) {			dwc_write_reg32(data_fifo, get_unaligned(data_buff));		}	}	_hc->xfer_count += byte_count;	_hc->xfer_buff += byte_count;}/** * Gets the current USB frame number. This is the frame number from the last * SOF packet. */uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if){	dsts_data_t dsts;	dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts);	/* read current frame/microframe number from DSTS register */	return dsts.b.soffn;}/** * This function reads a setup packet from the Rx FIFO into the destination * buffer.	This function is called from the Rx Status Queue Level (RxStsQLvl) * Interrupt routine when a SETUP packet has been received in Slave mode. * * @param _core_if Programming view of DWC_otg controller. * @param _dest Destination buffer for packet data. */void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if, uint32_t * _dest){	/* Get the 8 bytes of a setup transaction data */	/* Pop 2 DWORDS off the receive data FIFO into memory */	_dest[0] = dwc_read_reg32(_core_if->data_fifo[0]);	_dest[1] = dwc_read_reg32(_core_if->data_fifo[0]);}/** * This function enables EP0 OUT to receive SETUP packets and configures EP0 * IN for transmitting packets.	 It is normally called when the * "Enumeration Done" interrupt occurs. * * @param _core_if Programming view of DWC_otg controller. * @param _ep The EP0 data. */void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep){	dwc_otg_dev_if_t *dev_if = _core_if->dev_if;	dsts_data_t dsts;	depctl_data_t diepctl;	depctl_data_t doepctl;	dctl_data_t dctl = {.d32 = 0 };	/* Read the Device Status and Endpoint 0 Control registers */	dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts);	diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl);	doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);	/* Set the MPS of the IN EP based on the enumeration speed */	switch (dsts.b.enumspd) {	case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:	case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:	case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:		diepctl.b.mps = DWC_DEP0CTL_MPS_64;		break;	case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:		diepctl.b.mps = DWC_DEP0CTL_MPS_8;		break;	}	dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);	/* Enable OUT EP for receive */	doepctl.b.epena = 1;	dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);#ifdef VERBOSE	DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n", dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));	DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n", dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));#endif	dctl.b.cgnpinnak = 1;	dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);	DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n", dwc_read_reg32(&dev_if->dev_global_regs->dctl));}/** * This function activates an EP.  The Device EP control register for * the EP is configured as defined in the ep structure.	 Note: This * function is not used for EP0. * * @param _core_if Programming view of DWC_otg controller. * @param _ep The EP to activate. */void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep){	dwc_otg_dev_if_t *dev_if = _core_if->dev_if;	depctl_data_t depctl;	volatile uint32_t *addr;	daint_data_t daintmsk = {.d32 = 0 };	DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, _ep->num, (_ep->is_in ? "IN" : "OUT"));	/* Read DEPCTLn register */	if (_ep->is_in == 1) {		addr = &dev_if->in_ep_regs[_ep->num]->diepctl;		daintmsk.ep.in = 1 << _ep->num;	} else {		addr = &dev_if->out_ep_regs[_ep->num]->doepctl;		daintmsk.ep.out = 1 << _ep->num;	}	/* If the EP is already active don't change the EP Control	 * register. */	depctl.d32 = dwc_read_reg32(addr);	if (!depctl.b.usbactep) {		depctl.b.mps = _ep->maxpacket;		depctl.b.eptype = _ep->type;		depctl.b.txfnum = _ep->tx_fifo_num;		if (_ep->type == DWC_OTG_EP_TYPE_ISOC) {			depctl.b.setd0pid = 1;	// ???		} else {			depctl.b.setd0pid = 1;		}		depctl.b.usbactep = 1;		dwc_write_reg32(addr, depctl.d32);		DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", dwc_read_reg32(addr));	}	/* Enable the Interrupt for this EP */	dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk, 0, daintmsk.d32);	DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n", dwc_read_reg32(&dev_if->dev_global_regs->daintmsk));	_ep->stall_clear_flag = 0;	return;}/** * This function deactivates an EP.	 This is done by clearing the USB Active * EP bit in the Device EP control register.  Note: This function is not used * for EP0. EP0 cannot be deactivated. * * @param _core_if Programming view of DWC_otg controller. * @param _ep The EP to deactivate. */void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep){	depctl_data_t depctl = {.d32 = 0 };	volatile uint32_t *addr;	daint_data_t daintmsk = {.d32 = 0 };	/* Read DEPCTLn register */	if (_ep->is_in == 1) {		addr = &_core_if->dev_if->in_ep_regs[_ep->num]->diepctl;		daintmsk.ep.in = 1 << _ep->num;	} else {		addr = &_core_if->dev_if->out_ep_regs[_ep->num]->doepctl;		daintmsk.ep.out = 1 << _ep->num;	}	depctl.b.usbactep = 0;	if (_core_if->dma_desc_enable)		depctl.b.epdis = 1;	dwc_write_reg32(addr, depctl.d32);	/* Disable the Interrupt for this EP */	dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->daintmsk, daintmsk.d32, 0);	return;}/** * This function does the setup for a data transfer for an EP and * starts the transfer.	 For an IN transfer, the packets will be * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, * the packets are unloaded from the Rx FIFO in the ISR.  the ISR. * * @param _core_if Programming view of DWC_otg controller. * @param _ep The EP to start the transfer on. * FOR PCD only. by scsuh */void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep){	/** @todo Refactor this funciton to check the transfer size	 * count value does not execed the number bits in the Transfer	 * count register. */	depctl_data_t depctl;	deptsiz_data_t deptsiz;	gintmsk_data_t intr_mask = {.d32 = 0 };	dwc_otg_dma_desc_t *dma_desc;	dbg_otg("%s()\n", __func__);	dbg_otg("ep%d-%s xfer_len=%d xfer_cnt=%d "		    "xfer_buff=%p start_xfer_buff=%p\n",		    _ep->num, (_ep->is_in ? "IN" : "OUT"), _ep->xfer_len,		    _ep->xfer_count, _ep->xf

⌨️ 快捷键说明

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