struct usb_pipe * ohci_alloc_intr_pipe(u32 endp, int period) { if (! CONFIG_USB_OHCI) return NULL; dprintf(7, "ohci_alloc_intr_pipe %x %d\n", endp, period); struct usb_s *cntl = endp2cntl(endp); int maxpacket = endp2maxsize(endp); int lowspeed = endp2speed(endp); int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7); // XXX - just grab 20 for now. int count = 20; struct ohci_pipe *pipe = malloc_low(sizeof(*pipe)); struct ohci_td *tds = malloc_low(sizeof(*tds) * count); void *data = malloc_low(maxpacket * count); if (!pipe || !tds || !data) goto err; struct ohci_ed *ed = &pipe->ed; ed->hwHeadP = (u32)&tds[0]; ed->hwTailP = (u32)&tds[count-1]; ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0); ed->hwNextED = 0; int i; for (i=0; i<count-1; i++) { tds[i].hwINFO = TD_DP_IN | TD_T_TOGGLE | TD_CC; tds[i].hwCBP = (u32)data + maxpacket * i; tds[i].hwNextTD = (u32)&tds[i+1]; tds[i].hwBE = tds[i].hwCBP + maxpacket - 1; } // XXX - need schedule - just add to primary list for now. barrier(); struct ohci_hcca *hcca = (void*)cntl->ohci.regs->hcca; for (i=0; i<ARRAY_SIZE(hcca->int_table); i++) hcca->int_table[i] = (u32)ed; pipe->data = data; pipe->count = count; pipe->tds = tds; pipe->pipe.endp = endp; return &pipe->pipe; err: free(pipe); free(tds); free(data); return NULL; }
int create_bounce_buf(void) { if (bounce_buf_fl) return 0; u8 *buf = malloc_low(CDROM_SECTOR_SIZE); if (!buf) { warn_noalloc(); return -1; } bounce_buf_fl = buf; return 0; }
static struct usb_pipe * ehci_alloc_intr_pipe(struct usbdevice_s *usbdev , struct usb_endpoint_descriptor *epdesc) { struct usb_ehci_s *cntl = container_of( usbdev->hub->cntl, struct usb_ehci_s, usb); int frameexp = usb_getFrameExp(usbdev, epdesc); dprintf(7, "ehci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp); if (frameexp > 10) frameexp = 10; int maxpacket = epdesc->wMaxPacketSize; // Determine number of entries needed for 2 timer ticks. int ms = 1<<frameexp; int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms); struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe)); struct ehci_qtd *tds = memalign_low(EHCI_QTD_ALIGN, sizeof(*tds) * count); void *data = malloc_low(maxpacket * count); if (!pipe || !tds || !data) { warn_noalloc(); goto fail; } memset(pipe, 0, sizeof(*pipe)); ehci_desc2pipe(pipe, usbdev, epdesc); pipe->next_td = pipe->tds = tds; pipe->data = data; pipe->qh.qtd_next = (u32)tds; int i; for (i=0; i<count; i++) { struct ehci_qtd *td = &tds[i]; td->qtd_next = (i==count-1 ? (u32)tds : (u32)&td[1]); td->alt_next = EHCI_PTR_TERM; td->token = (ehci_explen(maxpacket) | QTD_STS_ACTIVE | QTD_PID_IN | ehci_maxerr(3)); td->buf[0] = (u32)data + maxpacket * i; } // Add to interrupt schedule. struct ehci_framelist *fl = (void*)readl(&cntl->regs->periodiclistbase); if (frameexp == 0) { // Add to existing interrupt entry. struct ehci_qh *intr_qh = (void*)(fl->links[0] & ~EHCI_PTR_BITS); pipe->qh.next = intr_qh->next; barrier(); intr_qh->next = (u32)&pipe->qh | EHCI_PTR_QH; } else { int startpos = 1<<(frameexp-1); pipe->qh.next = fl->links[startpos]; barrier(); for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms) fl->links[i] = (u32)&pipe->qh | EHCI_PTR_QH; } return &pipe->pipe; fail: free(pipe); free(tds); free(data); return NULL; }
struct usb_pipe * ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp) { if (! CONFIG_USB_EHCI) return NULL; struct usb_ehci_s *cntl = container_of( dummy->cntl, struct usb_ehci_s, usb); dprintf(7, "ehci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp); if (frameexp > 10) frameexp = 10; int maxpacket = dummy->maxpacket; // Determine number of entries needed for 2 timer ticks. int ms = 1<<frameexp; int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms); struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe)); struct ehci_qtd *tds = memalign_low(EHCI_QTD_ALIGN, sizeof(*tds) * count); void *data = malloc_low(maxpacket * count); if (!pipe || !tds || !data) { warn_noalloc(); goto fail; } memset(pipe, 0, sizeof(*pipe)); memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); pipe->next_td = pipe->tds = tds; pipe->data = data; pipe->qh.info1 = ( (1 << QH_MULT_SHIFT) | (maxpacket << QH_MAXPACKET_SHIFT) | (pipe->pipe.speed << QH_SPEED_SHIFT) | (pipe->pipe.ep << QH_EP_SHIFT) | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT)); pipe->qh.info2 = ((1 << QH_MULT_SHIFT) | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT) | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT) | (0x01 << QH_SMASK_SHIFT) | (0x1c << QH_CMASK_SHIFT)); pipe->qh.qtd_next = (u32)tds; int i; for (i=0; i<count; i++) { struct ehci_qtd *td = &tds[i]; td->qtd_next = (i==count-1 ? (u32)tds : (u32)&td[1]); td->alt_next = EHCI_PTR_TERM; td->token = (ehci_explen(maxpacket) | QTD_STS_ACTIVE | QTD_PID_IN | ehci_maxerr(3)); td->buf[0] = (u32)data + maxpacket * i; } // Add to interrupt schedule. struct ehci_framelist *fl = (void*)readl(&cntl->regs->periodiclistbase); if (frameexp == 0) { // Add to existing interrupt entry. struct ehci_qh *intr_qh = (void*)(fl->links[0] & ~EHCI_PTR_BITS); pipe->qh.next = intr_qh->next; barrier(); intr_qh->next = (u32)&pipe->qh | EHCI_PTR_QH; } else { int startpos = 1<<(frameexp-1); pipe->qh.next = fl->links[startpos]; barrier(); for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms) fl->links[i] = (u32)&pipe->qh | EHCI_PTR_QH; } return &pipe->pipe; fail: free(pipe); free(tds); free(data); return NULL; }