/*---------------------------------------------------------------------------* * isic_attach_common - common attach routine for all busses *---------------------------------------------------------------------------*/ int isic_attach_common(device_t dev) { char *drvid = NULL; int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; sc->sc_unit = unit; sc->sc_isac_version = 0; sc->sc_hscx_version = 0; if(sc->sc_ipac) { sc->sc_ipac_version = IPAC_READ(IPAC_ID); switch(sc->sc_ipac_version) { case IPAC_V11: case IPAC_V12: break; default: printf("isic%d: Error, IPAC version %d unknown!\n", unit, sc->sc_ipac_version); return(0); break; } } else { sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; switch(sc->sc_isac_version) { case ISAC_VA: case ISAC_VB1: case ISAC_VB2: case ISAC_VB3: break; default: printf("isic%d: Error, ISAC version %d unknown!\n", unit, sc->sc_isac_version); return ENXIO; break; } sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; switch(sc->sc_hscx_version) { case HSCX_VA1: case HSCX_VA2: case HSCX_VA3: case HSCX_V21: break; default: printf("isic%d: Error, HSCX version %d unknown!\n", unit, sc->sc_hscx_version); return ENXIO; break; } } isic_isac_init(sc); /* ISAC setup */ /* HSCX setup */ isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); isic_init_linktab(sc); /* setup linktab */ sc->sc_trace = TRACE_OFF; /* set trace level */ sc->sc_state = ISAC_IDLE; /* set state */ sc->sc_ibuf = NULL; /* input buffering */ sc->sc_ib = NULL; sc->sc_ilen = 0; sc->sc_obuf = NULL; /* output buffering */ sc->sc_op = NULL; sc->sc_ol = 0; sc->sc_freeflag = 0; sc->sc_obuf2 = NULL; /* second output buffer */ sc->sc_freeflag2 = 0; /* timer setup */ callout_handle_init(&sc->sc_T3_callout); callout_handle_init(&sc->sc_T4_callout); /* init higher protocol layers */ i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_ATTACH, sc->sc_cardtyp, &isic_l1mux_func); /* announce manufacturer and card type for ISA cards */ switch(sc->sc_cardtyp) { case CARD_TYPEP_8: drvid = "Teles S0/8 (or compatible)"; break; case CARD_TYPEP_16: drvid = "Teles S0/16 (or compatible)"; break; case CARD_TYPEP_16_3: drvid = "Teles S0/16.3"; break; case CARD_TYPEP_AVMA1: drvid = "AVM A1 or Fritz!Card Classic"; break; case CARD_TYPEP_PCFRITZ: drvid = "AVM Fritz!Card PCMCIA"; break; case CARD_TYPEP_USRTA: drvid = "USRobotics Sportster ISDN TA intern"; break; case CARD_TYPEP_ITKIX1: drvid = "ITK ix1 micro"; break; case CARD_TYPEP_PCC16: drvid = "ELSA MicroLink ISDN/PCC-16"; break; default: drvid = NULL; /* pnp/pci cards announce themselves */ break; } if(drvid) printf("isic%d: %s\n", unit, drvid); if(bootverbose) { /* announce chip versions */ if(sc->sc_ipac) { if(sc->sc_ipac_version == IPAC_V11) printf("isic%d: IPAC PSB2115 Version 1.1\n", unit); else printf("isic%d: IPAC PSB2115 Version 1.2\n", unit); } else { printf("isic%d: ISAC %s (IOM-%c)\n", unit, ISACversion[sc->sc_isac_version], sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); printf("isic%d: HSCX %s\n", unit, HSCXversion[sc->sc_hscx_version]); } } return 0; }
/*---------------------------------------------------------------------------* * start transmission on a b channel *---------------------------------------------------------------------------*/ static void isic_bchannel_start(int unit, int h_chan) { struct l1_softc *sc = &l1_sc[unit]; l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int next_len; int len; int activity = -1; int cmd = 0; crit_enter(); if(chan->state & HSCX_TX_ACTIVE) /* already running ? */ { crit_exit(); return; /* yes, leave */ } /* get next mbuf from queue */ IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head); if(chan->out_mbuf_head == NULL) /* queue empty ? */ { crit_exit(); return; /* yes, exit */ } /* init current mbuf values */ chan->out_mbuf_cur = chan->out_mbuf_head; chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; /* activity indicator for timeout handling */ if(chan->bprot == BPROT_NONE) { if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) activity = ACT_TX; } else { activity = ACT_TX; } chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */ if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */ { i4b_trace_hdr_t hdr; hdr.unit = L0ISICUNIT(unit); hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_bcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); } len = 0; /* # of chars put into HSCX tx fifo this time */ /* * fill the HSCX tx fifo with data from the current mbuf. if * current mbuf holds less data than HSCX fifo length, try to * get the next mbuf from (a possible) mbuf chain. if there is * not enough data in a single mbuf or in a chain, then this * is the last mbuf and we tell the HSCX that it has to send * CRC and closing flag */ while((len < sc->sc_bfifolen) && chan->out_mbuf_cur) { /* * put as much data into the HSCX fifo as is * available from the current mbuf */ if((len + chan->out_mbuf_cur_len) >= sc->sc_bfifolen) next_len = sc->sc_bfifolen - len; else next_len = chan->out_mbuf_cur_len; #ifdef NOTDEF kprintf("b:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ", chan->out_mbuf_head, chan->out_mbuf_cur, chan->out_mbuf_cur_ptr, chan->out_mbuf_cur_len, len, next_len); #endif /* wait for tx fifo write enabled */ isic_hscx_waitxfw(sc, h_chan); /* write what we have from current mbuf to HSCX fifo */ HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, next_len); len += next_len; /* update # of bytes written */ chan->txcount += next_len; /* statistics */ chan->out_mbuf_cur_ptr += next_len; /* data ptr */ chan->out_mbuf_cur_len -= next_len; /* data len */ /* * in case the current mbuf (of a possible chain) data * has been put into the fifo, check if there is a next * mbuf in the chain. If there is one, get ptr to it * and update the data ptr and the length */ if((chan->out_mbuf_cur_len <= 0) && ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)) { chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; if(sc->sc_trace & TRACE_B_TX) { i4b_trace_hdr_t hdr; hdr.unit = L0ISICUNIT(unit); hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_bcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); } } } /* * if there is either still data in the current mbuf and/or * there is a successor on the chain available issue just * a XTF (transmit) command to HSCX. if ther is no more * data available from the current mbuf (-chain), issue * an XTF and an XME (message end) command which will then * send the CRC and the closing HDLC flag sequence */ if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0)) { /* * more data available, send current fifo out. * next xfer to HSCX tx fifo is done in the * HSCX interrupt routine. */ cmd |= HSCX_CMDR_XTF; } else { /* end of mbuf chain */ if(chan->bprot == BPROT_NONE) cmd |= HSCX_CMDR_XTF; else cmd |= HSCX_CMDR_XTF | HSCX_CMDR_XME; i4b_Bfreembuf(chan->out_mbuf_head); /* free mbuf chain */ chan->out_mbuf_head = NULL; chan->out_mbuf_cur = NULL; chan->out_mbuf_cur_ptr = NULL; chan->out_mbuf_cur_len = 0; } /* call timeout handling routine */ if(activity == ACT_RX || activity == ACT_TX) (*chan->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity); if(cmd) isic_hscx_cmd(sc, h_chan, cmd); crit_exit(); }
/*---------------------------------------------------------------------------* * * L2 -> L1: PH-DATA-REQUEST * ========================= * * parms: * unit physical interface unit number * m mbuf containing L2 frame to be sent out * freeflag MBUF_FREE: free mbuf here after having sent * it out * MBUF_DONTFREE: mbuf is freed by Layer 2 * returns: * ==0 fail, nothing sent out * !=0 ok, frame sent out * *---------------------------------------------------------------------------*/ int isic_ph_data_req(int unit, struct mbuf *m, int freeflag) { u_char cmd; int s; struct l1_softc *sc = &l1_sc[unit]; #ifdef NOTDEF NDBGL1(L1_PRIM, "unit %d, freeflag=%d", unit, freeflag); #endif if(m == NULL) /* failsafe */ return (0); s = SPLI4B(); if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ { NDBGL1(L1_I_ERR, "still in state F3!"); isic_ph_activate_req(unit); } if(sc->sc_state & ISAC_TX_ACTIVE) { if(sc->sc_obuf2 == NULL) { sc->sc_obuf2 = m; /* save mbuf ptr */ if(freeflag) sc->sc_freeflag2 = 1; /* IRQ must mfree */ else sc->sc_freeflag2 = 0; /* IRQ must not mfree */ NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", isic_printstate(sc)); if(sc->sc_trace & TRACE_D_TX) { i4b_trace_hdr_t hdr; hdr.unit = L0ISICUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } splx(s); return(1); } NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", isic_printstate(sc)); if(freeflag == MBUF_FREE) i4b_Dfreembuf(m); splx(s); return (0); } if(sc->sc_trace & TRACE_D_TX) { i4b_trace_hdr_t hdr; hdr.unit = L0ISICUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); sc->sc_freeflag = 0; /* IRQ must NOT mfree */ ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ { sc->sc_obuf = m; /* save mbuf ptr */ sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ if(freeflag) sc->sc_freeflag = 1; /* IRQ must mfree */ cmd = ISAC_CMDR_XTF; } else { sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; if(freeflag) i4b_Dfreembuf(m); cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; } ISAC_WRITE(I_CMDR, cmd); ISACCMDRWRDELAY(); splx(s); return(1); }