if_ct.c revision 256219
12088Ssos/*- 25536Ssos * Cronyx-Tau adapter driver for FreeBSD. 32088Ssos * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode, 42088Ssos * and asynchronous channels with full modem control. 52088Ssos * Keepalive protocol implemented in both Cisco and PPP modes. 62088Ssos * 72088Ssos * Copyright (C) 1994-2002 Cronyx Engineering. 82088Ssos * Author: Serge Vakulenko, <vak@cronyx.ru> 95994Ssos * 105994Ssos * Copyright (C) 1999-2004 Cronyx Engineering. 112088Ssos * Author: Roman Kurakin, <rik@cronyx.ru> 122088Ssos * 132088Ssos * This software is distributed with NO WARRANTIES, not even the implied 142088Ssos * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 152088Ssos * 162088Ssos * Authors grant any other persons or organisations a permission to use, 172088Ssos * modify and redistribute this software in source and binary forms, 182088Ssos * as long as this message is kept with the software, all derivative 192088Ssos * works or modified versions. 202088Ssos * 212088Ssos * Cronyx Id: if_ct.c,v 1.1.2.31 2004/06/23 17:09:13 rik Exp $ 222088Ssos */ 232088Ssos 242088Ssos#include <sys/cdefs.h> 252088Ssos__FBSDID("$FreeBSD: stable/9/sys/dev/ctau/if_ct.c 256219 2013-10-09 19:04:48Z mav $"); 262088Ssos 272088Ssos#include <sys/param.h> 282088Ssos#include <sys/proc.h> 2929603Scharnier#include <sys/systm.h> 3029603Scharnier#include <sys/kernel.h> 3150479Speter#include <sys/module.h> 3229603Scharnier#include <sys/mbuf.h> 3329603Scharnier#include <sys/sockio.h> 342088Ssos#include <sys/malloc.h> 3529603Scharnier#include <sys/priv.h> 362088Ssos#include <sys/socket.h> 3729603Scharnier#include <sys/sysctl.h> 383864Sswallace#include <sys/conf.h> 3929603Scharnier#include <sys/errno.h> 4042505Syokota#include <sys/tty.h> 4166834Sphk#include <sys/bus.h> 4266834Sphk#include <machine/bus.h> 432088Ssos#include <sys/rman.h> 442088Ssos#include <isa/isavar.h> 452088Ssos#include <sys/interrupt.h> 4676643Simp#include <vm/vm.h> 4776643Simp#include <vm/pmap.h> 4876643Simp#include <net/if.h> 4976643Simp#include <machine/cpufunc.h> 5076643Simp#include <machine/cserial.h> 5176643Simp#include <machine/resource.h> 5276643Simp#include <dev/cx/machdep.h> 5376643Simp#include <dev/ctau/ctddk.h> 542088Ssos#include <dev/cx/cronyxfw.h> 558857Srgrimes#include "opt_ng_cronyx.h" 562088Ssos#ifdef NETGRAPH_CRONYX 572088Ssos# include "opt_netgraph.h" 5838139Syokota# include <netgraph/ng_message.h> 592088Ssos# include <netgraph/netgraph.h> 602088Ssos# include <dev/ctau/ng_ct.h> 6132316Syokota#else 6232316Syokota# include <net/if_types.h> 6332316Syokota# include <net/if_sppp.h> 6432316Syokota# define PP_CISCO IFF_LINK2 6532316Syokota# include <net/bpf.h> 6632316Syokota#endif 6732316Syokota 6832316Syokota#define NCTAU 1 6932316Syokota 7032316Syokota/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */ 7132316Syokota#ifndef PP_FR 7232316Syokota#define PP_FR 0 735994Ssos#endif 745994Ssos 755994Ssos#define CT_DEBUG(d,s) ({if (d->chan->debug) {\ 765994Ssos printf ("%s: ", d->name); printf s;}}) 775994Ssos#define CT_DEBUG2(d,s) ({if (d->chan->debug>1) {\ 785994Ssos printf ("%s: ", d->name); printf s;}}) 795994Ssos 805994Ssos#define CT_LOCK_NAME "ctX" 815994Ssos 825994Ssos#define CT_LOCK(_bd) mtx_lock (&(_bd)->ct_mtx) 835994Ssos#define CT_UNLOCK(_bd) mtx_unlock (&(_bd)->ct_mtx) 845994Ssos#define CT_LOCK_ASSERT(_bd) mtx_assert (&(_bd)->ct_mtx, MA_OWNED) 859202Srgrimes 865994Ssosstatic void ct_identify __P((driver_t *, device_t)); 875994Ssosstatic int ct_probe __P((device_t)); 885994Ssosstatic int ct_attach __P((device_t)); 899202Srgrimesstatic int ct_detach __P((device_t)); 905994Ssos 915994Ssosstatic device_method_t ct_isa_methods [] = { 925994Ssos DEVMETHOD(device_identify, ct_identify), 935994Ssos DEVMETHOD(device_probe, ct_probe), 945994Ssos DEVMETHOD(device_attach, ct_attach), 955994Ssos DEVMETHOD(device_detach, ct_detach), 965994Ssos {0, 0} 975994Ssos}; 982088Ssos 992088Ssostypedef struct _ct_dma_mem_t { 10046761Syokota unsigned long phys; 10146761Syokota void *virt; 10246761Syokota size_t size; 10346761Syokota bus_dma_tag_t dmat; 10446761Syokota bus_dmamap_t mapp; 10546761Syokota} ct_dma_mem_t; 10646761Syokota 1072088Ssostypedef struct _drv_t { 1086046Ssos char name [8]; 1092088Ssos ct_chan_t *chan; 11032316Syokota ct_board_t *board; 1112088Ssos struct _bdrv_t *bd; 11229603Scharnier ct_dma_mem_t dmamem; 1132088Ssos int running; 1142088Ssos#ifdef NETGRAPH 1152088Ssos char nodename [NG_NODESIZ]; 1162088Ssos hook_p hook; 1172088Ssos hook_p debug_hook; 1182088Ssos node_p node; 11929603Scharnier struct ifqueue queue; 1202088Ssos struct ifqueue hi_queue; 1212088Ssos#else 1222088Ssos struct ifqueue queue; 1232088Ssos struct ifnet *ifp; 1242088Ssos#endif 1252088Ssos short timeout; 1262088Ssos struct callout timeout_handle; 1272088Ssos struct cdev *devt; 1285536Ssos} drv_t; 1295536Ssos 1305536Ssostypedef struct _bdrv_t { 1312088Ssos ct_board_t *board; 1322088Ssos struct resource *base_res; 1332088Ssos struct resource *drq_res; 1342088Ssos struct resource *irq_res; 1352088Ssos int base_rid; 1362088Ssos int drq_rid; 1372088Ssos int irq_rid; 1382088Ssos void *intrhand; 1392088Ssos drv_t channel [NCHAN]; 1402088Ssos struct mtx ct_mtx; 1412088Ssos} bdrv_t; 1422088Ssos 1432088Ssosstatic driver_t ct_isa_driver = { 1442088Ssos "ct", 1452088Ssos ct_isa_methods, 1462088Ssos sizeof (bdrv_t), 1472088Ssos}; 1482088Ssos 1492088Ssosstatic devclass_t ct_devclass; 1502088Ssos 1512088Ssosstatic void ct_receive (ct_chan_t *c, char *data, int len); 1522088Ssosstatic void ct_transmit (ct_chan_t *c, void *attachment, int len); 1532088Ssosstatic void ct_error (ct_chan_t *c, int data); 15432316Syokotastatic void ct_up (drv_t *d); 1552088Ssosstatic void ct_start (drv_t *d); 1562088Ssosstatic void ct_down (drv_t *d); 1572088Ssosstatic void ct_watchdog (drv_t *d); 1582088Ssosstatic void ct_watchdog_timer (void *arg); 1592088Ssos#ifdef NETGRAPH 1602088Ssosextern struct ng_type typestruct; 1612088Ssos#else 1622088Ssosstatic void ct_ifstart (struct ifnet *ifp); 1632088Ssosstatic void ct_tlf (struct sppp *sp); 1642088Ssosstatic void ct_tls (struct sppp *sp); 1652088Ssosstatic int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 1662088Ssosstatic void ct_initialize (void *softc); 1672088Ssos#endif 1682088Ssos 1692088Ssosstatic ct_board_t *adapter [NCTAU]; 1702088Ssosstatic drv_t *channel [NCTAU*NCHAN]; 1712088Ssosstatic struct callout led_timo [NCTAU]; 1722088Ssosstatic struct callout timeout_handle; 1732088Ssos 1742088Ssosstatic int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td); 17548105Syokotastatic int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td); 17648105Syokotastatic int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td); 1772088Ssosstatic struct cdevsw ct_cdevsw = { 1782088Ssos .d_version = D_VERSION, 1792088Ssos .d_open = ct_open, 1802088Ssos .d_close = ct_close, 1812088Ssos .d_ioctl = ct_ioctl, 1822088Ssos .d_name = "ct", 1832088Ssos}; 1842088Ssos 1852088Ssos/* 1862088Ssos * Print the mbuf chain, for debug purposes only. 1872088Ssos */ 1882088Ssosstatic void printmbuf (struct mbuf *m) 1892088Ssos{ 1902088Ssos printf ("mbuf:"); 1915994Ssos for (; m; m=m->m_next) { 1925994Ssos if (m->m_flags & M_PKTHDR) 19338053Syokota printf (" HDR %d:", m->m_pkthdr.len); 19438053Syokota if (m->m_flags & M_EXT) 19554380Syokota printf (" EXT:"); 19654380Syokota printf (" %d", m->m_len); 19754380Syokota } 19854380Syokota printf ("\n"); 19954380Syokota} 20054380Syokota 20154380Syokota/* 20254380Syokota * Make an mbuf from data. 20354380Syokota */ 20454380Syokotastatic struct mbuf *makembuf (void *buf, u_int len) 20554380Syokota{ 20654380Syokota struct mbuf *m; 20754380Syokota 20854380Syokota MGETHDR (m, M_NOWAIT, MT_DATA); 20965759Sdwmalone if (! m) 21065759Sdwmalone return 0; 21165759Sdwmalone MCLGET (m, M_NOWAIT); 21265759Sdwmalone if (! (m->m_flags & M_EXT)) { 21374118Sache m_freem (m); 21474118Sache return 0; 21532316Syokota } 21632316Syokota m->m_pkthdr.len = m->m_len = len; 21732316Syokota bcopy (buf, mtod (m, caddr_t), len); 21832316Syokota return m; 2192088Ssos} 2202088Ssos 2212088Ssosstatic void ct_timeout (void *arg) 2222088Ssos{ 2232088Ssos drv_t *d; 2242088Ssos int s, i, k; 2252088Ssos 2262088Ssos for (i = 0; i < NCTAU; ++i) { 2272088Ssos if (adapter[i] == NULL) 2282088Ssos continue; 2292088Ssos for (k = 0; k < NCHAN; k++) { 2302088Ssos d = channel[i * NCHAN + k]; 2312088Ssos if (! d) 2322088Ssos continue; 2332088Ssos if (d->chan->mode != M_G703) 2342088Ssos continue; 2352088Ssos s = splimp (); 2362088Ssos CT_LOCK ((bdrv_t *)d->bd); 2372088Ssos ct_g703_timer (d->chan); 2382088Ssos CT_UNLOCK ((bdrv_t *)d->bd); 23932316Syokota splx (s); 2402088Ssos } 24132316Syokota } 2422088Ssos 2432088Ssos callout_reset (&timeout_handle, hz, ct_timeout, 0); 2442088Ssos} 24532316Syokota 24632316Syokotastatic void ct_led_off (void *arg) 24732316Syokota{ 24832316Syokota ct_board_t *b = arg; 24932316Syokota bdrv_t *bd = ((drv_t *)b->chan->sys)->bd; 25032316Syokota int s = splimp (); 25132316Syokota 25232316Syokota CT_LOCK (bd); 25332316Syokota ct_led (b, 0); 25432316Syokota CT_UNLOCK (bd); 25532316Syokota splx (s); 25632316Syokota} 25732316Syokota 25832316Syokota/* 25932316Syokota * Activate interrupt handler from DDK. 26032316Syokota */ 26132316Syokotastatic void ct_intr (void *arg) 26232316Syokota{ 26332316Syokota bdrv_t *bd = arg; 2642088Ssos ct_board_t *b = bd->board; 26532316Syokota#ifndef NETGRAPH 26632316Syokota int i; 26732316Syokota#endif 26832316Syokota int s = splimp (); 26932316Syokota 27032316Syokota CT_LOCK (bd); 27132316Syokota /* Turn LED on. */ 27232316Syokota ct_led (b, 1); 27332316Syokota 27432316Syokota ct_int_handler (b); 27532316Syokota 27632316Syokota /* Turn LED off 50 msec later. */ 2772088Ssos callout_reset (&led_timo[b->num], hz/20, ct_led_off, b); 2782088Ssos CT_UNLOCK (bd); 2792088Ssos splx (s); 2802088Ssos 2812088Ssos#ifndef NETGRAPH 2822088Ssos /* Pass packets in a lock-free state */ 2832088Ssos for (i = 0; i < NCHAN && b->chan[i].type; i++) { 2842088Ssos drv_t *d = b->chan[i].sys; 2852088Ssos struct mbuf *m; 2862088Ssos if (!d || !d->running) 2872088Ssos continue; 2882088Ssos while (_IF_QLEN(&d->queue)) { 2892088Ssos IF_DEQUEUE (&d->queue,m); 2902088Ssos if (!m) 29132316Syokota continue; 2922088Ssos sppp_input (d->ifp, m); 2932088Ssos } 29432316Syokota } 29532316Syokota#endif 2962088Ssos} 2972088Ssos 29832316Syokotastatic int probe_irq (ct_board_t *b, int irq) 29932316Syokota{ 30032316Syokota int mask, busy, cnt; 30132316Syokota 30232316Syokota /* Clear pending irq, if any. */ 30332316Syokota ct_probe_irq (b, -irq); 3042088Ssos DELAY (100); 30532316Syokota for (cnt=0; cnt<5; ++cnt) { 30632316Syokota /* Get the mask of pending irqs, assuming they are busy. 30732316Syokota * Activate the adapter on given irq. */ 30832316Syokota busy = ct_probe_irq (b, irq); 30932316Syokota DELAY (1000); 31032316Syokota 31132316Syokota /* Get the mask of active irqs. 31232316Syokota * Deactivate our irq. */ 31332316Syokota mask = ct_probe_irq (b, -irq); 31432316Syokota DELAY (100); 31532316Syokota if ((mask & ~busy) == 1 << irq) { 31632316Syokota ct_probe_irq (b, 0); 31732316Syokota /* printf ("ct%d: irq %d ok, mask=0x%04x, busy=0x%04x\n", 31832316Syokota b->num, irq, mask, busy); */ 31932316Syokota return 1; 32032316Syokota } 32132316Syokota } 32232316Syokota /* printf ("ct%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n", 32332316Syokota b->num, irq, mask, busy); */ 32432316Syokota ct_probe_irq (b, 0); 32532316Syokota return 0; 32632316Syokota} 32732316Syokota 32832316Syokotastatic short porttab [] = { 32932316Syokota 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 33032316Syokota 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 33132316Syokota }; 33232316Syokotastatic char dmatab [] = { 7, 6, 5, 0 }; 33332316Syokotastatic char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 }; 33432316Syokota 33532316Syokotastatic int ct_is_free_res (device_t dev, int rid, int type, u_long start, 33632316Syokota u_long end, u_long count) 33732316Syokota{ 33832316Syokota struct resource *res; 33932316Syokota 34032316Syokota if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count, 34132316Syokota RF_ALLOCATED))) 34232316Syokota return 0; 34332316Syokota 34432316Syokota bus_release_resource (dev, type, rid, res); 34532316Syokota 34632316Syokota return 1; 34732316Syokota} 34832316Syokota 34932316Syokotastatic void ct_identify (driver_t *driver, device_t dev) 35032316Syokota{ 35132316Syokota u_long iobase, rescount; 35232316Syokota int devcount; 35332316Syokota device_t *devices; 35432316Syokota device_t child; 35532316Syokota devclass_t my_devclass; 35632316Syokota int i, k; 35732316Syokota 35832316Syokota if ((my_devclass = devclass_find ("ct")) == NULL) 35929603Scharnier return; 3602088Ssos 3612088Ssos devclass_get_devices (my_devclass, &devices, &devcount); 3622088Ssos 3632088Ssos if (devcount == 0) { 3642088Ssos /* We should find all devices by our self. We could alter other 3652088Ssos * devices, but we don't have a choise 3668857Srgrimes */ 3672088Ssos for (i = 0; (iobase = porttab [i]) != 0; i++) { 3682088Ssos if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT, 3692088Ssos iobase, iobase + NPORT, NPORT)) 3702088Ssos continue; 3712088Ssos if (ct_probe_board (iobase, -1, -1) == 0) 3722088Ssos continue; 3732088Ssos 3742088Ssos devcount++; 3752088Ssos child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "ct", 3762088Ssos -1); 3772088Ssos 3782088Ssos if (child == NULL) 3792088Ssos return; 3802088Ssos 3812088Ssos device_set_desc_copy (child, "Cronyx Tau-ISA"); 3822088Ssos device_set_driver (child, driver); 3832088Ssos bus_set_resource (child, SYS_RES_IOPORT, 0, 3842088Ssos iobase, NPORT); 3852088Ssos 3862088Ssos if (devcount >= NCTAU) 3872088Ssos break; 3882088Ssos } 3892088Ssos } else { 3902088Ssos static short porttab [] = { 3912088Ssos 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 3922088Ssos 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 3932088Ssos }; 3942088Ssos /* Lets check user choise. 39548105Syokota */ 39648105Syokota for (k = 0; k < devcount; k++) { 39748105Syokota if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, 3982088Ssos &iobase, &rescount) != 0) 3992088Ssos continue; 4002088Ssos 4012088Ssos for (i = 0; porttab [i] != 0; i++) { 4022088Ssos if (porttab [i] != iobase) 4032088Ssos continue; 4042088Ssos 4052088Ssos if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT, 4062088Ssos iobase, iobase + NPORT, NPORT)) 4072088Ssos continue; 4082088Ssos 4092088Ssos if (ct_probe_board (iobase, -1, -1) == 0) 4102088Ssos continue; 4112088Ssos porttab [i] = -1; 4122088Ssos device_set_desc_copy (devices[k], "Cronyx Tau-ISA"); 4132088Ssos break; 4142088Ssos } 4152088Ssos if (porttab [i] == 0) { 4162088Ssos device_delete_child ( 4172088Ssos device_get_parent (devices[k]), 4182088Ssos devices [k]); 41932316Syokota devices[k] = 0; 42032316Syokota continue; 42132316Syokota } 42238053Syokota } 42338053Syokota for (k = 0; k < devcount; k++) { 42438053Syokota if (devices[k] == 0) 42554380Syokota continue; 42654380Syokota if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, 42754380Syokota &iobase, &rescount) == 0) 42854380Syokota continue; 42954380Syokota for (i = 0; (iobase = porttab [i]) != 0; i++) { 43054380Syokota if (porttab [i] == -1) 43154380Syokota continue; 43254380Syokota if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT, 43354380Syokota iobase, iobase + NPORT, NPORT)) 43454380Syokota continue; 43554380Syokota if (ct_probe_board (iobase, -1, -1) == 0) 43654380Syokota continue; 43754380Syokota 43854380Syokota bus_set_resource (devices[k], SYS_RES_IOPORT, 0, 43954380Syokota iobase, NPORT); 44054380Syokota porttab [i] = -1; 44154380Syokota device_set_desc_copy (devices[k], "Cronyx Tau-ISA"); 44254380Syokota break; 44354380Syokota } 44454380Syokota if (porttab [i] == 0) { 44554380Syokota device_delete_child ( 44665759Sdwmalone device_get_parent (devices[k]), 44765759Sdwmalone devices [k]); 44865759Sdwmalone } 44965759Sdwmalone } 45065759Sdwmalone free (devices, M_TEMP); 45165759Sdwmalone } 45274118Sache 45374118Sache return; 45474118Sache} 4552088Ssos 4562088Ssosstatic int ct_probe (device_t dev) 4578857Srgrimes{ 4582088Ssos int unit = device_get_unit (dev); 4598857Srgrimes u_long iobase, rescount; 4602088Ssos 46132316Syokota if (!device_get_desc (dev) || 46232316Syokota strcmp (device_get_desc (dev), "Cronyx Tau-ISA")) 4632088Ssos return ENXIO; 4648857Srgrimes 4652088Ssos/* KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));*/ 46632316Syokota if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) { 4672088Ssos printf ("ct%d: Couldn't get IOPORT\n", unit); 4682088Ssos return ENXIO; 4692088Ssos } 4708857Srgrimes 4712088Ssos if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT, 4728857Srgrimes iobase, iobase + NPORT, NPORT)) { 4739202Srgrimes printf ("ct%d: Resource IOPORT isn't free\n", unit); 4748857Srgrimes return ENXIO; 4752088Ssos } 4768857Srgrimes 4772088Ssos if (!ct_probe_board (iobase, -1, -1)) { 4788857Srgrimes printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase); 4792088Ssos return ENXIO; 4802088Ssos } 4812088Ssos 4822088Ssos return 0; 4832088Ssos} 4842088Ssos 48542505Syokotastatic void 4862088Ssosct_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) 48729603Scharnier{ 4882088Ssos unsigned long *addr; 4892088Ssos 4902088Ssos if (error) 4912088Ssos return; 4922088Ssos 4932088Ssos KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 4942088Ssos addr = arg; 4952088Ssos *addr = segs->ds_addr; 4962088Ssos} 4972088Ssos 4982088Ssosstatic int 4992088Ssosct_bus_dma_mem_alloc (int bnum, int cnum, ct_dma_mem_t *dmem) 5008857Srgrimes{ 5012088Ssos int error; 5022088Ssos 5032088Ssos error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT, 5042088Ssos BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1, 5052088Ssos dmem->size, 0, NULL, NULL, &dmem->dmat); 5062088Ssos if (error) { 5072088Ssos if (cnum >= 0) printf ("ct%d-%d: ", bnum, cnum); 5082088Ssos else printf ("ct%d: ", bnum); 5092088Ssos printf ("couldn't allocate tag for dma memory\n"); 5102088Ssos return 0; 5112088Ssos } 5122088Ssos error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt, 5132088Ssos BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp); 5146046Ssos if (error) { 5156046Ssos if (cnum >= 0) printf ("ct%d-%d: ", bnum, cnum); 5166046Ssos else printf ("ct%d: ", bnum); 5178857Srgrimes printf ("couldn't allocate mem for dma memory\n"); 5182088Ssos bus_dma_tag_destroy (dmem->dmat); 5192088Ssos return 0; 52032316Syokota } 52132316Syokota error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt, 52232316Syokota dmem->size, ct_bus_dmamap_addr, &dmem->phys, 0); 52332316Syokota if (error) { 52432316Syokota if (cnum >= 0) printf ("ct%d-%d: ", bnum, cnum); 5252088Ssos else printf ("ct%d: ", bnum); 52632316Syokota printf ("couldn't load mem map for dma memory\n"); 52732316Syokota bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); 52832316Syokota bus_dma_tag_destroy (dmem->dmat); 52932316Syokota return 0; 53032316Syokota } 53132316Syokota return 1; 53232316Syokota} 53332316Syokota 53432316Syokotastatic void 53532316Syokotact_bus_dma_mem_free (ct_dma_mem_t *dmem) 53632316Syokota{ 53732316Syokota bus_dmamap_unload (dmem->dmat, dmem->mapp); 53832316Syokota bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); 53932316Syokota bus_dma_tag_destroy (dmem->dmat); 54032316Syokota} 54132316Syokota 54232316Syokota/* 54332316Syokota * The adapter is present, initialize the driver structures. 54432316Syokota */ 54532316Syokotastatic int ct_attach (device_t dev) 54632316Syokota{ 54732316Syokota bdrv_t *bd = device_get_softc (dev); 54832316Syokota u_long iobase, drq, irq, rescount; 54932316Syokota int unit = device_get_unit (dev); 55032316Syokota char *ct_ln = CT_LOCK_NAME; 55132316Syokota ct_board_t *b; 55232316Syokota ct_chan_t *c; 55332316Syokota drv_t *d; 55432316Syokota int i; 55532316Syokota int s; 55632316Syokota 55732316Syokota KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit)); 55832316Syokota 55932316Syokota bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount); 56032316Syokota bd->base_rid = 0; 5612088Ssos bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid, 56232316Syokota iobase, iobase + NPORT, NPORT, RF_ACTIVE); 56332316Syokota if (! bd->base_res) { 56432316Syokota printf ("ct%d: cannot alloc base address\n", unit); 56532316Syokota return ENXIO; 56632316Syokota } 56732316Syokota 56832316Syokota if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) { 56932316Syokota for (i = 0; (drq = dmatab [i]) != 0; i++) { 57032316Syokota if (!ct_is_free_res (dev, 0, SYS_RES_DRQ, 57132316Syokota drq, drq + 1, 1)) 57232316Syokota continue; 57332316Syokota bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1); 57432316Syokota break; 57532316Syokota } 57632316Syokota 57732316Syokota if (dmatab[i] == 0) { 57832316Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 57932316Syokota bd->base_res); 58032316Syokota printf ("ct%d: Couldn't get DRQ\n", unit); 58132316Syokota return ENXIO; 58232316Syokota } 58332316Syokota } 58432316Syokota 58532316Syokota bd->drq_rid = 0; 58632316Syokota bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid, 58732316Syokota drq, drq + 1, 1, RF_ACTIVE); 58832316Syokota if (! bd->drq_res) { 58932316Syokota printf ("ct%d: cannot allocate drq\n", unit); 59032316Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 59132316Syokota bd->base_res); 59232316Syokota return ENXIO; 59332316Syokota } 59432316Syokota 59532316Syokota if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) { 59632316Syokota for (i = 0; (irq = irqtab [i]) != 0; i++) { 59748105Syokota if (!ct_is_free_res (dev, 0, SYS_RES_IRQ, 59848105Syokota irq, irq + 1, 1)) 59948105Syokota continue; 60032316Syokota bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1); 60132316Syokota break; 60232316Syokota } 60332316Syokota 60432316Syokota if (irqtab[i] == 0) { 60532316Syokota bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 60632316Syokota bd->drq_res); 60732316Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 60832316Syokota bd->base_res); 60932316Syokota printf ("ct%d: Couldn't get IRQ\n", unit); 61032316Syokota return ENXIO; 61132316Syokota } 61232316Syokota } 61332316Syokota 61432316Syokota bd->irq_rid = 0; 61532316Syokota bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid, 61632316Syokota irq, irq + 1, 1, RF_ACTIVE); 61732316Syokota if (! bd->irq_res) { 61832316Syokota printf ("ct%d: Couldn't allocate irq\n", unit); 61932316Syokota bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 62032316Syokota bd->drq_res); 62132316Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 62232316Syokota bd->base_res); 62332316Syokota return ENXIO; 62438053Syokota } 62538053Syokota 62638053Syokota b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK); 62754380Syokota if (!b) { 62854380Syokota printf ("ct:%d: Couldn't allocate memory\n", unit); 62954380Syokota return (ENXIO); 63054380Syokota } 63154380Syokota adapter[unit] = b; 63254380Syokota bzero (b, sizeof(ct_board_t)); 63354380Syokota 63454380Syokota if (! ct_open_board (b, unit, iobase, irq, drq)) { 63554380Syokota printf ("ct%d: error loading firmware\n", unit); 63654380Syokota free (b, M_DEVBUF); 63754380Syokota bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 63854380Syokota bd->irq_res); 63954380Syokota bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 64054380Syokota bd->drq_res); 64154380Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 64254380Syokota bd->base_res); 64354380Syokota return ENXIO; 64454380Syokota } 64554380Syokota 64654380Syokota bd->board = b; 64754380Syokota 64865759Sdwmalone ct_ln[2] = '0' + unit; 64965759Sdwmalone mtx_init (&bd->ct_mtx, ct_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE); 65065759Sdwmalone if (! probe_irq (b, irq)) { 65165759Sdwmalone printf ("ct%d: irq %ld not functional\n", unit, irq); 65265759Sdwmalone bd->board = 0; 65365759Sdwmalone adapter [unit] = 0; 65474118Sache free (b, M_DEVBUF); 65574118Sache bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 65674118Sache bd->irq_res); 65732316Syokota bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 65832316Syokota bd->drq_res); 65932316Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 66032316Syokota bd->base_res); 66132486Syokota mtx_destroy (&bd->ct_mtx); 66232316Syokota return ENXIO; 66332316Syokota } 66432316Syokota 66532316Syokota callout_init (&led_timo[unit], CALLOUT_MPSAFE); 66632316Syokota s = splimp (); 66732316Syokota if (bus_setup_intr (dev, bd->irq_res, 66832316Syokota INTR_TYPE_NET|INTR_MPSAFE, 66932316Syokota NULL, ct_intr, bd, &bd->intrhand)) { 67032316Syokota printf ("ct%d: Can't setup irq %ld\n", unit, irq); 67132316Syokota bd->board = 0; 67232316Syokota adapter [unit] = 0; 67332316Syokota free (b, M_DEVBUF); 67432316Syokota bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 67532316Syokota bd->irq_res); 67632316Syokota bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 67732316Syokota bd->drq_res); 67832316Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 67932316Syokota bd->base_res); 68032316Syokota mtx_destroy (&bd->ct_mtx); 68132316Syokota splx (s); 68232316Syokota return ENXIO; 68332316Syokota } 68432486Syokota 68532316Syokota CT_LOCK (bd); 68632316Syokota ct_init_board (b, b->num, b->port, irq, drq, b->type, b->osc); 68732486Syokota ct_setup_board (b, 0, 0, 0); 68832486Syokota CT_UNLOCK (bd); 68932486Syokota 69032316Syokota printf ("ct%d: <Cronyx-%s>, clock %s MHz\n", b->num, b->name, 69132316Syokota b->osc == 20000000 ? "20" : "16.384"); 69232316Syokota 69332486Syokota for (c = b->chan; c < b->chan + NCHAN; ++c) { 69432316Syokota d = &bd->channel[c->num]; 69532316Syokota d->dmamem.size = sizeof(ct_buf_t); 69632316Syokota if (! ct_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) 69732316Syokota continue; 69832316Syokota d->board = b; 69932316Syokota d->chan = c; 70032486Syokota d->bd = bd; 70132316Syokota c->sys = d; 70232316Syokota channel [b->num*NCHAN + c->num] = d; 70332316Syokota sprintf (d->name, "ct%d.%d", b->num, c->num); 70432486Syokota callout_init (&d->timeout_handle, CALLOUT_MPSAFE); 70532316Syokota 70632316Syokota#ifdef NETGRAPH 70732316Syokota if (ng_make_node_common (&typestruct, &d->node) != 0) { 70832316Syokota printf ("%s: cannot make common node\n", d->name); 70932316Syokota channel [b->num*NCHAN + c->num] = 0; 71032316Syokota c->sys = 0; 71132316Syokota ct_bus_dma_mem_free (&d->dmamem); 71232316Syokota continue; 71332486Syokota } 71432316Syokota NG_NODE_SET_PRIVATE (d->node, d); 71532486Syokota sprintf (d->nodename, "%s%d", NG_CT_NODE_TYPE, 71632486Syokota c->board->num*NCHAN + c->num); 71732486Syokota if (ng_name_node (d->node, d->nodename)) { 71832486Syokota printf ("%s: cannot name node\n", d->nodename); 71932486Syokota NG_NODE_UNREF (d->node); 72032316Syokota channel [b->num*NCHAN + c->num] = 0; 72132316Syokota c->sys = 0; 72232316Syokota ct_bus_dma_mem_free (&d->dmamem); 72332316Syokota continue; 72432316Syokota } 72532316Syokota d->queue.ifq_maxlen = ifqmaxlen; 72632316Syokota d->hi_queue.ifq_maxlen = ifqmaxlen; 72732316Syokota mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF); 72832316Syokota mtx_init (&d->hi_queue.ifq_mtx, "ct_queue_hi", NULL, MTX_DEF); 72932316Syokota#else /*NETGRAPH*/ 73032316Syokota d->ifp = if_alloc(IFT_PPP); 73132316Syokota if (d->ifp == NULL) { 73232316Syokota printf ("%s: cannot if_alloc common interface\n", 73332316Syokota d->name); 73432316Syokota channel [b->num*NCHAN + c->num] = 0; 73532316Syokota c->sys = 0; 73632316Syokota ct_bus_dma_mem_free (&d->dmamem); 73732316Syokota continue; 73832316Syokota } 73932316Syokota d->ifp->if_softc = d; 74032316Syokota if_initname (d->ifp, "ct", b->num * NCHAN + c->num); 74132316Syokota d->ifp->if_mtu = PP_MTU; 74232316Syokota d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 74332316Syokota d->ifp->if_ioctl = ct_sioctl; 74432316Syokota d->ifp->if_start = ct_ifstart; 74532316Syokota d->ifp->if_init = ct_initialize; 74632316Syokota d->queue.ifq_maxlen = NBUF; 74732316Syokota mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF); 74832486Syokota sppp_attach (d->ifp); 74932316Syokota if_attach (d->ifp); 75032316Syokota IFP2SP(d->ifp)->pp_tlf = ct_tlf; 75132316Syokota IFP2SP(d->ifp)->pp_tls = ct_tls; 75219569Sjoerg /* If BPF is in the kernel, call the attach for it. 7532088Ssos * Header size is 4 bytes. */ 75432316Syokota bpfattach (d->ifp, DLT_PPP, 4); 75532316Syokota#endif /*NETGRAPH*/ 7562088Ssos CT_LOCK (bd); 75776502Ssobomax ct_start_chan (c, d->dmamem.virt, d->dmamem.phys); 75819569Sjoerg ct_register_receive (c, &ct_receive); 75976502Ssobomax ct_register_transmit (c, &ct_transmit); 76076502Ssobomax ct_register_error (c, &ct_error); 7612088Ssos CT_UNLOCK (bd); 76276569Ssobomax d->devt = make_dev (&ct_cdevsw, b->num*NCHAN+c->num, UID_ROOT, 76376569Ssobomax GID_WHEEL, 0600, "ct%d", b->num*NCHAN+c->num); 76476569Ssobomax } 76576502Ssobomax splx (s); 76676643Simp 76776643Simp return 0; 76876643Simp} 76976502Ssobomax 77076643Simpstatic int ct_detach (device_t dev) 77176502Ssobomax{ 77276643Simp bdrv_t *bd = device_get_softc (dev); 7732088Ssos ct_board_t *b = bd->board; 77429603Scharnier ct_chan_t *c; 7752088Ssos int s; 7762088Ssos 77732316Syokota KASSERT (mtx_initialized (&bd->ct_mtx), ("ct mutex not initialized")); 77832316Syokota 77932316Syokota s = splimp (); 7802088Ssos CT_LOCK (bd); 78132316Syokota /* Check if the device is busy (open). */ 7822088Ssos for (c = b->chan; c < b->chan + NCHAN; ++c) { 7832088Ssos drv_t *d = (drv_t*) c->sys; 78419569Sjoerg 78519569Sjoerg if (!d || !d->chan->type) 78619569Sjoerg continue; 78719569Sjoerg 78832316Syokota if (d->running) { 78932316Syokota CT_UNLOCK (bd); 79032316Syokota splx (s); 79132316Syokota return EBUSY; 79232316Syokota } 79332316Syokota } 79419569Sjoerg 79519569Sjoerg /* Deactivate the timeout routine. */ 79632316Syokota callout_stop (&led_timo[b->num]); 79729603Scharnier 7982088Ssos CT_UNLOCK (bd); 7992088Ssos 8002088Ssos bus_teardown_intr (dev, bd->irq_res, bd->intrhand); 80132316Syokota bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); 80232316Syokota 80332316Syokota bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); 80432316Syokota 80532316Syokota bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res); 80632316Syokota 8072088Ssos CT_LOCK (bd); 8082088Ssos ct_close_board (b); 8092088Ssos CT_UNLOCK (bd); 8102088Ssos 8112088Ssos /* Detach the interfaces, free buffer memory. */ 81232316Syokota for (c = b->chan; c < b->chan + NCHAN; ++c) { 81332316Syokota drv_t *d = (drv_t*) c->sys; 8142088Ssos 8152088Ssos if (!d || !d->chan->type) 81632316Syokota continue; 81729603Scharnier 81832316Syokota callout_stop (&d->timeout_handle); 81932316Syokota#ifdef NETGRAPH 8202088Ssos if (d->node) { 8212088Ssos ng_rmnode_self (d->node); 8222088Ssos NG_NODE_UNREF (d->node); 8232088Ssos d->node = NULL; 8242088Ssos } 8252088Ssos mtx_destroy (&d->queue.ifq_mtx); 82632316Syokota mtx_destroy (&d->hi_queue.ifq_mtx); 82732316Syokota#else 82832316Syokota /* Detach from the packet filter list of interfaces. */ 82932316Syokota bpfdetach (d->ifp); 83032316Syokota 83132316Syokota /* Detach from the sync PPP list. */ 83232316Syokota sppp_detach (d->ifp); 8332088Ssos 8342088Ssos if_detach (d->ifp); 8352088Ssos if_free (d->ifp); 8362088Ssos IF_DRAIN (&d->queue); 8372088Ssos mtx_destroy (&d->queue.ifq_mtx); 8382088Ssos#endif 8392088Ssos destroy_dev (d->devt); 8402088Ssos } 8412088Ssos 8422088Ssos CT_LOCK (bd); 8432088Ssos ct_led_off (b); 8442088Ssos CT_UNLOCK (bd); 8452088Ssos callout_drain (&led_timo[b->num]); 8462088Ssos splx (s); 84729603Scharnier 8482088Ssos for (c = b->chan; c < b->chan + NCHAN; ++c) { 8492088Ssos drv_t *d = (drv_t*) c->sys; 8502088Ssos 8512088Ssos if (!d || !d->chan->type) 8522088Ssos continue; 8532088Ssos callout_drain(&d->timeout_handle); 8542088Ssos 8552088Ssos /* Deallocate buffers. */ 8562088Ssos ct_bus_dma_mem_free (&d->dmamem); 8572088Ssos } 8582088Ssos bd->board = 0; 8592088Ssos adapter [b->num] = 0; 8602088Ssos free (b, M_DEVBUF); 8612088Ssos 86229603Scharnier mtx_destroy (&bd->ct_mtx); 8632088Ssos 8642088Ssos return 0; 8652088Ssos} 8662088Ssos 86729603Scharnier#ifndef NETGRAPH 8682088Ssosstatic void ct_ifstart (struct ifnet *ifp) 8692088Ssos{ 8702088Ssos drv_t *d = ifp->if_softc; 8712088Ssos bdrv_t *bd = d->bd; 8722088Ssos 8732088Ssos CT_LOCK (bd); 87429603Scharnier ct_start (d); 8752088Ssos CT_UNLOCK (bd); 8762088Ssos} 8772088Ssos 8782088Ssosstatic void ct_tlf (struct sppp *sp) 8792088Ssos{ 8802088Ssos drv_t *d = SP2IFP(sp)->if_softc; 8815536Ssos 8822088Ssos CT_DEBUG (d, ("ct_tlf\n")); 88338044Syokota/* ct_set_dtr (d->chan, 0);*/ 88438044Syokota/* ct_set_rts (d->chan, 0);*/ 88538044Syokota if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) 88638044Syokota sp->pp_down (sp); 88738044Syokota} 8888857Srgrimes 88938044Syokotastatic void ct_tls (struct sppp *sp) 8905536Ssos{ 89138044Syokota drv_t *d = SP2IFP(sp)->if_softc; 89248982Syokota 89348982Syokota CT_DEBUG (d, ("ct_tls\n")); 8942088Ssos if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) 8952088Ssos sp->pp_up (sp); 8968857Srgrimes} 8975536Ssos 8982088Ssos/* 8992088Ssos * Initialization of interface. 9002088Ssos * Ii seems to be never called by upper level. 9012088Ssos */ 9022088Ssosstatic void ct_initialize (void *softc) 9032088Ssos{ 9042088Ssos drv_t *d = softc; 90529603Scharnier 9062088Ssos CT_DEBUG (d, ("ct_initialize\n")); 9072088Ssos} 90838044Syokota 90938044Syokota/* 91038044Syokota * Process an ioctl request. 9112088Ssos */ 9122088Ssosstatic int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 9135536Ssos{ 91438044Syokota drv_t *d = ifp->if_softc; 9155536Ssos bdrv_t *bd = d->bd; 9162088Ssos int error, s, was_up, should_be_up; 9172088Ssos 9182088Ssos was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 9192088Ssos error = sppp_ioctl (ifp, cmd, data); 9202088Ssos if (error) 9212088Ssos return error; 92244628Syokota 92339047Syokota if (! (ifp->if_flags & IFF_DEBUG)) 92439047Syokota d->chan->debug = 0; 92546761Syokota else 9262088Ssos d->chan->debug = d->chan->debug_shadow; 92746761Syokota 92844628Syokota switch (cmd) { 92946761Syokota default: CT_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; 93046761Syokota case SIOCADDMULTI: CT_DEBUG2 (d, ("SIOCADDMULTI\n")); return 0; 93144628Syokota case SIOCDELMULTI: CT_DEBUG2 (d, ("SIOCDELMULTI\n")); return 0; 93246761Syokota case SIOCSIFFLAGS: CT_DEBUG2 (d, ("SIOCSIFFLAGS\n")); break; 93346761Syokota case SIOCSIFADDR: CT_DEBUG2 (d, ("SIOCSIFADDR\n")); break; 93439047Syokota } 93546761Syokota 93646761Syokota /* We get here only in case of SIFFLAGS or SIFADDR. */ 9372088Ssos s = splimp (); 9382088Ssos CT_LOCK (bd); 9392088Ssos should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 9402088Ssos if (! was_up && should_be_up) { 9412088Ssos /* Interface goes up -- start it. */ 9422088Ssos ct_up (d); 9432088Ssos ct_start (d); 9442088Ssos } else if (was_up && ! should_be_up) { 9452088Ssos /* Interface is going down -- stop it. */ 9462088Ssos /* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ 94729603Scharnier ct_down (d); 9482088Ssos } 9492088Ssos CT_UNLOCK (bd); 95046761Syokota splx (s); 95146761Syokota return 0; 95246761Syokota} 95346761Syokota#endif /*NETGRAPH*/ 95446761Syokota 95546761Syokota/* 95646761Syokota * Stop the interface. Called on splimp(). 95746761Syokota */ 9582088Ssosstatic void ct_down (drv_t *d) 9592088Ssos{ 96044628Syokota int s = splimp (); 96144628Syokota CT_DEBUG (d, ("ct_down\n")); 96246761Syokota ct_set_dtr (d->chan, 0); 96346761Syokota ct_set_rts (d->chan, 0); 96446761Syokota d->running = 0; 96546761Syokota callout_stop (&d->timeout_handle); 9662088Ssos splx (s); 9672088Ssos} 9682088Ssos 9696046Ssos/* 9706046Ssos * Start the interface. Called on splimp(). 9716046Ssos */ 9726046Ssosstatic void ct_up (drv_t *d) 9736046Ssos{ 9746046Ssos int s = splimp (); 9756046Ssos CT_DEBUG (d, ("ct_up\n")); 97629603Scharnier ct_set_dtr (d->chan, 1); 9776046Ssos ct_set_rts (d->chan, 1); 9786046Ssos d->running = 1; 9796046Ssos splx (s); 98029603Scharnier} 9816046Ssos 9826046Ssos/* 98342505Syokota * Start output on the (slave) interface. Get another datagram to send 98442505Syokota * off of the interface queue, and copy it to the interface 98542505Syokota * before starting the output. 98642505Syokota */ 98742505Syokotastatic void ct_send (drv_t *d) 98842505Syokota{ 98942505Syokota struct mbuf *m; 99042505Syokota u_short len; 99142505Syokota 99242505Syokota CT_DEBUG2 (d, ("ct_send, tn=%d\n", d->chan->tn)); 99342505Syokota 99442505Syokota /* No output if the interface is down. */ 9956046Ssos if (! d->running) 99642505Syokota return; 99742505Syokota 99842505Syokota /* No output if the modem is off. */ 99942505Syokota if (! ct_get_dsr (d->chan) && !ct_get_loop (d->chan)) 100042505Syokota return; 100142505Syokota 100242505Syokota while (ct_buf_free (d->chan)) { 100342505Syokota /* Get the packet to send. */ 100442505Syokota#ifdef NETGRAPH 100542505Syokota IF_DEQUEUE (&d->hi_queue, m); 100642505Syokota if (! m) 100742505Syokota IF_DEQUEUE (&d->queue, m); 100842505Syokota#else 100942505Syokota m = sppp_dequeue (d->ifp); 101042505Syokota#endif 101142505Syokota if (! m) 101242505Syokota return; 101342505Syokota#ifndef NETGRAPH 101442505Syokota BPF_MTAP (d->ifp, m); 101542505Syokota#endif 101642505Syokota len = m_length (m, NULL); 101742505Syokota if (! m->m_next) 101842505Syokota ct_send_packet (d->chan, (u_char*)mtod (m, caddr_t), 101942505Syokota len, 0); 102042505Syokota else { 102142505Syokota m_copydata (m, 0, len, d->chan->tbuf[d->chan->te]); 102242505Syokota ct_send_packet (d->chan, d->chan->tbuf[d->chan->te], 102342505Syokota len, 0); 102442505Syokota } 102542505Syokota m_freem (m); 102642505Syokota 102742505Syokota /* Set up transmit timeout, if the transmit ring is not empty. 102842505Syokota * Transmit timeout is 10 seconds. */ 102942505Syokota d->timeout = 10; 103042505Syokota } 103142505Syokota#ifndef NETGRAPH 103242505Syokota d->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 103342505Syokota#endif 103442505Syokota} 103542505Syokota 103642505Syokota/* 103742505Syokota * Start output on the interface. 103842505Syokota * Always called on splimp(). 103942505Syokota */ 104042505Syokotastatic void ct_start (drv_t *d) 104142505Syokota{ 104242505Syokota int s = splimp (); 104342505Syokota 104442505Syokota if (d->running) { 104542505Syokota if (! d->chan->dtr) 104642505Syokota ct_set_dtr (d->chan, 1); 104742505Syokota if (! d->chan->rts) 104842505Syokota ct_set_rts (d->chan, 1); 104942505Syokota ct_send (d); 105042505Syokota callout_reset (&d->timeout_handle, hz, ct_watchdog_timer, d); 105142505Syokota } 105242505Syokota 105342505Syokota splx (s); 105442505Syokota} 105542505Syokota 105642505Syokota/* 105742505Syokota * Handle transmit timeouts. 105842505Syokota * Recover after lost transmit interrupts. 105942505Syokota * Always called on splimp(). 106042505Syokota */ 106142505Syokotastatic void ct_watchdog (drv_t *d) 106242505Syokota{ 106342505Syokota 106442505Syokota CT_DEBUG (d, ("device timeout\n")); 106542505Syokota if (d->running) { 106642505Syokota ct_setup_chan (d->chan); 106742505Syokota ct_start_chan (d->chan, 0, 0); 106842505Syokota ct_set_dtr (d->chan, 1); 106942505Syokota ct_set_rts (d->chan, 1); 107042505Syokota ct_start (d); 107142505Syokota } 107242505Syokota} 107342505Syokota 107442505Syokotastatic void ct_watchdog_timer (void *arg) 107542505Syokota{ 107642505Syokota drv_t *d = arg; 107742505Syokota bdrv_t *bd = d->bd; 107829603Scharnier 10792088Ssos CT_LOCK (bd); 10802088Ssos if (d->timeout == 1) 108129603Scharnier ct_watchdog (d); 108242505Syokota if (d->timeout) 108329603Scharnier d->timeout--; 108442505Syokota callout_reset (&d->timeout_handle, hz, ct_watchdog_timer, d); 108529603Scharnier CT_UNLOCK (bd); 10862088Ssos} 10872088Ssos 10882088Ssos/* 108951287Speter * Transmit callback function. 10902088Ssos */ 10912088Ssosstatic void ct_transmit (ct_chan_t *c, void *attachment, int len) 10922088Ssos{ 10932088Ssos drv_t *d = c->sys; 109442505Syokota 10952088Ssos if (!d) 10962088Ssos return; 10972088Ssos d->timeout = 0; 10982088Ssos#ifndef NETGRAPH 10992088Ssos ++d->ifp->if_opackets; 11002088Ssos d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 11012088Ssos#endif 11022088Ssos ct_start (d); 110319569Sjoerg} 11042088Ssos 110519569Sjoerg/* 110619569Sjoerg * Process the received packet. 110719569Sjoerg */ 11082088Ssosstatic void ct_receive (ct_chan_t *c, char *data, int len) 11098857Srgrimes{ 11102088Ssos drv_t *d = c->sys; 11112088Ssos struct mbuf *m; 11122088Ssos#ifdef NETGRAPH 11132088Ssos int error; 11142088Ssos#endif 11156046Ssos 11166046Ssos if (!d || !d->running) 11176046Ssos return; 111842505Syokota 111942505Syokota m = makembuf (data, len); 112042505Syokota if (! m) { 112142505Syokota CT_DEBUG (d, ("no memory for packet\n")); 112242505Syokota#ifndef NETGRAPH 112342505Syokota ++d->ifp->if_iqdrops; 112442505Syokota#endif 112542505Syokota return; 112642505Syokota } 11272088Ssos if (c->debug > 1) 11282088Ssos printmbuf (m); 11292088Ssos#ifdef NETGRAPH 11302088Ssos m->m_pkthdr.rcvif = 0; 11312088Ssos NG_SEND_DATA_ONLY (error, d->hook, m); 11322088Ssos#else 11332088Ssos ++d->ifp->if_ipackets; 11342088Ssos m->m_pkthdr.rcvif = d->ifp; 11352088Ssos /* Check if there's a BPF listener on this interface. 113629603Scharnier * If so, hand off the raw packet to bpf. */ 11372088Ssos BPF_TAP (d->ifp, data, len); 11382088Ssos IF_ENQUEUE (&d->queue, m); 11392088Ssos#endif 1140} 1141 1142/* 1143 * Error callback function. 1144 */ 1145static void ct_error (ct_chan_t *c, int data) 1146{ 1147 drv_t *d = c->sys; 1148 1149 if (!d) 1150 return; 1151 1152 switch (data) { 1153 case CT_FRAME: 1154 CT_DEBUG (d, ("frame error\n")); 1155#ifndef NETGRAPH 1156 ++d->ifp->if_ierrors; 1157#endif 1158 break; 1159 case CT_CRC: 1160 CT_DEBUG (d, ("crc error\n")); 1161#ifndef NETGRAPH 1162 ++d->ifp->if_ierrors; 1163#endif 1164 break; 1165 case CT_OVERRUN: 1166 CT_DEBUG (d, ("overrun error\n")); 1167#ifndef NETGRAPH 1168 ++d->ifp->if_collisions; 1169 ++d->ifp->if_ierrors; 1170#endif 1171 break; 1172 case CT_OVERFLOW: 1173 CT_DEBUG (d, ("overflow error\n")); 1174#ifndef NETGRAPH 1175 ++d->ifp->if_ierrors; 1176#endif 1177 break; 1178 case CT_UNDERRUN: 1179 CT_DEBUG (d, ("underrun error\n")); 1180 d->timeout = 0; 1181#ifndef NETGRAPH 1182 ++d->ifp->if_oerrors; 1183 d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1184#endif 1185 ct_start (d); 1186 break; 1187 default: 1188 CT_DEBUG (d, ("error #%d\n", data)); 1189 } 1190} 1191 1192static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td) 1193{ 1194 drv_t *d; 1195 1196 if (dev2unit(dev) >= NCTAU*NCHAN || ! (d = channel[dev2unit(dev)])) 1197 return ENXIO; 1198 1199 CT_DEBUG2 (d, ("ct_open\n")); 1200 return 0; 1201} 1202 1203static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td) 1204{ 1205 drv_t *d = channel [dev2unit(dev)]; 1206 1207 if (!d) 1208 return 0; 1209 1210 CT_DEBUG2 (d, ("ct_close\n")); 1211 return 0; 1212} 1213 1214static int ct_modem_status (ct_chan_t *c) 1215{ 1216 drv_t *d = c->sys; 1217 bdrv_t *bd; 1218 int status, s; 1219 1220 if (!d) 1221 return 0; 1222 1223 bd = d->bd; 1224 1225 status = d->running ? TIOCM_LE : 0; 1226 s = splimp (); 1227 CT_LOCK (bd); 1228 if (ct_get_cd (c)) status |= TIOCM_CD; 1229 if (ct_get_cts (c)) status |= TIOCM_CTS; 1230 if (ct_get_dsr (c)) status |= TIOCM_DSR; 1231 if (c->dtr) status |= TIOCM_DTR; 1232 if (c->rts) status |= TIOCM_RTS; 1233 CT_UNLOCK (bd); 1234 splx (s); 1235 return status; 1236} 1237 1238/* 1239 * Process an ioctl request on /dev/cronyx/ctauN. 1240 */ 1241static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1242{ 1243 drv_t *d = channel [dev2unit (dev)]; 1244 bdrv_t *bd; 1245 ct_chan_t *c; 1246 struct serial_statistics *st; 1247 struct e1_statistics *opte1; 1248 int error, s; 1249 char mask[16]; 1250 1251 if (!d || !d->chan) 1252 return 0; 1253 1254 bd = d->bd; 1255 c = d->chan; 1256 1257 switch (cmd) { 1258 case SERIAL_GETREGISTERED: 1259 bzero (mask, sizeof(mask)); 1260 for (s=0; s<NCTAU*NCHAN; ++s) 1261 if (channel [s]) 1262 mask [s/8] |= 1 << (s & 7); 1263 bcopy (mask, data, sizeof (mask)); 1264 return 0; 1265 1266#ifndef NETGRAPH 1267 case SERIAL_GETPROTO: 1268 strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" : 1269 (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp"); 1270 return 0; 1271 1272 case SERIAL_SETPROTO: 1273 /* Only for superuser! */ 1274 error = priv_check (td, PRIV_DRIVER); 1275 if (error) 1276 return error; 1277 if (d->ifp->if_drv_flags & IFF_DRV_RUNNING) 1278 return EBUSY; 1279 if (! strcmp ("cisco", (char*)data)) { 1280 IFP2SP(d->ifp)->pp_flags &= ~(PP_FR); 1281 IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; 1282 d->ifp->if_flags |= PP_CISCO; 1283 } else if (! strcmp ("fr", (char*)data)) { 1284 d->ifp->if_flags &= ~(PP_CISCO); 1285 IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE; 1286 } else if (! strcmp ("ppp", (char*)data)) { 1287 IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE); 1288 d->ifp->if_flags &= ~(PP_CISCO); 1289 } else 1290 return EINVAL; 1291 return 0; 1292 1293 case SERIAL_GETKEEPALIVE: 1294 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || 1295 (d->ifp->if_flags & PP_CISCO)) 1296 return EINVAL; 1297 *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0; 1298 return 0; 1299 1300 case SERIAL_SETKEEPALIVE: 1301 /* Only for superuser! */ 1302 error = priv_check (td, PRIV_DRIVER); 1303 if (error) 1304 return error; 1305 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || 1306 (d->ifp->if_flags & PP_CISCO)) 1307 return EINVAL; 1308 if (*(int*)data) 1309 IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; 1310 else 1311 IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; 1312 return 0; 1313#endif /*NETGRAPH*/ 1314 1315 case SERIAL_GETMODE: 1316 *(int*)data = SERIAL_HDLC; 1317 return 0; 1318 1319 case SERIAL_GETCFG: 1320 if (c->mode == M_HDLC) 1321 return EINVAL; 1322 switch (ct_get_config (c->board)) { 1323 default: *(char*)data = 'a'; break; 1324 case CFG_B: *(char*)data = 'b'; break; 1325 case CFG_C: *(char*)data = 'c'; break; 1326 } 1327 return 0; 1328 1329 case SERIAL_SETCFG: 1330 /* Only for superuser! */ 1331 error = priv_check (td, PRIV_DRIVER); 1332 if (error) 1333 return error; 1334 if (c->mode == M_HDLC) 1335 return EINVAL; 1336 s = splimp (); 1337 CT_LOCK (bd); 1338 switch (*(char*)data) { 1339 case 'a': ct_set_config (c->board, CFG_A); break; 1340 case 'b': ct_set_config (c->board, CFG_B); break; 1341 case 'c': ct_set_config (c->board, CFG_C); break; 1342 } 1343 CT_UNLOCK (bd); 1344 splx (s); 1345 return 0; 1346 1347 case SERIAL_GETSTAT: 1348 st = (struct serial_statistics*) data; 1349 st->rintr = c->rintr; 1350 st->tintr = c->tintr; 1351 st->mintr = c->mintr; 1352 st->ibytes = c->ibytes; 1353 st->ipkts = c->ipkts; 1354 st->ierrs = c->ierrs; 1355 st->obytes = c->obytes; 1356 st->opkts = c->opkts; 1357 st->oerrs = c->oerrs; 1358 return 0; 1359 1360 case SERIAL_GETESTAT: 1361 opte1 = (struct e1_statistics*)data; 1362 opte1->status = c->status; 1363 opte1->cursec = c->cursec; 1364 opte1->totsec = c->totsec + c->cursec; 1365 1366 opte1->currnt.bpv = c->currnt.bpv; 1367 opte1->currnt.fse = c->currnt.fse; 1368 opte1->currnt.crce = c->currnt.crce; 1369 opte1->currnt.rcrce = c->currnt.rcrce; 1370 opte1->currnt.uas = c->currnt.uas; 1371 opte1->currnt.les = c->currnt.les; 1372 opte1->currnt.es = c->currnt.es; 1373 opte1->currnt.bes = c->currnt.bes; 1374 opte1->currnt.ses = c->currnt.ses; 1375 opte1->currnt.oofs = c->currnt.oofs; 1376 opte1->currnt.css = c->currnt.css; 1377 opte1->currnt.dm = c->currnt.dm; 1378 1379 opte1->total.bpv = c->total.bpv + c->currnt.bpv; 1380 opte1->total.fse = c->total.fse + c->currnt.fse; 1381 opte1->total.crce = c->total.crce + c->currnt.crce; 1382 opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce; 1383 opte1->total.uas = c->total.uas + c->currnt.uas; 1384 opte1->total.les = c->total.les + c->currnt.les; 1385 opte1->total.es = c->total.es + c->currnt.es; 1386 opte1->total.bes = c->total.bes + c->currnt.bes; 1387 opte1->total.ses = c->total.ses + c->currnt.ses; 1388 opte1->total.oofs = c->total.oofs + c->currnt.oofs; 1389 opte1->total.css = c->total.css + c->currnt.css; 1390 opte1->total.dm = c->total.dm + c->currnt.dm; 1391 for (s=0; s<48; ++s) { 1392 opte1->interval[s].bpv = c->interval[s].bpv; 1393 opte1->interval[s].fse = c->interval[s].fse; 1394 opte1->interval[s].crce = c->interval[s].crce; 1395 opte1->interval[s].rcrce = c->interval[s].rcrce; 1396 opte1->interval[s].uas = c->interval[s].uas; 1397 opte1->interval[s].les = c->interval[s].les; 1398 opte1->interval[s].es = c->interval[s].es; 1399 opte1->interval[s].bes = c->interval[s].bes; 1400 opte1->interval[s].ses = c->interval[s].ses; 1401 opte1->interval[s].oofs = c->interval[s].oofs; 1402 opte1->interval[s].css = c->interval[s].css; 1403 opte1->interval[s].dm = c->interval[s].dm; 1404 } 1405 return 0; 1406 1407 case SERIAL_CLRSTAT: 1408 /* Only for superuser! */ 1409 error = priv_check (td, PRIV_DRIVER); 1410 if (error) 1411 return error; 1412 c->rintr = 0; 1413 c->tintr = 0; 1414 c->mintr = 0; 1415 c->ibytes = 0; 1416 c->ipkts = 0; 1417 c->ierrs = 0; 1418 c->obytes = 0; 1419 c->opkts = 0; 1420 c->oerrs = 0; 1421 bzero (&c->currnt, sizeof (c->currnt)); 1422 bzero (&c->total, sizeof (c->total)); 1423 bzero (c->interval, sizeof (c->interval)); 1424 return 0; 1425 1426 case SERIAL_GETBAUD: 1427 *(long*)data = ct_get_baud(c); 1428 return 0; 1429 1430 case SERIAL_SETBAUD: 1431 /* Only for superuser! */ 1432 error = priv_check (td, PRIV_DRIVER); 1433 if (error) 1434 return error; 1435 s = splimp (); 1436 CT_LOCK (bd); 1437 ct_set_baud (c, *(long*)data); 1438 CT_UNLOCK (bd); 1439 splx (s); 1440 return 0; 1441 1442 case SERIAL_GETLOOP: 1443 *(int*)data = ct_get_loop (c); 1444 return 0; 1445 1446 case SERIAL_SETLOOP: 1447 /* Only for superuser! */ 1448 error = priv_check (td, PRIV_DRIVER); 1449 if (error) 1450 return error; 1451 s = splimp (); 1452 CT_LOCK (bd); 1453 ct_set_loop (c, *(int*)data); 1454 CT_UNLOCK (bd); 1455 splx (s); 1456 return 0; 1457 1458 case SERIAL_GETDPLL: 1459 if (c->mode == M_E1 || c->mode == M_G703) 1460 return EINVAL; 1461 *(int*)data = ct_get_dpll (c); 1462 return 0; 1463 1464 case SERIAL_SETDPLL: 1465 /* Only for superuser! */ 1466 error = priv_check (td, PRIV_DRIVER); 1467 if (error) 1468 return error; 1469 if (c->mode == M_E1 || c->mode == M_G703) 1470 return EINVAL; 1471 s = splimp (); 1472 CT_LOCK (bd); 1473 ct_set_dpll (c, *(int*)data); 1474 CT_UNLOCK (bd); 1475 splx (s); 1476 return 0; 1477 1478 case SERIAL_GETNRZI: 1479 if (c->mode == M_E1 || c->mode == M_G703) 1480 return EINVAL; 1481 *(int*)data = ct_get_nrzi (c); 1482 return 0; 1483 1484 case SERIAL_SETNRZI: 1485 /* Only for superuser! */ 1486 error = priv_check (td, PRIV_DRIVER); 1487 if (error) 1488 return error; 1489 if (c->mode == M_E1 || c->mode == M_G703) 1490 return EINVAL; 1491 s = splimp (); 1492 CT_LOCK (bd); 1493 ct_set_nrzi (c, *(int*)data); 1494 CT_UNLOCK (bd); 1495 splx (s); 1496 return 0; 1497 1498 case SERIAL_GETDEBUG: 1499 *(int*)data = c->debug; 1500 return 0; 1501 1502 case SERIAL_SETDEBUG: 1503 /* Only for superuser! */ 1504 error = priv_check (td, PRIV_DRIVER); 1505 if (error) 1506 return error; 1507#ifndef NETGRAPH 1508 /* 1509 * The debug_shadow is always greater than zero for logic 1510 * simplicity. For switching debug off the IFF_DEBUG is 1511 * responsible. 1512 */ 1513 c->debug_shadow = (*(int*)data) ? (*(int*)data) : 1; 1514 if (d->ifp->if_flags & IFF_DEBUG) 1515 c->debug = c->debug_shadow; 1516#else 1517 c->debug = *(int*)data; 1518#endif 1519 return 0; 1520 1521 case SERIAL_GETHIGAIN: 1522 if (c->mode != M_E1) 1523 return EINVAL; 1524 *(int*)data = ct_get_higain (c); 1525 return 0; 1526 1527 case SERIAL_SETHIGAIN: 1528 /* Only for superuser! */ 1529 error = priv_check (td, PRIV_DRIVER); 1530 if (error) 1531 return error; 1532 s = splimp (); 1533 CT_LOCK (bd); 1534 ct_set_higain (c, *(int*)data); 1535 CT_UNLOCK (bd); 1536 splx (s); 1537 return 0; 1538 1539 case SERIAL_GETPHONY: 1540 CT_DEBUG2 (d, ("ioctl: getphony\n")); 1541 if (c->mode != M_E1) 1542 return EINVAL; 1543 *(int*)data = c->gopt.phony; 1544 return 0; 1545 1546 case SERIAL_SETPHONY: 1547 CT_DEBUG2 (d, ("ioctl: setphony\n")); 1548 if (c->mode != M_E1) 1549 return EINVAL; 1550 /* Only for superuser! */ 1551 error = priv_check (td, PRIV_DRIVER); 1552 if (error) 1553 return error; 1554 s = splimp (); 1555 CT_LOCK (bd); 1556 ct_set_phony (c, *(int*)data); 1557 CT_UNLOCK (bd); 1558 splx (s); 1559 return 0; 1560 1561 case SERIAL_GETCLK: 1562 if (c->mode != M_E1 && c->mode != M_G703) 1563 return EINVAL; 1564 switch (ct_get_clk(c)) { 1565 default: *(int*)data = E1CLK_INTERNAL; break; 1566 case GCLK_RCV: *(int*)data = E1CLK_RECEIVE; break; 1567 case GCLK_RCLKO: *(int*)data = c->num ? 1568 E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1; break; 1569 } 1570 return 0; 1571 1572 case SERIAL_SETCLK: 1573 /* Only for superuser! */ 1574 error = priv_check (td, PRIV_DRIVER); 1575 if (error) 1576 return error; 1577 s = splimp (); 1578 CT_LOCK (bd); 1579 switch (*(int*)data) { 1580 default: ct_set_clk (c, GCLK_INT); break; 1581 case E1CLK_RECEIVE: ct_set_clk (c, GCLK_RCV); break; 1582 case E1CLK_RECEIVE_CHAN0: 1583 case E1CLK_RECEIVE_CHAN1: 1584 ct_set_clk (c, GCLK_RCLKO); break; 1585 } 1586 CT_UNLOCK (bd); 1587 splx (s); 1588 return 0; 1589 1590 case SERIAL_GETTIMESLOTS: 1591 if (c->mode != M_E1) 1592 return EINVAL; 1593 *(long*)data = ct_get_ts (c); 1594 return 0; 1595 1596 case SERIAL_SETTIMESLOTS: 1597 /* Only for superuser! */ 1598 error = priv_check (td, PRIV_DRIVER); 1599 if (error) 1600 return error; 1601 s = splimp (); 1602 CT_LOCK (bd); 1603 ct_set_ts (c, *(long*)data); 1604 CT_UNLOCK (bd); 1605 splx (s); 1606 return 0; 1607 1608 case SERIAL_GETSUBCHAN: 1609 if (c->mode != M_E1) 1610 return EINVAL; 1611 *(long*)data = ct_get_subchan (c->board); 1612 return 0; 1613 1614 case SERIAL_SETSUBCHAN: 1615 /* Only for superuser! */ 1616 error = priv_check (td, PRIV_DRIVER); 1617 if (error) 1618 return error; 1619 s = splimp (); 1620 CT_LOCK (bd); 1621 ct_set_subchan (c->board, *(long*)data); 1622 CT_UNLOCK (bd); 1623 splx (s); 1624 return 0; 1625 1626 case SERIAL_GETINVCLK: 1627 case SERIAL_GETINVTCLK: 1628 if (c->mode == M_E1 || c->mode == M_G703) 1629 return EINVAL; 1630 *(int*)data = ct_get_invtxc (c); 1631 return 0; 1632 1633 case SERIAL_GETINVRCLK: 1634 if (c->mode == M_E1 || c->mode == M_G703) 1635 return EINVAL; 1636 *(int*)data = ct_get_invrxc (c); 1637 return 0; 1638 1639 case SERIAL_SETINVCLK: 1640 case SERIAL_SETINVTCLK: 1641 /* Only for superuser! */ 1642 error = priv_check (td, PRIV_DRIVER); 1643 if (error) 1644 return error; 1645 if (c->mode == M_E1 || c->mode == M_G703) 1646 return EINVAL; 1647 s = splimp (); 1648 CT_LOCK (bd); 1649 ct_set_invtxc (c, *(int*)data); 1650 CT_UNLOCK (bd); 1651 splx (s); 1652 return 0; 1653 1654 case SERIAL_SETINVRCLK: 1655 /* Only for superuser! */ 1656 error = priv_check (td, PRIV_DRIVER); 1657 if (error) 1658 return error; 1659 if (c->mode == M_E1 || c->mode == M_G703) 1660 return EINVAL; 1661 s = splimp (); 1662 CT_LOCK (bd); 1663 ct_set_invrxc (c, *(int*)data); 1664 CT_UNLOCK (bd); 1665 splx (s); 1666 return 0; 1667 1668 case SERIAL_GETLEVEL: 1669 if (c->mode != M_G703) 1670 return EINVAL; 1671 s = splimp (); 1672 CT_LOCK (bd); 1673 *(int*)data = ct_get_lq (c); 1674 CT_UNLOCK (bd); 1675 splx (s); 1676 return 0; 1677 1678 case TIOCSDTR: /* Set DTR */ 1679 s = splimp (); 1680 CT_LOCK (bd); 1681 ct_set_dtr (c, 1); 1682 CT_UNLOCK (bd); 1683 splx (s); 1684 return 0; 1685 1686 case TIOCCDTR: /* Clear DTR */ 1687 s = splimp (); 1688 CT_LOCK (bd); 1689 ct_set_dtr (c, 0); 1690 CT_UNLOCK (bd); 1691 splx (s); 1692 return 0; 1693 1694 case TIOCMSET: /* Set DTR/RTS */ 1695 s = splimp (); 1696 CT_LOCK (bd); 1697 ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); 1698 ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); 1699 CT_UNLOCK (bd); 1700 splx (s); 1701 return 0; 1702 1703 case TIOCMBIS: /* Add DTR/RTS */ 1704 s = splimp (); 1705 CT_LOCK (bd); 1706 if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1); 1707 if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1); 1708 CT_UNLOCK (bd); 1709 splx (s); 1710 return 0; 1711 1712 case TIOCMBIC: /* Clear DTR/RTS */ 1713 s = splimp (); 1714 CT_LOCK (bd); 1715 if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0); 1716 if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0); 1717 CT_UNLOCK (bd); 1718 splx (s); 1719 return 0; 1720 1721 case TIOCMGET: /* Get modem status */ 1722 *(int*)data = ct_modem_status (c); 1723 return 0; 1724 } 1725 return ENOTTY; 1726} 1727 1728#ifdef NETGRAPH 1729static int ng_ct_constructor (node_p node) 1730{ 1731 drv_t *d = NG_NODE_PRIVATE (node); 1732 CT_DEBUG (d, ("Constructor\n")); 1733 return EINVAL; 1734} 1735 1736static int ng_ct_newhook (node_p node, hook_p hook, const char *name) 1737{ 1738 int s; 1739 drv_t *d = NG_NODE_PRIVATE (node); 1740 1741 if (!d) 1742 return EINVAL; 1743 1744 bdrv_t *bd = d->bd; 1745 1746 /* Attach debug hook */ 1747 if (strcmp (name, NG_CT_HOOK_DEBUG) == 0) { 1748 NG_HOOK_SET_PRIVATE (hook, NULL); 1749 d->debug_hook = hook; 1750 return 0; 1751 } 1752 1753 /* Check for raw hook */ 1754 if (strcmp (name, NG_CT_HOOK_RAW) != 0) 1755 return EINVAL; 1756 1757 NG_HOOK_SET_PRIVATE (hook, d); 1758 d->hook = hook; 1759 s = splimp (); 1760 CT_LOCK (bd); 1761 ct_up (d); 1762 CT_UNLOCK (bd); 1763 splx (s); 1764 return 0; 1765} 1766 1767static char *format_timeslots (u_long s) 1768{ 1769 static char buf [100]; 1770 char *p = buf; 1771 int i; 1772 1773 for (i=1; i<32; ++i) 1774 if ((s >> i) & 1) { 1775 int prev = (i > 1) & (s >> (i-1)); 1776 int next = (i < 31) & (s >> (i+1)); 1777 1778 if (prev) { 1779 if (next) 1780 continue; 1781 *p++ = '-'; 1782 } else if (p > buf) 1783 *p++ = ','; 1784 1785 if (i >= 10) 1786 *p++ = '0' + i / 10; 1787 *p++ = '0' + i % 10; 1788 } 1789 *p = 0; 1790 return buf; 1791} 1792 1793static int print_modems (char *s, ct_chan_t *c, int need_header) 1794{ 1795 int status = ct_modem_status (c); 1796 int length = 0; 1797 1798 if (need_header) 1799 length += sprintf (s + length, " LE DTR DSR RTS CTS CD\n"); 1800 length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n", 1801 status & TIOCM_LE ? "On" : "-", 1802 status & TIOCM_DTR ? "On" : "-", 1803 status & TIOCM_DSR ? "On" : "-", 1804 status & TIOCM_RTS ? "On" : "-", 1805 status & TIOCM_CTS ? "On" : "-", 1806 status & TIOCM_CD ? "On" : "-"); 1807 return length; 1808} 1809 1810static int print_stats (char *s, ct_chan_t *c, int need_header) 1811{ 1812 struct serial_statistics st; 1813 int length = 0; 1814 1815 st.rintr = c->rintr; 1816 st.tintr = c->tintr; 1817 st.mintr = c->mintr; 1818 st.ibytes = c->ibytes; 1819 st.ipkts = c->ipkts; 1820 st.ierrs = c->ierrs; 1821 st.obytes = c->obytes; 1822 st.opkts = c->opkts; 1823 st.oerrs = c->oerrs; 1824 if (need_header) 1825 length += sprintf (s + length, " Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); 1826 length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n", 1827 st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts, 1828 st.ierrs, st.obytes, st.opkts, st.oerrs); 1829 return length; 1830} 1831 1832static char *format_e1_status (u_char status) 1833{ 1834 static char buf [80]; 1835 1836 if (status & E1_NOALARM) 1837 return "Ok"; 1838 buf[0] = 0; 1839 if (status & E1_LOS) strcat (buf, ",LOS"); 1840 if (status & E1_AIS) strcat (buf, ",AIS"); 1841 if (status & E1_LOF) strcat (buf, ",LOF"); 1842 if (status & E1_LOMF) strcat (buf, ",LOMF"); 1843 if (status & E1_FARLOF) strcat (buf, ",FARLOF"); 1844 if (status & E1_AIS16) strcat (buf, ",AIS16"); 1845 if (status & E1_FARLOMF) strcat (buf, ",FARLOMF"); 1846 if (status & E1_TSTREQ) strcat (buf, ",TSTREQ"); 1847 if (status & E1_TSTERR) strcat (buf, ",TSTERR"); 1848 if (buf[0] == ',') 1849 return buf+1; 1850 return "Unknown"; 1851} 1852 1853static int print_frac (char *s, int leftalign, u_long numerator, u_long divider) 1854{ 1855 int n, length = 0; 1856 1857 if (numerator < 1 || divider < 1) { 1858 length += sprintf (s+length, leftalign ? "/- " : " -"); 1859 return length; 1860 } 1861 n = (int) (0.5 + 1000.0 * numerator / divider); 1862 if (n < 1000) { 1863 length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n); 1864 return length; 1865 } 1866 *(s + length) = leftalign ? '/' : ' '; 1867 length ++; 1868 1869 if (n >= 1000000) n = (n+500) / 1000 * 1000; 1870 else if (n >= 100000) n = (n+50) / 100 * 100; 1871 else if (n >= 10000) n = (n+5) / 10 * 10; 1872 1873 switch (n) { 1874 case 1000: length += printf (s+length, ".999"); return length; 1875 case 10000: n = 9990; break; 1876 case 100000: n = 99900; break; 1877 case 1000000: n = 999000; break; 1878 } 1879 if (n < 10000) length += sprintf (s+length, "%d.%d", n/1000, n/10%100); 1880 else if (n < 100000) length += sprintf (s+length, "%d.%d", n/1000, n/100%10); 1881 else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000); 1882 else length += sprintf (s+length, "%d", n/1000); 1883 1884 return length; 1885} 1886 1887static int print_e1_stats (char *s, ct_chan_t *c) 1888{ 1889 struct e1_counters total; 1890 u_long totsec; 1891 int length = 0; 1892 1893 totsec = c->totsec + c->cursec; 1894 total.bpv = c->total.bpv + c->currnt.bpv; 1895 total.fse = c->total.fse + c->currnt.fse; 1896 total.crce = c->total.crce + c->currnt.crce; 1897 total.rcrce = c->total.rcrce + c->currnt.rcrce; 1898 total.uas = c->total.uas + c->currnt.uas; 1899 total.les = c->total.les + c->currnt.les; 1900 total.es = c->total.es + c->currnt.es; 1901 total.bes = c->total.bes + c->currnt.bes; 1902 total.ses = c->total.ses + c->currnt.ses; 1903 total.oofs = c->total.oofs + c->currnt.oofs; 1904 total.css = c->total.css + c->currnt.css; 1905 total.dm = c->total.dm + c->currnt.dm; 1906 1907 length += sprintf (s + length, " Unav/Degr Bpv/Fsyn CRC/RCRC Err/Lerr Sev/Bur Oof/Slp Status\n"); 1908 1909 /* Unavailable seconds, degraded minutes */ 1910 length += print_frac (s + length, 0, c->currnt.uas, c->cursec); 1911 length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec); 1912 1913 /* Bipolar violations, frame sync errors */ 1914 length += print_frac (s + length, 0, c->currnt.bpv, c->cursec); 1915 length += print_frac (s + length, 1, c->currnt.fse, c->cursec); 1916 1917 /* CRC errors, remote CRC errors (E-bit) */ 1918 length += print_frac (s + length, 0, c->currnt.crce, c->cursec); 1919 length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec); 1920 1921 /* Errored seconds, line errored seconds */ 1922 length += print_frac (s + length, 0, c->currnt.es, c->cursec); 1923 length += print_frac (s + length, 1, c->currnt.les, c->cursec); 1924 1925 /* Severely errored seconds, burst errored seconds */ 1926 length += print_frac (s + length, 0, c->currnt.ses, c->cursec); 1927 length += print_frac (s + length, 1, c->currnt.bes, c->cursec); 1928 1929 /* Out of frame seconds, controlled slip seconds */ 1930 length += print_frac (s + length, 0, c->currnt.oofs, c->cursec); 1931 length += print_frac (s + length, 1, c->currnt.css, c->cursec); 1932 1933 length += sprintf (s + length, " %s\n", format_e1_status (c->status)); 1934 1935 /* Print total statistics. */ 1936 length += print_frac (s + length, 0, total.uas, totsec); 1937 length += print_frac (s + length, 1, 60 * total.dm, totsec); 1938 1939 length += print_frac (s + length, 0, total.bpv, totsec); 1940 length += print_frac (s + length, 1, total.fse, totsec); 1941 1942 length += print_frac (s + length, 0, total.crce, totsec); 1943 length += print_frac (s + length, 1, total.rcrce, totsec); 1944 1945 length += print_frac (s + length, 0, total.es, totsec); 1946 length += print_frac (s + length, 1, total.les, totsec); 1947 1948 length += print_frac (s + length, 0, total.ses, totsec); 1949 length += print_frac (s + length, 1, total.bes, totsec); 1950 1951 length += print_frac (s + length, 0, total.oofs, totsec); 1952 length += print_frac (s + length, 1, total.css, totsec); 1953 1954 length += sprintf (s + length, " -- Total\n"); 1955 return length; 1956} 1957 1958static int print_chan (char *s, ct_chan_t *c) 1959{ 1960 drv_t *d = c->sys; 1961 bdrv_t *bd = d->bd; 1962 int length = 0; 1963 1964 length += sprintf (s + length, "ct%d", c->board->num * NCHAN + c->num); 1965 if (d->chan->debug) 1966 length += sprintf (s + length, " debug=%d", d->chan->debug); 1967 1968 switch (ct_get_config (c->board)) { 1969 case CFG_A: length += sprintf (s + length, " cfg=A"); break; 1970 case CFG_B: length += sprintf (s + length, " cfg=B"); break; 1971 case CFG_C: length += sprintf (s + length, " cfg=C"); break; 1972 default: length += sprintf (s + length, " cfg=unknown"); break; 1973 } 1974 1975 if (ct_get_baud (c)) 1976 length += sprintf (s + length, " %ld", ct_get_baud (c)); 1977 else 1978 length += sprintf (s + length, " extclock"); 1979 1980 if (c->mode == M_E1 || c->mode == M_G703) 1981 switch (ct_get_clk(c)) { 1982 case GCLK_INT : length += sprintf (s + length, " syn=int"); break; 1983 case GCLK_RCV : length += sprintf (s + length, " syn=rcv"); break; 1984 case GCLK_RCLKO : length += sprintf (s + length, " syn=xrcv"); break; 1985 } 1986 if (c->mode == M_HDLC) { 1987 length += sprintf (s + length, " dpll=%s", ct_get_dpll (c) ? "on" : "off"); 1988 length += sprintf (s + length, " nrzi=%s", ct_get_nrzi (c) ? "on" : "off"); 1989 length += sprintf (s + length, " invtclk=%s", ct_get_invtxc (c) ? "on" : "off"); 1990 length += sprintf (s + length, " invrclk=%s", ct_get_invrxc (c) ? "on" : "off"); 1991 } 1992 if (c->mode == M_E1) 1993 length += sprintf (s + length, " higain=%s", ct_get_higain (c)? "on" : "off"); 1994 1995 length += sprintf (s + length, " loop=%s", ct_get_loop (c) ? "on" : "off"); 1996 1997 if (c->mode == M_E1) 1998 length += sprintf (s + length, " ts=%s", format_timeslots (ct_get_ts(c))); 1999 if (c->mode == M_E1 && ct_get_config (c->board) != CFG_A) 2000 length += sprintf (s + length, " pass=%s", format_timeslots (ct_get_subchan(c->board))); 2001 if (c->mode == M_G703) { 2002 int lq, x; 2003 2004 x = splimp (); 2005 CT_LOCK (bd); 2006 lq = ct_get_lq (c); 2007 CT_UNLOCK (bd); 2008 splx (x); 2009 length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0); 2010 } 2011 length += sprintf (s + length, "\n"); 2012 return length; 2013} 2014 2015static int ng_ct_rcvmsg (node_p node, item_p item, hook_p lasthook) 2016{ 2017 drv_t *d = NG_NODE_PRIVATE (node); 2018 struct ng_mesg *msg; 2019 struct ng_mesg *resp = NULL; 2020 int error = 0; 2021 2022 if (!d) 2023 return EINVAL; 2024 2025 CT_DEBUG (d, ("Rcvmsg\n")); 2026 NGI_GET_MSG (item, msg); 2027 switch (msg->header.typecookie) { 2028 default: 2029 error = EINVAL; 2030 break; 2031 2032 case NGM_CT_COOKIE: 2033 printf ("Don't forget to implement\n"); 2034 error = EINVAL; 2035 break; 2036 2037 case NGM_GENERIC_COOKIE: 2038 switch (msg->header.cmd) { 2039 default: 2040 error = EINVAL; 2041 break; 2042 2043 case NGM_TEXT_STATUS: { 2044 char *s; 2045 int l = 0; 2046 int dl = sizeof (struct ng_mesg) + 730; 2047 2048 NG_MKRESPONSE (resp, msg, dl, M_NOWAIT); 2049 if (! resp) { 2050 error = ENOMEM; 2051 break; 2052 } 2053 s = (resp)->data; 2054 l += print_chan (s + l, d->chan); 2055 l += print_stats (s + l, d->chan, 1); 2056 l += print_modems (s + l, d->chan, 1); 2057 l += print_e1_stats (s + l, d->chan); 2058 strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRSIZ); 2059 } 2060 break; 2061 } 2062 break; 2063 } 2064 NG_RESPOND_MSG (error, node, item, resp); 2065 NG_FREE_MSG (msg); 2066 return error; 2067} 2068 2069static int ng_ct_rcvdata (hook_p hook, item_p item) 2070{ 2071 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook)); 2072 struct mbuf *m; 2073 struct ng_tag_prio *ptag; 2074 bdrv_t *bd; 2075 struct ifqueue *q; 2076 int s; 2077 2078 if (!d) 2079 return ENETDOWN; 2080 2081 bd = d->bd; 2082 NGI_GET_M (item, m); 2083 NG_FREE_ITEM (item); 2084 if (! NG_HOOK_PRIVATE (hook) || ! d) { 2085 NG_FREE_M (m); 2086 return ENETDOWN; 2087 } 2088 2089 /* Check for high priority data */ 2090 if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE, 2091 NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) ) 2092 q = &d->hi_queue; 2093 else 2094 q = &d->queue; 2095 2096 s = splimp (); 2097 CT_LOCK (bd); 2098 IF_LOCK (q); 2099 if (_IF_QFULL (q)) { 2100 _IF_DROP (q); 2101 IF_UNLOCK (q); 2102 CT_UNLOCK (bd); 2103 splx (s); 2104 NG_FREE_M (m); 2105 return ENOBUFS; 2106 } 2107 _IF_ENQUEUE (q, m); 2108 IF_UNLOCK (q); 2109 ct_start (d); 2110 CT_UNLOCK (bd); 2111 splx (s); 2112 return 0; 2113} 2114 2115static int ng_ct_rmnode (node_p node) 2116{ 2117 drv_t *d = NG_NODE_PRIVATE (node); 2118 bdrv_t *bd; 2119 2120 CT_DEBUG (d, ("Rmnode\n")); 2121 if (d && d->running) { 2122 bd = d->bd; 2123 int s = splimp (); 2124 CT_LOCK (bd); 2125 ct_down (d); 2126 CT_UNLOCK (bd); 2127 splx (s); 2128 } 2129#ifdef KLD_MODULE 2130 if (node->nd_flags & NGF_REALLY_DIE) { 2131 NG_NODE_SET_PRIVATE (node, NULL); 2132 NG_NODE_UNREF (node); 2133 } 2134 NG_NODE_REVIVE(node); /* Persistant node */ 2135#endif 2136 return 0; 2137} 2138 2139static int ng_ct_connect (hook_p hook) 2140{ 2141 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2142 2143 if (!d) 2144 return 0; 2145 2146 callout_reset (&d->timeout_handle, hz, ct_watchdog_timer, d); 2147 return 0; 2148} 2149 2150static int ng_ct_disconnect (hook_p hook) 2151{ 2152 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2153 bdrv_t *bd; 2154 2155 if (!d) 2156 return 0; 2157 2158 bd = d->bd; 2159 2160 CT_LOCK (bd); 2161 if (NG_HOOK_PRIVATE (hook)) 2162 ct_down (d); 2163 CT_UNLOCK (bd); 2164 /* If we were wait it than it reasserted now, just stop it. */ 2165 if (!callout_drain (&d->timeout_handle)) 2166 callout_stop (&d->timeout_handle); 2167 return 0; 2168} 2169#endif 2170 2171static int ct_modevent (module_t mod, int type, void *unused) 2172{ 2173 static int load_count = 0; 2174 2175 switch (type) { 2176 case MOD_LOAD: 2177#ifdef NETGRAPH 2178 if (ng_newtype (&typestruct)) 2179 printf ("Failed to register ng_ct\n"); 2180#endif 2181 ++load_count; 2182 callout_init (&timeout_handle, CALLOUT_MPSAFE); 2183 callout_reset (&timeout_handle, hz*5, ct_timeout, 0); 2184 break; 2185 case MOD_UNLOAD: 2186 if (load_count == 1) { 2187 printf ("Removing device entry for Tau-ISA\n"); 2188#ifdef NETGRAPH 2189 ng_rmtype (&typestruct); 2190#endif 2191 } 2192 /* If we were wait it than it reasserted now, just stop it. */ 2193 if (!callout_drain (&timeout_handle)) 2194 callout_stop (&timeout_handle); 2195 --load_count; 2196 break; 2197 case MOD_SHUTDOWN: 2198 break; 2199 } 2200 return 0; 2201} 2202 2203#ifdef NETGRAPH 2204static struct ng_type typestruct = { 2205 .version = NG_ABI_VERSION, 2206 .name = NG_CT_NODE_TYPE, 2207 .constructor = ng_ct_constructor, 2208 .rcvmsg = ng_ct_rcvmsg, 2209 .shutdown = ng_ct_rmnode, 2210 .newhook = ng_ct_newhook, 2211 .connect = ng_ct_connect, 2212 .rcvdata = ng_ct_rcvdata, 2213 .disconnect = ng_ct_disconnect, 2214}; 2215#endif /*NETGRAPH*/ 2216 2217#ifdef NETGRAPH 2218MODULE_DEPEND (ng_ct, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 2219#else 2220MODULE_DEPEND (ct, sppp, 1, 1, 1); 2221#endif 2222DRIVER_MODULE (ct, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL); 2223MODULE_VERSION (ct, 1); 2224