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

📄 dwc_otg_hcd.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (hprt0.b.prtovrcurract)			port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);		if (hprt0.b.prtrst)			port_status |= (1 << USB_PORT_FEAT_RESET);		if (hprt0.b.prtpwr)			port_status |= (1 << USB_PORT_FEAT_POWER);		if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)			port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);		else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)			port_status |= (1 << USB_PORT_FEAT_LOWSPEED);		if (hprt0.b.prttstctl)			port_status |= (1 << USB_PORT_FEAT_TEST);		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */		*((__le32 *) _buf) = cpu_to_le32(port_status);		break;	case SetHubFeature:		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " "SetHubFeature\n");		/* No HUB features supported */		break;	case SetPortFeature:		if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1))			goto error;		if (!dwc_otg_hcd->flags.b.port_connect_status) {			/*			 * The port is disconnected, which means the core is			 * either in device mode or it soon will be. Just			 * return without doing anything since the port			 * register can't be written if the core is in device			 * mode.			 */			break;		}		switch (_wValue) {		case USB_PORT_FEAT_SUSPEND:			printk("DWC OTG HCD HUB CONTROL - "				    "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");			if (_hcd->self.otg_port == _wIndex && _hcd->self.b_hnp_enable) {				gotgctl_data_t gotgctl = {.d32 = 0 };				gotgctl.b.hstsethnpen = 1;				dwc_modify_reg32(&core_if->core_global_regs->gotgctl,						 0, gotgctl.d32);				core_if->op_state = A_SUSPEND;			}			hprt0.d32 = dwc_otg_read_hprt0(core_if);			hprt0.b.prtsusp = 1;			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);			//DWC_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32);			/* Suspend the Phy Clock */			{				pcgcctl_data_t pcgcctl = {.d32 = 0 };				pcgcctl.b.stoppclk = 1;				dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);			}			/* For HNP the bus must be suspended for at least 200ms. */			if (_hcd->self.b_hnp_enable) {				mdelay(200);				//DWC_PRINT( "SUSPEND: wait complete! (%d)\n", _hcd->state);			}			break;		case USB_PORT_FEAT_POWER:			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "				    "SetPortFeature - USB_PORT_FEAT_POWER\n");			hprt0.d32 = dwc_otg_read_hprt0(core_if);			hprt0.b.prtpwr = 1;			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);			break;		case USB_PORT_FEAT_RESET:			printk("DWC OTG HCD HUB CONTROL - "				    "SetPortFeature - USB_PORT_FEAT_RESET\n");			hprt0.d32 = dwc_otg_read_hprt0(core_if);			/* When B-Host the Port reset bit is set in			 * the Start HCD Callback function, so that			 * the reset is started within 1ms of the HNP			 * success interrupt. */			if (!_hcd->self.is_b_host) {				hprt0.b.prtrst = 1;				dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);			}			/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */			mdelay(60);			hprt0.b.prtrst = 0;			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);			break;#ifdef DWC_HS_ELECT_TST		case USB_PORT_FEAT_TEST:			{				uint32_t t;				gintmsk_data_t gintmsk;				t = (_wIndex >> 8);	/* MSB wIndex USB */				DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "					    "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t);				warn("USB_PORT_FEAT_TEST %d\n", t);				if (t < 6) {					hprt0.d32 = dwc_otg_read_hprt0(core_if);					hprt0.b.prttstctl = t;					dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);				} else {					/* Setup global vars with reg addresses (quick and					 * dirty hack, should be cleaned up)					 */					global_regs = core_if->core_global_regs;					hc_global_regs = core_if->host_if->host_global_regs;					hc_regs =						(dwc_otg_hc_regs_t *) ((char *) global_regs +								       0x500);					data_fifo = (uint32_t *) ((char *) global_regs + 0x1000);					if (t == 6) {	/* HS_HOST_PORT_SUSPEND_RESUME */						/* Save current interrupt mask */						gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk);						/* Disable all interrupts while we muck with						 * the hardware directly						 */						dwc_write_reg32(&global_regs->gintmsk, 0);						/* 15 second delay per the test spec */						mdelay(15000);						/* Drive suspend on the root port */						hprt0.d32 = dwc_otg_read_hprt0(core_if);						hprt0.b.prtsusp = 1;						hprt0.b.prtres = 0;						dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);						/* 15 second delay per the test spec */						mdelay(15000);						/* Drive resume on the root port */						hprt0.d32 = dwc_otg_read_hprt0(core_if);						hprt0.b.prtsusp = 0;						hprt0.b.prtres = 1;						dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);						mdelay(100);						/* Clear the resume bit */						hprt0.b.prtres = 0;						dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);						/* Restore interrupts */						dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32);					} else if (t == 7) {	/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */						/* Save current interrupt mask */						gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk);						/* Disable all interrupts while we muck with						 * the hardware directly						 */						dwc_write_reg32(&global_regs->gintmsk, 0);						/* 15 second delay per the test spec */						mdelay(15000);						/* Send the Setup packet */						do_setup();						/* 15 second delay so nothing else happens for awhile */						mdelay(15000);						/* Restore interrupts */						dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32);					} else if (t == 8) {	/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */						/* Save current interrupt mask */						gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk);						/* Disable all interrupts while we muck with						 * the hardware directly						 */						dwc_write_reg32(&global_regs->gintmsk, 0);						/* Send the Setup packet */						do_setup();						/* 15 second delay so nothing else happens for awhile */						mdelay(15000);						/* Send the In and Ack packets */						do_in_ack();						/* 15 second delay so nothing else happens for awhile */						mdelay(15000);						/* Restore interrupts */						dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32);					}				}				break;			}#endif				/* DWC_HS_ELECT_TST */		case USB_PORT_FEAT_INDICATOR:			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "				    "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");			/* Not supported */			break;		default:			retval = -EINVAL;			DWC_ERROR("DWC OTG HCD - "				  "SetPortFeature request %xh "				  "unknown or unsupported\n", _wValue);			break;		}		break;	default:	      error:		retval = -EINVAL;		DWC_WARN("DWC OTG HCD - "			 "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",			 _typeReq, _wIndex, _wValue);		break;	}	return retval;}/** * Assigns transactions from a QTD to a free host channel and initializes the * host channel to perform the transactions. The host channel is removed from * the free list. * * @param _hcd The HCD state structure. * @param _qh Transactions from the first QTD for this QH are selected and * assigned to a free host channel. */static void assign_and_init_hc(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh){	dwc_hc_t *hc;	dwc_otg_qtd_t *qtd;	struct urb *urb;	dbg_otg("%s(%p,%p)\n", __FUNCTION__, _hcd, _qh);	hc = list_entry(_hcd->free_hc_list.next, dwc_hc_t, hc_list_entry);	/* Remove the host channel from the free list. */	list_del_init(&hc->hc_list_entry);	qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry);	urb = qtd->urb;	_qh->channel = hc;	_qh->qtd_in_process = qtd;	/*	 * Use usb_pipedevice to determine device address. This address is	 * 0 before the SET_ADDRESS command and the correct address afterward.	 */	hc->dev_addr = usb_pipedevice(urb->pipe);	hc->ep_num = usb_pipeendpoint(urb->pipe);	if (urb->dev->speed == USB_SPEED_LOW) {		hc->speed = DWC_OTG_EP_SPEED_LOW;	} else if (urb->dev->speed == USB_SPEED_FULL) {		hc->speed = DWC_OTG_EP_SPEED_FULL;	} else {		hc->speed = DWC_OTG_EP_SPEED_HIGH;	}	hc->max_packet = dwc_max_packet(_qh->maxp);	hc->xfer_started = 0;	hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;	hc->error_state = (qtd->error_count > 0);	hc->halt_on_queue = 0;	hc->halt_pending = 0;	hc->requests = 0;	/*	 * The following values may be modified in the transfer type section	 * below. The xfer_len value may be reduced when the transfer is	 * started to accommodate the max widths of the XferSize and PktCnt	 * fields in the HCTSIZn register.	 */	hc->do_ping = _qh->ping_state;	hc->ep_is_in = (usb_pipein(urb->pipe) != 0);	hc->data_pid_start = _qh->data_toggle;	hc->multi_count = 1;	if (_hcd->core_if->dma_enable) {		hc->xfer_buff = (uint8_t *) urb->transfer_dma + urb->actual_length;	} else {		hc->xfer_buff = (uint8_t *) urb->transfer_buffer + urb->actual_length;	}	hc->xfer_len = urb->transfer_buffer_length - urb->actual_length;	hc->xfer_count = 0;	/*	 * Set the split attributes	 */	hc->do_split = 0;	if (_qh->do_split) {		hc->do_split = 1;		hc->xact_pos = qtd->isoc_split_pos;		hc->complete_split = qtd->complete_split;		hc->hub_addr = urb->dev->tt->hub->devnum;		hc->port_addr = urb->dev->ttport;	}	switch (usb_pipetype(urb->pipe)) {	case PIPE_CONTROL:		hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;		switch (qtd->control_phase) {		case DWC_OTG_CONTROL_SETUP:			DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction\n");			hc->do_ping = 0;			hc->ep_is_in = 0;			hc->data_pid_start = DWC_OTG_HC_PID_SETUP;			if (_hcd->core_if->dma_enable) {				hc->xfer_buff = (uint8_t *) urb->setup_dma;			} else {				hc->xfer_buff = (uint8_t *) urb->setup_packet;			}			hc->xfer_len = 8;			break;		case DWC_OTG_CONTROL_DATA:			DWC_DEBUGPL(DBG_HCDV, "  Control data transaction\n");			hc->data_pid_start = qtd->data_toggle;			break;		case DWC_OTG_CONTROL_STATUS:			/*			 * Direction is opposite of data direction or IN if no			 * data.			 */			DWC_DEBUGPL(DBG_HCDV, "  Control status transaction\n");			if (urb->transfer_buffer_length == 0) {				hc->ep_is_in = 1;			} else {				hc->ep_is_in = (usb_pipein(urb->pipe) != USB_DIR_IN);			}			if (hc->ep_is_in) {				hc->do_ping = 0;			}			hc->data_pid_start = DWC_OTG_HC_PID_DATA1;			hc->xfer_len = 0;			if (_hcd->core_if->dma_enable) {				hc->xfer_buff = (uint8_t *) _hcd->status_buf_dma;			} else {				hc->xfer_buff = (uint8_t *) _hcd->status_buf;			}			break;		}		break;	case PIPE_BULK:		hc->ep_type = DWC_OTG_EP_TYPE_BULK;		break;	case PIPE_INTERRUPT:		hc->ep_type = DWC_OTG_EP_TYPE_INTR;		break;	case PIPE_ISOCHRONOUS:		{			struct usb_iso_packet_descriptor *frame_desc;			frame_desc = &urb->iso_frame_desc[qtd->isoc_frame_index];			hc->ep_type = DWC_OTG_EP_TYPE_ISOC;			if (_hcd->core_if->dma_enable) {				hc->xfer_buff = (uint8_t *) urb->transfer_dma;			} else {				hc->xfer_buff = (uint8_t *) urb->transfer_buffer;			}			hc->xfer_buff += frame_desc->offset + qtd->isoc_split_offset;			hc->xfer_len = frame_desc->length - qtd->isoc_split_offset;			if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {				if (hc->xfer_len <= 188) {					hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;				} else {					hc->xact_pos = DWC_HCSPLIT_XACTPOS_BEGIN;				}			}		}		break;	}	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {		/*		 * This value may be modified when the transfer is started to		 * reflect the actual transfer length.		 */		hc->multi_count = dwc_hb_mult(_qh->maxp);	}	dwc_otg_hc_init(_hcd->core_if, hc);	hc->qh = _qh;}/** * This function selects transactions from the HCD transfer schedule and * assigns them to available host channels. It is called from HCD interrupt * handler functions. * * @param _hcd The HCD state structure. * * @return The types of new transactions that were assigned to host channels. */dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * _hcd){	struct list_head *qh_ptr;	dwc_otg_qh_t *qh;	int num_channels;	dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;#ifdef DEBUG_SOF	DWC_DEBUGPL(DBG_HCD, "  Select Transactions\n");#endif	/* Process entries in the periodic ready list. */	qh_ptr = _hcd->periodic_sched_ready.next;	while (qh_ptr != &_hcd->periodic_sched_ready && !list_empty(&_hcd->free_hc_list)) {		qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);		assign_and_init_hc(_hcd, qh);		/*		 * Move the QH from the periodic ready schedule to the		 * periodic assigned schedule.		 */		qh_ptr = qh_ptr->next;		list_move(&qh->qh_list_entry, &_hcd->periodic_sched_assigned);		ret_val = DWC_OTG_TRANSACTION_PERIODIC;	}	/*	 * Process entries in the inactive portion of the non-periodic	 * schedule. Some free host channels may not be used if they are	 * reserved for periodic transfers.	 */	qh_ptr = _hcd->non_periodic_sched_inactive.next;	num_channels = _hcd->core_if->core_params->host_channels;	while (qh_ptr != &_hcd->non_periodic_sched_inactive &&	       (_hcd->non_periodic_channels <		num_channels - _hcd->periodic_channels

⌨️ 快捷键说明

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