From 34dc93c2f2a2e67b9f17f39ad8552571a143e782 Mon Sep 17 00:00:00 2001 From: obrien Date: Wed, 7 Sep 2005 09:53:35 +0000 Subject: Reorder code to not depend on an ISO-C illegal forward extern declaration. --- sys/dev/cx/if_cx.c | 3085 ++++++++++++++++++++++++++-------------------------- 1 file changed, 1542 insertions(+), 1543 deletions(-) (limited to 'sys/dev/cx') diff --git a/sys/dev/cx/if_cx.c b/sys/dev/cx/if_cx.c index 2d75f97..bdc15ad 100644 --- a/sys/dev/cx/if_cx.c +++ b/sys/dev/cx/if_cx.c @@ -229,1755 +229,1763 @@ static cx_board_t *adapter [NCX]; static drv_t *channel [NCX*NCHAN]; static struct callout led_timo [NCX]; static struct callout timeout_handle; -extern struct cdevsw cx_cdevsw; static int MY_SOFT_INTR; -/* - * Print the mbuf chain, for debug purposes only. - */ -static void printmbuf (struct mbuf *m) -{ - printf ("mbuf:"); - for (; m; m=m->m_next) { - if (m->m_flags & M_PKTHDR) - printf (" HDR %d:", m->m_pkthdr.len); - if (m->m_flags & M_EXT) - printf (" EXT:"); - printf (" %d", m->m_len); - } - printf ("\n"); -} - -/* - * Make an mbuf from data. - */ -static struct mbuf *makembuf (void *buf, u_int len) +static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td) { - struct mbuf *m, *o, *p; - - MGETHDR (m, M_DONTWAIT, MT_DATA); - - if (! m) - return 0; + int unit; + drv_t *d; - if (len >= MINCLSIZE) - MCLGET (m, M_DONTWAIT); + d = dev->si_drv1; + unit = d->chan->num; - m->m_pkthdr.len = len; - m->m_len = 0; + CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n", + unit, flag, mode)); - p = m; - while (len) { - u_int n = M_TRAILINGSPACE (p); - if (n > len) - n = len; - if (! n) { - /* Allocate new mbuf. */ - o = p; - MGET (p, M_DONTWAIT, MT_DATA); - if (! p) { - m_freem (m); - return 0; - } - if (len >= MINCLSIZE) - MCLGET (p, M_DONTWAIT); - p->m_len = 0; - o->m_next = p; + d->open_dev |= 0x1; - n = M_TRAILINGSPACE (p); - if (n > len) - n = len; - } - bcopy (buf, mtod (p, caddr_t) + p->m_len, n); + CX_DEBUG2 (d, ("cx_open done\n")); - p->m_len += n; - buf = n + (char*) buf; - len -= n; - } - return m; + return 0; } -/* - * Recover after lost transmit interrupts. - */ -static void cx_timeout (void *arg) +static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td) { drv_t *d; - int s, i, k; - - for (i = 0; i < NCX; i++) { - if (adapter[i] == NULL) - continue; - for (k = 0; k < NCHAN; ++k) { - d = channel[i * NCHAN + k]; - if (! d) - continue; - s = splhigh (); - CX_LOCK ((bdrv_t *)d->board->sys); - if (d->atimeout == 1 && d->tty && d->tty->t_state & TS_BUSY) { - d->tty->t_state &= ~TS_BUSY; - if (d->tty->t_dev) { - d->intr_action |= CX_WRITE; - MY_SOFT_INTR = 1; - swi_sched (cx_fast_ih, 0); - } - CX_DEBUG (d, ("cx_timeout\n")); - } - if (d->atimeout) - d->atimeout--; - CX_UNLOCK ((bdrv_t *)d->board->sys); - splx (s); - } - } - callout_reset (&timeout_handle, hz*5, cx_timeout, 0); -} - -static void cx_led_off (void *arg) -{ - cx_board_t *b = arg; - bdrv_t *bd = b->sys; - int s; - s = splhigh (); - CX_LOCK (bd); - cx_led (b, 0); - CX_UNLOCK (bd); - splx (s); + d = dev->si_drv1; + CX_DEBUG2 (d, ("cx_close\n")); + d->open_dev &= ~0x1; + return 0; } -/* - * Activate interupt handler from DDK. - */ -static void cx_intr (void *arg) +static int cx_modem_status (drv_t *d) { - bdrv_t *bd = arg; - cx_board_t *b = bd->board; -#ifndef NETGRAPH - int i; -#endif - int s = splhigh (); - + bdrv_t *bd = d->board->sys; + int status = 0, s = splhigh (); CX_LOCK (bd); - /* Turn LED on. */ - cx_led (b, 1); - - cx_int_handler (b); + /* Already opened by someone or network interface is up? */ + if ((d->chan->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && + (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running)) + status = TIOCM_LE; /* always enabled while open */ - /* Turn LED off 50 msec later. */ - callout_reset (&led_timo[b->num], hz/20, cx_led_off, b); + if (cx_get_dsr (d->chan)) status |= TIOCM_DSR; + if (cx_get_cd (d->chan)) status |= TIOCM_CD; + if (cx_get_cts (d->chan)) status |= TIOCM_CTS; + if (d->chan->dtr) status |= TIOCM_DTR; + if (d->chan->rts) status |= TIOCM_RTS; CX_UNLOCK (bd); splx (s); - -#ifndef NETGRAPH - /* Pass packets in a lock-free state */ - for (i = 0; i < NCHAN && b->chan[i].type; i++) { - drv_t *d = b->chan[i].sys; - struct mbuf *m; - if (!d || !d->running) - continue; - while (_IF_QLEN(&d->queue)) { - IF_DEQUEUE (&d->queue,m); - if (!m) - continue; - sppp_input (d->ifp, m); - } - } -#endif + return status; } -static int probe_irq (cx_board_t *b, int irq) +static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { - int mask, busy, cnt; - - /* Clear pending irq, if any. */ - cx_probe_irq (b, -irq); - DELAY (100); - for (cnt=0; cnt<5; ++cnt) { - /* Get the mask of pending irqs, assuming they are busy. - * Activate the adapter on given irq. */ - busy = cx_probe_irq (b, irq); - DELAY (100); - - /* Get the mask of active irqs. - * Deactivate our irq. */ - mask = cx_probe_irq (b, -irq); - DELAY (100); - if ((mask & ~busy) == 1 << irq) { - cx_probe_irq (b, 0); - /* printf ("cx%d: irq %d ok, mask=0x%04x, busy=0x%04x\n", - b->num, irq, mask, busy); */ - return 1; - } - } - /* printf ("cx%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n", - b->num, irq, mask, busy); */ - cx_probe_irq (b, 0); - return 0; -} - -static short porttab [] = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, - 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 -}; -static char dmatab [] = { 7, 6, 5, 0 }; -static char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 }; + drv_t *d; + bdrv_t *bd; + cx_chan_t *c; + struct serial_statistics *st; + int error, s; + char mask[16]; -static int cx_is_free_res (device_t dev, int rid, int type, u_long start, - u_long end, u_long count) -{ - struct resource *res; - - if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count, - RF_ALLOCATED))) - return 0; + d = dev->si_drv1; + c = d->chan; - bus_release_resource (dev, type, rid, res); + bd = d->board->sys; - return 1; -} - -static void cx_identify (driver_t *driver, device_t dev) -{ - u_long iobase, rescount; - int devcount; - device_t *devices; - device_t child; - devclass_t my_devclass; - int i, k; + switch (cmd) { + case SERIAL_GETREGISTERED: + CX_DEBUG2 (d, ("ioctl: getregistered\n")); + bzero (mask, sizeof(mask)); + for (s=0; s= NCX) - break; - } - } else { - static short porttab [] = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, - 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 - }; - /* Lets check user choise. - */ - for (k = 0; k < devcount; k++) { - if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, - &iobase, &rescount) != 0) - continue; - - for (i = 0; porttab [i] != 0; i++) { - if (porttab [i] != iobase) - continue; - if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT, - iobase, iobase + NPORT, NPORT)) - continue; - if (cx_probe_board (iobase, -1, -1) == 0) - continue; - porttab [i] = -1; - device_set_desc_copy (devices[k], "Cronyx Sigma"); - break; - } - - if (porttab [i] == 0) { - device_delete_child ( - device_get_parent (devices[k]), - devices [k]); - devices[k] = 0; - continue; - } - } - for (k = 0; k < devcount; k++) { - if (devices[k] == 0) - continue; - if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, - &iobase, &rescount) == 0) - continue; - for (i = 0; (iobase = porttab [i]) != 0; i++) { - if (porttab [i] == -1) { - continue; - } - if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT, - iobase, iobase + NPORT, NPORT)) - continue; - if (cx_probe_board (iobase, -1, -1) == 0) - continue; - - bus_set_resource (devices[k], SYS_RES_IOPORT, 0, - iobase, NPORT); - porttab [i] = -1; - device_set_desc_copy (devices[k], "Cronyx Sigma"); - break; - } - if (porttab [i] == 0) { - device_delete_child ( - device_get_parent (devices[k]), - devices [k]); - } - } - free (devices, M_TEMP); - } - - return; -} - -static int cx_probe (device_t dev) -{ - int unit = device_get_unit (dev); - int i; - u_long iobase, rescount; - - if (!device_get_desc (dev) || - strcmp (device_get_desc (dev), "Cronyx Sigma")) - return ENXIO; - - if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) { - printf ("cx%d: Couldn't get IOPORT\n", unit); - return ENXIO; - } - - if (!cx_is_free_res (dev, 0, SYS_RES_IOPORT, - iobase, iobase + NPORT, NPORT)) { - printf ("cx%d: Resource IOPORT isn't free %lx\n", unit, iobase); - return ENXIO; - } - - for (i = 0; porttab [i] != 0; i++) { - if (porttab [i] == iobase) { - porttab [i] = -1; - break; - } - } - - if (porttab [i] == 0) { - return ENXIO; - } - - if (!cx_probe_board (iobase, -1, -1)) { - printf ("cx%d: probing for Sigma at %lx faild\n", unit, iobase); - return ENXIO; - } - - return 0; -} - -static void -cx_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - unsigned long *addr; - - if (error) - return; - - KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); - addr = arg; - *addr = segs->ds_addr; -} - -static int -cx_bus_dma_mem_alloc (int bnum, int cnum, cx_dma_mem_t *dmem) -{ - int error; - - error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT, - BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1, - dmem->size, 0, NULL, NULL, &dmem->dmat); - if (error) { - if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); - else printf ("cx%d: ", bnum); - printf ("couldn't allocate tag for dma memory\n"); - return 0; - } - error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt, - BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp); - if (error) { - if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); - else printf ("cx%d: ", bnum); - printf ("couldn't allocate mem for dma memory\n"); - bus_dma_tag_destroy (dmem->dmat); - return 0; - } - error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt, - dmem->size, cx_bus_dmamap_addr, &dmem->phys, 0); - if (error) { - if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); - else printf ("cx%d: ", bnum); - printf ("couldn't load mem map for dma memory\n"); - bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); - bus_dma_tag_destroy (dmem->dmat); - return 0; - } - return 1; -} - -static void -cx_bus_dma_mem_free (cx_dma_mem_t *dmem) -{ - bus_dmamap_unload (dmem->dmat, dmem->mapp); - bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); - bus_dma_tag_destroy (dmem->dmat); -} - -/* - * The adapter is present, initialize the driver structures. - */ -static int cx_attach (device_t dev) -{ - bdrv_t *bd = device_get_softc (dev); - u_long iobase, drq, irq, rescount; - int unit = device_get_unit (dev); - char *cx_ln = CX_LOCK_NAME; - cx_board_t *b; - cx_chan_t *c; - drv_t *d; - int i; - int s; - - KASSERT ((bd != NULL), ("cx%d: NULL device softc\n", unit)); - - bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount); - bd->base_rid = 0; - bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid, - iobase, iobase + NPORT, NPORT, RF_ACTIVE); - if (! bd->base_res) { - printf ("cx%d: cannot allocate base address\n", unit); - return ENXIO; - } - - if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) { - for (i = 0; (drq = dmatab [i]) != 0; i++) { - if (!cx_is_free_res (dev, 0, SYS_RES_DRQ, - drq, drq + 1, 1)) - continue; - bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1); - break; - } - - if (dmatab[i] == 0) { - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, - bd->base_res); - printf ("cx%d: Couldn't get DRQ\n", unit); - return ENXIO; - } - } - - bd->drq_rid = 0; - bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid, - drq, drq + 1, 1, RF_ACTIVE); - if (! bd->drq_res) { - printf ("cx%d: cannot allocate drq\n", unit); - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, - bd->base_res); - return ENXIO; - } - - if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) { - for (i = 0; (irq = irqtab [i]) != 0; i++) { - if (!cx_is_free_res (dev, 0, SYS_RES_IRQ, - irq, irq + 1, 1)) - continue; - bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1); - break; - } - - if (irqtab[i] == 0) { - bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, - bd->drq_res); - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, - bd->base_res); - printf ("cx%d: Couldn't get IRQ\n", unit); - return ENXIO; - } - } - - bd->irq_rid = 0; - bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid, - irq, irq + 1, 1, RF_ACTIVE); - if (! bd->irq_res) { - printf ("cx%d: Couldn't allocate irq\n", unit); - bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, - bd->drq_res); - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, - bd->base_res); - return ENXIO; - } - - b = malloc (sizeof (cx_board_t), M_DEVBUF, M_WAITOK); - if (!b) { - printf ("cx:%d: Couldn't allocate memory\n", unit); - return (ENXIO); - } - adapter[unit] = b; - bzero (b, sizeof(cx_board_t)); - - if (! cx_open_board (b, unit, iobase, irq, drq)) { - printf ("cx%d: error loading firmware\n", unit); - free (b, M_DEVBUF); - bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, - bd->irq_res); - bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, - bd->drq_res); - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, - bd->base_res); - return ENXIO; - } - - bd->board = b; - - cx_ln[2] = '0' + unit; - mtx_init (&bd->cx_mtx, cx_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE); - if (! probe_irq (b, irq)) { - printf ("cx%d: irq %ld not functional\n", unit, irq); - bd->board = 0; - adapter [unit] = 0; - mtx_destroy (&bd->cx_mtx); - free (b, M_DEVBUF); - bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, - bd->irq_res); - bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, - bd->drq_res); - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, - bd->base_res); - return ENXIO; - } - b->sys = bd; - callout_init (&led_timo[b->num], cx_mpsafenet ? CALLOUT_MPSAFE : 0); - s = splhigh (); - if (bus_setup_intr (dev, bd->irq_res, - INTR_TYPE_NET|(cx_mpsafenet?INTR_MPSAFE:0), - cx_intr, bd, &bd->intrhand)) { - printf ("cx%d: Can't setup irq %ld\n", unit, irq); - bd->board = 0; - b->sys = 0; - adapter [unit] = 0; - mtx_destroy (&bd->cx_mtx); - free (b, M_DEVBUF); - bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, - bd->irq_res); - bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, - bd->drq_res); - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, - bd->base_res); + s = splhigh (); + CX_LOCK (bd); + cx_set_port (c, *(int *)data); + CX_UNLOCK (bd); splx (s); - return ENXIO; - } - - CX_LOCK (bd); - cx_init (b, b->num, b->port, irq, drq); - cx_setup_board (b, 0, 0, 0); - CX_UNLOCK (bd); + return 0; - printf ("cx%d: \n", b->num, b->name); +#ifndef NETGRAPH + case SERIAL_GETPROTO: + CX_DEBUG2 (d, ("ioctl: getproto\n")); + s = splhigh (); + CX_LOCK (bd); + strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" : + (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" : + (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp"); + CX_UNLOCK (bd); + splx (s); + return 0; - for (c=b->chan; cchan+NCHAN; ++c) { - if (c->type == T_NONE) - continue; - d = &bd->channel[c->num]; - d->dmamem.size = sizeof(cx_buf_t); - if (! cx_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) - continue; - d->board = b; - d->chan = c; - d->open_dev = 0; - c->sys = d; - channel [b->num*NCHAN + c->num] = d; - sprintf (d->name, "cx%d.%d", b->num, c->num); + case SERIAL_SETPROTO: + CX_DEBUG2 (d, ("ioctl: setproto\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_ASYNC) + return EBUSY; + if (d->ifp->if_drv_flags & IFF_DRV_RUNNING) + return EBUSY; + if (! strcmp ("cisco", (char*)data)) { + IFP2SP(d->ifp)->pp_flags &= ~(PP_FR); + IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; + d->ifp->if_flags |= PP_CISCO; + } else if (! strcmp ("fr", (char*)data)) { + d->ifp->if_flags &= ~(PP_CISCO); + IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE; + } else if (! strcmp ("ppp", (char*)data)) { + IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE); + d->ifp->if_flags &= ~(PP_CISCO); + } else + return EINVAL; + return 0; - switch (c->type) { - case T_SYNC_RS232: - case T_SYNC_V35: - case T_SYNC_RS449: - case T_UNIV: - case T_UNIV_RS232: - case T_UNIV_RS449: - case T_UNIV_V35: -#ifdef NETGRAPH - if (ng_make_node_common (&typestruct, &d->node) != 0) { - printf ("%s: cannot make common node\n", d->name); - channel [b->num*NCHAN + c->num] = 0; - c->sys = 0; - cx_bus_dma_mem_free (&d->dmamem); - continue; - } - NG_NODE_SET_PRIVATE (d->node, d); - sprintf (d->nodename, "%s%d", NG_CX_NODE_TYPE, - c->board->num*NCHAN + c->num); - if (ng_name_node (d->node, d->nodename)) { - printf ("%s: cannot name node\n", d->nodename); - NG_NODE_UNREF (d->node); - channel [b->num*NCHAN + c->num] = 0; - c->sys = 0; - cx_bus_dma_mem_free (&d->dmamem); - continue; - } - d->lo_queue.ifq_maxlen = IFQ_MAXLEN; - d->hi_queue.ifq_maxlen = IFQ_MAXLEN; - mtx_init (&d->lo_queue.ifq_mtx, "cx_queue_lo", NULL, MTX_DEF); - mtx_init (&d->hi_queue.ifq_mtx, "cx_queue_hi", NULL, MTX_DEF); - callout_init (&d->timeout_handle, - cx_mpsafenet ? CALLOUT_MPSAFE : 0); -#else /*NETGRAPH*/ - d->ifp = if_alloc(IFT_PPP); - if (d->ifp == NULL) { - printf ("%s: cannot if_alloc() common interface\n", - d->name); - channel [b->num*NCHAN + c->num] = 0; - c->sys = 0; - cx_bus_dma_mem_free (&d->dmamem); - continue; - } - d->ifp->if_softc = d; - if_initname (d->ifp, "cx", b->num * NCHAN + c->num); - d->ifp->if_mtu = PP_MTU; - d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; - if (!cx_mpsafenet) - d->ifp->if_flags |= IFF_NEEDSGIANT; - d->ifp->if_ioctl = cx_sioctl; - d->ifp->if_start = cx_ifstart; - d->ifp->if_watchdog = cx_ifwatchdog; - d->ifp->if_init = cx_initialize; - d->queue.ifq_maxlen = 2; - mtx_init (&d->queue.ifq_mtx, "cx_queue", NULL, MTX_DEF); - sppp_attach (d->ifp); - if_attach (d->ifp); - IFP2SP(d->ifp)->pp_tlf = cx_tlf; - IFP2SP(d->ifp)->pp_tls = cx_tls; - /* If BPF is in the kernel, call the attach for it. - * Size of PPP header is 4 bytes. */ - bpfattach (d->ifp, DLT_PPP, 4); -#endif /*NETGRAPH*/ - } - d->tty = ttyalloc (); - d->tty->t_open = cx_topen; - d->tty->t_close = cx_tclose; - d->tty->t_param = cx_param; - d->tty->t_stop = cx_stop; - d->tty->t_modem = cx_tmodem; - d->tty->t_oproc = cx_oproc; - d->tty->t_sc = d; + case SERIAL_GETKEEPALIVE: + CX_DEBUG2 (d, ("ioctl: getkeepalive\n")); + if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || + (d->ifp->if_flags & PP_CISCO) || + (c->mode == M_ASYNC)) + return EINVAL; + s = splhigh (); CX_LOCK (bd); - cx_start_chan (c, d->dmamem.virt, d->dmamem.phys); - cx_register_receive (c, &cx_receive); - cx_register_transmit (c, &cx_transmit); - cx_register_error (c, &cx_error); - cx_register_modem (c, &cx_modem); + *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0; CX_UNLOCK (bd); + splx (s); + return 0; - ttycreate(d->tty, NULL, 0, MINOR_CALLOUT, - "x%r%r", b->num, c->num); - d->devt = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 64, UID_ROOT, GID_WHEEL, 0600, "cx%d", b->num*NCHAN + c->num); - d->devt->si_drv1 = d; - callout_init (&d->dcd_timeout_handle, - cx_mpsafenet ? CALLOUT_MPSAFE : 0); - } - splx (s); - - return 0; -} + case SERIAL_SETKEEPALIVE: + CX_DEBUG2 (d, ("ioctl: setkeepalive\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || + (d->ifp->if_flags & PP_CISCO)) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + if (*(int*)data) + IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; + else + IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; + CX_UNLOCK (bd); + splx (s); + return 0; +#endif /*NETGRAPH*/ -static int cx_detach (device_t dev) -{ - bdrv_t *bd = device_get_softc (dev); - cx_board_t *b = bd->board; - cx_chan_t *c; - int s; - - KASSERT (mtx_initialized (&bd->cx_mtx), ("cx mutex not initialized")); + case SERIAL_GETMODE: + CX_DEBUG2 (d, ("ioctl: getmode\n")); + s = splhigh (); + CX_LOCK (bd); + *(int*)data = (c->mode == M_ASYNC) ? + SERIAL_ASYNC : SERIAL_HDLC; + CX_UNLOCK (bd); + splx (s); + return 0; - s = splhigh (); - CX_LOCK (bd); - /* Check if the device is busy (open). */ - for (c = b->chan; c < b->chan + NCHAN; ++c) { - drv_t *d = (drv_t*) c->sys; + case SERIAL_SETMODE: + CX_DEBUG2 (d, ("ioctl: setmode\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; - if (!d || d->chan->type == T_NONE) - continue; - if (d->lock) { - CX_UNLOCK (bd); - splx (s); + /* Somebody is waiting for carrier? */ + if (d->lock) return EBUSY; - } + /* /dev/ttyXX is already opened by someone? */ if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && - (d->open_dev|0x2)) { - CX_UNLOCK (bd); - splx (s); + (d->open_dev|0x2)) return EBUSY; - } - if (d->running) { - CX_UNLOCK (bd); - splx (s); + /* Network interface is up? + * Cannot change to async mode. */ + if (c->mode != M_ASYNC && d->running && + (*(int*)data == SERIAL_ASYNC)) return EBUSY; + + s = splhigh (); + CX_LOCK (bd); + if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) { + cx_set_mode (c, M_ASYNC); + cx_enable_receive (c, 0); + cx_enable_transmit (c, 0); + } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) { + cx_set_mode (c, M_HDLC); + cx_enable_receive (c, 1); + cx_enable_transmit (c, 1); } - } + CX_UNLOCK (bd); + splx (s); + return 0; - /* Deactivate the timeout routine. And soft interrupt*/ - callout_stop (&led_timo[b->num]); + case SERIAL_GETSTAT: + CX_DEBUG2 (d, ("ioctl: getestat\n")); + st = (struct serial_statistics*) data; + s = splhigh (); + CX_LOCK (bd); + st->rintr = c->rintr; + st->tintr = c->tintr; + st->mintr = c->mintr; + st->ibytes = c->ibytes; + st->ipkts = c->ipkts; + st->ierrs = c->ierrs; + st->obytes = c->obytes; + st->opkts = c->opkts; + st->oerrs = c->oerrs; + CX_UNLOCK (bd); + splx (s); + return 0; - for (c = b->chan; c < b->chan + NCHAN; ++c) { - drv_t *d = c->sys; + case SERIAL_CLRSTAT: + CX_DEBUG2 (d, ("ioctl: clrstat\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splhigh (); + CX_LOCK (bd); + c->rintr = 0; + c->tintr = 0; + c->mintr = 0; + c->ibytes = 0; + c->ipkts = 0; + c->ierrs = 0; + c->obytes = 0; + c->opkts = 0; + c->oerrs = 0; + CX_UNLOCK (bd); + splx (s); + return 0; - if (!d || d->chan->type == T_NONE) - continue; + case SERIAL_GETBAUD: + CX_DEBUG2 (d, ("ioctl: getbaud\n")); + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + *(long*)data = cx_get_baud(c); + CX_UNLOCK (bd); + splx (s); + return 0; - callout_stop (&d->dcd_timeout_handle); + case SERIAL_SETBAUD: + CX_DEBUG2 (d, ("ioctl: setbaud\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + cx_set_baud (c, *(long*)data); + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETLOOP: + CX_DEBUG2 (d, ("ioctl: getloop\n")); + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + *(int*)data = cx_get_loop (c); + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_SETLOOP: + CX_DEBUG2 (d, ("ioctl: setloop\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + cx_set_loop (c, *(int*)data); + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETDPLL: + CX_DEBUG2 (d, ("ioctl: getdpll\n")); + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + *(int*)data = cx_get_dpll (c); + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_SETDPLL: + CX_DEBUG2 (d, ("ioctl: setdpll\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + cx_set_dpll (c, *(int*)data); + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETNRZI: + CX_DEBUG2 (d, ("ioctl: getnrzi\n")); + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + *(int*)data = cx_get_nrzi (c); + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_SETNRZI: + CX_DEBUG2 (d, ("ioctl: setnrzi\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_ASYNC) + return EINVAL; + s = splhigh (); + CX_LOCK (bd); + cx_set_nrzi (c, *(int*)data); + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETDEBUG: + CX_DEBUG2 (d, ("ioctl: getdebug\n")); + s = splhigh (); + CX_LOCK (bd); + *(int*)data = c->debug; + CX_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_SETDEBUG: + CX_DEBUG2 (d, ("ioctl: setdebug\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splhigh (); + CX_LOCK (bd); + c->debug = *(int*)data; + CX_UNLOCK (bd); + splx (s); +#ifndef NETGRAPH + if (d->chan->debug) + d->ifp->if_flags |= IFF_DEBUG; + else + d->ifp->if_flags &= (~IFF_DEBUG); +#endif + return 0; } - CX_UNLOCK (bd); - bus_teardown_intr (dev, bd->irq_res, bd->intrhand); - bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); - bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); - - bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); - bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); - - bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res); - bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res); - CX_LOCK (bd); - cx_close_board (b); + switch (cmd) { + case TIOCSDTR: /* Set DTR */ + CX_DEBUG2 (d, ("ioctl: tiocsdtr\n")); + s = splhigh (); + CX_LOCK (bd); + cx_set_dtr (c, 1); + CX_UNLOCK (bd); + splx (s); + return 0; + + case TIOCCDTR: /* Clear DTR */ + CX_DEBUG2 (d, ("ioctl: tioccdtr\n")); + s = splhigh (); + CX_LOCK (bd); + cx_set_dtr (c, 0); + CX_UNLOCK (bd); + splx (s); + return 0; + + case TIOCMSET: /* Set DTR/RTS */ + CX_DEBUG2 (d, ("ioctl: tiocmset\n")); + s = splhigh (); + CX_LOCK (bd); + cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); + cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); + CX_UNLOCK (bd); + splx (s); + return 0; - /* Detach the interfaces, free buffer memory. */ - for (c = b->chan; c < b->chan + NCHAN; ++c) { - drv_t *d = (drv_t*) c->sys; + case TIOCMBIS: /* Add DTR/RTS */ + CX_DEBUG2 (d, ("ioctl: tiocmbis\n")); + s = splhigh (); + CX_LOCK (bd); + if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1); + if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1); + CX_UNLOCK (bd); + splx (s); + return 0; - if (!d || d->chan->type == T_NONE) - continue; - - if (d->tty) { - ttyfree (d->tty); - d->tty = NULL; - } + case TIOCMBIC: /* Clear DTR/RTS */ + CX_DEBUG2 (d, ("ioctl: tiocmbic\n")); + s = splhigh (); + CX_LOCK (bd); + if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0); + if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0); + CX_UNLOCK (bd); + splx (s); + return 0; -#ifdef NETGRAPH - if (d->node) { - ng_rmnode_self (d->node); - NG_NODE_UNREF (d->node); - d->node = NULL; - } - mtx_destroy (&d->lo_queue.ifq_mtx); - mtx_destroy (&d->hi_queue.ifq_mtx); -#else - /* Detach from the packet filter list of interfaces. */ - bpfdetach (d->ifp); - /* Detach from the sync PPP list. */ - sppp_detach (d->ifp); + case TIOCMGET: /* Get modem status */ + CX_DEBUG2 (d, ("ioctl: tiocmget\n")); + *(int*)data = cx_modem_status (d); + return 0; - if_detach (d->ifp); - if_free(d->ifp); - /* XXXRIK: check interconnection with irq handler */ - IF_DRAIN (&d->queue); - mtx_destroy (&d->queue.ifq_mtx); -#endif - destroy_dev (d->devt); } - cx_led_off (b); - CX_UNLOCK (bd); - callout_drain (&led_timo[b->num]); - for (c = b->chan; c < b->chan + NCHAN; ++c) { - drv_t *d = c->sys; - - if (!d || d->chan->type == T_NONE) - continue; + CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd)); + return ENOTTY; +} - callout_drain (&d->dcd_timeout_handle); - } - splx (s); - - s = splhigh (); - for (c = b->chan; c < b->chan + NCHAN; ++c) { - drv_t *d = (drv_t*) c->sys; +static struct cdevsw cx_cdevsw = { + .d_version = D_VERSION, + .d_open = cx_open, + .d_close = cx_close, + .d_ioctl = cx_ioctl, + .d_name = "cx", + .d_flags = D_TTY | D_NEEDGIANT, +}; - if (!d || d->chan->type == T_NONE) - continue; - - /* Deallocate buffers. */ - cx_bus_dma_mem_free (&d->dmamem); +/* + * Print the mbuf chain, for debug purposes only. + */ +static void printmbuf (struct mbuf *m) +{ + printf ("mbuf:"); + for (; m; m=m->m_next) { + if (m->m_flags & M_PKTHDR) + printf (" HDR %d:", m->m_pkthdr.len); + if (m->m_flags & M_EXT) + printf (" EXT:"); + printf (" %d", m->m_len); } - bd->board = 0; - adapter [b->num] = 0; - free (b, M_DEVBUF); - splx (s); - - mtx_destroy (&bd->cx_mtx); - - return 0; + printf ("\n"); } -#ifndef NETGRAPH -static void cx_ifstart (struct ifnet *ifp) +/* + * Make an mbuf from data. + */ +static struct mbuf *makembuf (void *buf, u_int len) { - drv_t *d = ifp->if_softc; - bdrv_t *bd = d->board->sys; + struct mbuf *m, *o, *p; - CX_LOCK (bd); - cx_start (d); - CX_UNLOCK (bd); -} + MGETHDR (m, M_DONTWAIT, MT_DATA); -static void cx_ifwatchdog (struct ifnet *ifp) -{ - drv_t *d = ifp->if_softc; + if (! m) + return 0; - cx_watchdog (d); -} + if (len >= MINCLSIZE) + MCLGET (m, M_DONTWAIT); -static void cx_tlf (struct sppp *sp) -{ - drv_t *d = SP2IFP(sp)->if_softc; + m->m_pkthdr.len = len; + m->m_len = 0; - CX_DEBUG (d, ("cx_tlf\n")); -/* cx_set_dtr (d->chan, 0);*/ -/* cx_set_rts (d->chan, 0);*/ - if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) - sp->pp_down (sp); -} + p = m; + while (len) { + u_int n = M_TRAILINGSPACE (p); + if (n > len) + n = len; + if (! n) { + /* Allocate new mbuf. */ + o = p; + MGET (p, M_DONTWAIT, MT_DATA); + if (! p) { + m_freem (m); + return 0; + } + if (len >= MINCLSIZE) + MCLGET (p, M_DONTWAIT); + p->m_len = 0; + o->m_next = p; -static void cx_tls (struct sppp *sp) -{ - drv_t *d = SP2IFP(sp)->if_softc; + n = M_TRAILINGSPACE (p); + if (n > len) + n = len; + } + bcopy (buf, mtod (p, caddr_t) + p->m_len, n); - CX_DEBUG (d, ("cx_tls\n")); - if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) - sp->pp_up (sp); + p->m_len += n; + buf = n + (char*) buf; + len -= n; + } + return m; } /* - * Initialization of interface. - * It seems to be never called by upper level. + * Recover after lost transmit interrupts. */ -static void cx_initialize (void *softc) +static void cx_timeout (void *arg) { - drv_t *d = softc; + drv_t *d; + int s, i, k; - CX_DEBUG (d, ("cx_initialize\n")); + for (i = 0; i < NCX; i++) { + if (adapter[i] == NULL) + continue; + for (k = 0; k < NCHAN; ++k) { + d = channel[i * NCHAN + k]; + if (! d) + continue; + s = splhigh (); + CX_LOCK ((bdrv_t *)d->board->sys); + if (d->atimeout == 1 && d->tty && d->tty->t_state & TS_BUSY) { + d->tty->t_state &= ~TS_BUSY; + if (d->tty->t_dev) { + d->intr_action |= CX_WRITE; + MY_SOFT_INTR = 1; + swi_sched (cx_fast_ih, 0); + } + CX_DEBUG (d, ("cx_timeout\n")); + } + if (d->atimeout) + d->atimeout--; + CX_UNLOCK ((bdrv_t *)d->board->sys); + splx (s); + } + } + callout_reset (&timeout_handle, hz*5, cx_timeout, 0); } -/* - * Process an ioctl request. - */ -static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) +static void cx_led_off (void *arg) { - drv_t *d = ifp->if_softc; - bdrv_t *bd = d->board->sys; - int error, s, was_up, should_be_up; - - /* No socket ioctls while the channel is in async mode. */ - if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC) - return EBUSY; - - /* Socket ioctls on slave subchannels are not allowed. */ - was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; - error = sppp_ioctl (ifp, cmd, data); - if (error) - return error; - - if (! (ifp->if_flags & IFF_DEBUG)) - d->chan->debug = 0; - else if (! d->chan->debug) - d->chan->debug = 1; - - switch (cmd) { - default: CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; - case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n")); return 0; - case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n")); return 0; - case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n")); break; - case SIOCSIFADDR: CX_DEBUG2 (d, ("SIOCSIFADDR\n")); break; - } + cx_board_t *b = arg; + bdrv_t *bd = b->sys; + int s; - /* We get here only in case of SIFFLAGS or SIFADDR. */ s = splhigh (); - CX_LOCK (bd); - should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; - if (!was_up && should_be_up) { - /* Interface goes up -- start it. */ - cx_up (d); - cx_start (d); - } else if (was_up && !should_be_up) { - /* Interface is going down -- stop it. */ - /* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ - cx_down (d); - } + CX_LOCK (bd); + cx_led (b, 0); CX_UNLOCK (bd); splx (s); - return 0; } -#endif /*NETGRAPH*/ /* - * Stop the interface. Called on splimp(). + * Activate interupt handler from DDK. */ -static void cx_down (drv_t *d) +static void cx_intr (void *arg) { + bdrv_t *bd = arg; + cx_board_t *b = bd->board; +#ifndef NETGRAPH + int i; +#endif int s = splhigh (); - CX_DEBUG (d, ("cx_down\n")); - cx_set_dtr (d->chan, 0); - cx_set_rts (d->chan, 0); - d->running = 0; + + CX_LOCK (bd); + /* Turn LED on. */ + cx_led (b, 1); + + cx_int_handler (b); + + /* Turn LED off 50 msec later. */ + callout_reset (&led_timo[b->num], hz/20, cx_led_off, b); + CX_UNLOCK (bd); splx (s); + +#ifndef NETGRAPH + /* Pass packets in a lock-free state */ + for (i = 0; i < NCHAN && b->chan[i].type; i++) { + drv_t *d = b->chan[i].sys; + struct mbuf *m; + if (!d || !d->running) + continue; + while (_IF_QLEN(&d->queue)) { + IF_DEQUEUE (&d->queue,m); + if (!m) + continue; + sppp_input (d->ifp, m); + } + } +#endif } -/* - * Start the interface. Called on splimp(). - */ -static void cx_up (drv_t *d) +static int probe_irq (cx_board_t *b, int irq) { - int s = splhigh (); - CX_DEBUG (d, ("cx_up\n")); - cx_set_dtr (d->chan, 1); - cx_set_rts (d->chan, 1); - d->running = 1; - splx (s); + int mask, busy, cnt; + + /* Clear pending irq, if any. */ + cx_probe_irq (b, -irq); + DELAY (100); + for (cnt=0; cnt<5; ++cnt) { + /* Get the mask of pending irqs, assuming they are busy. + * Activate the adapter on given irq. */ + busy = cx_probe_irq (b, irq); + DELAY (100); + + /* Get the mask of active irqs. + * Deactivate our irq. */ + mask = cx_probe_irq (b, -irq); + DELAY (100); + if ((mask & ~busy) == 1 << irq) { + cx_probe_irq (b, 0); + /* printf ("cx%d: irq %d ok, mask=0x%04x, busy=0x%04x\n", + b->num, irq, mask, busy); */ + return 1; + } + } + /* printf ("cx%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n", + b->num, irq, mask, busy); */ + cx_probe_irq (b, 0); + return 0; } -/* - * Start output on the (slave) interface. Get another datagram to send - * off of the interface queue, and copy it to the interface - * before starting the output. - */ -static void cx_send (drv_t *d) +static short porttab [] = { + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, + 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 +}; +static char dmatab [] = { 7, 6, 5, 0 }; +static char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 }; + +static int cx_is_free_res (device_t dev, int rid, int type, u_long start, + u_long end, u_long count) { - struct mbuf *m; - u_short len; + struct resource *res; + + if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count, + RF_ALLOCATED))) + return 0; + + bus_release_resource (dev, type, rid, res); + + return 1; +} - CX_DEBUG2 (d, ("cx_send\n")); +static void cx_identify (driver_t *driver, device_t dev) +{ + u_long iobase, rescount; + int devcount; + device_t *devices; + device_t child; + devclass_t my_devclass; + int i, k; - /* No output if the interface is down. */ - if (! d->running) + if ((my_devclass = devclass_find ("cx")) == NULL) return; - /* No output if the modem is off. */ - if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan)) - return; + devclass_get_devices (my_devclass, &devices, &devcount); - if (cx_buf_free (d->chan)) { - /* Get the packet to send. */ -#ifdef NETGRAPH - IF_DEQUEUE (&d->hi_queue, m); - if (! m) - IF_DEQUEUE (&d->lo_queue, m); -#else - m = sppp_dequeue (d->ifp); -#endif - if (! m) - return; -#ifndef NETGRAPH - if (d->ifp->if_bpf) - BPF_MTAP (d->ifp, m); -#endif - len = m_length (m, NULL); - if (! m->m_next) - cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t), - len, 0); - else { - u_char buf [DMABUFSZ]; - m_copydata (m, 0, len, buf); - cx_send_packet (d->chan, buf, len, 0); + if (devcount == 0) { + /* We should find all devices by our self. We could alter other + * devices, but we don't have a choise + */ + for (i = 0; (iobase = porttab [i]) != 0; i++) { + if (!cx_is_free_res (dev, 0, SYS_RES_IOPORT, + iobase, iobase + NPORT, NPORT)) + continue; + if (cx_probe_board (iobase, -1, -1) == 0) + continue; + + devcount++; + + child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "cx", + -1); + + if (child == NULL) + return; + + device_set_desc_copy (child, "Cronyx Sigma"); + device_set_driver (child, driver); + bus_set_resource (child, SYS_RES_IOPORT, 0, + iobase, NPORT); + + if (devcount >= NCX) + break; } - m_freem (m); + } else { + static short porttab [] = { + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, + 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 + }; + /* Lets check user choise. + */ + for (k = 0; k < devcount; k++) { + if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, + &iobase, &rescount) != 0) + continue; - /* Set up transmit timeout, 10 seconds. */ -#ifdef NETGRAPH - d->timeout = 10; -#else - d->ifp->if_timer = 10; -#endif - } -#ifndef NETGRAPH - d->ifp->if_drv_flags |= IFF_DRV_OACTIVE; -#endif -} + for (i = 0; porttab [i] != 0; i++) { + if (porttab [i] != iobase) + continue; + if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT, + iobase, iobase + NPORT, NPORT)) + continue; + if (cx_probe_board (iobase, -1, -1) == 0) + continue; + porttab [i] = -1; + device_set_desc_copy (devices[k], "Cronyx Sigma"); + break; + } -/* - * Start output on the interface. - * Always called on splimp(). - */ -static void cx_start (drv_t *d) -{ - int s = splhigh (); - if (d->running) { - if (! d->chan->dtr) - cx_set_dtr (d->chan, 1); - if (! d->chan->rts) - cx_set_rts (d->chan, 1); - cx_send (d); + if (porttab [i] == 0) { + device_delete_child ( + device_get_parent (devices[k]), + devices [k]); + devices[k] = 0; + continue; + } + } + for (k = 0; k < devcount; k++) { + if (devices[k] == 0) + continue; + if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, + &iobase, &rescount) == 0) + continue; + for (i = 0; (iobase = porttab [i]) != 0; i++) { + if (porttab [i] == -1) { + continue; + } + if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT, + iobase, iobase + NPORT, NPORT)) + continue; + if (cx_probe_board (iobase, -1, -1) == 0) + continue; + + bus_set_resource (devices[k], SYS_RES_IOPORT, 0, + iobase, NPORT); + porttab [i] = -1; + device_set_desc_copy (devices[k], "Cronyx Sigma"); + break; + } + if (porttab [i] == 0) { + device_delete_child ( + device_get_parent (devices[k]), + devices [k]); + } + } + free (devices, M_TEMP); } - splx (s); + + return; } -/* - * Handle transmit timeouts. - * Recover after lost transmit interrupts. - * Always called on splimp(). - */ -static void cx_watchdog (drv_t *d) +static int cx_probe (device_t dev) { - bdrv_t *bd = d->board->sys; + int unit = device_get_unit (dev); + int i; + u_long iobase, rescount; + + if (!device_get_desc (dev) || + strcmp (device_get_desc (dev), "Cronyx Sigma")) + return ENXIO; - int s = splhigh (); - CX_LOCK (bd); - CX_DEBUG (d, ("device timeout\n")); - if (d->running) { - cx_setup_chan (d->chan); - cx_start_chan (d->chan, 0, 0); - cx_set_dtr (d->chan, 1); - cx_set_rts (d->chan, 1); - cx_start (d); + if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) { + printf ("cx%d: Couldn't get IOPORT\n", unit); + return ENXIO; } - CX_UNLOCK (bd); - splx (s); + + if (!cx_is_free_res (dev, 0, SYS_RES_IOPORT, + iobase, iobase + NPORT, NPORT)) { + printf ("cx%d: Resource IOPORT isn't free %lx\n", unit, iobase); + return ENXIO; + } + + for (i = 0; porttab [i] != 0; i++) { + if (porttab [i] == iobase) { + porttab [i] = -1; + break; + } + } + + if (porttab [i] == 0) { + return ENXIO; + } + + if (!cx_probe_board (iobase, -1, -1)) { + printf ("cx%d: probing for Sigma at %lx faild\n", unit, iobase); + return ENXIO; + } + + return 0; } -/* - * Transmit callback function. - */ -static void cx_transmit (cx_chan_t *c, void *attachment, int len) +static void +cx_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) { - drv_t *d = c->sys; + unsigned long *addr; - if (!d) - return; - - if (c->mode == M_ASYNC && d->tty) { - d->tty->t_state &= ~(TS_BUSY | TS_FLUSH); - d->atimeout = 0; - if (d->tty->t_dev) { - d->intr_action |= CX_WRITE; - MY_SOFT_INTR = 1; - swi_sched (cx_fast_ih, 0); - } + if (error) return; + + KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); + addr = arg; + *addr = segs->ds_addr; +} + +static int +cx_bus_dma_mem_alloc (int bnum, int cnum, cx_dma_mem_t *dmem) +{ + int error; + + error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT, + BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1, + dmem->size, 0, NULL, NULL, &dmem->dmat); + if (error) { + if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); + else printf ("cx%d: ", bnum); + printf ("couldn't allocate tag for dma memory\n"); + return 0; } -#ifdef NETGRAPH - d->timeout = 0; -#else - ++d->ifp->if_opackets; - d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - d->ifp->if_timer = 0; -#endif - cx_start (d); + error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp); + if (error) { + if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); + else printf ("cx%d: ", bnum); + printf ("couldn't allocate mem for dma memory\n"); + bus_dma_tag_destroy (dmem->dmat); + return 0; + } + error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt, + dmem->size, cx_bus_dmamap_addr, &dmem->phys, 0); + if (error) { + if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); + else printf ("cx%d: ", bnum); + printf ("couldn't load mem map for dma memory\n"); + bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); + bus_dma_tag_destroy (dmem->dmat); + return 0; + } + return 1; +} + +static void +cx_bus_dma_mem_free (cx_dma_mem_t *dmem) +{ + bus_dmamap_unload (dmem->dmat, dmem->mapp); + bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); + bus_dma_tag_destroy (dmem->dmat); } /* - * Process the received packet. + * The adapter is present, initialize the driver structures. */ -static void cx_receive (cx_chan_t *c, char *data, int len) +static int cx_attach (device_t dev) { - drv_t *d = c->sys; - struct mbuf *m; - char *cc = data; -#ifdef NETGRAPH - int error; -#endif + bdrv_t *bd = device_get_softc (dev); + u_long iobase, drq, irq, rescount; + int unit = device_get_unit (dev); + char *cx_ln = CX_LOCK_NAME; + cx_board_t *b; + cx_chan_t *c; + drv_t *d; + int i; + int s; - if (!d) - return; + KASSERT ((bd != NULL), ("cx%d: NULL device softc\n", unit)); + + bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount); + bd->base_rid = 0; + bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid, + iobase, iobase + NPORT, NPORT, RF_ACTIVE); + if (! bd->base_res) { + printf ("cx%d: cannot allocate base address\n", unit); + return ENXIO; + } + + if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) { + for (i = 0; (drq = dmatab [i]) != 0; i++) { + if (!cx_is_free_res (dev, 0, SYS_RES_DRQ, + drq, drq + 1, 1)) + continue; + bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1); + break; + } - if (c->mode == M_ASYNC && d->tty) { - if (d->tty->t_state & TS_ISOPEN) { - async_q *q = &d->aqueue; - int size = BF_SZ - 1 - AQ_GSZ (q); + if (dmatab[i] == 0) { + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, + bd->base_res); + printf ("cx%d: Couldn't get DRQ\n", unit); + return ENXIO; + } + } + + bd->drq_rid = 0; + bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid, + drq, drq + 1, 1, RF_ACTIVE); + if (! bd->drq_res) { + printf ("cx%d: cannot allocate drq\n", unit); + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, + bd->base_res); + return ENXIO; + } + + if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) { + for (i = 0; (irq = irqtab [i]) != 0; i++) { + if (!cx_is_free_res (dev, 0, SYS_RES_IRQ, + irq, irq + 1, 1)) + continue; + bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1); + break; + } + + if (irqtab[i] == 0) { + bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, + bd->drq_res); + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, + bd->base_res); + printf ("cx%d: Couldn't get IRQ\n", unit); + return ENXIO; + } + } + + bd->irq_rid = 0; + bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid, + irq, irq + 1, 1, RF_ACTIVE); + if (! bd->irq_res) { + printf ("cx%d: Couldn't allocate irq\n", unit); + bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, + bd->drq_res); + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, + bd->base_res); + return ENXIO; + } + + b = malloc (sizeof (cx_board_t), M_DEVBUF, M_WAITOK); + if (!b) { + printf ("cx:%d: Couldn't allocate memory\n", unit); + return (ENXIO); + } + adapter[unit] = b; + bzero (b, sizeof(cx_board_t)); + + if (! cx_open_board (b, unit, iobase, irq, drq)) { + printf ("cx%d: error loading firmware\n", unit); + free (b, M_DEVBUF); + bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, + bd->irq_res); + bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, + bd->drq_res); + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, + bd->base_res); + return ENXIO; + } - if (len <= 0 && !size) - return; + bd->board = b; + + cx_ln[2] = '0' + unit; + mtx_init (&bd->cx_mtx, cx_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE); + if (! probe_irq (b, irq)) { + printf ("cx%d: irq %ld not functional\n", unit, irq); + bd->board = 0; + adapter [unit] = 0; + mtx_destroy (&bd->cx_mtx); + free (b, M_DEVBUF); + bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, + bd->irq_res); + bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, + bd->drq_res); + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, + bd->base_res); + return ENXIO; + } + b->sys = bd; + callout_init (&led_timo[b->num], cx_mpsafenet ? CALLOUT_MPSAFE : 0); + s = splhigh (); + if (bus_setup_intr (dev, bd->irq_res, + INTR_TYPE_NET|(cx_mpsafenet?INTR_MPSAFE:0), + cx_intr, bd, &bd->intrhand)) { + printf ("cx%d: Can't setup irq %ld\n", unit, irq); + bd->board = 0; + b->sys = 0; + adapter [unit] = 0; + mtx_destroy (&bd->cx_mtx); + free (b, M_DEVBUF); + bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, + bd->irq_res); + bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, + bd->drq_res); + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, + bd->base_res); + splx (s); + return ENXIO; + } + + CX_LOCK (bd); + cx_init (b, b->num, b->port, irq, drq); + cx_setup_board (b, 0, 0, 0); + CX_UNLOCK (bd); - if (len > size) { - c->ierrs++; - cx_error (c, CX_OVERRUN); - len = size - 1; - } + printf ("cx%d: \n", b->num, b->name); - while (len--) { - AQ_PUSH (q, *(unsigned char *)cc); - cc++; - } + for (c=b->chan; cchan+NCHAN; ++c) { + if (c->type == T_NONE) + continue; + d = &bd->channel[c->num]; + d->dmamem.size = sizeof(cx_buf_t); + if (! cx_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) + continue; + d->board = b; + d->chan = c; + d->open_dev = 0; + c->sys = d; + channel [b->num*NCHAN + c->num] = d; + sprintf (d->name, "cx%d.%d", b->num, c->num); - d->intr_action |= CX_READ; - MY_SOFT_INTR = 1; - swi_sched (cx_fast_ih, 0); + switch (c->type) { + case T_SYNC_RS232: + case T_SYNC_V35: + case T_SYNC_RS449: + case T_UNIV: + case T_UNIV_RS232: + case T_UNIV_RS449: + case T_UNIV_V35: +#ifdef NETGRAPH + if (ng_make_node_common (&typestruct, &d->node) != 0) { + printf ("%s: cannot make common node\n", d->name); + channel [b->num*NCHAN + c->num] = 0; + c->sys = 0; + cx_bus_dma_mem_free (&d->dmamem); + continue; } - return; - } - if (! d->running) - return; + NG_NODE_SET_PRIVATE (d->node, d); + sprintf (d->nodename, "%s%d", NG_CX_NODE_TYPE, + c->board->num*NCHAN + c->num); + if (ng_name_node (d->node, d->nodename)) { + printf ("%s: cannot name node\n", d->nodename); + NG_NODE_UNREF (d->node); + channel [b->num*NCHAN + c->num] = 0; + c->sys = 0; + cx_bus_dma_mem_free (&d->dmamem); + continue; + } + d->lo_queue.ifq_maxlen = IFQ_MAXLEN; + d->hi_queue.ifq_maxlen = IFQ_MAXLEN; + mtx_init (&d->lo_queue.ifq_mtx, "cx_queue_lo", NULL, MTX_DEF); + mtx_init (&d->hi_queue.ifq_mtx, "cx_queue_hi", NULL, MTX_DEF); + callout_init (&d->timeout_handle, + cx_mpsafenet ? CALLOUT_MPSAFE : 0); +#else /*NETGRAPH*/ + d->ifp = if_alloc(IFT_PPP); + if (d->ifp == NULL) { + printf ("%s: cannot if_alloc() common interface\n", + d->name); + channel [b->num*NCHAN + c->num] = 0; + c->sys = 0; + cx_bus_dma_mem_free (&d->dmamem); + continue; + } + d->ifp->if_softc = d; + if_initname (d->ifp, "cx", b->num * NCHAN + c->num); + d->ifp->if_mtu = PP_MTU; + d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; + if (!cx_mpsafenet) + d->ifp->if_flags |= IFF_NEEDSGIANT; + d->ifp->if_ioctl = cx_sioctl; + d->ifp->if_start = cx_ifstart; + d->ifp->if_watchdog = cx_ifwatchdog; + d->ifp->if_init = cx_initialize; + d->queue.ifq_maxlen = 2; + mtx_init (&d->queue.ifq_mtx, "cx_queue", NULL, MTX_DEF); + sppp_attach (d->ifp); + if_attach (d->ifp); + IFP2SP(d->ifp)->pp_tlf = cx_tlf; + IFP2SP(d->ifp)->pp_tls = cx_tls; + /* If BPF is in the kernel, call the attach for it. + * Size of PPP header is 4 bytes. */ + bpfattach (d->ifp, DLT_PPP, 4); +#endif /*NETGRAPH*/ + } + d->tty = ttyalloc (); + d->tty->t_open = cx_topen; + d->tty->t_close = cx_tclose; + d->tty->t_param = cx_param; + d->tty->t_stop = cx_stop; + d->tty->t_modem = cx_tmodem; + d->tty->t_oproc = cx_oproc; + d->tty->t_sc = d; + CX_LOCK (bd); + cx_start_chan (c, d->dmamem.virt, d->dmamem.phys); + cx_register_receive (c, &cx_receive); + cx_register_transmit (c, &cx_transmit); + cx_register_error (c, &cx_error); + cx_register_modem (c, &cx_modem); + CX_UNLOCK (bd); - m = makembuf (data, len); - if (! m) { - CX_DEBUG (d, ("no memory for packet\n")); -#ifndef NETGRAPH - ++d->ifp->if_iqdrops; -#endif - return; + ttycreate(d->tty, NULL, 0, MINOR_CALLOUT, + "x%r%r", b->num, c->num); + d->devt = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 64, UID_ROOT, GID_WHEEL, 0600, "cx%d", b->num*NCHAN + c->num); + d->devt->si_drv1 = d; + callout_init (&d->dcd_timeout_handle, + cx_mpsafenet ? CALLOUT_MPSAFE : 0); } - if (c->debug > 1) - printmbuf (m); -#ifdef NETGRAPH - m->m_pkthdr.rcvif = 0; - NG_SEND_DATA_ONLY (error, d->hook, m); -#else - ++d->ifp->if_ipackets; - m->m_pkthdr.rcvif = d->ifp; - /* Check if there's a BPF listener on this interface. - * If so, hand off the raw packet to bpf. */ - if (d->ifp->if_bpf) - BPF_TAP (d->ifp, data, len); - IF_ENQUEUE (&d->queue, m); -#endif -} + splx (s); -#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ - && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ - && (!(tp->t_iflag & PARMRK)\ - || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ - && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ - && linesw[tp->t_line]->l_rint == ttyinput) + return 0; +} -/* - * Error callback function. - */ -static void cx_error (cx_chan_t *c, int data) +static int cx_detach (device_t dev) { - drv_t *d = c->sys; - async_q *q; - - if (!d) - return; + bdrv_t *bd = device_get_softc (dev); + cx_board_t *b = bd->board; + cx_chan_t *c; + int s; + + KASSERT (mtx_initialized (&bd->cx_mtx), ("cx mutex not initialized")); - q = &(d->aqueue); + s = splhigh (); + CX_LOCK (bd); + /* Check if the device is busy (open). */ + for (c = b->chan; c < b->chan + NCHAN; ++c) { + drv_t *d = (drv_t*) c->sys; - switch (data) { - case CX_FRAME: - CX_DEBUG (d, ("frame error\n")); - if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) - && (AQ_GSZ (q) < BF_SZ - 1) - && (!CONDITION((&d->tty->t_termios), (d->tty)) - || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { - AQ_PUSH (q, TTY_FE); - d->intr_action |= CX_READ; - MY_SOFT_INTR = 1; - swi_sched (cx_fast_ih, 0); - } -#ifndef NETGRAPH - else - ++d->ifp->if_ierrors; -#endif - break; - case CX_CRC: - CX_DEBUG (d, ("crc error\n")); - if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) - && (AQ_GSZ (q) < BF_SZ - 1) - && (!CONDITION((&d->tty->t_termios), (d->tty)) - || !(d->tty->t_iflag & INPCK) - || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { - AQ_PUSH (q, TTY_PE); - d->intr_action |= CX_READ; - MY_SOFT_INTR = 1; - swi_sched (cx_fast_ih, 0); - } -#ifndef NETGRAPH - else - ++d->ifp->if_ierrors; -#endif - break; - case CX_OVERRUN: - CX_DEBUG (d, ("overrun error\n")); -#ifdef TTY_OE - if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) - && (AQ_GSZ (q) < BF_SZ - 1) - && (!CONDITION((&d->tty->t_termios), (d->tty)))) { - AQ_PUSH (q, TTY_OE); - d->intr_action |= CX_READ; - MY_SOFT_INTR = 1; - swi_sched (cx_fast_ih, 0); - } -#endif -#ifndef NETGRAPH - else { - ++d->ifp->if_collisions; - ++d->ifp->if_ierrors; + if (!d || d->chan->type == T_NONE) + continue; + if (d->lock) { + CX_UNLOCK (bd); + splx (s); + return EBUSY; } -#endif - break; - case CX_OVERFLOW: - CX_DEBUG (d, ("overflow error\n")); -#ifndef NETGRAPH - if (c->mode != M_ASYNC) - ++d->ifp->if_ierrors; -#endif - break; - case CX_UNDERRUN: - CX_DEBUG (d, ("underrun error\n")); - if (c->mode != M_ASYNC) { -#ifdef NETGRAPH - d->timeout = 0; -#else - ++d->ifp->if_oerrors; - d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - d->ifp->if_timer = 0; - cx_start (d); -#endif + if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && + (d->open_dev|0x2)) { + CX_UNLOCK (bd); + splx (s); + return EBUSY; } - break; - case CX_BREAK: - CX_DEBUG (d, ("break error\n")); - if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) - && (AQ_GSZ (q) < BF_SZ - 1) - && (!CONDITION((&d->tty->t_termios), (d->tty)) - || !(d->tty->t_iflag & (IGNBRK | BRKINT | PARMRK)))) { - AQ_PUSH (q, TTY_BI); - d->intr_action |= CX_READ; - MY_SOFT_INTR = 1; - swi_sched (cx_fast_ih, 0); + if (d->running) { + CX_UNLOCK (bd); + splx (s); + return EBUSY; } -#ifndef NETGRAPH - else - ++d->ifp->if_ierrors; -#endif - break; - default: - CX_DEBUG (d, ("error #%d\n", data)); } -} -static int cx_topen (struct tty *tp, struct cdev *dev) -{ - bdrv_t *bd; - drv_t *d; + /* Deactivate the timeout routine. And soft interrupt*/ + callout_stop (&led_timo[b->num]); - d = tp->t_sc; - CX_DEBUG2 (d, ("cx_open (serial)\n")); + for (c = b->chan; c < b->chan + NCHAN; ++c) { + drv_t *d = c->sys; - bd = d->board->sys; + if (!d || d->chan->type == T_NONE) + continue; - if (d->chan->mode != M_ASYNC) - return (EBUSY); + callout_stop (&d->dcd_timeout_handle); + } + CX_UNLOCK (bd); + bus_teardown_intr (dev, bd->irq_res, bd->intrhand); + bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); + bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); + + bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); + bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); + + bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res); + bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res); - d->open_dev |= 0x2; CX_LOCK (bd); - cx_start_chan (d->chan, 0, 0); - cx_set_dtr (d->chan, 1); - cx_set_rts (d->chan, 1); - d->cd = cx_get_cd (d->chan); + cx_close_board (b); + + /* Detach the interfaces, free buffer memory. */ + for (c = b->chan; c < b->chan + NCHAN; ++c) { + drv_t *d = (drv_t*) c->sys; + + if (!d || d->chan->type == T_NONE) + continue; + + if (d->tty) { + ttyfree (d->tty); + d->tty = NULL; + } + +#ifdef NETGRAPH + if (d->node) { + ng_rmnode_self (d->node); + NG_NODE_UNREF (d->node); + d->node = NULL; + } + mtx_destroy (&d->lo_queue.ifq_mtx); + mtx_destroy (&d->hi_queue.ifq_mtx); +#else + /* Detach from the packet filter list of interfaces. */ + bpfdetach (d->ifp); + /* Detach from the sync PPP list. */ + sppp_detach (d->ifp); + + if_detach (d->ifp); + if_free(d->ifp); + /* XXXRIK: check interconnection with irq handler */ + IF_DRAIN (&d->queue); + mtx_destroy (&d->queue.ifq_mtx); +#endif + destroy_dev (d->devt); + } + + cx_led_off (b); CX_UNLOCK (bd); + callout_drain (&led_timo[b->num]); + for (c = b->chan; c < b->chan + NCHAN; ++c) { + drv_t *d = c->sys; - CX_DEBUG2 (d, ("cx_open done\n")); + if (!d || d->chan->type == T_NONE) + continue; - return 0; + callout_drain (&d->dcd_timeout_handle); + } + splx (s); + + s = splhigh (); + for (c = b->chan; c < b->chan + NCHAN; ++c) { + drv_t *d = (drv_t*) c->sys; + + if (!d || d->chan->type == T_NONE) + continue; + + /* Deallocate buffers. */ + cx_bus_dma_mem_free (&d->dmamem); + } + bd->board = 0; + adapter [b->num] = 0; + free (b, M_DEVBUF); + splx (s); + + mtx_destroy (&bd->cx_mtx); + + return 0; } -static void cx_tclose (struct tty *tp) +#ifndef NETGRAPH +static void cx_ifstart (struct ifnet *ifp) { - drv_t *d; - bdrv_t *bd; + drv_t *d = ifp->if_softc; + bdrv_t *bd = d->board->sys; - d = tp->t_sc; - CX_DEBUG2 (d, ("cx_close\n")); - bd = d->board->sys; CX_LOCK (bd); - /* Disable receiver. - * Transmitter continues sending the queued data. */ - cx_enable_receive (d->chan, 0); + cx_start (d); CX_UNLOCK (bd); - d->open_dev &= ~0x2; } -static int cx_tmodem (struct tty *tp, int sigon, int sigoff) +static void cx_ifwatchdog (struct ifnet *ifp) { - drv_t *d; - bdrv_t *bd; + drv_t *d = ifp->if_softc; - d = tp->t_sc; - bd = d->board->sys; + cx_watchdog (d); +} - CX_LOCK (bd); - if (!sigon && !sigoff) { - if (cx_get_dsr (d->chan)) sigon |= SER_DSR; - if (cx_get_cd (d->chan)) sigon |= SER_DCD; - if (cx_get_cts (d->chan)) sigon |= SER_CTS; - if (d->chan->dtr) sigon |= SER_DTR; - if (d->chan->rts) sigon |= SER_RTS; - CX_UNLOCK (bd); - return sigon; - } +static void cx_tlf (struct sppp *sp) +{ + drv_t *d = SP2IFP(sp)->if_softc; - if (sigon & SER_DTR) - cx_set_dtr (d->chan, 1); - if (sigoff & SER_DTR) - cx_set_dtr (d->chan, 0); - if (sigon & SER_RTS) - cx_set_rts (d->chan, 1); - if (sigoff & SER_RTS) - cx_set_rts (d->chan, 0); - CX_UNLOCK (bd); + CX_DEBUG (d, ("cx_tlf\n")); +/* cx_set_dtr (d->chan, 0);*/ +/* cx_set_rts (d->chan, 0);*/ + if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) + sp->pp_down (sp); +} - return (0); +static void cx_tls (struct sppp *sp) +{ + drv_t *d = SP2IFP(sp)->if_softc; + + CX_DEBUG (d, ("cx_tls\n")); + if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) + sp->pp_up (sp); } -static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td) +/* + * Initialization of interface. + * It seems to be never called by upper level. + */ +static void cx_initialize (void *softc) { - int unit; - drv_t *d; + drv_t *d = softc; - d = dev->si_drv1; - unit = d->chan->num; + CX_DEBUG (d, ("cx_initialize\n")); +} - CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n", - unit, flag, mode)); +/* + * Process an ioctl request. + */ +static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) +{ + drv_t *d = ifp->if_softc; + bdrv_t *bd = d->board->sys; + int error, s, was_up, should_be_up; - d->open_dev |= 0x1; + /* No socket ioctls while the channel is in async mode. */ + if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC) + return EBUSY; - CX_DEBUG2 (d, ("cx_open done\n")); + /* Socket ioctls on slave subchannels are not allowed. */ + was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; + error = sppp_ioctl (ifp, cmd, data); + if (error) + return error; + + if (! (ifp->if_flags & IFF_DEBUG)) + d->chan->debug = 0; + else if (! d->chan->debug) + d->chan->debug = 1; + + switch (cmd) { + default: CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; + case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n")); return 0; + case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n")); return 0; + case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n")); break; + case SIOCSIFADDR: CX_DEBUG2 (d, ("SIOCSIFADDR\n")); break; + } + /* We get here only in case of SIFFLAGS or SIFADDR. */ + s = splhigh (); + CX_LOCK (bd); + should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; + if (!was_up && should_be_up) { + /* Interface goes up -- start it. */ + cx_up (d); + cx_start (d); + } else if (was_up && !should_be_up) { + /* Interface is going down -- stop it. */ + /* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ + cx_down (d); + } + CX_UNLOCK (bd); + splx (s); return 0; } +#endif /*NETGRAPH*/ -static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td) +/* + * Stop the interface. Called on splimp(). + */ +static void cx_down (drv_t *d) { - drv_t *d; - - d = dev->si_drv1; - CX_DEBUG2 (d, ("cx_close\n")); - d->open_dev &= ~0x1; - return 0; + int s = splhigh (); + CX_DEBUG (d, ("cx_down\n")); + cx_set_dtr (d->chan, 0); + cx_set_rts (d->chan, 0); + d->running = 0; + splx (s); } -static int cx_modem_status (drv_t *d) +/* + * Start the interface. Called on splimp(). + */ +static void cx_up (drv_t *d) { - bdrv_t *bd = d->board->sys; - int status = 0, s = splhigh (); - CX_LOCK (bd); - /* Already opened by someone or network interface is up? */ - if ((d->chan->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && - (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running)) - status = TIOCM_LE; /* always enabled while open */ - - if (cx_get_dsr (d->chan)) status |= TIOCM_DSR; - if (cx_get_cd (d->chan)) status |= TIOCM_CD; - if (cx_get_cts (d->chan)) status |= TIOCM_CTS; - if (d->chan->dtr) status |= TIOCM_DTR; - if (d->chan->rts) status |= TIOCM_RTS; - CX_UNLOCK (bd); + int s = splhigh (); + CX_DEBUG (d, ("cx_up\n")); + cx_set_dtr (d->chan, 1); + cx_set_rts (d->chan, 1); + d->running = 1; splx (s); - return status; } -static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) +/* + * Start output on the (slave) interface. Get another datagram to send + * off of the interface queue, and copy it to the interface + * before starting the output. + */ +static void cx_send (drv_t *d) { - drv_t *d; - bdrv_t *bd; - cx_chan_t *c; - struct serial_statistics *st; - int error, s; - char mask[16]; - - d = dev->si_drv1; - c = d->chan; - - bd = d->board->sys; - - switch (cmd) { - case SERIAL_GETREGISTERED: - CX_DEBUG2 (d, ("ioctl: getregistered\n")); - bzero (mask, sizeof(mask)); - for (s=0; srunning) + return; - s = splhigh (); - CX_LOCK (bd); - cx_set_port (c, *(int *)data); - CX_UNLOCK (bd); - splx (s); - return 0; + /* No output if the modem is off. */ + if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan)) + return; + if (cx_buf_free (d->chan)) { + /* Get the packet to send. */ +#ifdef NETGRAPH + IF_DEQUEUE (&d->hi_queue, m); + if (! m) + IF_DEQUEUE (&d->lo_queue, m); +#else + m = sppp_dequeue (d->ifp); +#endif + if (! m) + return; #ifndef NETGRAPH - case SERIAL_GETPROTO: - CX_DEBUG2 (d, ("ioctl: getproto\n")); - s = splhigh (); - CX_LOCK (bd); - strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" : - (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" : - (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp"); - CX_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_SETPROTO: - CX_DEBUG2 (d, ("ioctl: setproto\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_ASYNC) - return EBUSY; - if (d->ifp->if_drv_flags & IFF_DRV_RUNNING) - return EBUSY; - if (! strcmp ("cisco", (char*)data)) { - IFP2SP(d->ifp)->pp_flags &= ~(PP_FR); - IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; - d->ifp->if_flags |= PP_CISCO; - } else if (! strcmp ("fr", (char*)data)) { - d->ifp->if_flags &= ~(PP_CISCO); - IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE; - } else if (! strcmp ("ppp", (char*)data)) { - IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE); - d->ifp->if_flags &= ~(PP_CISCO); - } else - return EINVAL; - return 0; - - case SERIAL_GETKEEPALIVE: - CX_DEBUG2 (d, ("ioctl: getkeepalive\n")); - if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || - (d->ifp->if_flags & PP_CISCO) || - (c->mode == M_ASYNC)) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0; - CX_UNLOCK (bd); - splx (s); - return 0; + if (d->ifp->if_bpf) + BPF_MTAP (d->ifp, m); +#endif + len = m_length (m, NULL); + if (! m->m_next) + cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t), + len, 0); + else { + u_char buf [DMABUFSZ]; + m_copydata (m, 0, len, buf); + cx_send_packet (d->chan, buf, len, 0); + } + m_freem (m); - case SERIAL_SETKEEPALIVE: - CX_DEBUG2 (d, ("ioctl: setkeepalive\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || - (d->ifp->if_flags & PP_CISCO)) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - if (*(int*)data) - IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; - else - IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; - CX_UNLOCK (bd); - splx (s); - return 0; -#endif /*NETGRAPH*/ + /* Set up transmit timeout, 10 seconds. */ +#ifdef NETGRAPH + d->timeout = 10; +#else + d->ifp->if_timer = 10; +#endif + } +#ifndef NETGRAPH + d->ifp->if_drv_flags |= IFF_DRV_OACTIVE; +#endif +} - case SERIAL_GETMODE: - CX_DEBUG2 (d, ("ioctl: getmode\n")); - s = splhigh (); - CX_LOCK (bd); - *(int*)data = (c->mode == M_ASYNC) ? - SERIAL_ASYNC : SERIAL_HDLC; - CX_UNLOCK (bd); - splx (s); - return 0; +/* + * Start output on the interface. + * Always called on splimp(). + */ +static void cx_start (drv_t *d) +{ + int s = splhigh (); + if (d->running) { + if (! d->chan->dtr) + cx_set_dtr (d->chan, 1); + if (! d->chan->rts) + cx_set_rts (d->chan, 1); + cx_send (d); + } + splx (s); +} - case SERIAL_SETMODE: - CX_DEBUG2 (d, ("ioctl: setmode\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; +/* + * Handle transmit timeouts. + * Recover after lost transmit interrupts. + * Always called on splimp(). + */ +static void cx_watchdog (drv_t *d) +{ + bdrv_t *bd = d->board->sys; + + int s = splhigh (); + CX_LOCK (bd); + CX_DEBUG (d, ("device timeout\n")); + if (d->running) { + cx_setup_chan (d->chan); + cx_start_chan (d->chan, 0, 0); + cx_set_dtr (d->chan, 1); + cx_set_rts (d->chan, 1); + cx_start (d); + } + CX_UNLOCK (bd); + splx (s); +} - /* Somebody is waiting for carrier? */ - if (d->lock) - return EBUSY; - /* /dev/ttyXX is already opened by someone? */ - if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && - (d->open_dev|0x2)) - return EBUSY; - /* Network interface is up? - * Cannot change to async mode. */ - if (c->mode != M_ASYNC && d->running && - (*(int*)data == SERIAL_ASYNC)) - return EBUSY; +/* + * Transmit callback function. + */ +static void cx_transmit (cx_chan_t *c, void *attachment, int len) +{ + drv_t *d = c->sys; - s = splhigh (); - CX_LOCK (bd); - if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) { - cx_set_mode (c, M_ASYNC); - cx_enable_receive (c, 0); - cx_enable_transmit (c, 0); - } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) { - cx_set_mode (c, M_HDLC); - cx_enable_receive (c, 1); - cx_enable_transmit (c, 1); + if (!d) + return; + + if (c->mode == M_ASYNC && d->tty) { + d->tty->t_state &= ~(TS_BUSY | TS_FLUSH); + d->atimeout = 0; + if (d->tty->t_dev) { + d->intr_action |= CX_WRITE; + MY_SOFT_INTR = 1; + swi_sched (cx_fast_ih, 0); } - CX_UNLOCK (bd); - splx (s); - return 0; + return; + } +#ifdef NETGRAPH + d->timeout = 0; +#else + ++d->ifp->if_opackets; + d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + d->ifp->if_timer = 0; +#endif + cx_start (d); +} - case SERIAL_GETSTAT: - CX_DEBUG2 (d, ("ioctl: getestat\n")); - st = (struct serial_statistics*) data; - s = splhigh (); - CX_LOCK (bd); - st->rintr = c->rintr; - st->tintr = c->tintr; - st->mintr = c->mintr; - st->ibytes = c->ibytes; - st->ipkts = c->ipkts; - st->ierrs = c->ierrs; - st->obytes = c->obytes; - st->opkts = c->opkts; - st->oerrs = c->oerrs; - CX_UNLOCK (bd); - splx (s); - return 0; +/* + * Process the received packet. + */ +static void cx_receive (cx_chan_t *c, char *data, int len) +{ + drv_t *d = c->sys; + struct mbuf *m; + char *cc = data; +#ifdef NETGRAPH + int error; +#endif - case SERIAL_CLRSTAT: - CX_DEBUG2 (d, ("ioctl: clrstat\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splhigh (); - CX_LOCK (bd); - c->rintr = 0; - c->tintr = 0; - c->mintr = 0; - c->ibytes = 0; - c->ipkts = 0; - c->ierrs = 0; - c->obytes = 0; - c->opkts = 0; - c->oerrs = 0; - CX_UNLOCK (bd); - splx (s); - return 0; + if (!d) + return; + + if (c->mode == M_ASYNC && d->tty) { + if (d->tty->t_state & TS_ISOPEN) { + async_q *q = &d->aqueue; + int size = BF_SZ - 1 - AQ_GSZ (q); - case SERIAL_GETBAUD: - CX_DEBUG2 (d, ("ioctl: getbaud\n")); - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - *(long*)data = cx_get_baud(c); - CX_UNLOCK (bd); - splx (s); - return 0; + if (len <= 0 && !size) + return; - case SERIAL_SETBAUD: - CX_DEBUG2 (d, ("ioctl: setbaud\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - cx_set_baud (c, *(long*)data); - CX_UNLOCK (bd); - splx (s); - return 0; + if (len > size) { + c->ierrs++; + cx_error (c, CX_OVERRUN); + len = size - 1; + } - case SERIAL_GETLOOP: - CX_DEBUG2 (d, ("ioctl: getloop\n")); - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - *(int*)data = cx_get_loop (c); - CX_UNLOCK (bd); - splx (s); - return 0; + while (len--) { + AQ_PUSH (q, *(unsigned char *)cc); + cc++; + } - case SERIAL_SETLOOP: - CX_DEBUG2 (d, ("ioctl: setloop\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - cx_set_loop (c, *(int*)data); - CX_UNLOCK (bd); - splx (s); - return 0; + d->intr_action |= CX_READ; + MY_SOFT_INTR = 1; + swi_sched (cx_fast_ih, 0); + } + return; + } + if (! d->running) + return; - case SERIAL_GETDPLL: - CX_DEBUG2 (d, ("ioctl: getdpll\n")); - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - *(int*)data = cx_get_dpll (c); - CX_UNLOCK (bd); - splx (s); - return 0; + m = makembuf (data, len); + if (! m) { + CX_DEBUG (d, ("no memory for packet\n")); +#ifndef NETGRAPH + ++d->ifp->if_iqdrops; +#endif + return; + } + if (c->debug > 1) + printmbuf (m); +#ifdef NETGRAPH + m->m_pkthdr.rcvif = 0; + NG_SEND_DATA_ONLY (error, d->hook, m); +#else + ++d->ifp->if_ipackets; + m->m_pkthdr.rcvif = d->ifp; + /* Check if there's a BPF listener on this interface. + * If so, hand off the raw packet to bpf. */ + if (d->ifp->if_bpf) + BPF_TAP (d->ifp, data, len); + IF_ENQUEUE (&d->queue, m); +#endif +} - case SERIAL_SETDPLL: - CX_DEBUG2 (d, ("ioctl: setdpll\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - cx_set_dpll (c, *(int*)data); - CX_UNLOCK (bd); - splx (s); - return 0; +#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ + && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ + && (!(tp->t_iflag & PARMRK)\ + || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ + && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ + && linesw[tp->t_line]->l_rint == ttyinput) - case SERIAL_GETNRZI: - CX_DEBUG2 (d, ("ioctl: getnrzi\n")); - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - *(int*)data = cx_get_nrzi (c); - CX_UNLOCK (bd); - splx (s); - return 0; +/* + * Error callback function. + */ +static void cx_error (cx_chan_t *c, int data) +{ + drv_t *d = c->sys; + async_q *q; - case SERIAL_SETNRZI: - CX_DEBUG2 (d, ("ioctl: setnrzi\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_ASYNC) - return EINVAL; - s = splhigh (); - CX_LOCK (bd); - cx_set_nrzi (c, *(int*)data); - CX_UNLOCK (bd); - splx (s); - return 0; + if (!d) + return; - case SERIAL_GETDEBUG: - CX_DEBUG2 (d, ("ioctl: getdebug\n")); - s = splhigh (); - CX_LOCK (bd); - *(int*)data = c->debug; - CX_UNLOCK (bd); - splx (s); - return 0; + q = &(d->aqueue); - case SERIAL_SETDEBUG: - CX_DEBUG2 (d, ("ioctl: setdebug\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splhigh (); - CX_LOCK (bd); - c->debug = *(int*)data; - CX_UNLOCK (bd); - splx (s); -#ifndef NETGRAPH - if (d->chan->debug) - d->ifp->if_flags |= IFF_DEBUG; + switch (data) { + case CX_FRAME: + CX_DEBUG (d, ("frame error\n")); + if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) + && (AQ_GSZ (q) < BF_SZ - 1) + && (!CONDITION((&d->tty->t_termios), (d->tty)) + || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { + AQ_PUSH (q, TTY_FE); + d->intr_action |= CX_READ; + MY_SOFT_INTR = 1; + swi_sched (cx_fast_ih, 0); + } +#ifndef NETGRAPH else - d->ifp->if_flags &= (~IFF_DEBUG); + ++d->ifp->if_ierrors; #endif - return 0; + break; + case CX_CRC: + CX_DEBUG (d, ("crc error\n")); + if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) + && (AQ_GSZ (q) < BF_SZ - 1) + && (!CONDITION((&d->tty->t_termios), (d->tty)) + || !(d->tty->t_iflag & INPCK) + || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { + AQ_PUSH (q, TTY_PE); + d->intr_action |= CX_READ; + MY_SOFT_INTR = 1; + swi_sched (cx_fast_ih, 0); + } +#ifndef NETGRAPH + else + ++d->ifp->if_ierrors; +#endif + break; + case CX_OVERRUN: + CX_DEBUG (d, ("overrun error\n")); +#ifdef TTY_OE + if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) + && (AQ_GSZ (q) < BF_SZ - 1) + && (!CONDITION((&d->tty->t_termios), (d->tty)))) { + AQ_PUSH (q, TTY_OE); + d->intr_action |= CX_READ; + MY_SOFT_INTR = 1; + swi_sched (cx_fast_ih, 0); + } +#endif +#ifndef NETGRAPH + else { + ++d->ifp->if_collisions; + ++d->ifp->if_ierrors; + } +#endif + break; + case CX_OVERFLOW: + CX_DEBUG (d, ("overflow error\n")); +#ifndef NETGRAPH + if (c->mode != M_ASYNC) + ++d->ifp->if_ierrors; +#endif + break; + case CX_UNDERRUN: + CX_DEBUG (d, ("underrun error\n")); + if (c->mode != M_ASYNC) { +#ifdef NETGRAPH + d->timeout = 0; +#else + ++d->ifp->if_oerrors; + d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + d->ifp->if_timer = 0; + cx_start (d); +#endif + } + break; + case CX_BREAK: + CX_DEBUG (d, ("break error\n")); + if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) + && (AQ_GSZ (q) < BF_SZ - 1) + && (!CONDITION((&d->tty->t_termios), (d->tty)) + || !(d->tty->t_iflag & (IGNBRK | BRKINT | PARMRK)))) { + AQ_PUSH (q, TTY_BI); + d->intr_action |= CX_READ; + MY_SOFT_INTR = 1; + swi_sched (cx_fast_ih, 0); + } +#ifndef NETGRAPH + else + ++d->ifp->if_ierrors; +#endif + break; + default: + CX_DEBUG (d, ("error #%d\n", data)); } +} - switch (cmd) { - case TIOCSDTR: /* Set DTR */ - CX_DEBUG2 (d, ("ioctl: tiocsdtr\n")); - s = splhigh (); - CX_LOCK (bd); - cx_set_dtr (c, 1); - CX_UNLOCK (bd); - splx (s); - return 0; +static int cx_topen (struct tty *tp, struct cdev *dev) +{ + bdrv_t *bd; + drv_t *d; - case TIOCCDTR: /* Clear DTR */ - CX_DEBUG2 (d, ("ioctl: tioccdtr\n")); - s = splhigh (); - CX_LOCK (bd); - cx_set_dtr (c, 0); - CX_UNLOCK (bd); - splx (s); - return 0; + d = tp->t_sc; + CX_DEBUG2 (d, ("cx_open (serial)\n")); - case TIOCMSET: /* Set DTR/RTS */ - CX_DEBUG2 (d, ("ioctl: tiocmset\n")); - s = splhigh (); - CX_LOCK (bd); - cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); - cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); - CX_UNLOCK (bd); - splx (s); - return 0; + bd = d->board->sys; - case TIOCMBIS: /* Add DTR/RTS */ - CX_DEBUG2 (d, ("ioctl: tiocmbis\n")); - s = splhigh (); - CX_LOCK (bd); - if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1); - if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1); - CX_UNLOCK (bd); - splx (s); - return 0; + if (d->chan->mode != M_ASYNC) + return (EBUSY); - case TIOCMBIC: /* Clear DTR/RTS */ - CX_DEBUG2 (d, ("ioctl: tiocmbic\n")); - s = splhigh (); - CX_LOCK (bd); - if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0); - if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0); - CX_UNLOCK (bd); - splx (s); - return 0; + d->open_dev |= 0x2; + CX_LOCK (bd); + cx_start_chan (d->chan, 0, 0); + cx_set_dtr (d->chan, 1); + cx_set_rts (d->chan, 1); + d->cd = cx_get_cd (d->chan); + CX_UNLOCK (bd); - case TIOCMGET: /* Get modem status */ - CX_DEBUG2 (d, ("ioctl: tiocmget\n")); - *(int*)data = cx_modem_status (d); - return 0; + CX_DEBUG2 (d, ("cx_open done\n")); + + return 0; +} + +static void cx_tclose (struct tty *tp) +{ + drv_t *d; + bdrv_t *bd; + + d = tp->t_sc; + CX_DEBUG2 (d, ("cx_close\n")); + bd = d->board->sys; + CX_LOCK (bd); + /* Disable receiver. + * Transmitter continues sending the queued data. */ + cx_enable_receive (d->chan, 0); + CX_UNLOCK (bd); + d->open_dev &= ~0x2; +} + +static int cx_tmodem (struct tty *tp, int sigon, int sigoff) +{ + drv_t *d; + bdrv_t *bd; + + d = tp->t_sc; + bd = d->board->sys; + CX_LOCK (bd); + if (!sigon && !sigoff) { + if (cx_get_dsr (d->chan)) sigon |= SER_DSR; + if (cx_get_cd (d->chan)) sigon |= SER_DCD; + if (cx_get_cts (d->chan)) sigon |= SER_CTS; + if (d->chan->dtr) sigon |= SER_DTR; + if (d->chan->rts) sigon |= SER_RTS; + CX_UNLOCK (bd); + return sigon; } - CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd)); - return ENOTTY; + if (sigon & SER_DTR) + cx_set_dtr (d->chan, 1); + if (sigoff & SER_DTR) + cx_set_dtr (d->chan, 0); + if (sigon & SER_RTS) + cx_set_rts (d->chan, 1); + if (sigoff & SER_RTS) + cx_set_rts (d->chan, 0); + CX_UNLOCK (bd); + + return (0); } void cx_softintr (void *unused) @@ -2265,15 +2273,6 @@ static void cx_modem (cx_chan_t *c) callout_reset (&d->dcd_timeout_handle, hz/2, cx_carrier, d); } -static struct cdevsw cx_cdevsw = { - .d_version = D_VERSION, - .d_open = cx_open, - .d_close = cx_close, - .d_ioctl = cx_ioctl, - .d_name = "cx", - .d_flags = D_TTY | D_NEEDGIANT, -}; - #ifdef NETGRAPH static int ng_cx_constructor (node_p node) { -- cgit v1.1