if_ce.c revision 271373
1139743Simp/* 243412Snewton * Cronyx-Tau32-PCI adapter driver for FreeBSD. 343412Snewton * 443412Snewton * Copyright (C) 2003-2005 Cronyx Engineering. 543412Snewton * Copyright (C) 2003-2005 Kurakin Roman, <rik@FreeBSD.org> 643412Snewton * 743412Snewton * This software is distributed with NO WARRANTIES, not even the implied 843412Snewton * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 943412Snewton * 1043412Snewton * Authors grant any other persons or organisations a permission to use, 1143412Snewton * modify and redistribute this software in source and binary forms, 1243412Snewton * as long as this message is kept with the software, all derivative 1343412Snewton * works or modified versions. 1443412Snewton * 1543412Snewton * $Cronyx: if_ce.c,v 1.9.2.8 2005/11/21 14:17:44 rik Exp $ 1643412Snewton */ 1743412Snewton 1843412Snewton#include <sys/cdefs.h> 1943412Snewton__FBSDID("$FreeBSD: head/sys/dev/ce/if_ce.c 271373 2014-09-10 09:57:32Z rwatson $"); 2043412Snewton 2143412Snewton#include <sys/param.h> 2243412Snewton 2343412Snewton#if __FreeBSD_version >= 500000 2443412Snewton# define NPCI 1 2543412Snewton#else 2643412Snewton# include "pci.h" 2743412Snewton#endif 2843412Snewton 2943412Snewton#if NPCI > 0 3043412Snewton 3143412Snewton#include <sys/ucred.h> 3243412Snewton#include <sys/priv.h> 3343412Snewton#include <sys/proc.h> 3443412Snewton#include <sys/systm.h> 35116174Sobrien#include <sys/mbuf.h> 36116174Sobrien#include <sys/kernel.h> 37116174Sobrien#include <sys/module.h> 3843412Snewton#include <sys/conf.h> 3943412Snewton#include <sys/malloc.h> 40224778Srwatson#include <sys/socket.h> 4143412Snewton#include <sys/sockio.h> 4276166Smarkm#if __FreeBSD_version >= 504000 4343412Snewton#include <sys/sysctl.h> 44141486Sjhb#endif 4543412Snewton#include <sys/tty.h> 4676166Smarkm#include <sys/bus.h> 4776166Smarkm#include <vm/vm.h> 4876166Smarkm#include <vm/pmap.h> 4943412Snewton#include <net/if.h> 5043412Snewton#include <net/if_var.h> 5176166Smarkm#if __FreeBSD_version > 501000 5276166Smarkm# include <dev/pci/pcivar.h> 5376166Smarkm# include <dev/pci/pcireg.h> 54164033Srwatson#else 5576166Smarkm# include <pci/pcivar.h> 5676166Smarkm# include <pci/pcireg.h> 5743412Snewton#endif 5843412Snewton#include <machine/bus.h> 5976166Smarkm#include <sys/rman.h> 60138129Sdas#include "opt_ng_cronyx.h" 6176166Smarkm#ifdef NETGRAPH_CRONYX 6274940Sjhb# include "opt_netgraph.h" 63139739Sjhb# ifndef NETGRAPH 6476166Smarkm# error #option NETGRAPH missed from configuration 6576166Smarkm# endif 6676166Smarkm# include <netgraph/ng_message.h> 6743412Snewton# include <netgraph/netgraph.h> 6876166Smarkm# include <dev/ce/ng_ce.h> 6943412Snewton#else 7043412Snewton# include <net/if_types.h> 7165302Sobrien# include <net/if_sppp.h> 7265302Sobrien# define PP_CISCO IFF_LINK2 7365302Sobrien# include <net/bpf.h> 7465302Sobrien#endif 7565302Sobrien#include <dev/cx/machdep.h> 7665302Sobrien#include <dev/ce/ceddk.h> 7765302Sobrien#include <machine/cserial.h> 7865302Sobrien#include <machine/resource.h> 7965302Sobrien#include <machine/pmap.h> 8065302Sobrien 8165302Sobrien/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */ 8265302Sobrien#ifndef PP_FR 8365302Sobrien#define PP_FR 0 8443412Snewton#endif 85163606Srwatson 86163606Srwatson#ifndef IFP2SP 8743412Snewton#define IFP2SP(ifp) ((struct sppp*)ifp) 8843412Snewton#endif 8943412Snewton#ifndef SP2IFP 9043412Snewton#define SP2IFP(sp) ((struct ifnet*)sp) 9171452Sjhb#endif 9292787Sjeff 93109254Sdillon#ifndef PCIR_BAR 9471452Sjhb#define PCIR_BAR(x) (PCIR_MAPS + (x) * 4) 9543412Snewton#endif 9643412Snewton 9743412Snewton/* define as our previous return value */ 9843412Snewton#ifndef BUS_PROBE_DEFAULT 9943412Snewton#define BUS_PROBE_DEFAULT 0 10043412Snewton#endif 10143412Snewton 10243412Snewton#define CE_DEBUG(d,s) ({if (d->chan->debug) {\ 10343412Snewton printf ("%s: ", d->name); printf s;}}) 10492761Salfred#define CE_DEBUG2(d,s) ({if (d->chan->debug>1) {\ 10592761Salfred printf ("%s: ", d->name); printf s;}}) 10643412Snewton 10792761Salfred#ifndef CALLOUT_MPSAFE 108160510Sjhb#define CALLOUT_MPSAFE 0 10943412Snewton#endif 11043412Snewton 11192761Salfred#ifndef IF_DRAIN 11292761Salfred#define IF_DRAIN(ifq) do { \ 11392761Salfred struct mbuf *m; \ 11492761Salfred for (;;) { \ 11592761Salfred IF_DEQUEUE(ifq, m); \ 11692761Salfred if (m == NULL) \ 11792761Salfred break; \ 11843412Snewton m_freem(m); \ 11943412Snewton } \ 12043412Snewton} while (0) 12143412Snewton#endif 12283366Sjulian 123193014Sdelphij#ifndef _IF_QLEN 12443412Snewton#define _IF_QLEN(ifq) ((ifq)->ifq_len) 12543412Snewton#endif 12683366Sjulian 12743412Snewton#ifndef callout_drain 12843412Snewton#define callout_drain callout_stop 12943412Snewton#endif 13043412Snewton 13143412Snewton#define CE_LOCK_NAME "ceX" 13283366Sjulian 13383366Sjulian#define CE_LOCK(_bd) mtx_lock (&(_bd)->ce_mtx) 13443412Snewton#define CE_UNLOCK(_bd) mtx_unlock (&(_bd)->ce_mtx) 13543412Snewton#define CE_LOCK_ASSERT(_bd) mtx_assert (&(_bd)->ce_mtx, MA_OWNED) 136127140Sjhb 13743412Snewton#define CDEV_MAJOR 185 138127140Sjhb 139127140Sjhbstatic int ce_probe __P((device_t)); 140127140Sjhbstatic int ce_attach __P((device_t)); 14143412Snewtonstatic int ce_detach __P((device_t)); 14243412Snewton 14343412Snewtonstatic device_method_t ce_methods[] = { 14443412Snewton /* Device interface */ 14551793Smarcel DEVMETHOD(device_probe, ce_probe), 14643412Snewton DEVMETHOD(device_attach, ce_attach), 14743412Snewton DEVMETHOD(device_detach, ce_detach), 14843412Snewton 14951793Smarcel DEVMETHOD_END 15043412Snewton}; 15143412Snewton 15243412Snewtontypedef struct _ce_dma_mem_t { 15343412Snewton unsigned long phys; 15443412Snewton void *virt; 15543412Snewton size_t size; 156127140Sjhb#if __FreeBSD_version >= 500000 15743412Snewton bus_dma_tag_t dmat; 158107849Salfred bus_dmamap_t mapp; 159127140Sjhb#endif 16043412Snewton} ce_dma_mem_t; 161127140Sjhb 16243412Snewtontypedef struct _drv_t { 16343412Snewton char name [8]; 16443412Snewton int running; 16583366Sjulian ce_board_t *board; 16683366Sjulian ce_chan_t *chan; 16743412Snewton struct ifqueue rqueue; 16843412Snewton#ifdef NETGRAPH 169141486Sjhb char nodename [NG_NODESIZE]; 170141486Sjhb hook_p hook; 171141486Sjhb hook_p debug_hook; 17243412Snewton node_p node; 173141486Sjhb struct ifqueue queue; 17443412Snewton struct ifqueue hi_queue; 175141486Sjhb#else 176141486Sjhb struct ifnet *ifp; 177141486Sjhb#endif 178141486Sjhb short timeout; 179141486Sjhb struct callout timeout_handle; 18043412Snewton#if __FreeBSD_version >= 500000 18143412Snewton struct cdev *devt; 18243412Snewton#else /* __FreeBSD_version < 500000 */ 18383366Sjulian dev_t devt; 18483366Sjulian#endif 18543412Snewton ce_dma_mem_t dmamem; 18643412Snewton} drv_t; 187141486Sjhb 188141486Sjhbtypedef struct _bdrv_t { 189141486Sjhb ce_board_t *board; 19043412Snewton struct resource *ce_res; 191141486Sjhb struct resource *ce_irq; 19243412Snewton void *ce_intrhand; 193141486Sjhb ce_dma_mem_t dmamem; 194141486Sjhb drv_t channel [NCHAN]; 195141486Sjhb#if __FreeBSD_version >= 504000 196141486Sjhb struct mtx ce_mtx; 197141486Sjhb#endif 198141486Sjhb} bdrv_t; 19943412Snewton 20043412Snewtonstatic driver_t ce_driver = { 20143412Snewton "ce", 20283366Sjulian ce_methods, 20383366Sjulian sizeof(bdrv_t), 20443412Snewton}; 20543412Snewton 20643412Snewtonstatic devclass_t ce_devclass; 20743412Snewton 20843412Snewtonstatic void ce_receive (ce_chan_t *c, unsigned char *data, int len); 20943412Snewtonstatic void ce_transmit (ce_chan_t *c, void *attachment, int len); 21043412Snewtonstatic void ce_error (ce_chan_t *c, int data); 211107849Salfredstatic void ce_up (drv_t *d); 212107849Salfredstatic void ce_start (drv_t *d); 213107849Salfredstatic void ce_down (drv_t *d); 21483366Sjulianstatic void ce_watchdog (drv_t *d); 21543412Snewtonstatic void ce_watchdog_timer (void *arg); 21643412Snewton#ifdef NETGRAPH 21743412Snewtonextern struct ng_type typestruct; 21843412Snewton#else 21943412Snewtonstatic void ce_ifstart (struct ifnet *ifp); 22043412Snewtonstatic void ce_tlf (struct sppp *sp); 22143412Snewtonstatic void ce_tls (struct sppp *sp); 22254494Snewtonstatic int ce_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 22343412Snewtonstatic void ce_initialize (void *softc); 22454494Snewton#endif 22554494Snewton 22654494Snewtonstatic ce_board_t *adapter [NBRD]; 22743412Snewtonstatic drv_t *channel [NBRD*NCHAN]; 22843412Snewtonstatic struct callout led_timo [NBRD]; 22983366Sjulianstatic struct callout timeout_handle; 23083366Sjulian 23143412Snewtonstatic int ce_destroy = 0; 23243412Snewton 233193014Sdelphij#if __FreeBSD_version < 500000 23443412Snewtonstatic int ce_open (dev_t dev, int oflags, int devtype, struct proc *p); 23554494Snewtonstatic int ce_close (dev_t dev, int fflag, int devtype, struct proc *p); 23654494Snewtonstatic int ce_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p); 23754494Snewton#else 23854494Snewtonstatic int ce_open (struct cdev *dev, int oflags, int devtype, struct thread *td); 23943412Snewtonstatic int ce_close (struct cdev *dev, int fflag, int devtype, struct thread *td); 24043412Snewtonstatic int ce_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td); 24143412Snewton#endif 24254494Snewton#if __FreeBSD_version < 500000 24354494Snewtonstatic struct cdevsw ce_cdevsw = { 244160276Sjhb ce_open, ce_close, noread, nowrite, 24554494Snewton ce_ioctl, nopoll, nommap, nostrategy, 24654494Snewton "ce", CDEV_MAJOR, nodump, nopsize, 24743412Snewton D_NAGGED, -1 24854494Snewton }; 249107849Salfred#elif __FreeBSD_version == 500000 250224778Srwatsonstatic struct cdevsw ce_cdevsw = { 251224778Srwatson ce_open, ce_close, noread, nowrite, 25243412Snewton ce_ioctl, nopoll, nommap, nostrategy, 25354494Snewton "ce", CDEV_MAJOR, nodump, nopsize, 25443412Snewton D_NAGGED, 25589306Salfred }; 25689306Salfred#elif __FreeBSD_version <= 501000 25743412Snewtonstatic struct cdevsw ce_cdevsw = { 25889306Salfred .d_open = ce_open, 25943412Snewton .d_close = ce_close, 260116678Sphk .d_read = noread, 261160276Sjhb .d_write = nowrite, 26289306Salfred .d_ioctl = ce_ioctl, 263160276Sjhb .d_poll = nopoll, 26489306Salfred .d_mmap = nommap, 26543412Snewton .d_strategy = nostrategy, 26689306Salfred .d_name = "ce", 26743412Snewton .d_maj = CDEV_MAJOR, 268107849Salfred .d_dump = nodump, 26954494Snewton .d_flags = D_NAGGED, 27054494Snewton}; 27154494Snewton#elif __FreeBSD_version < 502103 27254494Snewtonstatic struct cdevsw ce_cdevsw = { 27354494Snewton .d_open = ce_open, 27454494Snewton .d_close = ce_close, 27554494Snewton .d_ioctl = ce_ioctl, 27654494Snewton .d_name = "ce", 27754494Snewton .d_maj = CDEV_MAJOR, 27854494Snewton .d_flags = D_NAGGED, 27954494Snewton}; 280111119Simp#elif __FreeBSD_version < 600000 281188588Sjhbstatic struct cdevsw ce_cdevsw = { 28243412Snewton .d_version = D_VERSION, 28343412Snewton .d_open = ce_open, 28443412Snewton .d_close = ce_close, 28543412Snewton .d_ioctl = ce_ioctl, 28643412Snewton .d_name = "ce", 28743412Snewton .d_maj = CDEV_MAJOR, 28843412Snewton .d_flags = D_NEEDGIANT, 28983366Sjulian}; 29043412Snewton#else /* __FreeBSD_version >= 600000 */ 29143412Snewtonstatic struct cdevsw ce_cdevsw = { 29243412Snewton .d_version = D_VERSION, 29354494Snewton .d_open = ce_open, 29454494Snewton .d_close = ce_close, 29554494Snewton .d_ioctl = ce_ioctl, 29654494Snewton .d_name = "ce", 29754494Snewton}; 298101709Srwatson#endif 299172930Srwatson 300101709Srwatson/* 301101924Srwatson * Make an mbuf from data. 302101709Srwatson */ 303101709Srwatsonstatic struct mbuf *makembuf (void *buf, unsigned len) 30454494Snewton{ 30554494Snewton struct mbuf *m; 30654494Snewton 30743412Snewton MGETHDR (m, M_NOWAIT, MT_DATA); 30854494Snewton if (! m) 30943412Snewton return 0; 31043412Snewton MCLGET (m, M_NOWAIT); 311107849Salfred if (! (m->m_flags & M_EXT)) { 31254494Snewton m_freem (m); 31354494Snewton return 0; 31443412Snewton } 31554494Snewton m->m_pkthdr.len = m->m_len = len; 31643412Snewton bcopy (buf, mtod (m, caddr_t), len); 31754494Snewton return m; 31854494Snewton} 31954494Snewton 32054494Snewtonstatic int ce_probe (device_t dev) 32154494Snewton{ 32254494Snewton if ((pci_get_vendor (dev) == TAU32_PCI_VENDOR_ID) && 32354494Snewton (pci_get_device (dev) == TAU32_PCI_DEVICE_ID)) { 32454494Snewton device_set_desc (dev, "Cronyx-Tau32-PCI serial adapter"); 32554494Snewton return BUS_PROBE_DEFAULT; 32654494Snewton } 32754494Snewton return ENXIO; 32854494Snewton} 32954494Snewton 33054494Snewtonstatic void ce_timeout (void *arg) 33154494Snewton{ 33254494Snewton drv_t *d; 33354494Snewton int s, i, k; 33454494Snewton 33554494Snewton for (i = 0; i < NBRD; ++i) { 33654494Snewton if (adapter[i] == NULL) 33754494Snewton continue; 33854494Snewton for (k = 0; k < NCHAN; ++k) { 33954494Snewton s = splimp (); 34043412Snewton if (ce_destroy) { 34154494Snewton splx (s); 34254494Snewton return; 34354494Snewton } 34454494Snewton d = channel[i * NCHAN + k]; 34554494Snewton if (!d) { 34654494Snewton splx (s); 34743412Snewton continue; 34854494Snewton } 34954494Snewton CE_LOCK ((bdrv_t *)d->board->sys); 35054494Snewton switch (d->chan->type) { 35154494Snewton case T_E1: 35254494Snewton ce_e1_timer (d->chan); 35354494Snewton break; 35454494Snewton default: 35543412Snewton break; 35643412Snewton } 35754494Snewton CE_UNLOCK ((bdrv_t *)d->board->sys); 35854494Snewton splx (s); 35943412Snewton } 36043412Snewton } 36143412Snewton s = splimp (); 36254494Snewton if (!ce_destroy) 36354494Snewton callout_reset (&timeout_handle, hz, ce_timeout, 0); 36454494Snewton splx (s); 36554494Snewton} 36654494Snewton 36754494Snewtonstatic void ce_led_off (void *arg) 36854494Snewton{ 36954494Snewton ce_board_t *b = arg; 37054494Snewton bdrv_t *bd = (bdrv_t *) b->sys; 37154494Snewton int s; 37254494Snewton s = splimp (); 373192994Sdelphij if (ce_destroy) { 37454494Snewton splx (s); 37543412Snewton return; 37643412Snewton } 37754494Snewton CE_LOCK (bd); 37854494Snewton TAU32_LedSet (b->ddk.pControllerObject, 0); 37954494Snewton CE_UNLOCK (bd); 38054494Snewton splx (s); 38154494Snewton} 38254494Snewton 38354494Snewtonstatic void ce_intr (void *arg) 38454494Snewton{ 38554494Snewton bdrv_t *bd = arg; 38654494Snewton ce_board_t *b = bd->board; 38754494Snewton int s; 38854494Snewton int i; 389107849Salfred#if __FreeBSD_version >= 500000 && defined NETGRAPH 39043412Snewton int error; 39154494Snewton#endif 39243412Snewton s = splimp (); 39354494Snewton if (ce_destroy) { 39454494Snewton splx (s); 39554494Snewton return; 39643412Snewton } 39783366Sjulian CE_LOCK (bd); 39843412Snewton /* Turn LED on. */ 399175294Sattilio TAU32_LedSet (b->ddk.pControllerObject, 1); 400160276Sjhb 40189306Salfred TAU32_HandleInterrupt (b->ddk.pControllerObject); 40254494Snewton 40354494Snewton /* Turn LED off 50 msec later. */ 40443412Snewton callout_reset (&led_timo[b->num], hz/20, ce_led_off, b); 40543412Snewton CE_UNLOCK (bd); 40643412Snewton splx (s); 40743412Snewton 40843412Snewton /* Pass packets in a lock-free state */ 40943412Snewton for (i = 0; i < NCHAN && b->chan[i].type; i++) { 41083366Sjulian drv_t *d = b->chan[i].sys; 41183366Sjulian struct mbuf *m; 41243412Snewton if (!d || !d->running) 41343412Snewton continue; 41443412Snewton while (_IF_QLEN(&d->rqueue)) { 41543412Snewton IF_DEQUEUE (&d->rqueue,m); 41643412Snewton if (!m) 41743412Snewton continue; 41843412Snewton#ifdef NETGRAPH 41943412Snewton if (d->hook) { 42043412Snewton#if __FreeBSD_version >= 500000 42143412Snewton NG_SEND_DATA_ONLY (error, d->hook, m); 42243412Snewton#else 42343412Snewton ng_queue_data (d->hook, m, 0); 42443412Snewton#endif 425160276Sjhb } else { 42643412Snewton IF_DRAIN (&d->rqueue); 42783366Sjulian } 42843412Snewton#else 429121275Stjr sppp_input (d->ifp, m); 430121275Stjr#endif 431121275Stjr } 432224778Srwatson } 433224778Srwatson} 43443412Snewton 43543412Snewton#if __FreeBSD_version >= 500000 43689306Salfredstatic void 43789306Salfredce_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) 43843412Snewton{ 43989306Salfred unsigned long *addr; 44043412Snewton 441116678Sphk if (error) 442160276Sjhb return; 44389306Salfred 444160276Sjhb KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 44589306Salfred addr = arg; 44643412Snewton *addr = segs->ds_addr; 44789306Salfred} 44843412Snewton 449107849Salfred#ifndef BUS_DMA_ZERO 450111119Simp#define BUS_DMA_ZERO 0 451188588Sjhb#endif 45243412Snewton 45343412Snewtonstatic int 45443412Snewtonce_bus_dma_mem_alloc (int bnum, int cnum, ce_dma_mem_t *dmem) 45543412Snewton{ 45643412Snewton int error; 45743412Snewton 45843412Snewton error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT, 45943412Snewton BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1, 46083366Sjulian dmem->size, 0, 46143412Snewton#if __FreeBSD_version >= 502000 46243412Snewton NULL, NULL, 463101709Srwatson#endif 464101709Srwatson &dmem->dmat); 465172930Srwatson if (error) { 466101709Srwatson if (cnum >= 0) printf ("ce%d-%d: ", bnum, cnum); 467101709Srwatson else printf ("ce%d: ", bnum); 468101709Srwatson printf ("couldn't allocate tag for dma memory\n"); 469101709Srwatson return 0; 47043412Snewton } 47143412Snewton error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt, 47243412Snewton BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp); 47343412Snewton if (error) { 47443412Snewton if (cnum >= 0) printf ("ce%d-%d: ", bnum, cnum); 47543412Snewton else printf ("ce%d: ", bnum); 47689306Salfred printf ("couldn't allocate mem for dma memory\n"); 47743412Snewton bus_dma_tag_destroy (dmem->dmat); 47889306Salfred return 0; 47943412Snewton } 48043412Snewton error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt, 481107849Salfred dmem->size, ce_bus_dmamap_addr, &dmem->phys, 0); 482107849Salfred if (error) { 48343412Snewton if (cnum >= 0) printf ("ce%d-%d: ", bnum, cnum); 48443412Snewton else printf ("ce%d: ", bnum); 48543412Snewton printf ("couldn't load mem map for dma memory\n"); 48643412Snewton bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); 48743412Snewton bus_dma_tag_destroy (dmem->dmat); 48843412Snewton return 0; 48943412Snewton } 49054494Snewton#if __FreeBSD_version >= 502000 491193013Sdelphij bzero (dmem->virt, dmem->size); 492193013Sdelphij#endif 493193013Sdelphij return 1; 494193013Sdelphij} 49543412Snewton 49654494Snewtonstatic void 49743412Snewtonce_bus_dma_mem_free (ce_dma_mem_t *dmem) 49843412Snewton{ 49943412Snewton bus_dmamap_unload (dmem->dmat, dmem->mapp); 50043412Snewton bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); 50143412Snewton bus_dma_tag_destroy (dmem->dmat); 50243412Snewton} 50343412Snewton#else 50443412Snewtonstatic int 50543412Snewtonce_bus_dma_mem_alloc (int bnum, int cnum, ce_dma_mem_t *dmem) 50643412Snewton{ 50743412Snewton dmem->virt = contigmalloc (dmem->size, M_DEVBUF, M_WAITOK, 50843412Snewton 0x100000, 0xffffffff, 16, 0); 50943412Snewton if (dmem->virt == NULL) { 51043412Snewton if (cnum >= 0) printf ("ce%d-%d: ", bnum, cnum); 51143412Snewton else printf ("ce%d: ", bnum); 51243412Snewton printf ("couldn't allocate dma memory\n"); 51343412Snewton return 0; 51443412Snewton } 51543412Snewton dmem->phys = vtophys (dmem->virt); 51643412Snewton bzero (dmem->virt, dmem->size); 51743412Snewton return 1; 518192994Sdelphij} 51943412Snewton 52043412Snewtonstatic void 52143412Snewtonce_bus_dma_mem_free (ce_dma_mem_t *dmem) 52243412Snewton{ 52343412Snewton contigfree (dmem->virt, dmem->size, M_DEVBUF); 52443412Snewton} 52543412Snewton#endif 52643412Snewton 52743412Snewton/* 52843412Snewton * Called if the probe succeeded. 529107849Salfred */ 53043412Snewtonstatic int ce_attach (device_t dev) 53143412Snewton{ 53243412Snewton bdrv_t *bd = device_get_softc (dev); 53343412Snewton int unit = device_get_unit (dev); 534107849Salfred#if __FreeBSD_version >= 504000 53543412Snewton char *ce_ln = CE_LOCK_NAME; 536175294Sattilio#endif 537160276Sjhb vm_offset_t vbase; 53889306Salfred int rid, error; 53943412Snewton ce_board_t *b; 54043412Snewton ce_chan_t *c; 54143412Snewton drv_t *d; 54243412Snewton int s; 54343412Snewton 54443412Snewton b = malloc (sizeof(ce_board_t), M_DEVBUF, M_WAITOK); 54543412Snewton if (!b) { 54643412Snewton printf ("ce%d: couldn't allocate memory\n", unit); 54783366Sjulian return (ENXIO); 54883366Sjulian } 54943412Snewton bzero (b, sizeof(ce_board_t)); 55043412Snewton 55143412Snewton b->ddk.sys = &b; 55243412Snewton 55343412Snewton#if __FreeBSD_version >= 440000 55483366Sjulian pci_enable_busmaster (dev); 55543412Snewton#endif 55643412Snewton 55743412Snewton bd->dmamem.size = TAU32_ControllerObjectSize; 55843412Snewton if (! ce_bus_dma_mem_alloc (unit, -1, &bd->dmamem)) { 559107849Salfred free (b, M_DEVBUF); 56043412Snewton return (ENXIO); 56143412Snewton } 562107849Salfred b->ddk.pControllerObject = bd->dmamem.virt; 56343412Snewton 56443412Snewton bd->board = b; 565107849Salfred b->sys = bd; 566107849Salfred rid = PCIR_BAR(0); 567107849Salfred bd->ce_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid, 568107849Salfred 0, ~0, 1, RF_ACTIVE); 569107849Salfred if (! bd->ce_res) { 570107849Salfred printf ("ce%d: cannot map memory\n", unit); 57143412Snewton ce_bus_dma_mem_free (&bd->dmamem); 572225617Skmacy free (b, M_DEVBUF); 57343412Snewton return (ENXIO); 57443412Snewton } 57543412Snewton vbase = (vm_offset_t) rman_get_virtual (bd->ce_res); 57683366Sjulian 57783366Sjulian b->ddk.PciBar1VirtualAddress = (void *)vbase; 57843412Snewton b->ddk.ControllerObjectPhysicalAddress = bd->dmamem.phys; 57943412Snewton b->ddk.pErrorNotifyCallback = ce_error_callback; 58043412Snewton b->ddk.pStatusNotifyCallback = ce_status_callback; 58143412Snewton b->num = unit; 58243412Snewton 58343412Snewton TAU32_BeforeReset(&b->ddk); 58443412Snewton pci_write_config (dev, TAU32_PCI_RESET_ADDRESS, TAU32_PCI_RESET_ON, 4); 58543412Snewton pci_write_config (dev, TAU32_PCI_RESET_ADDRESS, TAU32_PCI_RESET_OFF, 4); 58643412Snewton 587107849Salfred if(!TAU32_Initialize(&b->ddk, 0)) 58843412Snewton { 58943412Snewton printf ("ce%d: init adapter error 0x%08x, bus dead bits 0x%08lx\n", 590107849Salfred unit, b->ddk.InitErrors, b->ddk.DeadBits); 59143412Snewton bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->ce_res); 59243412Snewton ce_bus_dma_mem_free (&bd->dmamem); 593107849Salfred free (b, M_DEVBUF); 594107849Salfred return (ENXIO); 595107849Salfred } 596107849Salfred 597107849Salfred s = splimp (); 598107849Salfred 59943412Snewton ce_init_board (b); 60084783Sps 601107849Salfred rid = 0; 602107849Salfred bd->ce_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 603107849Salfred RF_SHAREABLE | RF_ACTIVE); 60443412Snewton if (! bd->ce_irq) { 605225617Skmacy printf ("ce%d: cannot map interrupt\n", unit); 60643412Snewton bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->ce_res); 60743412Snewton ce_bus_dma_mem_free (&bd->dmamem); 60843412Snewton free (b, M_DEVBUF); 60943412Snewton splx (s); 61083366Sjulian return (ENXIO); 61183366Sjulian } 61243412Snewton#if __FreeBSD_version >= 500000 61343412Snewton callout_init (&led_timo[unit], CALLOUT_MPSAFE); 61483366Sjulian#else 615160557Sjhb callout_init (&led_timo[unit]); 61643412Snewton#endif 617160557Sjhb error = bus_setup_intr (dev, bd->ce_irq, 61843412Snewton#if __FreeBSD_version >= 500013 619170587Srwatson INTR_TYPE_NET|INTR_MPSAFE, 62043412Snewton#else 621224778Srwatson INTR_TYPE_NET, 622224778Srwatson#endif 62343412Snewton NULL, ce_intr, bd, &bd->ce_intrhand); 624116678Sphk if (error) { 625160557Sjhb printf ("ce%d: cannot set up irq\n", unit); 626160557Sjhb bus_release_resource (dev, SYS_RES_IRQ, 0, bd->ce_irq); 627160557Sjhb bus_release_resource (dev, SYS_RES_MEMORY, 628175202Sattilio PCIR_BAR(0), bd->ce_res); 629160557Sjhb ce_bus_dma_mem_free (&bd->dmamem); 630160557Sjhb free (b, M_DEVBUF); 631160557Sjhb splx (s); 632160557Sjhb return (ENXIO); 633172930Srwatson } 634160557Sjhb 635160557Sjhb switch (b->ddk.Model) { 636160557Sjhb case 1: strcpy (b->name, TAU32_BASE_NAME); break; 637175294Sattilio case 2: strcpy (b->name, TAU32_LITE_NAME); break; 638160557Sjhb case 3: strcpy (b->name, TAU32_ADPCM_NAME); break; 639160557Sjhb default: strcpy (b->name, TAU32_UNKNOWN_NAME); break; 640160557Sjhb } 641160557Sjhb 642160557Sjhb printf ("ce%d: %s\n", unit, b->name); 643160557Sjhb 644160557Sjhb for (c = b->chan; c < b->chan + NCHAN; ++c) { 645160557Sjhb c->num = (c - b->chan); 64643412Snewton c->board = b; 64743412Snewton 64843412Snewton d = &bd->channel[c->num]; 64943412Snewton d->dmamem.size = sizeof(ce_buf_t); 65083366Sjulian if (! ce_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) 65183366Sjulian continue; 65243412Snewton 65343412Snewton channel [b->num * NCHAN + c->num] = d; 65443412Snewton sprintf (d->name, "ce%d.%d", b->num, c->num); 65543412Snewton d->board = b; 65643412Snewton d->chan = c; 657141486Sjhb c->sys = d; 658141486Sjhb } 65943412Snewton 660141486Sjhb for (c = b->chan; c < b->chan + NCHAN; ++c) { 66143412Snewton if (c->sys == NULL) 662141486Sjhb continue; 663141486Sjhb d = c->sys; 664141486Sjhb 665141486Sjhb callout_init (&d->timeout_handle, CALLOUT_MPSAFE); 666141486Sjhb#ifdef NETGRAPH 667141486Sjhb if (ng_make_node_common (&typestruct, &d->node) != 0) { 66843412Snewton printf ("%s: cannot make common node\n", d->name); 66943412Snewton d->node = NULL; 67043412Snewton continue; 67143412Snewton } 67283366Sjulian#if __FreeBSD_version >= 500000 673193014Sdelphij NG_NODE_SET_PRIVATE (d->node, d); 67443412Snewton#else 67543412Snewton d->node->private = d; 67683366Sjulian#endif 67783366Sjulian sprintf (d->nodename, "%s%d", NG_CE_NODE_TYPE, 678107849Salfred c->board->num * NCHAN + c->num); 679107849Salfred if (ng_name_node (d->node, d->nodename)) { 68043412Snewton printf ("%s: cannot name node\n", d->nodename); 68143412Snewton#if __FreeBSD_version >= 500000 68243412Snewton NG_NODE_UNREF (d->node); 68343412Snewton#else 68483366Sjulian ng_rmnode (d->node); 68583366Sjulian ng_unref (d->node); 68643412Snewton#endif 68743412Snewton continue; 68883366Sjulian } 68983366Sjulian d->queue.ifq_maxlen = ifqmaxlen; 690107849Salfred d->hi_queue.ifq_maxlen = ifqmaxlen; 691107849Salfred d->rqueue.ifq_maxlen = ifqmaxlen; 69243412Snewton#if __FreeBSD_version >= 500000 69343412Snewton mtx_init (&d->queue.ifq_mtx, "ce_queue", NULL, MTX_DEF); 69443412Snewton mtx_init (&d->hi_queue.ifq_mtx, "ce_queue_hi", NULL, MTX_DEF); 69543412Snewton mtx_init (&d->rqueue.ifq_mtx, "ce_rqueue", NULL, MTX_DEF); 69683366Sjulian#endif 69783366Sjulian#else /*NETGRAPH*/ 69843412Snewton#if __FreeBSD_version >= 600031 69943412Snewton d->ifp = if_alloc(IFT_PPP); 70043412Snewton#else 70143412Snewton d->ifp = malloc (sizeof(struct sppp), M_DEVBUF, M_WAITOK); 70243412Snewton bzero (d->ifp, sizeof(struct sppp)); 70343412Snewton#endif 70443412Snewton if (!d->ifp) { 70583366Sjulian printf ("%s: cannot if_alloc() interface\n", d->name); 70683366Sjulian continue; 70743412Snewton } 70843412Snewton d->ifp->if_softc = d; 70943412Snewton#if __FreeBSD_version > 501000 71043412Snewton if_initname (d->ifp, "ce", b->num * NCHAN + c->num); 71183366Sjulian#else 71243412Snewton d->ifp->if_unit = b->num * NCHAN + c->num; 713107849Salfred d->ifp->if_name = "ce"; 71443412Snewton#endif 715202143Sbrooks d->ifp->if_mtu = PP_MTU; 71643412Snewton d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 71743412Snewton d->ifp->if_ioctl = ce_sioctl; 71843412Snewton d->ifp->if_start = ce_ifstart; 71943412Snewton d->ifp->if_init = ce_initialize; 72043412Snewton d->rqueue.ifq_maxlen = ifqmaxlen; 72143412Snewton#if __FreeBSD_version >= 500000 72243412Snewton mtx_init (&d->rqueue.ifq_mtx, "ce_rqueue", NULL, MTX_DEF); 72343412Snewton#endif 72443412Snewton sppp_attach (d->ifp); 72543412Snewton if_attach (d->ifp); 72643412Snewton IFP2SP(d->ifp)->pp_tlf = ce_tlf; 72743412Snewton IFP2SP(d->ifp)->pp_tls = ce_tls; 72843412Snewton /* If BPF is in the kernel, call the attach for it. 72943412Snewton * The header size of PPP or Cisco/HDLC is 4 bytes. */ 73043412Snewton bpfattach (d->ifp, DLT_PPP, 4); 73143412Snewton#endif /*NETGRAPH*/ 73243412Snewton ce_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys); 73343412Snewton 73443412Snewton /* Register callback functions. */ 73543412Snewton ce_register_transmit (c, &ce_transmit); 73643412Snewton ce_register_receive (c, &ce_receive); 73743412Snewton ce_register_error (c, &ce_error); 73843412Snewton d->devt = make_dev (&ce_cdevsw, b->num*NCHAN+c->num, UID_ROOT, 73943412Snewton GID_WHEEL, 0600, "ce%d", b->num*NCHAN+c->num); 74043412Snewton } 74143412Snewton 74243412Snewton#if __FreeBSD_version >= 504000 74343412Snewton ce_ln[2] = '0' + unit; 74443412Snewton mtx_init (&bd->ce_mtx, ce_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE); 74543412Snewton#endif 74643412Snewton CE_LOCK (bd); 74743412Snewton TAU32_EnableInterrupts(b->ddk.pControllerObject); 74843412Snewton adapter[unit] = b; 74943412Snewton CE_UNLOCK (bd); 75043412Snewton splx (s); 75143412Snewton 75243412Snewton return 0; 75343412Snewton} 75443412Snewton 75543412Snewtonstatic int ce_detach (device_t dev) 75643412Snewton{ 75743412Snewton bdrv_t *bd = device_get_softc (dev); 75843412Snewton ce_board_t *b = bd->board; 75943412Snewton ce_chan_t *c; 76043412Snewton int s; 76143412Snewton 76243412Snewton#if __FreeBSD_version >= 504000 76343412Snewton KASSERT (mtx_initialized (&bd->ce_mtx), ("ce mutex not initialized")); 76443412Snewton#endif 76543412Snewton s = splimp (); 76643412Snewton CE_LOCK (bd); 76743412Snewton /* Check if the device is busy (open). */ 76843412Snewton for (c = b->chan; c < b->chan + NCHAN; ++c) { 76943412Snewton drv_t *d = (drv_t*) c->sys; 77043412Snewton 77143412Snewton /* XXX Non existen chan! */ 77243412Snewton if (! d || ! d->chan) 77343412Snewton continue; 77443412Snewton if (d->running) { 77543412Snewton CE_UNLOCK (bd); 77643412Snewton splx (s); 77743412Snewton return EBUSY; 77843412Snewton } 77943412Snewton } 78043412Snewton 78143412Snewton /* Ok, we can unload driver */ 782170170Sattilio /* At first we should disable interrupts */ 78343412Snewton ce_destroy = 1; 78443412Snewton TAU32_DisableInterrupts(b->ddk.pControllerObject); 78543412Snewton 78643412Snewton callout_stop (&led_timo[b->num]); 78743412Snewton 78843412Snewton for (c = b->chan; c < b->chan + NCHAN; ++c) { 789170170Sattilio drv_t *d = (drv_t*) c->sys; 79043412Snewton 79143412Snewton if (! d || ! d->chan) 79243412Snewton continue; 793193012Sdelphij callout_stop (&d->timeout_handle); 794193012Sdelphij#ifndef NETGRAPH 795193012Sdelphij /* Detach from the packet filter list of interfaces. */ 796193012Sdelphij bpfdetach (d->ifp); 797193012Sdelphij 798193012Sdelphij /* Detach from the sync PPP list. */ 799193012Sdelphij sppp_detach (d->ifp); 800193012Sdelphij 801193012Sdelphij /* Detach from the system list of interfaces. */ 802193012Sdelphij if_detach (d->ifp); 803193012Sdelphij#if __FreeBSD_version > 600031 804193012Sdelphij if_free(d->ifp); 805193012Sdelphij#else 806193012Sdelphij free (d->ifp, M_DEVBUF); 807193012Sdelphij#endif 808193012Sdelphij 809193012Sdelphij IF_DRAIN (&d->rqueue); 810193012Sdelphij#if __FreeBSD_version >= 500000 811193012Sdelphij mtx_destroy (&d->rqueue.ifq_mtx); 812193012Sdelphij#endif 813193012Sdelphij#else 814193012Sdelphij#if __FreeBSD_version >= 500000 815193012Sdelphij if (d->node) { 816193012Sdelphij ng_rmnode_self (d->node); 817193012Sdelphij NG_NODE_UNREF (d->node); 818193012Sdelphij d->node = NULL; 819193012Sdelphij } 820193012Sdelphij IF_DRAIN (&d->rqueue); 821193012Sdelphij mtx_destroy (&d->queue.ifq_mtx); 822193012Sdelphij mtx_destroy (&d->hi_queue.ifq_mtx); 823193012Sdelphij mtx_destroy (&d->rqueue.ifq_mtx); 824193012Sdelphij#else 825193012Sdelphij ng_rmnode (d->node); 826193012Sdelphij d->node = 0; 827193012Sdelphij#endif 828193012Sdelphij#endif 829193012Sdelphij destroy_dev (d->devt); 830193012Sdelphij } 831193012Sdelphij 83243412Snewton CE_UNLOCK (bd); 83343412Snewton splx (s); 83443412Snewton 83543412Snewton callout_drain (&led_timo[b->num]); 83643412Snewton 83743412Snewton /* Disable the interrupt request. */ 83843412Snewton bus_teardown_intr (dev, bd->ce_irq, bd->ce_intrhand); 83943412Snewton bus_release_resource (dev, SYS_RES_IRQ, 0, bd->ce_irq); 84083366Sjulian TAU32_DestructiveHalt (b->ddk.pControllerObject, 0); 84183366Sjulian bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->ce_res); 84243412Snewton 84343412Snewton for (c = b->chan; c < b->chan + NCHAN; ++c) { 844159960Sjhb drv_t *d = (drv_t*) c->sys; 84543412Snewton 846159960Sjhb if (! d || ! d->chan) 847225617Skmacy continue; 84843412Snewton callout_drain (&d->timeout_handle); 84943412Snewton channel [b->num * NCHAN + c->num] = 0; 85043412Snewton /* Deallocate buffers. */ 85143412Snewton ce_bus_dma_mem_free (&d->dmamem); 85243412Snewton } 85343412Snewton adapter [b->num] = 0; 85443412Snewton ce_bus_dma_mem_free (&bd->dmamem); 85543412Snewton free (b, M_DEVBUF); 85643412Snewton#if __FreeBSD_version >= 504000 85743412Snewton mtx_destroy (&bd->ce_mtx); 85843412Snewton#endif 85983366Sjulian return 0; 86083366Sjulian} 86143412Snewton 86243412Snewton#ifndef NETGRAPH 863136152Sjhbstatic void ce_ifstart (struct ifnet *ifp) 864136152Sjhb{ 865136152Sjhb drv_t *d = ifp->if_softc; 866136152Sjhb bdrv_t *bd = d->board->sys; 86743412Snewton 868136152Sjhb CE_LOCK (bd); 869136152Sjhb ce_start (d); 870170472Sattilio CE_UNLOCK (bd); 871136152Sjhb} 872170472Sattilio 873136152Sjhbstatic void ce_tlf (struct sppp *sp) 874136152Sjhb{ 87543412Snewton drv_t *d = SP2IFP(sp)->if_softc; 876136152Sjhb 877136152Sjhb CE_DEBUG2 (d, ("ce_tlf\n")); 87843412Snewton sp->pp_down (sp); 879136152Sjhb} 880136152Sjhb 88143412Snewtonstatic void ce_tls (struct sppp *sp) 882136152Sjhb{ 88343412Snewton drv_t *d = SP2IFP(sp)->if_softc; 884136152Sjhb 88543412Snewton CE_DEBUG2 (d, ("ce_tls\n")); 886136152Sjhb sp->pp_up (sp); 887136152Sjhb} 888136152Sjhb 88943412Snewton/* 89043412Snewton * Process an ioctl request. 89143412Snewton */ 89243412Snewtonstatic int ce_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 89383366Sjulian{ 89483366Sjulian drv_t *d = ifp->if_softc; 89543412Snewton bdrv_t *bd = d->board->sys; 89643412Snewton int error, s, was_up, should_be_up; 89783366Sjulian 898125454Sjhb#if __FreeBSD_version >= 600034 89943412Snewton was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 900107849Salfred#else 90143412Snewton was_up = (ifp->if_flags & IFF_RUNNING) != 0; 902125454Sjhb#endif 903125454Sjhb error = sppp_ioctl (ifp, cmd, data); 904125454Sjhb 90543412Snewton if (error) 90643412Snewton return error; 90743412Snewton 90843412Snewton if (! (ifp->if_flags & IFF_DEBUG)) 90943412Snewton d->chan->debug = 0; 91043412Snewton else 91143412Snewton d->chan->debug = d->chan->debug_shadow; 91243412Snewton 913107849Salfred switch (cmd) { 914125454Sjhb default: CE_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; 915125454Sjhb case SIOCADDMULTI: CE_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0; 916125454Sjhb case SIOCDELMULTI: CE_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0; 91743412Snewton case SIOCSIFFLAGS: CE_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break; 918125454Sjhb case SIOCSIFADDR: CE_DEBUG2 (d, ("ioctl SIOCSIFADDR\n")); break; 91943412Snewton } 92043412Snewton 92143412Snewton /* We get here only in case of SIFFLAGS or SIFADDR. */ 922125454Sjhb s = splimp (); 923125454Sjhb CE_LOCK (bd); 924125454Sjhb#if __FreeBSD_version >= 600034 92543412Snewton should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 92643412Snewton#else 92743412Snewton should_be_up = (ifp->if_flags & IFF_RUNNING) != 0; 92843412Snewton#endif 92943412Snewton if (! was_up && should_be_up) { 93043412Snewton /* Interface goes up -- start it. */ 93143412Snewton ce_up (d); 93283366Sjulian ce_start (d); 93371452Sjhb } else if (was_up && ! should_be_up) { 93443412Snewton /* Interface is going down -- stop it. */ 935125454Sjhb/* if ((IFP2SP(ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ 936125454Sjhb ce_down (d); 937125454Sjhb } 93871452Sjhb CE_DEBUG (d, ("ioctl 0x%lx p4\n", cmd)); 93943412Snewton CE_UNLOCK (bd); 94043412Snewton splx (s); 94143412Snewton return 0; 94243412Snewton} 94343412Snewton 94443412Snewton/* 94543412Snewton * Initialization of interface. 94643412Snewton * It seems to be never called by upper level? 94743412Snewton */ 94843412Snewtonstatic void ce_initialize (void *softc) 949125454Sjhb{ 950125454Sjhb drv_t *d = softc; 951125454Sjhb 95243412Snewton CE_DEBUG (d, ("ce_initialize\n")); 95343412Snewton} 95443412Snewton#endif /*NETGRAPH*/ 95543412Snewton 95643412Snewton/* 95743412Snewton * Stop the interface. Called on splimp(). 95843412Snewton */ 95943412Snewtonstatic void ce_down (drv_t *d) 96043412Snewton{ 96143412Snewton CE_DEBUG (d, ("ce_down\n")); 96243412Snewton /* Interface is going down -- stop it. */ 96343412Snewton ce_set_dtr (d->chan, 0); 96443412Snewton ce_set_rts (d->chan, 0); 96543412Snewton 96643412Snewton d->running = 0; 96743412Snewton callout_stop (&d->timeout_handle); 96871452Sjhb} 96971452Sjhb 97071452Sjhb/* 97143412Snewton * Start the interface. Called on splimp(). 97269947Sjake */ 97343412Snewtonstatic void ce_up (drv_t *d) 97443412Snewton{ 97543412Snewton CE_DEBUG (d, ("ce_up\n")); 97643412Snewton ce_set_dtr (d->chan, 1); 97783366Sjulian ce_set_rts (d->chan, 1); 97883366Sjulian 97943412Snewton d->running = 1; 98043412Snewton} 98183366Sjulian 98283366Sjulian/* 98343412Snewton * Start output on the interface. Get another datagram to send 984107849Salfred * off of the interface queue, and copy it to the interface 98543412Snewton * before starting the output. 98643412Snewton */ 98743412Snewtonstatic void ce_send (drv_t *d) 98843412Snewton{ 98943412Snewton struct mbuf *m; 99043412Snewton u_short len; 99143412Snewton 99243412Snewton CE_DEBUG2 (d, ("ce_send\n")); 993225617Skmacy 99443412Snewton /* No output if the interface is down. */ 99543412Snewton if (! d->running) 99643412Snewton return; 99791140Stanimura 99843412Snewton while (ce_transmit_space (d->chan)) { 99991140Stanimura /* Get the packet to send. */ 100043412Snewton#ifdef NETGRAPH 100143412Snewton IF_DEQUEUE (&d->hi_queue, m); 100243412Snewton if (! m) 1003107849Salfred IF_DEQUEUE (&d->queue, m); 100489545Stanimura#else 1005107849Salfred m = sppp_dequeue (d->ifp); 100643412Snewton#endif 100743412Snewton if (! m) 100843412Snewton return; 100943412Snewton#ifndef NETGRAPH 101043412Snewton#if __FreeBSD_version >= 500000 101189541Stanimura BPF_MTAP (d->ifp, m); 101275893Sjhb#else 101343412Snewton if (d->ifp->if_bpf) 101443412Snewton bpf_mtap (d->ifp, m); 101543412Snewton#endif 1016225617Skmacy#endif 101743412Snewton#if __FreeBSD_version >= 490000 101843412Snewton len = m_length (m, NULL); 101943412Snewton#else 1020107849Salfred len = m->m_pkthdr.len; 102189545Stanimura#endif 1022107849Salfred if (len >= BUFSZ) 102343412Snewton printf ("%s: too long packet: %d bytes: ", 102443412Snewton d->name, len); 102543412Snewton else if (! m->m_next) 102675893Sjhb ce_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); 102743412Snewton else { 102843412Snewton ce_buf_item_t *item = (ce_buf_item_t*)d->chan->tx_queue; 102943412Snewton m_copydata (m, 0, len, item->buf); 103043412Snewton ce_send_packet (d->chan, item->buf, len, 0); 103143412Snewton } 103243412Snewton m_freem (m); 1033107849Salfred /* Set up transmit timeout, if the transmit ring is not empty.*/ 1034107849Salfred d->timeout = 10; 1035225617Skmacy } 103643412Snewton#ifndef NETGRAPH 103743412Snewton#if __FreeBSD_version >= 600034 103843412Snewton d->ifp->if_flags |= IFF_DRV_OACTIVE; 103943412Snewton#else 104043412Snewton d->ifp->if_flags |= IFF_OACTIVE; 104143412Snewton#endif 104243412Snewton#endif 104343412Snewton} 104443412Snewton 104543412Snewton/* 104643412Snewton * Start output on the interface. 104743412Snewton * Always called on splimp(). 104843412Snewton */ 104943412Snewtonstatic void ce_start (drv_t *d) 105043412Snewton{ 105143412Snewton if (d->running) { 105243412Snewton if (! d->chan->dtr) 105383366Sjulian ce_set_dtr (d->chan, 1); 105483366Sjulian if (! d->chan->rts) 105543412Snewton ce_set_rts (d->chan, 1); 105643412Snewton ce_send (d); 105743412Snewton callout_reset (&d->timeout_handle, hz, ce_watchdog_timer, d); 1058107849Salfred } 105943412Snewton} 106043412Snewton 106143412Snewton/* 106243412Snewton * Handle transmit timeouts. 106343412Snewton * Recover after lost transmit interrupts. 106443412Snewton * Always called on splimp(). 106543412Snewton */ 106643412Snewtonstatic void ce_watchdog (drv_t *d) 106743412Snewton{ 106843412Snewton CE_DEBUG (d, ("device timeout\n")); 1069107849Salfred if (d->running) { 1070107849Salfred ce_set_dtr (d->chan, 0); 107143412Snewton ce_set_rts (d->chan, 0); 107243412Snewton/* ce_stop_chan (d->chan);*/ 1073107849Salfred/* ce_start_chan (d->chan, 1, 1, 0, 0);*/ 107443412Snewton ce_set_dtr (d->chan, 1); 107543412Snewton ce_set_rts (d->chan, 1); 107643412Snewton ce_start (d); 107743412Snewton } 107843412Snewton} 107943412Snewton 108043412Snewtonstatic void ce_watchdog_timer (void *arg) 1081107849Salfred{ 108243412Snewton drv_t *d = arg; 108343412Snewton bdrv_t *bd = d->board->sys; 108443412Snewton 108543412Snewton CE_LOCK(bd); 108643412Snewton if (d->timeout == 1) 108743412Snewton ce_watchdog (d); 108843412Snewton if (d->timeout) 108943412Snewton d->timeout--; 109043412Snewton callout_reset (&d->timeout_handle, hz, ce_watchdog_timer, d); 109143412Snewton CE_UNLOCK(bd); 1092107849Salfred} 109343412Snewton 109443412Snewtonstatic void ce_transmit (ce_chan_t *c, void *attachment, int len) 109543412Snewton{ 109643412Snewton drv_t *d = c->sys; 109743412Snewton 109843412Snewton d->timeout = 0; 109983366Sjulian#ifndef NETGRAPH 110083366Sjulian ++d->ifp->if_opackets; 110143412Snewton#if __FreeBSD_version >= 600034 110243412Snewton d->ifp->if_flags &= ~IFF_DRV_OACTIVE; 110383366Sjulian#else 110443412Snewton d->ifp->if_flags &= ~IFF_OACTIVE; 1105107849Salfred#endif 110643412Snewton#endif 110783366Sjulian ce_start (d); 110843412Snewton} 110943412Snewton 111043412Snewtonstatic void ce_receive (ce_chan_t *c, unsigned char *data, int len) 111143412Snewton{ 111243412Snewton drv_t *d = c->sys; 111343412Snewton struct mbuf *m; 111443412Snewton 111543412Snewton if (! d->running) 111643412Snewton return; 111743412Snewton 111843412Snewton m = makembuf (data, len); 111943412Snewton if (! m) { 112043412Snewton CE_DEBUG (d, ("no memory for packet\n")); 112143412Snewton#ifndef NETGRAPH 112243412Snewton ++d->ifp->if_iqdrops; 1123107849Salfred#endif 112443412Snewton return; 112543412Snewton } 112643412Snewton if (c->debug > 1) 112743412Snewton m_print (m, 0); 112843412Snewton#ifdef NETGRAPH 112943412Snewton m->m_pkthdr.rcvif = 0; 1130160510Sjhb IF_ENQUEUE(&d->rqueue, m); 1131160510Sjhb#else 1132160510Sjhb ++d->ifp->if_ipackets; 113343412Snewton m->m_pkthdr.rcvif = d->ifp; 113443412Snewton /* Check if there's a BPF listener on this interface. 113543412Snewton * If so, hand off the raw packet to bpf. */ 113643412Snewton#if __FreeBSD_version >= 500000 113743412Snewton BPF_TAP (d->ifp, data, len); 113843412Snewton#else 113943412Snewton if (d->ifp->if_bpf) 114043412Snewton bpf_tap (d->ifp, data, len); 1141151463Sdavidxu#endif 1142151463Sdavidxu IF_ENQUEUE(&d->rqueue, m); 114343412Snewton#endif 1144160510Sjhb} 1145160510Sjhb 1146160510Sjhbstatic void ce_error (ce_chan_t *c, int data) 1147160510Sjhb{ 114843412Snewton drv_t *d = c->sys; 114943412Snewton 115043412Snewton switch (data) { 1151151463Sdavidxu case CE_FRAME: 1152151463Sdavidxu CE_DEBUG (d, ("frame error\n")); 115343412Snewton#ifndef NETGRAPH 115443412Snewton ++d->ifp->if_ierrors; 115543412Snewton#endif 1156151463Sdavidxu break; 115743412Snewton case CE_CRC: 1158151463Sdavidxu CE_DEBUG (d, ("crc error\n")); 1159151463Sdavidxu#ifndef NETGRAPH 116043412Snewton ++d->ifp->if_ierrors; 1161151463Sdavidxu#endif 116243412Snewton break; 116343412Snewton case CE_OVERRUN: 116443412Snewton CE_DEBUG (d, ("overrun error\n")); 1165151463Sdavidxu#ifndef NETGRAPH 116643412Snewton ++d->ifp->if_collisions; 116743412Snewton ++d->ifp->if_ierrors; 1168151463Sdavidxu#endif 116943412Snewton break; 1170151463Sdavidxu case CE_OVERFLOW: 117143412Snewton CE_DEBUG (d, ("overflow error\n")); 117243412Snewton#ifndef NETGRAPH 117343412Snewton ++d->ifp->if_ierrors; 1174151463Sdavidxu#endif 1175151463Sdavidxu break; 117643412Snewton case CE_UNDERRUN: 117743412Snewton CE_DEBUG (d, ("underrun error\n")); 117843412Snewton d->timeout = 0; 117943412Snewton#ifndef NETGRAPH 118043412Snewton ++d->ifp->if_oerrors; 118143412Snewton#if __FreeBSD_version >= 600034 118283366Sjulian d->ifp->if_flags &= ~IFF_DRV_OACTIVE; 118383366Sjulian#else 118443412Snewton d->ifp->if_flags &= ~IFF_OACTIVE; 118543412Snewton#endif 1186160510Sjhb#endif 1187160510Sjhb ce_start (d); 1188160510Sjhb break; 118983366Sjulian default: 1190160510Sjhb CE_DEBUG (d, ("error #%d\n", data)); 119143412Snewton break; 1192160510Sjhb } 1193160510Sjhb} 1194160510Sjhb 1195160510Sjhb/* 1196160510Sjhb * You also need read, write, open, close routines. 1197107849Salfred * This should get you started 1198160510Sjhb */ 1199160510Sjhb#if __FreeBSD_version < 500000 120043412Snewtonstatic int ce_open (dev_t dev, int oflags, int devtype, struct proc *p) 120143412Snewton#else 120243412Snewtonstatic int ce_open (struct cdev *dev, int oflags, int devtype, struct thread *td) 1203160510Sjhb#endif 1204160510Sjhb{ 1205160510Sjhb int unit = dev2unit (dev); 120643412Snewton drv_t *d; 120743412Snewton 120843412Snewton if (unit >= NBRD*NCHAN || ! (d = channel[unit])) 1209160510Sjhb return ENXIO; 121043412Snewton CE_DEBUG2 (d, ("ce_open\n")); 121143412Snewton return 0; 121243412Snewton} 121343412Snewton 121443412Snewton/* 121543412Snewton * Only called on the LAST close. 1216160510Sjhb */ 1217160510Sjhb#if __FreeBSD_version < 500000 1218160510Sjhbstatic int ce_close (dev_t dev, int fflag, int devtype, struct proc *p) 1219160510Sjhb#else 122043412Snewtonstatic int ce_close (struct cdev *dev, int fflag, int devtype, struct thread *td) 1221160510Sjhb#endif 1222160510Sjhb{ 1223160510Sjhb drv_t *d = channel [dev2unit (dev)]; 1224160510Sjhb 1225160510Sjhb CE_DEBUG2 (d, ("ce_close\n")); 1226160510Sjhb return 0; 1227160510Sjhb} 1228160510Sjhb 1229160510Sjhbstatic int ce_modem_status (ce_chan_t *c) 1230160510Sjhb{ 1231160510Sjhb drv_t *d = c->sys; 1232160510Sjhb bdrv_t *bd = d->board->sys; 1233160510Sjhb int status, s; 1234160510Sjhb 1235160510Sjhb status = d->running ? TIOCM_LE : 0; 1236160510Sjhb s = splimp (); 1237160510Sjhb CE_LOCK (bd); 1238160510Sjhb if (ce_get_cd (c)) status |= TIOCM_CD; 1239160510Sjhb if (ce_get_cts (c)) status |= TIOCM_CTS; 1240160510Sjhb if (ce_get_dsr (c)) status |= TIOCM_DSR; 1241160510Sjhb if (c->dtr) status |= TIOCM_DTR; 1242192459Sjhb if (c->rts) status |= TIOCM_RTS; 1243160510Sjhb CE_UNLOCK (bd); 1244160510Sjhb splx (s); 1245160510Sjhb return status; 1246192459Sjhb} 1247192459Sjhb 1248160510Sjhb#if __FreeBSD_version < 500000 124943412Snewtonstatic int ce_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 125043412Snewton#else 125174927Sjhbstatic int ce_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1252160510Sjhb#endif 1253160510Sjhb{ 1254160510Sjhb drv_t *d = channel [dev2unit (dev)]; 1255160510Sjhb bdrv_t *bd = d->board->sys; 1256160510Sjhb ce_chan_t *c = d->chan; 1257160510Sjhb struct serial_statistics *st; 1258160510Sjhb struct e1_statistics *opte1; 125943412Snewton int error, s; 126043412Snewton char mask[16]; 1261160510Sjhb 1262160510Sjhb switch (cmd) { 1263160510Sjhb case SERIAL_GETREGISTERED: 1264160510Sjhb CE_DEBUG2 (d, ("ioctl: getregistered\n")); 1265160510Sjhb bzero (mask, sizeof(mask)); 126643412Snewton for (s=0; s<NBRD*NCHAN; ++s) 1267160510Sjhb if (channel [s]) 1268170466Sattilio mask [s/8] |= 1 << (s & 7); 1269160510Sjhb bcopy (mask, data, sizeof (mask)); 1270160510Sjhb return 0; 1271160510Sjhb 1272160510Sjhb#ifndef NETGRAPH 1273160510Sjhb case SERIAL_GETPROTO: 1274107849Salfred CE_DEBUG2 (d, ("ioctl: getproto\n")); 1275170466Sattilio strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" : 1276160510Sjhb (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp"); 1277160510Sjhb return 0; 1278160510Sjhb 1279160510Sjhb case SERIAL_SETPROTO: 1280160510Sjhb CE_DEBUG2 (d, ("ioctl: setproto\n")); 1281160510Sjhb /* Only for superuser! */ 1282170466Sattilio#if __FreeBSD_version < 500000 1283170472Sattilio error = suser (p); 1284160510Sjhb#elif __FreeBSD_version < 700000 1285170472Sattilio error = suser (td); 1286160510Sjhb#else 128774927Sjhb error = priv_check (td, PRIV_DRIVER); 1288160510Sjhb#endif 1289160510Sjhb if (error) 129043412Snewton return error; 1291160510Sjhb#if __FreeBSD_version >= 600034 1292160510Sjhb if (d->ifp->if_flags & IFF_DRV_RUNNING) 1293160510Sjhb#else 129443412Snewton if (d->ifp->if_flags & IFF_RUNNING) 1295160510Sjhb#endif 1296160510Sjhb return EBUSY; 1297160510Sjhb if (! strcmp ("cisco", (char*)data)) { 1298160510Sjhb IFP2SP(d->ifp)->pp_flags &= ~(PP_FR); 1299160510Sjhb IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; 1300160510Sjhb d->ifp->if_flags |= PP_CISCO; 1301160510Sjhb#if PP_FR != 0 1302160510Sjhb } else if (! strcmp ("fr", (char*)data)) { 1303170307Sjeff d->ifp->if_flags &= ~(PP_CISCO); 1304160510Sjhb IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE; 1305160510Sjhb#endif 1306160510Sjhb } else if (! strcmp ("ppp", (char*)data)) { 1307160510Sjhb IFP2SP(d->ifp)->pp_flags &= ~PP_FR; 1308160510Sjhb IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; 1309170466Sattilio d->ifp->if_flags &= ~(PP_CISCO); 1310170472Sattilio } else 1311160510Sjhb return EINVAL; 1312170472Sattilio return 0; 1313160510Sjhb 131443412Snewton case SERIAL_GETKEEPALIVE: 1315160510Sjhb CE_DEBUG2 (d, ("ioctl: getkeepalive\n")); 1316160510Sjhb if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || 1317160510Sjhb (d->ifp->if_flags & PP_CISCO)) 1318160510Sjhb return EINVAL; 131943412Snewton *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0; 132043412Snewton return 0; 1321160510Sjhb 1322160510Sjhb case SERIAL_SETKEEPALIVE: 1323160510Sjhb CE_DEBUG2 (d, ("ioctl: setkeepalive\n")); 1324160510Sjhb /* Only for superuser! */ 1325170307Sjeff#if __FreeBSD_version < 500000 1326160510Sjhb error = suser (p); 1327160510Sjhb#elif __FreeBSD_version < 700000 1328160510Sjhb error = suser (td); 1329160510Sjhb#else 1330160510Sjhb error = priv_check (td, PRIV_DRIVER); 1331160510Sjhb#endif 1332170466Sattilio if (error) 1333160510Sjhb return error; 1334170472Sattilio if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || 1335160510Sjhb (d->ifp->if_flags & PP_CISCO)) 1336170472Sattilio return EINVAL; 1337160510Sjhb s = splimp (); 1338160510Sjhb CE_LOCK (bd); 1339160510Sjhb if (*(int*)data) 1340160510Sjhb IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; 1341160510Sjhb else 1342160510Sjhb IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; 134373907Sjhb CE_UNLOCK (bd); 134443412Snewton splx (s); 134543412Snewton return 0; 1346160510Sjhb#endif /*NETGRAPH*/ 1347160510Sjhb 134843412Snewton case SERIAL_GETMODE: 1349160510Sjhb CE_DEBUG2 (d, ("ioctl: getmode\n")); 135043412Snewton *(int*)data = SERIAL_HDLC; 135143412Snewton return 0; 1352160510Sjhb 1353160510Sjhb case SERIAL_SETMODE: 1354160510Sjhb /* Only for superuser! */ 1355160510Sjhb#if __FreeBSD_version < 500000 135643412Snewton error = suser (p); 1357107849Salfred#elif __FreeBSD_version < 700000 1358160510Sjhb error = suser (td); 135943412Snewton#else 1360160510Sjhb error = priv_check (td, PRIV_DRIVER); 136143412Snewton#endif 136243412Snewton if (error) 1363160510Sjhb return error; 1364160510Sjhb if (*(int*)data != SERIAL_HDLC) 1365160510Sjhb return EINVAL; 1366160510Sjhb return 0; 1367160510Sjhb 1368160510Sjhb case SERIAL_GETCFG: 1369160510Sjhb CE_DEBUG2 (d, ("ioctl: getcfg\n")); 1370160510Sjhb *(char*)data = 'c'; 1371160510Sjhb return 0; 137243412Snewton 137343412Snewton case SERIAL_SETCFG: 137443412Snewton CE_DEBUG2 (d, ("ioctl: setcfg\n")); 137543412Snewton#if __FreeBSD_version < 500000 137643412Snewton error = suser (p); 137743412Snewton#elif __FreeBSD_version < 700000 137843412Snewton error = suser (td); 137943412Snewton#else 138043412Snewton error = priv_check (td, PRIV_DRIVER); 138143412Snewton#endif 138243412Snewton if (error) 138343412Snewton return error; 138443412Snewton if (*((char*)data) != 'c') 138543412Snewton return EINVAL; 138643412Snewton return 0; 138743412Snewton 138843412Snewton case SERIAL_GETSTAT: 138943412Snewton CE_DEBUG2 (d, ("ioctl: getstat\n")); 139043412Snewton st = (struct serial_statistics*) data; 139143412Snewton st->rintr = c->rintr; 139243412Snewton st->tintr = c->tintr; 139343412Snewton st->mintr = 0; 139443412Snewton st->ibytes = c->ibytes; 139543412Snewton st->ipkts = c->ipkts; 139643412Snewton st->obytes = c->obytes; 139743412Snewton st->opkts = c->opkts; 139843412Snewton st->ierrs = c->overrun + c->frame + c->crc; 139943412Snewton st->oerrs = c->underrun; 140043412Snewton return 0; 140143412Snewton 140243412Snewton case SERIAL_GETESTAT: 140343412Snewton CE_DEBUG2 (d, ("ioctl: getestat\n")); 140443412Snewton if (c->type != T_E1) 140543412Snewton return EINVAL; 140643412Snewton opte1 = (struct e1_statistics*) data; 140743412Snewton 140843412Snewton opte1->status = 0; 140943412Snewton if (c->status & ESTS_NOALARM) 141043412Snewton opte1->status |= E1_NOALARM; 141143412Snewton if (c->status & ESTS_LOS) 141243412Snewton opte1->status |= E1_LOS; 141343412Snewton if (c->status & ESTS_LOF) 141443412Snewton opte1->status |= E1_LOF; 141543412Snewton if (c->status & ESTS_AIS) 141643412Snewton opte1->status |= E1_AIS; 141743412Snewton if (c->status & ESTS_LOMF) 141843412Snewton opte1->status |= E1_LOMF; 141943412Snewton if (c->status & ESTS_AIS16) 142043412Snewton opte1->status |= E1_AIS16; 142143412Snewton if (c->status & ESTS_FARLOF) 142243412Snewton opte1->status |= E1_FARLOF; 142343412Snewton if (c->status & ESTS_FARLOMF) 142443412Snewton opte1->status |= E1_FARLOMF; 142543412Snewton if (c->status & ESTS_TSTREQ) 142643412Snewton opte1->status |= E1_TSTREQ; 142743412Snewton if (c->status & ESTS_TSTERR) 142843412Snewton opte1->status |= E1_TSTERR; 142943412Snewton 143083366Sjulian opte1->cursec = c->cursec; 143183366Sjulian opte1->totsec = c->totsec + c->cursec; 143243412Snewton 143343412Snewton opte1->currnt.bpv = c->currnt.bpv; 1434141486Sjhb opte1->currnt.fse = c->currnt.fse; 143543412Snewton opte1->currnt.crce = c->currnt.crce; 1436141486Sjhb opte1->currnt.rcrce = c->currnt.rcrce; 143743412Snewton opte1->currnt.uas = c->currnt.uas; 143843412Snewton opte1->currnt.les = c->currnt.les; 1439141486Sjhb opte1->currnt.es = c->currnt.es; 144043412Snewton opte1->currnt.bes = c->currnt.bes; 1441141486Sjhb opte1->currnt.ses = c->currnt.ses; 1442141486Sjhb opte1->currnt.oofs = c->currnt.oofs; 1443141486Sjhb opte1->currnt.css = c->currnt.css; 1444141486Sjhb opte1->currnt.dm = c->currnt.dm; 144543412Snewton 1446107849Salfred opte1->total.bpv = c->total.bpv + c->currnt.bpv; 144743412Snewton opte1->total.fse = c->total.fse + c->currnt.fse; 144843412Snewton opte1->total.crce = c->total.crce + c->currnt.crce; 144943412Snewton opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce; 145043412Snewton opte1->total.uas = c->total.uas + c->currnt.uas; 145183366Sjulian opte1->total.les = c->total.les + c->currnt.les; 145283366Sjulian opte1->total.es = c->total.es + c->currnt.es; 145343412Snewton opte1->total.bes = c->total.bes + c->currnt.bes; 145443412Snewton opte1->total.ses = c->total.ses + c->currnt.ses; 1455141486Sjhb opte1->total.oofs = c->total.oofs + c->currnt.oofs; 145643412Snewton opte1->total.css = c->total.css + c->currnt.css; 145743412Snewton opte1->total.dm = c->total.dm + c->currnt.dm; 145843412Snewton for (s=0; s<48; ++s) { 1459141486Sjhb opte1->interval[s].bpv = c->interval[s].bpv; 1460141486Sjhb opte1->interval[s].fse = c->interval[s].fse; 1461141486Sjhb opte1->interval[s].crce = c->interval[s].crce; 146243412Snewton opte1->interval[s].rcrce = c->interval[s].rcrce; 1463107849Salfred opte1->interval[s].uas = c->interval[s].uas; 146443412Snewton opte1->interval[s].les = c->interval[s].les; 146543412Snewton opte1->interval[s].es = c->interval[s].es; 146643412Snewton opte1->interval[s].bes = c->interval[s].bes; 146743412Snewton opte1->interval[s].ses = c->interval[s].ses; 146883366Sjulian opte1->interval[s].oofs = c->interval[s].oofs; 146983366Sjulian opte1->interval[s].css = c->interval[s].css; 147043412Snewton opte1->interval[s].dm = c->interval[s].dm; 147143412Snewton } 1472141486Sjhb return 0; 147343412Snewton 1474141486Sjhb case SERIAL_CLRSTAT: 147543412Snewton CE_DEBUG2 (d, ("ioctl: clrstat\n")); 147643412Snewton /* Only for superuser! */ 1477141486Sjhb#if __FreeBSD_version < 500000 147843412Snewton error = suser (p); 1479141486Sjhb#elif __FreeBSD_version < 700000 1480141486Sjhb error = suser (td); 1481141486Sjhb#else 1482141486Sjhb error = priv_check (td, PRIV_DRIVER); 148343412Snewton#endif 1484107849Salfred if (error) 148543412Snewton return error; 148643412Snewton c->rintr = 0; 148743412Snewton c->tintr = 0; 148843412Snewton c->ibytes = 0; 148983366Sjulian c->obytes = 0; 149083366Sjulian c->ipkts = 0; 149143412Snewton c->opkts = 0; 149243412Snewton c->overrun = 0; 1493141486Sjhb c->frame = 0; 149443412Snewton c->crc = 0; 149543412Snewton c->underrun = 0; 149643412Snewton bzero (&c->currnt, sizeof (c->currnt)); 1497141486Sjhb bzero (&c->total, sizeof (c->total)); 1498141486Sjhb bzero (c->interval, sizeof (c->interval)); 1499141486Sjhb return 0; 150043412Snewton 1501107849Salfred case SERIAL_GETLOOP: 150243412Snewton CE_DEBUG2 (d, ("ioctl: getloop\n")); 150343412Snewton if (c->type != T_E1) 150443412Snewton return EINVAL; 150583366Sjulian *(int*)data = c->lloop; 150683366Sjulian return 0; 150743412Snewton 150843412Snewton case SERIAL_SETLOOP: 1509141486Sjhb CE_DEBUG2 (d, ("ioctl: setloop\n")); 151043412Snewton if (c->type != T_E1) 151143412Snewton return EINVAL; 1512141486Sjhb /* Only for superuser! */ 1513141486Sjhb#if __FreeBSD_version < 500000 1514141486Sjhb error = suser (p); 1515141486Sjhb#elif __FreeBSD_version < 700000 151643412Snewton error = suser (td); 1517141486Sjhb#else 1518141486Sjhb error = priv_check (td, PRIV_DRIVER); 1519141486Sjhb#endif 1520141486Sjhb if (error) 1521141486Sjhb return error; 152243412Snewton s = splimp (); 152343412Snewton CE_LOCK (bd); 152443412Snewton ce_set_lloop (c, *(int*)data); 152583366Sjulian CE_UNLOCK (bd); 152683366Sjulian splx (s); 152743412Snewton return 0; 152843412Snewton 1529107849Salfred case SERIAL_GETRLOOP: 153043412Snewton CE_DEBUG2 (d, ("ioctl: getrloop\n")); 153143412Snewton if (c->type != T_E1) 153243412Snewton return EINVAL; 1533107849Salfred *(int*)data = c->rloop; 153443412Snewton return 0; 153543412Snewton 153643412Snewton case SERIAL_SETRLOOP: 153743412Snewton CE_DEBUG2 (d, ("ioctl: setloop\n")); 153843412Snewton if (c->type != T_E1) 153943412Snewton return EINVAL; 154083366Sjulian /* Only for superuser! */ 154183366Sjulian#if __FreeBSD_version < 500000 154243412Snewton error = suser (p); 154343412Snewton#elif __FreeBSD_version < 700000 154443412Snewton error = suser (td); 154543412Snewton#else 154683366Sjulian error = priv_check (td, PRIV_DRIVER); 154743412Snewton#endif 154843412Snewton if (error) 1549107849Salfred return error; 155043412Snewton s = splimp (); 155143412Snewton CE_LOCK (bd); 155243412Snewton ce_set_rloop (c, *(int*)data); 155343412Snewton CE_UNLOCK (bd); 155443412Snewton splx (s); 1555107849Salfred return 0; 1556107849Salfred 155743412Snewton case SERIAL_GETDEBUG: 155843412Snewton CE_DEBUG2 (d, ("ioctl: getdebug\n")); 155943412Snewton *(int*)data = d->chan->debug; 156043412Snewton return 0; 156143412Snewton 156243412Snewton case SERIAL_SETDEBUG: 156343412Snewton CE_DEBUG2 (d, ("ioctl: setdebug\n")); 156443412Snewton /* Only for superuser! */ 156543412Snewton#if __FreeBSD_version < 500000 156643412Snewton error = suser (p); 156743412Snewton#elif __FreeBSD_version < 700000 156883366Sjulian error = suser (td); 156983366Sjulian#else 157043412Snewton error = priv_check (td, PRIV_DRIVER); 157143412Snewton#endif 157243412Snewton if (error) 157383366Sjulian return error; 157443412Snewton#ifndef NETGRAPH 157543412Snewton /* 157643412Snewton * The debug_shadow is always greater than zero for logic 157783366Sjulian * simplicity. For switching debug off the IFF_DEBUG is 157883366Sjulian * responsible. 157943412Snewton */ 158043412Snewton d->chan->debug_shadow = (*(int*)data) ? (*(int*)data) : 1; 158143412Snewton if (d->ifp->if_flags & IFF_DEBUG) 158243412Snewton d->chan->debug = d->chan->debug_shadow; 158343412Snewton#else 158443412Snewton d->chan->debug = *(int*)data; 158543412Snewton#endif 158643412Snewton return 0; 158743412Snewton 158883366Sjulian case SERIAL_GETBAUD: 158983366Sjulian CE_DEBUG2 (d, ("ioctl: getbaud\n")); 159043412Snewton *(long*)data = c->baud; 159143412Snewton return 0; 1592107849Salfred 159343412Snewton case SERIAL_SETBAUD: 159443412Snewton CE_DEBUG2 (d, ("ioctl: setbaud\n")); 159543412Snewton if (c->type != T_E1 || !c->unfram) 159643412Snewton return EINVAL; 1597107849Salfred /* Only for superuser! */ 1598107849Salfred#if __FreeBSD_version < 500000 1599107849Salfred error = suser (p); 160043412Snewton#elif __FreeBSD_version < 700000 1601225617Skmacy error = suser (td); 160243412Snewton#else 160343412Snewton error = priv_check (td, PRIV_DRIVER); 160443412Snewton#endif 160543412Snewton if (error) 160643412Snewton return error; 1607107849Salfred s = splimp (); 1608107849Salfred CE_LOCK (bd); 1609107849Salfred ce_set_baud (c, *(long*)data); 161043412Snewton CE_UNLOCK (bd); 1611225617Skmacy splx (s); 161243412Snewton return 0; 161343412Snewton 161443412Snewton case SERIAL_GETTIMESLOTS: 161543412Snewton CE_DEBUG2 (d, ("ioctl: gettimeslots\n")); 161643412Snewton if ((c->type != T_E1 || c->unfram) && c->type != T_DATA) 161743412Snewton return EINVAL; 161843412Snewton *(u_long*)data = c->ts; 161943412Snewton return 0; 162043412Snewton 162143412Snewton case SERIAL_SETTIMESLOTS: 162243412Snewton CE_DEBUG2 (d, ("ioctl: settimeslots\n")); 162343412Snewton /* Only for superuser! */ 162443412Snewton#if __FreeBSD_version < 500000 162583366Sjulian error = suser (p); 162683366Sjulian#elif __FreeBSD_version < 700000 162743412Snewton error = suser (td); 162843412Snewton#else 162943412Snewton error = priv_check (td, PRIV_DRIVER); 163043412Snewton#endif 163143412Snewton if (error) 1632107849Salfred return error; 1633107849Salfred if ((c->type != T_E1 || c->unfram) && c->type != T_DATA) 1634107849Salfred return EINVAL; 163543412Snewton s = splimp (); 1636225617Skmacy CE_LOCK (bd); 163743412Snewton ce_set_ts (c, *(u_long*)data); 163843412Snewton CE_UNLOCK (bd); 163943412Snewton splx (s); 1640225617Skmacy return 0; 164143412Snewton 164243412Snewton case SERIAL_GETHIGAIN: 164343412Snewton CE_DEBUG2 (d, ("ioctl: gethigain\n")); 164443412Snewton if (c->type != T_E1) 164543412Snewton return EINVAL; 164643412Snewton *(int*)data = c->higain; 164783366Sjulian return 0; 164883366Sjulian 164943412Snewton case SERIAL_SETHIGAIN: 165043412Snewton CE_DEBUG2 (d, ("ioctl: sethigain\n")); 165143412Snewton if (c->type != T_E1) 165283366Sjulian return EINVAL; 1653121275Stjr /* Only for superuser! */ 165443412Snewton#if __FreeBSD_version < 500000 1655160511Sjhb error = suser (p); 1656107849Salfred#elif __FreeBSD_version < 700000 165743412Snewton error = suser (td); 165843412Snewton#else 1659192455Sjhb error = priv_check (td, PRIV_DRIVER); 1660192455Sjhb#endif 1661192455Sjhb if (error) 166243412Snewton return error; 1663121275Stjr s = splimp (); 1664121275Stjr CE_LOCK (bd); 166543412Snewton ce_set_higain (c, *(int*)data); 166643412Snewton CE_UNLOCK (bd); 1667121275Stjr splx (s); 166843412Snewton return 0; 166954655Seivind 167043412Snewton case SERIAL_GETPHONY: 167143412Snewton CE_DEBUG2 (d, ("ioctl: getphony\n")); 1672 *(int*)data = c->phony; 1673 return 0; 1674 1675 case SERIAL_SETPHONY: 1676 CE_DEBUG2 (d, ("ioctl: setphony\n")); 1677 /* Only for superuser! */ 1678#if __FreeBSD_version < 500000 1679 error = suser (p); 1680#elif __FreeBSD_version < 700000 1681 error = suser (td); 1682#else 1683 error = priv_check (td, PRIV_DRIVER); 1684#endif 1685 if (error) 1686 return error; 1687 s = splimp (); 1688 CE_LOCK (bd); 1689 ce_set_phony (c, *(int*)data); 1690 CE_UNLOCK (bd); 1691 splx (s); 1692 return 0; 1693 1694 case SERIAL_GETUNFRAM: 1695 CE_DEBUG2 (d, ("ioctl: getunfram\n")); 1696 if (c->type != T_E1 || c->num != 0) 1697 return EINVAL; 1698 *(int*)data = c->unfram; 1699 return 0; 1700 1701 case SERIAL_SETUNFRAM: 1702 CE_DEBUG2 (d, ("ioctl: setunfram\n")); 1703 if (c->type != T_E1 || c->num != 0) 1704 return EINVAL; 1705 /* Only for superuser! */ 1706#if __FreeBSD_version < 500000 1707 error = suser (p); 1708#elif __FreeBSD_version < 700000 1709 error = suser (td); 1710#else 1711 error = priv_check (td, PRIV_DRIVER); 1712#endif 1713 if (error) 1714 return error; 1715 s = splimp (); 1716 CE_LOCK (bd); 1717 ce_set_unfram (c, *(int*)data); 1718 CE_UNLOCK (bd); 1719 splx (s); 1720 return 0; 1721 1722 case SERIAL_GETSCRAMBLER: 1723 CE_DEBUG2 (d, ("ioctl: getscrambler\n")); 1724 if (!c->unfram) 1725 return EINVAL; 1726 *(int*)data = c->scrambler; 1727 return 0; 1728 1729 case SERIAL_SETSCRAMBLER: 1730 CE_DEBUG2 (d, ("ioctl: setscrambler\n")); 1731 /* Only for superuser! */ 1732#if __FreeBSD_version < 500000 1733 error = suser (p); 1734#elif __FreeBSD_version < 700000 1735 error = suser (td); 1736#else 1737 error = priv_check (td, PRIV_DRIVER); 1738#endif 1739 if (error) 1740 return error; 1741 if (!c->unfram) 1742 return EINVAL; 1743 s = splimp (); 1744 CE_LOCK (bd); 1745 ce_set_scrambler (c, *(int*)data); 1746 CE_UNLOCK (bd); 1747 splx (s); 1748 return 0; 1749 1750 case SERIAL_GETMONITOR: 1751 CE_DEBUG2 (d, ("ioctl: getmonitor\n")); 1752 if (c->type != T_E1) 1753 return EINVAL; 1754 *(int*)data = c->monitor; 1755 return 0; 1756 1757 case SERIAL_SETMONITOR: 1758 CE_DEBUG2 (d, ("ioctl: setmonitor\n")); 1759 /* Only for superuser! */ 1760#if __FreeBSD_version < 500000 1761 error = suser (p); 1762#elif __FreeBSD_version < 700000 1763 error = suser (td); 1764#else 1765 error = priv_check (td, PRIV_DRIVER); 1766#endif 1767 if (error) 1768 return error; 1769 if (c->type != T_E1) 1770 return EINVAL; 1771 s = splimp (); 1772 CE_LOCK (bd); 1773 ce_set_monitor (c, *(int*)data); 1774 CE_UNLOCK (bd); 1775 splx (s); 1776 return 0; 1777 1778 case SERIAL_GETUSE16: 1779 CE_DEBUG2 (d, ("ioctl: getuse16\n")); 1780 if (c->type != T_E1 || c->unfram) 1781 return EINVAL; 1782 *(int*)data = c->use16; 1783 return 0; 1784 1785 case SERIAL_SETUSE16: 1786 CE_DEBUG2 (d, ("ioctl: setuse16\n")); 1787 /* Only for superuser! */ 1788#if __FreeBSD_version < 500000 1789 error = suser (p); 1790#elif __FreeBSD_version < 700000 1791 error = suser (td); 1792#else 1793 error = priv_check (td, PRIV_DRIVER); 1794#endif 1795 if (error) 1796 return error; 1797 if (c->type != T_E1) 1798 return EINVAL; 1799 s = splimp (); 1800 CE_LOCK (bd); 1801 ce_set_use16 (c, *(int*)data); 1802 CE_UNLOCK (bd); 1803 splx (s); 1804 return 0; 1805 1806 case SERIAL_GETCRC4: 1807 CE_DEBUG2 (d, ("ioctl: getcrc4\n")); 1808 if (c->type != T_E1 || c->unfram) 1809 return EINVAL; 1810 *(int*)data = c->crc4; 1811 return 0; 1812 1813 case SERIAL_SETCRC4: 1814 CE_DEBUG2 (d, ("ioctl: setcrc4\n")); 1815 /* Only for superuser! */ 1816#if __FreeBSD_version < 500000 1817 error = suser (p); 1818#elif __FreeBSD_version < 700000 1819 error = suser (td); 1820#else 1821 error = priv_check (td, PRIV_DRIVER); 1822#endif 1823 if (error) 1824 return error; 1825 if (c->type != T_E1 || c->unfram) 1826 return EINVAL; 1827 s = splimp (); 1828 CE_LOCK (bd); 1829 ce_set_crc4 (c, *(int*)data); 1830 CE_UNLOCK (bd); 1831 splx (s); 1832 return 0; 1833 1834 case SERIAL_GETCLK: 1835 CE_DEBUG2 (d, ("ioctl: getclk\n")); 1836 if (c->type != T_E1) 1837 return EINVAL; 1838 switch (c->gsyn) { 1839 default: *(int*)data = E1CLK_INTERNAL; break; 1840 case GSYN_RCV: *(int*)data = E1CLK_RECEIVE; break; 1841 case GSYN_RCV0: *(int*)data = E1CLK_RECEIVE_CHAN0; break; 1842 case GSYN_RCV1: *(int*)data = E1CLK_RECEIVE_CHAN1; break; 1843 } 1844 return 0; 1845 1846 case SERIAL_SETCLK: 1847 CE_DEBUG2 (d, ("ioctl: setclk\n")); 1848 /* Only for superuser! */ 1849#if __FreeBSD_version < 500000 1850 error = suser (p); 1851#elif __FreeBSD_version < 700000 1852 error = suser (td); 1853#else 1854 error = priv_check (td, PRIV_DRIVER); 1855#endif 1856 if (error) 1857 return error; 1858 if (c->type != T_E1) 1859 return EINVAL; 1860 s = splimp (); 1861 CE_LOCK (bd); 1862 switch (*(int*)data) { 1863 default: ce_set_gsyn (c, GSYN_INT); break; 1864 case E1CLK_RECEIVE: ce_set_gsyn (c, GSYN_RCV); break; 1865 case E1CLK_RECEIVE_CHAN0: ce_set_gsyn (c, GSYN_RCV0); break; 1866 case E1CLK_RECEIVE_CHAN1: ce_set_gsyn (c, GSYN_RCV1); break; 1867 } 1868 CE_UNLOCK (bd); 1869 splx (s); 1870 return 0; 1871 1872#if 0 1873 case SERIAL_RESET: 1874 CE_DEBUG2 (d, ("ioctl: reset\n")); 1875 /* Only for superuser! */ 1876#if __FreeBSD_version < 500000 1877 error = suser (p); 1878#elif __FreeBSD_version < 700000 1879 error = suser (td); 1880#else 1881 error = priv_check (td, PRIV_DRIVER); 1882#endif 1883 if (error) 1884 return error; 1885 s = splimp (); 1886 CE_LOCK (bd); 1887/* ce_reset (c->board, 0, 0);*/ 1888 CE_UNLOCK (bd); 1889 splx (s); 1890 return 0; 1891 1892 case SERIAL_HARDRESET: 1893 CE_DEBUG2 (d, ("ioctl: hardreset\n")); 1894 /* Only for superuser! */ 1895#if __FreeBSD_version < 500000 1896 error = suser (p); 1897#elif __FreeBSD_version < 700000 1898 error = suser (td); 1899#else 1900 error = priv_check (td, PRIV_DRIVER); 1901#endif 1902 if (error) 1903 return error; 1904 s = splimp (); 1905 CE_LOCK (bd); 1906 /* hard_reset (c->board); */ 1907 CE_UNLOCK (bd); 1908 splx (s); 1909 return 0; 1910#endif 1911 1912 case SERIAL_GETCABLE: 1913 CE_DEBUG2 (d, ("ioctl: getcable\n")); 1914 if (c->type != T_E1) 1915 return EINVAL; 1916 s = splimp (); 1917 CE_LOCK (bd); 1918 *(int*)data = CABLE_TP; 1919 CE_UNLOCK (bd); 1920 splx (s); 1921 return 0; 1922 1923 case SERIAL_GETDIR: 1924 CE_DEBUG2 (d, ("ioctl: getdir\n")); 1925 if (c->type != T_E1 && c->type != T_DATA) 1926 return EINVAL; 1927 *(int*)data = c->dir; 1928 return 0; 1929 1930 case SERIAL_SETDIR: 1931 CE_DEBUG2 (d, ("ioctl: setdir\n")); 1932 /* Only for superuser! */ 1933#if __FreeBSD_version < 500000 1934 error = suser (p); 1935#elif __FreeBSD_version < 700000 1936 error = suser (td); 1937#else 1938 error = priv_check (td, PRIV_DRIVER); 1939#endif 1940 if (error) 1941 return error; 1942 s = splimp (); 1943 CE_LOCK (bd); 1944 ce_set_dir (c, *(int*)data); 1945 CE_UNLOCK (bd); 1946 splx (s); 1947 return 0; 1948 1949 case TIOCSDTR: /* Set DTR */ 1950 s = splimp (); 1951 CE_LOCK (bd); 1952 ce_set_dtr (c, 1); 1953 CE_UNLOCK (bd); 1954 splx (s); 1955 return 0; 1956 1957 case TIOCCDTR: /* Clear DTR */ 1958 s = splimp (); 1959 CE_LOCK (bd); 1960 ce_set_dtr (c, 0); 1961 CE_UNLOCK (bd); 1962 splx (s); 1963 return 0; 1964 1965 case TIOCMSET: /* Set DTR/RTS */ 1966 s = splimp (); 1967 CE_LOCK (bd); 1968 ce_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); 1969 ce_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); 1970 CE_UNLOCK (bd); 1971 splx (s); 1972 return 0; 1973 1974 case TIOCMBIS: /* Add DTR/RTS */ 1975 s = splimp (); 1976 CE_LOCK (bd); 1977 if (*(int*)data & TIOCM_DTR) ce_set_dtr (c, 1); 1978 if (*(int*)data & TIOCM_RTS) ce_set_rts (c, 1); 1979 CE_UNLOCK (bd); 1980 splx (s); 1981 return 0; 1982 1983 case TIOCMBIC: /* Clear DTR/RTS */ 1984 s = splimp (); 1985 CE_LOCK (bd); 1986 if (*(int*)data & TIOCM_DTR) ce_set_dtr (c, 0); 1987 if (*(int*)data & TIOCM_RTS) ce_set_rts (c, 0); 1988 CE_UNLOCK (bd); 1989 splx (s); 1990 return 0; 1991 1992 case TIOCMGET: /* Get modem status */ 1993 *(int*)data = ce_modem_status (c); 1994 return 0; 1995 } 1996 return ENOTTY; 1997} 1998 1999#ifdef NETGRAPH 2000#if __FreeBSD_version >= 500000 2001static int ng_ce_constructor (node_p node) 2002{ 2003 drv_t *d = NG_NODE_PRIVATE (node); 2004#else 2005static int ng_ce_constructor (node_p *node) 2006{ 2007 drv_t *d = (*node)->private; 2008#endif 2009 CE_DEBUG (d, ("Constructor\n")); 2010 return EINVAL; 2011} 2012 2013static int ng_ce_newhook (node_p node, hook_p hook, const char *name) 2014{ 2015 int s; 2016#if __FreeBSD_version >= 500000 2017 drv_t *d = NG_NODE_PRIVATE (node); 2018#else 2019 drv_t *d = node->private; 2020#endif 2021 bdrv_t *bd = d->board->sys; 2022 2023 CE_DEBUG (d, ("Newhook\n")); 2024 /* Attach debug hook */ 2025 if (strcmp (name, NG_CE_HOOK_DEBUG) == 0) { 2026#if __FreeBSD_version >= 500000 2027 NG_HOOK_SET_PRIVATE (hook, NULL); 2028#else 2029 hook->private = 0; 2030#endif 2031 d->debug_hook = hook; 2032 return 0; 2033 } 2034 2035 /* Check for raw hook */ 2036 if (strcmp (name, NG_CE_HOOK_RAW) != 0) 2037 return EINVAL; 2038 2039#if __FreeBSD_version >= 500000 2040 NG_HOOK_SET_PRIVATE (hook, d); 2041#else 2042 hook->private = d; 2043#endif 2044 d->hook = hook; 2045 s = splimp (); 2046 CE_LOCK (bd); 2047 ce_up (d); 2048 CE_UNLOCK (bd); 2049 splx (s); 2050 return 0; 2051} 2052 2053static char *format_timeslots (u_long s) 2054{ 2055 static char buf [100]; 2056 char *p = buf; 2057 int i; 2058 2059 for (i=1; i<32; ++i) 2060 if ((s >> i) & 1) { 2061 int prev = (i > 1) & (s >> (i-1)); 2062 int next = (i < 31) & (s >> (i+1)); 2063 2064 if (prev) { 2065 if (next) 2066 continue; 2067 *p++ = '-'; 2068 } else if (p > buf) 2069 *p++ = ','; 2070 2071 if (i >= 10) 2072 *p++ = '0' + i / 10; 2073 *p++ = '0' + i % 10; 2074 } 2075 *p = 0; 2076 return buf; 2077} 2078 2079static int print_modems (char *s, ce_chan_t *c, int need_header) 2080{ 2081 int status = ce_modem_status (c); 2082 int length = 0; 2083 2084 if (need_header) 2085 length += sprintf (s + length, " LE DTR DSR RTS CTS CD\n"); 2086 length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n", 2087 status & TIOCM_LE ? "On" : "-", 2088 status & TIOCM_DTR ? "On" : "-", 2089 status & TIOCM_DSR ? "On" : "-", 2090 status & TIOCM_RTS ? "On" : "-", 2091 status & TIOCM_CTS ? "On" : "-", 2092 status & TIOCM_CD ? "On" : "-"); 2093 return length; 2094} 2095 2096static int print_stats (char *s, ce_chan_t *c, int need_header) 2097{ 2098 int length = 0; 2099 2100 if (need_header) 2101 length += sprintf (s + length, " Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); 2102 length += sprintf (s + length, "%7ld %7ld %7ld %8lu %7ld %7ld %8lu %7ld %7ld\n", 2103 c->rintr, c->tintr, 0l, (unsigned long) c->ibytes, 2104 c->ipkts, c->overrun + c->frame + c->crc, 2105 (unsigned long) c->obytes, c->opkts, c->underrun); 2106 return length; 2107} 2108 2109static char *format_e1_status (u_char status) 2110{ 2111 static char buf [80]; 2112 2113 if (status & E1_NOALARM) 2114 return "Ok"; 2115 buf[0] = 0; 2116 if (status & E1_LOS) strcat (buf, ",LOS"); 2117 if (status & E1_AIS) strcat (buf, ",AIS"); 2118 if (status & E1_LOF) strcat (buf, ",LOF"); 2119 if (status & E1_LOMF) strcat (buf, ",LOMF"); 2120 if (status & E1_FARLOF) strcat (buf, ",FARLOF"); 2121 if (status & E1_AIS16) strcat (buf, ",AIS16"); 2122 if (status & E1_FARLOMF) strcat (buf, ",FARLOMF"); 2123 if (status & E1_TSTREQ) strcat (buf, ",TSTREQ"); 2124 if (status & E1_TSTERR) strcat (buf, ",TSTERR"); 2125 if (buf[0] == ',') 2126 return buf+1; 2127 return "Unknown"; 2128} 2129 2130static int print_frac (char *s, int leftalign, u_long numerator, u_long divider) 2131{ 2132 int n, length = 0; 2133 2134 if (numerator < 1 || divider < 1) { 2135 length += sprintf (s+length, leftalign ? "/- " : " -"); 2136 return length; 2137 } 2138 n = (int) (0.5 + 1000.0 * numerator / divider); 2139 if (n < 1000) { 2140 length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n); 2141 return length; 2142 } 2143 *(s + length) = leftalign ? '/' : ' '; 2144 length ++; 2145 2146 if (n >= 1000000) n = (n+500) / 1000 * 1000; 2147 else if (n >= 100000) n = (n+50) / 100 * 100; 2148 else if (n >= 10000) n = (n+5) / 10 * 10; 2149 2150 switch (n) { 2151 case 1000: length += printf (s+length, ".999"); return length; 2152 case 10000: n = 9990; break; 2153 case 100000: n = 99900; break; 2154 case 1000000: n = 999000; break; 2155 } 2156 if (n < 10000) length += sprintf (s+length, "%d.%d", n/1000, n/10%100); 2157 else if (n < 100000) length += sprintf (s+length, "%d.%d", n/1000, n/100%10); 2158 else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000); 2159 else length += sprintf (s+length, "%d", n/1000); 2160 2161 return length; 2162} 2163 2164static int print_e1_stats (char *s, ce_chan_t *c) 2165{ 2166 struct e1_counters total; 2167 u_long totsec; 2168 int length = 0; 2169 2170 totsec = c->totsec + c->cursec; 2171 total.bpv = c->total.bpv + c->currnt.bpv; 2172 total.fse = c->total.fse + c->currnt.fse; 2173 total.crce = c->total.crce + c->currnt.crce; 2174 total.rcrce = c->total.rcrce + c->currnt.rcrce; 2175 total.uas = c->total.uas + c->currnt.uas; 2176 total.les = c->total.les + c->currnt.les; 2177 total.es = c->total.es + c->currnt.es; 2178 total.bes = c->total.bes + c->currnt.bes; 2179 total.ses = c->total.ses + c->currnt.ses; 2180 total.oofs = c->total.oofs + c->currnt.oofs; 2181 total.css = c->total.css + c->currnt.css; 2182 total.dm = c->total.dm + c->currnt.dm; 2183 2184 length += sprintf (s + length, " Unav/Degr Bpv/Fsyn CRC/RCRC Err/Lerr Sev/Bur Oof/Slp Status\n"); 2185 2186 /* Unavailable seconds, degraded minutes */ 2187 length += print_frac (s + length, 0, c->currnt.uas, c->cursec); 2188 length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec); 2189 2190 /* Bipolar violations, frame sync errors */ 2191 length += print_frac (s + length, 0, c->currnt.bpv, c->cursec); 2192 length += print_frac (s + length, 1, c->currnt.fse, c->cursec); 2193 2194 /* CRC errors, remote CRC errors (E-bit) */ 2195 length += print_frac (s + length, 0, c->currnt.crce, c->cursec); 2196 length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec); 2197 2198 /* Errored seconds, line errored seconds */ 2199 length += print_frac (s + length, 0, c->currnt.es, c->cursec); 2200 length += print_frac (s + length, 1, c->currnt.les, c->cursec); 2201 2202 /* Severely errored seconds, burst errored seconds */ 2203 length += print_frac (s + length, 0, c->currnt.ses, c->cursec); 2204 length += print_frac (s + length, 1, c->currnt.bes, c->cursec); 2205 2206 /* Out of frame seconds, controlled slip seconds */ 2207 length += print_frac (s + length, 0, c->currnt.oofs, c->cursec); 2208 length += print_frac (s + length, 1, c->currnt.css, c->cursec); 2209 2210 length += sprintf (s + length, " %s\n", format_e1_status (c->status)); 2211 2212 /* Print total statistics. */ 2213 length += print_frac (s + length, 0, total.uas, totsec); 2214 length += print_frac (s + length, 1, 60 * total.dm, totsec); 2215 2216 length += print_frac (s + length, 0, total.bpv, totsec); 2217 length += print_frac (s + length, 1, total.fse, totsec); 2218 2219 length += print_frac (s + length, 0, total.crce, totsec); 2220 length += print_frac (s + length, 1, total.rcrce, totsec); 2221 2222 length += print_frac (s + length, 0, total.es, totsec); 2223 length += print_frac (s + length, 1, total.les, totsec); 2224 2225 length += print_frac (s + length, 0, total.ses, totsec); 2226 length += print_frac (s + length, 1, total.bes, totsec); 2227 2228 length += print_frac (s + length, 0, total.oofs, totsec); 2229 length += print_frac (s + length, 1, total.css, totsec); 2230 2231 length += sprintf (s + length, " -- Total\n"); 2232 return length; 2233} 2234 2235static int print_chan (char *s, ce_chan_t *c) 2236{ 2237 drv_t *d = c->sys; 2238 int length = 0; 2239 2240 length += sprintf (s + length, "ce%d", c->board->num * NCHAN + c->num); 2241 if (d->chan->debug) 2242 length += sprintf (s + length, " debug=%d", d->chan->debug); 2243 2244 if (c->board->mux) { 2245 length += sprintf (s + length, " cfg=C"); 2246 } else { 2247 length += sprintf (s + length, " cfg=A"); 2248 } 2249 2250 if (c->baud) 2251 length += sprintf (s + length, " %ld", c->baud); 2252 else 2253 length += sprintf (s + length, " extclock"); 2254 2255 if (c->type == T_E1) 2256 switch (c->gsyn) { 2257 case GSYN_INT : length += sprintf (s + length, " syn=int"); break; 2258 case GSYN_RCV : length += sprintf (s + length, " syn=rcv"); break; 2259 case GSYN_RCV0 : length += sprintf (s + length, " syn=rcv0"); break; 2260 case GSYN_RCV1 : length += sprintf (s + length, " syn=rcv1"); break; 2261 } 2262 if (c->type == T_E1) 2263 length += sprintf (s + length, " higain=%s", c->higain ? "on" : "off"); 2264 2265 length += sprintf (s + length, " loop=%s", c->lloop ? "on" : "off"); 2266 2267 if (c->type == T_E1) 2268 length += sprintf (s + length, " ts=%s", format_timeslots (c->ts)); 2269 length += sprintf (s + length, "\n"); 2270 return length; 2271} 2272 2273#if __FreeBSD_version >= 500000 2274static int ng_ce_rcvmsg (node_p node, item_p item, hook_p lasthook) 2275{ 2276 drv_t *d = NG_NODE_PRIVATE (node); 2277 struct ng_mesg *msg; 2278#else 2279static int ng_ce_rcvmsg (node_p node, struct ng_mesg *msg, 2280 const char *retaddr, struct ng_mesg **rptr) 2281{ 2282 drv_t *d = node->private; 2283#endif 2284 struct ng_mesg *resp = NULL; 2285 int error = 0; 2286 2287 CE_DEBUG (d, ("Rcvmsg\n")); 2288#if __FreeBSD_version >= 500000 2289 NGI_GET_MSG (item, msg); 2290#endif 2291 switch (msg->header.typecookie) { 2292 default: 2293 error = EINVAL; 2294 break; 2295 2296 case NGM_CE_COOKIE: 2297 printf ("Not implemented yet\n"); 2298 error = EINVAL; 2299 break; 2300 2301 case NGM_GENERIC_COOKIE: 2302 switch (msg->header.cmd) { 2303 default: 2304 error = EINVAL; 2305 break; 2306 2307 case NGM_TEXT_STATUS: { 2308 char *s; 2309 int l = 0; 2310 int dl = sizeof (struct ng_mesg) + 730; 2311 2312#if __FreeBSD_version >= 500000 2313 NG_MKRESPONSE (resp, msg, dl, M_NOWAIT); 2314 if (! resp) { 2315 error = ENOMEM; 2316 break; 2317 } 2318#else 2319 resp = malloc (M_NETGRAPH, M_NOWAIT); 2320 if (! resp) { 2321 error = ENOMEM; 2322 break; 2323 } 2324 bzero (resp, dl); 2325#endif 2326 s = (resp)->data; 2327 if (d) { 2328 l += print_chan (s + l, d->chan); 2329 l += print_stats (s + l, d->chan, 1); 2330 l += print_modems (s + l, d->chan, 1); 2331 l += print_e1_stats (s + l, d->chan); 2332 } else 2333 l += sprintf (s + l, "Error: node not connect to channel"); 2334#if __FreeBSD_version < 500000 2335 (resp)->header.version = NG_VERSION; 2336 (resp)->header.arglen = strlen (s) + 1; 2337 (resp)->header.token = msg->header.token; 2338 (resp)->header.typecookie = NGM_CE_COOKIE; 2339 (resp)->header.cmd = msg->header.cmd; 2340#endif 2341 strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRSIZ); 2342 } 2343 break; 2344 } 2345 break; 2346 } 2347#if __FreeBSD_version >= 500000 2348 NG_RESPOND_MSG (error, node, item, resp); 2349 NG_FREE_MSG (msg); 2350#else 2351 *rptr = resp; 2352 free (msg, M_NETGRAPH); 2353#endif 2354 return error; 2355} 2356 2357#if __FreeBSD_version >= 500000 2358static int ng_ce_rcvdata (hook_p hook, item_p item) 2359{ 2360 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook)); 2361 struct mbuf *m; 2362#if __FreeBSD_version < 502120 2363 meta_p meta; 2364#else 2365 struct ng_tag_prio *ptag; 2366#endif 2367#else 2368static int ng_ce_rcvdata (hook_p hook, struct mbuf *m, meta_p meta) 2369{ 2370 drv_t *d = hook->node->private; 2371#endif 2372 bdrv_t *bd = d->board->sys; 2373 struct ifqueue *q; 2374 int s; 2375 2376 CE_DEBUG2 (d, ("Rcvdata\n")); 2377#if __FreeBSD_version >= 500000 2378 NGI_GET_M (item, m); 2379#if __FreeBSD_version < 502120 2380 NGI_GET_META (item, meta); 2381#endif 2382 NG_FREE_ITEM (item); 2383 if (! NG_HOOK_PRIVATE (hook) || ! d) { 2384 NG_FREE_M (m); 2385#if __FreeBSD_version < 502120 2386 NG_FREE_META (meta); 2387#endif 2388#else 2389 if (! hook->private || ! d) { 2390 NG_FREE_DATA (m,meta); 2391#endif 2392 return ENETDOWN; 2393 } 2394 2395#if __FreeBSD_version >= 502120 2396 /* Check for high priority data */ 2397 if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE, 2398 NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) ) 2399 q = &d->hi_queue; 2400 else 2401 q = &d->queue; 2402#else 2403 q = (meta && meta->priority > 0) ? &d->hi_queue : &d->queue; 2404#endif 2405 2406 s = splimp (); 2407 CE_LOCK (bd); 2408#if __FreeBSD_version >= 500000 2409 IF_LOCK (q); 2410 if (_IF_QFULL (q)) { 2411 _IF_DROP (q); 2412 IF_UNLOCK (q); 2413 CE_UNLOCK (bd); 2414 splx (s); 2415 NG_FREE_M (m); 2416#if __FreeBSD_version < 502120 2417 NG_FREE_META (meta); 2418#endif 2419 return ENOBUFS; 2420 } 2421 _IF_ENQUEUE (q, m); 2422 IF_UNLOCK (q); 2423#else 2424 if (IF_QFULL (q)) { 2425 IF_DROP (q); 2426 CE_UNLOCK (bd); 2427 splx (s); 2428 NG_FREE_DATA (m, meta); 2429 return ENOBUFS; 2430 } 2431 IF_ENQUEUE (q, m); 2432#endif 2433 ce_start (d); 2434 CE_UNLOCK (bd); 2435 splx (s); 2436 return 0; 2437} 2438 2439static int ng_ce_rmnode (node_p node) 2440{ 2441#if __FreeBSD_version >= 500000 2442 drv_t *d = NG_NODE_PRIVATE (node); 2443 2444 CE_DEBUG (d, ("Rmnode\n")); 2445 if (d && d->running) { 2446 bdrv_t *bd = d->board->sys; 2447 int s = splimp (); 2448 CE_LOCK (bd); 2449 ce_down (d); 2450 CE_UNLOCK (bd); 2451 splx (s); 2452 } 2453#ifdef KLD_MODULE 2454#if __FreeBSD_version >= 502120 2455 if (node->nd_flags & NGF_REALLY_DIE) { 2456#else 2457 if (node->nd_flags & NG_REALLY_DIE) { 2458#endif 2459 NG_NODE_SET_PRIVATE (node, NULL); 2460 NG_NODE_UNREF (node); 2461 } 2462#if __FreeBSD_version >= 502120 2463 NG_NODE_REVIVE(node); /* Persistant node */ 2464#else 2465 node->nd_flags &= ~NG_INVALID; 2466#endif 2467#endif 2468#else /* __FreeBSD_version < 500000 */ 2469 drv_t *d = node->private; 2470 2471 if (d && d->running) { 2472 bdrv_t *bd = d->board->sys; 2473 int s = splimp (); 2474 CE_LOCK (bd); 2475 ce_down (d); 2476 CE_UNLOCK (bd); 2477 splx (s); 2478 } 2479 2480 node->flags |= NG_INVALID; 2481 ng_cutlinks (node); 2482#ifdef KLD_MODULE 2483 ng_unname (node); 2484 ng_unref (node); 2485#endif 2486#endif 2487 return 0; 2488} 2489 2490static int ng_ce_connect (hook_p hook) 2491{ 2492#if __FreeBSD_version >= 500000 2493 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2494#else 2495 drv_t *d = hook->node->private; 2496#endif 2497 2498 if (d) { 2499 CE_DEBUG (d, ("Connect\n")); 2500 callout_reset (&d->timeout_handle, hz, ce_watchdog_timer, d); 2501 } 2502 2503 return 0; 2504} 2505 2506static int ng_ce_disconnect (hook_p hook) 2507{ 2508#if __FreeBSD_version >= 500000 2509 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2510#else 2511 drv_t *d = hook->node->private; 2512#endif 2513 2514 if (d) { 2515 CE_DEBUG (d, ("Disconnect\n")); 2516#if __FreeBSD_version >= 500000 2517 if (NG_HOOK_PRIVATE (hook)) 2518#else 2519 if (hook->private) 2520#endif 2521 { 2522 bdrv_t *bd = d->board->sys; 2523 int s = splimp (); 2524 CE_LOCK (bd); 2525 ce_down (d); 2526 CE_UNLOCK (bd); 2527 splx (s); 2528 } 2529 /* If we were wait it than it reasserted now, just stop it. */ 2530 if (!callout_drain (&d->timeout_handle)) 2531 callout_stop (&d->timeout_handle); 2532 } 2533 return 0; 2534} 2535#endif 2536 2537static int ce_modevent (module_t mod, int type, void *unused) 2538{ 2539#if __FreeBSD_version < 500000 2540 dev_t dev; 2541 struct cdevsw *cdsw; 2542#endif 2543 static int load_count = 0; 2544 2545#if __FreeBSD_version < 500000 2546 dev = makedev (CDEV_MAJOR, 0); 2547#endif 2548 2549 switch (type) { 2550 case MOD_LOAD: 2551#if __FreeBSD_version < 500000 2552 if (dev != NODEV && 2553 (cdsw = devsw (dev)) && 2554 cdsw->d_maj == CDEV_MAJOR) { 2555 printf ("Tau32-PCI driver is already in system\n"); 2556 return (ENXIO); 2557 } 2558#endif 2559#if __FreeBSD_version >= 500000 && defined NETGRAPH 2560 if (ng_newtype (&typestruct)) 2561 printf ("Failed to register ng_ce\n"); 2562#endif 2563 ++load_count; 2564#if __FreeBSD_version <= 500000 2565 cdevsw_add (&ce_cdevsw); 2566#endif 2567#if __FreeBSD_version >= 500000 2568 callout_init (&timeout_handle, CALLOUT_MPSAFE); 2569#else 2570 callout_init (&timeout_handle); 2571#endif 2572 callout_reset (&timeout_handle, hz*5, ce_timeout, 0); 2573 break; 2574 case MOD_UNLOAD: 2575 if (load_count == 1) { 2576 printf ("Removing device entry for Tau32-PCI\n"); 2577#if __FreeBSD_version <= 500000 2578 cdevsw_remove (&ce_cdevsw); 2579#endif 2580#if __FreeBSD_version >= 500000 && defined NETGRAPH 2581 ng_rmtype (&typestruct); 2582#endif 2583 } 2584 /* If we were wait it than it reasserted now, just stop it. 2585 * Actually we shouldn't get this condition. But code could be 2586 * changed in the future, so just be a litle paranoid. 2587 */ 2588 if (!callout_drain (&timeout_handle)) 2589 callout_stop (&timeout_handle); 2590 --load_count; 2591 break; 2592 case MOD_SHUTDOWN: 2593 break; 2594 } 2595 return 0; 2596} 2597 2598#ifdef NETGRAPH 2599#if __FreeBSD_version >= 502100 2600static struct ng_type typestruct = { 2601 .version = NG_ABI_VERSION, 2602 .name = NG_CE_NODE_TYPE, 2603 .constructor = ng_ce_constructor, 2604 .rcvmsg = ng_ce_rcvmsg, 2605 .shutdown = ng_ce_rmnode, 2606 .newhook = ng_ce_newhook, 2607 .connect = ng_ce_connect, 2608 .rcvdata = ng_ce_rcvdata, 2609 .disconnect = ng_ce_disconnect, 2610}; 2611#else /* __FreeBSD_version < 502100 */ 2612static struct ng_type typestruct = { 2613#if __FreeBSD_version >= 500000 2614 NG_ABI_VERSION, 2615#else 2616 NG_VERSION, 2617#endif 2618 NG_CE_NODE_TYPE, 2619 ce_modevent, 2620 ng_ce_constructor, 2621 ng_ce_rcvmsg, 2622 ng_ce_rmnode, 2623 ng_ce_newhook, 2624 NULL, 2625 ng_ce_connect, 2626 ng_ce_rcvdata, 2627#if __FreeBSD_version < 500000 2628 NULL, 2629#endif 2630 ng_ce_disconnect, 2631 NULL 2632}; 2633#endif /* __FreeBSD_version < 502100 */ 2634 2635#endif /*NETGRAPH*/ 2636 2637#if __FreeBSD_version >= 500000 2638#ifdef NETGRAPH 2639MODULE_DEPEND (ng_ce, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 2640#else 2641MODULE_DEPEND (ce, sppp, 1, 1, 1); 2642#endif 2643#ifdef KLD_MODULE 2644DRIVER_MODULE (cemod, pci, ce_driver, ce_devclass, ce_modevent, NULL); 2645#else 2646DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ce_modevent, NULL); 2647#endif 2648#else /* if __FreeBSD_version < 500000*/ 2649#ifdef NETGRAPH 2650DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ng_mod_event, &typestruct); 2651#else 2652DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ce_modevent, NULL); 2653#endif 2654#endif /* __FreeBSD_version < 500000 */ 2655#endif /* NPCI */ 2656