📄 usb-ohci.c
字号:
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 + -