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

📄 m8xxhci.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif/* called once every 1ms; update delay list & see if there is work */static voidstart_of_frame(void){        struct m8xxhci_qe *qe;        /* update top of delay list */        if ((qe = delay_qe_list) != 0) {                --qe->delta;        }        /* switch active frames */        switch_frames();        /* jam as much as we can into this frame */        schedule_current_frame();#if 0        /* see if we need to retransmit a failed setup */        retransmit_setup();#endif        /* try and start something */        pick_next_thing_to_send();}/* ---- */static inline cbd_t *next_bd(void){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        cbd_t *bdp;        int index;        index = hp->txnext;        hp->tx_bd_qe[index] = 0;        bdp = hp->tbase + hp->txnext++;        if (bdp->cbd_sc & BD_SC_WRAP)                hp->txnext = 0;        bdp->cbd_sc &= BD_SC_WRAP;        hp->txfree--;        return bdp;}static inline cbd_t *next_bd_qe(struct m8xxhci_qe *qe){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        cbd_t *bdp;        int index;        index = hp->txnext;        bdp = next_bd();        if (bdp)                hp->tx_bd_qe[index] = qe;        return bdp;}static voidadvance_rx_bd(void){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        cbd_t *bdp;        bdp = hp->rbase + hp->rxnext;        hp->rxnext++;        if (bdp->cbd_sc & BD_SC_WRAP)                hp->rxnext = 0;        bdp->cbd_datlen = 0;        bdp->cbd_sc &= BD_SC_WRAP;        bdp->cbd_sc |= BD_SC_EMPTY | BD_SC_INTRPT;}/* reset a bd and advance the txlast ptr */static inline voidadvance_tx_bd(void){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        cbd_t *bdp;        bdp = hp->tbase + hp->txlast;        hp->tx_bd_qe[ hp->txlast ] = 0;        hp->txlast++;        if (bdp->cbd_sc & BD_SC_WRAP)                hp->txlast = 0;        /* collect stats */        if ((bdp->cbd_sc & (BD_USB_NAK|BD_USB_STAL|BD_USB_TO|BD_USB_UN)))                hp->stats.tx_err++;        if (bdp->cbd_sc & BD_USB_NAK)                hp->stats.tx_nak++;        if (bdp->cbd_sc & BD_USB_STAL)                hp->stats.tx_stal++;        if (bdp->cbd_sc & BD_USB_TO)                hp->stats.tx_to++;        if (bdp->cbd_sc & BD_USB_UN)                hp->stats.tx_un++;        hp->txfree++;        /* I turned this off so I could see what had been sent */#if 1        bdp->cbd_sc &= BD_SC_WRAP;        bdp->cbd_datlen = 0;        bdp->cbd_bufaddr = 0;#endif}static inline intfree_bds(void){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        return hp->txfree;}/* move a queue element (pending transaction) to it's next state */static voidadvance_qe_state(struct m8xxhci_qe *qe){        struct urb *urb = qe->urb;        qe->retries = 0;        switch (qe->qstate) {        case QS_SETUP:                qe->qstate = QS_SETUP2;                if (usb_pipeslow(qe->pipe)) {                        pace_qe(qe);                        return;                }                break;        case QS_SETUP2:                if (qe->data_len > 0) {                        /* give the slow device time to setup after SETUP */                        if (usb_pipeslow(qe->pipe)) {                                pace_qe(qe);                                return;                        }                        break;                }                qe->qstate = QS_SETUP3;                if (usb_pipeslow(qe->pipe)) {                        pace_qe(qe);                        return;                }                break;        case QS_ISO:                /* don't advance for IN's, we do that in rx code */                if (usb_pipein(urb->pipe)) {                        log_event(3, "ISO; recv frame done", (int)qe);                        if (qe->iso_ptr < urb->number_of_packets) {                                pace_qe(qe);                                break;                        }                        /* iso IN xmit completes *after* the rx */                        complete_iso_rx(qe);                        break;                }                log_event(3, "ISO; xmit frame done", (int)qe);                urb->iso_frame_desc[qe->iso_ptr].status = 0;                urb->iso_frame_desc[qe->iso_ptr].actual_length = qe->send_len;                qe->send_len = 0;                qe->iso_ptr++;                log_event(3, "ISO; number_of_packets", urb->number_of_packets);                log_event(3, "ISO; iso_ptr", qe->iso_ptr);                if (qe->iso_ptr == urb->number_of_packets) {                        log_event(3, "ISO; all done", (int)qe);                        goto finish_qe;                }                qe->data_len = urb->iso_frame_desc[qe->iso_ptr].length;                qe->retries = 0;                qe->busys = 0;		/* keep sending IN's until we get a nak; that will pace it */                pace_qe(qe);                break;        case QS_BULK:                if (qe->data_len > 0)                        break;                if (0) printk("BULK done; send_len %d, recv_len %d\n",                              qe->send_len, qe->recv_len);                usb_settoggle(qe->dev,                              usb_pipeendpoint(qe->pipe),                              usb_pipeout(qe->pipe),                              qe->whichdata);                goto finish_qe;        case QS_INTR:                if (0) printk("INTR done; send_len %d, recv_len %d\n",                              qe->send_len, qe->recv_len);                usb_settoggle(qe->dev,                              usb_pipeendpoint(qe->pipe),                              usb_pipeout(qe->pipe),                              qe->whichdata);                /* fall through */        case QS_SETUP3:        finish_qe:                qe->qstate = 0;                make_inactive_qe_idle_endpoint(qe);                complete_qe(qe, USB_ST_NOERROR);                if (qe->reschedule) {                        qe->reschedule = 0;                        reschedule_qe(qe);                }                break;        }}/* advance h/w tx pointer to match s/w tx ptr */static voidadvance_hw_tx_ptr(void){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        volatile epb_t *epb = hp->epbptr[0];        ushort new_tbptr;        /* advance tx ring ptr to the right spot */        new_tbptr = epb->epb_tbase + (hp->txlast * sizeof(cbd_t));        if (epb->epb_tbptr != new_tbptr) {                epb->epb_tbptr = new_tbptr;        }}/* if active, continue sending else pick next thing to do */static voidcontinue_xmit(void){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        struct m8xxhci_qe *qe;        /* if more frames are needed for current qe, or retry, send them now */        if ((qe = hp->active_qe)) {                switch (send_qe(qe)) {                case -1:                        abort_qe(qe, -1);                        break;                case 1:                        /* we're sending... */                        return;                case 2:                        /* no time in frame */                        pace_qe(qe);                        break;                }        }        /* nothing on the active_qe... */        pick_next_thing_to_send();}/* run through completed tx bd's, matching them up with qe's */static voidprocess_done_txbds(void){        struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;        struct m8xxhci_qe *qe;        cbd_t *bdp;        int i, retry, nak, alldone, count, status, dbg = 0;        log_event(3, "process_done_txbds; active_qe", (int)hp->active_qe);        if (dbg) printk("process_done_txbds() txlast %d, txnext %d\n",                      hp->txlast, hp->txnext);        if (dbg) dump_tx_bds("tx bds:");        while (hp->txlast != hp->txnext) {                bdp = hp->tbase + hp->txlast;                if (dbg) printk("txlast %d, txnext %d, sc %04x\n",                                hp->txlast, hp->txnext, bdp->cbd_sc);                if ((bdp->cbd_sc & BD_SC_READY))                        break;                /* find the qe */                qe = hp->tx_bd_qe[ hp->txlast ];                if (dbg) printk("txlast %d, qe %p\n", hp->txlast, qe);                /*                 * if it's a SETUP, follow all the tx bd's                 * if it's an IN, just one tx bd                 * if it's an OUT, one tx bd + 'n' more for data                 */                if (!qe) {                        advance_tx_bd();                        continue;                }                alldone = 1;                retry = 0;                nak = 0;                count = 0;                /* clean up the bd's for this qe */                for (i = 0; i < TX_RING_SIZE; i++) {                        if (qe != hp->tx_bd_qe[ hp->txlast ])                                break;                        if (dbg) printk("found tx bd, sc 0x%x\n", bdp->cbd_sc);                        count++;                        status = bdp->cbd_sc;                        log_event(3, "index/sc",                                  (hp->txlast << 16) | status);                        /* note errors */                        retry |= status & (BD_USB_TO | BD_USB_UN);                        nak |= status & (BD_USB_NAK | BD_USB_STAL);                        /* if not done and no errors, keep waiting */                        if ((status & BD_SC_READY)) {                                alldone = 0;                                if (retry == 0 && nak == 0) {                                        log_event(3, "qe not done ok", (int)qe);                                        return;                                }                                log_event(3, "qe not done err", (int)qe);                        }                        /* if data out & ok, advance send */                        if ((status & (BD_USB_DATA0|BD_USB_DATA1)) &&                            (qe->qstate == QS_SETUP2 ||                             qe->qstate == QS_BULK ||                             qe->qstate == QS_ISO) &&                            nak == 0 && retry == 0)                        {                                qe->data_len -= bdp->cbd_datlen;                                qe->send_len += bdp->cbd_datlen;                        }                        advance_tx_bd();                        bdp = hp->tbase + hp->txlast;                }                log_event(3, "bds scanned ", count);                if (dbg) printk("retry 0x%x\n", retry);                if (nak & BD_USB_NAK)                        log_event(3, "nak", nak);                if (nak & BD_USB_STAL)                        log_event(3, "stall", nak);#if 1                /* if we get a timeout on a slow interrupt transactions,                   pretend it's a nak so we delay and retry later */                if (retry &&                    usb_pipeslow(qe->pipe) &&                    qe->qtype == Q_INTR)                {                        retry = 0;                        nak = BD_USB_NAK;                }#endif                /* if error, retry transaction */                if (retry) {                        log_event(3, "retry qe", (int)qe);                        if (dbg) printk("qe %p, retry #%d, state %d\n",                                        qe, qe->retries, qe->qstate);                        hp->stats.retransmit++;                        if (++(qe->retries) > MAX_QE_RETRIES) {                                abort_qe(qe, USB_ST_NORESPONSE);                        } else {                                /* always retry in the next frame... */                                nak_qe(qe);                        }                } else {                        /* if short, we tried to read to much and we're done */                        /* if stalled and short, spec says no status phase */                        if (qe->shortread) {                                if ((nak & BD_USB_STAL)) {					/* don't advance if protocol stall */					/* (i.e. control pipe) */                                        if (qe->qstate == QS_SETUP2					    && qe->qtype != Q_CTRL)                                                qe->qstate = QS_SETUP3;                                }                                /* finish up on short only or short+nak */                                qe->data_len = 0;                                nak = 0;                                alldone = 1;                        }                        /* if nak, resend IN's from where we left off */                

⌨️ 快捷键说明

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