diff options
author | jkh <jkh@FreeBSD.org> | 1995-02-14 15:00:39 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1995-02-14 15:00:39 +0000 |
commit | 1ff34ff975e38dfd1087289b463b765f409104ad (patch) | |
tree | fde5c0029111a58a30ca5ffc6ca10322a59d1605 | |
parent | 01bd5245a2bcb750f43b611651b1b7cae5754109 (diff) | |
download | FreeBSD-src-1ff34ff975e38dfd1087289b463b765f409104ad.zip FreeBSD-src-1ff34ff975e38dfd1087289b463b765f409104ad.tar.gz |
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 <dfriede@drnhh.neuhaus.de> and
Juergen Krause <jkr@saarlink.de>
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.
-rw-r--r-- | sys/gnu/i386/isa/nic3008.c | 1142 | ||||
-rw-r--r-- | sys/gnu/i386/isa/nic3008.h | 114 | ||||
-rw-r--r-- | sys/gnu/i386/isa/nic3009.c | 1209 | ||||
-rw-r--r-- | sys/gnu/i386/isa/nic3009.h | 79 | ||||
-rw-r--r-- | sys/gnu/i386/isa/niccyreg.h | 158 | ||||
-rw-r--r-- | sys/gnu/isdn/if_ii.c | 245 | ||||
-rw-r--r-- | sys/gnu/isdn/iispy.c | 171 | ||||
-rw-r--r-- | sys/gnu/isdn/iitel.c | 234 | ||||
-rw-r--r-- | sys/gnu/isdn/iitty.c | 306 | ||||
-rw-r--r-- | sys/gnu/isdn/isdn.c | 626 | ||||
-rw-r--r-- | sys/gnu/isdn/isdn_ioctl.h | 136 | ||||
-rw-r--r-- | sys/gnu/scsi/nic5000.c | 1467 | ||||
-rw-r--r-- | sys/gnu/scsi/scsi_nic.h | 53 |
13 files changed, 5940 insertions, 0 deletions
diff --git a/sys/gnu/i386/isa/nic3008.c b/sys/gnu/i386/isa/nic3008.c new file mode 100644 index 0000000..a581408 --- /dev/null +++ b/sys/gnu/i386/isa/nic3008.c @@ -0,0 +1,1142 @@ +static char nic38_id[] = "@(#)$Id: nic3008.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: nic3008.c,v $ + * + ******************************************************************************/ + +/* + * Copyright (c) 1994 Dietmar Friede (dietmar@friede.de) All rights reserved. + * FSF/FSAG GNU Copyright applies + * + * A low level driver for the NICCY-3008 ISDN Card. + * + */ + +#include "nic.h" +#if NNIC > 0 + +#include "param.h" +#include "ioctl.h" +#include "kernel.h" +#include "systm.h" + +#include "i386/isa/isa_device.h" +#include "i386/isa/nic3008.h" +#include "i386/isa/niccyreg.h" +#include "isdn/isdn_ioctl.h" + +#define OPEN 1 +#define LOAD_HEAD 3 +#define LOAD_DATA 5 +#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 con_act_resp(sc,pl) en_q_d(sc,DD_CONN_ACT_RSP, pl ,0,NULL) +#define discon_resp(sc,pl) en_q_d(sc,DD_DISC_RSP, pl ,0,NULL) +#define inf_resp(sc,pl) en_q_d(sc,DD_INFO_RSP, pl ,0,NULL) +#define listen_b3_req(sc,mb,pl) en_q_b(sc,mb,BD_LIST_B3_REQ,pl,0,NULL) +#define con_b3_req(sc,mb,pl) en_q_b(sc,mb,BD_CONN_B3_REQ,pl,0,NULL) +#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; +extern int hz; + +static old_spy= 0; + +int nicprobe(), nicattach(); +int nic_connect(), nic_listen(), nic_disconnect(), nic_accept(); +int nic_output(); +extern isdn_start_out(); + +static void s_intr(), reset_req(), reset_card(); +static int cstrcmp(), discon_req(), reset_plci(), sel_b2_prot_req(); + +static short bsintr; + +struct isa_driver nicdriver = {nicprobe, nicattach, "nic"}; + +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; + +struct nic_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; + short sc_stat; + chan_t sc_chan[2]; +} nic_sc[NNIC]; + + +int +nicprobe(struct isa_device * is) +{ + register struct nic_softc *sc = &nic_sc[is->id_unit & 127]; + dpr_type *dpr; + + sc->sc_vector = is->id_irq; + sc->sc_port = is->id_iobase; + sc->sc_unit = is->id_unit; + dpr = sc->sc_dpr = (dpr_type *) is->id_maddr; + + if (cstrcmp(dpr->niccy_ver, "NICCY V ") == 0) + { + printf("NICCY NICCY-Card %d not found at %x\n" + ,is->id_unit, is->id_maddr); + return (0); + } + while (dpr->card_state & 1); /* self test running */ + + if (dpr->card_state & 0x8A) + { + printf("Check Niccy Card, error state %d \n", dpr->card_state); + return (0); + } + dpr->card_number = is->id_unit; + is->id_msize = 8192; + reset_card(sc); + return (8); +} + +/* + * nicattach() Install device + */ +int +nicattach(struct isa_device * is) +{ + struct nic_softc *sc; + dpr_type *dpr; + int cn; + isdn_ctrl_t *ctrl0, *ctrl1; + + sc = &nic_sc[is->id_unit]; + dpr = sc->sc_dpr; + 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 = nic_listen; + ctrl0->disconnect = ctrl1->disconnect = nic_disconnect; + ctrl0->accept = ctrl1->accept = nic_accept; + ctrl0->connect = ctrl1->connect = nic_connect; + ctrl0->output = ctrl1->output = nic_output; + ctrl0->unit = ctrl1->unit = is->id_unit; + ctrl0->appl = ctrl1->appl = -1; + ctrl0->o_len = ctrl1->o_len = -1; + + while (dpr->card_state & 1); /* self test running */ + dpr->card_number = is->id_unit; + dpr->int_flg_pc = 0xff; + reset_req(sc, MBX_MU, 4); + return (1); +} + +static int +cstrcmp(char *str1, char *str2) +{ + while (*str2 && (*str2 == *str1)) + { + str1++; + str2++; + } + if (!*str2) + return (1); + return (0); +} + +/* If the niccy card wants it: Interupt it. */ +static void +make_intr(int box, struct nic_softc * sc) +{ + dpr_type *dpr = sc->sc_dpr; + + dpr->watchdog_cnt = 0xFF; + if ((dpr->int_flg_nic & (1 << box)) == 0) + return; + if (dpr->ext_hw_config == 1) + { + u_char s; + s = inb(sc->sc_port + 4); + outb(sc->sc_port + 4, s & 0xfb); + outb(sc->sc_port + 4, s | 4); + outb(sc->sc_port + 4, s); + return; + } + outb(sc->sc_port + 2, 1); +} + +static void +reset_req(struct nic_softc * sc, unsigned box, int w) +{ + if(box >= 8) + return; + + (sc->sc_dpr)->msg_flg[box] = 0; + make_intr(box, sc); +} + +static int +en_q_d(struct nic_softc * sc, int t, int pl, int l, u_char * b) +{ + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[3]; + + if (dpr->card_state & ~4) + return (ENODEV); + if (dpr->msg_flg[3]) + return (EBUSY); + + bzero(mbx, 18); + mbx->type = t; + mbx->add_info = pl; + if (l) + { + mbx->data_len = l; + bcopy(b, mbx->data, l); + } + dpr->msg_flg[3] = 1; + make_intr(3, sc); + return (0); +} + +static int +en_q_b(struct nic_softc * sc, int mb, int t, int pl, int l, u_char * b) +{ + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[++mb]; + + if (mb == 7) + t |= 0x40; + + if (dpr->card_state) + return (ENODEV); + if (dpr->msg_flg[mb]) + return (EBUSY); + + bzero(mbx, 18); + mbx->type = t; + mbx->add_info = pl; + if (l) + { + mbx->data_len = l; + bcopy(b, mbx->data, l); + } + dpr->msg_flg[mb] = 1; + make_intr(mb, 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) + { + u_char *b = (u_char *) dpr; + int i; + + b += dpr->buf_ptr[mb]; + for(i=0; i<mbx->data_len; i++) printf(" %x",mbx->data[i]); + printf("."); + for(i=0; i<mbx->data_len; i++) printf(" %x",b[i]); + } + printf("\n"); +} + +int +nic_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 > 22) + 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_d(&nic_sc[isdn_ctrl[cn].unit], DD_CONN_REQ, MK_APPL(ap), ad_len + 10, buf)); +} + +int +nic_listen(int cn, int ap, int inf_mask, int subadr_mask, int si_mask) +{ + u_short sbuf[4]; + + *(u_long *) sbuf = inf_mask; + sbuf[2] = subadr_mask; + sbuf[3] = si_mask; + return (en_q_d(&nic_sc[isdn_ctrl[cn].unit], DD_LISTEN_REQ, MK_APPL(ap), 8, (u_char *) sbuf)); +} + +int +nic_disconnect(int cn, int rea) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + struct nic_softc *sc = &nic_sc[ctrl->unit]; + chan_t *chan = &sc->sc_chan[C_CHAN(cn)]; + u_char buf[16]; + int l = 3; + int p; + int err; + + if(chan->ncci != -1) + { + bzero(buf,16); + *(u_short *) buf = chan->ncci; + l += sizeof(ncpi_t); + err= en_q_b(sc, C_CHAN(cn)?6:4, BD_DISC_B3_REQ, chan->plci, l, buf); + if(err==0) + { + chan->more= 0; + ctrl->o_len= -1; + } + return(err); + } + + p = chan->plci; + if((p == 0) || (p == -1)) + return (ENODEV); + + err= en_q_d(sc, DD_DISC_REQ, p, 1, (u_char *) & rea); + if(err==0) + { + chan->more= 0; + ctrl->o_len= -1; + } + return(err); +} + +int +nic_accept(int cn, int an, int rea) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + struct nic_softc *sc = &nic_sc[ctrl->unit]; + chan_t *chan = &sc->sc_chan[C_CHAN(cn)]; + isdn_appl_t *appl = &isdn_appl[an]; + + if (rea) + { + ctrl->appl= -1; + return(discon_req(1, sc, chan->plci, rea, 0)); + } + ctrl->appl= an; + ctrl->lastact = time.tv_sec; + appl->ctrl= cn; + appl->state= 4; + + return(sel_b2_prot_req(sc, C_CHAN(cn), chan->plci, &appl->dlpd)); +} + +int +nic_output(int cn) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + struct nic_softc *sc = &nic_sc[ctrl->unit]; + chan_t *chan = &sc->sc_chan[C_CHAN(cn)]; + int mb = C_CHAN(cn) ? 7 : 5; + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[mb]; + int r, l; + u_char *b = (u_char *) dpr; + int len= ctrl->o_len; + char *buf= ctrl->o_buf; + + if (dpr->card_state /* & ~4 */) + return (ENODEV); + + if ((chan->ncci == -1) || dpr->msg_flg[mb] || (chan->state != IDLE)) + return (EBUSY); + + chan->state = ACTIVE; + + bzero(mbx, 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++; + b += dpr->buf_ptr[mb]; + l = min(1024, len); + mbx->data_len = l; + bcopy(buf, b, l); + + if (l < len) + { + chan->more = min(len - l, 1024); /* This is a bug, but */ + /* max. blocks length is 2048 bytes including protokoll */ + chan->more_b = buf + l; + mbx->more_data = 1; + } else + { + chan->more = 0; + ctrl->o_len = -1; + } + + dpr->msg_flg[mb] = 3; + bsintr |= (1 << C_CHAN(cn)); + make_intr(mb, sc); + ctrl->lastact = time.tv_sec; + return (0); +} + +static void +con_resp(struct nic_softc * sc, int pl, int rea) +{ + en_q_d(sc, DD_CONN_RSP, pl, 1, (u_char *) & rea); +} + +static int +discon_req(int w, struct nic_softc * sc, int pl, int rea, int err) +{ + if ((pl == 0) || (pl == -1)) + return(0); + return(en_q_d(sc, DD_DISC_REQ, pl, 1, (u_char *) & rea)); +} + +static int +sel_b2_prot_req(struct nic_softc * sc, int c, int pl, dlpd_t * dlpd) +{ + return(en_q_b(sc, c ? 6 : 4, BD_SEL_PROT_REQ | 0x200, pl, + sizeof(dlpd_t), (u_char *) dlpd)); +} + +static void +sel_b3_prot_req(struct nic_softc * sc, int mb, u_short pl, ncpd_t * ncpd) +{ + en_q_b(sc, mb, BD_SEL_PROT_REQ | 0x300, pl, sizeof(ncpd_t), (u_char *) ncpd); +} + +static void +con_b3_resp(struct nic_softc * sc, int mb, u_short ncci, 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; + en_q_b(sc, mb, BD_CONN_B3_RSP, 0, l, buf); +} + +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 void +reset_card(struct nic_softc * sc) +{ + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[1]; + bzero(mbx, 16); + mbx->type = MD_RESET_REQ; + dpr->msg_flg[1] = 1; + make_intr(1, sc); +} + +/* + * nicopen() New open on device. + * + * We forbid all but first open + */ +int +nicopen(dev_t dev, int flag) +{ + struct nic_softc *sc; + u_char unit; + dpr_type *dpr; + int x; + + unit = minor(dev); + + /* minor number out of limits ? */ + if (unit >= NNIC) + return (ENXIO); + sc = &nic_sc[unit]; + + sc->sc_flags |= OPEN; + dpr = sc->sc_dpr; + dpr->card_number = sc->sc_unit; + dpr->int_flg_pc = 0xff; + if (dpr->msg_flg[0]) + { + x = splhigh(); + s_intr(sc, dpr); + splx(x); + } + return (0); +} + +/* + * nicclose() Close device + */ +int +nicclose(dev_t dev, int flag) +{ + struct nic_softc *sc = &nic_sc[minor(dev)]; + + sc->sc_flags = 0; + return (0); +} + +int +nicioctl(dev_t dev, int cmd, caddr_t data, int flag) +{ + int error; + u_char unit; + int i, x; + struct nic_softc *sc = &nic_sc[minor(dev)]; + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx; + + dpr->int_flg_pc = 0xff; + + error = 0; + switch (cmd) + { + case NICCY_DEBUG: + data[0]= 0x38; + bcopy((char *)dpr, data+1, sizeof(dpr_type)); + break; + case NICCY_LOAD: + { + struct head *head = (struct head *) data; + u_char *b = (u_char *) dpr; + int len, l, off; + + x = splhigh(); + while (dpr->msg_flg[1]) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic1head", 1); + if (error != EWOULDBLOCK) + { + splx(x); + return (error); + } + } + mbx = &dpr->dpr_mbx[1]; + bzero(mbx, 16); + mbx->type = MD_DNL_MOD_REQ | ((u_short) head->typ << 8); + mbx->data_len = 12; + bcopy(head->nam, mbx->data, 8); + *(u_long *) (mbx->data + 8) = head->len; + + sc->sc_flags = LOAD_HEAD; + sc->sc_stat = -1; + dpr->msg_flg[1] = 1; + make_intr(1, sc); + while (sc->sc_flags == LOAD_HEAD) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic2head", 1); + if (error != EWOULDBLOCK) + break; + } + + len= head->d_len; + off= 0; + b += dpr->buf_ptr[1]; + + while(len > 0) + { + while (dpr->msg_flg[1]) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic1load", 1); + if (error != EWOULDBLOCK) + { + splx(x); + return (error); + } + } + bzero(mbx, 16); + mbx->type = MD_DNL_MOD_DATA | ((u_short) head->typ << 8); + l= min(len,1024); + len-= l; + mbx->buf_valid = 1; + mbx->more_data = len > 0; + mbx->data_len = l; + bcopy(head->nam, mbx->data, 8); + + if(error= copyin(head->data+off, b, l)) + { + splx(x); + return(error); + } + off+= l; + sc->sc_flags = LOAD_DATA; + sc->sc_stat = -1; + dpr->msg_flg[1] = 3; + make_intr(1, sc); + } + + while ((sc->sc_flags == LOAD_DATA) || (dpr->card_state & 0x20)) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic2load", 1); + if (error != EWOULDBLOCK) + break; + } + if (sc->sc_flags) + sc->sc_flags = OPEN; + head->status = sc->sc_stat; + splx(x); + return (0); + } + case NICCY_SET_CLOCK: + x = splhigh(); + if (dpr->msg_flg[1]) + { + splx(x); + return (EBUSY); + } + mbx = &dpr->dpr_mbx[1]; + bzero(mbx, 16); + mbx->type = MD_SET_CLOCK_REQ; + mbx->data_len = 14; + bcopy(data, mbx->data, 14); + + dpr->msg_flg[1] = 1; + if (dpr->int_flg_nic & 2) + make_intr(1, sc); + splx(x); + return (0); + case NICCY_SPY: + x = splhigh(); + if (dpr->msg_flg[1]) + { + splx(x); + return (EBUSY); + } + mbx = &dpr->dpr_mbx[1]; + bzero(mbx, 16); + mbx->type = MD_MANUFACT_REQ | (18<<8); + mbx->data_len = 1; + mbx->add_info = 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]; + + dpr->msg_flg[1] = 1; + if (dpr->int_flg_nic & 2) + make_intr(1, sc); + splx(x); + return (0); + case NICCY_RESET: + x = splhigh(); + + reset_card(sc); + + while (dpr->card_state & 1) /* self test running */ + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic: reset", 10); + if (error != EWOULDBLOCK) + break; + } + dpr->card_number = sc->sc_unit; + dpr->int_flg_pc = 0xff; + if (dpr->msg_flg[0]) + s_intr(sc, dpr); + splx(x); + return (0); + + default: + error = ENODEV; + } + return (error); +} + +static void +b_intr(int mb, int c, struct nic_softc * sc) +{ + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[mb]; + chan_t *chan = &sc->sc_chan[c]; + u_short ap, n, err = 0; + u_short pl = mbx->add_info; + isdn_ctrl_t *ctrl = &isdn_ctrl[chan->ctrl]; + + if(((unsigned)(mbx->type >> 8) > 3) || ((pl & 0xff00) == 0xff00)) + panic("3008 conflict with 16 bit card\nReconfig your system\n"); + + if (dpr->msg_flg[mb+1]) + return; /* can happen. Should make no problems */ + + if (ISBUSY(ap = ctrl->appl)) + switch (mbx->type & 0x1f) + { + case 0: /* SELECT PROT CONF */ + err = *(u_short *) mbx->data; + if (err) + { + discon_req(2, sc, pl, 0, err); + break; + } + + switch ((mbx->type >> 8) & 3) + { + case 2:/* SELECT B2 PROTOCOL */ + sel_b3_prot_req(sc, mb, pl, &isdn_appl[ap].ncpd); + break; + + case 3:/* SELECT B3 PROTOCOL */ + if (IS_DIAL(pl)) + con_b3_req(sc, mb, pl); + else + listen_b3_req(sc, mb, pl); + break; + } + break; + + case 1: /* LISTEN B3 CONF */ + err = *(u_short *) mbx->data; + if (err) + { + discon_req(4, sc, pl, 0, err); + break; + } + con_resp(sc, pl, 0); + break; + + case 2: /* CONNECT B3 CONF */ + err = *(u_short *) (mbx->data + 2); + n = *(u_short *) mbx->data; + + if (err) + { + discon_req(5, sc, pl, 0, err); + break; + } + chan->ncci = n; + chan->state = CONNECT; + break; + + case 3: /* CONNECT B3 IND */ + n = *(u_short *) mbx->data; + chan->ncci = n; + chan->state = CONNECT; + con_b3_resp(sc, mb, n, 0); + break; + + case 4: /* CONNECT B3 ACTIVE IND */ + if (chan->state < IDLE) + { + chan->state = IDLE; + ctrl->o_len = 0; + timeout(isdn_start_out,chan->ctrl,hz/5); + break; + } + break; + + case 5: /* DISCONNECT B3 CONF */ + chan->state = ISDISCON; + err = *(u_short *) (mbx->data + 2); + if (err) + { + discon_req(6, sc, chan->plci, 0, err); + break; + } + break; + case 6: /* DISCONNECT B3 IND */ + chan->state = ISDISCON; + err = *(u_short *) (mbx->data + 2); + discon_req(7, sc, chan->plci, 0, err); + break; + + case 8: /* DATA B3 CONF */ + err = *(u_short *) (mbx->data + 2); + if (err) + { + ctrl->send_err++; + isdn_appl[ap].send_err++; + } + ctrl->o_len = 0; + chan->state= IDLE; + isdn_start_out(chan->ctrl); + break; + + case 9: /* DATA B3 IND */ + { + u_char *b = (u_char *) dpr; + u_char mno; + + b += dpr->buf_ptr[mb]; + if (mbx->more_data) + { + chan->morenr= mbx->data[4]; + if(chan->i_len) + { + chan->i_len= 0; + break; + } + bcopy(b, &chan->i_buf[chan->i_len], mbx->data_len); + chan->i_len = mbx->data_len; + break; + } /* mbx->more_data == 0 */ + if (chan->i_len) + { + int l; + if(chan->morenr != mbx->data[4]) + break; + + if ((l = chan->i_len + mbx->data_len) <= 2048) + { + bcopy(b, &chan->i_buf[chan->i_len], mbx->data_len); + if(isdn_input(ap, l, chan->i_buf, ctrl->islisten)) + ctrl->lastact = time.tv_sec; + } + chan->i_len = 0; + break; + } /* chan->i_len == 0 && mbx->more_data == 0 */ + if(isdn_input(ap, mbx->data_len, b, ctrl->islisten)) + ctrl->lastact = time.tv_sec; + break; + } + break; + + default: + badstate(mbx,1,mb,dpr); + } +/* + else badstate(mbx,2,mb,dpr); +*/ + + reset_req(sc, mb,1); +} + +static void +d_intr(struct nic_softc * sc) +{ + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[2]; + chan_t *chan; + u_short ap, c, pl, err = 0; + isdn_ctrl_t *ctrl; + isdn_appl_t *appl; + + if (dpr->msg_flg[3]) + return; /* should not happen. might make problems */ + /* but there should be another intr., so what? */ + + pl = mbx->add_info; + if ((c = CHAN(pl)) < 2) + { + chan = &sc->sc_chan[c]; + ctrl = &isdn_ctrl[chan->ctrl]; + } else + { + c = 0xffff; + chan = NULL; + ctrl = NULL; + } + + ap= APPL(pl); + if(ctrl && (ctrl->appl & 0xC0) == 0) + appl= &isdn_appl[ctrl->appl]; + else if(ap < 0x30) + appl = &isdn_appl[ap]; + else if(ap < 0x40) + appl = NULL; + else + { + reset_req(sc, 2,2); + return; + } + + switch (mbx->type & 0x1f) + { + case 0: /* CONNECT CONF */ + err = *(u_short *) mbx->data; + if(err || (appl == NULL) || (chan == NULL) || (ctrl == NULL)) + { + if(chan) reset_plci(1, chan, pl); + if(appl) appl->state= 0; + break; + } + + if (ISBUSY(ctrl->appl)) + { + discon_req(8, sc, pl, 0, 0); + break; + } + chan->plci = pl; + chan->msg_nr= 0; + chan->ncci = -1; + ctrl->lastact = time.tv_sec; + ctrl->appl = ap; + appl->ctrl = chan->ctrl; + ctrl->islisten= 0; + chan->state = DIAL; + appl->state = 3; + break; + + case 1: /* CONNECT IND */ + if (ISBUSY(ctrl->appl)) + { + discon_req(9, sc, 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; + mbx->data[mbx->data[3] + 4] = 0; + isdn_accept_con_ind(ap, chan->ctrl, mbx->data[0], mbx->data[1] + ,mbx->data[2], mbx->data[3], (char *) &mbx->data[4]); + break; + + case 2: /* CONNECT ACTIVE IND */ + con_act_resp(sc, 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 = ap; + appl->ctrl = chan->ctrl; + break; + + case 3: /* DISCONNECT CONF */ + reset_plci(2, chan, pl); + break; + + case 4: /* DISCONNECT IND */ + discon_resp(sc, reset_plci(3, chan, pl)); + break; + + case 7: /* LISTEN CONF */ + isdn_state = *(u_short *) mbx->data; + break; + + case 10: /* INFO IND */ + isdn_info(ap,*(u_short *)mbx->data, mbx->data[2], mbx->data+3); + inf_resp(sc, pl); + break; + + default: + badstate(mbx,3,2,dpr); + } + reset_req(sc, 2,2); +} + +static void +s_intr(struct nic_softc * sc) +{ + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[0]; + mbx_type *smbx = &dpr->dpr_mbx[1]; + + if (dpr->msg_flg[1]) + return; /* should not happen. might make problems */ + /* but there should be another intr., so what? */ + + bzero(smbx, 16); + + switch (mbx->type & 0x1f) + { + case 0: /* INIT CONF */ + break; + case 1: /* INIT IND */ + smbx->type = mbx->type + 0x20; + dpr->msg_flg[1] = 1; + make_intr(1, sc); + break; + case 4: /* DNL MOD CONF */ + sc->sc_stat = mbx->data[0]; + if (sc->sc_flags) + sc->sc_flags = OPEN; + break; + case 6: /* DNL MOD IND */ + smbx->type = mbx->type + 0x20; + smbx->data_len = 1; + smbx->data[0] = mbx->data[1]; + sc->sc_stat = mbx->data[0]; + if (sc->sc_flags) + sc->sc_flags = OPEN; + dpr->msg_flg[1] = 1; + make_intr(1, sc); + break; + case 0x0e: /* SET CLOCK CONF */ + dpr->watchdog_cnt = 0xFF; + dpr->int_flg_pc = 0xFF; + dpr->api_active = 1; + break; + case 0x15: /* POLL IND */ + dpr->watchdog_cnt = 0xFF; + dpr->int_flg_pc = 0xFF; + dpr->api_active = 1; + smbx->type = mbx->type + 0x20; + dpr->msg_flg[1] = 1; + make_intr(1, sc); + break; + case 0x1e: /* MANUFACT CONF */ + if(((mbx->type >> 8) == 18 ) && (*mbx->data == 0)) /* LISTEN */ + break; + badstate(mbx,4,0,dpr); + break; + case 0x1f: /* MANUFACT IND */ + if((mbx->type >> 8) == 19 ) /* DATA */ + { + u_char *b = (u_char *) dpr; + b += dpr->buf_ptr[0]; + isdn_input(ispy_applnr, mbx->data_len, b, 0); + smbx->type = mbx->type + 0x20; + dpr->msg_flg[1] = 1; + make_intr(1, sc); + break; + } + default: + badstate(mbx,5,0,dpr); + } + reset_req(sc, 0, 3); +} + +static void +bs_intr(int mb, int c, struct nic_softc * sc) +{ + chan_t *chan = &sc->sc_chan[c]; + isdn_ctrl_t *ctrl = &isdn_ctrl[chan->ctrl]; + + if (chan->state == ACTIVE) + { + if (chan->more) + { + dpr_type *dpr = sc->sc_dpr; + mbx_type *mbx = &dpr->dpr_mbx[mb]; + u_char *b = (u_char *) dpr; + + bzero(mbx, 20); + mbx->type = BD_DATA_B3_REQ; + if (mb == 7) + mbx->type |= 0x40; + *(u_short *) mbx->data = chan->ncci; + mbx->data[4] = chan->msg_nr; + b += dpr->buf_ptr[mb]; + mbx->data_len = chan->more; + bcopy(chan->more_b, b, chan->more); + + chan->more = 0; + ctrl->o_len = -1; + + dpr->msg_flg[mb] = 3; + make_intr(mb, sc); + + ctrl->lastact = time.tv_sec; + return; + } + bsintr &= ~(1 << c); + } +} + +void +nicintr(int unit) +{ + register struct nic_softc *sc = &nic_sc[unit]; + dpr_type *dpr = sc->sc_dpr; + + if (dpr->msg_flg[2]) + d_intr(sc); + if (dpr->msg_flg[0]) + s_intr(sc); + if (dpr->msg_flg[6]) + b_intr(6, 1, sc); + if (dpr->msg_flg[4]) + b_intr(4, 0, sc); + if (bsintr) + { + if (dpr->msg_flg[7] == 0) + bs_intr(7, 1, sc); + if (dpr->msg_flg[5] == 0) + bs_intr(5, 0, sc); + } +} + +#endif /* NNIC > 0 */ diff --git a/sys/gnu/i386/isa/nic3008.h b/sys/gnu/i386/isa/nic3008.h new file mode 100644 index 0000000..da82696 --- /dev/null +++ b/sys/gnu/i386/isa/nic3008.h @@ -0,0 +1,114 @@ +static char nic38hid[] = "@(#)$Id: nic3008.h,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: nic3008.h,v $ + * + ******************************************************************************/ + +/* + * This file defines the NICCY 3008 Interface. + * Copyright Dr. Neuhaus GmbH, Hamburg and Dietmar Friede + * +*/ + +#pragma pack (1) + +typedef struct { + u_short type; /* Message Subtype/Type */ + u_char source; + u_char dest; + u_short number; /* laufende Nachrichten-Nummer */ + u_short timeoutval; /* Wert fr Timeout */ + u_char priority; /* Nachrichten-Priorit„t */ + u_char more_data; /* Nachricht vollst„ndig? */ + u_short data_len; /* Datenmenge */ + u_char buf_valid; /* im aux. buf.? */ + u_char reserved[1]; + u_short add_info; /* Maske */ + u_char data[0x30];/* Datenfeld */ +} mbx_type; + +/* ------------------------------------------------------------------------ */ + +typedef struct { +/* Offset 0x0000 ---------------------------------------------------------- */ + u_char msg_flg[8]; /* Messages in MBX i */ + u_char card_number; /* Kartennummer of Applikation */ + u_char card_state; /* Kartenstatus */ + u_short mainloop_cnt; /* NICCY's M'loop,68000-Notation*/ + u_char watchdog_cnt; /* Applikation "lebt"? */ + u_char hw_config; /* Steckmodule? */ + u_char jmp_config; /* Karten-Jumper? */ + u_char ram_config; /* Karten-Speicher? */ +/* Offset 0x0010 -----------------------------------------------------------*/ + char niccy_ver[0x0E]; /* "NICCY V x.yyy\c" */ + u_char int_flg_pc; /* Will PC Interrupts? */ + u_char int_flg_nic; /* Will NICCY Interrupts? */ +/* Offset 0x0020 -----------------------------------------------------------*/ + u_short buf_ptr[8]; /* Pointer to aux. buf. ... */ +/* Offset 0x0030 -----------------------------------------------------------*/ + u_short buf_len[8]; /* Size of aux. buf. ... */ +/* Offset 0x0040 -----------------------------------------------------------*/ + /* 0x40 Bytes fr die */ + /* frei verfgbar */ + u_char old_flg[8]; /* Messages in MBX i */ + u_char irq_level; /* welcher IRQ (als Bitmaske */ + u_char res[7]; /* FREI */ +/* Offset 0x0050 -----------------------------------------------------------*/ + u_char api_area_int_nr; /*SW-Int des API wenn API_ACTIVE*/ + u_char api_area_PLCI[2]; /* PLCI w„hrend ApiManufacturer */ + u_char capi_version[6]; /* Versionsnummer der CAPI */ + u_char api_area[0x27]; /* FREI */ +/* Offset 0x0080 -----------------------------------------------------------*/ + u_char api_active; /* Flag ob CAPI aktiv ist */ + u_char ext_hw_config; /* Bit 0: UART 16550 */ + /* Bit 1..7: reserved */ + u_char dpr_hw_id[0x0E]; /* Hardware ID */ +/* Offset 0x0090 -----------------------------------------------------------*/ + u_char dpr_listen_req;/* Anzahl Listen Request's */ + u_char dpr_state_b1; /* state B1 channel */ + /* 0x00 : channel ist frei */ + /* 0x01 : Verbindungsaufb. Req */ + /* 0x02 : Verbindungsaufb. Act */ + /* 0x03 : Verbindung besteht */ + /* 0x04 : eintreffender Ruf */ + /* 0x05 : Verbindung angenommen */ + /* 0x06 : Verbindungsabb. Req */ + /* 0x07 : Verbindungsabb. laeuft*/ + /* 0x08 : Verbindung getrennt */ + u_char dpr_state_b2; /* state B2 channel (siehe oben)*/ + u_char dpr_state_ic1; /* state of Intercomm-Channel */ + u_char dpr_state_ic2; /* ----------- " -------------- */ + u_char state_res[0x04]; + u_char dpr_si_b1; /* Service Indicator auf B1 */ + u_char dpr_si_b2; /* Service Indicator auf B2 */ + u_char dpr_state_res_0[0x05]; +/* Offset 0x00A0 -----------------------------------------------------------*/ + u_char dpr_state_hscx; /* state of HSCX */ + u_char dpr_state_itac; /* state of ITAC */ + u_char dpr_state_arcofi;/* state of ARCOFI */ + u_char dpr_state_modem; /* state of Aufsteckmodem */ + u_char dpr_state_com; /* state of COM */ + u_char dpr_state_res[0x0B]; +/* Offset 0x00B0 -----------------------------------------------------------*/ + u_char dpr_state_ia_tel;/* state of internal Appl. */ + u_char dpr_state_ia_com;/* state of internal Appl. */ + u_char dpr_state_ia_mod;/* state of internal Appl. */ + u_char dpr_state_res_1[0x0D]; +/* Offset 0x00C0 -----------------------------------------------------------*/ + u_char dpr_state_dcp[0x10];/* state of D-channel Prot */ +/* Offset 0x00D0 -----------------------------------------------------------*/ + u_char reserved[0x130]; +/* Offset 0x0200 -----------------------------------------------------------*/ + mbx_type dpr_mbx[8]; /* the mailboxes ... */ +} dpr_type; + +#pragma pack () diff --git a/sys/gnu/i386/isa/nic3009.c b/sys/gnu/i386/isa/nic3009.c new file mode 100644 index 0000000..8062586 --- /dev/null +++ b/sys/gnu/i386/isa/nic3009.c @@ -0,0 +1,1209 @@ +static char nic39_id[] = "@(#)$Id: nic3009.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $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 $ + * + ******************************************************************************/ + +/* + * 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 "param.h" +#include "ioctl.h" +#include "kernel.h" +#include "systm.h" + +#include "i386/isa/isa_device.h" +#include "i386/isa/nic3009.h" +#include "i386/isa/niccyreg.h" +#include "isdn/isdn_ioctl.h" + +#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; +extern int hz; +extern isdn_start_out(); + +static old_spy= 0; + +int nnicprobe(), nnicattach(); +int nnic_connect(), nnic_listen(), nnic_disconnect(), nnic_accept(); +int nnic_output(), nnic_state(); + +static discon_req(), sel_b2_prot_req(), reset_plci(); +static short bsintr; + +struct isa_driver nnidriver = {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; + +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]; +} nnic_sc[NNNIC]; + + +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;i<DPR_LEN;i++) + w[i] = (i+0xaf) & 0xff; + for (i=0;i<DPR_LEN;i++) + if (w[i] != ((i+0xaf) & 0xff)) + { + printf("Niccy card not found or bad memory %x\n",is->id_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 + */ +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; + + 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(struct nnic_softc * sc) +{ + 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; i<mbx->data_len; i++) printf(" %x",mbx->data[i]); + } + printf("\n"); +} + +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); +} + +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)); +} + +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)); +} + +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)); +} + +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); +} + +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)); +} + +int +nnicopen(dev_t dev, int flag) +{ + struct nnic_softc *sc; + u_char unit; + int x; + unsigned error; + u_char b= 0xff; + + 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); +} + +int +nnicclose(dev_t dev, int flag) +{ + struct nnic_softc *sc = &nnic_sc[minor(dev)]; + + sc->sc_flags &= ~7; + return (0); +} + +int +nnicioctl(dev_t dev, int cmd, caddr_t data, int flag) +{ + 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; + 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,sc,1); +} + +static void +nnnicintr(unsigned unit) +{ + 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(unsigned unit) +{ + timeout(nnnicintr,unit,1); +} + +#endif /* NNNIC > 0 */ diff --git a/sys/gnu/i386/isa/nic3009.h b/sys/gnu/i386/isa/nic3009.h new file mode 100644 index 0000000..223619f --- /dev/null +++ b/sys/gnu/i386/isa/nic3009.h @@ -0,0 +1,79 @@ +static char nic39hid[] = "@(#)$Id: nic3009.h,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: nic3009.h,v $ + * + ******************************************************************************/ + +/* + * This file defines the NICCY 3009 Interface. Copyright Dr. Neuhaus GmbH, + * Hamburg and Dietmar Friede + * + */ + +#define NO_MORE_DATA 0x00 /* der Message folgen keine Daten */ +#define MORE_DATA 0x01 /* der Message folgen weitere Daten */ + +#define DPR_LEN 0x800 /* 2 kBytes gross */ +#define DPR_VAR_AREA_LEN 0x100 /* davon fuer allg. Variablen */ + +#define DPR_MBX_LEN (DPR_LEN-DPR_VAR_AREA_LEN)/2 /* 0x380 lang */ +#define DPR_MBX_FLAG_LEN 2 /* zwei Bytes MBX-Zustand... */ +#define DPR_MSG_HDR_LEN 10 /* Msg-Laenge ohne Datafield */ +#define DATAFIELD_LEN (DPR_MBX_LEN-DPR_MBX_FLAG_LEN-DPR_MSG_HDR_LEN) +#define MAX_B3_LEN (2048+2) /* Daten und Network-Header */ + +#pragma pack (1) +typedef struct +{ + u_char msg_flag; /* Signalisierung NICCY / PC */ + u_char progress; /* NICCY-interne Verwendung ! */ + u_char type; + u_char subtype; + u_short number; + u_char more_data; + u_char reserved; + u_short data_len; + u_short plci; + u_char data[DATAFIELD_LEN]; +} mbx_type; + +typedef struct +{ + mbx_type up_mbx; /* Offset 0x000-0x37F */ + mbx_type dn_mbx; /* Offset 0x380-0x6FF */ + u_char card_number; /* Offset 0x700 */ + u_char card_state; /* Offset 0x701 */ + u_short mainloop_cnt; /* Offset 0x702-0x703 */ + u_char watchdog_cnt; /* Offset 0x704 */ + u_char hw_config; /* Offset 0x705 */ + u_char int_flg_pc; /* Offset 0x706 */ + u_char int_flg_nic; /* Offset 0x707 */ + u_char api_area[64]; /* Offset 0x708-0x747 */ + u_char api_active; /* Offset 0x748 */ + u_char tei; /* Offset 0x749 */ + u_char state_b1; /* Offset 0x74A */ + u_char state_b2; /* Offset 0x74B */ + u_char si_b1; /* Offset 0x74C */ + u_char si_b2; /* Offset 0x74D */ + u_short calls_in; /* Offset 0x74E-0x74F */ + u_short calls_out; /* Offset 0x750-0x751 */ + u_char ram_config; /* Offset 0x752 */ + u_char spv_request_flag; /* Offset 0x753 */ + u_char dcp_state_b1; /* Offset 0x754 */ + u_char dcp_state_b2; /* Offset 0x755 */ + u_char dc_protocol; /* Offset 0x756 */ + u_char poll_flag; /* Offset 0x757 */ + u_char debug[DPR_LEN - 0x758 - 4]; /* Offset 0x758-0x7FB */ + u_short signal_niccy_to_pc; /* Offset 0x7FC-0x7FD */ + u_short signal_pc_to_niccy; /* Offset 0x7FE-0x7FF */ +} dpr_type; +#pragma pack () diff --git a/sys/gnu/i386/isa/niccyreg.h b/sys/gnu/i386/isa/niccyreg.h new file mode 100644 index 0000000..a9d8328 --- /dev/null +++ b/sys/gnu/i386/isa/niccyreg.h @@ -0,0 +1,158 @@ +static char nicregh_id[] = "@(#)$Id: niccyreg.h,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: niccyreg.h,v $ + * + ******************************************************************************/ + +/* + * This file defines the NICCY 3008 Interface. + * Copyright Dr. Neuhaus GmbH, Hamburg and Dietmar Friede + * +*/ + +#define MBX_MU 0 +#define MBX_MD 1 +#define MBX_DU 2 +#define MBX_DD 3 +#define MBX_B1U 4 +#define MBX_B1D 5 +#define MBX_B2U 6 +#define MBX_B2D 7 + +#define MBX_xU 0x55 +#define MBX_xD 0xAA + +/* -------------------------------------------------------------------- */ + +#define MU_INIT_CNF 0x00 +#define MU_INIT_IND 0x01 +#define MU_RESET_CNF 0x02 +#define MU_HANDSET_IND 0x03 +#define MU_DNL_MOD_CNF 0x04 +/* reserved: 0x05 */ +#define MU_DNL_MOD_IND 0x06 +#define MU_DISC_MOD_CNF 0x07 +#define MU_LIST_MOD_CNF 0x08 +#define MU_LIST_MOD_DATA 0x09 +/* reserved: 0x0A to 0x0B */ +#define MU_HW_CONFIG_CNF 0x0C +#define MU_HW_ID_CNF 0x0D +#define MU_SET_CLOCK_CNF 0x0E +#define MU_GET_CLOCK_CNF 0x0F +#define MU_ACT_IA_CNF 0x10 +#define MU_ACT_IA_IND 0x11 +#define MU_DEACT_IA_CNF 0x12 +#define MU_DEACT_IA_IND 0x13 +#define MU_POLL_CNF 0x14 +#define MU_POLL_IND 0x15 +/* reserved: 0x16 to 0x1D */ +#define MU_MANUFACT_CNF 0x1E +#define MU_MANUFACT_IND 0x1F + +/*---------------------------------------------------------------------------*/ + +#define MD_INIT_REQ 0x20 +#define MD_INIT_RSP 0x21 +#define MD_RESET_REQ 0x22 +#define MD_HANDSET_RSP 0x23 +#define MD_DNL_MOD_REQ 0x24 +#define MD_DNL_MOD_DATA 0x25 +#define MD_DNL_MOD_RSP 0x26 +#define MD_DISC_MOD_REQ 0x27 +#define MD_LIST_MOD_REQ 0x28 +/* reserved: 0x29 to 0x2B */ +#define MD_HW_CONFIG_REQ 0x2C +#define MD_HW_ID_REQ 0x2D +#define MD_SET_CLOCK_REQ 0x2E +#define MD_GET_CLOCK_REQ 0x2F +#define MD_ACT_IA_REQ 0x30 +#define MD_ACT_IA_RSP 0x31 +#define MD_DEACT_IA_REQ 0x32 +#define MD_DEACT_IA_RSP 0x33 +#define MD_POLL_REQ 0x34 +#define MD_POLL_RSP 0x35 +#define MD_STATE_IND 0x37 +#define MD_MANUFACT_REQ 0x3E +#define MD_MANUFACT_RSP 0x3F + +/*---------------------------------------------------------------------------*/ + +#define DU_CONN_CNF 0x40 +#define DU_CONN_IND 0x41 +#define DU_CONN_ACT_IND 0x42 +#define DU_DISC_CNF 0x43 +#define DU_DISC_IND 0x44 +#define DU_DATA_CNF 0x45 +#define DU_DATA_IND 0x46 +#define DU_LISTEN_CNF 0x47 +#define DU_GET_PAR_CNF 0x48 +#define DU_INFO_CNF 0x49 +#define DU_INFO_IND 0x4A +#define DU_CONN_INFO_CNF 0x4B +#define DU_REL_PLCI_CNF 0x4C +/* reserved: 0x4C to 0x5E */ +#define DU_STR_NOT_COMP 0x5F + +/*---------------------------------------------------------------------------*/ + +#define DD_CONN_REQ 0x60 +#define DD_CONN_RSP 0x61 +#define DD_CONN_ACT_RSP 0x62 +#define DD_DISC_REQ 0x63 +#define DD_DISC_RSP 0x64 +#define DD_DATA_REQ 0x65 +#define DD_DATA_RSP 0x66 +#define DD_LISTEN_REQ 0x67 +#define DD_GET_PAR_REQ 0x68 +#define DD_INFO_REQ 0x69 +#define DD_INFO_RSP 0x6A +#define DD_CONN_INFO_REQ 0x6B +#define DD_REL_PLCI_REQ 0x6C + +/*---------------------------------------------------------------------------*/ + +#define BD_SEL_PROT_REQ 0xA0 +#define BD_LIST_B3_REQ 0xA1 +#define BD_CONN_B3_REQ 0xA2 +#define BD_CONN_B3_RSP 0xA3 +#define BD_C_B3_ACT_RSP 0xA4 +#define BD_DISC_B3_REQ 0xA5 +#define BD_DISC_B3_RSP 0xA6 +#define BD_GET_P_B3_REQ 0xA7 +#define BD_DATA_B3_REQ 0xA8 +#define BD_DATA_B3_RSP 0xA9 +#define BD_RESET_B3_REQ 0xAA +#define BD_RESET_B3_RSP 0xAB + +/*---------------------------------------------------------------------------*/ + + +#define NICCY_DEBUG _IOWR('N',1,dbg_type) +#define NICCY_RESET _IOWR('N',2,int) +#define NICCY_LOAD _IOWR('N',3,struct head) +#define NICCY_SET_CLOCK _IOWR('N',4,time_str_t) +#define NICCY_SPY _IOWR('N',5,int) + +struct head +{ + u_long len; + u_long sig; + char nam[8]; + char ver[5]; + u_char typ; + u_short status; + u_long d_len; + u_char *data; +}; + +typedef char time_str_t[14]; +typedef u_char dbg_type[10000]; diff --git a/sys/gnu/isdn/if_ii.c b/sys/gnu/isdn/if_ii.c new file mode 100644 index 0000000..c02657e --- /dev/null +++ b/sys/gnu/isdn/if_ii.c @@ -0,0 +1,245 @@ +static char _if_iiid[] = "@(#)$Id: if_ii.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: if_ii.c,v $ + * + ******************************************************************************/ + +/* + * Copyright (c) 1994 Dietmar Friede (dietmar@friede.de) All rights reserved. + * FSF/FSAG GNU Copyright applies + * + * A high level ip isdn driver. + * + * Uses loop driver as template. Small - and simple - is beautiful. + */ + +#include "param.h" +#include "systm.h" +#include "mbuf.h" +#include "socket.h" +#include "errno.h" +#include "ioctl.h" +#include "protosw.h" + +#include "net/if.h" +#include "net/if_types.h" +#include "net/netisr.h" +#include "net/route.h" + +#ifdef INET +#include "netinet/in.h" +#include "netinet/in_systm.h" +#include "netinet/in_var.h" +#include "netinet/ip.h" +#endif + +#include "ii.h" +#include "isdn/isdn_ioctl.h" + +#define IIMTU 1500 + +static struct ifnet ii_if[NII]; +static int applnr[NII]; +static int next_if = 0; +int iioutput(), ii_ioctl(); + +int +iiattach(int ap) +{ + register struct ifnet *ifp; + + if (next_if >= NII) + return -1; + + applnr[next_if] = ap; + ifp = &ii_if[next_if]; + ifp->if_unit = next_if; + ifp->if_name = "ii"; + ifp->if_mtu = IIMTU; + ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT ; + ifp->if_ioctl = ii_ioctl; + ifp->if_output = iioutput; + ifp->if_type = IFT_ISDNBASIC; + ifp->if_hdrlen = 0; + ifp->if_addrlen = 0; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + if_attach(ifp); + /* ifp->if_flags |= IFF_RUNNING; */ + return next_if++; +} + +int +iioutput(struct ifnet * ifp, struct mbuf * m, struct sockaddr * dst) +{ + int s, isr; + register struct ifqueue *ifq = 0; + + if (dst->sa_family != AF_INET) + { + m_freem(m); + return EAFNOSUPPORT; + } + s = splhigh(); + if (IF_QFULL(&ifp->if_snd)) + { + IF_DROP(&ifp->if_snd); + m_freem(m); + ifp->if_oerrors++; + isdn_output(applnr[ifp->if_unit]); + splx(s); + return (ENOBUFS); + } + IF_ENQUEUE(&ifp->if_snd, m); + + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; + + isdn_output(applnr[ifp->if_unit]); + splx(s); + return (0); +} + +int +ii_input(int no, int len, char *buf) +{ + int error = 0; + struct mbuf *m; + struct ifnet *ifp = &(ii_if[no]); + int s; + + s = splhigh(); + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + { + splx(s); + return (0); + } + + if (len >= MHLEN) + { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) + { + (void) m_free(m); + splx(s); + return (0); + } + } + bcopy((caddr_t) buf, mtod(m, caddr_t), len); + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = len; + m->m_len = len; + + if (IF_QFULL(&ipintrq)) + { + IF_DROP(&ipintrq); + ifp->if_ierrors++; + m_freem(m); + splx(s); + return(0); + } + IF_ENQUEUE(&ipintrq, m); + ifp->if_ipackets++; + schednetisr(NETISR_IP); + splx(s); + return(len); +} + +int +ii_connect(int no) +{ + struct ifnet *ifp = &ii_if[no]; + ifp->if_flags |= IFF_RUNNING; +} + +int +ii_disconnect(int no) +{ + struct ifnet *ifp = &ii_if[no]; + ifp->if_flags &= ~IFF_RUNNING; +} + +int +ii_out(int no, char *buf, int len) +{ + struct ifnet *ifp = &ii_if[no]; + struct mbuf *m0, *m; + int l; + + IF_DEQUEUE(&ifp->if_snd, m); + if (m == 0) + { + return (0); + } + /* + * Copy the mbuf chain into the transmit buf + */ + l = 0; + for (m0 = m; m != 0; m = m->m_next) + { + if((l+= m->m_len) > len) + { + m_freem(m0); + return(0); + } + bcopy(mtod(m, caddr_t), buf, m->m_len); + buf += m->m_len; + } + m_freem(m0); + + return (l); +} + +/* + * Process an ioctl request. + */ +int +ii_ioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + struct ifaddr *ifa = (struct ifaddr *) data; + struct ifreq *ifr = (struct ifreq *) data; + int s; + + switch (cmd) + { + case SIOCSIFDSTADDR: + case SIOCAIFADDR: + case SIOCSIFADDR: + if (ifa->ifa_addr->sa_family != AF_INET) + return(EAFNOSUPPORT); + ifp->if_flags |= IFF_UP; + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + s= splhigh(); + if((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) + { + isdn_disconnect(applnr[ifp->if_unit],0); + ifp->if_flags &= ~IFF_RUNNING; + } + break; + case SIOCSIFMTU: + ifr->ifr_metric = ifp->if_mtu; + break; + case SIOCGIFMTU: + if(ifr->ifr_metric < 2048) + return(EAFNOSUPPORT); + ifp->if_mtu = ifr->ifr_metric; + break; + default: +printf("IIO %x",cmd); + return(EINVAL); + } + return(0); +} diff --git a/sys/gnu/isdn/iispy.c b/sys/gnu/isdn/iispy.c new file mode 100644 index 0000000..e426f1d --- /dev/null +++ b/sys/gnu/isdn/iispy.c @@ -0,0 +1,171 @@ +static char _ispyid[] = "@(#)$Id: iispy.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: iispy.c,v $ + * + ******************************************************************************/ + +#include "ispy.h" +#if NISPY > 0 + +#include "param.h" +#include "buf.h" +#include "systm.h" +#include "ioctl.h" +#include "tty.h" +#include "proc.h" +#include "user.h" +#include "uio.h" +#include "kernel.h" +/*#include "malloc.h"*/ + +#include "isdn/isdn_ioctl.h" + +int ispyattach(); + +int nispy = NISPY; +int ispy_applnr; +static int next_if =0; +static unsigned long ispy_cnt, ispy_out; +static char dir; +#define ISPY_SIZE 260 +#define OPEN 1 +#define READ_WAIT 2 +#define ISPYBUF 16 +#define ISPYMASK (ISPYBUF-1) +/* ISPYBUF has to be a power of 2 */ + +static +struct ispy_data +{ + struct ispy_buf + { + unsigned long cnt; + struct timeval stamp; + char ibuf[ISPY_SIZE]; + unsigned char dir; + int ilen; + } b[ISPYBUF]; + int state; +} ispy_data[NISPY]; + +int +ispyattach(int ap) +{ + struct ispy_data *ispy; + if(next_if >= NISPY) + return(-1); + ispy= &ispy_data[next_if]; + ispy->state= 0; + ispy_applnr= ap; + return(next_if++); +} + +int +ispy_input(int no, int len, char *buf, int out) +{ + struct ispy_data *ispy= &ispy_data[no]; + struct ispy_buf *b= &ispy->b[ispy_cnt&ISPYMASK]; + + if(len > ISPY_SIZE) + return(0); + if(len) + { + b->cnt= ispy_cnt++; + b->stamp= time; + b->dir= out; + bcopy(buf, b->ibuf, len); + } + b->ilen= len; + if(ispy->state & READ_WAIT) + { + ispy->state &= ~READ_WAIT; + wakeup((caddr_t) &ispy->state); + } + return(len); +} + +int +ispyopen(dev_t dev, int flag) +{ + int err; + struct ispy_data *ispy; + + if (minor(dev)>NISPY) + return (ENXIO); + + ispy= &ispy_data[minor(dev)]; + + if(ispy->state&OPEN) return(EBUSY); + ispy->state |= OPEN; + + return (0); +} + +int +ispyclose(dev_t dev, int flag) +{ + struct ispy_data *ispy= &ispy_data[minor(dev)]; + + if(ispy->state & READ_WAIT) + wakeup((caddr_t) &ispy->state); + ispy->state = 0; + return (0); +} + +int +ispyioctl (dev, cmd, data, flag) +dev_t dev; +caddr_t data; +int cmd, flag; +{ + int unit = minor(dev); + + switch (cmd) { + default: + return (ENOTTY); + } + return (0); +} + +int +ispyread(dev_t dev, struct uio * uio) +{ + int x; + int error = 0; + struct ispy_data *ispy= &ispy_data[minor(dev)]; + struct ispy_buf *b; + + if((ispy_cnt-ispy_out) > ISPYBUF) + ispy_out= ispy_cnt - ISPYBUF; + b= &ispy->b[ispy_out&ISPYMASK]; + ispy_out++; + while(b->ilen == 0) + { + ispy->state |= READ_WAIT; + if(error= tsleep((caddr_t) &ispy->state, TTIPRI | PCATCH, "ispy", 0 )) + return(error); + } + + x = splhigh(); + if(b->ilen) + { + error = uiomove((char *) &b->dir, 1, uio); + if(error == 0) + error = uiomove((char *) &b->cnt + ,sizeof(unsigned long)+sizeof(struct timeval)+b->ilen, uio); + b->ilen= 0; + } + splx(x); + return error; +} + +#endif diff --git a/sys/gnu/isdn/iitel.c b/sys/gnu/isdn/iitel.c new file mode 100644 index 0000000..bf2b72a --- /dev/null +++ b/sys/gnu/isdn/iitel.c @@ -0,0 +1,234 @@ +static char _itelid[] = "@(#)$Id: iitel.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: iitel.c,v $ + * + ******************************************************************************/ + +#include "itel.h" +#if NITEL > 0 + +#include "param.h" +#include "buf.h" +#include "systm.h" +#include "ioctl.h" +#include "tty.h" +#include "proc.h" +#include "user.h" +#include "uio.h" +#include "kernel.h" +#include "malloc.h" + +#include "isdn/isdn_ioctl.h" + +int itelattach(); + +int nitel = NITEL; +static int applnr[NITEL]; +static int next_if =0; +#define ITEL_SIZE 1024 +#define OPEN 1 +#define CONNECT 2 +#define READ_WAIT 4 +#define WRITE_WAIT 8 +#define min(a,b) ((a)<(b)?(a):(b)) + +static +struct itel_data +{ + char ibuf[ITEL_SIZE]; + char obuf[ITEL_SIZE]; + int state; + int ilen, olen; +} itel_data[NITEL]; + +int +itelattach(int ap) +{ + struct itel_data *itel; + if(next_if >= NITEL) + return(-1); + itel= &itel_data[next_if]; + itel->ilen= itel->olen= 0; + itel->state= 0; + applnr[next_if]= ap; + return(next_if++); +} + +int +itel_input(int no, int len, char *buf) +{ + struct itel_data *itel= &itel_data[no]; + + if(itel->ilen || ( len > ITEL_SIZE)) + return(0); + if(len) + bcopy(buf, itel->ibuf, len); + itel->ilen= len; + if(itel->state & READ_WAIT) + { + itel->state &= ~READ_WAIT; + wakeup((caddr_t) itel->ibuf); + } + return(len); +} + +int +itel_out(int no, char *buf, int len) +{ + struct itel_data *itel= &itel_data[no]; + int l; + + if((itel->state & CONNECT) == 0) + return(0); + if((l= itel->olen) && (itel->olen <= len)) + bcopy(itel->obuf, buf, l); + + itel->olen= 0; + if(itel->state & WRITE_WAIT) + { + itel->state &= ~WRITE_WAIT; + wakeup((caddr_t) itel->obuf); + } + return(l); +} + +void +itel_connect(int no) +{ + itel_data[no].state |= CONNECT; +} + +void +itel_disconnect(int no) +{ + struct itel_data *itel= &itel_data[no]; + int s; + + s= itel->state; + if(itel->state &= OPEN) + { + itel->ilen= itel->olen= 0; + if(s & READ_WAIT) + wakeup((caddr_t) itel->ibuf); + if(s & WRITE_WAIT) + wakeup((caddr_t) itel->obuf); + } +} + +int +itelopen(dev_t dev, int flag) +{ + int err; + struct itel_data *itel; + + if (minor(dev)>NITEL) + return (ENXIO); + + itel= &itel_data[minor(dev)]; + if((itel->state & CONNECT) == 0) + return(EIO); + + if(itel->state&OPEN) return(0); + itel->ilen= itel->olen= 0; + itel->state |= OPEN; + + return (0); +} + +int +itelclose(dev_t dev, int flag) +{ + struct itel_data *itel= &itel_data[minor(dev)]; + + if(itel->state & READ_WAIT) + wakeup((caddr_t) itel->ibuf); + if(itel->state & WRITE_WAIT) + wakeup((caddr_t) itel->obuf); + itel_data[minor(dev)].state &= CONNECT; + return (0); +} + +int +itelioctl (dev, cmd, data, flag) +dev_t dev; +caddr_t data; +int cmd, flag; +{ + int unit = minor(dev); + + switch (cmd) { + default: + return (ENOTTY); + } + return (0); +} + +int +itelread(dev_t dev, struct uio * uio) +{ + int x; + int error = 0; + struct itel_data *itel= &itel_data[minor(dev)]; + + if((itel->state & CONNECT) == 0) + return(EIO); + + while((itel->ilen == 0) && (itel->state & CONNECT)) + { + itel->state |= READ_WAIT; + sleep((caddr_t) itel->ibuf, PZERO | PCATCH); + } + + x = splhigh(); + if(itel->ilen) + { + error = uiomove(itel->ibuf, itel->ilen, uio); + itel->ilen= 0; + } else error= EIO; + splx(x); + return error; +} + +int +itelwrite(dev_t dev, struct uio * uio) +{ + int x; + int error = 0; + struct itel_data *itel= &itel_data[minor(dev)]; + + if((itel->state & CONNECT) == 0) + return(EIO); + + while(itel->olen && (itel->state & CONNECT)) + { + itel->state |= WRITE_WAIT; + sleep((caddr_t) itel->obuf, PZERO | PCATCH); + } + + x = splhigh(); + if((itel->state & CONNECT) == 0) + { + splx(x); + return(0); + } + + if(itel->olen == 0) + { + itel->olen= min(ITEL_SIZE, uio->uio_resid); + error = uiomove(itel->obuf, itel->olen, uio); + isdn_output(applnr[minor(dev)]); + } + splx(x); + return error; +} + +#endif diff --git a/sys/gnu/isdn/iitty.c b/sys/gnu/isdn/iitty.c new file mode 100644 index 0000000..815da76 --- /dev/null +++ b/sys/gnu/isdn/iitty.c @@ -0,0 +1,306 @@ +static char _ittyid[] = "@(#)$Id: iitty.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: iitty.c,v $ + * + ******************************************************************************/ + +#include "ity.h" +#if NITY > 0 + +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "select.h" +#include "tty.h" +#include "proc.h" +#include "user.h" +#include "conf.h" +#include "file.h" +#include "uio.h" +#include "kernel.h" +#include "syslog.h" +#include "types.h" + +#include "isdn/isdn_ioctl.h" + +int ityattach(), itystart(), ityparam(); + +int nity = NITY; +int itydefaultrate = 64000; +short ity_addr[NITY]; +struct tty ity_tty[NITY]; +static int applnr[NITY]; +static int next_if= 0; + +#define UNIT(x) (minor(x)&0x3f) +#define OUTBOUND(x) ((minor(x)&0x80)==0x80) + +int +ityattach(int ap) +{ + if(next_if >= NITY) + return(-1); + + applnr[next_if]= ap; + return(next_if++); +} + +/* ARGSUSED */ +ityopen(dev_t dev, int flag, int mode, struct proc * p) +{ + register struct tty *tp; + register int unit; + int error = 0; + + unit = UNIT(dev); + if (unit >= next_if) + return (ENXIO); + + tp = &ity_tty[unit]; + tp->t_oproc = itystart; + tp->t_param = ityparam; + tp->t_dev = dev; + if ((tp->t_state & TS_ISOPEN) == 0) + { + tp->t_state |= TS_WOPEN; + ttychars(tp); + if (tp->t_ispeed == 0) + { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = itydefaultrate; + } + ityparam(tp, &tp->t_termios); + ttsetwater(tp); + } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) + return (EBUSY); + (void) spltty(); + + if(OUTBOUND(dev)) tp->t_cflag |= CLOCAL; + + while ((flag & O_NONBLOCK) == 0 && (tp->t_cflag & CLOCAL) == 0 && + (tp->t_state & TS_CARR_ON) == 0) + { + tp->t_state |= TS_WOPEN; + if (error = ttysleep(tp, (caddr_t) & tp->t_rawq, TTIPRI | PCATCH, + ttopen, 0)) + break; + } + (void) spl0(); + if (error == 0) + error = (*linesw[tp->t_line].l_open) (dev, tp); + return (error); +} + +/* ARGSUSED */ +ityclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + register struct tty *tp; + register ity; + register int unit; + + unit = UNIT(dev); + ity = ity_addr[unit]; + if(tp = &ity_tty[unit]) + (*linesw[tp->t_line].l_close) (tp, flag); + ttyclose(tp); + isdn_disconnect(applnr[unit],0); + return (0); +} + +ityread(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + register struct tty *tp = &ity_tty[UNIT(dev)]; + + return ((*linesw[tp->t_line].l_read) (tp, uio, flag)); +} + +itywrite(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + int unit = UNIT(dev); + register struct tty *tp = &ity_tty[unit]; + + return ((*linesw[tp->t_line].l_write) (tp, uio, flag)); +} + +ity_input(int no, int len, char *buf) +{ + register struct tty *tp = &ity_tty[no]; + int i; + + if (tp->t_state & TS_ISOPEN) + for(i= 0; i<len; i++) + (*linesw[tp->t_line].l_rint)(buf[i], tp); + else len= 0; + return(len); +} + +itystart(struct tty *tp) +{ + int s, unit; + + unit = UNIT(tp->t_dev); + + s = splhigh(); + if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) + { + splx(s); + return; + } + if (tp->t_outq.c_cc <= tp->t_lowat) + { + if (tp->t_state & TS_ASLEEP) + { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t) & tp->t_outq); + } + selwakeup(&tp->t_wsel); + } + if (tp->t_outq.c_cc) + { + if(OUTBOUND(tp->t_dev) && (tp->t_cflag & CLOCAL) && + ((tp->t_state & TS_CARR_ON) == 0)) + isdn_msg(applnr[unit]); + else isdn_output(applnr[unit]); + tp->t_state |= TS_BUSY; + } + splx(s); +} + +ity_out(int no, char *buf, int len) +{ + struct tty *tp = &ity_tty[no]; + int i; + + if(tp == NULL) + return(0); + if(tp->t_outq.c_cc) + { + for (i = 0; i < len && tp->t_outq.c_cc; ++i) + buf[i]= getc(&tp->t_outq); + return(i); + } + tp->t_state &=~ (TS_BUSY|TS_FLUSH); + if (tp->t_line) + (*linesw[tp->t_line].l_start)(tp); + else + itystart(tp); + return(0); +} + +ity_connect(int no) +{ + struct tty *tp = &ity_tty[no]; + + if(tp == NULL) + return; + if(OUTBOUND(tp->t_dev)) tp->t_cflag &= ~CLOCAL; + (*linesw[tp->t_line].l_modem) (tp, 1); + tp->t_state |= TS_CARR_ON; + tp->t_state &=~ (TS_BUSY|TS_FLUSH); + if (tp->t_line) + (*linesw[tp->t_line].l_start)(tp); + else + itystart(tp); +} + +ity_disconnect(int no) +{ + struct tty *tp = &ity_tty[no]; + if(tp) (*linesw[tp->t_line].l_modem) (tp, 0); +} + +ityioctl(dev, cmd, data, flag,p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + register struct tty *tp; + register int unit = UNIT(dev); + register int error; + + tp = &ity_tty[unit]; + error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag,p); + if (error >= 0) + return (error); + error = ttioctl(tp, cmd, data, flag); + if (error >= 0) + return (error); + + switch (cmd) + { + default: + return (ENOTTY); + } + return (0); +} + +ityparam(tp, t) + register struct tty *tp; + register struct termios *t; +{ + register ity; + register int cfcr, cflag = t->c_cflag; + int unit = UNIT(tp->t_dev); + int ospeed = t->c_ospeed; + + /* check requested parameters */ + if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) + return (EINVAL); + /* and copy to tty */ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = cflag; + + if (ospeed == 0) + { + isdn_disconnect(applnr[unit],0); + return (0); + } + return (0); +} + +/* + * Stop output on a line. + */ +/* ARGSUSED */ +itystop(struct tty *tp, int flag) +{ + register int s; + + s = splhigh(); + if (tp->t_state & TS_BUSY) + { + if ((tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; + } + splx(s); +} + +int +ityselect(dev_t dev, int rw, struct proc *p) +{ + return (ttselect(dev, rw, p)); +} + +#endif diff --git a/sys/gnu/isdn/isdn.c b/sys/gnu/isdn/isdn.c new file mode 100644 index 0000000..ddf59ed --- /dev/null +++ b/sys/gnu/isdn/isdn.c @@ -0,0 +1,626 @@ +static char _isdnid[] = "@(#)$Id: isdn.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: isdn.c,v $ + * + ******************************************************************************/ + +/* + * Copyright (c) 1994 Dietmar Friede (dietmar@friede.de) All rights reserved. + * FSF/FSAG GNU Copyright applies + * + * An intermediate level for ISDN Drivers. + * + */ + +#include "isdn.h" +#include "ii.h" +#include "ity.h" +#include "itel.h" +#include "ispy.h" +#if NISDN > 0 + +#define TYPNR 4 +#define N_ISDN_APPL (NII + NITY + NITEL + NISPY) + +#include "param.h" +#include "ioctl.h" +#include "kernel.h" +#include "systm.h" + +#include "isdn/isdn_ioctl.h" + +isdn_appl_t isdn_appl[N_ISDN_APPL]; +isdn_ctrl_t isdn_ctrl[N_ISDN_CTRL]; +int Isdn_Appl, Isdn_Ctrl, Isdn_Typ; + +int isdn_input(), isdn_output(); +int ii_input(), ii_out(), ii_connect(), ii_disconnect(); +int ity_input(), ity_out(), ity_connect(), ity_disconnect(); +int itel_input(), itel_out(), itel_connect(), itel_disconnect(); +int ispy_input(); +int isdn_stat(); + +void isdn_disconnect(); +static int o_flags, r_flags, bufind[TYPNR]; +static char buffer[TYPNR][257]; +static u_char appl_list[TYPNR]; + +typedef u_char prot[2]; +static u_char prot_size[2] = {0, 2}; +static prot passiv[6] = {{0}, {3, 3}}; +static prot activ[6] = {{0}, {1, 3}}; +static void passout(); + +u_short isdn_state= 0; +static isdn_timeout= 0; +extern int hz; + +int +isdn_get_prot_size(int ap) +{ + return (prot_size[isdn_appl[ap].prot]); +} + +char * +isdn_get_prot(int ap, int dir) +{ + if(dir) + return(activ[isdn_appl[ap].prot]); + return(passiv[isdn_appl[ap].prot]); +} + +int +isdn_set_prot(int ap, int dir, char *p) +{ + char *pr; + int i, l; + if ((l = isdn_get_prot_size(ap)) == 0) + return (0); + if (dir) + pr = passiv[isdn_appl[ap].prot]; + else + pr = activ[isdn_appl[ap].prot]; + for (i = 0; i < l; i++, pr++, p++) + *p = *pr; + return (l); +} + +void +isdn_attach() +{ + isdn_appl_t *appl; + int i, an; + + appl_list[0]= Isdn_Typ= an= 0; + + for(i= 0 ; i<NII; i++,an++) + { + appl = &isdn_appl[an]; + appl->ctrl = -1; + appl->state = 0; + appl->appl = an; + appl->typ = Isdn_Typ; + appl->drivno = iiattach(an); + appl->PassUp = ii_input; + appl->PassDown = ii_out; + appl->Connect = ii_connect; + appl->DisConn = ii_disconnect; + } + + appl_list[1]= an; + Isdn_Typ= 1; + for(i= 0 ; i<NITY; i++,an++) + { + appl = &isdn_appl[an]; + appl->ctrl = -1; + appl->state = 0; + appl->appl = an; + appl->typ = Isdn_Typ; + appl->drivno = ityattach(an); + appl->PassUp = ity_input; + appl->PassDown = ity_out; + appl->Connect = ity_connect; + appl->DisConn = ity_disconnect; + } + + appl_list[2]= an; + Isdn_Typ= 2; + for(i= 0 ; i<NITEL; i++,an++) + { + appl = &isdn_appl[an]; + appl->ctrl = -1; + appl->state = 0; + appl->appl = an; + appl->typ = Isdn_Typ; + appl->drivno = itelattach(an); + appl->PassUp = itel_input; + appl->PassDown = itel_out; + appl->Connect = itel_connect; + appl->DisConn = itel_disconnect; + } + + appl_list[3]= an; + Isdn_Typ= 3; + for(i= 0 ; i<NISPY; i++,an++) + { + appl = &isdn_appl[an]; + appl->ctrl = -1; + appl->state = 0; + appl->appl = an; + appl->typ = Isdn_Typ; + appl->drivno = ispyattach(an); + appl->PassUp = ispy_input; + } + Isdn_Appl= an; +} + +int +isdn_ctrl_attach(int n) +{ + int c = Isdn_Ctrl; + + if(Isdn_Ctrl == 0) isdn_attach(); + if ((Isdn_Ctrl += n) <= N_ISDN_CTRL) + return (c); + Isdn_Ctrl = c; + return (-1); +} + +/* + * isdnopen() New open on device. + * + * I forbid all but one open per application. The only programs opening the + * isdn device are the ISDN-daemon + */ +int +isdnopen(dev_t dev, int flag) +{ + int err; + + if (minor(dev)>Isdn_Typ) + return (ENXIO); + + /* Card busy ? */ + if (o_flags & (1 << minor(dev))) + return (EBUSY); + + o_flags |= (1 << minor(dev)); + + return (0); +} + +int +isdnclose(dev_t dev, int flag) +{ + o_flags &= ~(1 << minor(dev)); + return (0); +} + +int +isdnread(dev_t dev, struct uio * uio) +{ + int x; + int error = 0; + int unit= minor(dev); + + r_flags &= ~(1 << unit); + + x = splhigh(); + if(bufind[unit] == 0) + { + r_flags |= (1 << unit); + error= tsleep((caddr_t) buffer[unit], PZERO + 1, "isdnin", hz); + } + if(bufind[unit]) + { + buffer[unit][bufind[unit]++]= 0; + error = uiomove(buffer[unit], bufind[unit], uio); + bufind[unit] = 0; + } + splx(x); + return error; +} + +int +isdnioctl(dev_t dev, int cmd, caddr_t data, int flag) +{ + int err, x, i; + isdn_appl_t *appl; + isdn_ctrl_t *ctrl; + short *val = (short *) data; + unsigned ab, an, cn; + + err = 0; + ab= appl_list[minor(dev)]; + + switch (cmd) + { + case ISDN_LISTEN: + { + listen_t *s= (listen_t *) data; + + an= ab; + if (s->ctrl >= Isdn_Ctrl) + return (ENODEV); + cn= s->ctrl; + ctrl = &isdn_ctrl[cn]; + + x = splhigh(); + while(isdn_state) + { + err = tsleep((caddr_t) ctrl, PZERO | PCATCH, "slisten", 2); + if (err != EWOULDBLOCK) + { + splx(x); + return (err); + } + } + + isdn_state = 0xffff; + while((err = (*ctrl->listen) (s->ctrl, minor(dev) | 0x30 + , s->inf_mask ,s->subadr_mask ,s->si_mask)) == EBUSY) + { + err = tsleep((caddr_t) ctrl, PZERO | PCATCH, "blisten", 2); + if (err != EWOULDBLOCK) + { + splx(x); + return (err); + } + } + + if (err) + { + splx(x); + return (err); + } + while (isdn_state == 0xffff) + { + err = tsleep((caddr_t) ctrl, PZERO | PCATCH, "ilisten", 2); + if (err != EWOULDBLOCK) + { + splx(x); + return (err); + } + } + splx(x); + err= isdn_state; + isdn_state= 0; + return (err); /* tricky but it works */ + } + break; + + case ISDN_DIAL: + { + dial_t *d= (dial_t*)data; + telno_t *t= &d->telno; + + an = d->appl + ab; + cn = d->ctrl; + + if (an >= Isdn_Appl || cn >= Isdn_Ctrl) + return (ENODEV); + + appl = &isdn_appl[an]; + + if (ISBUSY(appl->ctrl) || appl->state) + return (EBUSY); + + appl->state= 1; + x = splhigh(); + + while((err = (*isdn_ctrl[cn].connect) (cn, an + ,d->b_channel, d->inf_mask, d->out_serv + ,d->out_serv_add, d->src_subadr, t->length + ,t->no, d->spv)) == EBUSY) + { + err = tsleep((caddr_t) appl, PZERO | PCATCH, "idial", 2); + if (err != EWOULDBLOCK) + { + splx(x); + return (err); + } + } + if(err) appl->state= 0; + splx(x); + return(err); + } + break; + case ISDN_HANGUP: + cn = data[0]; + if (cn >= Isdn_Ctrl) + return (ENODEV); + x = splhigh(); + + while((err = (*isdn_ctrl[cn].disconnect) (cn, data[1])) == EBUSY) + { + err = tsleep((caddr_t) data, PZERO | PCATCH, "ihang", 2); + if (err != EWOULDBLOCK) + { + splx(x); + return (err); + } + } + splx(x); + break; + case ISDN_ACCEPT: + cn = data[0]; + an = data[1] + ab; + if (cn >= Isdn_Ctrl) + return (ENODEV); + x = splhigh(); + while((err = (*isdn_ctrl[cn].accept) (cn, an, data[2])) == EBUSY) + { + err = tsleep((caddr_t) data, PZERO | PCATCH, "iaccept", 2); + if (err != EWOULDBLOCK) + { + splx(x); + return (err); + } + } + splx(x); + break; + case ISDN_SET_PARAM: + { + isdn_param *p = (isdn_param *) data; + + an = p->appl + ab; + if (an >= Isdn_Appl) + return (ENODEV); + appl = &isdn_appl[an]; + bcopy(p, appl, sizeof(isdn_param)); + appl->appl+= ab; + } + break; + case ISDN_GET_PARAM: + { + isdn_param *p = (isdn_param *) data; + an = p->appl + ab; + if (an >= Isdn_Appl) + return (ENODEV); + appl = &isdn_appl[an]; + bcopy(appl, p, sizeof(isdn_param)); + } + break; + default: + err = ENODEV; + } + + return (err); +} + +void +isdn_start_out(int cn) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + isdn_appl_t *appl = &isdn_appl[ctrl->appl]; + int x; + + x= splhigh(); + if (ctrl->o_len == 0) + { + int l; + l = isdn_set_prot(ctrl->appl, ctrl->islisten, ctrl->o_buf); + ctrl->o_len = (*appl->PassDown) (appl->drivno, ctrl->o_buf+l,2048-l); + + if (ctrl->o_len == 0) + { + splx(x); + return; + } + ctrl->o_len+= l; + (*ctrl->output) (cn); + } + + splx(x); +} + +int +isdn_stat(int cn) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + return((*ctrl->state) (cn)); +} + +int +isdn_output(int an) +{ + isdn_appl_t *appl = &isdn_appl[an]; + + if (ISFREE(appl->ctrl)) + { + int l; + char buf[10]; + + if(appl->state) + return(0); + + l = sprintf(buf,"d %d", an-appl_list[appl->typ]); + passout(appl->typ,l,buf); + return(0); + } + isdn_start_out(appl->ctrl); + return (0); +} + +int +isdn_msg(int an) +{ + isdn_appl_t *appl = &isdn_appl[an]; + + if (ISFREE(appl->ctrl)) + { + int l; + char buf[256]; + + l = sprintf(buf,"M %d", an-appl_list[appl->typ]); + l += (*appl->PassDown) (appl->drivno, buf+l,256-l); + passout(appl->typ,l,buf); + return(0); + } + return (1); +} + +int +isdn_input(int an, int len, char *buf, int dir) +{ + int l; + char *p; + isdn_appl_t *appl = &isdn_appl[an]; + + if (l = isdn_get_prot_size(an)) + { + p= isdn_get_prot(an,dir); + if((p[0] != buf[0]) || (p[1] != buf[1])) + return(0); + len -= l; + buf += l; + } + return ((*appl->PassUp) (appl->drivno, len, buf, dir)); +} + +void +isdn_accept_con_ind(int an, int cn, char serv, char serv_add, char subadr, char nl, char *num) +{ + int l; + char buf[32]; + + an&= 0xf; + l = sprintf(buf, "a %d %d %d %d %c %d %d %s", an, cn ,serv, serv_add + , subadr,(u_char) num[0], nl, num + 1); + passout(an,l,buf); +} + +void +isdn_info(int an, int typ, int len, char *data) +{ + int l; + char buf[64]; + u_short no; + + if(an < Isdn_Appl) + no= isdn_appl[an].typ; + else no= an&0xf; + + if(no > Isdn_Typ) no= 3; + + if(len>48) len= 48; + data[len]= 0; + l = sprintf(buf,"i %d %d %d %s", an, typ, len, data); + passout(no,l,buf); +} + +static void +isdn_check() +{ + int i; + + isdn_timeout= 0; + for(i= 0; i < Isdn_Ctrl; i++) + { + int an; + isdn_ctrl_t *ctrl = &isdn_ctrl[i]; + + if((an= ctrl->appl) < Isdn_Appl) + { + isdn_appl_t *appl = &isdn_appl[an]; + + if(appl->timeout) + { + isdn_timeout= 1; + if(time.tv_sec > (ctrl->lastact + (appl->timeout))) + { + isdn_disconnect(an,0); + break; + } + } + } + } + + if(isdn_timeout) + { + timeout(isdn_check,0,hz/2); + } +} + +void +isdn_conn_ind(int an, int cn, int dial) +{ + isdn_appl_t *appl = &isdn_appl[an]; + int l; + char buf[10]; + + if (appl->Connect) + (*appl->Connect) (appl->drivno); + + l = sprintf(buf,"C %d %d %d", an-appl_list[appl->typ], cn, dial); + passout(appl->typ,l,buf); + if((isdn_timeout == 0) && appl->timeout) + { + isdn_timeout= 1; + timeout(isdn_check,0,hz/2); + } +} + +void +isdn_disconn_ind(int an) +{ + isdn_appl_t *appl = &isdn_appl[an]; + int l; + char buf[10]; + + if(( an < 0) || (an >= Isdn_Appl)) + return; + + appl->state= 0; + if (appl->DisConn) + (*appl->DisConn) (appl->drivno); + l = sprintf(buf,"D %d", an-appl_list[appl->typ]); + passout(appl->typ,l,buf); +} + +void +isdn_disconnect(int an, int rea) +{ + isdn_appl_t *appl = &isdn_appl[an]; + + if (ISBUSY(appl->ctrl)) + { + int x; + x = splhigh(); + (*isdn_ctrl[appl->ctrl].disconnect)(appl->ctrl,rea); + splx(x); + } +} + +static void +passout(int unit, int l, char *buf) +{ + int x; + + x = splhigh(); + if ((bufind[unit] + l) >= 256) + { + splx(x); + return; + } + bcopy(buf,&buffer[unit][bufind[unit]],l); + bufind[unit] += l; + buffer[unit][bufind[unit]++]= 0; + if (r_flags & (1<<unit)) + { + r_flags &= ~(1 << unit); + wakeup((caddr_t) buffer[unit]); + } + splx(x); +} + +#endif /* NISDN > 0 */ diff --git a/sys/gnu/isdn/isdn_ioctl.h b/sys/gnu/isdn/isdn_ioctl.h new file mode 100644 index 0000000..ff49486 --- /dev/null +++ b/sys/gnu/isdn/isdn_ioctl.h @@ -0,0 +1,136 @@ +static char _isdn_ioctl_id[] = "@(#)$Id: isdn_ioctl.h,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: isdn_ioctl.h,v $ + * + ******************************************************************************/ + + +#pragma pack (1) +typedef struct +{ + u_char protokoll; + u_char length; + u_short data_length; + u_char link_addr_a; + u_char link_addr_b; + u_char modulo_mode; + u_char window_size; + u_char xid; +} dlpd_t; + +typedef struct +{ + u_char protokoll; + u_char length; + u_short lic, hic, ltc, htc, loc, hoc; + u_char modulo_mode; +}ncpd_t; + +typedef struct +{ + u_char length; + u_short lic, hic, ltc, htc, loc, hoc; + u_char modulo_mode; +}ncpi_t; + +typedef struct +{ + u_char stat; + u_char length; + u_char no[124]; +} telno_t; + +#pragma pack () + +typedef struct +{ + short appl; + dlpd_t dlpd; + ncpd_t ncpd; + u_long timeout; + u_char prot; + int (*PassUp)(); /* pass data from isdn interface upstream to appl. */ + int (*PassUpInfo)(); /* pass info from isdn interface upstream to appl. */ + int (*PassDown)(); /* get data from application */ + int (*Connect)(); /* Connect Indikation */ + int (*DisConn)(); /* Disconnect Indikation */ + short drivno; /* Number of the high level Driver */ + char ctrl; + char typ; + short state; + short listen_state; + u_long send_err; +} isdn_appl_t; + +typedef struct +{ + char ctrl; + char islisten; + short unit; + short appl; + int (*connect)(); + int (*listen)(); + int (*accept)(); + int (*disconnect)(); + int (*output)(); + int (*state)(); + short o_len; + char *o_buf; + time_t lastact; + u_long send_err; + u_long rcv_err; +} isdn_ctrl_t; + +typedef struct +{ + short appl; + dlpd_t dlpd; + ncpd_t ncpd; + u_long timeout; + u_char prot; +} isdn_param; + +typedef struct +{ + short appl; + short ctrl; + u_char b_channel; + u_long inf_mask; + u_char out_serv; + u_char out_serv_add; + u_char src_subadr; + u_char spv; + telno_t telno; +} dial_t; + +typedef struct +{ + short appl; + short ctrl; + u_long inf_mask; + u_short subadr_mask; + u_short si_mask; +} listen_t; + +#define ISBUSY(x) (((x) & 0x80) == 0) +#define ISFREE(x) (((x) & 0x80) == 0x80) +#define TELNO_VALID 1 +#define TELNO_PROMISC 2 + +#define N_ISDN_CTRL 2 + +#define ISDN_DIAL _IOWR('I',1,dial_t) +#define ISDN_LISTEN _IOWR('I',2,listen_t) +#define ISDN_ACCEPT _IOWR('I',3,int) +#define ISDN_HANGUP _IOWR('I',4,int) +#define ISDN_SET_PARAM _IOWR('I',8,isdn_param) +#define ISDN_GET_PARAM _IOWR('I',9,isdn_param) diff --git a/sys/gnu/scsi/nic5000.c b/sys/gnu/scsi/nic5000.c new file mode 100644 index 0000000..b885dca --- /dev/null +++ b/sys/gnu/scsi/nic5000.c @@ -0,0 +1,1467 @@ +static char rcsid[] = "@(#)$Id: nic5000.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: nic5000.c,v $ + * + ******************************************************************************/ + +/* + * + * Copyright (c) 1994 Dietmar Friede (dietmar@friede.de) All rights reserved. + * FSF/FSAG GNU Copyright applies + * + * A low level driver for the NICCY-5000 ISDN/SCSI device + * + */ + +#include "snic.h" +#if NSNIC > 0 + +#define SPLSNIC splbio +#define ESUCCESS 0 +#define SNIC_RETRIES 8 +#include "sys/types.h" +#include "sys/param.h" +#include "sys/ioctl.h" +#include "sys/malloc.h" +#include "sys/kernel.h" + +#include "scsi/scsi_all.h" +#include "scsi/scsiconf.h" +#include "isdn/isdn_ioctl.h" +#include "i386/isa/niccyreg.h" +#include "scsi/scsi_nic.h" +/* #define NETBSD */ + +#undef SCSI_NOMASK +#define OPEN 1 +#define LOAD_HEAD 2 +#define LOAD_DATA 4 +#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)) + +#define SNICOUTSTANDING 2 + +extern int hz; + +struct snic_data +{ + struct scsi_switch *sc_sw; /* address of scsi low level switch */ + int ctrl; /* so they know which one we want */ + int targ; /* our scsi target ID */ + int lu; /* out scsi lu */ + int cmdscount; /* cmds allowed outstanding by board*/ + int xfer_block_wait; + struct scsi_xfer *free_xfer; + struct scsi_xfer scsi_xfer[SNICOUTSTANDING]; /* XXX */ +}; + +struct snic_driver +{ + int size; + struct snic_data **snic_data; +}*snic_driver; + +static int next_snic_unit = 0; +static unsigned dnlnum = 0; + +static u_char ack_msg= 0xff; +static u_char snic_nxt_b; + +typedef enum +{ + DISCON, ISDISCON, DIAL, CALLED, CONNECT, IDLE, ACTIVE, WAITING, WAIT_ACK +} io_state; + +typedef struct +{ + char ctrl; + u_char msg_nr; + short plci; + short ncci; + short state; + Buffer o_buf; +} chan_t; + +struct snic_softc +{ + short sc_stat; + u_char sc_flags; + u_char sc_unit; + u_char sc_ctrl; + u_char sc_type; + u_short sc_istat; + struct scsi_msg sc_icmd; + Buffer sc_imsg; + Header sc_imsg0; + u_short sc_ostat; + struct scsi_msg sc_ocmd; + Buffer sc_omsg; + chan_t sc_chan[2]; + u_char sc_state_ind[8]; + u_char sc_gotack; +} snic_sc[NSNIC]; + +extern isdn_appl_t isdn_appl[]; +extern isdn_ctrl_t isdn_ctrl[]; +extern u_short isdn_state; +extern int ispy_applnr; +extern int Isdn_Appl, Isdn_Ctrl, Isdn_Typ; +extern void isdn_start_out(); + +static old_spy= 0; +static void snic_interupt(); +static int snic_get_msg(); +static void snic_start(); + +int snic_connect(), snic_listen(), snic_disconnect(), snic_accept(); +int snic_output(); + +#ifdef NETBSD +int snicattach(int ctrl, struct scsi_switch *scsi_switch, int physid, int *sunit) +{ + int targ, lu; +#else /* FreeBSD */ +int snicattach(int ctrl, int targ, int lu, struct scsi_switch *scsi_switch) +{ +#endif + int unit,i; + struct snic_data *snic, **snicrealloc; + struct snic_softc *sc; + int cn; + isdn_ctrl_t *ctrl0, *ctrl1; + +#ifdef NETBSD + targ = physid >> 3; + lu = physid & 7; +#endif + + if(next_snic_unit >= NSNIC) + return(0); + + unit = next_snic_unit; + if (next_snic_unit == 0) + { + snic_driver = + malloc(sizeof(struct snic_driver),M_DEVBUF,M_NOWAIT); + if(!snic_driver) + { + printf("snic%d: malloc failed\n",unit); + return(0); + } + bzero(snic_driver,sizeof(snic_driver)); + snic_driver->size = 0; + } + next_snic_unit++; + + if(unit >= snic_driver->size) + { + snicrealloc = + malloc(sizeof(snic_driver->snic_data) * next_snic_unit, + M_DEVBUF,M_NOWAIT); + if(!snicrealloc) + { + printf("snic%d: malloc failed\n",unit); + return(0); + } + /* Make sure we have something to copy before we copy it */ + bzero(snicrealloc,sizeof(snic_driver->snic_data) * next_snic_unit); + if(snic_driver->size) + { + bcopy(snic_driver->snic_data,snicrealloc, + sizeof(snic_driver->snic_data) * snic_driver->size); + free(snic_driver->snic_data,M_DEVBUF); + } + snic_driver->snic_data = snicrealloc; + snic_driver->snic_data[unit] = NULL; + snic_driver->size++; + } + + if(snic_driver->snic_data[unit]) + { + return(0); + } + + snic = snic_driver->snic_data[unit] = + malloc(sizeof(struct snic_data),M_DEVBUF,M_NOWAIT); + if(!snic) + { + printf("snic%d: malloc failed\n",unit); + return(0); + } +#ifdef NETBSD + *sunit= unit; +#endif + bzero(snic,sizeof(struct snic_data)); + + snic->sc_sw = scsi_switch; + snic->ctrl = ctrl; + snic->targ = targ; + snic->lu = lu; + snic->cmdscount = SNICOUTSTANDING; /* XXX (ask the board) */ + + i = snic->cmdscount; + while(i-- ) + { + snic->scsi_xfer[i].next = snic->free_xfer; + snic->free_xfer = &snic->scsi_xfer[i]; + } + + sc = &snic_sc[unit]; + sc->sc_ctrl = -1; + sc->sc_gotack= 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.Data[5]; + ctrl1->o_buf = &sc->sc_chan[1].o_buf.Data[5]; + + ctrl0->listen = ctrl1->listen = snic_listen; + ctrl0->disconnect = ctrl1->disconnect = snic_disconnect; + ctrl0->accept = ctrl1->accept = snic_accept; + ctrl0->connect = ctrl1->connect = snic_connect; + ctrl0->output = ctrl1->output = snic_output; + ctrl0->unit = ctrl1->unit = unit; + ctrl0->appl = ctrl1->appl = -1; + ctrl0->o_len = ctrl1->o_len = -1; + sc->sc_flags= LOAD_ENTITY; + return(1); +} + +static +struct scsi_xfer *snic_get_xs(int unit) +{ + struct scsi_xfer *xs; + struct snic_data *snic; + int s; + + snic = snic_driver->snic_data[unit]; + if (xs = snic->free_xfer) + { + snic->free_xfer = xs->next; + xs->flags = 0; + } + return(xs); +} + +static void +snic_free_xs(int unit, struct scsi_xfer *xs) +{ + struct snic_data *snic; + + snic = snic_driver->snic_data[unit]; + xs->next = snic->free_xfer; + snic->free_xfer = xs; +} + +static void +snic_timout(int unit) +{ + struct snic_softc * sc= &snic_sc[unit&0xff]; + + if(sc->sc_istat&0x100) + { + snic_interupt(unit); + return; + } + if(sc->sc_istat & 2) + sc->sc_istat= sc->sc_ostat= 0; + else if((sc->sc_istat & 0x200) == 0 ) return; + if(sc->sc_ostat & 0xff) + { + sc->sc_istat|= 0x200; + timeout(snic_timout,unit,2); + return; + } + if(sc->sc_gotack) snic_start(unit); + snic_get_msg(unit); +} + +static int +isdn_small_interupt(int unit, struct scsi_xfer *xs) +{ + struct snic_data *snic = snic_driver->snic_data[unit]; + struct snic_softc * sc= &snic_sc[unit]; + Header *msg = &sc->sc_imsg0; + int c; + + switch (msg->Type) + { + case 0: + if(sc->sc_istat&0x200) + break; + sc->sc_istat|= 0x200; + timeout(snic_timout,unit,2); + break; + case 0xff: + sc->sc_gotack= 1; + break; + case 0xfe: +printf("f"); + sc->sc_gotack= 1; + for(c= 0; c < 2; c++) + { + chan_t *chan = &sc->sc_chan[c]; + if(chan->state == WAIT_ACK) + { + chan->state = WAITING; + sc->sc_ostat |= c?0x800:0x400; + } + } + break; + case 0xfd: +printf("fd"); + break; + default: + return(0); + } + sc->sc_istat&= ~0xff; + sc->sc_imsg0.Type= 0; + return(1); +} + +static void +snic_get_done(int unit, struct scsi_xfer *xs) +{ + struct snic_data *snic = snic_driver->snic_data[unit]; + struct snic_softc * sc= &snic_sc[unit]; + Header *msg = &sc->sc_imsg0; + int len, error; + + error= xs->error; + + switch(error) + { + case XS_NOERROR: + if(xs->datalen == 0) + sc->sc_imsg.h.Type= 0; + + if(isdn_small_interupt(unit,xs)) break; + + if(xs->datalen < (len=(msg->DataLen + 10))) + { + struct scsi_msg *scsi_cmd= &sc->sc_icmd; + /* resubmit it */ + + sc->sc_imsg.h.Type= 0xba; + scsi_cmd->len[1]= (len>>8)&0xff; + scsi_cmd->len[2]= len&0xff; + xs->retries= SNIC_RETRIES; + xs->error = XS_NOERROR; + xs->flags &= ~ITSDONE; + xs->data = (char *) &sc->sc_imsg; + xs->datalen = len; + xs->resid = len; + + if ((*(snic->sc_sw->scsi_cmd))(xs) == SUCCESSFULLY_QUEUED) + { + return; + } + error= xs->error | 0x1000; + break; + } + if(xs->datalen <= 10) + { + sc->sc_istat|= 0x400; + sc->sc_imsg.h = sc->sc_imsg0; + } + sc->sc_imsg0.Type= 0; + break; + + case XS_TIMEOUT: + case XS_BUSY: + case XS_DRIVER_STUFFUP: + break; + default: + printf("snic%d: unknown error %x\n",unit,xs->error); + } + + if(error) + { + sc->sc_imsg.h.Type= sc->sc_imsg0.Type= 0; + sc->sc_istat&= 0x200; + if((sc->sc_istat&0x200) == 0) + { + sc->sc_istat= 0x200; + timeout(snic_timout,unit,2); + } + } + + snic_free_xs(unit,xs); + if(sc->sc_istat&0x4ff == 0x400 ) + sc->sc_istat|= 1; + if(sc->sc_istat&0xff) + { + snic_interupt(unit); + return; + } + if(sc->sc_gotack) snic_start(unit); + if(sc->sc_istat & 0x200) + return; + sc->sc_istat|= 0x200; + timeout(snic_timout,unit,2); +} + +static int +snic_get_msg(unit) +int unit; +{ + struct snic_data *snic = snic_driver->snic_data[unit]; + struct snic_softc * sc= &snic_sc[unit]; + struct scsi_msg *scsi_cmd= &sc->sc_icmd; + struct scsi_xfer *xs; + Header *data= &sc->sc_imsg0; + int retval; + + if(sc->sc_istat&0xff) + return(-1); + sc->sc_istat |= 1; + + data->Type= 0xbb; + sc->sc_istat &= ~0x200; + + bzero(scsi_cmd, sizeof(struct scsi_msg)); + bzero(data,10); + + scsi_cmd->op_code = GET_MSG_COMMAND; + scsi_cmd->len[2]= 10; + + xs = snic_get_xs(unit); + if(!xs) + { + sc->sc_istat&= ~0xff; + data->Type= 0; + return(EBUSY); + } + + xs->flags |= (INUSE | SCSI_DATA_IN | SCSI_NOSLEEP); + xs->adapter = snic->ctrl; + xs->targ = snic->targ; + xs->lu = snic->lu; + xs->retries = SNIC_RETRIES; + xs->timeout = 2000; + xs->cmd = (struct scsi_generic *) scsi_cmd; + xs->cmdlen = sizeof(struct scsi_msg); + xs->data = (char *) data; + xs->datalen = 10; + xs->resid = 10; + xs->when_done = snic_get_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->bp = NULL; + xs->error = XS_NOERROR; + + if(retval = (*(snic->sc_sw->scsi_cmd))(xs)) + { + sc->sc_istat= ~0xff; + data->Type= 0; + snic_free_xs(unit,xs); + } + return (retval); +} + +static void +snic_put_done(int unit, struct scsi_xfer *xs) +{ + int retval; + struct snic_data *snic = snic_driver->snic_data[unit]; + struct snic_softc * sc= &snic_sc[unit]; + Header *b= (Header *) xs->data; + int c; + + sc->sc_ostat&= ~0xff; + if(xs->error != XS_NOERROR) + { + snic_free_xs(unit,xs); + switch(b->Type) + { + case 0: + return; + case 0xff: + sc->sc_ostat|= 0x100; + return; + case BD_DATA_B3_REQ | 0x40: + case BD_DATA_B3_REQ: + sc->sc_ostat|= 0x400; + return; + default: + sc->sc_ostat|= 0x200; + return; + } + } + + snic_free_xs(unit,xs); + + c= 0; + switch(b->Type) + { + case 0xff: break; + case BD_DATA_B3_REQ | 0x40: + c= 1; + case BD_DATA_B3_REQ: + sc->sc_chan[c].state = WAIT_ACK; + break; + default: + b->Type= 0; + } + + if(sc->sc_istat&0x100) + { + snic_interupt(unit); + return; + } + + if(sc->sc_ostat&0x100) + { + sc->sc_ostat&= ~0x100; + if(snic_put_msg(unit,&ack_msg,1,0)) + sc->sc_ostat|= 0x100; + else return; + } + + if(sc->sc_gotack) snic_start(unit); + if(sc->sc_istat&0x200) + return; + sc->sc_istat|= 0x200; + timeout(snic_timout,unit,2); +} + +static void +snic_start(int unit) +{ + int retval; + struct snic_softc * sc= &snic_sc[unit]; + Header *b; + int c; + + if(sc->sc_ostat&0x200) + { + b= &sc->sc_omsg.h; + sc->sc_ostat&= ~0x200; + if(snic_put_msg(unit,b, b->DataLen+10,2)) + sc->sc_ostat|= 0x200; + else return; + } + + + for(c= 0; c<2; c++) + { + int cc= (snic_nxt_b++)&1; + u_short m= 0x400 << cc; + + if(sc->sc_ostat&m) + { + chan_t *chan= &sc->sc_chan[cc]; + b= &chan->o_buf.h; + sc->sc_ostat&= ~m; + if(chan->state == WAITING) + { + chan->state= ACTIVE; + if(snic_put_msg(unit,b, b->DataLen+10,4)) + { + chan->state= WAITING; + sc->sc_ostat|= m; + } + else return; + } + } + } +} + +int +snic_put_msg(int unit, Header *data, unsigned len, int w) +{ + struct snic_softc *sc = &snic_sc[unit]; + struct scsi_msg *scsi_cmd = &sc->sc_ocmd; + int retval; + struct scsi_xfer *xs; + struct snic_data *snic = snic_driver->snic_data[unit]; + + if(data->Type==0) + return(0); + + if(sc->sc_ostat&0xff) + return(EBUSY); + + sc->sc_ostat |= 1; + if((data->Type == 0xa8) || (data->Type == 0xe8)) + { + if(sc->sc_gotack==0) + { + sc->sc_ostat &= ~0xff; + return(EBUSY); + } + } + if(data->Type != 0xff) + sc->sc_gotack= 0; + bzero(scsi_cmd, sizeof(struct scsi_msg)); + + scsi_cmd->op_code = PUT_MSG_COMMAND; + if(len > 2063) + { + printf("snic%d: unsupported length %d\n",unit,len); + sc->sc_ostat &= ~0xff; + return(ENODEV); + } + scsi_cmd->len[1]= (len >> 8) & 0xff; + scsi_cmd->len[2]= len & 0xff; + + xs = snic_get_xs(unit); + if(!xs) + { + printf("snic pm%d: busy %d\n", unit, w); + sc->sc_ostat &= ~0xff; + return(EBUSY); + } + xs->flags |= (INUSE | SCSI_DATA_OUT | SCSI_NOSLEEP); + xs->adapter = snic->ctrl; + xs->targ = snic->targ; + xs->lu = snic->lu; + xs->retries = SNIC_RETRIES; + xs->timeout = 2000; + xs->cmd = (struct scsi_generic *) scsi_cmd; + xs->cmdlen = sizeof(struct scsi_msg); + xs->data = (char *)data; + xs->datalen = len; + xs->resid = len; + xs->when_done = snic_put_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->bp = NULL; + xs->error = XS_NOERROR; + + if(retval = (*(snic->sc_sw->scsi_cmd))(xs)) + { + sc->sc_ostat &= ~0xff; + snic_free_xs(unit,xs); + return(EBUSY); + } + + return(0); +} + +int +snicopen(dev_t dev, int flag) +{ + struct snic_softc *sc; + u_char unit; + int x; + unsigned error; + u_char b= 0xff; + + unit = minor(dev); + /* minor number out of limits ? */ + if (unit >= next_snic_unit) + return (ENXIO); + sc = &snic_sc[unit]; + + x= splhigh(); + /* Card busy ? */ + if (sc->sc_flags & 7) + { + splx(x); + return (EBUSY); + } + sc->sc_flags |= OPEN; + + if(sc->sc_flags & LOAD_ENTITY) + { + snic_get_msg(unit); +/* + if(snic_put_msg(unit,(Header *) &ack_msg,1,5)) + sc->sc_ostat|= 0x100; +*/ + } + + splx(x); + return (0); +} + +int +snicclose(dev_t dev, int flag) +{ + struct snic_softc *sc = &snic_sc[minor(dev)]; + + sc->sc_flags &= ~7; + return (0); +} + +int +snicioctl(dev_t dev, int cmd, caddr_t data, int flag) +{ + int error; + u_char unit= minor(dev); + int i, x; + struct snic_softc *sc = &snic_sc[minor(dev)]; + Buffer *b= &sc->sc_omsg; + + error = 0; + x= splhigh(); + while(sc->sc_ostat || (sc->sc_gotack==0)) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "ioctl", 2); + if (error != EWOULDBLOCK) + { + splx(x); + return(error); + } + } + + switch (cmd) + { + case NICCY_DEBUG: + data[0]= 0x50; + bcopy(sc->sc_state_ind,data+1,8); + break; + case NICCY_LOAD: + { + struct head *head = (struct head *) data; + int len, l, off; + + bzero(b, 22); + b->h.Type = MD_DNL_MOD_REQ; + sc->sc_type = head->typ; + b->h.SubType = head->typ; + b->h.DataLen = 12; + bcopy(head->nam, b->Data, 8); + bcopy(&head->len, &b->Data[8], 4); + + sc->sc_flags |= LOAD_HEAD; + sc->sc_stat = -1; + while((error= snic_put_msg(unit,(Header *) b,22,6)) == EBUSY) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic1", 1); + if (error != EWOULDBLOCK) + break; + } + if(error == 0) + { + while (sc->sc_flags & LOAD_HEAD) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic2", 1); + if (error != EWOULDBLOCK) + break; + error= 0; + } + } + if (sc->sc_flags & 7) + sc->sc_flags = (sc->sc_flags & ~7 ) | OPEN; + if(error) + { + head->status = sc->sc_stat; + splx(x); + return (error); + } + + len= head->d_len; + off= 0; + while(len > 0) + { + while(sc->sc_ostat || (sc->sc_gotack==0)) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic7", 2); + if (error != EWOULDBLOCK) + { + splx(x); + return(error); + } + } + bzero(b,10); + b->h.Type = MD_DNL_MOD_DATA; + sc->sc_type = head->typ; + b->h.SubType = head->typ; + l= min(len,512); + len-= l; + b->h.DataLen = l + 8; + b->h.Number = dnlnum++; + b->h.MoreData= len>0; + bcopy(head->nam, b->Data, 8); + if(error= copyin(head->data+off, b->Data+8, l)) + { + splx(x); + return(error); + } + off+= l; + sc->sc_flags |= LOAD_DATA; + sc->sc_stat = -1; + + while((error= snic_put_msg(unit,(Header *) b,b->h.DataLen+10,7)) == EBUSY) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic3", 1); + if (error != EWOULDBLOCK) + break; + } + } + + if(error == 0) + { + while (sc->sc_flags & LOAD_DATA) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic4", 1); + if (error != EWOULDBLOCK) + break; + error= 0; + } + } + if (sc->sc_flags & 7) + sc->sc_flags = (sc->sc_flags & ~7 ) | OPEN; + head->status = sc->sc_stat; + splx(x); + return (error); + } + case NICCY_SET_CLOCK: + bzero(b,10); + b->h.Type = MD_SET_CLOCK_REQ; + b->h.DataLen = 14; + bcopy(data, b->Data,14); + while((error= snic_put_msg(unit,(Header *) b,24,8)) == EBUSY) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic5", 1); + if (error != EWOULDBLOCK) + break; + } + splx(x); + return (error); + case NICCY_SPY: + bzero(b,10); + b->h.Type = MD_MANUFACT_REQ; + b->h.SubType = 18; + b->h.DataLen = 1; +/* 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= b->Data[0]= data[0]; + while((error= snic_put_msg(unit,(Header *) b,11,9)) == EBUSY) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic6", 1); + if (error != EWOULDBLOCK) + break; + } + splx(x); + return (error); + case NICCY_RESET: + bzero(b,10); + b->h.Type = MD_RESET_REQ; + while((error= snic_put_msg(unit,(Header *) b,10,9)) == EBUSY) + { + error = tsleep((caddr_t) sc, PZERO | PCATCH, "nic6", 1); + if (error != EWOULDBLOCK) + break; + } + sc->sc_flags|= LOAD_ENTITY; + splx(x); + return (error); + + default: + error = ENODEV; + } + splx(x); + return (error); +} + +#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) +#define con_resp(unit,pl,rea) en_q(unit,DD_CONN_RSP,0, pl, 1,(u_char *) &rea) + +static int +en_q(int unit, int t, int st, int pl, int l, u_char *val) +{ + struct snic_softc * sc= &snic_sc[unit]; + Buffer *b= &sc->sc_omsg; + int error= 0; + + if(b->h.Type) + { + return(EBUSY); + } + bzero(b,10); +if(( t >= 0x80) && CHAN(pl) && ((t & 0x40) == 0)) +printf("?%x %x",t,pl); +if(t>=0x40) +printf("S%x %x",t,pl); + + b->h.Type = t; + b->h.SubType = st; + b->h.PLCI = pl; + if(l) + { + b->h.DataLen= l; + bcopy(val,b->Data,l); + } + + if((error= snic_put_msg(unit,(Header *) b,10+l,13)) == EBUSY) + { + sc->sc_ostat|= 0x200; + return(0); + } + return(error); +} + +static int +reset_plci(int w, chan_t * chan, short 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->o_buf.h.Type= 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 +state_ind(int unit, int api, int spv) +{ + u_char buf[3]; + + buf[0]= unit; buf[1]= api; buf[2]= spv; + return(en_q(unit, MD_STATE_IND,0, 0, 3, buf)); +} + +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)); +} + +int +snic_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)); +} + +int +snic_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)); +} + +int +snic_disconnect(int cn, int rea) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + chan_t *chan = &snic_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); +} + +int +snic_accept(int cn, int an, int rea) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + struct snic_softc *sc = &snic_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)); +} + +int +snic_output(int cn) +{ + isdn_ctrl_t *ctrl = &isdn_ctrl[cn]; + struct snic_softc *sc = &snic_sc[ctrl->unit]; + chan_t *chan = &sc->sc_chan[C_CHAN(cn)]; + int len= ctrl->o_len; + Buffer *b= &chan->o_buf; + int error= 0; + + if (sc->sc_state_ind[1] || (chan->ncci == -1)) + return (ENODEV); + + if(chan->state != IDLE) + return(EBUSY); + chan->state= WAITING; + + bzero(b,10); + + b->h.Type = BD_DATA_B3_REQ; + if(C_CHAN(cn)) b->h.Type |= 0x40; + b->h.PLCI = chan->plci; + b->h.DataLen= len+5; + *(u_short *) b->Data = chan->ncci; + *(u_short *) &b->Data[2] = 0; + b->h.Number = b->Data[4] = chan->msg_nr++; + + chan->state = ACTIVE; + ctrl->lastact = time.tv_sec; + + if((error= snic_put_msg(ctrl->unit,(Header *) b,15+len,14)) == EBUSY) + { + sc->sc_ostat|= C_CHAN(cn)?0x800:0x400; + chan->state= WAITING; + return(0); + } + return(error); +} + +static void +badstate(Header *h, int n) +{ + int i; + u_char *p= (u_char *)h; + printf("Niccy: not implemented %x.%x len %d at %d", h->Type, + h->SubType, h->DataLen,n); + if(h->DataLen) + { + p+= 10; + for(i=0; i < h->DataLen ; i++) printf(" %x",p[i]); + } + printf("\n"); +} + +unsigned SavMsgTyp; + +static void +snic_interupt(unsigned unit) +{ + struct snic_softc * sc= &snic_sc[unit&0xff]; + Buffer *msg; + chan_t *chan; + u_short n, mb, c, pl, err = 0; + isdn_ctrl_t *ctrl; + isdn_appl_t *appl; + int error= 0; + + msg = &sc->sc_imsg; + chan= NULL; + ctrl= NULL; + appl= NULL; + +SavMsgTyp= msg->h.Type; + + if(sc->sc_istat & 2) + return; + + if(sc->sc_ostat&0xff) + { + sc->sc_istat|= 0x101; + if(sc->sc_istat&0x200) + return; + sc->sc_istat|= 0x200; + timeout(snic_timout,unit,2); + return; + } + + mb= 0; + pl = msg->h.PLCI; + if(pl && (msg->h.Type >= 0x40) && (msg->h.Type < 0xfd) && (msg->h.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->h.Type >= 0x80) + { + mb= msg->h.Type & 0x40; + msg->h.Type &= 0xbf; + } + } +SavMsgTyp|= 0x100; + +if(msg->h.Type>=0x40) +printf("I%x %x %x",msg->h.Type,pl,mb); + switch (msg->h.Type) + { + case 0x01: /* INIT IND */ + case 0x15: /* POLL IND */ + error= en_q(unit,msg->h.Type|0x20,0,0,0,NULL); + break; + case 0x04: /* DNL MOD CONF */ + sc->sc_stat = msg->Data[0]; + if (sc->sc_flags & 7) + sc->sc_flags = (sc->sc_flags & ~7) | OPEN; + break; + case 0x06: /* DNL MOD IND */ + sc->sc_stat = msg->Data[0]; + error= en_q(unit,msg->h.Type|0x20,sc->sc_type,0,1, &msg->Data[1]); + if(sc->sc_flags & LOAD_ENTITY) + { + sc->sc_istat= sc->sc_ostat= 2; + timeout(snic_timout,unit,hz); + msg->h.Type= 0; + return; + } + if (sc->sc_flags) + sc->sc_flags = OPEN; + break; + case 0x0e: /* SET CLOCK CONF */ + error= state_ind(unit,1,0); + break; + case 0x16: /* STATE IND */ + if(sc->sc_flags & LOAD_ENTITY) + { + if(sc->sc_flags & 7) + sc->sc_flags = OPEN; + else sc->sc_flags= 0; + } + bcopy( msg->Data, sc->sc_state_ind, 8); + error= en_q(unit,msg->h.Type|0x20,0,0,0,NULL); + break; + case 0x17: /* STATE RESP */ + bcopy( msg->Data, sc->sc_state_ind, 8); + break; + case 0x1e: /* MANUFACT CONF */ + if(msg->h.SubType == 18) + break; + badstate(&msg->h,1); + break; + case 0x1f: /* MANUFACT IND */ + if(msg->h.SubType == 19) + { + isdn_input(ispy_applnr, msg->h.DataLen, msg->Data,0); + error= en_q(unit,msg->h.Type|0x20,msg->h.SubType,0,0,NULL); + break; + } + badstate(&msg->h,2); + 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)) + { + 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)) + { + 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 */ + 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 */ + 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 */ + 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 */ + err = *(u_short *) msg->Data; + if (err) + { + error= discon_req(4, unit, pl, 0, err); + break; + } + + switch (msg->h.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 */ + err = *(u_short *) msg->Data; + if (err) + { + error= discon_req(5, unit, pl, 0, err); + break; + } + error= con_resp(unit, pl, err); + break; + + case 0x82: /* CONNECT B3 CONF */ + err = *(u_short *) (msg->Data + 2); + n = *(u_short *) msg->Data; + + if (err) + { + 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; + 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; + 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) + { + error= discon_req(7, unit, pl, 0, err); + break; + } + break; + case 0x86: /* DISCONNECT B3 IND */ + 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) + { +printf("e%x\n",err); + ctrl->send_err++; + isdn_appl[ctrl->appl].send_err++; + } + chan->state = IDLE; + chan->o_buf.h.Type= 0; + ctrl->o_len = 0; + isdn_start_out(chan->ctrl); + break; + + case 0x89: /* DATA B3 IND */ + if(ISFREE(ctrl->appl)) + break; + if(isdn_input(ctrl->appl, msg->h.DataLen-5, msg->Data+5,ctrl->islisten)) + ctrl->lastact = time.tv_sec; + break; + + default: + badstate(&msg->h,3); + break; + } + +fin: + if(error) + { +printf("x%x %x %x %x %x\n",error,msg->h.Type,sc->sc_istat,sc->sc_ostat,sc->sc_omsg.h.Type); + sc->sc_istat|= 0x101; + if(sc->sc_istat&0x200) + return; + sc->sc_istat|= 0x200; + timeout(snic_timout,unit,2); + return; + } + + msg->h.Type= 0; + if(snic_put_msg(unit,(Header *) &ack_msg,1,15)) + sc->sc_ostat|= 0x100; + sc->sc_istat= 0x200; + snic_get_msg(unit); +} + +#endif /* NSNIC > 0 */ diff --git a/sys/gnu/scsi/scsi_nic.h b/sys/gnu/scsi/scsi_nic.h new file mode 100644 index 0000000..4847df8 --- /dev/null +++ b/sys/gnu/scsi/scsi_nic.h @@ -0,0 +1,53 @@ +static char rcsid[] = "@(#)$Id: scsi_nic.h,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: scsi_nic.h,v $ + * + ******************************************************************************/ + +/* + * This file defines the NICCY 5000 Interface. + * Copyright Dr. Neuhaus GmbH, Hamburg and Dietmar Friede + * +*/ +#define GET_MSG_COMMAND 0x08 +#define PUT_MSG_COMMAND 0x0a + +#pragma pack (1) +struct scsi_msg +{ + u_char op_code; + u_char dummy; + u_char len[3]; + u_char control; +}; + +typedef struct +{ + unsigned char Type; + unsigned char SubType; + unsigned short Number ; + unsigned char MoreData ; + unsigned char Reserved[1] ; + unsigned short DataLen ; + unsigned short PLCI; +} Header; + +#define SNIC_BUF_SIZE 2048+15 + +typedef struct +{ + Header h; + unsigned char Data[SNIC_BUF_SIZE]; +} Buffer; + +#pragma pack () + |