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

📄 dwc_otg_pcd.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (_req->flags & USB_REQ_ISO_ASAP) {			frmnumber = dsts.b.soffn + 1;			if (dwc_ep->bInterval != 1) {				frmnumber =					frmnumber + (dwc_ep->bInterval - 1 -						     frmnumber % dwc_ep->bInterval);			}		} else {			frmnumber = _req->start_frame;		}		sts.b.framenum = frmnumber;		sts.b.txbytes = dwc_ep->data_per_frame;		sts.b.l = 0;		/** Buffer 0 descriptors setup */		for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {			writel((uint32_t) dma_ad, &dma_desc->buf);			writel(sts.d32, &dma_desc->status);			dma_desc++;			(uint32_t) dma_ad += dwc_ep->data_per_frame;			sts.b.framenum += dwc_ep->bInterval;		}		sts.b.ioc = 1;		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) {			writel((uint32_t) dma_ad, &dma_desc->buf);			writel(sts.d32, &dma_desc->status);			dma_desc++;			(uint32_t) dma_ad += dwc_ep->data_per_frame;			sts.b.framenum += dwc_ep->bInterval;			sts.b.ioc = 0;		}		sts.b.ioc = 1;		sts.b.l = 1;		writel((uint32_t) dma_ad, &dma_desc->buf);		writel(sts.d32, &dma_desc->status);		dwc_ep->next_frame = sts.b.framenum + dwc_ep->bInterval;		/** Write dma_ad into diepdma register */		dwc_write_reg32(&(in_regs->diepdma), (uint32_t) dwc_ep->iso_dma_desc_addr);	}	/** Enable endpoint, clear nak  */	depctl.d32 = 0;	depctl.b.epena = 1;	depctl.b.usbactep = 1;	depctl.b.cnak = 1;	dwc_modify_reg32(addr, depctl.d32, depctl.d32);	depctl.d32 = dwc_read_reg32(addr);	return 0;}/** * This function stops ISO EP Periodic Data Transfer. */static int dwc_otg_pcd_iso_ep_stop(struct usb_ep *_ep, struct usb_iso_request *_iso_req){	dwc_otg_pcd_ep_t *ep;	dwc_otg_pcd_t *pcd;	dwc_ep_t *dwc_ep;	unsigned long flags;	depctl_data_t depctl = {.d32 = 0 };	volatile uint32_t *addr;	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;	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_ep = &ep->dwc_ep;	SPIN_LOCK_IRQSAVE(&pcd->lock, flags);	if (ep->iso_req != _iso_req) {		return -EINVAL;	}	_iso_req->status = -ECONNRESET;	SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);	if (ep->dwc_ep.is_in == 1) {		addr = &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;	} else {		addr = &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->doepctl;	}	depctl.d32 = dwc_read_reg32(addr);	dwc_write_reg32(addr, depctl.d32);	ep_free_iso_desc_chain(ep->dwc_ep.iso_desc_addr, ep->dwc_ep.iso_dma_desc_addr,			       ep->dwc_ep.desc_cnt * 2);	/* reset varibales */	dwc_ep->dma_addr0 = 0;	dwc_ep->dma_addr1 = 0;	dwc_ep->xfer_buff0 = 0;	dwc_ep->xfer_buff1 = 0;	dwc_ep->data_per_frame = 0;	dwc_ep->data_pattern_frame = 0;	dwc_ep->sync_frame = 0;	dwc_ep->buf_proc_intrvl = 0;	dwc_ep->bInterval = 0;	dwc_ep->proc_buf_num = 0;	dwc_ep->pkt_per_frm = 0;	dwc_ep->pkt_per_frm = 0;	dwc_ep->desc_cnt = 0;	dwc_ep->iso_desc_addr = 0;	dwc_ep->iso_dma_desc_addr = 0;	return 0;}static struct usb_iso_request *dwc_otg_pcd_alloc_iso_request(struct usb_ep *_ep, int packets,#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)							     int gfp_flags#else							     gfp_t gfp_flags#endif	){	struct usb_iso_request *pReq = NULL;	uint32_t req_size;	req_size = sizeof(struct usb_iso_request);	req_size += (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));	pReq = kmalloc(req_size, gfp_flags);	pReq->iso_packet_desc0 = (void *) (pReq + 1);	pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;	return pReq;}static void dwc_otg_pcd_free_iso_request(struct usb_ep *_ep, struct usb_iso_request *req){	kfree(req);}static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {	.ep_ops = {		   .enable = dwc_otg_pcd_ep_enable,		   .disable = dwc_otg_pcd_ep_disable,		   .alloc_request = dwc_otg_pcd_alloc_request,		   .free_request = dwc_otg_pcd_free_request,		   .alloc_buffer = dwc_otg_pcd_alloc_buffer,		   .free_buffer = dwc_otg_pcd_free_buffer,		   .queue = dwc_otg_pcd_ep_queue,		   .dequeue = dwc_otg_pcd_ep_dequeue,		   .set_halt = dwc_otg_pcd_ep_set_halt,		   .fifo_status = 0,		   .fifo_flush = 0,		   },	.iso_ep_start = dwc_otg_pcd_iso_ep_start,	.iso_ep_stop = dwc_otg_pcd_iso_ep_stop,	.alloc_iso_request = dwc_otg_pcd_alloc_iso_request,	.free_iso_request = dwc_otg_pcd_free_iso_request,};#elsestatic struct usb_ep_ops dwc_otg_pcd_ep_ops = {	.enable = dwc_otg_pcd_ep_enable,	.disable = dwc_otg_pcd_ep_disable,	.alloc_request = dwc_otg_pcd_alloc_request,	.free_request = dwc_otg_pcd_free_request,	.alloc_buffer = dwc_otg_pcd_alloc_buffer,	.free_buffer = dwc_otg_pcd_free_buffer,	.queue = dwc_otg_pcd_ep_queue,	.dequeue = dwc_otg_pcd_ep_dequeue,	.set_halt = dwc_otg_pcd_ep_set_halt,	.fifo_status = 0,	.fifo_flush = 0,};#endif				/* _EN_ISOC_ *//*	Gadget Operations *//** * The following gadget operations will be implemented in the DWC_otg * PCD. Functions in the API that are not described below are not * implemented. * * The Gadget API provides wrapper functions for each of the function * pointers defined in usb_gadget_ops. The Gadget Driver calls the * wrapper function, which then calls the underlying PCD function. The * following sections are named according to the wrapper functions * (except for ioctl, which doesn't have a wrapper function). Within * each section, the corresponding DWC_otg PCD function name is * specified. * *//** *Gets the USB Frame number of the last SOF. */static int dwc_otg_pcd_get_frame(struct usb_gadget *_gadget){	dwc_otg_pcd_t *pcd;	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _gadget);	if (_gadget == 0) {		return -ENODEV;	} else {		pcd = container_of(_gadget, dwc_otg_pcd_t, gadget);		dwc_otg_get_frame_number(GET_CORE_IF(pcd));	}	return 0;}void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * _pcd){	uint32_t *addr = (uint32_t *) & (GET_CORE_IF(_pcd)->core_global_regs->gotgctl);	gotgctl_data_t mem;	gotgctl_data_t val;	val.d32 = dwc_read_reg32(addr);	if (val.b.sesreq) {		DWC_ERROR("Session Request Already active!\n");		return;	}	DWC_NOTICE("Session Request Initated\n");	mem.d32 = dwc_read_reg32(addr);	mem.b.sesreq = 1;	dwc_write_reg32(addr, mem.d32);	/* Start the SRP timer */	dwc_otg_pcd_start_srp_timer(_pcd);	return;}void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * _pcd, int set){	dctl_data_t dctl = {.d32 = 0 };	volatile uint32_t *addr = &(GET_CORE_IF(_pcd)->dev_if->dev_global_regs->dctl);	if (dwc_otg_is_device_mode(GET_CORE_IF(_pcd))) {		if (_pcd->remote_wakeup_enable) {			if (set) {				dctl.b.rmtwkupsig = 1;				dwc_modify_reg32(addr, 0, dctl.d32);				DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");				mdelay(1);				dwc_modify_reg32(addr, dctl.d32, 0);				DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");			} else {			}		} else {			DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");		}	}	return;}/** * Initiates Session Request Protocol (SRP) to wakeup the host if no * session is in progress. If a session is already in progress, but * the device is suspended, remote wakeup signaling is started. * */static int dwc_otg_pcd_wakeup(struct usb_gadget *_gadget){	unsigned long flags;	dwc_otg_pcd_t *pcd;	dsts_data_t dsts;	gotgctl_data_t gotgctl;	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _gadget);	if (_gadget == 0) {		return -ENODEV;	} else {		pcd = container_of(_gadget, dwc_otg_pcd_t, gadget);	}	SPIN_LOCK_IRQSAVE(&pcd->lock, flags);	/*	 * This function starts the Protocol if no session is in progress. If	 * a session is already in progress, but the device is suspended,	 * remote wakeup signaling is started.	 */	/* Check if valid session */	gotgctl.d32 = dwc_read_reg32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));	if (gotgctl.b.bsesvld) {		/* Check if suspend state */		dsts.d32 = dwc_read_reg32(&(GET_CORE_IF(pcd)->dev_if->dev_global_regs->dsts));		if (dsts.b.suspsts) {			dwc_otg_pcd_remote_wakeup(pcd, 1);		}	} else {		dwc_otg_pcd_initiate_srp(pcd);	}	SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);	return 0;}static const struct usb_gadget_ops dwc_otg_pcd_ops = {	.get_frame = dwc_otg_pcd_get_frame,	.wakeup = dwc_otg_pcd_wakeup,	// current versions must always be self-powered};/** * This function updates the otg values in the gadget structure. */void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * _pcd, const unsigned _reset){	if (!_pcd->gadget.is_otg)		return;	if (_reset) {		_pcd->b_hnp_enable = 0;		_pcd->a_hnp_support = 0;		_pcd->a_alt_hnp_support = 0;	}	_pcd->gadget.b_hnp_enable = _pcd->b_hnp_enable;	_pcd->gadget.a_hnp_support = _pcd->a_hnp_support;	_pcd->gadget.a_alt_hnp_support = _pcd->a_alt_hnp_support;}/** * This function is the top level PCD interrupt handler. */static irqreturn_t dwc_otg_pcd_irq(int _irq, void *_dev#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)				   , struct pt_regs *_r#endif	){	dwc_otg_pcd_t *pcd = _dev;	int32_t retval = IRQ_NONE;	retval = dwc_otg_pcd_handle_intr(pcd);	return IRQ_RETVAL(retval);}/** * PCD Callback function for initializing the PCD when switching to * device mode. * * @param _p void pointer to the <code>dwc_otg_pcd_t</code> */static int32_t dwc_otg_pcd_start_cb(void *_p){	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) _p;	/*	 * Initialized the Core for Device mode.	 */	if (dwc_otg_is_device_mode(GET_CORE_IF(pcd))) {		dwc_otg_core_dev_init(GET_CORE_IF(pcd));	}	return 1;}/** * PCD Callback function for stopping the PCD when switching to Host * mode. * * @param _p void pointer to the <code>dwc_otg_pcd_t</code> */static int32_t dwc_otg_pcd_stop_cb(void *_p){	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) _p;	extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);	dwc_otg_pcd_stop(pcd);	return 1;}/** * PCD Callback function for notifying the PCD when resuming from * suspend. * * @param _p void pointer to the <code>dwc_otg_pcd_t</code> */static int32_t dwc_otg_pcd_suspend_cb(void *_p){	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) _p;	if (pcd->driver && pcd->driver->resume) {		SPIN_UNLOCK(&pcd->lock);		pcd->driver->suspend(&pcd->gadget);		SPIN_LOCK(&pcd->lock);	}	return 1;}/** * PCD Callback function for notifying the PCD when resuming from * suspend. * * @param _p void pointer to the <code>dwc_otg_pcd_t</code> */static int32_t dwc_otg_pcd_resume_cb(void *_p){	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) _p;	if (pcd->driver && pcd->driver->resume) {		SPIN_UNLOCK(&pcd->lock);		pcd->driver->resume(&pcd->gadget);		SPIN_LOCK(&pcd->lock);	}	/* Stop the SRP timeout timer. */	if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS) ||	    (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {		if (GET_CORE_IF(pcd)->srp_timer_started) {			GET_CORE_IF(pcd)->srp_timer_started = 0;			del_timer(&pcd->srp_timer);		}	}	return 1;}/** * PCD Callback structure for handling mode switching. */static dwc_otg_cil_callbacks_t pcd_callbacks = {	.start = dwc_otg_pcd_start_cb,	.stop = dwc_otg_pcd_stop_cb,	.suspend = dwc_otg_pcd_suspend_cb,	.resume_wakeup = dwc_otg_pcd_resume_cb,	.p = 0,			/* Set at registration */};/** * This function is called when the SRP timer expires.	The SRP should * complete within 6 seconds. */static void srp_timeout(unsigned long _ptr){	gotgctl_data_t gotgctl;	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) _ptr;	volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;	gotgctl.d32 = dwc_read_reg32(addr);	core_if->srp_timer_started = 0;	if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&	    (core_if->core_params->i2c_enable)) {		DWC_PRINT("SRP Timeout\n");		if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);			}			/* Clear Session Request */			gotgctl.d32 = 0;			gotgctl.b.sesreq = 1;			dwc_modify_reg32(&core_if->core_global_regs->gotgctl, gotgctl.d32, 0);			core_if->srp_success = 0;		} else {			DWC_ERROR("Device not connected/responding\n");			gotgctl.b.sesreq = 0;			dwc_write_reg32(addr, gotgctl.d32);		}	} else if (gotgctl.b.sesreq) {		DWC_PRINT("SRP Timeout\n");		DWC_ERROR("Device not connected/responding\n");		gotgctl.b.sesreq = 0;		dwc_write_reg32(addr, gotgctl.d32);	} else {		DWC_PRINT(" SRP GOTGCTL=%0x\n", gotgctl.d32);	}}/** * Start the SRP timer to detect when the SRP does not complete within * 6 seconds. * * @param _pcd the pcd structure. */void dwc_otg_pcd_start_srp_timer(dwc_otg_pcd_t * _pcd){	struct timer_list *srp_timer = &_pcd->srp_timer;	GET_CORE_IF(_pcd)->srp_timer_started = 1;	init_timer(srp_timer);	srp_timer->function = srp_timeout;	srp_timer->data = (unsigned long) GET_CORE_IF(_pcd);

⌨️ 快捷键说明

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