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

📄 dwc_otg_pcd_intr.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 5 页
字号:
/** * This interrupt indicates that the ISO OUT Packet was dropped due to * Rx FIFO full or Rx Status Queue Full.  If this interrupt occurs * read all the data from the Rx FIFO. */int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t *_pcd ){	gintmsk_data_t intr_mask = { .d32 = 0};	gintsts_data_t gintsts;	DWC_PRINT("INTERRUPT Handler not implemented for %s\n",			  "ISOC Out Dropped");	intr_mask.b.isooutdrop = 1;	dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,					  intr_mask.d32, 0 );	/* Clear interrupt */	gintsts.d32 = 0;	gintsts.b.isooutdrop = 1;	dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,						 gintsts.d32);	return 1;}/** * This interrupt indicates the end of the portion of the micro-frame * for periodic transactions.  If there is a periodic transaction for * the next frame, load the packets into the EP periodic Tx FIFO. */int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t *_pcd ){	gintmsk_data_t intr_mask = { .d32 = 0};	gintsts_data_t gintsts;	DWC_PRINT("INTERRUPT Handler not implemented for %s\n",			  "EOP");	intr_mask.b.eopframe = 1;	dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,					  intr_mask.d32, 0 );	/* Clear interrupt */	gintsts.d32 = 0;	gintsts.b.eopframe = 1;	dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,						 gintsts.d32);	return 1;}/** * This interrupt indicates that EP of the packet on the top of the * non-periodic Tx FIFO does not match EP of the IN Token received. * * The "Device IN Token Queue" Registers are read to determine the * order the IN Tokens have been received.	The non-periodic Tx FIFO * is flushed, so it can be reloaded in the order seen in the IN Token * Queue. */int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_core_if_t *_core_if){	gintsts_data_t gintsts;	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _core_if);	/* Clear interrupt */	gintsts.d32 = 0;	gintsts.b.epmismatch = 1;	dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);	return 1;}/** * This funcion stalls EP0. */static inline void ep0_do_stall( dwc_otg_pcd_t *_pcd, const int err_val ){	dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;	struct usb_ctrlrequest	*ctrl = &_pcd->setup_pkt->req;	DWC_WARN("req %02x.%02x protocol STALL; err %d\n",			 ctrl->bRequestType, ctrl->bRequest, err_val);	ep0->dwc_ep.is_in = 1;	dwc_otg_ep_set_stall( _pcd->otg_dev->core_if, &ep0->dwc_ep );	_pcd->ep0.stopped = 1;	_pcd->ep0state = EP0_IDLE;	ep0_out_start( GET_CORE_IF(_pcd), _pcd );}/** * This functions delegates the setup command to the gadget driver. */static inline void do_gadget_setup( dwc_otg_pcd_t *_pcd,									struct usb_ctrlrequest * _ctrl){	int ret = 0;	if (_pcd->driver && _pcd->driver->setup)	{		SPIN_UNLOCK(&_pcd->lock);		ret = _pcd->driver->setup(&_pcd->gadget, _ctrl);		SPIN_LOCK(&_pcd->lock);		if (ret < 0)		{			ep0_do_stall( _pcd, ret );		}		/** @todo This is a g_file_storage gadget driver specific		 * workaround: a DELAYED_STATUS result from the fsg_setup		 * routine will result in the gadget queueing a EP0 IN status		 * phase for a two-stage control transfer.	Exactly the same as		 * a SET_CONFIGURATION/SET_INTERFACE except that this is a class		 * specific request.  Need a generic way to know when the gadget		 * driver will queue the status phase.	Can we assume when we		 * call the gadget driver setup() function that it will always		 * queue and require the following flag?  Need to look into		 * this.		 */		if (ret == 256 + 999)		{			_pcd->request_config = 1;		}	}}/** * This function starts the Zero-Length Packet for the IN status phase * of a 2 stage control transfer. */static inline void do_setup_in_status_phase( dwc_otg_pcd_t *_pcd){	dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;	if (_pcd->ep0state == EP0_STALL)	{		return;	}	_pcd->ep0state = EP0_IN_STATUS_PHASE;	/* Prepare for more SETUP Packets */	DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");	ep0->dwc_ep.xfer_len = 0;	ep0->dwc_ep.xfer_count = 0;	ep0->dwc_ep.is_in = 1;	ep0->dwc_ep.dma_addr = _pcd->setup_pkt_dma_handle;	dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );	/* Prepare for more SETUP Packets */	ep0_out_start( GET_CORE_IF(_pcd), _pcd );}/** * This function starts the Zero-Length Packet for the OUT status phase * of a 2 stage control transfer. */static inline void do_setup_out_status_phase( dwc_otg_pcd_t *_pcd){	dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;	if (_pcd->ep0state == EP0_STALL)	{		DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");		return;	}	_pcd->ep0state = EP0_OUT_STATUS_PHASE;	DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");	ep0->dwc_ep.xfer_len = 0;	ep0->dwc_ep.xfer_count = 0;	ep0->dwc_ep.is_in = 0;	ep0->dwc_ep.dma_addr = _pcd->setup_pkt_dma_handle;	dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );	/* Prepare for more SETUP Packets */	ep0_out_start( GET_CORE_IF(_pcd), _pcd );}/** * Clear the EP halt (STALL) and if pending requests start the * transfer. */static inline void pcd_clear_halt( dwc_otg_pcd_t *_pcd, dwc_otg_pcd_ep_t *_ep ){	if(_ep->dwc_ep.stall_clear_flag == 0)		dwc_otg_ep_clear_stall( GET_CORE_IF(_pcd), &_ep->dwc_ep );	/* Reactive the EP */	dwc_otg_ep_activate( GET_CORE_IF(_pcd), &_ep->dwc_ep );	if (_ep->stopped)	{		_ep->stopped = 0;		/* If there is a request in the EP queue start it */		/** @todo FIXME: this causes an EP mismatch in DMA mode.		 * epmismatch not yet implemented. */		/*		 * Above fixme is solved by implmenting a tasklet to call the		 * start_next_request(), outside of interrupt context at some		 * time after the current time, after a clear-halt setup packet.		 * Still need to implement ep mismatch in the future if a gadget		 * ever uses more than one endpoint at once		 */		if (GET_CORE_IF(_pcd)->dma_enable)		{			_ep->queue_sof = 1;			tasklet_schedule (_pcd->start_xfer_tasklet);		}		else		{#if 0			_ep->queue_sof = 1;			DWC_ERROR("tasklet schedule\n");			tasklet_schedule (_pcd->start_xfer_tasklet);			if (GET_CORE_IF(_pcd)->core_params->opt)			{				start_next_request( _ep );			}#endif		}	}	/* Start Control Status Phase */	do_setup_in_status_phase( _pcd );}/** * This function is called when the SET_FEATURE TEST_MODE Setup packet * is sent from the host.  The Device Control register is written with * the Test Mode bits set to the specified Test Mode.  This is done as * a tasklet so that the "Status" phase of the control transfer * completes before transmitting the TEST packets. * * @todo This has not been tested since the tasklet struct was put * into the PCD struct! * */static void do_test_mode( unsigned long _data ){	dctl_data_t		dctl;	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_data;	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);	int test_mode = pcd->test_mode;//	  DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);	dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);	switch (test_mode)	{	case 1: // TEST_J		dctl.b.tstctl = 1;		break;	case 2: // TEST_K		dctl.b.tstctl = 2;		break;	case 3: // TEST_SE0_NAK		dctl.b.tstctl = 3;		break;	case 4: // TEST_PACKET		dctl.b.tstctl = 4;		break;	case 5: // TEST_FORCE_ENABLE		dctl.b.tstctl = 5;		break;	}	dwc_write_reg32(&core_if->dev_if->dev_global_regs->dctl,						dctl.d32);}/** * This function process the GET_STATUS Setup Commands. */static inline void do_get_status( dwc_otg_pcd_t *_pcd ){	struct usb_ctrlrequest	ctrl = _pcd->setup_pkt->req;	dwc_otg_pcd_ep_t		*ep;	dwc_otg_pcd_ep_t		*ep0 = &_pcd->ep0;	uint16_t				*status = _pcd->status_buf;#ifdef DEBUG_EP0		DWC_DEBUGPL(DBG_PCD,						"GET_STATUS %02x.%02x v%04x i%04x l%04x\n",						ctrl.bRequestType, ctrl.bRequest,						ctrl.wValue, ctrl.wIndex, ctrl.wLength);#endif	switch (ctrl.bRequestType & USB_RECIP_MASK)	{	case USB_RECIP_DEVICE:		*status = 0x1; /* Self powered */		*status |= _pcd->remote_wakeup_enable << 1;		break;	case USB_RECIP_INTERFACE:		*status = 0;		break;	case USB_RECIP_ENDPOINT:		ep = get_ep_by_addr(_pcd, ctrl.wIndex);		if ( ep == 0 || ctrl.wLength > 2)		{			ep0_do_stall(_pcd, -EOPNOTSUPP);			return;		}		/** @todo check for EP stall */		*status = ep->stopped;		break;	}	_pcd->ep0_pending = 1;	ep0->dwc_ep.start_xfer_buff = (uint8_t *)status;	ep0->dwc_ep.xfer_buff = (uint8_t *)status;	ep0->dwc_ep.dma_addr = _pcd->status_buf_dma_handle;	ep0->dwc_ep.xfer_len = 2;	ep0->dwc_ep.xfer_count = 0;	ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;	dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );}/** * This function process the SET_FEATURE Setup Commands. */static inline void do_set_feature( dwc_otg_pcd_t *_pcd ){	dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);	dwc_otg_core_global_regs_t *global_regs =			core_if->core_global_regs;	struct usb_ctrlrequest	ctrl = _pcd->setup_pkt->req;	dwc_otg_pcd_ep_t	*ep = 0;	int32_t otg_cap_param = core_if->core_params->otg_cap;	gotgctl_data_t gotgctl = { .d32 = 0 };	DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",					ctrl.bRequestType, ctrl.bRequest,					ctrl.wValue, ctrl.wIndex, ctrl.wLength);	DWC_DEBUGPL(DBG_PCD,"otg_cap=%d\n", otg_cap_param);	switch (ctrl.bRequestType & USB_RECIP_MASK)	{	case USB_RECIP_DEVICE:		switch (ctrl.wValue)		{		case USB_DEVICE_REMOTE_WAKEUP:			_pcd->remote_wakeup_enable = 1;			break;		case USB_DEVICE_TEST_MODE:			/* Setup the Test Mode tasklet to do the Test			 * Packet generation after the SETUP Status			 * phase has completed. */			/** @todo This has not been tested since the			 * tasklet struct was put into the PCD			 * struct! */			_pcd->test_mode_tasklet.next = 0;			_pcd->test_mode_tasklet.state = 0;			atomic_set( &_pcd->test_mode_tasklet.count, 0);			_pcd->test_mode_tasklet.func = do_test_mode;			_pcd->test_mode_tasklet.data = (unsigned long)_pcd;			_pcd->test_mode = ctrl.wIndex >> 8;			tasklet_schedule(&_pcd->test_mode_tasklet);			break;		case USB_DEVICE_B_HNP_ENABLE:			DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");			/* dev may initiate HNP */			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)			{				_pcd->b_hnp_enable = 1;				dwc_otg_pcd_update_otg( _pcd, 0 );				DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");				/**@todo Is the gotgctl.devhnpen cleared				 * by a USB Reset? */				gotgctl.b.devhnpen = 1;				gotgctl.b.hnpreq = 1;				dwc_write_reg32( &global_regs->gotgctl, gotgctl.d32 );			}			else			{				ep0_do_stall( _pcd, -EOPNOTSUPP);			}			break;		case USB_DEVICE_A_HNP_SUPPORT:			/* RH port supports HNP */			DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)			{				_pcd->a_hnp_support = 1;				dwc_otg_pcd_update_otg( _pcd, 0 );			}			else			{				ep0_do_stall( _pcd, -EOPNOTSUPP);			}			break;		case USB_DEVICE_A_ALT_HNP_SUPPORT:			/* other RH port does */			DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)			{				_pcd->a_alt_hnp_support = 1;				dwc_otg_pcd_update_otg( _pcd, 0 );			}			else			{				ep0_do_stall( _pcd, -EOPNOTSUPP);			}			break;		}		do_setup_in_status_phase( _pcd );		break;	case USB_RECIP_INTERFACE:		do_gadget_setup(_pcd, &ctrl );		break;	case USB_RECIP_ENDPOINT:		if (ctrl.wValue == USB_ENDPOINT_HALT)		{			ep = get_ep_by_addr(_pcd, ctrl.wIndex);			if (ep == 0)			{				ep0_do_stall(_pcd, -EOPNOTSUPP);				return;			}			ep->stopped = 1;			dwc_otg_ep_set_stall( core_if, &ep->dwc_ep );		}		do_setup_in_status_phase( _pcd );		break;	}}/** * This function process the CLEAR_FEATURE Setup Commands. */static inline void do_clear_feature( dwc_otg_pcd_t *_pcd ){	struct usb_ctrlrequest	ctrl = _pcd->setup_pkt->req;	dwc_otg_pcd_ep_t	*ep = 0;	DWC_DEBUGPL(DBG_PCD,				"CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",				ctrl.bRequestType, ctrl.bRequest,				ctrl.wValue, ctrl.wIndex, ctrl.wLength);	switch (ctrl.bRequestType & USB_RECIP_MASK)	{	case USB_RECIP_DEVICE:		switch (ctrl.wValue)		{		case USB_DEVICE_REMOTE_WAKEUP:			_pcd->remote_wakeup_enable = 0;			break;		case USB_DEVICE_TEST_MODE:			/** @todo Add CLEAR_FEATURE for TEST modes. */			break;		}		do_setup_in_status_phase( _pcd );		break;	case USB_RECIP_ENDPOINT:		ep = get_ep_by_addr(_pcd, ctrl.wIndex);		if (ep == 0)		{			ep0_do_stall(_pcd, -EOPNOTSUPP);			return;		}		pcd_clear_halt(_pcd, ep );		break;	}}/** * This function process the SET_ADDRESS Setup Commands. */static inline void do_set_address( dwc_otg_pcd_t *_pcd ){	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(_pcd)->dev_if;	struct usb_ctrlrequest	ctrl = _pcd->setup_pkt->req;	if (ctrl.bRequestType == USB_RECIP_DEVICE)	{		dcfg_data_t dcfg = {.d32=0};#ifdef DEBUG_EP0//			DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);

⌨️ 快捷键说明

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