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

📄 dwc_otg_pcd.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 4 页
字号:
	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);	pcd = ep->pcd;	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%0x,%d)\n", __func__, _ep, _buf, _dma, _bytes);	if (GET_CORE_IF(pcd)->dma_enable) {		dma_free_coherent(NULL, _bytes, _buf, _dma);	} else {		kfree(_buf);	}}/** * This function is used to submit an I/O Request to an EP. * *	- When the request completes the request's completion callback *	  is called to return the request to the driver. *	- An EP, except control EPs, may have multiple requests *	  pending. *	- Once submitted the request cannot be examined or modified. *	- Each request is turned into one or more packets. *	- A BULK EP can queue any amount of data; the transfer is *	  packetized. *	- Zero length Packets are specified with the request 'zero' *	  flag. */static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep, struct usb_request *_req,#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)				int _gfp_flags#else				gfp_t _gfp_flags#endif	){	int prevented = 0;	dwc_otg_pcd_request_t *req;	dwc_otg_pcd_ep_t *ep;	dwc_otg_pcd_t *pcd;	unsigned long flags = 0;	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n", __func__, _ep, _req, _gfp_flags);	req = container_of(_req, dwc_otg_pcd_request_t, req);	if (!_req || !_req->complete || !_req->buf || !list_empty(&req->queue)) {		DWC_WARN("%s, bad params\n", __func__);		return -EINVAL;	}	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);	if (!_ep || (!ep->desc && ep->dwc_ep.num != 0) /* || ep->stopped != 0 */ ) {		DWC_WARN("%s, bad ep\n", __func__);		return -EINVAL;	}	pcd = ep->pcd;	if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN) {		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", pcd->gadget.speed);		DWC_WARN("%s, bogus device state\n", __func__);		return -ESHUTDOWN;	}	DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",		    _ep->name, _req, _req->length, _req->buf);	if (!GET_CORE_IF(pcd)->core_params->opt) {		if (ep->dwc_ep.num != 0) {			DWC_ERROR("%s queue req %p, len %d buf %p\n",				  _ep->name, _req, _req->length, _req->buf);		}	}	SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);#if defined(DEBUG) & defined(VERBOSE)	dump_msg(_req->buf, _req->length);#endif	_req->status = -EINPROGRESS;	_req->actual = 0;	/*	 * For EP0 IN without premature status, zlp is required?	 */	if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {		DWC_DEBUGPL(DBG_PCDV, "%s-OUT ZLP\n", _ep->name);		//_req->zero = 1;	}	/* Start the transfer */	if (list_empty(&ep->queue) && !ep->stopped) {		/* EP0 Transfer? */		if (ep->dwc_ep.num == 0) {			switch (pcd->ep0state) {			case EP0_IN_DATA_PHASE:				DWC_DEBUGPL(DBG_PCD, "%s ep0: EP0_IN_DATA_PHASE\n", __func__);				break;			case EP0_OUT_DATA_PHASE:				DWC_DEBUGPL(DBG_PCD, "%s ep0: EP0_OUT_DATA_PHASE\n", __func__);				if (pcd->request_config) {					/* Complete STATUS PHASE */					ep->dwc_ep.is_in = 1;					pcd->ep0state = EP0_IN_STATUS_PHASE;				}				break;			case EP0_IN_STATUS_PHASE:				DWC_DEBUGPL(DBG_PCD, "%s ep0: EP0_IN_STATUS_PHASE\n", __func__);				break;			default:				DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n", pcd->ep0state);				SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);				return -EL2HLT;			}			ep->dwc_ep.dma_addr = _req->dma;			ep->dwc_ep.start_xfer_buff = _req->buf;			ep->dwc_ep.xfer_buff = _req->buf;			ep->dwc_ep.xfer_len = _req->length;			ep->dwc_ep.xfer_count = 0;			ep->dwc_ep.sent_zlp = 0;			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;			if (_req->zero) {				if ((ep->dwc_ep.xfer_len % ep->dwc_ep.maxpacket == 0)				    && (ep->dwc_ep.xfer_len != 0)) {					ep->dwc_ep.sent_zlp = 1;				}			}			dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep->dwc_ep);		} else {			/* Setup and start the Transfer */			ep->dwc_ep.dma_addr = _req->dma;			ep->dwc_ep.start_xfer_buff = _req->buf;			ep->dwc_ep.xfer_buff = _req->buf;			ep->dwc_ep.xfer_len = _req->length;			ep->dwc_ep.xfer_count = 0;			ep->dwc_ep.sent_zlp = 0;			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;			if (_req->zero) {				if ((ep->dwc_ep.xfer_len % ep->dwc_ep.maxpacket == 0)				    && (ep->dwc_ep.xfer_len != 0)) {					ep->dwc_ep.sent_zlp = 1;				}			}			dwc_otg_ep_start_transfer(GET_CORE_IF(pcd), &ep->dwc_ep);		}	}	if ((req != 0) || prevented) {		++pcd->request_pending;		list_add_tail(&req->queue, &ep->queue);		if (ep->dwc_ep.is_in && ep->stopped && !(GET_CORE_IF(pcd)->dma_enable)) {			/** @todo NGS Create a function for this. */			diepmsk_data_t diepmsk = {.d32 = 0 };			diepmsk.b.intktxfemp = 1;			dwc_modify_reg32(&GET_CORE_IF(pcd)->dev_if->dev_global_regs->diepmsk, 0,					 diepmsk.d32);		}	}	SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);	return 0;}/** * This function cancels an I/O request from an EP. */static int dwc_otg_pcd_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req){	dwc_otg_pcd_request_t *req;	dwc_otg_pcd_ep_t *ep;	dwc_otg_pcd_t *pcd;	unsigned long flags;	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, _ep, _req);	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);	if (!_ep || !_req || (!ep->desc && ep->dwc_ep.num != 0)) {		DWC_WARN("%s, bad argument\n", __func__);		return -EINVAL;	}	pcd = ep->pcd;	if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN) {		DWC_WARN("%s, bogus device state\n", __func__);		return -ESHUTDOWN;	}	SPIN_LOCK_IRQSAVE(&pcd->lock, flags);	DWC_DEBUGPL(DBG_PCDV, "%s %s %s %p\n", __func__, _ep->name,		    ep->dwc_ep.is_in ? "IN" : "OUT", _req);	/* make sure it's actually queued on this endpoint */	list_for_each_entry(req, &ep->queue, queue) {		if (&req->req == _req) {			break;		}	}	if (&req->req != _req) {		SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);		return -EINVAL;	}	if (!list_empty(&req->queue)) {		request_done(ep, req, -ECONNRESET);	} else {		req = 0;	}	SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);	return req ? 0 : -EOPNOTSUPP;}/** * usb_ep_set_halt stalls an endpoint. * * usb_ep_clear_halt clears an endpoint halt and resets its data * toggle. * * Both of these functions are implemented with the same underlying * function. The behavior depends on the value argument. * * @param[in] _ep the Endpoint to halt or clear halt. * @param[in] _value *	- 0 means clear_halt. *	- 1 means set_halt, *	- 2 means clear stall lock flag. *	- 3 means set  stall lock flag. */static int dwc_otg_pcd_ep_set_halt(struct usb_ep *_ep, int _value){	int retval = 0;	unsigned long flags;	dwc_otg_pcd_ep_t *ep = 0;	DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", _ep->name, _value);	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);	if (!_ep || (!ep->desc && ep != &ep->pcd->ep0) ||	    ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {		DWC_WARN("%s, bad ep\n", __func__);		return -EINVAL;	}	SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);	if (!list_empty(&ep->queue)) {		DWC_WARN("%s() %s XFer In process\n", __func__, _ep->name);		retval = -EAGAIN;	} else if (_value == 0) {		dwc_otg_ep_clear_stall(ep->pcd->otg_dev->core_if, &ep->dwc_ep);	} else if (_value == 1) {		if (ep->dwc_ep.is_in == 1 && ep->pcd->otg_dev->core_if->dma_desc_enable) {			dtxfsts_data_t txstatus;			fifosize_data_t txfifosize;			txfifosize.d32 =				dwc_read_reg32(&ep->pcd->otg_dev->core_if->core_global_regs->					       dptxfsiz_dieptxf[ep->dwc_ep.tx_fifo_num]);			txstatus.d32 =				dwc_read_reg32(&ep->pcd->otg_dev->core_if->dev_if->					       in_ep_regs[ep->dwc_ep.num]->dtxfsts);			if (txstatus.b.txfspcavail < txfifosize.b.depth) {				DWC_WARN("%s() %s Data In Tx Fifo\n", __func__, _ep->name);				retval = -EAGAIN;			} else {				if (ep->dwc_ep.num == 0) {					ep->pcd->ep0state = EP0_STALL;				}				ep->stopped = 1;				dwc_otg_ep_set_stall(ep->pcd->otg_dev->core_if, &ep->dwc_ep);			}		} else {			if (ep->dwc_ep.num == 0) {				ep->pcd->ep0state = EP0_STALL;			}			ep->stopped = 1;			dwc_otg_ep_set_stall(ep->pcd->otg_dev->core_if, &ep->dwc_ep);		}	} else if (_value == 2) {		ep->dwc_ep.stall_clear_flag = 0;	} else if (_value == 3) {		ep->dwc_ep.stall_clear_flag = 1;	}	SPIN_UNLOCK_IRQRESTORE(&ep->pcd->lock, flags);	return retval;}#ifdef _EN_ISOC_/** * This function is used to submit an ISOC Transfer Request to an EP. * *	- Every time a sync period completes the request's completion callback *	  is called to provide data to the gadget driver. *	- Once submitted the request cannot be modified. *	- Each request is turned into periodic data packets untill ISO *	  Transfer is stopped.. */static int dwc_otg_pcd_iso_ep_start(struct usb_ep *_ep, struct usb_iso_request *_req,#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)				    int _gfp_flags#else				    gfp_t _gfp_flags#endif	){	dwc_otg_pcd_ep_t *ep;	dwc_otg_pcd_t *pcd;	dwc_ep_t *dwc_ep;	dsts_data_t dsts = {.d32 = 0 };	depctl_data_t depctl = {.d32 = 0 };	volatile uint32_t *addr;	unsigned long flags = 0;	int32_t frm_data;	int i, j;	dwc_otg_core_if_t *core_if;	dctl_data_t dctl;	dcfg_data_t dcfg;	if (!_req || !_req->process_buffer || !_req->buf0 || !_req->buf1) {		DWC_WARN("%s, bad params\n", __func__);		return -EINVAL;	}	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);	if (!_ep || !ep->desc || ep->dwc_ep.num == 0) {		DWC_WARN("%s, bad ep\n", __func__);		return -EINVAL;	}	pcd = ep->pcd;	core_if = GET_CORE_IF(pcd);	dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);	dctl.b.ifrmnum = 1;	//dwc_write_reg32(&core_if->dev_if->dev_global_regs->dctl,dctl.d32);	dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);	if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN) {		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", pcd->gadget.speed);		DWC_WARN("%s, bogus device state\n", __func__);		return -ESHUTDOWN;	}	SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);	dwc_ep = &ep->dwc_ep;	_req->status = -EINPROGRESS;	dwc_ep->dma_addr0 = _req->dma0;	dwc_ep->dma_addr1 = _req->dma1;	dwc_ep->xfer_buff0 = _req->buf0;	dwc_ep->xfer_buff1 = _req->buf1;	ep->iso_req = _req;	dwc_ep->data_per_frame = _req->data_per_frame;	/* todo - pattern data support is to be implemented in the future */	dwc_ep->data_pattern_frame = _req->data_pattern_frame;	dwc_ep->sync_frame = _req->sync_frame;	dwc_ep->buf_proc_intrvl = _req->buf_proc_intrvl;	SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);	dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);	dwc_ep->proc_buf_num = 0;	dwc_ep->pkt_per_frm = 0;	frm_data = ep->dwc_ep.data_per_frame;	while (frm_data > 0) {		dwc_ep->pkt_per_frm++;		frm_data -= ep->dwc_ep.maxpacket;	}	if (dwc_ep->is_in)		dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;	else		dwc_ep->desc_cnt =			dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm / dwc_ep->bInterval;	/** Allocate descriptors for double buffering */	dwc_ep->iso_desc_addr =		ep_alloc_iso_desc_chain(&dwc_ep->iso_dma_desc_addr, dwc_ep->desc_cnt * 2);	dsts.d32 = dwc_read_reg32(&(GET_CORE_IF(pcd)->dev_if->dev_global_regs->dsts));	if (dwc_ep->is_in == 0) {/** ISO OUT EP */		iso_out_sts_data_t sts = {.d32 = 0 };		dwc_otg_iso_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;		dma_addr_t dma_ad;		uint32_t data_per_desc;		dwc_otg_dev_out_ep_regs_t *out_regs = core_if->dev_if->out_ep_regs[dwc_ep->num];		addr = &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->doepctl;		dma_ad = (dma_addr_t) dwc_read_reg32(&(out_regs->doepdma));		/** Buffer 0 descriptors setup */		dma_ad = dwc_ep->dma_addr0;		sts.b.bs = BS_HOST_READY;	//0		sts.b.rxsts = 0;		sts.b.l = 0;		sts.b.sp = 0;		sts.b.ioc = 0;		sts.b.pid = 0;		sts.b.framenum = 0;		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; i += dwc_ep->pkt_per_frm) {			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {				data_per_desc =					((j + 1) * dwc_ep->maxpacket >					 dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -					j * dwc_ep->maxpacket : dwc_ep->maxpacket;				sts.b.rxbytes = data_per_desc;				writel((uint32_t) dma_ad, &dma_desc->buf);				writel(sts.d32, &dma_desc->status);				dma_desc++;				(uint32_t) dma_ad += data_per_desc;			}		}		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {			data_per_desc = ((j + 1) * dwc_ep->maxpacket > dwc_ep->data_per_frame) ?				dwc_ep->data_per_frame - j * dwc_ep->maxpacket : dwc_ep->maxpacket;			sts.b.rxbytes = data_per_desc;			writel((uint32_t) dma_ad, &dma_desc->buf);			writel(sts.d32, &dma_desc->status);			dma_desc++;			(uint32_t) dma_ad += data_per_desc;		}		sts.b.ioc = 1;		data_per_desc = ((j + 1) * dwc_ep->maxpacket > dwc_ep->data_per_frame) ?			dwc_ep->data_per_frame - j * dwc_ep->maxpacket : dwc_ep->maxpacket;		sts.b.rxbytes = data_per_desc;		writel((uint32_t) dma_ad, &dma_desc->buf);		writel(sts.d32, &dma_desc->status);		dma_desc++;		/** Buffer 1 descriptors setup */		sts.b.ioc = 0;		dma_ad = dwc_ep->dma_addr1;		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; i += dwc_ep->pkt_per_frm) {			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {				data_per_desc =					((j + 1) * dwc_ep->maxpacket >					 dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -					j * dwc_ep->maxpacket : dwc_ep->maxpacket;				sts.b.rxbytes = data_per_desc;				writel((uint32_t) dma_ad, &dma_desc->buf);				writel(sts.d32, &dma_desc->status);				dma_desc++;				(uint32_t) dma_ad += data_per_desc;			}		}		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {			data_per_desc = ((j + 1) * dwc_ep->maxpacket > dwc_ep->data_per_frame) ?				dwc_ep->data_per_frame - j * dwc_ep->maxpacket : dwc_ep->maxpacket;			sts.b.rxbytes = data_per_desc;			writel((uint32_t) dma_ad, &dma_desc->buf);			writel(sts.d32, &dma_desc->status);			dma_desc++;			(uint32_t) dma_ad += data_per_desc;		}		sts.b.ioc = 1;		sts.b.l = 1;		data_per_desc = ((j + 1) * dwc_ep->maxpacket > dwc_ep->data_per_frame) ?			dwc_ep->data_per_frame - j * dwc_ep->maxpacket : dwc_ep->maxpacket;		sts.b.rxbytes = data_per_desc;		writel((uint32_t) dma_ad, &dma_desc->buf);		writel(sts.d32, &dma_desc->status);		dwc_ep->next_frame = 0;		/** Write dma_ad into DOEPDMA register */		dwc_write_reg32(&(out_regs->doepdma), (uint32_t) dwc_ep->iso_dma_desc_addr);	} else {/** ISO IN EP */		iso_in_sts_data_t sts = {.d32 = 0 };		dwc_otg_iso_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;		dma_addr_t dma_ad;		dwc_otg_dev_in_ep_regs_t *in_regs = core_if->dev_if->in_ep_regs[dwc_ep->num];		unsigned int frmnumber;		fifosize_data_t txfifosize, rxfifosize;		txfifosize.d32 = dwc_read_reg32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->dtxfsts);		rxfifosize.d32 = dwc_read_reg32(&core_if->core_global_regs->grxfsiz);		addr = &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;		dma_ad = dwc_ep->dma_addr0;		dsts.d32 = dwc_read_reg32(&(GET_CORE_IF(pcd)->dev_if->dev_global_regs->dsts));		sts.b.bs = BS_HOST_READY;		sts.b.txsts = 0;		sts.b.sp = (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;		sts.b.ioc = 0;		sts.b.pid = dwc_ep->pkt_per_frm;

⌨️ 快捷键说明

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