📄 m8xxhci.c
字号:
#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 + -