⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb-musb.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
}static inline void musb_cb_tick1(void *opaque){    struct musb_ep_s *ep = (struct musb_ep_s *) opaque;    ep->delayed_cb[1](&ep->packey[1], opaque);}#define musb_cb_tick	(dir ? musb_cb_tick1 : musb_cb_tick0)static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir){    struct musb_ep_s *ep = (struct musb_ep_s *) opaque;    int timeout = 0;    if (ep->status[dir] == USB_RET_NAK)        timeout = ep->timeout[dir];    else if (ep->interrupt[dir])        timeout = 8;    else        return musb_cb_tick(opaque);    if (!ep->intv_timer[dir])        ep->intv_timer[dir] = qemu_new_timer(vm_clock, musb_cb_tick, opaque);    qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock(vm_clock) +                    muldiv64(timeout, ticks_per_sec, 8000));}static void musb_schedule0_cb(USBPacket *packey, void *opaque){    return musb_schedule_cb(packey, opaque, 0);}static void musb_schedule1_cb(USBPacket *packey, void *opaque){    return musb_schedule_cb(packey, opaque, 1);}static int musb_timeout(int ttype, int speed, int val){#if 1    return val << 3;#endif    switch (ttype) {    case USB_ENDPOINT_XFER_CONTROL:        if (val < 2)            return 0;        else if (speed == USB_SPEED_HIGH)            return 1 << (val - 1);        else            return 8 << (val - 1);    case USB_ENDPOINT_XFER_INT:        if (speed == USB_SPEED_HIGH)            if (val < 2)                return 0;            else                return 1 << (val - 1);        else            return val << 3;    case USB_ENDPOINT_XFER_BULK:    case USB_ENDPOINT_XFER_ISOC:        if (val < 2)            return 0;        else if (speed == USB_SPEED_HIGH)            return 1 << (val - 1);        else            return 8 << (val - 1);        /* TODO: what with low-speed Bulk and Isochronous?  */    }    cpu_abort(cpu_single_env, "bad interval\n");}static inline void musb_packet(struct musb_s *s, struct musb_ep_s *ep,                int epnum, int pid, int len, USBCallback cb, int dir){    int ret;    int idx = epnum && dir;    int ttype;    /* ep->type[0,1] contains:     * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)     * in bits 5:4 the transfer type (BULK / INT)     * in bits 3:0 the EP num     */    ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;    ep->timeout[dir] = musb_timeout(ttype,                    ep->type[idx] >> 6, ep->interval[idx]);    ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;    ep->delayed_cb[dir] = cb;    cb = dir ? musb_schedule1_cb : musb_schedule0_cb;    ep->packey[dir].pid = pid;    /* A wild guess on the FADDR semantics... */    ep->packey[dir].devaddr = ep->faddr[idx];    ep->packey[dir].devep = ep->type[idx] & 0xf;    ep->packey[dir].data = (void *) ep->buf[idx];    ep->packey[dir].len = len;    ep->packey[dir].complete_cb = cb;    ep->packey[dir].complete_opaque = ep;    if (s->port.dev)        ret = s->port.dev->handle_packet(s->port.dev, &ep->packey[dir]);    else        ret = USB_RET_NODEV;    if (ret == USB_RET_ASYNC) {        ep->status[dir] = len;        return;    }    ep->status[dir] = ret;    usb_packet_complete(&ep->packey[dir]);}static void musb_tx_packet_complete(USBPacket *packey, void *opaque){    /* Unfortunately we can't use packey->devep because that's the remote     * endpoint number and may be different than our local.  */    struct musb_ep_s *ep = (struct musb_ep_s *) opaque;    int epnum = ep->epnum;    struct musb_s *s = ep->musb;    ep->fifostart[0] = 0;    ep->fifolen[0] = 0;#ifdef CLEAR_NAK    if (ep->status[0] != USB_RET_NAK) {#endif        if (epnum)            ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);        else            ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;#ifdef CLEAR_NAK    }#endif    /* Clear all of the error bits first */    if (epnum)        ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |                        MGC_M_TXCSR_H_NAKTIMEOUT);    else        ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |                        MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);    if (ep->status[0] == USB_RET_STALL) {        /* Command not supported by target! */        ep->status[0] = 0;        if (epnum)            ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;        else            ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;    }    if (ep->status[0] == USB_RET_NAK) {        ep->status[0] = 0;        /* NAK timeouts are only generated in Bulk transfers and         * Data-errors in Isochronous.  */        if (ep->interrupt[0]) {            return;        }        if (epnum)            ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;        else            ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;    }    if (ep->status[0] < 0) {        if (ep->status[0] == USB_RET_BABBLE)            musb_intr_set(s, musb_irq_rst_babble, 1);        /* Pretend we've tried three times already and failed (in         * case of USB_TOKEN_SETUP).  */        if (epnum)            ep->csr[0] |= MGC_M_TXCSR_H_ERROR;        else            ep->csr[0] |= MGC_M_CSR0_H_ERROR;        musb_tx_intr_set(s, epnum, 1);        return;    }    /* TODO: check len for over/underruns of an OUT packet?  */#ifdef SETUPLEN_HACK    if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)        s->setup_len = ep->packey[0].data[6];#endif    /* In DMA mode: if no error, assert DMA request for this EP,     * and skip the interrupt.  */    musb_tx_intr_set(s, epnum, 1);}static void musb_rx_packet_complete(USBPacket *packey, void *opaque){    /* Unfortunately we can't use packey->devep because that's the remote     * endpoint number and may be different than our local.  */    struct musb_ep_s *ep = (struct musb_ep_s *) opaque;    int epnum = ep->epnum;    struct musb_s *s = ep->musb;    ep->fifostart[1] = 0;    ep->fifolen[1] = 0;#ifdef CLEAR_NAK    if (ep->status[1] != USB_RET_NAK) {#endif        ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;        if (!epnum)            ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;#ifdef CLEAR_NAK    }#endif    /* Clear all of the imaginable error bits first */    ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |                    MGC_M_RXCSR_DATAERROR);    if (!epnum)        ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |                        MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);    if (ep->status[1] == USB_RET_STALL) {        ep->status[1] = 0;        packey->len = 0;        ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;        if (!epnum)            ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;    }    if (ep->status[1] == USB_RET_NAK) {        ep->status[1] = 0;        /* NAK timeouts are only generated in Bulk transfers and         * Data-errors in Isochronous.  */        if (ep->interrupt[1])            return musb_packet(s, ep, epnum, USB_TOKEN_IN,                            packey->len, musb_rx_packet_complete, 1);        ep->csr[1] |= MGC_M_RXCSR_DATAERROR;        if (!epnum)            ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;    }    if (ep->status[1] < 0) {        if (ep->status[1] == USB_RET_BABBLE) {            musb_intr_set(s, musb_irq_rst_babble, 1);            return;        }        /* Pretend we've tried three times already and failed (in         * case of a control transfer).  */        ep->csr[1] |= MGC_M_RXCSR_H_ERROR;        if (!epnum)            ep->csr[0] |= MGC_M_CSR0_H_ERROR;        musb_rx_intr_set(s, epnum, 1);        return;    }    /* TODO: check len for over/underruns of an OUT packet?  */    /* TODO: perhaps make use of e->ext_size[1] here.  */    packey->len = ep->status[1];    if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {        ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;        if (!epnum)            ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;        ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */        /* In DMA mode: assert DMA request for this EP */    }    /* Only if DMA has not been asserted */    musb_rx_intr_set(s, epnum, 1);}static void musb_tx_rdy(struct musb_s *s, int epnum){    struct musb_ep_s *ep = s->ep + epnum;    int pid;    int total, valid = 0;    ep->fifostart[0] += ep->fifolen[0];    ep->fifolen[0] = 0;    /* XXX: how's the total size of the packet retrieved exactly in     * the generic case?  */    total = ep->maxp[0] & 0x3ff;    if (ep->ext_size[0]) {        total = ep->ext_size[0];        ep->ext_size[0] = 0;        valid = 1;    }    /* If the packet is not fully ready yet, wait for a next segment.  */    if (epnum && (ep->fifostart[0] << 2) < total)        return;    if (!valid)        total = ep->fifostart[0] << 2;    pid = USB_TOKEN_OUT;    if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {        pid = USB_TOKEN_SETUP;        if (total != 8)            printf("%s: illegal SETUPPKT length of %i bytes\n",                            __FUNCTION__, total);        /* Controller should retry SETUP packets three times on errors         * but it doesn't make sense for us to do that.  */    }    return musb_packet(s, ep, epnum, pid,                    total, musb_tx_packet_complete, 0);}static void musb_rx_req(struct musb_s *s, int epnum){    struct musb_ep_s *ep = s->ep + epnum;    int total;    /* If we already have a packet, which didn't fit into the     * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */    if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 &&                    (ep->fifostart[1] << 2) + ep->rxcount <                    ep->packey[1].len) {        ep->fifostart[1] += ep->rxcount >> 2;        ep->fifolen[1] = 0;        ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1] << 2),                        ep->maxp[1]);        ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;        if (!epnum)            ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;        /* Clear all of the error bits first */        ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |                        MGC_M_RXCSR_DATAERROR);        if (!epnum)            ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |                            MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);        ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;        if (!epnum)            ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;        musb_rx_intr_set(s, epnum, 1);        return;    }    /* The driver sets maxp[1] to 64 or less because it knows the hardware     * FIFO is this deep.  Bigger packets get split in     * usb_generic_handle_packet but we can also do the splitting locally     * for performance.  It turns out we can also have a bigger FIFO and     * ignore the limit set in ep->maxp[1].  The Linux MUSB driver deals     * OK with single packets of even 32KB and we avoid splitting, however     * usb_msd.c sometimes sends a packet bigger than what Linux expects     * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN.  Splitting     * hides this overrun from Linux.  Up to 4096 everything is fine     * though.  Currently this is disabled.     *     * XXX: mind ep->fifosize.  */    total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));#ifdef SETUPLEN_HACK    /* Why should *we* do that instead of Linux?  */    if (!epnum) {        if (ep->packey[0].devaddr == 2)            total = MIN(s->setup_len, 8);        else            total = MIN(s->setup_len, 64);        s->setup_len -= total;    }#endif    return musb_packet(s, ep, epnum, USB_TOKEN_IN,                    total, musb_rx_packet_complete, 1);}static void musb_ep_frame_cancel(struct musb_ep_s *ep, int dir){    if (ep->intv_timer[dir])        qemu_del_timer(ep->intv_timer[dir]);}/* Bus control */static uint8_t musb_busctl_readb(void *opaque, int ep, int addr){    struct musb_s *s = (struct musb_s *) opaque;    switch (addr) {    /* For USB2.0 HS hubs only */    case MUSB_HDRC_TXHUBADDR:        return s->ep[ep].haddr[0];    case MUSB_HDRC_TXHUBPORT:        return s->ep[ep].hport[0];    case MUSB_HDRC_RXHUBADDR:        return s->ep[ep].haddr[1];    case MUSB_HDRC_RXHUBPORT:        return s->ep[ep].hport[1];    default:        printf("%s: unknown register at %02x\n", __FUNCTION__, addr);        return 0x00;    };}static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value){    struct musb_s *s = (struct musb_s *) opaque;    switch (addr) {    case MUSB_HDRC_TXHUBADDR:        s->ep[ep].haddr[0] = value;        break;    case MUSB_HDRC_TXHUBPORT:        s->ep[ep].hport[0] = value;        break;    case MUSB_HDRC_RXHUBADDR:        s->ep[ep].haddr[1] = value;        break;    case MUSB_HDRC_RXHUBPORT:        s->ep[ep].hport[1] = value;        break;    default:        printf("%s: unknown register at %02x\n", __FUNCTION__, addr);    };}static uint16_t musb_busctl_readh(void *opaque, int ep, int addr){    struct musb_s *s = (struct musb_s *) opaque;    switch (addr) {    case MUSB_HDRC_TXFUNCADDR:        return s->ep[ep].faddr[0];    case MUSB_HDRC_RXFUNCADDR:        return s->ep[ep].faddr[1];    default:        return musb_busctl_readb(s, ep, addr) |                (musb_busctl_readb(s, ep, addr | 1) << 8);    };}static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value){    struct musb_s *s = (struct musb_s *) opaque;    switch (addr) {    case MUSB_HDRC_TXFUNCADDR:        s->ep[ep].faddr[0] = value;        break;    case MUSB_HDRC_RXFUNCADDR:        s->ep[ep].faddr[1] = value;        break;    default:        musb_busctl_writeb(s, ep, addr, value & 0xff);        musb_busctl_writeb(s, ep, addr | 1, value >> 8);    };}/* Endpoint control */static uint8_t musb_ep_readb(void *opaque, int ep, int addr){    struct musb_s *s = (struct musb_s *) opaque;    switch (addr) {    case MUSB_HDRC_TXTYPE:        return s->ep[ep].type[0];    case MUSB_HDRC_TXINTERVAL:        return s->ep[ep].interval[0];    case MUSB_HDRC_RXTYPE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -