diff options
author | obrien <obrien@FreeBSD.org> | 2005-09-07 09:53:35 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2005-09-07 09:53:35 +0000 |
commit | 34dc93c2f2a2e67b9f17f39ad8552571a143e782 (patch) | |
tree | 28f83baedd163c4751acbd1ff6da3ae8c9c91c01 /sys/dev | |
parent | a477d798c9d45ce12b97ca4ff0933eab79a52b77 (diff) | |
download | FreeBSD-src-34dc93c2f2a2e67b9f17f39ad8552571a143e782.zip FreeBSD-src-34dc93c2f2a2e67b9f17f39ad8552571a143e782.tar.gz |
Reorder code to not depend on an ISO-C illegal forward extern declaration.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/cp/if_cp.c | 1599 | ||||
-rw-r--r-- | sys/dev/ctau/if_ct.c | 1083 | ||||
-rw-r--r-- | sys/dev/cx/if_cx.c | 907 |
3 files changed, 1793 insertions, 1796 deletions
diff --git a/sys/dev/cp/if_cp.c b/sys/dev/cp/if_cp.c index 6a0355e..ab24f6f 100644 --- a/sys/dev/cp/if_cp.c +++ b/sys/dev/cp/if_cp.c @@ -185,806 +185,6 @@ static struct callout timeout_handle; static int cp_destroy = 0; /* - * 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, unsigned len) -{ - struct mbuf *m; - - MGETHDR (m, M_DONTWAIT, MT_DATA); - if (! m) - return 0; - MCLGET (m, M_DONTWAIT); - if (! (m->m_flags & M_EXT)) { - m_freem (m); - return 0; - } - m->m_pkthdr.len = m->m_len = len; - bcopy (buf, mtod (m, caddr_t), len); - return m; -} - -static int cp_probe (device_t dev) -{ - if ((pci_get_vendor (dev) == cp_vendor_id) && - (pci_get_device (dev) == cp_device_id)) { - device_set_desc (dev, "Cronyx-Tau-PCI serial adapter"); - return BUS_PROBE_DEFAULT; - } - return ENXIO; -} - -static void cp_timeout (void *arg) -{ - drv_t *d; - int s, i, k; - - for (i = 0; i < NBRD; ++i) { - if (adapter[i] == NULL) - continue; - for (k = 0; k < NCHAN; ++k) { - s = splimp (); - if (cp_destroy) { - splx (s); - return; - } - d = channel[i * NCHAN + k]; - if (!d) { - splx (s); - continue; - } - CP_LOCK ((bdrv_t *)d->board->sys); - switch (d->chan->type) { - case T_G703: - cp_g703_timer (d->chan); - break; - case T_E1: - cp_e1_timer (d->chan); - break; - case T_E3: - case T_T3: - case T_STS1: - cp_e3_timer (d->chan); - break; - default: - break; - } - CP_UNLOCK ((bdrv_t *)d->board->sys); - splx (s); - } - } - s = splimp (); - if (!cp_destroy) - callout_reset (&timeout_handle, hz, cp_timeout, 0); - splx (s); -} - -static void cp_led_off (void *arg) -{ - cp_board_t *b = arg; - bdrv_t *bd = (bdrv_t *) b->sys; - int s; - s = splimp (); - if (cp_destroy) { - splx (s); - return; - } - CP_LOCK (bd); - cp_led (b, 0); - CP_UNLOCK (bd); - splx (s); -} - -static void cp_intr (void *arg) -{ - bdrv_t *bd = arg; - cp_board_t *b = bd->board; -#ifndef NETGRAPH - int i; -#endif - int s = splimp (); - if (cp_destroy) { - splx (s); - return; - } - CP_LOCK (bd); - /* Check if we are ready */ - if (b->sys == NULL) { - /* Not we are not, just cleanup. */ - cp_interrupt_poll (b, 1); - CP_UNLOCK (bd); - return; - } - /* Turn LED on. */ - cp_led (b, 1); - - cp_interrupt (b); - - /* Turn LED off 50 msec later. */ - callout_reset (&led_timo[b->num], hz/20, cp_led_off, b); - CP_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 -} - -extern struct cdevsw cp_cdevsw; - -static void -cp_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 -cp_bus_dma_mem_alloc (int bnum, int cnum, cp_dma_mem_t *dmem) -{ - int error; - - error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT, - BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1, - dmem->size, 0, NULL, NULL, &dmem->dmat); - if (error) { - if (cnum >= 0) printf ("cp%d-%d: ", bnum, cnum); - else printf ("cp%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 ("cp%d-%d: ", bnum, cnum); - else printf ("cp%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, cp_bus_dmamap_addr, &dmem->phys, 0); - if (error) { - if (cnum >= 0) printf ("cp%d-%d: ", bnum, cnum); - else printf ("cp%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 -cp_bus_dma_mem_free (cp_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); -} - -/* - * Called if the probe succeeded. - */ -static int cp_attach (device_t dev) -{ - bdrv_t *bd = device_get_softc (dev); - int unit = device_get_unit (dev); - char *cp_ln = CP_LOCK_NAME; - unsigned short res; - vm_offset_t vbase; - int rid, error; - cp_board_t *b; - cp_chan_t *c; - drv_t *d; - int s = splimp (); - - b = malloc (sizeof(cp_board_t), M_DEVBUF, M_WAITOK); - if (!b) { - printf ("cp%d: couldn't allocate memory\n", unit); - splx (s); - return (ENXIO); - } - bzero (b, sizeof(cp_board_t)); - - bd->board = b; - rid = PCIR_BAR(0); - bd->cp_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid, - 0, ~0, 1, RF_ACTIVE); - if (! bd->cp_res) { - printf ("cp%d: cannot map memory\n", unit); - free (b, M_DEVBUF); - splx (s); - return (ENXIO); - } - vbase = (vm_offset_t) rman_get_virtual (bd->cp_res); - - cp_ln[2] = '0' + unit; - mtx_init (&bd->cp_mtx, cp_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE); - res = cp_init (b, unit, (u_char*) vbase); - if (res) { - printf ("cp%d: can't init, error code:%x\n", unit, res); - bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); - free (b, M_DEVBUF); - splx (s); - return (ENXIO); - } - - bd->dmamem.size = sizeof(cp_qbuf_t); - if (! cp_bus_dma_mem_alloc (unit, -1, &bd->dmamem)) { - free (b, M_DEVBUF); - splx (s); - return (ENXIO); - } - CP_LOCK (bd); - cp_reset (b, bd->dmamem.virt, bd->dmamem.phys); - CP_UNLOCK (bd); - - rid = 0; - bd->cp_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1, - RF_SHAREABLE | RF_ACTIVE); - if (! bd->cp_irq) { - cp_destroy = 1; - printf ("cp%d: cannot map interrupt\n", unit); - bus_release_resource (dev, SYS_RES_MEMORY, - PCIR_BAR(0), bd->cp_res); - mtx_destroy (&bd->cp_mtx); - free (b, M_DEVBUF); - splx (s); - return (ENXIO); - } - callout_init (&led_timo[unit], cp_mpsafenet ? CALLOUT_MPSAFE : 0); - error = bus_setup_intr (dev, bd->cp_irq, - INTR_TYPE_NET|(cp_mpsafenet?INTR_MPSAFE:0), - cp_intr, bd, &bd->cp_intrhand); - if (error) { - cp_destroy = 1; - printf ("cp%d: cannot set up irq\n", unit); - bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); - bus_release_resource (dev, SYS_RES_MEMORY, - PCIR_BAR(0), bd->cp_res); - mtx_destroy (&bd->cp_mtx); - free (b, M_DEVBUF); - splx (s); - return (ENXIO); - } - printf ("cp%d: %s, clock %ld MHz\n", unit, b->name, b->osc / 1000000); - - for (c = b->chan; c < b->chan + NCHAN; ++c) { - if (! c->type) - continue; - d = &bd->channel[c->num]; - d->dmamem.size = sizeof(cp_buf_t); - if (! cp_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) - continue; - channel [b->num*NCHAN + c->num] = d; - sprintf (d->name, "cp%d.%d", b->num, c->num); - d->board = b; - d->chan = c; - c->sys = d; -#ifdef NETGRAPH - if (ng_make_node_common (&typestruct, &d->node) != 0) { - printf ("%s: cannot make common node\n", d->name); - d->node = NULL; - continue; - } - NG_NODE_SET_PRIVATE (d->node, d); - sprintf (d->nodename, "%s%d", NG_CP_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); - continue; - } - d->queue.ifq_maxlen = IFQ_MAXLEN; - d->hi_queue.ifq_maxlen = IFQ_MAXLEN; - mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); - mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF); - callout_init (&d->timeout_handle, - cp_mpsafenet ? CALLOUT_MPSAFE : 0); -#else /*NETGRAPH*/ - d->ifp = if_alloc(IFT_PPP); - if (d->ifp == NULL) { - printf ("%s: cannot if_alloc() interface\n", d->name); - continue; - } - d->ifp->if_softc = d; - if_initname (d->ifp, "cp", b->num * NCHAN + c->num); - d->ifp->if_mtu = PP_MTU; - d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; - if (!cp_mpsafenet) - d->ifp->if_flags |= IFF_NEEDSGIANT; - d->ifp->if_ioctl = cp_sioctl; - d->ifp->if_start = cp_ifstart; - d->ifp->if_watchdog = cp_ifwatchdog; - d->ifp->if_init = cp_initialize; - d->queue.ifq_maxlen = NRBUF; - mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); - sppp_attach (d->ifp); - if_attach (d->ifp); - IFP2SP(d->ifp)->pp_tlf = cp_tlf; - IFP2SP(d->ifp)->pp_tls = cp_tls; - /* If BPF is in the kernel, call the attach for it. - * The header size of PPP or Cisco/HDLC is 4 bytes. */ - bpfattach (d->ifp, DLT_PPP, 4); -#endif /*NETGRAPH*/ - cp_start_e1 (c); - cp_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys); - - /* Register callback functions. */ - cp_register_transmit (c, &cp_transmit); - cp_register_receive (c, &cp_receive); - cp_register_error (c, &cp_error); - d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT, - GID_WHEEL, 0600, "cp%d", b->num*NCHAN+c->num); - } - CP_LOCK (bd); - b->sys = bd; - adapter[unit] = b; - CP_UNLOCK (bd); - splx (s); - return 0; -} - -static int cp_detach (device_t dev) -{ - bdrv_t *bd = device_get_softc (dev); - cp_board_t *b = bd->board; - cp_chan_t *c; - int s; - - KASSERT (mtx_initialized (&bd->cp_mtx), ("cp mutex not initialized")); - s = splimp (); - CP_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; - - if (! d || ! d->chan->type) - continue; - if (d->running) { - CP_UNLOCK (bd); - splx (s); - return EBUSY; - } - } - - /* Ok, we can unload driver */ - /* At first we should stop all channels */ - for (c = b->chan; c < b->chan + NCHAN; ++c) { - drv_t *d = (drv_t*) c->sys; - - if (! d || ! d->chan->type) - continue; - - cp_stop_chan (c); - cp_stop_e1 (c); - cp_set_dtr (d->chan, 0); - cp_set_rts (d->chan, 0); - } - - /* Reset the adapter. */ - cp_destroy = 1; - cp_interrupt_poll (b, 1); - cp_led_off (b); - cp_reset (b, 0 ,0); - callout_stop (&led_timo[b->num]); - - for (c=b->chan; c<b->chan+NCHAN; ++c) { - drv_t *d = (drv_t*) c->sys; - - if (! d || ! d->chan->type) - continue; -#ifndef NETGRAPH - /* Detach from the packet filter list of interfaces. */ - bpfdetach (d->ifp); - - /* Detach from the sync PPP list. */ - sppp_detach (d->ifp); - - /* Detach from the system list of interfaces. */ - if_detach (d->ifp); - if_free (d->ifp); - IF_DRAIN (&d->queue); - mtx_destroy (&d->queue.ifq_mtx); -#else - if (d->node) { - ng_rmnode_self (d->node); - NG_NODE_UNREF (d->node); - d->node = NULL; - } - mtx_destroy (&d->queue.ifq_mtx); - mtx_destroy (&d->hi_queue.ifq_mtx); -#endif - destroy_dev (d->devt); - } - - b->sys = NULL; - CP_UNLOCK (bd); - - /* Disable the interrupt request. */ - bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand); - bus_deactivate_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); - bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); - bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); - - CP_LOCK (bd); - cp_led_off (b); - CP_UNLOCK (bd); - callout_drain (&led_timo[b->num]); - splx (s); - - s = splimp (); - for (c = b->chan; c < b->chan + NCHAN; ++c) { - drv_t *d = (drv_t*) c->sys; - - if (! d || ! d->chan->type) - continue; - channel [b->num*NCHAN + c->num] = 0; - /* Deallocate buffers. */ - cp_bus_dma_mem_free (&d->dmamem); - } - adapter [b->num] = 0; - cp_bus_dma_mem_free (&bd->dmamem); - free (b, M_DEVBUF); - splx (s); - mtx_destroy (&bd->cp_mtx); - return 0; -} - -#ifndef NETGRAPH -static void cp_ifstart (struct ifnet *ifp) -{ - drv_t *d = ifp->if_softc; - bdrv_t *bd = d->board->sys; - - CP_LOCK (bd); - cp_start (d); - CP_UNLOCK (bd); -} - -static void cp_ifwatchdog (struct ifnet *ifp) -{ - drv_t *d = ifp->if_softc; - - cp_watchdog (d); -} - -static void cp_tlf (struct sppp *sp) -{ - drv_t *d = SP2IFP(sp)->if_softc; - - CP_DEBUG2 (d, ("cp_tlf\n")); - /* XXXRIK: Don't forget to protect them by LOCK, or kill them. */ -/* cp_set_dtr (d->chan, 0);*/ -/* cp_set_rts (d->chan, 0);*/ - if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) - sp->pp_down (sp); -} - -static void cp_tls (struct sppp *sp) -{ - drv_t *d = SP2IFP(sp)->if_softc; - - CP_DEBUG2 (d, ("cp_tls\n")); - if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) - sp->pp_up (sp); -} - -/* - * Process an ioctl request. - */ -static int cp_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; - - 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: CP_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; - case SIOCADDMULTI: CP_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0; - case SIOCDELMULTI: CP_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0; - case SIOCSIFFLAGS: CP_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break; - case SIOCSIFADDR: CP_DEBUG2 (d, ("ioctl SIOCSIFADDR\n")); break; - } - - /* We get here only in case of SIFFLAGS or SIFADDR. */ - s = splimp (); - CP_LOCK (bd); - should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; - if (! was_up && should_be_up) { - /* Interface goes up -- start it. */ - cp_up (d); - cp_start (d); - } else if (was_up && ! should_be_up) { - /* Interface is going down -- stop it. */ -/* if ((IFP2SP(ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ - cp_down (d); - } - CP_DEBUG (d, ("ioctl 0x%lx p4\n", cmd)); - CP_UNLOCK (bd); - splx (s); - return 0; -} - -/* - * Initialization of interface. - * It seems to be never called by upper level? - */ -static void cp_initialize (void *softc) -{ - drv_t *d = softc; - - CP_DEBUG (d, ("cp_initialize\n")); -} -#endif /*NETGRAPH*/ - -/* - * Stop the interface. Called on splimp(). - */ -static void cp_down (drv_t *d) -{ - CP_DEBUG (d, ("cp_down\n")); - /* Interface is going down -- stop it. */ - cp_set_dtr (d->chan, 0); - cp_set_rts (d->chan, 0); - - d->running = 0; -} - -/* - * Start the interface. Called on splimp(). - */ -static void cp_up (drv_t *d) -{ - CP_DEBUG (d, ("cp_up\n")); - cp_set_dtr (d->chan, 1); - cp_set_rts (d->chan, 1); - d->running = 1; -} - -/* - * Start output on the interface. Get another datagram to send - * off of the interface queue, and copy it to the interface - * before starting the output. - */ -static void cp_send (drv_t *d) -{ - struct mbuf *m; - u_short len; - - CP_DEBUG2 (d, ("cp_send, tn=%d te=%d\n", d->chan->tn, d->chan->te)); - - /* No output if the interface is down. */ - if (! d->running) - return; - - /* No output if the modem is off. */ - if (! (d->chan->lloop || d->chan->type != T_SERIAL || - cp_get_dsr (d->chan))) - return; - - while (cp_transmit_space (d->chan)) { - /* Get the packet to send. */ -#ifdef NETGRAPH - IF_DEQUEUE (&d->hi_queue, m); - if (! m) - IF_DEQUEUE (&d->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 (len >= BUFSZ) - printf ("%s: too long packet: %d bytes: ", - d->name, len); - else if (! m->m_next) - cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); - else { - u_char *buf = d->chan->tbuf[d->chan->te]; - m_copydata (m, 0, len, buf); - cp_send_packet (d->chan, buf, len, 0); - } - m_freem (m); - /* Set up transmit timeout, if the transmit ring is not empty.*/ -#ifdef NETGRAPH - d->timeout = 10; -#else - d->ifp->if_timer = 10; -#endif - } -#ifndef NETGRAPH - d->ifp->if_drv_flags |= IFF_DRV_OACTIVE; -#endif -} - -/* - * Start output on the interface. - * Always called on splimp(). - */ -static void cp_start (drv_t *d) -{ - if (d->running) { - if (! d->chan->dtr) - cp_set_dtr (d->chan, 1); - if (! d->chan->rts) - cp_set_rts (d->chan, 1); - cp_send (d); - } -} - -/* - * Handle transmit timeouts. - * Recover after lost transmit interrupts. - * Always called on splimp(). - */ -static void cp_watchdog (drv_t *d) -{ - bdrv_t *bd = d->board->sys; - CP_DEBUG (d, ("device timeout\n")); - if (d->running) { - int s = splimp (); - - CP_LOCK (bd); - cp_stop_chan (d->chan); - cp_stop_e1 (d->chan); - cp_start_e1 (d->chan); - cp_start_chan (d->chan, 1, 1, 0, 0); - cp_set_dtr (d->chan, 1); - cp_set_rts (d->chan, 1); - cp_start (d); - CP_UNLOCK (bd); - splx (s); - } -} - -static void cp_transmit (cp_chan_t *c, void *attachment, int len) -{ - drv_t *d = c->sys; - -#ifdef NETGRAPH - d->timeout = 0; -#else - ++d->ifp->if_opackets; - d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - d->ifp->if_timer = 0; -#endif - cp_start (d); -} - -static void cp_receive (cp_chan_t *c, unsigned char *data, int len) -{ - drv_t *d = c->sys; - struct mbuf *m; -#ifdef NETGRAPH - int error; -#endif - - if (! d->running) - return; - - m = makembuf (data, len); - if (! m) { - CP_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 -} - -static void cp_error (cp_chan_t *c, int data) -{ - drv_t *d = c->sys; - - switch (data) { - case CP_FRAME: - CP_DEBUG (d, ("frame error\n")); -#ifndef NETGRAPH - ++d->ifp->if_ierrors; -#endif - break; - case CP_CRC: - CP_DEBUG (d, ("crc error\n")); -#ifndef NETGRAPH - ++d->ifp->if_ierrors; -#endif - break; - case CP_OVERRUN: - CP_DEBUG (d, ("overrun error\n")); -#ifndef NETGRAPH - ++d->ifp->if_collisions; - ++d->ifp->if_ierrors; -#endif - break; - case CP_OVERFLOW: - CP_DEBUG (d, ("overflow error\n")); -#ifndef NETGRAPH - ++d->ifp->if_ierrors; -#endif - break; - case CP_UNDERRUN: - CP_DEBUG (d, ("underrun error\n")); -#ifdef NETGRAPH - d->timeout = 0; -#else - ++d->ifp->if_oerrors; - d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - d->ifp->if_timer = 0; -#endif - cp_start (d); - break; - default: - CP_DEBUG (d, ("error #%d\n", data)); - break; - } -} - -/* * You also need read, write, open, close routines. * This should get you started */ @@ -1029,6 +229,7 @@ static int cp_modem_status (cp_chan_t *c) return status; } + static int cp_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { drv_t *d = channel [minor (dev)]; @@ -1819,6 +1020,804 @@ static struct cdevsw cp_cdevsw = { .d_flags = D_NEEDGIANT, }; +/* + * 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, unsigned len) +{ + struct mbuf *m; + + MGETHDR (m, M_DONTWAIT, MT_DATA); + if (! m) + return 0; + MCLGET (m, M_DONTWAIT); + if (! (m->m_flags & M_EXT)) { + m_freem (m); + return 0; + } + m->m_pkthdr.len = m->m_len = len; + bcopy (buf, mtod (m, caddr_t), len); + return m; +} + +static int cp_probe (device_t dev) +{ + if ((pci_get_vendor (dev) == cp_vendor_id) && + (pci_get_device (dev) == cp_device_id)) { + device_set_desc (dev, "Cronyx-Tau-PCI serial adapter"); + return BUS_PROBE_DEFAULT; + } + return ENXIO; +} + +static void cp_timeout (void *arg) +{ + drv_t *d; + int s, i, k; + + for (i = 0; i < NBRD; ++i) { + if (adapter[i] == NULL) + continue; + for (k = 0; k < NCHAN; ++k) { + s = splimp (); + if (cp_destroy) { + splx (s); + return; + } + d = channel[i * NCHAN + k]; + if (!d) { + splx (s); + continue; + } + CP_LOCK ((bdrv_t *)d->board->sys); + switch (d->chan->type) { + case T_G703: + cp_g703_timer (d->chan); + break; + case T_E1: + cp_e1_timer (d->chan); + break; + case T_E3: + case T_T3: + case T_STS1: + cp_e3_timer (d->chan); + break; + default: + break; + } + CP_UNLOCK ((bdrv_t *)d->board->sys); + splx (s); + } + } + s = splimp (); + if (!cp_destroy) + callout_reset (&timeout_handle, hz, cp_timeout, 0); + splx (s); +} + +static void cp_led_off (void *arg) +{ + cp_board_t *b = arg; + bdrv_t *bd = (bdrv_t *) b->sys; + int s; + s = splimp (); + if (cp_destroy) { + splx (s); + return; + } + CP_LOCK (bd); + cp_led (b, 0); + CP_UNLOCK (bd); + splx (s); +} + +static void cp_intr (void *arg) +{ + bdrv_t *bd = arg; + cp_board_t *b = bd->board; +#ifndef NETGRAPH + int i; +#endif + int s = splimp (); + if (cp_destroy) { + splx (s); + return; + } + CP_LOCK (bd); + /* Check if we are ready */ + if (b->sys == NULL) { + /* Not we are not, just cleanup. */ + cp_interrupt_poll (b, 1); + CP_UNLOCK (bd); + return; + } + /* Turn LED on. */ + cp_led (b, 1); + + cp_interrupt (b); + + /* Turn LED off 50 msec later. */ + callout_reset (&led_timo[b->num], hz/20, cp_led_off, b); + CP_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 +} + +static void +cp_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 +cp_bus_dma_mem_alloc (int bnum, int cnum, cp_dma_mem_t *dmem) +{ + int error; + + error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1, + dmem->size, 0, NULL, NULL, &dmem->dmat); + if (error) { + if (cnum >= 0) printf ("cp%d-%d: ", bnum, cnum); + else printf ("cp%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 ("cp%d-%d: ", bnum, cnum); + else printf ("cp%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, cp_bus_dmamap_addr, &dmem->phys, 0); + if (error) { + if (cnum >= 0) printf ("cp%d-%d: ", bnum, cnum); + else printf ("cp%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 +cp_bus_dma_mem_free (cp_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); +} + +/* + * Called if the probe succeeded. + */ +static int cp_attach (device_t dev) +{ + bdrv_t *bd = device_get_softc (dev); + int unit = device_get_unit (dev); + char *cp_ln = CP_LOCK_NAME; + unsigned short res; + vm_offset_t vbase; + int rid, error; + cp_board_t *b; + cp_chan_t *c; + drv_t *d; + int s = splimp (); + + b = malloc (sizeof(cp_board_t), M_DEVBUF, M_WAITOK); + if (!b) { + printf ("cp%d: couldn't allocate memory\n", unit); + splx (s); + return (ENXIO); + } + bzero (b, sizeof(cp_board_t)); + + bd->board = b; + rid = PCIR_BAR(0); + bd->cp_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid, + 0, ~0, 1, RF_ACTIVE); + if (! bd->cp_res) { + printf ("cp%d: cannot map memory\n", unit); + free (b, M_DEVBUF); + splx (s); + return (ENXIO); + } + vbase = (vm_offset_t) rman_get_virtual (bd->cp_res); + + cp_ln[2] = '0' + unit; + mtx_init (&bd->cp_mtx, cp_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE); + res = cp_init (b, unit, (u_char*) vbase); + if (res) { + printf ("cp%d: can't init, error code:%x\n", unit, res); + bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); + free (b, M_DEVBUF); + splx (s); + return (ENXIO); + } + + bd->dmamem.size = sizeof(cp_qbuf_t); + if (! cp_bus_dma_mem_alloc (unit, -1, &bd->dmamem)) { + free (b, M_DEVBUF); + splx (s); + return (ENXIO); + } + CP_LOCK (bd); + cp_reset (b, bd->dmamem.virt, bd->dmamem.phys); + CP_UNLOCK (bd); + + rid = 0; + bd->cp_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE); + if (! bd->cp_irq) { + cp_destroy = 1; + printf ("cp%d: cannot map interrupt\n", unit); + bus_release_resource (dev, SYS_RES_MEMORY, + PCIR_BAR(0), bd->cp_res); + mtx_destroy (&bd->cp_mtx); + free (b, M_DEVBUF); + splx (s); + return (ENXIO); + } + callout_init (&led_timo[unit], cp_mpsafenet ? CALLOUT_MPSAFE : 0); + error = bus_setup_intr (dev, bd->cp_irq, + INTR_TYPE_NET|(cp_mpsafenet?INTR_MPSAFE:0), + cp_intr, bd, &bd->cp_intrhand); + if (error) { + cp_destroy = 1; + printf ("cp%d: cannot set up irq\n", unit); + bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); + bus_release_resource (dev, SYS_RES_MEMORY, + PCIR_BAR(0), bd->cp_res); + mtx_destroy (&bd->cp_mtx); + free (b, M_DEVBUF); + splx (s); + return (ENXIO); + } + printf ("cp%d: %s, clock %ld MHz\n", unit, b->name, b->osc / 1000000); + + for (c = b->chan; c < b->chan + NCHAN; ++c) { + if (! c->type) + continue; + d = &bd->channel[c->num]; + d->dmamem.size = sizeof(cp_buf_t); + if (! cp_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) + continue; + channel [b->num*NCHAN + c->num] = d; + sprintf (d->name, "cp%d.%d", b->num, c->num); + d->board = b; + d->chan = c; + c->sys = d; +#ifdef NETGRAPH + if (ng_make_node_common (&typestruct, &d->node) != 0) { + printf ("%s: cannot make common node\n", d->name); + d->node = NULL; + continue; + } + NG_NODE_SET_PRIVATE (d->node, d); + sprintf (d->nodename, "%s%d", NG_CP_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); + continue; + } + d->queue.ifq_maxlen = IFQ_MAXLEN; + d->hi_queue.ifq_maxlen = IFQ_MAXLEN; + mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); + mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF); + callout_init (&d->timeout_handle, + cp_mpsafenet ? CALLOUT_MPSAFE : 0); +#else /*NETGRAPH*/ + d->ifp = if_alloc(IFT_PPP); + if (d->ifp == NULL) { + printf ("%s: cannot if_alloc() interface\n", d->name); + continue; + } + d->ifp->if_softc = d; + if_initname (d->ifp, "cp", b->num * NCHAN + c->num); + d->ifp->if_mtu = PP_MTU; + d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; + if (!cp_mpsafenet) + d->ifp->if_flags |= IFF_NEEDSGIANT; + d->ifp->if_ioctl = cp_sioctl; + d->ifp->if_start = cp_ifstart; + d->ifp->if_watchdog = cp_ifwatchdog; + d->ifp->if_init = cp_initialize; + d->queue.ifq_maxlen = NRBUF; + mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); + sppp_attach (d->ifp); + if_attach (d->ifp); + IFP2SP(d->ifp)->pp_tlf = cp_tlf; + IFP2SP(d->ifp)->pp_tls = cp_tls; + /* If BPF is in the kernel, call the attach for it. + * The header size of PPP or Cisco/HDLC is 4 bytes. */ + bpfattach (d->ifp, DLT_PPP, 4); +#endif /*NETGRAPH*/ + cp_start_e1 (c); + cp_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys); + + /* Register callback functions. */ + cp_register_transmit (c, &cp_transmit); + cp_register_receive (c, &cp_receive); + cp_register_error (c, &cp_error); + d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT, + GID_WHEEL, 0600, "cp%d", b->num*NCHAN+c->num); + } + CP_LOCK (bd); + b->sys = bd; + adapter[unit] = b; + CP_UNLOCK (bd); + splx (s); + return 0; +} + +static int cp_detach (device_t dev) +{ + bdrv_t *bd = device_get_softc (dev); + cp_board_t *b = bd->board; + cp_chan_t *c; + int s; + + KASSERT (mtx_initialized (&bd->cp_mtx), ("cp mutex not initialized")); + s = splimp (); + CP_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; + + if (! d || ! d->chan->type) + continue; + if (d->running) { + CP_UNLOCK (bd); + splx (s); + return EBUSY; + } + } + + /* Ok, we can unload driver */ + /* At first we should stop all channels */ + for (c = b->chan; c < b->chan + NCHAN; ++c) { + drv_t *d = (drv_t*) c->sys; + + if (! d || ! d->chan->type) + continue; + + cp_stop_chan (c); + cp_stop_e1 (c); + cp_set_dtr (d->chan, 0); + cp_set_rts (d->chan, 0); + } + + /* Reset the adapter. */ + cp_destroy = 1; + cp_interrupt_poll (b, 1); + cp_led_off (b); + cp_reset (b, 0 ,0); + callout_stop (&led_timo[b->num]); + + for (c=b->chan; c<b->chan+NCHAN; ++c) { + drv_t *d = (drv_t*) c->sys; + + if (! d || ! d->chan->type) + continue; +#ifndef NETGRAPH + /* Detach from the packet filter list of interfaces. */ + bpfdetach (d->ifp); + + /* Detach from the sync PPP list. */ + sppp_detach (d->ifp); + + /* Detach from the system list of interfaces. */ + if_detach (d->ifp); + if_free (d->ifp); + IF_DRAIN (&d->queue); + mtx_destroy (&d->queue.ifq_mtx); +#else + if (d->node) { + ng_rmnode_self (d->node); + NG_NODE_UNREF (d->node); + d->node = NULL; + } + mtx_destroy (&d->queue.ifq_mtx); + mtx_destroy (&d->hi_queue.ifq_mtx); +#endif + destroy_dev (d->devt); + } + + b->sys = NULL; + CP_UNLOCK (bd); + + /* Disable the interrupt request. */ + bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand); + bus_deactivate_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); + bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); + bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); + + CP_LOCK (bd); + cp_led_off (b); + CP_UNLOCK (bd); + callout_drain (&led_timo[b->num]); + splx (s); + + s = splimp (); + for (c = b->chan; c < b->chan + NCHAN; ++c) { + drv_t *d = (drv_t*) c->sys; + + if (! d || ! d->chan->type) + continue; + channel [b->num*NCHAN + c->num] = 0; + /* Deallocate buffers. */ + cp_bus_dma_mem_free (&d->dmamem); + } + adapter [b->num] = 0; + cp_bus_dma_mem_free (&bd->dmamem); + free (b, M_DEVBUF); + splx (s); + mtx_destroy (&bd->cp_mtx); + return 0; +} + +#ifndef NETGRAPH +static void cp_ifstart (struct ifnet *ifp) +{ + drv_t *d = ifp->if_softc; + bdrv_t *bd = d->board->sys; + + CP_LOCK (bd); + cp_start (d); + CP_UNLOCK (bd); +} + +static void cp_ifwatchdog (struct ifnet *ifp) +{ + drv_t *d = ifp->if_softc; + + cp_watchdog (d); +} + +static void cp_tlf (struct sppp *sp) +{ + drv_t *d = SP2IFP(sp)->if_softc; + + CP_DEBUG2 (d, ("cp_tlf\n")); + /* XXXRIK: Don't forget to protect them by LOCK, or kill them. */ +/* cp_set_dtr (d->chan, 0);*/ +/* cp_set_rts (d->chan, 0);*/ + if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) + sp->pp_down (sp); +} + +static void cp_tls (struct sppp *sp) +{ + drv_t *d = SP2IFP(sp)->if_softc; + + CP_DEBUG2 (d, ("cp_tls\n")); + if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) + sp->pp_up (sp); +} + +/* + * Process an ioctl request. + */ +static int cp_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; + + 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: CP_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; + case SIOCADDMULTI: CP_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0; + case SIOCDELMULTI: CP_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0; + case SIOCSIFFLAGS: CP_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break; + case SIOCSIFADDR: CP_DEBUG2 (d, ("ioctl SIOCSIFADDR\n")); break; + } + + /* We get here only in case of SIFFLAGS or SIFADDR. */ + s = splimp (); + CP_LOCK (bd); + should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; + if (! was_up && should_be_up) { + /* Interface goes up -- start it. */ + cp_up (d); + cp_start (d); + } else if (was_up && ! should_be_up) { + /* Interface is going down -- stop it. */ +/* if ((IFP2SP(ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ + cp_down (d); + } + CP_DEBUG (d, ("ioctl 0x%lx p4\n", cmd)); + CP_UNLOCK (bd); + splx (s); + return 0; +} + +/* + * Initialization of interface. + * It seems to be never called by upper level? + */ +static void cp_initialize (void *softc) +{ + drv_t *d = softc; + + CP_DEBUG (d, ("cp_initialize\n")); +} +#endif /*NETGRAPH*/ + +/* + * Stop the interface. Called on splimp(). + */ +static void cp_down (drv_t *d) +{ + CP_DEBUG (d, ("cp_down\n")); + /* Interface is going down -- stop it. */ + cp_set_dtr (d->chan, 0); + cp_set_rts (d->chan, 0); + + d->running = 0; +} + +/* + * Start the interface. Called on splimp(). + */ +static void cp_up (drv_t *d) +{ + CP_DEBUG (d, ("cp_up\n")); + cp_set_dtr (d->chan, 1); + cp_set_rts (d->chan, 1); + d->running = 1; +} + +/* + * Start output on the interface. Get another datagram to send + * off of the interface queue, and copy it to the interface + * before starting the output. + */ +static void cp_send (drv_t *d) +{ + struct mbuf *m; + u_short len; + + CP_DEBUG2 (d, ("cp_send, tn=%d te=%d\n", d->chan->tn, d->chan->te)); + + /* No output if the interface is down. */ + if (! d->running) + return; + + /* No output if the modem is off. */ + if (! (d->chan->lloop || d->chan->type != T_SERIAL || + cp_get_dsr (d->chan))) + return; + + while (cp_transmit_space (d->chan)) { + /* Get the packet to send. */ +#ifdef NETGRAPH + IF_DEQUEUE (&d->hi_queue, m); + if (! m) + IF_DEQUEUE (&d->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 (len >= BUFSZ) + printf ("%s: too long packet: %d bytes: ", + d->name, len); + else if (! m->m_next) + cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); + else { + u_char *buf = d->chan->tbuf[d->chan->te]; + m_copydata (m, 0, len, buf); + cp_send_packet (d->chan, buf, len, 0); + } + m_freem (m); + /* Set up transmit timeout, if the transmit ring is not empty.*/ +#ifdef NETGRAPH + d->timeout = 10; +#else + d->ifp->if_timer = 10; +#endif + } +#ifndef NETGRAPH + d->ifp->if_drv_flags |= IFF_DRV_OACTIVE; +#endif +} + +/* + * Start output on the interface. + * Always called on splimp(). + */ +static void cp_start (drv_t *d) +{ + if (d->running) { + if (! d->chan->dtr) + cp_set_dtr (d->chan, 1); + if (! d->chan->rts) + cp_set_rts (d->chan, 1); + cp_send (d); + } +} + +/* + * Handle transmit timeouts. + * Recover after lost transmit interrupts. + * Always called on splimp(). + */ +static void cp_watchdog (drv_t *d) +{ + bdrv_t *bd = d->board->sys; + CP_DEBUG (d, ("device timeout\n")); + if (d->running) { + int s = splimp (); + + CP_LOCK (bd); + cp_stop_chan (d->chan); + cp_stop_e1 (d->chan); + cp_start_e1 (d->chan); + cp_start_chan (d->chan, 1, 1, 0, 0); + cp_set_dtr (d->chan, 1); + cp_set_rts (d->chan, 1); + cp_start (d); + CP_UNLOCK (bd); + splx (s); + } +} + +static void cp_transmit (cp_chan_t *c, void *attachment, int len) +{ + drv_t *d = c->sys; + +#ifdef NETGRAPH + d->timeout = 0; +#else + ++d->ifp->if_opackets; + d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + d->ifp->if_timer = 0; +#endif + cp_start (d); +} + +static void cp_receive (cp_chan_t *c, unsigned char *data, int len) +{ + drv_t *d = c->sys; + struct mbuf *m; +#ifdef NETGRAPH + int error; +#endif + + if (! d->running) + return; + + m = makembuf (data, len); + if (! m) { + CP_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 +} + +static void cp_error (cp_chan_t *c, int data) +{ + drv_t *d = c->sys; + + switch (data) { + case CP_FRAME: + CP_DEBUG (d, ("frame error\n")); +#ifndef NETGRAPH + ++d->ifp->if_ierrors; +#endif + break; + case CP_CRC: + CP_DEBUG (d, ("crc error\n")); +#ifndef NETGRAPH + ++d->ifp->if_ierrors; +#endif + break; + case CP_OVERRUN: + CP_DEBUG (d, ("overrun error\n")); +#ifndef NETGRAPH + ++d->ifp->if_collisions; + ++d->ifp->if_ierrors; +#endif + break; + case CP_OVERFLOW: + CP_DEBUG (d, ("overflow error\n")); +#ifndef NETGRAPH + ++d->ifp->if_ierrors; +#endif + break; + case CP_UNDERRUN: + CP_DEBUG (d, ("underrun error\n")); +#ifdef NETGRAPH + d->timeout = 0; +#else + ++d->ifp->if_oerrors; + d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + d->ifp->if_timer = 0; +#endif + cp_start (d); + break; + default: + CP_DEBUG (d, ("error #%d\n", data)); + break; + } +} + #ifdef NETGRAPH static int ng_cp_constructor (node_p node) { diff --git a/sys/dev/ctau/if_ct.c b/sys/dev/ctau/if_ct.c index 00751e2..251b3fa 100644 --- a/sys/dev/ctau/if_ct.c +++ b/sys/dev/ctau/if_ct.c @@ -186,6 +186,547 @@ static drv_t *channel [NCTAU*NCHAN]; static struct callout led_timo [NCTAU]; static struct callout timeout_handle; +static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + drv_t *d; + + if (minor(dev) >= NCTAU*NCHAN || ! (d = channel[minor(dev)])) + return ENXIO; + + CT_DEBUG2 (d, ("ct_open\n")); + return 0; +} + +static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td) +{ + drv_t *d = channel [minor(dev)]; + + if (!d) + return 0; + + CT_DEBUG2 (d, ("ct_close\n")); + return 0; +} + +static int ct_modem_status (ct_chan_t *c) +{ + drv_t *d = c->sys; + bdrv_t *bd; + int status, s; + + if (!d) + return 0; + + bd = d->bd; + + status = d->running ? TIOCM_LE : 0; + s = splimp (); + CT_LOCK (bd); + if (ct_get_cd (c)) status |= TIOCM_CD; + if (ct_get_cts (c)) status |= TIOCM_CTS; + if (ct_get_dsr (c)) status |= TIOCM_DSR; + if (c->dtr) status |= TIOCM_DTR; + if (c->rts) status |= TIOCM_RTS; + CT_UNLOCK (bd); + splx (s); + return status; +} + +/* + * Process an ioctl request on /dev/cronyx/ctauN. + */ +static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) +{ + drv_t *d = channel [minor (dev)]; + bdrv_t *bd; + ct_chan_t *c; + struct serial_statistics *st; + struct e1_statistics *opte1; + int error, s; + char mask[16]; + + if (!d || !d->chan) + return 0; + + bd = d->bd; + c = d->chan; + + switch (cmd) { + case SERIAL_GETREGISTERED: + bzero (mask, sizeof(mask)); + for (s=0; s<NCTAU*NCHAN; ++s) + if (channel [s]) + mask [s/8] |= 1 << (s & 7); + bcopy (mask, data, sizeof (mask)); + return 0; + +#ifndef NETGRAPH + case SERIAL_GETPROTO: + strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" : + (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp"); + return 0; + + case SERIAL_SETPROTO: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + 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: + if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || + (d->ifp->if_flags & PP_CISCO)) + return EINVAL; + *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0; + return 0; + + case SERIAL_SETKEEPALIVE: + /* 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; + if (*(int*)data) + IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; + else + IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; + return 0; +#endif /*NETGRAPH*/ + + case SERIAL_GETMODE: + *(int*)data = SERIAL_HDLC; + return 0; + + case SERIAL_GETCFG: + if (c->mode == M_HDLC) + return EINVAL; + switch (ct_get_config (c->board)) { + default: *(char*)data = 'a'; break; + case CFG_B: *(char*)data = 'b'; break; + case CFG_C: *(char*)data = 'c'; break; + } + return 0; + + case SERIAL_SETCFG: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_HDLC) + return EINVAL; + s = splimp (); + CT_LOCK (bd); + switch (*(char*)data) { + case 'a': ct_set_config (c->board, CFG_A); break; + case 'b': ct_set_config (c->board, CFG_B); break; + case 'c': ct_set_config (c->board, CFG_C); break; + } + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETSTAT: + st = (struct serial_statistics*) data; + 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; + return 0; + + case SERIAL_GETESTAT: + opte1 = (struct e1_statistics*)data; + opte1->status = c->status; + opte1->cursec = c->cursec; + opte1->totsec = c->totsec + c->cursec; + + opte1->currnt.bpv = c->currnt.bpv; + opte1->currnt.fse = c->currnt.fse; + opte1->currnt.crce = c->currnt.crce; + opte1->currnt.rcrce = c->currnt.rcrce; + opte1->currnt.uas = c->currnt.uas; + opte1->currnt.les = c->currnt.les; + opte1->currnt.es = c->currnt.es; + opte1->currnt.bes = c->currnt.bes; + opte1->currnt.ses = c->currnt.ses; + opte1->currnt.oofs = c->currnt.oofs; + opte1->currnt.css = c->currnt.css; + opte1->currnt.dm = c->currnt.dm; + + opte1->total.bpv = c->total.bpv + c->currnt.bpv; + opte1->total.fse = c->total.fse + c->currnt.fse; + opte1->total.crce = c->total.crce + c->currnt.crce; + opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce; + opte1->total.uas = c->total.uas + c->currnt.uas; + opte1->total.les = c->total.les + c->currnt.les; + opte1->total.es = c->total.es + c->currnt.es; + opte1->total.bes = c->total.bes + c->currnt.bes; + opte1->total.ses = c->total.ses + c->currnt.ses; + opte1->total.oofs = c->total.oofs + c->currnt.oofs; + opte1->total.css = c->total.css + c->currnt.css; + opte1->total.dm = c->total.dm + c->currnt.dm; + for (s=0; s<48; ++s) { + opte1->interval[s].bpv = c->interval[s].bpv; + opte1->interval[s].fse = c->interval[s].fse; + opte1->interval[s].crce = c->interval[s].crce; + opte1->interval[s].rcrce = c->interval[s].rcrce; + opte1->interval[s].uas = c->interval[s].uas; + opte1->interval[s].les = c->interval[s].les; + opte1->interval[s].es = c->interval[s].es; + opte1->interval[s].bes = c->interval[s].bes; + opte1->interval[s].ses = c->interval[s].ses; + opte1->interval[s].oofs = c->interval[s].oofs; + opte1->interval[s].css = c->interval[s].css; + opte1->interval[s].dm = c->interval[s].dm; + } + return 0; + + case SERIAL_CLRSTAT: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + 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; + bzero (&c->currnt, sizeof (c->currnt)); + bzero (&c->total, sizeof (c->total)); + bzero (c->interval, sizeof (c->interval)); + return 0; + + case SERIAL_GETBAUD: + *(long*)data = ct_get_baud(c); + return 0; + + case SERIAL_SETBAUD: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splimp (); + CT_LOCK (bd); + ct_set_baud (c, *(long*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETLOOP: + *(int*)data = ct_get_loop (c); + return 0; + + case SERIAL_SETLOOP: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splimp (); + CT_LOCK (bd); + ct_set_loop (c, *(int*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETDPLL: + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + *(int*)data = ct_get_dpll (c); + return 0; + + case SERIAL_SETDPLL: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + s = splimp (); + CT_LOCK (bd); + ct_set_dpll (c, *(int*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETNRZI: + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + *(int*)data = ct_get_nrzi (c); + return 0; + + case SERIAL_SETNRZI: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + s = splimp (); + CT_LOCK (bd); + ct_set_nrzi (c, *(int*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETDEBUG: + *(int*)data = c->debug; + return 0; + + case SERIAL_SETDEBUG: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + c->debug = *(int*)data; +#ifndef NETGRAPH + if (d->chan->debug) + d->ifp->if_flags |= IFF_DEBUG; + else + d->ifp->if_flags &= (~IFF_DEBUG); +#endif + return 0; + + case SERIAL_GETHIGAIN: + if (c->mode != M_E1) + return EINVAL; + *(int*)data = ct_get_higain (c); + return 0; + + case SERIAL_SETHIGAIN: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splimp (); + CT_LOCK (bd); + ct_set_higain (c, *(int*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETPHONY: + CT_DEBUG2 (d, ("ioctl: getphony\n")); + if (c->mode != M_E1) + return EINVAL; + *(int*)data = c->gopt.phony; + return 0; + + case SERIAL_SETPHONY: + CT_DEBUG2 (d, ("ioctl: setphony\n")); + if (c->mode != M_E1) + return EINVAL; + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splimp (); + CT_LOCK (bd); + ct_set_phony (c, *(int*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETCLK: + if (c->mode != M_E1 && c->mode != M_G703) + return EINVAL; + switch (ct_get_clk(c)) { + default: *(int*)data = E1CLK_INTERNAL; break; + case GCLK_RCV: *(int*)data = E1CLK_RECEIVE; break; + case GCLK_RCLKO: *(int*)data = c->num ? + E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1; break; + } + return 0; + + case SERIAL_SETCLK: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splimp (); + CT_LOCK (bd); + switch (*(int*)data) { + default: ct_set_clk (c, GCLK_INT); break; + case E1CLK_RECEIVE: ct_set_clk (c, GCLK_RCV); break; + case E1CLK_RECEIVE_CHAN0: + case E1CLK_RECEIVE_CHAN1: + ct_set_clk (c, GCLK_RCLKO); break; + } + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETTIMESLOTS: + if (c->mode != M_E1) + return EINVAL; + *(long*)data = ct_get_ts (c); + return 0; + + case SERIAL_SETTIMESLOTS: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splimp (); + CT_LOCK (bd); + ct_set_ts (c, *(long*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETSUBCHAN: + if (c->mode != M_E1) + return EINVAL; + *(long*)data = ct_get_subchan (c->board); + return 0; + + case SERIAL_SETSUBCHAN: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + s = splimp (); + CT_LOCK (bd); + ct_set_subchan (c->board, *(long*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETINVCLK: + case SERIAL_GETINVTCLK: + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + *(int*)data = ct_get_invtxc (c); + return 0; + + case SERIAL_GETINVRCLK: + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + *(int*)data = ct_get_invrxc (c); + return 0; + + case SERIAL_SETINVCLK: + case SERIAL_SETINVTCLK: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + s = splimp (); + CT_LOCK (bd); + ct_set_invtxc (c, *(int*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_SETINVRCLK: + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + if (c->mode == M_E1 || c->mode == M_G703) + return EINVAL; + s = splimp (); + CT_LOCK (bd); + ct_set_invrxc (c, *(int*)data); + CT_UNLOCK (bd); + splx (s); + return 0; + + case SERIAL_GETLEVEL: + if (c->mode != M_G703) + return EINVAL; + s = splimp (); + CT_LOCK (bd); + *(int*)data = ct_get_lq (c); + CT_UNLOCK (bd); + splx (s); + return 0; + + case TIOCSDTR: /* Set DTR */ + s = splimp (); + CT_LOCK (bd); + ct_set_dtr (c, 1); + CT_UNLOCK (bd); + splx (s); + return 0; + + case TIOCCDTR: /* Clear DTR */ + s = splimp (); + CT_LOCK (bd); + ct_set_dtr (c, 0); + CT_UNLOCK (bd); + splx (s); + return 0; + + case TIOCMSET: /* Set DTR/RTS */ + s = splimp (); + CT_LOCK (bd); + ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); + ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); + CT_UNLOCK (bd); + splx (s); + return 0; + + case TIOCMBIS: /* Add DTR/RTS */ + s = splimp (); + CT_LOCK (bd); + if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1); + if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1); + CT_UNLOCK (bd); + splx (s); + return 0; + + case TIOCMBIC: /* Clear DTR/RTS */ + s = splimp (); + CT_LOCK (bd); + if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0); + if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0); + CT_UNLOCK (bd); + splx (s); + return 0; + + case TIOCMGET: /* Get modem status */ + *(int*)data = ct_modem_status (c); + return 0; + } + return ENOTTY; +} + + +static struct cdevsw ct_cdevsw = { + .d_version = D_VERSION, + .d_open = ct_open, + .d_close = ct_close, + .d_ioctl = ct_ioctl, + .d_name = "ct", + .d_flags = D_NEEDGIANT, +}; + /* * Print the mbuf chain, for debug purposes only. */ @@ -486,8 +1027,6 @@ static int ct_probe (device_t dev) return 0; } -extern struct cdevsw ct_cdevsw; - static void ct_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) { @@ -1209,546 +1748,6 @@ static void ct_error (ct_chan_t *c, int data) } } -static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td) -{ - drv_t *d; - - if (minor(dev) >= NCTAU*NCHAN || ! (d = channel[minor(dev)])) - return ENXIO; - - CT_DEBUG2 (d, ("ct_open\n")); - return 0; -} - -static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td) -{ - drv_t *d = channel [minor(dev)]; - - if (!d) - return 0; - - CT_DEBUG2 (d, ("ct_close\n")); - return 0; -} - -static int ct_modem_status (ct_chan_t *c) -{ - drv_t *d = c->sys; - bdrv_t *bd; - int status, s; - - if (!d) - return 0; - - bd = d->bd; - - status = d->running ? TIOCM_LE : 0; - s = splimp (); - CT_LOCK (bd); - if (ct_get_cd (c)) status |= TIOCM_CD; - if (ct_get_cts (c)) status |= TIOCM_CTS; - if (ct_get_dsr (c)) status |= TIOCM_DSR; - if (c->dtr) status |= TIOCM_DTR; - if (c->rts) status |= TIOCM_RTS; - CT_UNLOCK (bd); - splx (s); - return status; -} - -/* - * Process an ioctl request on /dev/cronyx/ctauN. - */ -static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) -{ - drv_t *d = channel [minor (dev)]; - bdrv_t *bd; - ct_chan_t *c; - struct serial_statistics *st; - struct e1_statistics *opte1; - int error, s; - char mask[16]; - - if (!d || !d->chan) - return 0; - - bd = d->bd; - c = d->chan; - - switch (cmd) { - case SERIAL_GETREGISTERED: - bzero (mask, sizeof(mask)); - for (s=0; s<NCTAU*NCHAN; ++s) - if (channel [s]) - mask [s/8] |= 1 << (s & 7); - bcopy (mask, data, sizeof (mask)); - return 0; - -#ifndef NETGRAPH - case SERIAL_GETPROTO: - strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" : - (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp"); - return 0; - - case SERIAL_SETPROTO: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - 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: - if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || - (d->ifp->if_flags & PP_CISCO)) - return EINVAL; - *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0; - return 0; - - case SERIAL_SETKEEPALIVE: - /* 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; - if (*(int*)data) - IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; - else - IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; - return 0; -#endif /*NETGRAPH*/ - - case SERIAL_GETMODE: - *(int*)data = SERIAL_HDLC; - return 0; - - case SERIAL_GETCFG: - if (c->mode == M_HDLC) - return EINVAL; - switch (ct_get_config (c->board)) { - default: *(char*)data = 'a'; break; - case CFG_B: *(char*)data = 'b'; break; - case CFG_C: *(char*)data = 'c'; break; - } - return 0; - - case SERIAL_SETCFG: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_HDLC) - return EINVAL; - s = splimp (); - CT_LOCK (bd); - switch (*(char*)data) { - case 'a': ct_set_config (c->board, CFG_A); break; - case 'b': ct_set_config (c->board, CFG_B); break; - case 'c': ct_set_config (c->board, CFG_C); break; - } - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETSTAT: - st = (struct serial_statistics*) data; - 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; - return 0; - - case SERIAL_GETESTAT: - opte1 = (struct e1_statistics*)data; - opte1->status = c->status; - opte1->cursec = c->cursec; - opte1->totsec = c->totsec + c->cursec; - - opte1->currnt.bpv = c->currnt.bpv; - opte1->currnt.fse = c->currnt.fse; - opte1->currnt.crce = c->currnt.crce; - opte1->currnt.rcrce = c->currnt.rcrce; - opte1->currnt.uas = c->currnt.uas; - opte1->currnt.les = c->currnt.les; - opte1->currnt.es = c->currnt.es; - opte1->currnt.bes = c->currnt.bes; - opte1->currnt.ses = c->currnt.ses; - opte1->currnt.oofs = c->currnt.oofs; - opte1->currnt.css = c->currnt.css; - opte1->currnt.dm = c->currnt.dm; - - opte1->total.bpv = c->total.bpv + c->currnt.bpv; - opte1->total.fse = c->total.fse + c->currnt.fse; - opte1->total.crce = c->total.crce + c->currnt.crce; - opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce; - opte1->total.uas = c->total.uas + c->currnt.uas; - opte1->total.les = c->total.les + c->currnt.les; - opte1->total.es = c->total.es + c->currnt.es; - opte1->total.bes = c->total.bes + c->currnt.bes; - opte1->total.ses = c->total.ses + c->currnt.ses; - opte1->total.oofs = c->total.oofs + c->currnt.oofs; - opte1->total.css = c->total.css + c->currnt.css; - opte1->total.dm = c->total.dm + c->currnt.dm; - for (s=0; s<48; ++s) { - opte1->interval[s].bpv = c->interval[s].bpv; - opte1->interval[s].fse = c->interval[s].fse; - opte1->interval[s].crce = c->interval[s].crce; - opte1->interval[s].rcrce = c->interval[s].rcrce; - opte1->interval[s].uas = c->interval[s].uas; - opte1->interval[s].les = c->interval[s].les; - opte1->interval[s].es = c->interval[s].es; - opte1->interval[s].bes = c->interval[s].bes; - opte1->interval[s].ses = c->interval[s].ses; - opte1->interval[s].oofs = c->interval[s].oofs; - opte1->interval[s].css = c->interval[s].css; - opte1->interval[s].dm = c->interval[s].dm; - } - return 0; - - case SERIAL_CLRSTAT: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - 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; - bzero (&c->currnt, sizeof (c->currnt)); - bzero (&c->total, sizeof (c->total)); - bzero (c->interval, sizeof (c->interval)); - return 0; - - case SERIAL_GETBAUD: - *(long*)data = ct_get_baud(c); - return 0; - - case SERIAL_SETBAUD: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splimp (); - CT_LOCK (bd); - ct_set_baud (c, *(long*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETLOOP: - *(int*)data = ct_get_loop (c); - return 0; - - case SERIAL_SETLOOP: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splimp (); - CT_LOCK (bd); - ct_set_loop (c, *(int*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETDPLL: - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - *(int*)data = ct_get_dpll (c); - return 0; - - case SERIAL_SETDPLL: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - s = splimp (); - CT_LOCK (bd); - ct_set_dpll (c, *(int*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETNRZI: - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - *(int*)data = ct_get_nrzi (c); - return 0; - - case SERIAL_SETNRZI: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - s = splimp (); - CT_LOCK (bd); - ct_set_nrzi (c, *(int*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETDEBUG: - *(int*)data = c->debug; - return 0; - - case SERIAL_SETDEBUG: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - c->debug = *(int*)data; -#ifndef NETGRAPH - if (d->chan->debug) - d->ifp->if_flags |= IFF_DEBUG; - else - d->ifp->if_flags &= (~IFF_DEBUG); -#endif - return 0; - - case SERIAL_GETHIGAIN: - if (c->mode != M_E1) - return EINVAL; - *(int*)data = ct_get_higain (c); - return 0; - - case SERIAL_SETHIGAIN: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splimp (); - CT_LOCK (bd); - ct_set_higain (c, *(int*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETPHONY: - CT_DEBUG2 (d, ("ioctl: getphony\n")); - if (c->mode != M_E1) - return EINVAL; - *(int*)data = c->gopt.phony; - return 0; - - case SERIAL_SETPHONY: - CT_DEBUG2 (d, ("ioctl: setphony\n")); - if (c->mode != M_E1) - return EINVAL; - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splimp (); - CT_LOCK (bd); - ct_set_phony (c, *(int*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETCLK: - if (c->mode != M_E1 && c->mode != M_G703) - return EINVAL; - switch (ct_get_clk(c)) { - default: *(int*)data = E1CLK_INTERNAL; break; - case GCLK_RCV: *(int*)data = E1CLK_RECEIVE; break; - case GCLK_RCLKO: *(int*)data = c->num ? - E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1; break; - } - return 0; - - case SERIAL_SETCLK: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splimp (); - CT_LOCK (bd); - switch (*(int*)data) { - default: ct_set_clk (c, GCLK_INT); break; - case E1CLK_RECEIVE: ct_set_clk (c, GCLK_RCV); break; - case E1CLK_RECEIVE_CHAN0: - case E1CLK_RECEIVE_CHAN1: - ct_set_clk (c, GCLK_RCLKO); break; - } - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETTIMESLOTS: - if (c->mode != M_E1) - return EINVAL; - *(long*)data = ct_get_ts (c); - return 0; - - case SERIAL_SETTIMESLOTS: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splimp (); - CT_LOCK (bd); - ct_set_ts (c, *(long*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETSUBCHAN: - if (c->mode != M_E1) - return EINVAL; - *(long*)data = ct_get_subchan (c->board); - return 0; - - case SERIAL_SETSUBCHAN: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - s = splimp (); - CT_LOCK (bd); - ct_set_subchan (c->board, *(long*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETINVCLK: - case SERIAL_GETINVTCLK: - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - *(int*)data = ct_get_invtxc (c); - return 0; - - case SERIAL_GETINVRCLK: - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - *(int*)data = ct_get_invrxc (c); - return 0; - - case SERIAL_SETINVCLK: - case SERIAL_SETINVTCLK: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - s = splimp (); - CT_LOCK (bd); - ct_set_invtxc (c, *(int*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_SETINVRCLK: - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - if (c->mode == M_E1 || c->mode == M_G703) - return EINVAL; - s = splimp (); - CT_LOCK (bd); - ct_set_invrxc (c, *(int*)data); - CT_UNLOCK (bd); - splx (s); - return 0; - - case SERIAL_GETLEVEL: - if (c->mode != M_G703) - return EINVAL; - s = splimp (); - CT_LOCK (bd); - *(int*)data = ct_get_lq (c); - CT_UNLOCK (bd); - splx (s); - return 0; - - case TIOCSDTR: /* Set DTR */ - s = splimp (); - CT_LOCK (bd); - ct_set_dtr (c, 1); - CT_UNLOCK (bd); - splx (s); - return 0; - - case TIOCCDTR: /* Clear DTR */ - s = splimp (); - CT_LOCK (bd); - ct_set_dtr (c, 0); - CT_UNLOCK (bd); - splx (s); - return 0; - - case TIOCMSET: /* Set DTR/RTS */ - s = splimp (); - CT_LOCK (bd); - ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); - ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); - CT_UNLOCK (bd); - splx (s); - return 0; - - case TIOCMBIS: /* Add DTR/RTS */ - s = splimp (); - CT_LOCK (bd); - if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1); - if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1); - CT_UNLOCK (bd); - splx (s); - return 0; - - case TIOCMBIC: /* Clear DTR/RTS */ - s = splimp (); - CT_LOCK (bd); - if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0); - if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0); - CT_UNLOCK (bd); - splx (s); - return 0; - - case TIOCMGET: /* Get modem status */ - *(int*)data = ct_modem_status (c); - return 0; - } - return ENOTTY; -} - -static struct cdevsw ct_cdevsw = { - .d_version = D_VERSION, - .d_open = ct_open, - .d_close = ct_close, - .d_ioctl = ct_ioctl, - .d_name = "ct", - .d_flags = D_NEEDGIANT, -}; - #ifdef NETGRAPH static int ng_ct_constructor (node_p node) { 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,10 +229,462 @@ 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; +static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td) +{ + int unit; + drv_t *d; + + d = dev->si_drv1; + unit = d->chan->num; + + CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n", + unit, flag, mode)); + + d->open_dev |= 0x1; + + CX_DEBUG2 (d, ("cx_open done\n")); + + return 0; +} + +static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td) +{ + drv_t *d; + + d = dev->si_drv1; + CX_DEBUG2 (d, ("cx_close\n")); + d->open_dev &= ~0x1; + return 0; +} + +static int cx_modem_status (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); + splx (s); + return status; +} + +static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) +{ + 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; s<NCX*NCHAN; ++s) + if (channel [s]) + mask [s/8] |= 1 << (s & 7); + bcopy (mask, data, sizeof (mask)); + return 0; + + case SERIAL_GETPORT: + CX_DEBUG2 (d, ("ioctl: getport\n")); + s = splhigh (); + CX_LOCK (bd); + *(int *)data = cx_get_port (c); + CX_UNLOCK (bd); + splx (s); + if (*(int *)data<0) + return (EINVAL); + else + return 0; + + case SERIAL_SETPORT: + CX_DEBUG2 (d, ("ioctl: setproto\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + + s = splhigh (); + CX_LOCK (bd); + cx_set_port (c, *(int *)data); + CX_UNLOCK (bd); + splx (s); + return 0; + +#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; + + 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*/ + + 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; + + case SERIAL_SETMODE: + CX_DEBUG2 (d, ("ioctl: setmode\n")); + /* Only for superuser! */ + error = suser (td); + if (error) + return error; + + /* 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; + + 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; + + 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; + + 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; + + 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; + + 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; + } + + 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; + + 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; + + 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; + + case TIOCMGET: /* Get modem status */ + CX_DEBUG2 (d, ("ioctl: tiocmget\n")); + *(int*)data = cx_modem_status (d); + return 0; + + } + + CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd)); + return ENOTTY; +} + +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, +}; + /* * Print the mbuf chain, for debug purposes only. */ @@ -1536,450 +1988,6 @@ static int cx_tmodem (struct tty *tp, int sigon, int sigoff) return (0); } -static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td) -{ - int unit; - drv_t *d; - - d = dev->si_drv1; - unit = d->chan->num; - - CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n", - unit, flag, mode)); - - d->open_dev |= 0x1; - - CX_DEBUG2 (d, ("cx_open done\n")); - - return 0; -} - -static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td) -{ - drv_t *d; - - d = dev->si_drv1; - CX_DEBUG2 (d, ("cx_close\n")); - d->open_dev &= ~0x1; - return 0; -} - -static int cx_modem_status (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); - splx (s); - return status; -} - -static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) -{ - 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; s<NCX*NCHAN; ++s) - if (channel [s]) - mask [s/8] |= 1 << (s & 7); - bcopy (mask, data, sizeof (mask)); - return 0; - - case SERIAL_GETPORT: - CX_DEBUG2 (d, ("ioctl: getport\n")); - s = splhigh (); - CX_LOCK (bd); - *(int *)data = cx_get_port (c); - CX_UNLOCK (bd); - splx (s); - if (*(int *)data<0) - return (EINVAL); - else - return 0; - - case SERIAL_SETPORT: - CX_DEBUG2 (d, ("ioctl: setproto\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - - s = splhigh (); - CX_LOCK (bd); - cx_set_port (c, *(int *)data); - CX_UNLOCK (bd); - splx (s); - return 0; - -#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; - - 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*/ - - 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; - - case SERIAL_SETMODE: - CX_DEBUG2 (d, ("ioctl: setmode\n")); - /* Only for superuser! */ - error = suser (td); - if (error) - return error; - - /* 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; - - 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; - - 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; - - 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; - - 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; - - 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; - } - - 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; - - 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; - - 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; - - case TIOCMGET: /* Get modem status */ - CX_DEBUG2 (d, ("ioctl: tiocmget\n")); - *(int*)data = cx_modem_status (d); - return 0; - - } - - CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd)); - return ENOTTY; -} - void cx_softintr (void *unused) { drv_t *d; @@ -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) { |