📄 usb-ohci.c
字号:
**-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static char *hcfs2string (int state){ switch (state) { case OHCI_USB_RESET: return "reset"; case OHCI_USB_RESUME: return "resume"; case OHCI_USB_OPER: return "operational"; case OHCI_USB_SUSPEND: return "suspend"; } return "?";}/*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/// dump control and status registersstatic void ohci_dump_status (ohci_t *controller){ struct ohci_regs *regs = controller->regs; __u32 temp; temp = readl (®s->revision) & 0xff;// if (temp != 0x10) printk ("spec %d.%d\n", (temp >> 4), (temp & 0x0f)); temp = readl (®s->control); printk ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n", temp, (temp & OHCI_CTRL_RWE) ? " RWE" : "", (temp & OHCI_CTRL_RWC) ? " RWC" : "", (temp & OHCI_CTRL_IR) ? " IR" : "", hcfs2string (temp & OHCI_CTRL_HCFS), (temp & OHCI_CTRL_BLE) ? " BLE" : "", (temp & OHCI_CTRL_CLE) ? " CLE" : "", (temp & OHCI_CTRL_IE) ? " IE" : "", (temp & OHCI_CTRL_PLE) ? " PLE" : "", temp & OHCI_CTRL_CBSR ); temp = readl (®s->cmdstatus); printk ("cmdstatus: 0x%08x SOC=%d%s%s%s%s\n", temp, (temp & OHCI_SOC) >> 16, (temp & OHCI_OCR) ? " OCR" : "", (temp & OHCI_BLF) ? " BLF" : "", (temp & OHCI_CLF) ? " CLF" : "", (temp & OHCI_HCR) ? " HCR" : "" ); ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus)); ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); // intrdisable always same as intrenable // ohci_dump_intr_mask ("intrdisable", readl (®s->intrdisable)); maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); maybe_print_eds ("donehead", readl (®s->donehead));}static void ohci_dump_roothub (ohci_t *controller, int verbose){ __u32 temp, ndp, i; temp = roothub_a (controller); ndp = (temp & RH_A_NDP);// if (verbose) { printk ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp, ((temp & RH_A_POTPGT) >> 24) & 0xff, (temp & RH_A_NOCP) ? " NOCP" : "", (temp & RH_A_OCPM) ? " OCPM" : "", (temp & RH_A_DT) ? " DT" : "", (temp & RH_A_NPS) ? " NPS" : "", (temp & RH_A_PSM) ? " PSM" : "", ndp ); temp = roothub_b (controller); printk ("roothub.b: %08x PPCM=%04x DR=%04x\n", temp, (temp & RH_B_PPCM) >> 16, (temp & RH_B_DR) ); temp = roothub_status (controller); printk ("roothub.status: %08x%s%s%s%s%s%s\n", temp, (temp & RH_HS_CRWE) ? " CRWE" : "", (temp & RH_HS_OCIC) ? " OCIC" : "", (temp & RH_HS_LPSC) ? " LPSC" : "", (temp & RH_HS_DRWE) ? " DRWE" : "", (temp & RH_HS_OCI) ? " OCI" : "", (temp & RH_HS_LPS) ? " LPS" : "" );// } for (i = 0; i < ndp; i++) { temp = roothub_portstatus (controller, i); printk ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", i, temp, (temp & RH_PS_PRSC) ? " PRSC" : "", (temp & RH_PS_OCIC) ? " OCIC" : "", (temp & RH_PS_PSSC) ? " PSSC" : "", (temp & RH_PS_PESC) ? " PESC" : "", (temp & RH_PS_CSC) ? " CSC" : "", (temp & RH_PS_LSDA) ? " LSDA" : "", (temp & RH_PS_PPS) ? " PPS" : "", (temp & RH_PS_PRS) ? " PRS" : "", (temp & RH_PS_POCI) ? " POCI" : "", (temp & RH_PS_PSS) ? " PSS" : "", (temp & RH_PS_PES) ? " PES" : "", (temp & RH_PS_CCS) ? " CCS" : "" ); }}/*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static void ohci_dump (ohci_t *controller, int verbose){ printk ("OHCI controller usb-%s state\n", controller->slot_name); // dumps some of the state we know about ohci_dump_status (controller); if (verbose) ep_print_int_eds (controller, "hcca"); printk ("hcca frame #%04x\n", controller->hcca->frame_no); ohci_dump_roothub (controller, 1);}#endif/*-------------------------------------------------------------------------* * Interface functions (URB) *-------------------------------------------------------------------------*//* return a request to the completion handler */ /*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static int sohci_return_urb (struct ohci *hc, urb_t * urb){ urb_priv_t * urb_priv = urb->hcpriv; urb_t * urbt; unsigned long flags; int i; if (!urb_priv) return -1; /* urb already unlinked */ /* just to be sure */ if (!urb->complete) { urb_rm_priv (urb); return -1; } #ifdef DEBUG urb_print (urb, "RET", usb_pipeout (urb->pipe));#endif switch (usb_pipetype (urb->pipe)) { case PIPE_INTERRUPT: pci_unmap_single (hc->ohci_dev, urb_priv->td [0]->data_dma, urb->transfer_buffer_length, usb_pipeout (urb->pipe) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);#if 1 urb->complete (urb); /* implicitly requeued */ urb->actual_length = 0; urb->status = USB_ST_URB_PENDING; if (urb_priv->state != URB_DEL) td_submit_urb (urb);#else if (urb->interval) { urb->complete (urb); /* implicitly requeued */ urb->actual_length = 0; urb->status = USB_ST_URB_PENDING; if (urb_priv->state != URB_DEL) td_submit_urb (urb); } else { urb_rm_priv(urb); urb->complete (urb); }#endif break; case PIPE_ISOCHRONOUS: for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next); if (urbt) { /* send the reply and requeue URB */ pci_unmap_single (hc->ohci_dev, urb_priv->td [0]->data_dma, urb->transfer_buffer_length, usb_pipeout (urb->pipe) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); urb->complete (urb); spin_lock_irqsave (&usb_ed_lock, flags); urb->actual_length = 0; urb->status = USB_ST_URB_PENDING; urb->start_frame = urb_priv->ed->last_iso + 1; if (urb_priv->state != URB_DEL) { for (i = 0; i < urb->number_of_packets; i++) { urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = -EXDEV; } td_submit_urb (urb); } spin_unlock_irqrestore (&usb_ed_lock, flags); } else { /* unlink URB, call complete */ urb_rm_priv (urb); urb->complete (urb); } break; case PIPE_BULK: case PIPE_CONTROL: /* unlink URB, call complete */ urb_rm_priv (urb); urb->complete (urb); break; } return 0;}/*-------------------------------------------------------------------------*//* get a transfer request *//*********************************************************************************************************** Function name: sohci_submit_urb** Descriptions: USB设备类驱动程序通过调用该函数可将相应的URB传递给HCD层来进行相应的数据传输。** Input:A:** B:** C:** Output : 返回值为小于或等于零的数,其中零表示提交URB操作成功,其它为错误代码。** 0 操作成功** -ENOMEN 函数内部内存分配失败** -ENXIO 相应的端点已经存在一个控制传输、中断传输或批量传输URB** -EINVAL 在下面几种情况下都回返回该错误代码** 无效的数据传输类型** 无效的中断间隔** 多个被请求的中断数据包** 等时传输的数据包数目小于0** -EAGAIN 在下面几种情况下都回返回该错误代码** 被指定等时传输中的起始帧过早** 在使用ISO-ASAP时,太长的时间调度和数据重传** -EFBIG 太多的等时数据帧(仅仅针对UHCI主控制器驱动)** -EPIPE 相应的管道已经被中止(STALLED)** -ENOSPC USB总线没有足够的带宽用于该URB传输** -ESHUTDOWN 主控制器已被终止** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/ static int sohci_submit_urb (urb_t * urb){ ohci_t * ohci; ed_t * ed; urb_priv_t * urb_priv; unsigned int pipe = urb->pipe; int maxps = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)); int i, size = 0; unsigned long flags; int bustime = 0; int mem_flags = ALLOC_FLAGS; if (!urb->dev || !urb->dev->bus) return -ENODEV; if (urb->hcpriv) /* urb already in use */ return -EINVAL;// if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) // return -EPIPE; usb_inc_dev_use (urb->dev); ohci = (ohci_t *) urb->dev->bus->hcpriv; #ifdef DEBUG urb_print (urb, "SUB", usb_pipein (pipe));#endif /* handle a request to the virtual root hub */ if (usb_pipedevice (pipe) == ohci->rh.devnum) { // 如果与根集线器地址一至,即为操作根集线器,调用根集线器处理 return rh_submit_urb (urb); } /* when controller's hung, permit only roothub cleanup attempts * such as powering down ports */ if (ohci->disabled) { //主控制器已被终止 usb_dec_dev_use (urb->dev); return -ESHUTDOWN; } /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) { usb_dec_dev_use (urb->dev); return -ENOMEM; } /* for the private part of the URB we need the number of TDs (size) */ // 根据各传输类型,确定需要的传输描述符个数 switch (usb_pipetype (pipe)) { case PIPE_BULK: /* one TD for every 4096 Byte */ size = (urb->transfer_buffer_length - 1) / 4096 + 1; /* If the transfer size is multiple of the pipe mtu, * we may need an extra TD to create a empty frame * Jean II */ // 如果传输刚好是满包,则需要多一个空包 if ((urb->transfer_flags & USB_ZERO_PACKET) && usb_pipeout (pipe) && (urb->transfer_buffer_length != 0) && ((urb->transfer_buffer_length % maxps) == 0)) size++; break; case PIPE_ISOCHRONOUS: /* number of packets from URB */ size = urb->number_of_packets; if (size <= 0) { usb_dec_dev_use (urb->dev); return -EINVAL; } for (i = 0; i < urb->number_of_packets; i++) { urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = -EXDEV; } break; case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */ size = (urb->transfer_buffer_length == 0)? 2: (urb->transfer_buffer_length - 1) / 4096 + 3; break; case PIPE_INTERRUPT: /* one TD */ size = 1; // 中断传输只有一个TD(传输描述符) break; } /* allocate the private part of the URB */ // 分配URB的私有数据RAM urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!urb_priv) { usb_dec_dev_use (urb->dev); return -ENOMEM; } memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *)); /* fill the private part of the URB */ urb_priv->length = size; // 传输描述符的个数 urb_priv->ed = ed; // /* allocate the TDs (updating hash chains) */ spin_lock_irqsave (&usb_ed_lock, flags); for (i = 0; i < size; i++) { urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC);// 分配传输描述符 if (!urb_priv->td[i]) { urb_priv->length = i; urb_free_priv (ohci, urb_priv); // 释放URB私有数据 spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); return -ENOMEM; } } if (ed->state == ED_NEW || (ed->state & ED_DEL)) { // 检查端点状态
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -