* End point communication
****************************************************************/
-static void
-ehci_reset_pipe(struct ehci_pipe *pipe)
+struct usb_pipe *
+ehci_alloc_intr_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
{
- SET_FLATPTR(pipe->qh.qtd_next, EHCI_PTR_TERM);
- SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM);
- barrier();
- SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE);
-}
+ if (! CONFIG_USB_EHCI)
+ return NULL;
+ 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);
-static int
-ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, int timeout)
-{
- u64 end = calc_future_tsc(timeout);
- u32 status;
- for (;;) {
- status = td->token;
- if (!(status & QTD_STS_ACTIVE))
- break;
- if (check_tsc(end)) {
- u32 cur = GET_FLATPTR(pipe->qh.current);
- u32 tok = GET_FLATPTR(pipe->qh.token);
- u32 next = GET_FLATPTR(pipe->qh.qtd_next);
- warn_timeout();
- dprintf(1, "ehci pipe=%p cur=%08x tok=%08x next=%x td=%p status=%x\n"
- , pipe, cur, tok, next, td, status);
- ehci_reset_pipe(pipe);
- struct usb_ehci_s *cntl = container_of(
- GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb);
- ehci_waittick(cntl);
- return -1;
- }
- yield();
+ 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;
}
- if (status & QTD_STS_HALT) {
- dprintf(1, "ehci_wait_td error - status=%x\n", status);
- ehci_reset_pipe(pipe);
- return -2;
+ memset(pipe, 0, sizeof(*pipe));
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+ 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;
}
- return 0;
+
+ // 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 *
return &pipe->pipe;
}
+static void
+ehci_reset_pipe(struct ehci_pipe *pipe)
+{
+ SET_FLATPTR(pipe->qh.qtd_next, EHCI_PTR_TERM);
+ SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM);
+ barrier();
+ SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE);
+}
+
+static int
+ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, int timeout)
+{
+ u64 end = calc_future_tsc(timeout);
+ u32 status;
+ for (;;) {
+ status = td->token;
+ if (!(status & QTD_STS_ACTIVE))
+ break;
+ if (check_tsc(end)) {
+ u32 cur = GET_FLATPTR(pipe->qh.current);
+ u32 tok = GET_FLATPTR(pipe->qh.token);
+ u32 next = GET_FLATPTR(pipe->qh.qtd_next);
+ warn_timeout();
+ dprintf(1, "ehci pipe=%p cur=%08x tok=%08x next=%x td=%p status=%x\n"
+ , pipe, cur, tok, next, td, status);
+ ehci_reset_pipe(pipe);
+ struct usb_ehci_s *cntl = container_of(
+ GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb);
+ ehci_waittick(cntl);
+ return -1;
+ }
+ yield();
+ }
+ if (status & QTD_STS_HALT) {
+ dprintf(1, "ehci_wait_td error - status=%x\n", status);
+ ehci_reset_pipe(pipe);
+ return -2;
+ }
+ return 0;
+}
+
static int
fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes)
{
return 0;
}
-struct usb_pipe *
-ehci_alloc_intr_pipe(struct usbdevice_s *usbdev
- , struct usb_endpoint_descriptor *epdesc)
-{
- if (! CONFIG_USB_EHCI)
- return NULL;
- 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));
- usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
- 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;
-}
-
int
ehci_poll_intr(struct usb_pipe *p, void *data)
{
* End point communication
****************************************************************/
-static int
-wait_ed(struct ohci_ed *ed)
+struct usb_pipe *
+ohci_alloc_intr_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
{
- // XXX - 500ms just a guess
- u64 end = calc_future_tsc(500);
- for (;;) {
- if (ed->hwHeadP == ed->hwTailP)
- return 0;
- if (check_tsc(end)) {
- warn_timeout();
- return -1;
- }
- yield();
+ if (! CONFIG_USB_OHCI)
+ return NULL;
+ struct usb_ohci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_ohci_s, usb);
+ int frameexp = usb_getFrameExp(usbdev, epdesc);
+ dprintf(7, "ohci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+ if (frameexp > 5)
+ frameexp = 5;
+ 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)+1;
+ 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;
+ memset(pipe, 0, sizeof(*pipe));
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+ int lowspeed = pipe->pipe.speed;
+ int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+ pipe->data = data;
+ pipe->count = count;
+ pipe->tds = tds;
+
+ 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);
+
+ 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;
}
+
+ // Add to interrupt schedule.
+ barrier();
+ struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
+ ed->hwNextED = intr_ed->hwNextED;
+ intr_ed->hwNextED = (u32)ed;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ ed->hwNextED = hcca->int_table[startpos];
+ for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
+ hcca->int_table[i] = (u32)ed;
+ }
+
+ return &pipe->pipe;
+
+err:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
}
struct usb_pipe *
return &pipe->pipe;
}
+static int
+wait_ed(struct ohci_ed *ed)
+{
+ // XXX - 500ms just a guess
+ u64 end = calc_future_tsc(500);
+ for (;;) {
+ if (ed->hwHeadP == ed->hwTailP)
+ return 0;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
int
ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
, void *data, int datasize)
return -1;
}
-struct usb_pipe *
-ohci_alloc_intr_pipe(struct usbdevice_s *usbdev
- , struct usb_endpoint_descriptor *epdesc)
-{
- if (! CONFIG_USB_OHCI)
- return NULL;
- struct usb_ohci_s *cntl = container_of(
- usbdev->hub->cntl, struct usb_ohci_s, usb);
- int frameexp = usb_getFrameExp(usbdev, epdesc);
- dprintf(7, "ohci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
-
- if (frameexp > 5)
- frameexp = 5;
- 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)+1;
- 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;
- memset(pipe, 0, sizeof(*pipe));
- usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
- int lowspeed = pipe->pipe.speed;
- int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
- pipe->data = data;
- pipe->count = count;
- pipe->tds = tds;
-
- 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);
-
- 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;
- }
-
- // Add to interrupt schedule.
- barrier();
- struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
- if (frameexp == 0) {
- // Add to existing interrupt entry.
- struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
- ed->hwNextED = intr_ed->hwNextED;
- intr_ed->hwNextED = (u32)ed;
- } else {
- int startpos = 1<<(frameexp-1);
- ed->hwNextED = hcca->int_table[startpos];
- for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
- hcca->int_table[i] = (u32)ed;
- }
-
- return &pipe->pipe;
-
-err:
- free(pipe);
- free(tds);
- free(data);
- return NULL;
-}
-
int
ohci_poll_intr(struct usb_pipe *p, void *data)
{
* End point communication
****************************************************************/
-static int
-wait_pipe(struct uhci_pipe *pipe, int timeout)
+struct usb_pipe *
+uhci_alloc_intr_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
{
- u64 end = calc_future_tsc(timeout);
- for (;;) {
- u32 el_link = GET_FLATPTR(pipe->qh.element);
- if (el_link & UHCI_PTR_TERM)
- return 0;
- if (check_tsc(end)) {
- warn_timeout();
- u16 iobase = GET_FLATPTR(pipe->iobase);
- struct uhci_td *td = (void*)(el_link & ~UHCI_PTR_BITS);
- dprintf(1, "Timeout on wait_pipe %p (td=%p s=%x c=%x/%x)\n"
- , pipe, (void*)el_link, GET_FLATPTR(td->status)
- , inw(iobase + USBCMD)
- , inw(iobase + USBSTS));
- SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
- uhci_waittick(iobase);
- return -1;
- }
- yield();
+ if (! CONFIG_USB_UHCI)
+ return NULL;
+ struct usb_uhci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_uhci_s, usb);
+ int frameexp = usb_getFrameExp(usbdev, epdesc);
+ dprintf(7, "uhci_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);
+ count = ALIGN(count, 2);
+ struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+ struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
+ void *data = malloc_low(maxpacket * count);
+ if (!pipe || !tds || !data) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+ int lowspeed = pipe->pipe.speed;
+ int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+ pipe->qh.element = (u32)tds;
+ pipe->next_td = &tds[0];
+ pipe->iobase = cntl->iobase;
+
+ int toggle = 0;
+ int i;
+ for (i=0; i<count; i++) {
+ tds[i].link = (i==count-1 ? (u32)&tds[0] : (u32)&tds[i+1]);
+ tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ tds[i].token = (uhci_explen(maxpacket) | toggle
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | USB_PID_IN);
+ tds[i].buffer = data + maxpacket * i;
+ toggle ^= TD_TOKEN_TOGGLE;
}
+
+ // Add to interrupt schedule.
+ struct uhci_framelist *fl = cntl->framelist;
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
+ pipe->qh.link = intr_qh->link;
+ barrier();
+ intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+ if (cntl->control_qh == intr_qh)
+ cntl->control_qh = &pipe->qh;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ pipe->qh.link = fl->links[startpos];
+ barrier();
+ for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+ fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
+ }
+
+ return &pipe->pipe;
+fail:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
}
struct usb_pipe *
return &pipe->pipe;
}
+static int
+wait_pipe(struct uhci_pipe *pipe, int timeout)
+{
+ u64 end = calc_future_tsc(timeout);
+ for (;;) {
+ u32 el_link = GET_FLATPTR(pipe->qh.element);
+ if (el_link & UHCI_PTR_TERM)
+ return 0;
+ if (check_tsc(end)) {
+ warn_timeout();
+ u16 iobase = GET_FLATPTR(pipe->iobase);
+ struct uhci_td *td = (void*)(el_link & ~UHCI_PTR_BITS);
+ dprintf(1, "Timeout on wait_pipe %p (td=%p s=%x c=%x/%x)\n"
+ , pipe, (void*)el_link, GET_FLATPTR(td->status)
+ , inw(iobase + USBCMD)
+ , inw(iobase + USBSTS));
+ SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
+ uhci_waittick(iobase);
+ return -1;
+ }
+ yield();
+ }
+}
+
+static int
+wait_td(struct uhci_td *td)
+{
+ u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+ u32 status;
+ for (;;) {
+ status = td->status;
+ if (!(status & TD_CTRL_ACTIVE))
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ if (status & TD_CTRL_ANY_ERROR) {
+ dprintf(1, "wait_td error - status=%x\n", status);
+ return -2;
+ }
+ return 0;
+}
+
int
uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
, void *data, int datasize)
return ret;
}
-static int
-wait_td(struct uhci_td *td)
-{
- u64 end = calc_future_tsc(5000); // XXX - lookup real time.
- u32 status;
- for (;;) {
- status = td->status;
- if (!(status & TD_CTRL_ACTIVE))
- break;
- if (check_tsc(end)) {
- warn_timeout();
- return -1;
- }
- yield();
- }
- if (status & TD_CTRL_ANY_ERROR) {
- dprintf(1, "wait_td error - status=%x\n", status);
- return -2;
- }
- return 0;
-}
-
#define STACKTDS 4
#define TDALIGN 16
return -1;
}
-struct usb_pipe *
-uhci_alloc_intr_pipe(struct usbdevice_s *usbdev
- , struct usb_endpoint_descriptor *epdesc)
-{
- if (! CONFIG_USB_UHCI)
- return NULL;
- struct usb_uhci_s *cntl = container_of(
- usbdev->hub->cntl, struct usb_uhci_s, usb);
- int frameexp = usb_getFrameExp(usbdev, epdesc);
- dprintf(7, "uhci_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);
- count = ALIGN(count, 2);
- struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
- struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
- void *data = malloc_low(maxpacket * count);
- if (!pipe || !tds || !data) {
- warn_noalloc();
- goto fail;
- }
- memset(pipe, 0, sizeof(*pipe));
- usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
- int lowspeed = pipe->pipe.speed;
- int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
- pipe->qh.element = (u32)tds;
- pipe->next_td = &tds[0];
- pipe->iobase = cntl->iobase;
-
- int toggle = 0;
- int i;
- for (i=0; i<count; i++) {
- tds[i].link = (i==count-1 ? (u32)&tds[0] : (u32)&tds[i+1]);
- tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
- | TD_CTRL_ACTIVE);
- tds[i].token = (uhci_explen(maxpacket) | toggle
- | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
- | USB_PID_IN);
- tds[i].buffer = data + maxpacket * i;
- toggle ^= TD_TOKEN_TOGGLE;
- }
-
- // Add to interrupt schedule.
- struct uhci_framelist *fl = cntl->framelist;
- if (frameexp == 0) {
- // Add to existing interrupt entry.
- struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
- pipe->qh.link = intr_qh->link;
- barrier();
- intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
- if (cntl->control_qh == intr_qh)
- cntl->control_qh = &pipe->qh;
- } else {
- int startpos = 1<<(frameexp-1);
- pipe->qh.link = fl->links[startpos];
- barrier();
- for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
- fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
- }
-
- return &pipe->pipe;
-fail:
- free(pipe);
- free(tds);
- free(data);
- return NULL;
-}
-
int
uhci_poll_intr(struct usb_pipe *p, void *data)
{