/* @(#)$Id: nic3009.c,v 1.15 1996/03/28 14:27:28 scrappy Exp $ ******************************************************************************* * II - Version 0.1 $Revision: 1.15 $ $State: Exp $ * * Copyright 1994 Dietmar Friede ******************************************************************************* * Bug reports, patches, comments, suggestions should be sent to: * * jkr@saarlink.de or jkrause@guug.de * ******************************************************************************* * $Log: nic3009.c,v $ * Revision 1.15 1996/03/28 14:27:28 scrappy * Switched from using devfs_add_sw() to using devfs_add_swf() * * Reviewed by: julian@freebsd.org * * Revision 1.14 1995/12/17 21:14:36 phk * Staticize. * * Revision 1.13 1995/12/08 23:19:30 phk * Julian forgot to make the *devsw structures static. * * Revision 1.12 1995/12/08 11:12:47 julian * Pass 3 of the great devsw changes * most devsw referenced functions are now static, as they are * in the same file as their devsw structure. I've also added DEVFS * support for nearly every device in the system, however * many of the devices have 'incorrect' names under DEVFS * because I couldn't quickly work out the correct naming conventions. * (but devfs won't be coming on line for a month or so anyhow so that doesn't * matter) * * If you "OWN" a device which would normally have an entry in /dev * then search for the devfs_add_devsw() entries and munge to make them right.. * check out similar devices to see what I might have done in them in you * can't see what's going on.. * for a laugh compare conf.c conf.h defore and after... :) * I have not doen DEVFS entries for any DISKSLICE devices yet as that will be * a much more complicated job.. (pass 5 :) * * pass 4 will be to make the devsw tables of type (cdevsw * ) * rather than (cdevsw) * seems to work here.. * complaints to the usual places.. :) * * Revision 1.11 1995/11/29 14:39:08 julian * If you're going to mechanically replicate something in 50 files * it's best to not have a (compiles cleanly) typo in it! (sigh) * * Revision 1.10 1995/11/29 10:47:05 julian * OK, that's it.. * That's EVERY SINGLE driver that has an entry in conf.c.. * my next trick will be to define cdevsw[] and bdevsw[] * as empty arrays and remove all those DAMNED defines as well.. * * Revision 1.9 1995/11/21 14:56:02 bde * Completed function declarations, added prototypes and removed redundant * declarations. * * Revision 1.8 1995/09/19 18:54:42 bde * Fix benign type mismatches in isa interrupt handlers. Many returned int * instead of void. * * Revision 1.7 1995/09/08 11:06:47 bde * Fix benign type mismatches in devsw functions. 82 out of 299 devsw * functions were wrong. * * Revision 1.6 1995/05/11 19:25:56 rgrimes * Fix -Wformat warnings from LINT kernel. * * Revision 1.5 1995/03/28 07:54:33 bde * Add and move declarations to fix all of the warnings from `gcc -Wimplicit' * (except in netccitt, netiso and netns) that I didn't notice when I fixed * "all" such warnings before. * * Revision 1.4 1995/02/16 08:06:21 jkh * Fix a few bogons introduced when config lost the 3 char limitation. * * Revision 1.3 1995/02/15 11:59:41 jkh * Fix a few more nits. Should compile better now! :_) * * Revision 1.2 1995/02/15 06:28:20 jkh * Fix up include paths, nuke some warnings. * * Revision 1.1 1995/02/14 15:00:14 jkh * An ISDN driver that supports the EDSS1 and the 1TR6 ISDN interfaces. * EDSS1 is the "Euro-ISDN", 1TR6 is the soon obsolete german ISDN Interface. * Obtained from: Dietmar Friede and * Juergen Krause * * This is only one part - the rest to follow in a couple of hours. * This part is a benign import, since it doesn't affect anything else. * * ******************************************************************************/ /* * Copyright (c) 1994 Dietmar Friede (dietmar@friede.de) All rights reserved. * FSF/FSAG GNU Copyright applies * * A low level driver for the NICCY-3009 ISDN Card. * */ #include "nnic.h" #if NNNIC > 0 #include #include #include #include #include #include #ifdef DEVFS #include #endif /*DEVFS*/ #include #include #include #include #define OPEN 1 #define LOAD_HEAD 3 #define LOAD_DATA 5 #define LOAD_ENTITY 8 #define IS_DIAL(p) (((p)&0x20)==0) #define IS_LISTEN(p) ((p)&0x20) #define CHAN(pl) (((pl)&7)-1) #define C_CHAN(x) ((x)&1) #define APPL(pl) ((((pl)>>6)&0x7f)-1) #define CARD(pl) (((pl)>>13)&7) #define MK_APPL(pl) (((pl)+1)<<6) #define min(a,b) ((a)<(b)?(a):(b)) extern isdn_appl_t isdn_appl[]; extern u_short isdn_state; extern isdn_ctrl_t isdn_ctrl[]; extern int ispy_applnr; extern int Isdn_Appl, Isdn_Ctrl, Isdn_Typ; static old_spy= 0; static int nnicattach __P((struct isa_device *is)); static int nnicprobe __P((struct isa_device *is)); static int nnic_accept __P((int cn, int an, int rea)); static int nnic_connect __P((int cn, int ap, int b_channel, int inf_mask, int out_serv, int out_serv_add, int src_subadr, unsigned ad_len, char *dest_addr, int spv)); static int nnic_disconnect __P((int cn, int rea)); static int nnic_listen __P((int cn, int ap, int inf_mask, int subadr_mask, int si_mask, int spv)); static int nnic_output __P((int cn)); static int nnic_state __P((int cn)); static d_open_t nnicopen; static d_close_t nnicclose; static d_ioctl_t nnicioctl; #define CDEV_MAJOR 60 static struct cdevsw nnic_cdevsw = { nnicopen, nnicclose, noread, nowrite, /*60*/ nnicioctl, nostop, nullreset, nodevtotty,/* nnic */ seltrue, nommap, NULL, "nnic", NULL, -1 }; static short bsintr; struct isa_driver nnicdriver = {nnicprobe, nnicattach, "nnic"}; typedef enum { DISCON, ISDISCON, DIAL, CALLED, CONNECT, IDLE, ACTIVE } io_state; typedef struct { char ctrl; u_char msg_nr; u_char morenr; short plci; short ncci; short state; short i_len; char i_buf[2048]; char o_buf[2048]; u_short more; char *more_b; } chan_t; static struct nnic_softc { dpr_type *sc_dpr; /* card RAM virtual memory base */ u_short sc_vector; /* interrupt vector */ short sc_port; u_char sc_flags; u_char sc_unit; u_char sc_ctrl; u_char sc_type; short sc_stat; chan_t sc_chan[2]; #ifdef DEVFS void *devfs_token; #endif } nnic_sc[NNNIC]; static void badstate __P((mbx_type *mbx, int n, int mb, dpr_type *dpr)); static int con_b3_resp __P((int unit, int mb, u_short ncci, u_short pl, u_char reject)); static int discon_req __P((int w, int unit, int pl, int rea, int err)); static int con_resp __P((int unit, int pl, int rea)); static void dn_intr __P((unsigned unit, struct nnic_softc *sc)); static int en_q __P((int unit, int t, int st, int pl, int l, u_char *b)); static void make_intr __P((void *gen)); static void nnnicintr __P((void *gen)); static void nnic_reset __P((struct nnic_softc *sc, int reset)); static int reset_plci __P((int w, chan_t *chan, int p)); static int sel_b2_prot_req __P((int unit, int c, int pl, dlpd_t *dlpd)); static int sel_b3_prot_req __P((int unit, int mb, u_short pl, ncpd_t *ncpd)); static void up_intr __P((unsigned unit, struct nnic_softc *sc)); static int nnicprobe(struct isa_device * is) { register struct nnic_softc *sc = &nnic_sc[is->id_unit & 127]; dpr_type *dpr; u_char *w; int i; sc->sc_vector = is->id_irq; sc->sc_port = is->id_iobase; sc->sc_unit = is->id_unit; w= (u_char *) dpr = sc->sc_dpr = (dpr_type *) is->id_maddr; i= ffs(sc->sc_vector)-1; if(i == 9) i= 1; outb(sc->sc_port, 0); outb(sc->sc_port+1, i); outb(sc->sc_port, ((unsigned) dpr >> 12) & 0xff); /* There should be memory, so lets test that */ for (i=0;iid_maddr); outb(sc->sc_port, 0); return(0); } bzero(w,DPR_LEN-4); is->id_msize = DPR_LEN; return (2); } static void nnic_reset(struct nnic_softc *sc, int reset) { u_char o; o= ffs(sc->sc_vector)-1; if(reset == 0) o|= 0x80; outb(sc->sc_port+1,o); } /* * nnicattach() Install device */ static int nnicattach(struct isa_device * is) { struct nnic_softc *sc; int cn; isdn_ctrl_t *ctrl0, *ctrl1; sc = &nnic_sc[is->id_unit]; sc->sc_ctrl = -1; if ((cn = isdn_ctrl_attach(2)) == -1) { return (0); } sc->sc_ctrl = cn; sc->sc_chan[0].plci = sc->sc_chan[1].plci = -1; ctrl0 = &isdn_ctrl[cn]; ctrl1 = &isdn_ctrl[cn + 1]; sc->sc_chan[0].ctrl = ctrl0->ctrl = cn; sc->sc_chan[1].ctrl = ctrl1->ctrl = cn + 1; ctrl0->o_buf = sc->sc_chan[0].o_buf; ctrl1->o_buf = sc->sc_chan[1].o_buf; ctrl0->listen = ctrl1->listen = nnic_listen; ctrl0->disconnect = ctrl1->disconnect = nnic_disconnect; ctrl0->accept = ctrl1->accept = nnic_accept; ctrl0->connect = ctrl1->connect = nnic_connect; ctrl0->output = ctrl1->output = nnic_output; ctrl0->state = ctrl1->state = nnic_state; ctrl0->unit = ctrl1->unit = is->id_unit; ctrl0->appl = ctrl1->appl = -1; ctrl0->o_len = ctrl1->o_len = -1; sc->sc_flags= LOAD_ENTITY; #ifdef DEVFS sc->devfs_token = devfs_add_devswf(&nnic_cdevsw, is->id_unit, DV_CHR, 0, 0, 0600, "/isdn/nnic%d", is->id_unit); #endif return (1); } #define con_b3_req(unit,mb,pl) en_q(unit,mb|BD_CONN_B3_REQ,0,pl,0,NULL) #define con_act_resp(unit,pl) en_q(unit,DD_CONN_ACT_RSP,0, pl,0,NULL) #define discon_resp(sc,pl) en_q(unit,DD_DISC_RSP,0, pl,0,NULL) #define inf_resp(unit,pl) en_q(unit,DD_INFO_RSP,0, pl,0,NULL) #define listen_b3_req(unit,mb,pl) en_q(unit,mb|BD_LIST_B3_REQ,0,pl,0,NULL) /* If the Niccy card wants it: Interupt it. */ static void make_intr(void *gen) { struct nnic_softc * sc = (struct nnic_softc *)gen; dpr_type *dpr = sc->sc_dpr; dpr->watchdog_cnt = 0xFF; if (dpr->int_flg_nic) dpr->signal_pc_to_niccy++; } static int en_q(int unit, int t, int st, int pl, int l, u_char *b) { struct nnic_softc * sc= &nnic_sc[unit]; dpr_type *dpr = sc->sc_dpr; mbx_type *mbx = &dpr->dn_mbx; /* if (dpr->card_state & ~4) return (ENODEV); */ if (mbx->msg_flag) return (EBUSY); bzero(&mbx->type, 18); mbx->type = t; mbx->subtype = st; mbx->plci = pl; if (l) { mbx->data_len = l; bcopy(b, mbx->data, l); } mbx->msg_flag = 1; make_intr(sc); return (0); } static void badstate(mbx_type * mbx, int n, int mb, dpr_type *dpr) { printf("Niccy: not implemented %x len %d at %d.", mbx->type,mbx->data_len,n); if(mbx->data_len) { int i; for(i=0; idata_len; i++) printf(" %x",mbx->data[i]); } printf("\n"); } static int nnic_state(int cn) { isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; struct nnic_softc *sc = &nnic_sc[ctrl->unit]; chan_t *chan0 = &sc->sc_chan[0]; chan_t *chan1 = &sc->sc_chan[1]; dpr_type *dpr = sc->sc_dpr; if(sc->sc_flags == LOAD_ENTITY) return(ENODEV); if (dpr->card_state & ~4 ) return (ENODEV); if (dpr->card_state & 4 ) return (EAGAIN); if(chan0->state && chan1->state) return(EBUSY); return(0); } static int nnic_output(int cn) { isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; struct nnic_softc *sc = &nnic_sc[ctrl->unit]; chan_t *chan = &sc->sc_chan[C_CHAN(cn)]; dpr_type *dpr = sc->sc_dpr; mbx_type *mbx = &dpr->dn_mbx; int l; int len= ctrl->o_len; if (dpr->card_state /* & ~4 */) return (ENODEV); if (bsintr || (chan->ncci == -1) || mbx->msg_flag || (chan->state != IDLE)) return (EBUSY); chan->state = ACTIVE; bzero(&mbx->type, 20); mbx->type = BD_DATA_B3_REQ; if (C_CHAN(cn)) mbx->type |= 0x40; *(u_short *) mbx->data = chan->ncci; mbx->data[4] = chan->msg_nr; l = min(DATAFIELD_LEN-5, len); mbx->data_len = l+5; bcopy(ctrl->o_buf, &mbx->data[5], l); if (l < len) { chan->more = len - l; chan->more_b = ctrl->o_buf + l; mbx->more_data = 1; bsintr = C_CHAN(cn)+1; } else { chan->more = 0; ctrl->o_len = -1; bsintr= 0; ++chan->msg_nr; } mbx->msg_flag = 1; make_intr(sc); ctrl->lastact = time.tv_sec; return (0); } static int con_resp(int unit, int pl, int rea) { return(en_q(unit, DD_CONN_RSP, 0, pl, 1, (u_char *) & rea)); } static int reset_plci(int w, chan_t * chan, int p) { isdn_ctrl_t *ctrl; if (p == -1) return (-1); if(chan == NULL) return(p); ctrl = &isdn_ctrl[chan->ctrl]; if (chan->plci == p) { if (ISBUSY(ctrl->appl)) { isdn_disconn_ind(ctrl->appl); isdn_appl[ctrl->appl].ctrl = -1; isdn_appl[ctrl->appl].state = 0; } ctrl->appl = -1; ctrl->o_len = -1; chan->plci = -1; chan->ncci = -1; chan->state = DISCON; chan->i_len = 0; chan->more = 0; } return (p); } static int sel_b2_prot_req(int unit, int c, int pl, dlpd_t * dlpd) { return(en_q(unit, (c ? 0x40 : 0)| BD_SEL_PROT_REQ, 2, pl, sizeof(dlpd_t), (u_char *) dlpd)); } static int sel_b3_prot_req(int unit, int mb, u_short pl, ncpd_t * ncpd) { return(en_q(unit, mb | BD_SEL_PROT_REQ, 3, pl, sizeof(ncpd_t), (u_char *) ncpd)); } static int discon_req(int w, int unit , int pl, int rea, int err) { if((pl == 0) || (pl == -1)) return(0); return(en_q(unit, DD_DISC_REQ,0, pl, 1, (u_char *) &rea)); } static int con_b3_resp(int unit, int mb, u_short ncci, u_short pl, u_char reject) { u_char buf[32]; int l = 4; bzero(buf, 32); *(u_short *) buf = ncci; buf[2] = reject; buf[3] = 0; /* ncpi ??? */ l += 15; return(en_q(unit, mb | BD_CONN_B3_RSP,0, pl, l, buf)); } static int nnic_connect(int cn, int ap, int b_channel, int inf_mask, int out_serv ,int out_serv_add, int src_subadr, unsigned ad_len ,char *dest_addr, int spv) { char buf[128]; if (ad_len > 118) return (-1); buf[0] = spv ? 0x53 : 0; buf[1] = b_channel; if (spv) inf_mask |= 0x40000000; *(u_long *) & buf[2] = inf_mask; buf[6] = out_serv; buf[7] = out_serv_add; buf[8] = src_subadr; buf[9] = ad_len; bcopy(dest_addr, &buf[10], ad_len); return (en_q(isdn_ctrl[cn].unit, DD_CONN_REQ, 0, MK_APPL(ap), ad_len + 10, buf)); } static int nnic_listen(int cn, int ap, int inf_mask, int subadr_mask, int si_mask, int spv) { u_short sbuf[4]; if (spv) inf_mask |= 0x40000000; *(u_long *) sbuf = inf_mask; sbuf[2] = subadr_mask; sbuf[3] = si_mask; return (en_q(isdn_ctrl[cn].unit, DD_LISTEN_REQ, 0, MK_APPL(ap), 8, (u_char *) sbuf)); } static int nnic_disconnect(int cn, int rea) { isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; chan_t *chan = &nnic_sc[ctrl->unit].sc_chan[C_CHAN(cn)]; int p, err; u_char buf[16]; if(chan->ncci != -1) { bzero(buf,16); *(u_short *) buf = chan->ncci; err= en_q(ctrl->unit, (C_CHAN(cn)?0x40:0)|BD_DISC_B3_REQ, 0 , chan->plci, 3+sizeof(ncpi_t), buf); if((err==0) && (ctrl->o_len == 0)) ctrl->o_len= -1; return(err); } p = chan->plci; if ((p == 0) || (p == -1)) return (ENODEV); err= en_q(ctrl->unit, DD_DISC_REQ, 0, p, 1, (u_char *) &rea); if((err==0) && (ctrl->o_len == 0)) ctrl->o_len= -1; return(err); } static int nnic_accept(int cn, int an, int rea) { isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; struct nnic_softc *sc = &nnic_sc[ctrl->unit]; chan_t *chan = &sc->sc_chan[C_CHAN(cn)]; isdn_appl_t *appl = &isdn_appl[an]; if(ISFREE(ctrl->appl)) return(ENODEV); if (rea) { ctrl->appl= -1; return(discon_req(1, ctrl->unit, chan->plci, rea, 0)); } ctrl->appl= an; ctrl->lastact = time.tv_sec; appl->ctrl= cn; appl->state= 4; return(sel_b2_prot_req(ctrl->unit, C_CHAN(cn), chan->plci, &appl->dlpd)); } static int nnicopen(dev_t dev, int flags, int fmt, struct proc *p) { struct nnic_softc *sc; u_char unit; int x; unit = minor(dev); /* minor number out of limits ? */ if (unit >= NNNIC) return (ENXIO); sc = &nnic_sc[unit]; x= splhigh(); /* Card busy ? */ /* if (sc->sc_flags & 7) { splx(x); return (EBUSY); } */ sc->sc_flags |= OPEN; splx(x); return (0); } static int nnicclose(dev_t dev, int flags, int fmt, struct proc *p) { struct nnic_softc *sc = &nnic_sc[minor(dev)]; sc->sc_flags &= ~7; return (0); } static int nnicioctl(dev_t dev, int cmd, caddr_t data, int flags, struct proc *pr) { int error; int i, x; struct nnic_softc *sc = &nnic_sc[minor(dev)]; dpr_type *dpr = sc->sc_dpr; mbx_type *mbx= &dpr->dn_mbx; u_char *p= (u_char *)dpr; struct head *head = (struct head *) data; error = 0; switch (cmd) { case NICCY_DEBUG: data[0]= 0x39; bcopy(p, &data[1], 2044); break; case NICCY_LOAD: switch(head->status) { case 0: /* Loading initial boot code */ x = splhigh(); nnic_reset(sc,1); if(error = copyin(head->data+0x16,p, head->d_len-0x16)) { splx(x); return (error); } nnic_reset(sc,0); i= hz; while (p[7] && i--) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_0", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } nnic_reset(sc,1); splx(x); if(p[7]) return(ENODEV); return(0); case 1: /* Loading boot code */ x = splhigh(); if(error = copyin(head->data+0x64,p, head->d_len-0x64)) { splx(x); return (error); } nnic_reset(sc,0); i= 5*hz; while ((dpr->mainloop_cnt != 0x1147) && i--) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_1", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } if(dpr->mainloop_cnt != 0x1147) { splx(x); return(ENODEV); } i= 1*hz; while ((dpr->up_mbx.type != 1) && i--) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_2", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } if(dpr->up_mbx.type != 1) { splx(x); return(ENODEV); } bzero(&mbx->type, 16); dpr->up_mbx.msg_flag= 0; mbx->type= 0x21; mbx->msg_flag= 1; i= 1*hz; while (mbx->msg_flag && i--) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_3", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } if(mbx->msg_flag) { splx(x); return(ENODEV); } head->status= 0; splx(x); return(0); default: x = splhigh(); while (mbx->msg_flag) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_1h", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } bzero(&mbx->type, 16); mbx->type = MD_DNL_MOD_REQ; mbx->subtype = head->typ; sc->sc_type = head->typ; mbx->data_len = 12; bcopy(head->nam, mbx->data, 8); *(u_long *) (mbx->data + 8) = head->len; mbx->msg_flag = 1; make_intr(sc); i= 1*hz; while ((dpr->up_mbx.msg_flag == 0) && i--) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_2", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } if((dpr->up_mbx.type != MU_DNL_MOD_CNF) || dpr->up_mbx.data[0]) { dpr->up_mbx.msg_flag= 0; make_intr(sc); splx(x); return(ENODEV); } dpr->up_mbx.msg_flag= 0; make_intr(sc); { int len, l, off; len= head->d_len; off= 0; l= 0x64; while(len > 0) { while (mbx->msg_flag) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_4load", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } mbx->type = MD_DNL_MOD_DATA; len-= l; mbx->more_data = len > 0; mbx->data_len = l; if(error= copyin(head->data+off, mbx->data, l)) { splx(x); return (error); } off+= l; l= min(len,512); mbx->msg_flag = 1; make_intr(sc); } } i= 3*hz; while ((dpr->up_mbx.msg_flag == 0) && i--) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_2", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } if(dpr->up_mbx.type == 0) { dpr->up_mbx.msg_flag= 0; make_intr(sc); i= 3*hz; while ((dpr->up_mbx.msg_flag == 0) && i--) { error = tsleep((caddr_t) sc, PZERO | PCATCH, "l9_3", 1); if (error != EWOULDBLOCK) { splx(x); return (error); } } } if(dpr->up_mbx.type != MU_DNL_MOD_IND) { dpr->up_mbx.msg_flag= 0; make_intr(sc); splx(x); return(ENODEV); } head->status = dpr->up_mbx.data[0]; mbx->data[0] = dpr->up_mbx.data[1]; mbx->type= 0x20|MU_DNL_MOD_IND; mbx->subtype = head->typ; mbx->data_len = 1; dpr->card_number = sc->sc_unit; dpr->up_mbx.msg_flag= 0; mbx->msg_flag= 1; make_intr(sc); splx(x); return (0); } splx(x); return(0); case NICCY_SET_CLOCK: x = splhigh(); dpr->int_flg_pc = 0xff; dpr->card_number = sc->sc_unit; if (mbx->msg_flag) { splx(x); return (EBUSY); } bzero(&mbx->type, 16); mbx->type = MD_SET_CLOCK_REQ; mbx->data_len = 14; bcopy(data, mbx->data, 14); mbx->msg_flag = 1; make_intr(sc); splx(x); return (0); case NICCY_SPY: x = splhigh(); if (mbx->msg_flag) { splx(x); return (EBUSY); } bzero(&mbx->type, 16); mbx->type = MD_MANUFACT_REQ; mbx->subtype = 18; mbx->data_len = 1; mbx->plci = MK_APPL(ispy_applnr); /* There are ilegal states. So I use them to toggle */ if((data[0] == 0) && (old_spy == 0)) data[0]= 255; else if(data[0] && old_spy ) data[0]= 0; old_spy= mbx->data[0]= data[0]; mbx->msg_flag = 1; make_intr(sc); splx(x); return (0); case NICCY_RESET: x = splhigh(); nnic_reset(sc,1); bzero((u_char*)dpr,DPR_LEN); sc->sc_flags= LOAD_ENTITY; splx(x); return (0); default: error = ENODEV; } return (error); } static void dn_intr(unsigned unit, struct nnic_softc * sc) { dpr_type *dpr = sc->sc_dpr; mbx_type *mbx= &dpr->dn_mbx; chan_t *chan; isdn_ctrl_t *ctrl; int c,l, len; c= bsintr-1; chan = &sc->sc_chan[c]; ctrl = &isdn_ctrl[chan->ctrl]; if ((chan->state == ACTIVE) && (chan->more)) { len= chan->more; bzero(&mbx->type, 20); mbx->type = BD_DATA_B3_REQ; if (c) mbx->type |= 0x40; *(u_short *) mbx->data = chan->ncci; mbx->data[4] = chan->msg_nr; l = min(DATAFIELD_LEN-5, len); mbx->data_len = l+5; bcopy(chan->more_b, &mbx->data[5], l); if (l < len) { chan->more = len - l; chan->more_b += l; mbx->more_data = 1; } else { chan->more = 0; ctrl->o_len = -1; bsintr= 0; ++chan->msg_nr; } mbx->msg_flag = 1; make_intr(sc); ctrl->lastact = time.tv_sec; return; } bsintr= 0; } static void up_intr(unsigned unit, struct nnic_softc * sc) { dpr_type *dpr = sc->sc_dpr; mbx_type *msg= &dpr->up_mbx; chan_t *chan; u_short n, mb, c, pl, err = 0; isdn_ctrl_t *ctrl; isdn_appl_t *appl; int error= 0; chan= NULL; ctrl= NULL; appl= NULL; mb= 0; pl = msg->plci; if(pl && (msg->type >= 0x40) && (msg->type < 0xfd) && (msg->type != 0x47)) { if ((c = CHAN(pl)) < 2) { chan = &sc->sc_chan[c]; ctrl = &isdn_ctrl[chan->ctrl]; } else { c = 0xffff; chan= NULL; ctrl= NULL; } if(ctrl && (ctrl->appl & 0xC0) == 0) appl= &isdn_appl[ctrl->appl]; else if( APPL(pl) < 0x30) appl = &isdn_appl[APPL(pl)]; else if( APPL(pl) < 0x40) appl= NULL; else goto fin; if(msg->type >= 0x80) { mb= msg->type & 0x40; msg->type &= 0xbf; } } switch (msg->type) { case 0x01: /* INIT IND */ if(dpr->dn_mbx.msg_flag) return; error= en_q(unit,msg->type|0x20,0,0,0,NULL); break; case 0x04: /* DNL MOD */ sc->sc_stat = msg->data[0]; if (sc->sc_flags ) sc->sc_flags = OPEN; break; case 0x06: /* DNL MOD IND */ if(dpr->dn_mbx.msg_flag) return; sc->sc_stat = msg->data[0]; if (sc->sc_flags) sc->sc_flags = OPEN; if(sc->sc_stat) break; error= en_q(unit,msg->type|0x20,sc->sc_type,0,1, &msg->data[1]); break; case 0x0e: /* SET CLOCK CONF */ dpr->card_number = unit; /* dpr->api_active = 1; dpr->watchdog_cnt = 0xFF; dpr->api_area[0] = 0; dpr->api_area[2] = 0; */ dpr->int_flg_pc = 0xFF; break; case 0x15: /* POLL IND */ if(dpr->dn_mbx.msg_flag) return; dpr->api_active = 1; dpr->watchdog_cnt = 0xFF; dpr->int_flg_pc = 0xFF; error= en_q(unit,msg->type|0x20,0,0,0,NULL); break; case 0x16: /* STATE IND */ if(dpr->dn_mbx.msg_flag) return; if(sc->sc_flags & LOAD_ENTITY) { if(sc->sc_flags & 7) sc->sc_flags = OPEN; else sc->sc_flags= 0; } error= en_q(unit,msg->type|0x20,0,0,0,NULL); break; case 0x17: /* STATE RESP */ break; case 0x1e: /* MANUFACT CONF */ if(msg->subtype == 18) break; badstate(msg,1,0,dpr); break; case 0x1f: /* MANUFACT IND */ if(msg->subtype == 19) { if(dpr->dn_mbx.msg_flag) return; isdn_input(ispy_applnr, msg->data_len, msg->data,0); error= en_q(unit,msg->type|0x20,msg->subtype,0,0,NULL); break; } badstate(msg,2,0,dpr); break; case 0x40: /* CONNECT CONF */ err = *(u_short *) msg->data; if (err || (appl == NULL) || (chan == NULL) || (ctrl == NULL)) { if(chan) reset_plci(3, chan, pl); if(appl) appl->state= 0; break; } if (ISBUSY(ctrl->appl)) { if(dpr->dn_mbx.msg_flag) return; error= discon_req(2, unit, pl, 0, 0); break; } chan->plci = pl; chan->msg_nr = 0; chan->ncci = -1; ctrl->lastact = time.tv_sec; ctrl->appl = APPL(pl); appl->ctrl = chan->ctrl; ctrl->islisten= 0; chan->state = DIAL; appl->state= 3; break; case 0x41: /* CONNECT IND */ if (ISBUSY(ctrl->appl)) { if(dpr->dn_mbx.msg_flag) return; error= discon_req(3, unit, pl, 0, 0); break; } chan->plci = pl; chan->msg_nr = 0; chan->ncci = -1; ctrl->lastact = time.tv_sec; ctrl->appl = 0x7f; ctrl->islisten= 1; chan->state = CALLED; msg->data[msg->data[3] + 4] = 0; isdn_accept_con_ind(APPL(pl), chan->ctrl, msg->data[0], msg->data[1] ,msg->data[2], msg->data[3], (char *) &msg->data[4]); break; case 0x42: /* CONNECT ACTIVE IND */ if(dpr->dn_mbx.msg_flag) return; error= con_act_resp(unit, pl); if (IS_LISTEN(pl)) { isdn_conn_ind(ctrl->appl,chan->ctrl,0); break; } isdn_conn_ind(APPL(pl),chan->ctrl,1); chan->state = CONNECT; ctrl->appl = APPL(pl); appl->ctrl = chan->ctrl; break; case 0x43: /* DISCONNECT CONF */ reset_plci(4, chan, pl); break; case 0x44: /* DISCONNECT IND */ if(dpr->dn_mbx.msg_flag) return; error= discon_resp(unit, reset_plci(5, chan, pl)); break; case 0x47: /* LISTEN CONF */ isdn_state = *(u_short *) msg->data; break; case 0x4a: /* INFO IND */ if(dpr->dn_mbx.msg_flag) return; isdn_info(APPL(pl),*(u_short *)msg->data, msg->data[2], msg->data+3); error= inf_resp(unit, pl); break; case 0x80: /* SELECT PROT CONF */ if(dpr->dn_mbx.msg_flag) return; err = *(u_short *) msg->data; if (err) { error= discon_req(4, unit, pl, 0, err); break; } switch (msg->subtype) { case 2:/* SELECT B2 PROTOCOL */ if(ISFREE(ctrl->appl)) break; error= sel_b3_prot_req(unit, mb, pl, &isdn_appl[ctrl->appl].ncpd); break; case 3:/* SELECT B3 PROTOCOL */ if (IS_DIAL(pl)) error= con_b3_req(unit, mb, pl); else error= listen_b3_req(unit, mb, pl); break; } break; case 0x81: /* LISTEN B3 CONF */ if(dpr->dn_mbx.msg_flag) return; err = *(u_short *) msg->data; if (err) { error= discon_req(5, unit, pl, 0, err); break; } error= con_resp(unit, pl, 0); break; case 0x82: /* CONNECT B3 CONF */ err = *(u_short *) (msg->data + 2); n = *(u_short *) msg->data; if (err) { if(dpr->dn_mbx.msg_flag) return; error= discon_req(6, unit, pl, 0, err); break; } if(ISFREE(ctrl->appl)) break; chan->ncci = n; chan->state = CONNECT; break; case 0x83: /* CONNECT B3 IND */ if(ISFREE(ctrl->appl)) break; if(dpr->dn_mbx.msg_flag) return; n = *(u_short *) msg->data; chan->ncci = n; chan->state = CONNECT; error= con_b3_resp(unit, mb, n, pl, 0); break; case 0x84: /* CONNECT B3 ACTIVE IND */ if(ISFREE(ctrl->appl)) break; if (chan->state < IDLE) { chan->state = IDLE; ctrl->o_len = 0; /* * XXX the chan->ctrl arg is very bogus. * Don't just use a cast to "fix" it. */ timeout(isdn_start_out, chan->ctrl, hz / 5); } break; case 0x85: /* DISCONNECT B3 CONF */ if(ISBUSY(ctrl->appl)) chan->state = ISDISCON; err = *(u_short *) (msg->data + 2); if (err) { if(dpr->dn_mbx.msg_flag) return; error= discon_req(7, unit, pl, 0, err); break; } break; case 0x86: /* DISCONNECT B3 IND */ if(dpr->dn_mbx.msg_flag) return; if(ISBUSY(ctrl->appl)) chan->state = ISDISCON; err = *(u_short *) (msg->data + 2); error= discon_req(8, unit, pl, 0, err); break; case 0x88: /* DATA B3 CONF */ if(ISFREE(ctrl->appl)) break; err = *(u_short *) (msg->data + 2); if (err) { ctrl->send_err++; isdn_appl[ctrl->appl].send_err++; } chan->state = IDLE; ctrl->o_len = 0; isdn_start_out(chan->ctrl); break; case 0x89: /* DATA B3 IND */ if(ISFREE(ctrl->appl)) break; if (msg->more_data) { if(chan->i_len) { if((chan->morenr != msg->data[4]) || ((chan->i_len + msg->data_len - 5) > 2048)) break; } else chan->morenr= msg->data[4]; bcopy(msg->data+5, &chan->i_buf[chan->i_len], msg->data_len-5); chan->i_len += msg->data_len -5; break; } /* msg->more_data == 0 */ if (chan->i_len) { int l; if(chan->morenr != msg->data[4]) break; if ((l = chan->i_len + msg->data_len - 5) <= 2048) { bcopy(msg->data+5, &chan->i_buf[chan->i_len], msg->data_len); if(isdn_input(ctrl->appl, l, chan->i_buf, ctrl->islisten)) ctrl->lastact = time.tv_sec; } chan->i_len = 0; break; } /* chan->i_len == 0 && msg->more_data == 0 */ if(isdn_input(ctrl->appl, msg->data_len-5, msg->data+5,ctrl->islisten)) ctrl->lastact = time.tv_sec; break; default: badstate(msg,3,mb,dpr); break; } fin: if(error) { printf("E?%x",error); return; } msg->msg_flag= 0; timeout(make_intr, (void *)sc,1); } static void nnnicintr(void *gen) { unsigned int unit = (int)gen; register struct nnic_softc *sc = &nnic_sc[unit]; dpr_type *dpr = sc->sc_dpr; if(dpr->up_mbx.msg_flag) up_intr(unit,sc); if (bsintr && (dpr->dn_mbx.msg_flag == 0)) dn_intr(unit,sc); } void nnicintr(int unit) { timeout(nnnicintr, (void *)unit,1); } static nnic_devsw_installed = 0; static void nnic_drvinit(void *unused) { dev_t dev; if( ! nnic_devsw_installed ) { dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev,&nnic_cdevsw, NULL); nnic_devsw_installed = 1; } } SYSINIT(nnicdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,nnic_drvinit,NULL) #endif /* NNNIC > 0 */