Пример #1
0
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_LOWFLAT(pipe->qh.current);
            u32 tok = GET_LOWFLAT(pipe->qh.token);
            u32 next = GET_LOWFLAT(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_LOWFLAT(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;
}
Пример #2
0
static void
ehci_reset_pipe(struct ehci_pipe *pipe)
{
    SET_LOWFLAT(pipe->qh.qtd_next, EHCI_PTR_TERM);
    SET_LOWFLAT(pipe->qh.alt_next, EHCI_PTR_TERM);
    barrier();
    SET_LOWFLAT(pipe->qh.token, GET_LOWFLAT(pipe->qh.token) & QTD_TOGGLE);
}
Пример #3
0
// Maximum time (in ms) a data transfer should take
int
usb_xfer_time(struct usb_pipe *pipe, int datalen)
{
    // Use the maximum command time (5 seconds), except for
    // set_address commands where we don't want to stall the boot if
    // the device doesn't actually exist.  Add 100ms to account for
    // any controller delays.
    if (!GET_LOWFLAT(pipe->devaddr))
        return USB_TIME_STATUS + 100;
    return USB_TIME_COMMAND + 100;
}
Пример #4
0
int
ehci_poll_intr(struct usb_pipe *p, void *data)
{
    ASSERT16();
    if (! CONFIG_USB_EHCI)
        return -1;
    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
    struct ehci_qtd *td = GET_LOWFLAT(pipe->next_td);
    u32 token = GET_LOWFLAT(td->token);
    if (token & QTD_STS_ACTIVE)
        // No intrs found.
        return -1;
    // XXX - check for errors.

    // Copy data.
    int maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
    int pos = td - GET_LOWFLAT(pipe->tds);
    void *tddata = GET_LOWFLAT(pipe->data) + maxpacket * pos;
    memcpy_far(GET_SEG(SS), data, SEG_LOW, LOWFLAT2LOW(tddata), maxpacket);

    // Reenable this td.
    struct ehci_qtd *next = (void*)(GET_LOWFLAT(td->qtd_next) & ~EHCI_PTR_BITS);
    SET_LOWFLAT(pipe->next_td, next);
    SET_LOWFLAT(td->buf[0], (u32)tddata);
    barrier();
    SET_LOWFLAT(td->token, (ehci_explen(maxpacket) | QTD_STS_ACTIVE
                            | QTD_PID_IN | ehci_maxerr(3)));

    return 0;
}
Пример #5
0
int
ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
{
    if (! CONFIG_USB_EHCI)
        return -1;
    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
    dprintf(7, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n"
            , &pipe->qh, dir, data, datasize);

    // Allocate 4 tds on stack (with required alignment)
    u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1];
    struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN);
    memset(tds, 0, sizeof(*tds) * STACKQTDS);
    barrier();
    SET_LOWFLAT(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));

    u16 maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
    int tdpos = 0;
    while (datasize) {
        struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
        int ret = ehci_wait_td(pipe, td, 5000);
        if (ret)
            return -1;

        struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
                                                 , &tds[tdpos % STACKQTDS]);

        int transfer = fillTDbuffer(td, maxpacket, data, datasize);
        td->qtd_next = (transfer==datasize ? EHCI_PTR_TERM : (u32)nexttd_fl);
        td->alt_next = EHCI_PTR_TERM;
        barrier();
        td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE
                     | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));

        data += transfer;
        datasize -= transfer;
    }
    int i;
    for (i=0; i<STACKQTDS; i++) {
        struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
        int ret = ehci_wait_td(pipe, td, 5000);
        if (ret)
            return -1;
    }

    return 0;
}
Пример #6
0
int
usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
{
    ASSERT16();
    switch (GET_LOWFLAT(pipe_fl->type)) {
    default:
    case USB_TYPE_UHCI:
        return uhci_poll_intr(pipe_fl, data);
    case USB_TYPE_OHCI:
        return ohci_poll_intr(pipe_fl, data);
    case USB_TYPE_EHCI:
        return ehci_poll_intr(pipe_fl, data);
    case USB_TYPE_XHCI: ;
        return call32_params(xhci_poll_intr, pipe_fl
                             , MAKE_FLATPTR(GET_SEG(SS), data), 0, -1);
    }
}
Пример #7
0
int
usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
{
    ASSERT16();
    switch (GET_LOWFLAT(pipe_fl->type)) {
    default:
    case USB_TYPE_UHCI:
        return uhci_poll_intr(pipe_fl, data);
    case USB_TYPE_OHCI:
        return ohci_poll_intr(pipe_fl, data);
    case USB_TYPE_EHCI:
        return ehci_poll_intr(pipe_fl, data);
    case USB_TYPE_XHCI: ;
        extern void _cfunc32flat_xhci_poll_intr(void);
        return call32_params(_cfunc32flat_xhci_poll_intr, (u32)pipe_fl
                             , (u32)MAKE_FLATPTR(GET_SEG(SS), (u32)data), 0, -1);
    }
}
Пример #8
0
// Send a message on a control pipe using the default control descriptor.
static int
usb_send_pipe(struct usb_pipe *pipe_fl, int dir, const void *cmd
              , void *data, int datasize)
{
    switch (GET_LOWFLAT(pipe_fl->type)) {
    default:
    case USB_TYPE_UHCI:
        return uhci_send_pipe(pipe_fl, dir, cmd, data, datasize);
    case USB_TYPE_OHCI:
        if (MODESEGMENT)
            return -1;
        return ohci_send_pipe(pipe_fl, dir, cmd, data, datasize);
    case USB_TYPE_EHCI:
        return ehci_send_pipe(pipe_fl, dir, cmd, data, datasize);
    case USB_TYPE_XHCI:
        if (MODESEGMENT)
            return -1;
        return xhci_send_pipe(pipe_fl, dir, cmd, data, datasize);
    }
}
Пример #9
0
int usb_32bit_pipe(struct usb_pipe *pipe_fl)
{
    return (CONFIG_USB_XHCI && GET_LOWFLAT(pipe_fl->type) == USB_TYPE_XHCI)
           || (CONFIG_USB_OHCI && GET_LOWFLAT(pipe_fl->type) == USB_TYPE_OHCI);
}