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

📄 usb-ohci.c

📁 周立功magic2410实验箱源码 第6章Linux高级实验(part2) 6.9 IDE硬盘实验. 6.10 USB主机驱动编译与加载实验 6.11 U盘驱动程序编译与使用实验 6.12
💻 C
📖 第 1 页 / 共 5 页
字号:
		urb_free_priv (ohci, urb_priv);		spin_unlock_irqrestore (&usb_ed_lock, flags);		usb_dec_dev_use (urb->dev);			return -EINVAL;	}		/* allocate and claim bandwidth if needed; ISO	 * needs start frame index if it was't provided.	 */	 // 根据需要分配带宽,同步传输与中断传输	switch (usb_pipetype (pipe)) {		case PIPE_ISOCHRONOUS:// 同步传输			if (urb->transfer_flags & USB_ISO_ASAP) { 				urb->start_frame = ((ed->state == ED_OPER)					? (ed->last_iso + 1)					: (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff;			}				/* FALLTHROUGH */		case PIPE_INTERRUPT:// 中断传输			if (urb->bandwidth == 0) {				bustime = usb_check_bandwidth (urb->dev, urb);	// 检查带宽状态			}			if (bustime < 0) {									// 如果没有足够的带宽				urb_free_priv (ohci, urb_priv);				spin_unlock_irqrestore (&usb_ed_lock, flags);	// 开中断自旋锁				usb_dec_dev_use (urb->dev);					return bustime;			}			usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe)); // 分配USB带宽#ifdef	DO_TIMEOUTS			urb->timeout = 0;#endif	}// URB数据结构初始化完成	urb->actual_length = 0;							// 实际数据长度	urb->hcpriv = urb_priv;							// 设置私有数据指针	urb->status = USB_ST_URB_PENDING;		// 标记等待传输标志	/* link the ed into a chain if is not already */	if (ed->state != ED_OPER) {	// 如果端点还不存在,添加端点到链表		ep_link (ohci, ed);	}	/* fill the TDs and link it to the ed */	td_submit_urb (urb);				// 填充传输描述符并链接到相关的中断#ifdef	DO_TIMEOUTS	/* maybe add to ordered list of timeouts */	if (urb->timeout) {		struct list_head	*entry;		// FIXME:  usb-uhci uses relative timeouts (like this),		// while uhci uses absolute ones (probably better).		// Pick one solution and change the affected drivers.		urb->timeout += jiffies;		list_for_each (entry, &ohci->timeout_list) {			struct urb	*next_urb;			next_urb = list_entry (entry, struct urb, urb_list);			if (time_after_eq (urb->timeout, next_urb->timeout))				break;		}		list_add (&urb->urb_list, entry);		/* drive timeouts by SF (messy, but works) */		writel (OHCI_INTR_SF, &ohci->regs->intrenable);		}#endif	spin_unlock_irqrestore (&usb_ed_lock, flags);		// 开中断自旋锁	return 0;	}/*-------------------------------------------------------------------------*//* deactivate all TDs and remove the private part of the URB *//* interrupt callers must use async unlink mode *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static int sohci_unlink_urb (urb_t * urb){	unsigned long flags;	ohci_t * ohci;		if (!urb) /* just to be sure */ 		return -EINVAL;			if (!urb->dev || !urb->dev->bus)		return -ENODEV;	ohci = (ohci_t *) urb->dev->bus->hcpriv; #ifdef DEBUG	urb_print (urb, "UNLINK", 1);#endif		  	/* handle a request to the virtual root hub */	if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)		return rh_unlink_urb (urb);	if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) { 		if (!ohci->disabled) {			urb_priv_t  * urb_priv;			/* interrupt code may not sleep; it must use			 * async status return to unlink pending urbs.			 */			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)					&& in_interrupt ()) {				err ("bug in call from %p; use async!",					__builtin_return_address(0));				return -EWOULDBLOCK;			}			/* flag the urb and its TDs for deletion in some			 * upcoming SF interrupt delete list processing			 */			spin_lock_irqsave (&usb_ed_lock, flags);			urb_priv = urb->hcpriv;			if (!urb_priv || (urb_priv->state == URB_DEL)) {				spin_unlock_irqrestore (&usb_ed_lock, flags);				return 0;			}							urb_priv->state = URB_DEL; 			ep_rm_ed (urb->dev, urb_priv->ed);			urb_priv->ed->state |= ED_URB_DEL;			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {				DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 				DECLARE_WAITQUEUE (wait, current);				int timeout = OHCI_UNLINK_TIMEOUT;				add_wait_queue (&unlink_wakeup, &wait);				urb_priv->wait = &unlink_wakeup;				spin_unlock_irqrestore (&usb_ed_lock, flags);				/* wait until all TDs are deleted */				set_current_state(TASK_UNINTERRUPTIBLE);				while (timeout && (urb->status == USB_ST_URB_PENDING))					timeout = schedule_timeout (timeout);				set_current_state(TASK_RUNNING);				remove_wait_queue (&unlink_wakeup, &wait); 				if (urb->status == USB_ST_URB_PENDING) {					err ("unlink URB timeout");					return -ETIMEDOUT;				}			} else {				/* usb_dec_dev_use done in dl_del_list() */				urb->status = -EINPROGRESS;				spin_unlock_irqrestore (&usb_ed_lock, flags);			}		} else {			urb_rm_priv (urb);			if (urb->transfer_flags & USB_ASYNC_UNLINK) {				urb->status = -ECONNRESET;				if (urb->complete)					urb->complete (urb); 			} else 				urb->status = -ENOENT;		}		}		return 0;}/*-------------------------------------------------------------------------*//* allocate private data space for a usb device *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static int sohci_alloc_dev (struct usb_device *usb_dev){	struct ohci_device * dev;	dev = dev_alloc ((struct ohci *) usb_dev->bus->hcpriv, ALLOC_FLAGS);	if (!dev)		return -ENOMEM;	usb_dev->hcpriv = dev;	return 0;}/*-------------------------------------------------------------------------*//* may be called from interrupt context *//* frees private data space of usb device *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/  static int sohci_free_dev (struct usb_device * usb_dev){	unsigned long flags;	int i, cnt = 0;	ed_t * ed;	struct ohci_device * dev = usb_to_ohci (usb_dev);	ohci_t * ohci = usb_dev->bus->hcpriv;		if (!dev)		return 0;		if (usb_dev->devnum >= 0) {			/* driver disconnects should have unlinked all urbs		 * (freeing all the TDs, unlinking EDs) but we need		 * to defend against bugs that prevent that.		 */		spin_lock_irqsave (&usb_ed_lock, flags);			for(i = 0; i < NUM_EDS; i++) {  			ed = &(dev->ed[i]);  			if (ed->state != ED_NEW) {  				if (ed->state == ED_OPER) {					/* driver on that interface didn't unlink an urb */			//		dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",			//			ohci->slot_name, usb_dev->devnum, i);					ep_unlink (ohci, ed);				}  				ep_rm_ed (usb_dev, ed);  				ed->state = ED_DEL;  				cnt++;  			}  		}  		spin_unlock_irqrestore (&usb_ed_lock, flags);  				/* if the controller is running, tds for those unlinked		 * urbs get freed by dl_del_list at the next SF interrupt		 */		if (cnt > 0) {			if (ohci->disabled) {				/* FIXME: Something like this should kick in,				 * though it's currently an exotic case ...				 * the controller won't ever be touching				 * these lists again!!				dl_del_list (ohci,					le16_to_cpu (ohci->hcca->frame_no) & 1);				 */				warn ("TD leak, %d", cnt);			} else if (!in_interrupt ()) {				DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup); 				DECLARE_WAITQUEUE (wait, current);				int timeout = OHCI_UNLINK_TIMEOUT;				/* SF interrupt handler calls dl_del_list */				add_wait_queue (&freedev_wakeup, &wait);				dev->wait = &freedev_wakeup;				set_current_state(TASK_UNINTERRUPTIBLE);				while (timeout && dev->ed_cnt)					timeout = schedule_timeout (timeout);				set_current_state(TASK_RUNNING);				remove_wait_queue (&freedev_wakeup, &wait);				if (dev->ed_cnt) {					err ("free device %d timeout", usb_dev->devnum);					return -ETIMEDOUT;				}			} else {				/* likely some interface's driver has a refcount bug */				err ("bus %s devnum %d deletion in interrupt",					ohci->slot_name, usb_dev->devnum);				BUG ();			}		}	}	/* free device, and associated EDs */	dev_free (ohci, dev);	return 0;}/*-------------------------------------------------------------------------*//* tell us the current USB frame number *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static int sohci_get_current_frame_number (struct usb_device *usb_dev) {	ohci_t * ohci = usb_dev->bus->hcpriv;		return le16_to_cpu (ohci->hcca->frame_no);}/*-------------------------------------------------------------------------*/struct usb_operations sohci_device_operations = {	sohci_alloc_dev,								//为设备分配物理层的资源 	sohci_free_dev,									//释放设备占有的物理层资源 	sohci_get_current_frame_number,	//提供当前主机控制器所使用的帧号,一般用于实时传输	sohci_submit_urb,								//进行实际数据传输	sohci_unlink_urb								//结束数据传输请求};/*-------------------------------------------------------------------------* * ED handling functions *-------------------------------------------------------------------------*/  		/* search for the right branch to insert an interrupt ed into the int tree  * do some load ballancing; * returns the branch and  * sets the interval to interval = 2^integer (ld (interval)) *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static int ep_int_ballance (ohci_t * ohci, int interval, int load){	int i, branch = 0;   	/* search for the least loaded interrupt endpoint branch of all 32 branches */	for (i = 0; i < 32; i++) 		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i;   	branch = branch % interval;	for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;	return branch;}/*-------------------------------------------------------------------------*//*  2^int( ld (inter)) *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static int ep_2_n_interval (int inter){		int i;	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); 	return 1 << i;}/*-------------------------------------------------------------------------*//* the int tree is a binary tree  * in order to process it sequentially the indexes of the branches have to be mapped  * the mapping reverses the bits of a word of num_bits length *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static int ep_rev (int num_bits, int word)

⌨️ 快捷键说明

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