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

📄 dwc_otg_hcd_queue.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 2 页
字号:
	status = periodic_channel_available(_hcd);	if (status) {		DWC_NOTICE("%s: No host channel available for periodic " "transfer.\n", __func__);		return status;	}	status = check_periodic_bandwidth(_hcd, _qh);	if (status) {		DWC_NOTICE("%s: Insufficient periodic bandwidth for "			   "periodic transfer.\n", __func__);		return status;	}	status = check_max_xfer_size(_hcd, _qh);	if (status) {		DWC_NOTICE("%s: Channel max transfer size too small "			   "for periodic transfer.\n", __func__);		return status;	}	/* Always start in the inactive schedule. */	list_add_tail(&_qh->qh_list_entry, &_hcd->periodic_sched_inactive);	/* Reserve the periodic channel. */	_hcd->periodic_channels++;	/* Update claimed usecs per (micro)frame. */	_hcd->periodic_usecs += _qh->usecs;	/* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */	hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated += _qh->usecs / _qh->interval;	if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {		hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs++;		DWC_DEBUGPL(DBG_HCD, "Scheduled intr: qh %p, usecs %d, period %d\n",			    _qh, _qh->usecs, _qh->interval);	} else {		hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs++;		DWC_DEBUGPL(DBG_HCD, "Scheduled isoc: qh %p, usecs %d, period %d\n",			    _qh, _qh->usecs, _qh->interval);	}	return status;}/** * This function adds a QH to either the non periodic or periodic schedule if * it is not already in the schedule. If the QH is already in the schedule, no * action is taken. * * @return 0 if successful, negative error code otherwise. */int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh){	unsigned long flags;	int status = 0;	local_irq_save(flags);	if (!list_empty(&_qh->qh_list_entry)) {		/* QH already in a schedule. */		goto done;	}	/* Add the new QH to the appropriate schedule */	if (dwc_qh_is_non_per(_qh)) {		/* Always start in the inactive schedule. */		list_add_tail(&_qh->qh_list_entry, &_hcd->non_periodic_sched_inactive);	} else {		status = schedule_periodic(_hcd, _qh);	}      done:	local_irq_restore(flags);	return status;}/** * Removes an interrupt or isochronous transfer from the periodic schedule. * * @param _hcd The HCD state structure for the DWC OTG controller. * @param _qh QH for the periodic transfer. */static void deschedule_periodic(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh){	list_del_init(&_qh->qh_list_entry);	/* Release the periodic channel reservation. */	_hcd->periodic_channels--;	/* Update claimed usecs per (micro)frame. */	_hcd->periodic_usecs -= _qh->usecs;	/* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */	hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated -= _qh->usecs / _qh->interval;	if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {		hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs--;		DWC_DEBUGPL(DBG_HCD, "Descheduled intr: qh %p, usecs %d, period %d\n",			    _qh, _qh->usecs, _qh->interval);	} else {		hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs--;		DWC_DEBUGPL(DBG_HCD, "Descheduled isoc: qh %p, usecs %d, period %d\n",			    _qh, _qh->usecs, _qh->interval);	}}/** * Removes a QH from either the non-periodic or periodic schedule.  Memory is * not freed. * * @param[in] _hcd The HCD state structure. * @param[in] _qh QH to remove from schedule. */void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh){	unsigned long flags;	local_irq_save(flags);	if (list_empty(&_qh->qh_list_entry)) {		/* QH is not in a schedule. */		goto done;	}	if (dwc_qh_is_non_per(_qh)) {		if (_hcd->non_periodic_qh_ptr == &_qh->qh_list_entry) {			_hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next;		}		list_del_init(&_qh->qh_list_entry);	} else {		deschedule_periodic(_hcd, _qh);	}      done:	local_irq_restore(flags);}/** * Deactivates a QH. For non-periodic QHs, removes the QH from the active * non-periodic schedule. The QH is added to the inactive non-periodic * schedule if any QTDs are still attached to the QH. * * For periodic QHs, the QH is removed from the periodic queued schedule. If * there are any QTDs still attached to the QH, the QH is added to either the * periodic inactive schedule or the periodic ready schedule and its next * scheduled frame is calculated. The QH is placed in the ready schedule if * the scheduled frame has been reached already. Otherwise it's placed in the * inactive schedule. If there are no QTDs attached to the QH, the QH is * completely removed from the periodic schedule. */void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh,			       int sched_next_periodic_split){	unsigned long flags;	local_irq_save(flags);	if (dwc_qh_is_non_per(_qh)) {		dwc_otg_hcd_qh_remove(_hcd, _qh);		if (!list_empty(&_qh->qtd_list)) {			/* Add back to inactive non-periodic schedule. */			dwc_otg_hcd_qh_add(_hcd, _qh);		}	} else {		uint16_t frame_number = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd));		if (_qh->do_split) {			/* Schedule the next continuing periodic split transfer */			if (sched_next_periodic_split) {				_qh->sched_frame = frame_number;				if (dwc_frame_num_le(frame_number,						     dwc_frame_num_inc(_qh->start_split_frame,								       1))) {					/*					 * Allow one frame to elapse after start					 * split microframe before scheduling					 * complete split, but DONT if we are					 * doing the next start split in the					 * same frame for an ISOC out.					 */					if ((_qh->ep_type != USB_ENDPOINT_XFER_ISOC)					    || (_qh->ep_is_in != 0)) {						_qh->sched_frame =							dwc_frame_num_inc(_qh->sched_frame, 1);					}				}			} else {				_qh->sched_frame = dwc_frame_num_inc(_qh->start_split_frame,								     _qh->interval);				if (dwc_frame_num_le(_qh->sched_frame, frame_number)) {					_qh->sched_frame = frame_number;				}				_qh->sched_frame |= 0x7;				_qh->start_split_frame = _qh->sched_frame;			}		} else {			_qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, _qh->interval);			if (dwc_frame_num_le(_qh->sched_frame, frame_number)) {				_qh->sched_frame = frame_number;			}		}		if (list_empty(&_qh->qtd_list)) {			dwc_otg_hcd_qh_remove(_hcd, _qh);		} else {			/*			 * Remove from periodic_sched_queued and move to			 * appropriate queue.			 */			if (_qh->sched_frame == frame_number) {				list_move(&_qh->qh_list_entry, &_hcd->periodic_sched_ready);			} else {				list_move(&_qh->qh_list_entry, &_hcd->periodic_sched_inactive);			}		}	}	local_irq_restore(flags);}#if 0/** Allocates memory for a QTD structure. * @return Returns the memory allocate or NULL on error. */static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc (void){	return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_KERNEL);}#endif/** * Initializes a QTD structure. * * @param[in] _qtd The QTD to initialize. * @param[in] _urb The URB to use for initialization.  */static void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * _qtd, struct urb *_urb){	memset(_qtd, 0, sizeof(dwc_otg_qtd_t));	_qtd->urb = _urb;	if (usb_pipecontrol(_urb->pipe)) {		/*		 * The only time the QTD data toggle is used is on the data		 * phase of control transfers. This phase always starts with		 * DATA1.		 */		_qtd->data_toggle = DWC_OTG_HC_PID_DATA1;		_qtd->control_phase = DWC_OTG_CONTROL_SETUP;	}	/* start split */	_qtd->complete_split = 0;	_qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;	_qtd->isoc_split_offset = 0;	/* Store the qtd ptr in the urb to reference what QTD. */	_urb->hcpriv = _qtd;	return;}/** * This function allocates and initializes a QTD. * * @param[in] _urb The URB to create a QTD from.  Each URB-QTD pair will end up * pointing to each other so each pair should have a unique correlation. * * @return Returns pointer to the newly allocated QTD, or NULL on error. */dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(struct urb *_urb){	dwc_otg_qtd_t *qtd;#if 0	qtd = dwc_otg_hcd_qtd_alloc();#else	qtd = (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_KERNEL);#endif	if (qtd == NULL) {		return NULL;	}	dwc_otg_hcd_qtd_init(qtd, _urb);	return qtd;}/** * This function adds a QTD to the QTD-list of a QH.  It will find the correct * QH to place the QTD into.  If it does not find a QH, then it will create a * new QH. If the QH to which the QTD is added is not currently scheduled, it * is placed into the proper schedule based on its EP type. * * @param[in] _qtd The QTD to add * @param[in] _dwc_otg_hcd The DWC HCD structure * * @return 0 if successful, negative error code otherwise. */int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * _qtd, dwc_otg_hcd_t * _dwc_otg_hcd){	struct usb_host_endpoint *ep;	dwc_otg_qh_t *qh;	unsigned long flags;	int retval = 0;	struct urb *urb = _qtd->urb;	local_irq_save(flags);	/*	 * Get the QH which holds the QTD-list to insert to. Create QH if it	 * doesn't exist.	 */	ep = dwc_urb_to_endpoint(urb);	qh = (dwc_otg_qh_t *) ep->hcpriv;	if (qh == NULL) {		qh = dwc_otg_hcd_qh_create(_dwc_otg_hcd, urb);		if (qh == NULL) {			goto done;		}		ep->hcpriv = qh;	}	retval = dwc_otg_hcd_qh_add(_dwc_otg_hcd, qh);	if (retval == 0) {		list_add_tail(&_qtd->qtd_list_entry, &qh->qtd_list);	}done:	local_irq_restore(flags);	return retval;}#endif				/* DWC_DEVICE_ONLY */

⌨️ 快捷键说明

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