if_cp.c revision 129837
1193326Sed/* 2193326Sed * Cronyx-Tau-PCI adapter driver for FreeBSD. 3193326Sed * Supports PPP/HDLC, Cisco/HDLC and FrameRelay protocol in synchronous mode, 4193326Sed * and asyncronous channels with full modem control. 5193326Sed * Keepalive protocol implemented in both Cisco and PPP modes. 6193326Sed * 7193326Sed * Copyright (C) 1999-2004 Cronyx Engineering. 8193326Sed * Author: Kurakin Roman, <rik@cronyx.ru> 9193326Sed * 10193326Sed * Copyright (C) 1999-2002 Cronyx Engineering. 11193326Sed * Author: Serge Vakulenko, <vak@cronyx.ru> 12193326Sed * 13193326Sed * This software is distributed with NO WARRANTIES, not even the implied 14193326Sed * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15193326Sed * 16198092Srdivacky * Authors grant any other persons or organisations a permission to use, 17193326Sed * modify and redistribute this software in source and binary forms, 18193326Sed * as long as this message is kept with the software, all derivative 19234353Sdim * works or modified versions. 20193326Sed * 21193326Sed * $Cronyx: if_cp.c,v 1.1.2.32 2004/02/26 17:56:39 rik Exp $ 22193326Sed */ 23193326Sed 24193326Sed#include <sys/cdefs.h> 25193326Sed__FBSDID("$FreeBSD: head/sys/dev/cp/if_cp.c 129837 2004-05-29 13:17:28Z rik $"); 26193326Sed 27193326Sed#include <sys/param.h> 28193326Sed 29193326Sed#if __FreeBSD_version >= 500000 30193326Sed# define NPCI 1 31193326Sed#else 32193326Sed# include "pci.h" 33199990Srdivacky#endif 34193326Sed 35193326Sed#if NPCI > 0 36218893Sdim 37208600Srdivacky#include <sys/ucred.h> 38226633Sdim#include <sys/proc.h> 39226633Sdim#include <sys/systm.h> 40226633Sdim#include <sys/mbuf.h> 41226633Sdim#include <sys/kernel.h> 42226633Sdim#include <sys/conf.h> 43226633Sdim#include <sys/malloc.h> 44226633Sdim#include <sys/socket.h> 45226633Sdim#include <sys/sockio.h> 46226633Sdim#include <sys/tty.h> 47208600Srdivacky#if __FreeBSD_version >= 400000 48226633Sdim# include <sys/bus.h> 49226633Sdim#endif 50208600Srdivacky#include <vm/vm.h> 51218893Sdim#include <vm/pmap.h> 52208600Srdivacky#include <net/if.h> 53208600Srdivacky#if __FreeBSD_version > 501000 54218893Sdim# include <dev/pci/pcivar.h> 55218893Sdim# include <dev/pci/pcireg.h> 56218893Sdim#else 57218893Sdim# include <pci/pcivar.h> 58239462Sdim# include <pci/pcireg.h> 59239462Sdim#endif 60239462Sdim#include <machine/bus.h> 61239462Sdim#include <sys/rman.h> 62218893Sdim#include "opt_ng_cronyx.h" 63193326Sed#ifdef NETGRAPH_CRONYX 64239462Sdim# include "opt_netgraph.h" 65239462Sdim# ifndef NETGRAPH 66193326Sed# error #option NETGRAPH missed from configuration 67193326Sed# endif 68193326Sed# include <netgraph/ng_message.h> 69193326Sed# include <netgraph/netgraph.h> 70193326Sed# if __FreeBSD_version >= 500000 71193326Sed# include <dev/cp/ng_cp.h> 72193326Sed# else 73193326Sed# include <netgraph/ng_cp.h> 74193326Sed# endif 75193326Sed#else 76193326Sed# include <net/if_sppp.h> 77193326Sed# define PP_CISCO IFF_LINK2 78239462Sdim# if __FreeBSD_version < 400000 79239462Sdim# include <bpfilter.h> 80239462Sdim# if NBPFILTER > 0 81239462Sdim# include <net/bpf.h> 82239462Sdim# endif 83193326Sed# else 84226633Sdim# if __FreeBSD_version < 500000 85208600Srdivacky# include <bpf.h> 86234353Sdim# endif 87234353Sdim# include <net/bpf.h> 88234353Sdim# define NBPFILTER NBPF 89234353Sdim#endif 90226633Sdim#endif 91234353Sdim#if __FreeBSD_version >= 500000 92226633Sdim#include <dev/cx/machdep.h> 93226633Sdim#include <dev/cp/cpddk.h> 94226633Sdim#else 95226633Sdim#include <i386/isa/cronyx/machdep.h> 96208600Srdivacky#include <pci/cpddk.h> 97208600Srdivacky#endif 98193326Sed#include <machine/cserial.h> 99193326Sed#include <machine/resource.h> 100193326Sed#include <machine/pmap.h> 101198092Srdivacky 102193326Sed/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */ 103193326Sed#ifndef PP_FR 104193326Sed#define PP_FR 0 105193326Sed#endif 106221345Sdim 107221345Sdim#define CP_DEBUG(d,s) ({if (d->chan->debug) {\ 108221345Sdim printf ("%s: ", d->name); printf s;}}) 109193326Sed#define CP_DEBUG2(d,s) ({if (d->chan->debug>1) {\ 110224145Sdim printf ("%s: ", d->name); printf s;}}) 111224145Sdim 112224145Sdim#define CDEV_MAJOR 134 113193326Sed 114193326Sed#if __FreeBSD_version >= 400000 115234353Sdimstatic int cp_probe __P((device_t)); 116234353Sdimstatic int cp_attach __P((device_t)); 117234353Sdimstatic int cp_detach __P((device_t)); 118234353Sdim 119234353Sdimstatic device_method_t cp_methods[] = { 120234353Sdim /* Device interface */ 121234353Sdim DEVMETHOD(device_probe, cp_probe), 122234353Sdim DEVMETHOD(device_attach, cp_attach), 123234353Sdim DEVMETHOD(device_detach, cp_detach), 124234353Sdim 125239462Sdim {0, 0} 126234353Sdim}; 127234353Sdim 128234353Sdimtypedef struct _bdrv_t { 129234353Sdim cp_board_t *board; 130234353Sdim struct resource *cp_res; 131234353Sdim struct resource *cp_irq; 132234353Sdim void *cp_intrhand; 133193326Sed} bdrv_t; 134193326Sed 135193326Sedstatic driver_t cp_driver = { 136224145Sdim "cp", 137193326Sed cp_methods, 138193326Sed sizeof(bdrv_t), 139193326Sed}; 140193326Sed 141198092Srdivackystatic devclass_t cp_devclass; 142193326Sed#endif 143198092Srdivacky 144193326Sedtypedef struct _drv_t { 145198092Srdivacky char name [8]; 146193326Sed cp_chan_t *chan; 147193326Sed cp_board_t *board; 148193326Sed cp_buf_t buf; 149198398Srdivacky int running; 150193326Sed#ifdef NETGRAPH 151193326Sed char nodename [NG_NODELEN+1]; 152193326Sed hook_p hook; 153193326Sed hook_p debug_hook; 154193326Sed node_p node; 155193326Sed struct ifqueue queue; 156193326Sed struct ifqueue hi_queue; 157198092Srdivacky short timeout; 158218893Sdim struct callout_handle timeout_handle; 159198092Srdivacky#else 160193326Sed struct sppp pp; 161201361Srdivacky#endif 162193326Sed#if __FreeBSD_version >= 400000 163193326Sed dev_t devt; 164193326Sed#endif 165193326Sed} drv_t; 166193326Sed 167234353Sdimstatic void cp_receive (cp_chan_t *c, unsigned char *data, int len); 168218893Sdimstatic void cp_transmit (cp_chan_t *c, void *attachment, int len); 169210299Sedstatic void cp_error (cp_chan_t *c, int data); 170199482Srdivackystatic void cp_up (drv_t *d); 171224145Sdimstatic void cp_start (drv_t *d); 172218893Sdimstatic void cp_down (drv_t *d); 173218893Sdimstatic void cp_watchdog (drv_t *d); 174234353Sdim#ifdef NETGRAPH 175234353Sdimextern struct ng_type typestruct; 176234353Sdim#else 177239462Sdimstatic void cp_ifstart (struct ifnet *ifp); 178234353Sdimstatic void cp_tlf (struct sppp *sp); 179234353Sdimstatic void cp_tls (struct sppp *sp); 180234353Sdimstatic void cp_ifwatchdog (struct ifnet *ifp); 181234353Sdimstatic int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 182234353Sdimstatic void cp_initialize (void *softc); 183193326Sed#endif 184193326Sed 185224145Sdimstatic cp_board_t *adapter [NBRD]; 186224145Sdimstatic drv_t *channel [NBRD*NCHAN]; 187193326Sedstatic cp_qbuf_t *queue [NBRD]; 188200583Srdivackystatic struct callout_handle led_timo [NBRD]; 189226633Sdimstatic struct callout_handle timeout_handle; 190226633Sdim 191226633Sdimstatic int cp_destroy = 0; 192193326Sed 193193326Sed/* 194193326Sed * Print the mbuf chain, for debug purposes only. 195193326Sed */ 196193326Sedstatic void printmbuf (struct mbuf *m) 197193326Sed{ 198193326Sed printf ("mbuf:"); 199193326Sed for (; m; m=m->m_next) { 200193326Sed if (m->m_flags & M_PKTHDR) 201193326Sed printf (" HDR %d:", m->m_pkthdr.len); 202193326Sed if (m->m_flags & M_EXT) 203193326Sed printf (" EXT:"); 204239462Sdim printf (" %d", m->m_len); 205193326Sed } 206193326Sed printf ("\n"); 207208600Srdivacky} 208208600Srdivacky 209208600Srdivacky/* 210208600Srdivacky * Make an mbuf from data. 211208600Srdivacky */ 212208600Srdivackystatic struct mbuf *makembuf (void *buf, unsigned len) 213208600Srdivacky{ 214208600Srdivacky struct mbuf *m; 215208600Srdivacky 216208600Srdivacky MGETHDR (m, M_DONTWAIT, MT_DATA); 217208600Srdivacky if (! m) 218208600Srdivacky return 0; 219208600Srdivacky MCLGET (m, M_DONTWAIT); 220208600Srdivacky if (! (m->m_flags & M_EXT)) { 221208600Srdivacky m_freem (m); 222208600Srdivacky return 0; 223208600Srdivacky } 224226633Sdim m->m_pkthdr.len = m->m_len = len; 225226633Sdim bcopy (buf, mtod (m, caddr_t), len); 226208600Srdivacky return m; 227208600Srdivacky} 228208600Srdivacky 229226633Sdim#if __FreeBSD_version < 400000 230226633Sdimstatic const char *cp_probe (pcici_t tag, pcidi_t type) 231226633Sdim{ 232226633Sdim if (tag->vendor == cp_vendor_id && tag->device == cp_device_id) 233226633Sdim return "Cronyx-Tau-PCI serial adapter"; 234239462Sdim return 0; 235226633Sdim} 236226633Sdim#else 237226633Sdimstatic int cp_probe (device_t dev) 238226633Sdim{ 239226633Sdim if ((pci_get_vendor (dev) == cp_vendor_id) && 240210299Sed (pci_get_device (dev) == cp_device_id)) { 241226633Sdim device_set_desc (dev, "Cronyx-Tau-PCI serial adapter"); 242239462Sdim return 0; 243239462Sdim } 244239462Sdim return ENXIO; 245234982Sdim} 246239462Sdim#endif 247208600Srdivacky 248208600Srdivackystatic void cp_timeout (void *arg) 249193326Sed{ 250239462Sdim drv_t *d; 251239462Sdim int s, i; 252239462Sdim 253239462Sdim for (i=0; i<NBRD*NCHAN; ++i) { 254239462Sdim s = splimp (); 255239462Sdim if (cp_destroy) { 256193326Sed splx (s); 257239462Sdim return; 258239462Sdim } 259218893Sdim d = channel[i]; 260239462Sdim if (!d) { 261239462Sdim splx (s); 262239462Sdim continue; 263239462Sdim } 264239462Sdim switch (d->chan->type) { 265212904Sdim case T_G703: 266239462Sdim cp_g703_timer (d->chan); 267239462Sdim break; 268239462Sdim case T_E1: 269239462Sdim cp_e1_timer (d->chan); 270239462Sdim break; 271193326Sed case T_E3: 272239462Sdim case T_T3: 273239462Sdim case T_STS1: 274239462Sdim cp_e3_timer (d->chan); 275239462Sdim break; 276239462Sdim default: 277239462Sdim break; 278239462Sdim } 279239462Sdim splx (s); 280239462Sdim } 281198092Srdivacky s = splimp (); 282239462Sdim if (!cp_destroy) 283239462Sdim timeout_handle = timeout (cp_timeout, 0, hz); 284239462Sdim splx (s); 285198092Srdivacky} 286198092Srdivacky 287239462Sdimstatic void cp_led_off (void *arg) 288193326Sed{ 289239462Sdim cp_board_t *b = arg; 290239462Sdim int s = splimp (); 291239462Sdim if (cp_destroy) { 292239462Sdim splx (s); 293239462Sdim return; 294193326Sed } 295193326Sed cp_led (b, 0); 296234353Sdim led_timo[b->num].callout = 0; 297234353Sdim splx (s); 298234353Sdim} 299234353Sdim 300234353Sdimstatic void cp_intr (void *arg) 301234353Sdim{ 302234353Sdim#if __FreeBSD_version < 400000 303234353Sdim cp_board_t *b = arg; 304234353Sdim#else 305234353Sdim bdrv_t *bd = arg; 306234353Sdim cp_board_t *b = bd->board; 307234353Sdim#endif 308234353Sdim int s = splimp (); 309234353Sdim if (cp_destroy) { 310234353Sdim splx (s); 311234353Sdim return; 312234353Sdim } 313234353Sdim /* Turn LED on. */ 314234353Sdim cp_led (b, 1); 315234353Sdim 316234353Sdim cp_interrupt (b); 317234353Sdim 318234353Sdim /* Turn LED off 50 msec later. */ 319234353Sdim if (!led_timo[b->num].callout) 320234353Sdim led_timo[b->num] = timeout (cp_led_off, b, hz/20); 321234353Sdim splx (s); 322234353Sdim} 323234353Sdim 324234353Sdimextern struct cdevsw cp_cdevsw; 325234353Sdim 326234353Sdim/* 327234353Sdim * Called if the probe succeeded. 328234353Sdim */ 329234353Sdim#if __FreeBSD_version < 400000 330234353Sdimstatic void cp_attach (pcici_t tag, int unit) 331234353Sdim{ 332234353Sdim vm_offset_t pbase; 333234353Sdim#else 334234353Sdimstatic int cp_attach (device_t dev) 335234353Sdim{ 336234353Sdim bdrv_t *bd = device_get_softc (dev); 337234353Sdim int unit = device_get_unit (dev); 338234353Sdim int rid, error; 339234353Sdim#endif 340234353Sdim vm_offset_t vbase; 341234353Sdim cp_board_t *b; 342234353Sdim cp_chan_t *c; 343234353Sdim drv_t *d; 344234353Sdim unsigned short res; 345234353Sdim int s = splimp (); 346234353Sdim 347234353Sdim b = malloc (sizeof(cp_board_t), M_DEVBUF, M_WAITOK); 348234353Sdim if (!b) { 349234353Sdim printf ("cp%d: couldn't allocate memory\n", unit); 350234353Sdim#if __FreeBSD_version < 400000 351234353Sdim splx (s); 352234353Sdim return; 353234353Sdim#else 354234982Sdim splx (s); 355234982Sdim return (ENXIO); 356234353Sdim#endif 357234353Sdim } 358234353Sdim adapter[unit] = b; 359234353Sdim bzero (b, sizeof(cp_board_t)); 360234353Sdim 361234353Sdim#if __FreeBSD_version < 400000 362234353Sdim if (! pci_map_mem (tag, PCIR_MAPS, &vbase, &pbase)) { 363234353Sdim printf ("cp%d: cannot map memory\n", unit); 364234982Sdim free (b, M_DEVBUF); 365234353Sdim splx (s); 366234353Sdim return; 367234353Sdim } 368234353Sdim#else 369234353Sdim bd->board = b; 370234353Sdim b->sys = bd; 371234353Sdim rid = PCIR_BAR(0); 372234353Sdim bd->cp_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid, 373234353Sdim 0, ~0, 1, RF_ACTIVE); 374234353Sdim if (! bd->cp_res) { 375234353Sdim printf ("cp%d: cannot map memory\n", unit); 376234353Sdim free (b, M_DEVBUF); 377234353Sdim splx (s); 378234353Sdim return (ENXIO); 379234353Sdim } 380234353Sdim vbase = (vm_offset_t) rman_get_virtual (bd->cp_res); 381234353Sdim#endif 382234353Sdim 383234353Sdim res = cp_init (b, unit, (u_char*) vbase); 384234353Sdim if (res) { 385234353Sdim printf ("cp%d: can't init, error code:%x\n", unit, res); 386234353Sdim#if __FreeBSD_version >= 400000 387234353Sdim bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); 388234353Sdim#endif 389234353Sdim free (b, M_DEVBUF); 390234353Sdim splx (s); 391234353Sdim#if __FreeBSD_version >= 400000 392234353Sdim return (ENXIO); 393234353Sdim#else 394234353Sdim return; 395234353Sdim#endif 396234353Sdim } 397234353Sdim queue[unit] = contigmalloc (sizeof(cp_qbuf_t), M_DEVBUF, M_WAITOK, 398234353Sdim 0x100000, 0xffffffff, 16, 0); 399234353Sdim if (queue[unit] == NULL) { 400234353Sdim printf ("cp%d: allocate memory for qbuf_t\n", unit); 401234353Sdim free (b, M_DEVBUF); 402234353Sdim splx (s); 403234353Sdim#if __FreeBSD_version >= 400000 404234353Sdim return (ENXIO); 405234353Sdim#else 406234353Sdim return; 407234353Sdim#endif 408234353Sdim } 409234353Sdim cp_reset (b, queue[unit], vtophys (queue[unit])); 410234353Sdim 411234353Sdim#if __FreeBSD_version < 400000 412234353Sdim if (! pci_map_int (tag, cp_intr, b, &net_imask)) 413234353Sdim printf ("cp%d: cannot map interrupt\n", unit); 414234353Sdim#else 415234353Sdim rid = 0; 416234353Sdim bd->cp_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 417234353Sdim RF_SHAREABLE | RF_ACTIVE); 418234353Sdim if (! bd->cp_irq) { 419234353Sdim printf ("cp%d: cannot map interrupt\n", unit); 420234353Sdim bus_release_resource (dev, SYS_RES_MEMORY, 421234353Sdim PCIR_BAR(0), bd->cp_res); 422234353Sdim free (b, M_DEVBUF); 423234353Sdim splx (s); 424234353Sdim return (ENXIO); 425234353Sdim } 426234353Sdim error = bus_setup_intr (dev, bd->cp_irq, INTR_TYPE_NET, cp_intr, bd, 427234353Sdim &bd->cp_intrhand); 428234353Sdim if (error) { 429234353Sdim printf ("cp%d: cannot set up irq\n", unit); 430234353Sdim bus_release_resource (dev, SYS_RES_MEMORY, 431234353Sdim PCIR_BAR(0), bd->cp_res); 432234353Sdim bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); 433234353Sdim free (b, M_DEVBUF); 434234353Sdim splx (s); 435234353Sdim return (ENXIO); 436234353Sdim } 437234353Sdim#endif 438234353Sdim printf ("cp%d: %s, clock %ld MHz\n", unit, b->name, b->osc / 1000000); 439234353Sdim 440234353Sdim for (c=b->chan; c<b->chan+NCHAN; ++c) { 441234353Sdim if (! c->type) 442234353Sdim continue; 443234353Sdim d = contigmalloc (sizeof(drv_t), M_DEVBUF, M_WAITOK, 444234353Sdim 0x100000, 0xffffffff, 16, 0); 445234353Sdim if (d == NULL) { 446234353Sdim printf ("cp%d-%d: cannot allocate memory for drv_t\n", 447234353Sdim unit, c->num); 448234353Sdim } 449234353Sdim channel [b->num*NCHAN + c->num] = d; 450234353Sdim bzero (d, sizeof(drv_t)); 451234353Sdim sprintf (d->name, "cp%d.%d", b->num, c->num); 452234353Sdim d->board = b; 453234353Sdim d->chan = c; 454234353Sdim c->sys = d; 455234353Sdim#ifdef NETGRAPH 456234353Sdim if (ng_make_node_common (&typestruct, &d->node) != 0) { 457234353Sdim printf ("%s: cannot make common node\n", d->name); 458234353Sdim d->node = NULL; 459234353Sdim continue; 460234353Sdim } 461234353Sdim#if __FreeBSD_version >= 500000 462234353Sdim NG_NODE_SET_PRIVATE (d->node, d); 463234353Sdim#else 464234353Sdim d->node->private = d; 465234353Sdim#endif 466234353Sdim sprintf (d->nodename, "%s%d", NG_CP_NODE_TYPE, 467234353Sdim c->board->num*NCHAN + c->num); 468234353Sdim if (ng_name_node (d->node, d->nodename)) { 469234353Sdim printf ("%s: cannot name node\n", d->nodename); 470234353Sdim#if __FreeBSD_version >= 500000 471234353Sdim NG_NODE_UNREF (d->node); 472234353Sdim#else 473234353Sdim ng_rmnode (d->node); 474234353Sdim ng_unref (d->node); 475234353Sdim#endif 476234353Sdim continue; 477234353Sdim } 478234353Sdim d->queue.ifq_maxlen = IFQ_MAXLEN; 479234353Sdim d->hi_queue.ifq_maxlen = IFQ_MAXLEN; 480234353Sdim#if __FreeBSD_version >= 500000 481234353Sdim mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); 482234353Sdim mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF); 483234353Sdim#endif 484234353Sdim#else /*NETGRAPH*/ 485234353Sdim d->pp.pp_if.if_softc = d; 486234353Sdim#if __FreeBSD_version > 501000 487234353Sdim if_initname (&d->pp.pp_if, "cp", b->num * NCHAN + c->num); 488234353Sdim#else 489234353Sdim d->pp.pp_if.if_unit = b->num * NCHAN + c->num; 490234353Sdim d->pp.pp_if.if_name = "cp"; 491234353Sdim#endif 492234353Sdim d->pp.pp_if.if_mtu = PP_MTU; 493234353Sdim d->pp.pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 494234353Sdim d->pp.pp_if.if_ioctl = cp_sioctl; 495234353Sdim d->pp.pp_if.if_start = cp_ifstart; 496234353Sdim d->pp.pp_if.if_watchdog = cp_ifwatchdog; 497234353Sdim d->pp.pp_if.if_init = cp_initialize; 498234353Sdim sppp_attach (&d->pp.pp_if); 499234353Sdim if_attach (&d->pp.pp_if); 500234353Sdim d->pp.pp_tlf = cp_tlf; 501234353Sdim d->pp.pp_tls = cp_tls; 502234353Sdim#if __FreeBSD_version >= 400000 || NBPFILTER > 0 503234353Sdim /* If BPF is in the kernel, call the attach for it. 504234353Sdim * The header size of PPP or Cisco/HDLC is 4 bytes. */ 505234353Sdim bpfattach (&d->pp.pp_if, DLT_PPP, 4); 506234353Sdim#endif 507234353Sdim#endif /*NETGRAPH*/ 508234353Sdim cp_start_e1 (c); 509234353Sdim cp_start_chan (c, 1, 1, &d->buf, vtophys (&d->buf)); 510234353Sdim 511234353Sdim /* Register callback functions. */ 512234353Sdim cp_register_transmit (c, &cp_transmit); 513234353Sdim cp_register_receive (c, &cp_receive); 514234353Sdim cp_register_error (c, &cp_error); 515234353Sdim#if __FreeBSD_version >= 400000 516234353Sdim d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT, 517234353Sdim GID_WHEEL, 0600, "cp%d", b->num*NCHAN+c->num); 518234353Sdim#endif 519234353Sdim } 520193326Sed splx (s); 521193326Sed#if __FreeBSD_version >= 400000 522193326Sed return 0; 523193326Sed#endif 524224145Sdim} 525224145Sdim 526224145Sdim#if __FreeBSD_version >= 400000 527224145Sdimstatic int cp_detach (device_t dev) 528218893Sdim{ 529239462Sdim bdrv_t *bd = device_get_softc (dev); 530218893Sdim cp_board_t *b = bd->board; 531218893Sdim cp_chan_t *c; 532224145Sdim int s = splimp (); 533224145Sdim 534224145Sdim /* Check if the device is busy (open). */ 535224145Sdim for (c=b->chan; c<b->chan+NCHAN; ++c) { 536224145Sdim drv_t *d = (drv_t*) c->sys; 537224145Sdim 538224145Sdim if (! d || ! d->chan->type) 539224145Sdim continue; 540224145Sdim if (d->running) { 541224145Sdim splx (s); 542224145Sdim return EBUSY; 543224145Sdim } 544224145Sdim } 545224145Sdim 546224145Sdim /* Ok, we can unload driver */ 547224145Sdim /* At first we should stop all channels */ 548224145Sdim for (c=b->chan; c<b->chan+NCHAN; ++c) { 549198092Srdivacky drv_t *d = (drv_t*) c->sys; 550198092Srdivacky 551212904Sdim if (! d || ! d->chan->type) 552208600Srdivacky continue; 553208600Srdivacky 554208600Srdivacky cp_stop_chan (c); 555208600Srdivacky cp_stop_e1 (c); 556208600Srdivacky cp_set_dtr (d->chan, 0); 557208600Srdivacky cp_set_rts (d->chan, 0); 558208600Srdivacky } 559208600Srdivacky 560218893Sdim /* Reset the adapter. */ 561218893Sdim cp_destroy = 1; 562208600Srdivacky cp_interrupt_poll (b, 1); 563208600Srdivacky cp_led_off (b); 564208600Srdivacky cp_reset (b, 0 ,0); 565212904Sdim if (led_timo[b->num].callout) 566221345Sdim untimeout (cp_led_off, b, led_timo[b->num]); 567221345Sdim 568198092Srdivacky for (c=b->chan; c<b->chan+NCHAN; ++c) { 569212904Sdim drv_t *d = (drv_t*) c->sys; 570212904Sdim 571218893Sdim if (! d || ! d->chan->type) 572193401Sed continue; 573224145Sdim#ifndef NETGRAPH 574224145Sdim#if __FreeBSD_version >= 410000 && NBPFILTER > 0 575198092Srdivacky /* Detach from the packet filter list of interfaces. */ 576193326Sed bpfdetach (&d->pp.pp_if); 577193326Sed#endif 578212904Sdim /* Detach from the sync PPP list. */ 579212904Sdim sppp_detach (&d->pp.pp_if); 580212904Sdim 581226633Sdim /* Detach from the system list of interfaces. */ 582208600Srdivacky if_detach (&d->pp.pp_if); 583208600Srdivacky#else 584208600Srdivacky#if __FreeBSD_version >= 500000 585239462Sdim if (d->node) { 586239462Sdim ng_rmnode_self (d->node); 587239462Sdim NG_NODE_UNREF (d->node); 588239462Sdim d->node = NULL; 589239462Sdim } 590239462Sdim mtx_destroy (&d->queue.ifq_mtx); 591239462Sdim mtx_destroy (&d->hi_queue.ifq_mtx); 592239462Sdim#else 593239462Sdim ng_rmnode (d->node); 594212904Sdim d->node = 0; 595234353Sdim#endif 596234353Sdim#endif 597212904Sdim destroy_dev (d->devt); 598212904Sdim } 599198092Srdivacky 600198092Srdivacky /* Disable the interrupt request. */ 601198092Srdivacky bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand); 602198092Srdivacky bus_deactivate_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); 603198092Srdivacky bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); 604218893Sdim bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); 605212904Sdim cp_led_off (b); 606218893Sdim if (led_timo[b->num].callout) 607221345Sdim untimeout (cp_led_off, b, led_timo[b->num]); 608218893Sdim splx (s); 609218893Sdim 610218893Sdim s = splimp (); 611218893Sdim for (c=b->chan; c<b->chan+NCHAN; ++c) { 612218893Sdim drv_t *d = (drv_t*) c->sys; 613218893Sdim 614218893Sdim if (! d || ! d->chan->type) 615218893Sdim continue; 616218893Sdim channel [b->num*NCHAN + c->num] = 0; 617234353Sdim /* Deallocate buffers. */ 618218893Sdim#if __FreeBSD_version < 400000 619218893Sdim free (d, M_DEVBUF); 620218893Sdim#else 621218893Sdim contigfree (d, sizeof (*d), M_DEVBUF); 622218893Sdim#endif 623218893Sdim } 624218893Sdim adapter [b->num] = 0; 625218893Sdim#if __FreeBSD_version < 400000 626218893Sdim free (queue[b->num], M_DEVBUF); 627218893Sdim#else 628218893Sdim contigfree (queue[b->num], sizeof (cp_qbuf_t), M_DEVBUF); 629226633Sdim#endif 630226633Sdim free (b, M_DEVBUF); 631218893Sdim splx (s); 632218893Sdim return 0; 633218893Sdim} 634218893Sdim#endif 635218893Sdim 636218893Sdim#if __FreeBSD_version < 400000 637218893Sdimstatic u_long cp_count; 638218893Sdimstatic struct pci_device cp_driver = {"cp", cp_probe, cp_attach, &cp_count, 0}; 639218893SdimDATA_SET (pcidevice_set, cp_driver); 640218893Sdim#endif 641218893Sdim 642218893Sdim#ifndef NETGRAPH 643226633Sdimstatic void cp_ifstart (struct ifnet *ifp) 644226633Sdim{ 645226633Sdim drv_t *d = ifp->if_softc; 646226633Sdim 647234353Sdim cp_start (d); 648218893Sdim} 649198398Srdivacky 650193326Sedstatic void cp_ifwatchdog (struct ifnet *ifp) 651193326Sed{ 652193326Sed drv_t *d = ifp->if_softc; 653193326Sed 654193326Sed cp_watchdog (d); 655193326Sed} 656193326Sed 657198092Srdivackystatic void cp_tlf (struct sppp *sp) 658208600Srdivacky{ 659226633Sdim drv_t *d = sp->pp_if.if_softc; 660193326Sed 661193326Sed CP_DEBUG2 (d, ("cp_tlf\n")); 662193326Sed/* cp_set_dtr (d->chan, 0);*/ 663208600Srdivacky/* cp_set_rts (d->chan, 0);*/ 664226633Sdim sp->pp_down (sp); 665193326Sed} 666193326Sed 667193326Sedstatic void cp_tls (struct sppp *sp) 668218893Sdim{ 669218893Sdim drv_t *d = sp->pp_if.if_softc; 670193326Sed 671193326Sed CP_DEBUG2 (d, ("cp_tls\n")); 672193326Sed sp->pp_up (sp); 673218893Sdim} 674218893Sdim 675193326Sed/* 676193326Sed * Process an ioctl request. 677193326Sed */ 678212904Sdimstatic int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 679198398Srdivacky{ 680198398Srdivacky drv_t *d = ifp->if_softc; 681198398Srdivacky int error, s, was_up, should_be_up; 682193326Sed 683193326Sed was_up = (ifp->if_flags & IFF_RUNNING) != 0; 684198398Srdivacky error = sppp_ioctl (ifp, cmd, data); 685198398Srdivacky 686198398Srdivacky if (error) 687239462Sdim return error; 688198398Srdivacky 689198398Srdivacky if (! (ifp->if_flags & IFF_DEBUG)) 690239462Sdim d->chan->debug = 0; 691239462Sdim else if (! d->chan->debug) 692239462Sdim d->chan->debug = 1; 693239462Sdim 694239462Sdim switch (cmd) { 695239462Sdim default: CP_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; 696239462Sdim case SIOCADDMULTI: CP_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0; 697239462Sdim case SIOCDELMULTI: CP_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0; 698239462Sdim case SIOCSIFFLAGS: CP_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break; 699239462Sdim case SIOCSIFADDR: CP_DEBUG2 (d, ("ioctl SIOCSIFADDR\n")); break; 700239462Sdim } 701239462Sdim 702239462Sdim /* We get here only in case of SIFFLAGS or SIFADDR. */ 703239462Sdim s = splimp (); 704239462Sdim should_be_up = (ifp->if_flags & IFF_RUNNING) != 0; 705239462Sdim if (! was_up && should_be_up) { 706239462Sdim /* Interface goes up -- start it. */ 707239462Sdim cp_up (d); 708239462Sdim cp_start (d); 709239462Sdim } else if (was_up && ! should_be_up) { 710239462Sdim /* Interface is going down -- stop it. */ 711239462Sdim/* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ 712239462Sdim cp_down (d); 713239462Sdim } 714239462Sdim CP_DEBUG (d, ("ioctl 0x%lx p4\n", cmd)); 715239462Sdim splx (s); 716239462Sdim return 0; 717239462Sdim} 718239462Sdim 719239462Sdim/* 720239462Sdim * Initialization of interface. 721239462Sdim * It seems to be never called by upper level? 722239462Sdim */ 723239462Sdimstatic void cp_initialize (void *softc) 724239462Sdim{ 725239462Sdim drv_t *d = softc; 726239462Sdim 727239462Sdim CP_DEBUG (d, ("cp_initialize\n")); 728239462Sdim} 729239462Sdim#endif /*NETGRAPH*/ 730239462Sdim 731239462Sdim/* 732239462Sdim * Stop the interface. Called on splimp(). 733239462Sdim */ 734239462Sdimstatic void cp_down (drv_t *d) 735239462Sdim{ 736239462Sdim CP_DEBUG (d, ("cp_down\n")); 737239462Sdim /* Interface is going down -- stop it. */ 738239462Sdim cp_set_dtr (d->chan, 0); 739239462Sdim cp_set_rts (d->chan, 0); 740239462Sdim 741239462Sdim d->running = 0; 742239462Sdim} 743239462Sdim 744239462Sdim/* 745239462Sdim * Start the interface. Called on splimp(). 746239462Sdim */ 747239462Sdimstatic void cp_up (drv_t *d) 748239462Sdim{ 749239462Sdim CP_DEBUG (d, ("cp_up\n")); 750239462Sdim cp_set_dtr (d->chan, 1); 751239462Sdim cp_set_rts (d->chan, 1); 752239462Sdim d->running = 1; 753239462Sdim} 754239462Sdim 755239462Sdim/* 756193326Sed * Start output on the interface. Get another datagram to send 757193326Sed * off of the interface queue, and copy it to the interface 758193326Sed * before starting the output. 759193326Sed */ 760193326Sedstatic void cp_send (drv_t *d) 761193326Sed{ 762218893Sdim struct mbuf *m; 763239462Sdim u_short len; 764239462Sdim 765239462Sdim CP_DEBUG2 (d, ("cp_send, tn=%d te=%d\n", d->chan->tn, d->chan->te)); 766239462Sdim 767239462Sdim /* No output if the interface is down. */ 768239462Sdim if (! d->running) 769239462Sdim return; 770239462Sdim 771239462Sdim /* No output if the modem is off. */ 772239462Sdim if (! (d->chan->lloop || d->chan->type != T_SERIAL || 773239462Sdim cp_get_dsr (d->chan))) 774239462Sdim return; 775239462Sdim 776239462Sdim while (cp_transmit_space (d->chan)) { 777239462Sdim /* Get the packet to send. */ 778239462Sdim#ifdef NETGRAPH 779239462Sdim IF_DEQUEUE (&d->hi_queue, m); 780239462Sdim if (! m) 781239462Sdim IF_DEQUEUE (&d->queue, m); 782239462Sdim#else 783221345Sdim m = sppp_dequeue (&d->pp.pp_if); 784193326Sed#endif 785193326Sed if (! m) 786234353Sdim return; 787234353Sdim#if (__FreeBSD_version >= 400000 || NBPFILTER > 0) && !defined (NETGRAPH) 788234353Sdim if (d->pp.pp_if.if_bpf) 789234353Sdim#if __FreeBSD_version >= 500000 790234353Sdim BPF_MTAP (&d->pp.pp_if, m); 791239462Sdim#else 792239462Sdim bpf_mtap (&d->pp.pp_if, m); 793239462Sdim#endif 794239462Sdim#endif 795193326Sed len = m->m_pkthdr.len; 796193326Sed if (len >= BUFSZ) 797218893Sdim printf ("%s: too long packet: %d bytes: ", 798218893Sdim d->name, len); 799193326Sed else if (! m->m_next) 800193326Sed cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); 801193326Sed else { 802198092Srdivacky u_char *buf = d->chan->tbuf[d->chan->te]; 803218893Sdim m_copydata (m, 0, len, buf); 804218893Sdim cp_send_packet (d->chan, buf, len, 0); 805218893Sdim } 806218893Sdim m_freem (m); 807201361Srdivacky /* Set up transmit timeout, if the transmit ring is not empty.*/ 808198092Srdivacky#ifdef NETGRAPH 809218893Sdim d->timeout = 10; 810226633Sdim#else 811218893Sdim d->pp.pp_if.if_timer = 10; 812218893Sdim#endif 813193326Sed } 814218893Sdim#ifndef NETGRAPH 815218893Sdim d->pp.pp_if.if_flags |= IFF_OACTIVE; 816198092Srdivacky#endif 817218893Sdim} 818218893Sdim 819193326Sed/* 820218893Sdim * Start output on the interface. 821218893Sdim * Always called on splimp(). 822218893Sdim */ 823226633Sdimstatic void cp_start (drv_t *d) 824226633Sdim{ 825198092Srdivacky if (d->running) { 826218893Sdim if (! d->chan->dtr) 827193326Sed cp_set_dtr (d->chan, 1); 828218893Sdim if (! d->chan->rts) 829218893Sdim cp_set_rts (d->chan, 1); 830198092Srdivacky cp_send (d); 831193326Sed } 832193326Sed} 833193326Sed 834198092Srdivacky/* 835198092Srdivacky * Handle transmit timeouts. 836198092Srdivacky * Recover after lost transmit interrupts. 837198092Srdivacky * Always called on splimp(). 838193326Sed */ 839193326Sedstatic void cp_watchdog (drv_t *d) 840193326Sed{ 841193326Sed CP_DEBUG (d, ("device timeout\n")); 842193326Sed if (d->running) { 843193326Sed int s = splimp (); 844193326Sed 845193326Sed cp_stop_chan (d->chan); 846193326Sed cp_stop_e1 (d->chan); 847239462Sdim cp_start_e1 (d->chan); 848193326Sed cp_start_chan (d->chan, 1, 1, 0, 0); 849193326Sed cp_set_dtr (d->chan, 1); 850193326Sed cp_set_rts (d->chan, 1); 851218893Sdim cp_start (d); 852226633Sdim splx (s); 853226633Sdim } 854239462Sdim} 855198092Srdivacky 856226633Sdimstatic void cp_transmit (cp_chan_t *c, void *attachment, int len) 857226633Sdim{ 858226633Sdim drv_t *d = c->sys; 859218893Sdim 860193326Sed#ifdef NETGRAPH 861226633Sdim d->timeout = 0; 862226633Sdim#else 863234353Sdim ++d->pp.pp_if.if_opackets; 864193326Sed d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 865193326Sed d->pp.pp_if.if_timer = 0; 866193326Sed#endif 867193326Sed cp_start (d); 868218893Sdim} 869218893Sdim 870193326Sedstatic void cp_receive (cp_chan_t *c, unsigned char *data, int len) 871193326Sed{ 872234353Sdim drv_t *d = c->sys; 873234353Sdim struct mbuf *m; 874234353Sdim#if __FreeBSD_version >= 500000 && defined NETGRAPH 875234353Sdim int error; 876234353Sdim#endif 877234353Sdim 878218893Sdim if (! d->running) 879234353Sdim return; 880234353Sdim 881234353Sdim m = makembuf (data, len); 882193326Sed if (! m) { 883193326Sed CP_DEBUG (d, ("no memory for packet\n")); 884210299Sed#ifndef NETGRAPH 885218893Sdim ++d->pp.pp_if.if_iqdrops; 886218893Sdim#endif 887224145Sdim return; 888198398Srdivacky } 889198398Srdivacky if (c->debug > 1) 890201361Srdivacky printmbuf (m); 891218893Sdim#ifdef NETGRAPH 892218893Sdim m->m_pkthdr.rcvif = 0; 893224145Sdim#if __FreeBSD_version >= 500000 894218893Sdim NG_SEND_DATA_ONLY (error, d->hook, m); 895201361Srdivacky#else 896218893Sdim ng_queue_data (d->hook, m, 0); 897218893Sdim#endif 898218893Sdim#else 899218893Sdim ++d->pp.pp_if.if_ipackets; 900221345Sdim m->m_pkthdr.rcvif = &d->pp.pp_if; 901221345Sdim#if __FreeBSD_version >= 400000 || NBPFILTER > 0 902218893Sdim /* Check if there's a BPF listener on this interface. 903218893Sdim * If so, hand off the raw packet to bpf. */ 904218893Sdim if (d->pp.pp_if.if_bpf) 905218893Sdim#if __FreeBSD_version >= 500000 906218893Sdim BPF_TAP (&d->pp.pp_if, data, len); 907218893Sdim#else 908218893Sdim bpf_tap (&d->pp.pp_if, data, len); 909218893Sdim#endif 910218893Sdim#endif 911218893Sdim sppp_input (&d->pp.pp_if, m); 912218893Sdim#endif 913218893Sdim} 914218893Sdim 915218893Sdimstatic void cp_error (cp_chan_t *c, int data) 916218893Sdim{ 917218893Sdim drv_t *d = c->sys; 918218893Sdim 919218893Sdim switch (data) { 920218893Sdim case CP_FRAME: 921201361Srdivacky CP_DEBUG (d, ("frame error\n")); 922201361Srdivacky#ifndef NETGRAPH 923218893Sdim ++d->pp.pp_if.if_ierrors; 924203955Srdivacky#endif 925224145Sdim break; 926224145Sdim case CP_CRC: 927193326Sed CP_DEBUG (d, ("crc error\n")); 928193326Sed#ifndef NETGRAPH 929218893Sdim ++d->pp.pp_if.if_ierrors; 930218893Sdim#endif 931218893Sdim break; 932224145Sdim case CP_OVERRUN: 933224145Sdim CP_DEBUG (d, ("overrun error\n")); 934210299Sed#ifndef NETGRAPH 935224145Sdim ++d->pp.pp_if.if_collisions; 936224145Sdim ++d->pp.pp_if.if_ierrors; 937193326Sed#endif 938224145Sdim break; 939226633Sdim case CP_OVERFLOW: 940226633Sdim CP_DEBUG (d, ("overflow error\n")); 941226633Sdim#ifndef NETGRAPH 942226633Sdim ++d->pp.pp_if.if_ierrors; 943224145Sdim#endif 944224145Sdim break; 945224145Sdim case CP_UNDERRUN: 946193326Sed CP_DEBUG (d, ("underrun error\n")); 947224145Sdim#ifdef NETGRAPH 948193326Sed d->timeout = 0; 949193326Sed#else 950193326Sed ++d->pp.pp_if.if_oerrors; 951224145Sdim d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 952224145Sdim d->pp.pp_if.if_timer = 0; 953224145Sdim#endif 954218893Sdim cp_start (d); 955218893Sdim break; 956224145Sdim default: 957218893Sdim CP_DEBUG (d, ("error #%d\n", data)); 958218893Sdim break; 959224145Sdim } 960234353Sdim} 961224145Sdim 962234353Sdim/* 963234353Sdim * You also need read, write, open, close routines. 964234353Sdim * This should get you started 965234353Sdim */ 966234353Sdim#if __FreeBSD_version < 500000 967234353Sdimstatic int cp_open (dev_t dev, int oflags, int devtype, struct proc *p) 968234353Sdim#else 969234353Sdimstatic int cp_open (dev_t dev, int oflags, int devtype, struct thread *td) 970193326Sed#endif 971193326Sed{ 972193326Sed int unit = minor (dev); 973193326Sed drv_t *d; 974224145Sdim 975193326Sed if (unit >= NBRD*NCHAN || ! (d = channel[unit])) 976193326Sed return ENXIO; 977193326Sed CP_DEBUG2 (d, ("cp_open\n")); 978193326Sed return 0; 979193326Sed} 980200583Srdivacky 981200583Srdivacky/* 982193326Sed * Only called on the LAST close. 983193326Sed */ 984193326Sed#if __FreeBSD_version < 500000 985200583Srdivackystatic int cp_close (dev_t dev, int fflag, int devtype, struct proc *p) 986193326Sed#else 987200583Srdivackystatic int cp_close (dev_t dev, int fflag, int devtype, struct thread *td) 988200583Srdivacky#endif 989239462Sdim{ 990193326Sed drv_t *d = channel [minor (dev)]; 991193326Sed 992193326Sed CP_DEBUG2 (d, ("cp_close\n")); 993218893Sdim return 0; 994193326Sed} 995193326Sed 996234353Sdimstatic int cp_modem_status (cp_chan_t *c) 997234353Sdim{ 998234353Sdim drv_t *d = c->sys; 999234353Sdim int status, s; 1000218893Sdim 1001234982Sdim status = d->running ? TIOCM_LE : 0; 1002234982Sdim s = splimp (); 1003234982Sdim if (cp_get_cd (c)) status |= TIOCM_CD; 1004234353Sdim if (cp_get_cts (c)) status |= TIOCM_CTS; 1005193326Sed if (cp_get_dsr (c)) status |= TIOCM_DSR; 1006193326Sed if (c->dtr) status |= TIOCM_DTR; 1007234982Sdim if (c->rts) status |= TIOCM_RTS; 1008234982Sdim splx (s); 1009193326Sed return status; 1010234353Sdim} 1011234353Sdim 1012193326Sed#if __FreeBSD_version < 500000 1013234353Sdimstatic int cp_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1014234982Sdim#else 1015234353Sdimstatic int cp_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1016234353Sdim#endif 1017224145Sdim{ 1018234982Sdim drv_t *d = channel [minor (dev)]; 1019193326Sed cp_chan_t *c = d->chan; 1020193326Sed struct serial_statistics *st; 1021198092Srdivacky struct e1_statistics *opte1; 1022193326Sed struct e3_statistics *opte3; 1023198092Srdivacky int error, s; 1024193326Sed char mask[16]; 1025193326Sed 1026193326Sed switch (cmd) { 1027193326Sed case SERIAL_GETREGISTERED: 1028193326Sed CP_DEBUG2 (d, ("ioctl: getregistered\n")); 1029224145Sdim bzero (mask, sizeof(mask)); 1030212904Sdim for (s=0; s<NBRD*NCHAN; ++s) 1031224145Sdim if (channel [s]) 1032193326Sed mask [s/8] |= 1 << (s & 7); 1033193326Sed bcopy (mask, data, sizeof (mask)); 1034193326Sed return 0; 1035193326Sed 1036198092Srdivacky#ifndef NETGRAPH 1037193326Sed case SERIAL_GETPROTO: 1038193326Sed CP_DEBUG2 (d, ("ioctl: getproto\n")); 1039193326Sed strcpy ((char*)data, (d->pp.pp_flags & PP_FR) ? "fr" : 1040224145Sdim (d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp"); 1041224145Sdim return 0; 1042193326Sed 1043193326Sed case SERIAL_SETPROTO: 1044193326Sed CP_DEBUG2 (d, ("ioctl: setproto\n")); 1045193326Sed /* Only for superuser! */ 1046193326Sed#if __FreeBSD_version < 400000 1047193326Sed error = suser (p->p_ucred, &p->p_acflag); 1048193326Sed#elif __FreeBSD_version < 500000 1049193326Sed error = suser (p); 1050218893Sdim#else /* __FreeBSD_version >= 500000 */ 1051234982Sdim error = suser (td); 1052193326Sed#endif /* __FreeBSD_version >= 500000 */ 1053193326Sed if (error) 1054224145Sdim return error; 1055193326Sed if (d->pp.pp_if.if_flags & IFF_RUNNING) 1056218893Sdim return EBUSY; 1057224145Sdim if (! strcmp ("cisco", (char*)data)) { 1058193326Sed d->pp.pp_flags &= ~(PP_FR); 1059193326Sed d->pp.pp_flags |= PP_KEEPALIVE; 1060193326Sed d->pp.pp_if.if_flags |= PP_CISCO; 1061193326Sed } else if (! strcmp ("fr", (char*)data) && !PP_FR) { 1062198092Srdivacky d->pp.pp_if.if_flags &= ~(PP_CISCO); 1063224145Sdim d->pp.pp_flags |= PP_FR | PP_KEEPALIVE; 1064224145Sdim } else if (! strcmp ("ppp", (char*)data)) { 1065226633Sdim d->pp.pp_flags &= ~PP_FR; 1066234353Sdim d->pp.pp_flags &= ~PP_KEEPALIVE; 1067224145Sdim d->pp.pp_if.if_flags &= ~(PP_CISCO); 1068193326Sed } else 1069193326Sed return EINVAL; 1070224145Sdim return 0; 1071224145Sdim 1072224145Sdim case SERIAL_GETKEEPALIVE: 1073224145Sdim CP_DEBUG2 (d, ("ioctl: getkeepalive\n")); 1074224145Sdim if ((d->pp.pp_flags & PP_FR) || 1075224145Sdim (d->pp.pp_if.if_flags & PP_CISCO)) 1076193326Sed return EINVAL; 1077193326Sed *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0; 1078224145Sdim return 0; 1079224145Sdim 1080193326Sed case SERIAL_SETKEEPALIVE: 1081193326Sed CP_DEBUG2 (d, ("ioctl: setkeepalive\n")); 1082224145Sdim /* Only for superuser! */ 1083224145Sdim#if __FreeBSD_version < 400000 1084224145Sdim error = suser (p->p_ucred, &p->p_acflag); 1085224145Sdim#elif __FreeBSD_version < 500000 1086218893Sdim error = suser (p); 1087218893Sdim#else 1088218893Sdim error = suser (td); 1089234982Sdim#endif 1090234982Sdim if (error) 1091193326Sed return error; 1092224145Sdim if ((d->pp.pp_flags & PP_FR) || 1093218893Sdim (d->pp.pp_if.if_flags & PP_CISCO)) 1094224145Sdim return EINVAL; 1095204962Srdivacky s = splimp (); 1096224145Sdim if (*(int*)data) 1097193326Sed d->pp.pp_flags |= PP_KEEPALIVE; 1098193326Sed else 1099224145Sdim d->pp.pp_flags &= ~PP_KEEPALIVE; 1100193326Sed splx (s); 1101224145Sdim return 0; 1102224145Sdim#endif /*NETGRAPH*/ 1103224145Sdim 1104224145Sdim case SERIAL_GETMODE: 1105224145Sdim CP_DEBUG2 (d, ("ioctl: getmode\n")); 1106224145Sdim *(int*)data = SERIAL_HDLC; 1107224145Sdim return 0; 1108224145Sdim 1109224145Sdim case SERIAL_SETMODE: 1110234353Sdim /* Only for superuser! */ 1111234353Sdim#if __FreeBSD_version < 400000 1112234353Sdim error = suser (p->p_ucred, &p->p_acflag); 1113224145Sdim#elif __FreeBSD_version < 500000 1114224145Sdim error = suser (p); 1115224145Sdim#else 1116224145Sdim error = suser (td); 1117224145Sdim#endif 1118224145Sdim if (error) 1119218893Sdim return error; 1120218893Sdim if (*(int*)data != SERIAL_HDLC) 1121218893Sdim return EINVAL; 1122224145Sdim return 0; 1123218893Sdim 1124224145Sdim case SERIAL_GETCFG: 1125218893Sdim CP_DEBUG2 (d, ("ioctl: getcfg\n")); 1126218893Sdim if (c->type != T_E1 || c->unfram) 1127193326Sed return EINVAL; 1128224145Sdim *(char*)data = c->board->mux ? 'c' : 'a'; 1129224145Sdim return 0; 1130224145Sdim 1131224145Sdim case SERIAL_SETCFG: 1132234353Sdim CP_DEBUG2 (d, ("ioctl: setcfg\n")); 1133234353Sdim#if __FreeBSD_version < 400000 1134234353Sdim error = suser (p->p_ucred, &p->p_acflag); 1135234353Sdim#elif __FreeBSD_version < 500000 1136234353Sdim error = suser (p); 1137193326Sed#else 1138193326Sed error = suser (td); 1139193326Sed#endif 1140193326Sed if (error) 1141193326Sed return error; 1142193326Sed if (c->type != T_E1) 1143218893Sdim return EINVAL; 1144218893Sdim s = splimp (); 1145218893Sdim cp_set_mux (c->board, *((char*)data) == 'c'); 1146221345Sdim splx (s); 1147221345Sdim return 0; 1148218893Sdim 1149218893Sdim case SERIAL_GETSTAT: 1150221345Sdim CP_DEBUG2 (d, ("ioctl: getstat\n")); 1151218893Sdim st = (struct serial_statistics*) data; 1152218893Sdim st->rintr = c->rintr; 1153218893Sdim st->tintr = c->tintr; 1154218893Sdim st->mintr = 0; 1155218893Sdim st->ibytes = c->ibytes; 1156221345Sdim st->ipkts = c->ipkts; 1157218893Sdim st->obytes = c->obytes; 1158218893Sdim st->opkts = c->opkts; 1159218893Sdim st->ierrs = c->overrun + c->frame + c->crc; 1160218893Sdim st->oerrs = c->underrun; 1161218893Sdim return 0; 1162218893Sdim 1163218893Sdim case SERIAL_GETESTAT: 1164221345Sdim CP_DEBUG2 (d, ("ioctl: getestat\n")); 1165218893Sdim if (c->type != T_E1 && c->type != T_G703) 1166218893Sdim return EINVAL; 1167218893Sdim opte1 = (struct e1_statistics*) data; 1168218893Sdim opte1->status = c->status; 1169218893Sdim opte1->cursec = c->cursec; 1170218893Sdim opte1->totsec = c->totsec + c->cursec; 1171218893Sdim 1172218893Sdim opte1->currnt.bpv = c->currnt.bpv; 1173218893Sdim opte1->currnt.fse = c->currnt.fse; 1174218893Sdim opte1->currnt.crce = c->currnt.crce; 1175218893Sdim opte1->currnt.rcrce = c->currnt.rcrce; 1176218893Sdim opte1->currnt.uas = c->currnt.uas; 1177218893Sdim opte1->currnt.les = c->currnt.les; 1178218893Sdim opte1->currnt.es = c->currnt.es; 1179218893Sdim opte1->currnt.bes = c->currnt.bes; 1180218893Sdim opte1->currnt.ses = c->currnt.ses; 1181221345Sdim opte1->currnt.oofs = c->currnt.oofs; 1182226633Sdim opte1->currnt.css = c->currnt.css; 1183218893Sdim opte1->currnt.dm = c->currnt.dm; 1184218893Sdim 1185218893Sdim opte1->total.bpv = c->total.bpv + c->currnt.bpv; 1186218893Sdim opte1->total.fse = c->total.fse + c->currnt.fse; 1187218893Sdim opte1->total.crce = c->total.crce + c->currnt.crce; 1188218893Sdim opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce; 1189218893Sdim opte1->total.uas = c->total.uas + c->currnt.uas; 1190218893Sdim opte1->total.les = c->total.les + c->currnt.les; 1191218893Sdim opte1->total.es = c->total.es + c->currnt.es; 1192221345Sdim opte1->total.bes = c->total.bes + c->currnt.bes; 1193218893Sdim opte1->total.ses = c->total.ses + c->currnt.ses; 1194218893Sdim opte1->total.oofs = c->total.oofs + c->currnt.oofs; 1195218893Sdim opte1->total.css = c->total.css + c->currnt.css; 1196218893Sdim opte1->total.dm = c->total.dm + c->currnt.dm; 1197218893Sdim for (s=0; s<48; ++s) { 1198218893Sdim opte1->interval[s].bpv = c->interval[s].bpv; 1199218893Sdim opte1->interval[s].fse = c->interval[s].fse; 1200218893Sdim opte1->interval[s].crce = c->interval[s].crce; 1201218893Sdim opte1->interval[s].rcrce = c->interval[s].rcrce; 1202218893Sdim opte1->interval[s].uas = c->interval[s].uas; 1203218893Sdim opte1->interval[s].les = c->interval[s].les; 1204218893Sdim opte1->interval[s].es = c->interval[s].es; 1205218893Sdim opte1->interval[s].bes = c->interval[s].bes; 1206221345Sdim opte1->interval[s].ses = c->interval[s].ses; 1207221345Sdim opte1->interval[s].oofs = c->interval[s].oofs; 1208234353Sdim opte1->interval[s].css = c->interval[s].css; 1209221345Sdim opte1->interval[s].dm = c->interval[s].dm; 1210221345Sdim } 1211221345Sdim return 0; 1212221345Sdim 1213221345Sdim case SERIAL_GETE3STAT: 1214221345Sdim CP_DEBUG2 (d, ("ioctl: gete3stat\n")); 1215221345Sdim if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1) 1216218893Sdim return EINVAL; 1217221345Sdim opte3 = (struct e3_statistics*) data; 1218221345Sdim 1219221345Sdim opte3->status = c->e3status; 1220218893Sdim opte3->cursec = (c->e3csec_5 * 2 + 1) / 10; 1221218893Sdim opte3->totsec = c->e3tsec + opte3->cursec; 1222218893Sdim 1223218893Sdim opte3->ccv = c->e3ccv; 1224221345Sdim opte3->tcv = c->e3tcv + opte3->ccv; 1225221345Sdim 1226218893Sdim for (s = 0; s < 48; ++s) { 1227218893Sdim opte3->icv[s] = c->e3icv[s]; 1228218893Sdim } 1229221345Sdim return 0; 1230221345Sdim 1231218893Sdim case SERIAL_CLRSTAT: 1232218893Sdim CP_DEBUG2 (d, ("ioctl: clrstat\n")); 1233218893Sdim /* Only for superuser! */ 1234234353Sdim#if __FreeBSD_version < 400000 1235221345Sdim error = suser (p->p_ucred, &p->p_acflag); 1236221345Sdim#elif __FreeBSD_version < 500000 1237218893Sdim error = suser (p); 1238218893Sdim#else 1239218893Sdim error = suser (td); 1240218893Sdim#endif 1241218893Sdim if (error) 1242218893Sdim return error; 1243218893Sdim c->rintr = 0; 1244218893Sdim c->tintr = 0; 1245193326Sed c->ibytes = 0; 1246193326Sed c->obytes = 0; 1247193326Sed c->ipkts = 0; 1248193326Sed c->opkts = 0; 1249239462Sdim c->overrun = 0; 1250193326Sed c->frame = 0; 1251193326Sed c->crc = 0; 1252218893Sdim c->underrun = 0; 1253218893Sdim bzero (&c->currnt, sizeof (c->currnt)); 1254198092Srdivacky bzero (&c->total, sizeof (c->total)); 1255218893Sdim bzero (c->interval, sizeof (c->interval)); 1256218893Sdim c->e3ccv = 0; 1257218893Sdim c->e3tcv = 0; 1258239462Sdim bzero (c->e3icv, sizeof (c->e3icv)); 1259193326Sed return 0; 1260193326Sed 1261203955Srdivacky case SERIAL_GETBAUD: 1262203955Srdivacky CP_DEBUG2 (d, ("ioctl: getbaud\n")); 1263203955Srdivacky *(long*)data = c->baud; 1264212904Sdim return 0; 1265226633Sdim 1266226633Sdim case SERIAL_SETBAUD: 1267226633Sdim CP_DEBUG2 (d, ("ioctl: setbaud\n")); 1268212904Sdim /* Only for superuser! */ 1269203955Srdivacky#if __FreeBSD_version < 400000 1270203955Srdivacky error = suser (p->p_ucred, &p->p_acflag); 1271193326Sed#elif __FreeBSD_version < 500000 1272193326Sed error = suser (p); 1273239462Sdim#else 1274239462Sdim error = suser (td); 1275193326Sed#endif 1276198092Srdivacky if (error) 1277234353Sdim return error; 1278207619Srdivacky s = splimp (); 1279208600Srdivacky cp_set_baud (c, *(long*)data); 1280208600Srdivacky splx (s); 1281226633Sdim return 0; 1282226633Sdim 1283226633Sdim case SERIAL_GETLOOP: 1284208600Srdivacky CP_DEBUG2 (d, ("ioctl: getloop\n")); 1285208600Srdivacky *(int*)data = c->lloop; 1286208600Srdivacky return 0; 1287208600Srdivacky 1288207619Srdivacky case SERIAL_SETLOOP: 1289207619Srdivacky CP_DEBUG2 (d, ("ioctl: setloop\n")); 1290207619Srdivacky /* Only for superuser! */ 1291207619Srdivacky#if __FreeBSD_version < 400000 1292193326Sed error = suser (p->p_ucred, &p->p_acflag); 1293193326Sed#elif __FreeBSD_version < 500000 1294193326Sed error = suser (p); 1295193326Sed#else 1296193326Sed error = suser (td); 1297193326Sed#endif 1298193326Sed if (error) 1299193326Sed return error; 1300193326Sed s = splimp (); 1301193326Sed cp_set_lloop (c, *(int*)data); 1302198092Srdivacky splx (s); 1303193326Sed return 0; 1304221345Sdim 1305221345Sdim case SERIAL_GETDPLL: 1306198092Srdivacky CP_DEBUG2 (d, ("ioctl: getdpll\n")); 1307239462Sdim if (c->type != T_SERIAL) 1308239462Sdim return EINVAL; 1309234353Sdim *(int*)data = c->dpll; 1310193326Sed return 0; 1311198092Srdivacky 1312193326Sed case SERIAL_SETDPLL: 1313193326Sed CP_DEBUG2 (d, ("ioctl: setdpll\n")); 1314193326Sed /* Only for superuser! */ 1315193326Sed#if __FreeBSD_version < 400000 1316193326Sed error = suser (p->p_ucred, &p->p_acflag); 1317193326Sed#elif __FreeBSD_version < 500000 1318193326Sed error = suser (p); 1319193326Sed#else 1320193326Sed error = suser (td); 1321193326Sed#endif 1322206275Srdivacky if (error) 1323193326Sed return error; 1324206275Srdivacky if (c->type != T_SERIAL) 1325226633Sdim return EINVAL; 1326226633Sdim s = splimp (); 1327218893Sdim cp_set_dpll (c, *(int*)data); 1328226633Sdim splx (s); 1329206275Srdivacky return 0; 1330226633Sdim 1331226633Sdim case SERIAL_GETNRZI: 1332218893Sdim CP_DEBUG2 (d, ("ioctl: getnrzi\n")); 1333226633Sdim if (c->type != T_SERIAL) 1334206275Srdivacky return EINVAL; 1335224145Sdim *(int*)data = c->nrzi; 1336234353Sdim return 0; 1337224145Sdim 1338224145Sdim case SERIAL_SETNRZI: 1339210299Sed CP_DEBUG2 (d, ("ioctl: setnrzi\n")); 1340210299Sed /* Only for superuser! */ 1341221345Sdim#if __FreeBSD_version < 400000 1342226633Sdim error = suser (p->p_ucred, &p->p_acflag); 1343221345Sdim#elif __FreeBSD_version < 500000 1344210299Sed error = suser (p); 1345210299Sed#else 1346210299Sed error = suser (td); 1347210299Sed#endif 1348224145Sdim if (error) 1349210299Sed return error; 1350210299Sed if (c->type != T_SERIAL) 1351210299Sed return EINVAL; 1352221345Sdim s = splimp (); 1353226633Sdim cp_set_nrzi (c, *(int*)data); 1354221345Sdim splx (s); 1355221345Sdim return 0; 1356210299Sed 1357210299Sed case SERIAL_GETDEBUG: 1358210299Sed CP_DEBUG2 (d, ("ioctl: getdebug\n")); 1359210299Sed *(int*)data = d->chan->debug; 1360210299Sed return 0; 1361210299Sed 1362210299Sed case SERIAL_SETDEBUG: 1363218893Sdim CP_DEBUG2 (d, ("ioctl: setdebug\n")); 1364221345Sdim /* Only for superuser! */ 1365221345Sdim#if __FreeBSD_version < 400000 1366239462Sdim error = suser (p->p_ucred, &p->p_acflag); 1367193326Sed#elif __FreeBSD_version < 500000 1368234353Sdim error = suser (p); 1369234353Sdim#else 1370234353Sdim error = suser (td); 1371234353Sdim#endif 1372234353Sdim if (error) 1373234353Sdim return error; 1374234353Sdim d->chan->debug = *(int*)data; 1375234353Sdim#ifndef NETGRAPH 1376234353Sdim if (d->chan->debug) 1377234353Sdim d->pp.pp_if.if_flags |= IFF_DEBUG; 1378234353Sdim else 1379234353Sdim d->pp.pp_if.if_flags &= ~IFF_DEBUG; 1380234353Sdim#endif 1381234353Sdim return 0; 1382234353Sdim 1383234353Sdim case SERIAL_GETHIGAIN: 1384234353Sdim CP_DEBUG2 (d, ("ioctl: gethigain\n")); 1385234353Sdim if (c->type != T_E1) 1386234353Sdim return EINVAL; 1387234353Sdim *(int*)data = c->higain; 1388234353Sdim return 0; 1389234353Sdim 1390234353Sdim case SERIAL_SETHIGAIN: 1391234353Sdim CP_DEBUG2 (d, ("ioctl: sethigain\n")); 1392234353Sdim /* Only for superuser! */ 1393234353Sdim#if __FreeBSD_version < 400000 1394234353Sdim error = suser (p->p_ucred, &p->p_acflag); 1395234353Sdim#elif __FreeBSD_version < 500000 1396234353Sdim error = suser (p); 1397234353Sdim#else 1398234353Sdim error = suser (td); 1399234353Sdim#endif 1400234353Sdim if (error) 1401234353Sdim return error; 1402234353Sdim if (c->type != T_E1) 1403234353Sdim return EINVAL; 1404234353Sdim s = splimp (); 1405234353Sdim cp_set_higain (c, *(int*)data); 1406234353Sdim splx (s); 1407234353Sdim return 0; 1408234353Sdim 1409234353Sdim case SERIAL_GETPHONY: 1410234353Sdim CP_DEBUG2 (d, ("ioctl: getphony\n")); 1411234353Sdim if (c->type != T_E1) 1412234353Sdim return EINVAL; 1413234353Sdim *(int*)data = c->phony; 1414234353Sdim return 0; 1415234353Sdim 1416234353Sdim case SERIAL_SETPHONY: 1417234353Sdim CP_DEBUG2 (d, ("ioctl: setphony\n")); 1418234353Sdim /* Only for superuser! */ 1419234353Sdim#if __FreeBSD_version < 400000 1420234353Sdim error = suser (p->p_ucred, &p->p_acflag); 1421234353Sdim#elif __FreeBSD_version < 500000 1422234353Sdim error = suser (p); 1423#else 1424 error = suser (td); 1425#endif 1426 if (error) 1427 return error; 1428 if (c->type != T_E1) 1429 return EINVAL; 1430 s = splimp (); 1431 cp_set_phony (c, *(int*)data); 1432 splx (s); 1433 return 0; 1434 1435 case SERIAL_GETUNFRAM: 1436 CP_DEBUG2 (d, ("ioctl: getunfram\n")); 1437 if (c->type != T_E1) 1438 return EINVAL; 1439 *(int*)data = c->unfram; 1440 return 0; 1441 1442 case SERIAL_SETUNFRAM: 1443 CP_DEBUG2 (d, ("ioctl: setunfram\n")); 1444 /* Only for superuser! */ 1445#if __FreeBSD_version < 400000 1446 error = suser (p->p_ucred, &p->p_acflag); 1447#elif __FreeBSD_version < 500000 1448 error = suser (p); 1449#else 1450 error = suser (td); 1451#endif 1452 if (error) 1453 return error; 1454 if (c->type != T_E1) 1455 return EINVAL; 1456 s = splimp (); 1457 cp_set_unfram (c, *(int*)data); 1458 splx (s); 1459 return 0; 1460 1461 case SERIAL_GETSCRAMBLER: 1462 CP_DEBUG2 (d, ("ioctl: getscrambler\n")); 1463 if (c->type != T_G703 && !c->unfram) 1464 return EINVAL; 1465 *(int*)data = c->scrambler; 1466 return 0; 1467 1468 case SERIAL_SETSCRAMBLER: 1469 CP_DEBUG2 (d, ("ioctl: setscrambler\n")); 1470 /* Only for superuser! */ 1471#if __FreeBSD_version < 400000 1472 error = suser (p->p_ucred, &p->p_acflag); 1473#elif __FreeBSD_version < 500000 1474 error = suser (p); 1475#else 1476 error = suser (td); 1477#endif 1478 if (error) 1479 return error; 1480 if (c->type != T_G703 && !c->unfram) 1481 return EINVAL; 1482 s = splimp (); 1483 cp_set_scrambler (c, *(int*)data); 1484 splx (s); 1485 return 0; 1486 1487 case SERIAL_GETMONITOR: 1488 CP_DEBUG2 (d, ("ioctl: getmonitor\n")); 1489 if (c->type != T_E1 && 1490 c->type != T_E3 && 1491 c->type != T_T3 && 1492 c->type != T_STS1) 1493 return EINVAL; 1494 *(int*)data = c->monitor; 1495 return 0; 1496 1497 case SERIAL_SETMONITOR: 1498 CP_DEBUG2 (d, ("ioctl: setmonitor\n")); 1499 /* Only for superuser! */ 1500#if __FreeBSD_version < 400000 1501 error = suser (p->p_ucred, &p->p_acflag); 1502#elif __FreeBSD_version < 500000 1503 error = suser (p); 1504#else 1505 error = suser (td); 1506#endif 1507 if (error) 1508 return error; 1509 if (c->type != T_E1) 1510 return EINVAL; 1511 s = splimp (); 1512 cp_set_monitor (c, *(int*)data); 1513 splx (s); 1514 return 0; 1515 1516 case SERIAL_GETUSE16: 1517 CP_DEBUG2 (d, ("ioctl: getuse16\n")); 1518 if (c->type != T_E1 || c->unfram) 1519 return EINVAL; 1520 *(int*)data = c->use16; 1521 return 0; 1522 1523 case SERIAL_SETUSE16: 1524 CP_DEBUG2 (d, ("ioctl: setuse16\n")); 1525 /* Only for superuser! */ 1526#if __FreeBSD_version < 400000 1527 error = suser (p->p_ucred, &p->p_acflag); 1528#elif __FreeBSD_version < 500000 1529 error = suser (p); 1530#else 1531 error = suser (td); 1532#endif 1533 if (error) 1534 return error; 1535 if (c->type != T_E1) 1536 return EINVAL; 1537 s = splimp (); 1538 cp_set_use16 (c, *(int*)data); 1539 splx (s); 1540 return 0; 1541 1542 case SERIAL_GETCRC4: 1543 CP_DEBUG2 (d, ("ioctl: getcrc4\n")); 1544 if (c->type != T_E1 || c->unfram) 1545 return EINVAL; 1546 *(int*)data = c->crc4; 1547 return 0; 1548 1549 case SERIAL_SETCRC4: 1550 CP_DEBUG2 (d, ("ioctl: setcrc4\n")); 1551 /* Only for superuser! */ 1552#if __FreeBSD_version < 400000 1553 error = suser (p->p_ucred, &p->p_acflag); 1554#elif __FreeBSD_version < 500000 1555 error = suser (p); 1556#else 1557 error = suser (td); 1558#endif 1559 if (error) 1560 return error; 1561 if (c->type != T_E1) 1562 return EINVAL; 1563 s = splimp (); 1564 cp_set_crc4 (c, *(int*)data); 1565 splx (s); 1566 return 0; 1567 1568 case SERIAL_GETCLK: 1569 CP_DEBUG2 (d, ("ioctl: getclk\n")); 1570 if (c->type != T_E1 && 1571 c->type != T_G703 && 1572 c->type != T_E3 && 1573 c->type != T_T3 && 1574 c->type != T_STS1) 1575 return EINVAL; 1576 switch (c->gsyn) { 1577 default: *(int*)data = E1CLK_INTERNAL; break; 1578 case GSYN_RCV: *(int*)data = E1CLK_RECEIVE; break; 1579 case GSYN_RCV0: *(int*)data = E1CLK_RECEIVE_CHAN0; break; 1580 case GSYN_RCV1: *(int*)data = E1CLK_RECEIVE_CHAN1; break; 1581 case GSYN_RCV2: *(int*)data = E1CLK_RECEIVE_CHAN2; break; 1582 case GSYN_RCV3: *(int*)data = E1CLK_RECEIVE_CHAN3; break; 1583 } 1584 return 0; 1585 1586 case SERIAL_SETCLK: 1587 CP_DEBUG2 (d, ("ioctl: setclk\n")); 1588 /* Only for superuser! */ 1589#if __FreeBSD_version < 400000 1590 error = suser (p->p_ucred, &p->p_acflag); 1591#elif __FreeBSD_version < 500000 1592 error = suser (p); 1593#else 1594 error = suser (td); 1595#endif 1596 if (error) 1597 return error; 1598 if (c->type != T_E1 && 1599 c->type != T_G703 && 1600 c->type != T_E3 && 1601 c->type != T_T3 && 1602 c->type != T_STS1) 1603 return EINVAL; 1604 s = splimp (); 1605 switch (*(int*)data) { 1606 default: cp_set_gsyn (c, GSYN_INT); break; 1607 case E1CLK_RECEIVE: cp_set_gsyn (c, GSYN_RCV); break; 1608 case E1CLK_RECEIVE_CHAN0: cp_set_gsyn (c, GSYN_RCV0); break; 1609 case E1CLK_RECEIVE_CHAN1: cp_set_gsyn (c, GSYN_RCV1); break; 1610 case E1CLK_RECEIVE_CHAN2: cp_set_gsyn (c, GSYN_RCV2); break; 1611 case E1CLK_RECEIVE_CHAN3: cp_set_gsyn (c, GSYN_RCV3); break; 1612 } 1613 splx (s); 1614 return 0; 1615 1616 case SERIAL_GETTIMESLOTS: 1617 CP_DEBUG2 (d, ("ioctl: gettimeslots\n")); 1618 if ((c->type != T_E1 || c->unfram) && c->type != T_DATA) 1619 return EINVAL; 1620 *(u_long*)data = c->ts; 1621 return 0; 1622 1623 case SERIAL_SETTIMESLOTS: 1624 CP_DEBUG2 (d, ("ioctl: settimeslots\n")); 1625 /* Only for superuser! */ 1626#if __FreeBSD_version < 400000 1627 error = suser (p->p_ucred, &p->p_acflag); 1628#elif __FreeBSD_version < 500000 1629 error = suser (p); 1630#else 1631 error = suser (td); 1632#endif 1633 if (error) 1634 return error; 1635 if ((c->type != T_E1 || c->unfram) && c->type != T_DATA) 1636 return EINVAL; 1637 s = splimp (); 1638 cp_set_ts (c, *(u_long*)data); 1639 splx (s); 1640 return 0; 1641 1642 case SERIAL_GETINVCLK: 1643 CP_DEBUG2 (d, ("ioctl: getinvclk\n")); 1644#if 1 1645 return EINVAL; 1646#else 1647 if (c->type != T_SERIAL) 1648 return EINVAL; 1649 *(int*)data = c->invtxc; 1650 return 0; 1651#endif 1652 1653 case SERIAL_SETINVCLK: 1654 CP_DEBUG2 (d, ("ioctl: setinvclk\n")); 1655 /* Only for superuser! */ 1656#if __FreeBSD_version < 400000 1657 error = suser (p->p_ucred, &p->p_acflag); 1658#elif __FreeBSD_version < 500000 1659 error = suser (p); 1660#else 1661 error = suser (td); 1662#endif 1663 if (error) 1664 return error; 1665 if (c->type != T_SERIAL) 1666 return EINVAL; 1667 s = splimp (); 1668 cp_set_invtxc (c, *(int*)data); 1669 cp_set_invrxc (c, *(int*)data); 1670 splx (s); 1671 return 0; 1672 1673 case SERIAL_GETINVTCLK: 1674 CP_DEBUG2 (d, ("ioctl: getinvtclk\n")); 1675 if (c->type != T_SERIAL) 1676 return EINVAL; 1677 *(int*)data = c->invtxc; 1678 return 0; 1679 1680 case SERIAL_SETINVTCLK: 1681 CP_DEBUG2 (d, ("ioctl: setinvtclk\n")); 1682 /* Only for superuser! */ 1683#if __FreeBSD_version < 400000 1684 error = suser (p->p_ucred, &p->p_acflag); 1685#elif __FreeBSD_version < 500000 1686 error = suser (p); 1687#else 1688 error = suser (td); 1689#endif 1690 if (error) 1691 return error; 1692 if (c->type != T_SERIAL) 1693 return EINVAL; 1694 s = splimp (); 1695 cp_set_invtxc (c, *(int*)data); 1696 splx (s); 1697 return 0; 1698 1699 case SERIAL_GETINVRCLK: 1700 CP_DEBUG2 (d, ("ioctl: getinvrclk\n")); 1701 if (c->type != T_SERIAL) 1702 return EINVAL; 1703 *(int*)data = c->invrxc; 1704 return 0; 1705 1706 case SERIAL_SETINVRCLK: 1707 CP_DEBUG2 (d, ("ioctl: setinvrclk\n")); 1708 /* Only for superuser! */ 1709#if __FreeBSD_version < 400000 1710 error = suser (p->p_ucred, &p->p_acflag); 1711#elif __FreeBSD_version < 500000 1712 error = suser (p); 1713#else 1714 error = suser (td); 1715#endif 1716 if (error) 1717 return error; 1718 if (c->type != T_SERIAL) 1719 return EINVAL; 1720 s = splimp (); 1721 cp_set_invrxc (c, *(int*)data); 1722 splx (s); 1723 return 0; 1724 1725 case SERIAL_GETLEVEL: 1726 CP_DEBUG2 (d, ("ioctl: getlevel\n")); 1727 if (c->type != T_G703) 1728 return EINVAL; 1729 s = splimp (); 1730 *(int*)data = cp_get_lq (c); 1731 splx (s); 1732 return 0; 1733 1734#if 0 1735 case SERIAL_RESET: 1736 CP_DEBUG2 (d, ("ioctl: reset\n")); 1737 /* Only for superuser! */ 1738#if __FreeBSD_version < 400000 1739 error = suser (p->p_ucred, &p->p_acflag); 1740#elif __FreeBSD_version < 500000 1741 error = suser (p); 1742#else 1743 error = suser (td); 1744#endif 1745 if (error) 1746 return error; 1747 s = splimp (); 1748 cp_reset (c->board, 0, 0); 1749 splx (s); 1750 return 0; 1751 1752 case SERIAL_HARDRESET: 1753 CP_DEBUG2 (d, ("ioctl: hardreset\n")); 1754 /* Only for superuser! */ 1755#if __FreeBSD_version < 400000 1756 error = suser (p->p_ucred, &p->p_acflag); 1757#elif __FreeBSD_version < 500000 1758 error = suser (p); 1759#else 1760 error = suser (td); 1761#endif 1762 if (error) 1763 return error; 1764 s = splimp (); 1765 /* hard_reset (c->board); */ 1766 splx (s); 1767 return 0; 1768#endif 1769 1770 case SERIAL_GETCABLE: 1771 CP_DEBUG2 (d, ("ioctl: getcable\n")); 1772 if (c->type != T_SERIAL) 1773 return EINVAL; 1774 s = splimp (); 1775 *(int*)data = cp_get_cable (c); 1776 splx (s); 1777 return 0; 1778 1779 case SERIAL_GETDIR: 1780 CP_DEBUG2 (d, ("ioctl: getdir\n")); 1781 if (c->type != T_E1 && c->type != T_DATA) 1782 return EINVAL; 1783 *(int*)data = c->dir; 1784 return 0; 1785 1786 case SERIAL_SETDIR: 1787 CP_DEBUG2 (d, ("ioctl: setdir\n")); 1788 /* Only for superuser! */ 1789#if __FreeBSD_version < 400000 1790 error = suser (p->p_ucred, &p->p_acflag); 1791#elif __FreeBSD_version < 500000 1792 error = suser (p); 1793#else 1794 error = suser (td); 1795#endif 1796 if (error) 1797 return error; 1798 s = splimp (); 1799 cp_set_dir (c, *(int*)data); 1800 splx (s); 1801 return 0; 1802 1803 case SERIAL_GETRLOOP: 1804 CP_DEBUG2 (d, ("ioctl: getrloop\n")); 1805 if (c->type != T_G703 && 1806 c->type != T_E3 && 1807 c->type != T_T3 && 1808 c->type != T_STS1) 1809 return EINVAL; 1810 *(int*)data = cp_get_rloop (c); 1811 return 0; 1812 1813 case SERIAL_SETRLOOP: 1814 CP_DEBUG2 (d, ("ioctl: setloop\n")); 1815 if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1) 1816 return EINVAL; 1817 /* Only for superuser! */ 1818#if __FreeBSD_version < 400000 1819 error = suser (p->p_ucred, &p->p_acflag); 1820#elif __FreeBSD_version < 500000 1821 error = suser (p); 1822#else 1823 error = suser (td); 1824#endif 1825 if (error) 1826 return error; 1827 s = splimp (); 1828 cp_set_rloop (c, *(int*)data); 1829 splx (s); 1830 return 0; 1831 1832 case SERIAL_GETCABLEN: 1833 CP_DEBUG2 (d, ("ioctl: getcablen\n")); 1834 if (c->type != T_T3 && c->type != T_STS1) 1835 return EINVAL; 1836 *(int*)data = c->cablen; 1837 return 0; 1838 1839 case SERIAL_SETCABLEN: 1840 CP_DEBUG2 (d, ("ioctl: setloop\n")); 1841 if (c->type != T_T3 && c->type != T_STS1) 1842 return EINVAL; 1843 /* Only for superuser! */ 1844#if __FreeBSD_version < 400000 1845 error = suser (p->p_ucred, &p->p_acflag); 1846#elif __FreeBSD_version < 500000 1847 error = suser (p); 1848#else 1849 error = suser (td); 1850#endif 1851 if (error) 1852 return error; 1853 s = splimp (); 1854 cp_set_cablen (c, *(int*)data); 1855 splx (s); 1856 return 0; 1857 1858 case TIOCSDTR: /* Set DTR */ 1859 s = splimp (); 1860 cp_set_dtr (c, 1); 1861 splx (s); 1862 return 0; 1863 1864 case TIOCCDTR: /* Clear DTR */ 1865 s = splimp (); 1866 cp_set_dtr (c, 0); 1867 splx (s); 1868 return 0; 1869 1870 case TIOCMSET: /* Set DTR/RTS */ 1871 s = splimp (); 1872 cp_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); 1873 cp_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); 1874 splx (s); 1875 return 0; 1876 1877 case TIOCMBIS: /* Add DTR/RTS */ 1878 s = splimp (); 1879 if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 1); 1880 if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 1); 1881 splx (s); 1882 return 0; 1883 1884 case TIOCMBIC: /* Clear DTR/RTS */ 1885 s = splimp (); 1886 if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 0); 1887 if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 0); 1888 splx (s); 1889 return 0; 1890 1891 case TIOCMGET: /* Get modem status */ 1892 *(int*)data = cp_modem_status (c); 1893 return 0; 1894 } 1895 return ENOTTY; 1896} 1897 1898#if __FreeBSD_version < 400000 1899static struct cdevsw cp_cdevsw = { 1900 cp_open, cp_close, noread, nowrite, 1901 cp_ioctl, nullstop, nullreset, nodevtotty, 1902 seltrue, nommap, NULL, "cp", 1903 NULL, -1 1904 }; 1905#elif __FreeBSD_version < 500000 1906static struct cdevsw cp_cdevsw = { 1907 cp_open, cp_close, noread, nowrite, 1908 cp_ioctl, nopoll, nommap, nostrategy, 1909 "cp", CDEV_MAJOR, nodump, nopsize, 1910 D_NAGGED, -1 1911 }; 1912#elif __FreeBSD_version == 500000 1913static struct cdevsw cp_cdevsw = { 1914 cp_open, cp_close, noread, nowrite, 1915 cp_ioctl, nopoll, nommap, nostrategy, 1916 "cp", CDEV_MAJOR, nodump, nopsize, 1917 D_NAGGED, 1918 }; 1919#elif __FreeBSD_version <= 501000 1920static struct cdevsw cp_cdevsw = { 1921 .d_open = cp_open, 1922 .d_close = cp_close, 1923 .d_read = noread, 1924 .d_write = nowrite, 1925 .d_ioctl = cp_ioctl, 1926 .d_poll = nopoll, 1927 .d_mmap = nommap, 1928 .d_strategy = nostrategy, 1929 .d_name = "cp", 1930 .d_maj = CDEV_MAJOR, 1931 .d_dump = nodump, 1932 .d_flags = D_NAGGED, 1933}; 1934#elif __FreeBSD_version < 502103 1935static struct cdevsw cp_cdevsw = { 1936 .d_open = cp_open, 1937 .d_close = cp_close, 1938 .d_ioctl = cp_ioctl, 1939 .d_name = "cp", 1940 .d_maj = CDEV_MAJOR, 1941 .d_flags = D_NAGGED, 1942}; 1943#else /* __FreeBSD_version >= 502103 */ 1944static struct cdevsw cp_cdevsw = { 1945 .d_version = D_VERSION, 1946 .d_open = cp_open, 1947 .d_close = cp_close, 1948 .d_ioctl = cp_ioctl, 1949 .d_name = "cp", 1950 .d_maj = CDEV_MAJOR, 1951 .d_flags = D_NEEDGIANT, 1952}; 1953#endif 1954 1955#ifdef NETGRAPH 1956#if __FreeBSD_version >= 500000 1957static int ng_cp_constructor (node_p node) 1958{ 1959 drv_t *d = NG_NODE_PRIVATE (node); 1960#else 1961static int ng_cp_constructor (node_p *node) 1962{ 1963 drv_t *d = (*node)->private; 1964#endif 1965 CP_DEBUG (d, ("Constructor\n")); 1966 return EINVAL; 1967} 1968 1969static int ng_cp_newhook (node_p node, hook_p hook, const char *name) 1970{ 1971 int s; 1972#if __FreeBSD_version >= 500000 1973 drv_t *d = NG_NODE_PRIVATE (node); 1974#else 1975 drv_t *d = node->private; 1976#endif 1977 1978 CP_DEBUG (d, ("Newhook\n")); 1979 /* Attach debug hook */ 1980 if (strcmp (name, NG_CP_HOOK_DEBUG) == 0) { 1981#if __FreeBSD_version >= 500000 1982 NG_HOOK_SET_PRIVATE (hook, NULL); 1983#else 1984 hook->private = 0; 1985#endif 1986 d->debug_hook = hook; 1987 return 0; 1988 } 1989 1990 /* Check for raw hook */ 1991 if (strcmp (name, NG_CP_HOOK_RAW) != 0) 1992 return EINVAL; 1993 1994#if __FreeBSD_version >= 500000 1995 NG_HOOK_SET_PRIVATE (hook, d); 1996#else 1997 hook->private = d; 1998#endif 1999 d->hook = hook; 2000 s = splimp (); 2001 cp_up (d); 2002 splx (s); 2003 return 0; 2004} 2005 2006static char *format_timeslots (u_long s) 2007{ 2008 static char buf [100]; 2009 char *p = buf; 2010 int i; 2011 2012 for (i=1; i<32; ++i) 2013 if ((s >> i) & 1) { 2014 int prev = (i > 1) & (s >> (i-1)); 2015 int next = (i < 31) & (s >> (i+1)); 2016 2017 if (prev) { 2018 if (next) 2019 continue; 2020 *p++ = '-'; 2021 } else if (p > buf) 2022 *p++ = ','; 2023 2024 if (i >= 10) 2025 *p++ = '0' + i / 10; 2026 *p++ = '0' + i % 10; 2027 } 2028 *p = 0; 2029 return buf; 2030} 2031 2032static int print_modems (char *s, cp_chan_t *c, int need_header) 2033{ 2034 int status = cp_modem_status (c); 2035 int length = 0; 2036 2037 if (need_header) 2038 length += sprintf (s + length, " LE DTR DSR RTS CTS CD\n"); 2039 length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n", 2040 status & TIOCM_LE ? "On" : "-", 2041 status & TIOCM_DTR ? "On" : "-", 2042 status & TIOCM_DSR ? "On" : "-", 2043 status & TIOCM_RTS ? "On" : "-", 2044 status & TIOCM_CTS ? "On" : "-", 2045 status & TIOCM_CD ? "On" : "-"); 2046 return length; 2047} 2048 2049static int print_stats (char *s, cp_chan_t *c, int need_header) 2050{ 2051 int length = 0; 2052 2053 if (need_header) 2054 length += sprintf (s + length, " Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); 2055 length += sprintf (s + length, "%7ld %7ld %7ld %8lu %7ld %7ld %8lu %7ld %7ld\n", 2056 c->rintr, c->tintr, 0l, (unsigned long) c->ibytes, 2057 c->ipkts, c->overrun + c->frame + c->crc, 2058 (unsigned long) c->obytes, c->opkts, c->underrun); 2059 return length; 2060} 2061 2062static char *format_e1_status (u_char status) 2063{ 2064 static char buf [80]; 2065 2066 if (status & E1_NOALARM) 2067 return "Ok"; 2068 buf[0] = 0; 2069 if (status & E1_LOS) strcat (buf, ",LOS"); 2070 if (status & E1_AIS) strcat (buf, ",AIS"); 2071 if (status & E1_LOF) strcat (buf, ",LOF"); 2072 if (status & E1_LOMF) strcat (buf, ",LOMF"); 2073 if (status & E1_FARLOF) strcat (buf, ",FARLOF"); 2074 if (status & E1_AIS16) strcat (buf, ",AIS16"); 2075 if (status & E1_FARLOMF) strcat (buf, ",FARLOMF"); 2076 if (status & E1_TSTREQ) strcat (buf, ",TSTREQ"); 2077 if (status & E1_TSTERR) strcat (buf, ",TSTERR"); 2078 if (buf[0] == ',') 2079 return buf+1; 2080 return "Unknown"; 2081} 2082 2083static int print_frac (char *s, int leftalign, u_long numerator, u_long divider) 2084{ 2085 int n, length = 0; 2086 2087 if (numerator < 1 || divider < 1) { 2088 length += sprintf (s+length, leftalign ? "/- " : " -"); 2089 return length; 2090 } 2091 n = (int) (0.5 + 1000.0 * numerator / divider); 2092 if (n < 1000) { 2093 length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n); 2094 return length; 2095 } 2096 *(s + length) = leftalign ? '/' : ' '; 2097 length ++; 2098 2099 if (n >= 1000000) n = (n+500) / 1000 * 1000; 2100 else if (n >= 100000) n = (n+50) / 100 * 100; 2101 else if (n >= 10000) n = (n+5) / 10 * 10; 2102 2103 switch (n) { 2104 case 1000: length += printf (s+length, ".999"); return length; 2105 case 10000: n = 9990; break; 2106 case 100000: n = 99900; break; 2107 case 1000000: n = 999000; break; 2108 } 2109 if (n < 10000) length += sprintf (s+length, "%d.%d", n/1000, n/10%100); 2110 else if (n < 100000) length += sprintf (s+length, "%d.%d", n/1000, n/100%10); 2111 else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000); 2112 else length += sprintf (s+length, "%d", n/1000); 2113 2114 return length; 2115} 2116 2117static int print_e1_stats (char *s, cp_chan_t *c) 2118{ 2119 struct e1_counters total; 2120 u_long totsec; 2121 int length = 0; 2122 2123 totsec = c->totsec + c->cursec; 2124 total.bpv = c->total.bpv + c->currnt.bpv; 2125 total.fse = c->total.fse + c->currnt.fse; 2126 total.crce = c->total.crce + c->currnt.crce; 2127 total.rcrce = c->total.rcrce + c->currnt.rcrce; 2128 total.uas = c->total.uas + c->currnt.uas; 2129 total.les = c->total.les + c->currnt.les; 2130 total.es = c->total.es + c->currnt.es; 2131 total.bes = c->total.bes + c->currnt.bes; 2132 total.ses = c->total.ses + c->currnt.ses; 2133 total.oofs = c->total.oofs + c->currnt.oofs; 2134 total.css = c->total.css + c->currnt.css; 2135 total.dm = c->total.dm + c->currnt.dm; 2136 2137 length += sprintf (s + length, " Unav/Degr Bpv/Fsyn CRC/RCRC Err/Lerr Sev/Bur Oof/Slp Status\n"); 2138 2139 /* Unavailable seconds, degraded minutes */ 2140 length += print_frac (s + length, 0, c->currnt.uas, c->cursec); 2141 length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec); 2142 2143 /* Bipolar violations, frame sync errors */ 2144 length += print_frac (s + length, 0, c->currnt.bpv, c->cursec); 2145 length += print_frac (s + length, 1, c->currnt.fse, c->cursec); 2146 2147 /* CRC errors, remote CRC errors (E-bit) */ 2148 length += print_frac (s + length, 0, c->currnt.crce, c->cursec); 2149 length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec); 2150 2151 /* Errored seconds, line errored seconds */ 2152 length += print_frac (s + length, 0, c->currnt.es, c->cursec); 2153 length += print_frac (s + length, 1, c->currnt.les, c->cursec); 2154 2155 /* Severely errored seconds, burst errored seconds */ 2156 length += print_frac (s + length, 0, c->currnt.ses, c->cursec); 2157 length += print_frac (s + length, 1, c->currnt.bes, c->cursec); 2158 2159 /* Out of frame seconds, controlled slip seconds */ 2160 length += print_frac (s + length, 0, c->currnt.oofs, c->cursec); 2161 length += print_frac (s + length, 1, c->currnt.css, c->cursec); 2162 2163 length += sprintf (s + length, " %s\n", format_e1_status (c->status)); 2164 2165 /* Print total statistics. */ 2166 length += print_frac (s + length, 0, total.uas, totsec); 2167 length += print_frac (s + length, 1, 60 * total.dm, totsec); 2168 2169 length += print_frac (s + length, 0, total.bpv, totsec); 2170 length += print_frac (s + length, 1, total.fse, totsec); 2171 2172 length += print_frac (s + length, 0, total.crce, totsec); 2173 length += print_frac (s + length, 1, total.rcrce, totsec); 2174 2175 length += print_frac (s + length, 0, total.es, totsec); 2176 length += print_frac (s + length, 1, total.les, totsec); 2177 2178 length += print_frac (s + length, 0, total.ses, totsec); 2179 length += print_frac (s + length, 1, total.bes, totsec); 2180 2181 length += print_frac (s + length, 0, total.oofs, totsec); 2182 length += print_frac (s + length, 1, total.css, totsec); 2183 2184 length += sprintf (s + length, " -- Total\n"); 2185 return length; 2186} 2187 2188static int print_chan (char *s, cp_chan_t *c) 2189{ 2190 drv_t *d = c->sys; 2191 int length = 0; 2192 2193 length += sprintf (s + length, "cp%d", c->board->num * NCHAN + c->num); 2194 if (d->chan->debug) 2195 length += sprintf (s + length, " debug=%d", d->chan->debug); 2196 2197 if (c->board->mux) { 2198 length += sprintf (s + length, " cfg=C"); 2199 } else { 2200 length += sprintf (s + length, " cfg=A"); 2201 } 2202 2203 if (c->baud) 2204 length += sprintf (s + length, " %ld", c->baud); 2205 else 2206 length += sprintf (s + length, " extclock"); 2207 2208 if (c->type == T_E1 || c->type == T_G703) 2209 switch (c->gsyn) { 2210 case GSYN_INT : length += sprintf (s + length, " syn=int"); break; 2211 case GSYN_RCV : length += sprintf (s + length, " syn=rcv"); break; 2212 case GSYN_RCV0 : length += sprintf (s + length, " syn=rcv0"); break; 2213 case GSYN_RCV1 : length += sprintf (s + length, " syn=rcv1"); break; 2214 case GSYN_RCV2 : length += sprintf (s + length, " syn=rcv2"); break; 2215 case GSYN_RCV3 : length += sprintf (s + length, " syn=rcv3"); break; 2216 } 2217 if (c->type == T_SERIAL) { 2218 length += sprintf (s + length, " dpll=%s", c->dpll ? "on" : "off"); 2219 length += sprintf (s + length, " nrzi=%s", c->nrzi ? "on" : "off"); 2220 length += sprintf (s + length, " invclk=%s", c->invtxc ? "on" : "off"); 2221 } 2222 if (c->type == T_E1) 2223 length += sprintf (s + length, " higain=%s", c->higain ? "on" : "off"); 2224 2225 length += sprintf (s + length, " loop=%s", c->lloop ? "on" : "off"); 2226 2227 if (c->type == T_E1) 2228 length += sprintf (s + length, " ts=%s", format_timeslots (c->ts)); 2229 if (c->type == T_G703) { 2230 int lq, x; 2231 2232 x = splimp (); 2233 lq = cp_get_lq (c); 2234 splx (x); 2235 length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0); 2236 } 2237 length += sprintf (s + length, "\n"); 2238 return length; 2239} 2240 2241#if __FreeBSD_version >= 500000 2242static int ng_cp_rcvmsg (node_p node, item_p item, hook_p lasthook) 2243{ 2244 drv_t *d = NG_NODE_PRIVATE (node); 2245 struct ng_mesg *msg; 2246#else 2247static int ng_cp_rcvmsg (node_p node, struct ng_mesg *msg, 2248 const char *retaddr, struct ng_mesg **rptr) 2249{ 2250 drv_t *d = node->private; 2251#endif 2252 struct ng_mesg *resp = NULL; 2253 int error = 0; 2254 2255 CP_DEBUG (d, ("Rcvmsg\n")); 2256#if __FreeBSD_version >= 500000 2257 NGI_GET_MSG (item, msg); 2258#endif 2259 switch (msg->header.typecookie) { 2260 default: 2261 error = EINVAL; 2262 break; 2263 2264 case NGM_CP_COOKIE: 2265 printf ("Not implemented yet\n"); 2266 error = EINVAL; 2267 break; 2268 2269 case NGM_GENERIC_COOKIE: 2270 switch (msg->header.cmd) { 2271 default: 2272 error = EINVAL; 2273 break; 2274 2275 case NGM_TEXT_STATUS: { 2276 char *s; 2277 int l = 0; 2278 int dl = sizeof (struct ng_mesg) + 730; 2279 2280#if __FreeBSD_version >= 500000 2281 NG_MKRESPONSE (resp, msg, dl, M_NOWAIT); 2282 if (! resp) { 2283 error = ENOMEM; 2284 break; 2285 } 2286#else 2287 MALLOC (resp, struct ng_mesg *, dl, 2288 M_NETGRAPH, M_NOWAIT); 2289 if (! resp) { 2290 error = ENOMEM; 2291 break; 2292 } 2293 bzero (resp, dl); 2294#endif 2295 s = (resp)->data; 2296 if (d) { 2297 l += print_chan (s + l, d->chan); 2298 l += print_stats (s + l, d->chan, 1); 2299 l += print_modems (s + l, d->chan, 1); 2300 l += print_e1_stats (s + l, d->chan); 2301 } else 2302 l += sprintf (s + l, "Error: node not connect to channel"); 2303#if __FreeBSD_version < 500000 2304 (resp)->header.version = NG_VERSION; 2305 (resp)->header.arglen = strlen (s) + 1; 2306 (resp)->header.token = msg->header.token; 2307 (resp)->header.typecookie = NGM_CP_COOKIE; 2308 (resp)->header.cmd = msg->header.cmd; 2309#endif 2310 strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN); 2311 } 2312 break; 2313 } 2314 break; 2315 } 2316#if __FreeBSD_version >= 500000 2317 NG_RESPOND_MSG (error, node, item, resp); 2318 NG_FREE_MSG (msg); 2319#else 2320 *rptr = resp; 2321 FREE (msg, M_NETGRAPH); 2322#endif 2323 return error; 2324} 2325 2326#if __FreeBSD_version >= 500000 2327static int ng_cp_rcvdata (hook_p hook, item_p item) 2328{ 2329 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook)); 2330 struct mbuf *m; 2331 meta_p meta; 2332#else 2333static int ng_cp_rcvdata (hook_p hook, struct mbuf *m, meta_p meta) 2334{ 2335 drv_t *d = hook->node->private; 2336#endif 2337 struct ifqueue *q; 2338 int s; 2339 2340 CP_DEBUG2 (d, ("Rcvdata\n")); 2341#if __FreeBSD_version >= 500000 2342 NGI_GET_M (item, m); 2343 NGI_GET_META (item, meta); 2344 NG_FREE_ITEM (item); 2345 if (! NG_HOOK_PRIVATE (hook) || ! d) { 2346 NG_FREE_M (m); 2347 NG_FREE_META (meta); 2348#else 2349 if (! hook->private || ! d) { 2350 NG_FREE_DATA (m,meta); 2351#endif 2352 return ENETDOWN; 2353 } 2354 q = (meta && meta->priority > 0) ? &d->hi_queue : &d->queue; 2355 s = splimp (); 2356#if __FreeBSD_version >= 500000 2357 IF_LOCK (q); 2358 if (_IF_QFULL (q)) { 2359 _IF_DROP (q); 2360 IF_UNLOCK (q); 2361 splx (s); 2362 NG_FREE_M (m); 2363 NG_FREE_META (meta); 2364 return ENOBUFS; 2365 } 2366 _IF_ENQUEUE (q, m); 2367 IF_UNLOCK (q); 2368#else 2369 if (IF_QFULL (q)) { 2370 IF_DROP (q); 2371 splx (s); 2372 NG_FREE_DATA (m, meta); 2373 return ENOBUFS; 2374 } 2375 IF_ENQUEUE (q, m); 2376#endif 2377 cp_start (d); 2378 splx (s); 2379 return 0; 2380} 2381 2382static int ng_cp_rmnode (node_p node) 2383{ 2384#if __FreeBSD_version >= 500000 2385 drv_t *d = NG_NODE_PRIVATE (node); 2386 2387 CP_DEBUG (d, ("Rmnode\n")); 2388 if (d && d->running) { 2389 int s = splimp (); 2390 cp_down (d); 2391 splx (s); 2392 } 2393#ifdef KLD_MODULE 2394 if (node->nd_flags & NG_REALLY_DIE) { 2395 NG_NODE_SET_PRIVATE (node, NULL); 2396 NG_NODE_UNREF (node); 2397 } 2398 node->nd_flags &= ~NG_INVALID; 2399#endif 2400#else /* __FreeBSD_version < 500000 */ 2401 drv_t *d = node->private; 2402 2403 if (d && d->running) { 2404 int s = splimp (); 2405 cp_down (d); 2406 splx (s); 2407 } 2408 2409 node->flags |= NG_INVALID; 2410 ng_cutlinks (node); 2411#ifdef KLD_MODULE 2412#if __FreeBSD_version >= 400000 2413 /* We do so because of pci module problem, see also comment in 2414 cp_unload. Not in 4.x. */ 2415 ng_unname (node); 2416 ng_unref (node); 2417#else 2418 node->flags &= ~NG_INVALID; 2419#endif 2420#endif 2421#endif 2422 return 0; 2423} 2424 2425static void ng_cp_watchdog (void *arg) 2426{ 2427 drv_t *d = arg; 2428 2429 if (d) { 2430 if (d->timeout == 1) 2431 cp_watchdog (d); 2432 if (d->timeout) 2433 d->timeout--; 2434 d->timeout_handle = timeout (ng_cp_watchdog, d, hz); 2435 } 2436} 2437 2438static int ng_cp_connect (hook_p hook) 2439{ 2440#if __FreeBSD_version >= 500000 2441 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2442#else 2443 drv_t *d = hook->node->private; 2444#endif 2445 2446 if (d) { 2447 CP_DEBUG (d, ("Connect\n")); 2448 d->timeout_handle = timeout (ng_cp_watchdog, d, hz); 2449 } 2450 2451 return 0; 2452} 2453 2454static int ng_cp_disconnect (hook_p hook) 2455{ 2456#if __FreeBSD_version >= 500000 2457 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2458#else 2459 drv_t *d = hook->node->private; 2460#endif 2461 2462 if (d) { 2463 CP_DEBUG (d, ("Disconnect\n")); 2464#if __FreeBSD_version >= 500000 2465 if (NG_HOOK_PRIVATE (hook)) 2466#else 2467 if (hook->private) 2468#endif 2469 { 2470 int s = splimp (); 2471 cp_down (d); 2472 splx (s); 2473 } 2474 untimeout (ng_cp_watchdog, d, d->timeout_handle); 2475 } 2476 return 0; 2477} 2478#endif 2479 2480#if __FreeBSD_version < 400000 2481 2482#ifdef KLD_MODULE 2483extern STAILQ_HEAD(devlist, pci_devinfo) pci_devq; 2484 2485static 2486struct pci_devinfo *pci_device_find (u_int16_t device, u_int16_t vendor, int unit) 2487{ 2488 pcicfgregs *cfg; 2489 struct pci_devinfo *dinfo; 2490 int u=0,i; 2491 2492 for (dinfo = STAILQ_FIRST (&pci_devq), i=0; 2493 dinfo && (i < pci_numdevs); 2494 dinfo = STAILQ_NEXT (dinfo, pci_links), i++) { 2495 cfg = &dinfo->cfg; 2496 if ((device == cfg->device) && (vendor == cfg->vendor)) { 2497 if (u == unit) 2498 return dinfo; 2499 u++; 2500 } 2501 } 2502 return 0; 2503} 2504 2505/* 2506 * Function called when loading the driver. 2507 */ 2508static int cp_load (void) 2509{ 2510 int i, s; 2511 pcicfgregs *cfg; 2512 struct pci_devinfo *dinfo; 2513 2514 s = splimp (); 2515 for (i=0; i<NBRD; ++i) { 2516 dinfo = pci_device_find (cp_device_id, cp_vendor_id, i); 2517 if (! dinfo) 2518 break; 2519 2520 cfg = &dinfo->cfg; 2521 cp_attach (cfg, i); 2522 dinfo->device = &cp_driver; 2523 strncpy (dinfo->conf.pd_name, cp_driver.pd_name, 2524 sizeof(dinfo->conf.pd_name)); 2525 dinfo->conf.pd_name[sizeof(dinfo->conf.pd_name) - 1] = 0; 2526 dinfo->conf.pd_unit = i; 2527 } 2528 splx (s); 2529 if (! i) { 2530 /* Deactivate the timeout routine. */ 2531 untimeout (cp_timeout, 0, timeout_handle); 2532 return ENXIO; 2533 } 2534 return 0; 2535} 2536 2537/* 2538 * Function called when unloading the driver. 2539 */ 2540static int cp_unload (void) 2541{ 2542#if 1 2543 /* Currently pci loadable module not fully supported, so we just 2544 return EBUSY. Do not forget to correct ng_cp_rmnode then probelm 2545 would be solved. */ 2546 return EBUSY; 2547#else 2548 int i, s; 2549 2550 /* Check if the device is busy (open). */ 2551 for (i=0; i<NBRD*NCHAN; ++i) { 2552 drv_t *d = channel[i]; 2553 2554 if (d && d->chan->type && d->running) 2555 return EBUSY; 2556 } 2557 2558 s = splimp (); 2559 2560 /* Deactivate the timeout routine. */ 2561 untimeout (cp_timeout, 0, timeout_handle); 2562 2563 /* OK to unload the driver, unregister the interrupt first. */ 2564 for (i=0; i<NBRD; ++i) { 2565 cp_board_t *b = adapter [i]; 2566 2567 if (!b || ! b->type) 2568 continue; 2569 2570 cp_reset (b, 0 ,0); 2571/* pci_unmap_int (tag, cp_intr, b, &net_imask);*/ 2572 /* Here should be something like pci_unmap_mem ()*/ 2573 } 2574 2575 for (i=0; i<NBRD; i++) 2576 if (led_timo[i].callout) 2577 untimeout (cp_led_off, adapter + i, led_timo[i]); 2578 2579 /* Detach the interfaces, free buffer memory. */ 2580 for (i=0; i<NBRD*NCHAN; ++i) { 2581 drv_t *d = channel[i]; 2582 2583 if (! d) 2584 continue; 2585#ifndef NETGRAPH 2586#if __FreeBSD_version >= 400000 || NBPFILTER > 0 2587 /* Detach from the packet filter list of interfaces. */ 2588 { 2589 struct bpf_if *q, **b = &bpf_iflist; 2590 2591 while ((q = *b)) { 2592 if (q->bif_ifp == d->pp.pp_if) { 2593 *b = q->bif_next; 2594 free (q, M_DEVBUF); 2595 } 2596 b = &(q->bif_next); 2597 } 2598 } 2599#endif 2600 /* Detach from the sync PPP list. */ 2601 sppp_detach (&d->pp.pp_if); 2602 2603 /* Detach from the system list of interfaces. */ 2604 { 2605 struct ifaddr *ifa; 2606 TAILQ_FOREACH (ifa, &d->pp.pp_if.if_addrhead, ifa_link) { 2607 TAILQ_REMOVE (&d->pp.pp_if.if_addrhead, ifa, ifa_link); 2608 free (ifa, M_IFADDR); 2609 } 2610 TAILQ_REMOVE (&ifnet, &d->pp.pp_if, if_link); 2611 } 2612#endif 2613 /* Deallocate buffers. */ 2614/* free (d, M_DEVBUF);*/ 2615 } 2616 2617 for (i=0; i<NBRD; ++i) { 2618 cp_board_t *b = adapter + i; 2619 2620 if (b && b->type) 2621 free (b, M_DEVBUF); 2622 } 2623 splx (s); 2624 return 0; 2625#endif 2626} 2627#endif 2628#endif 2629 2630#if __FreeBSD_version < 400000 2631#ifdef KLD_MODULE 2632static int cp_modevent (module_t mod, int type, void *unused) 2633{ 2634 dev_t dev; 2635 2636 switch (type) { 2637 case MOD_LOAD: 2638 dev = makedev (CDEV_MAJOR, 0); 2639 cdevsw_add (&dev, &cp_cdevsw, 0); 2640 timeout_handle = timeout (cp_timeout, 0, hz*5); 2641 return cp_load (); 2642 case MOD_UNLOAD: 2643 return cp_unload (); 2644 case MOD_SHUTDOWN: 2645 break; 2646 } 2647 return 0; 2648} 2649#endif /* KLD_MODULE */ 2650 2651#else /* __FreeBSD_version >= 400000 */ 2652static int cp_modevent (module_t mod, int type, void *unused) 2653{ 2654 dev_t dev; 2655 static int load_count = 0; 2656 struct cdevsw *cdsw; 2657 2658#if __FreeBSD_version >= 502103 2659 dev = udev2dev (makeudev(CDEV_MAJOR, 0)); 2660#else 2661 dev = makedev (CDEV_MAJOR, 0); 2662#endif 2663 switch (type) { 2664 case MOD_LOAD: 2665 if (dev != NODEV && 2666 (cdsw = devsw (dev)) && 2667 cdsw->d_maj == CDEV_MAJOR) { 2668 printf ("Tau-PCI driver is already in system\n"); 2669 return (ENXIO); 2670 } 2671#if __FreeBSD_version >= 500000 && defined NETGRAPH 2672 if (ng_newtype (&typestruct)) 2673 printf ("Failed to register ng_cp\n"); 2674#endif 2675 ++load_count; 2676#if __FreeBSD_version <= 500000 2677 cdevsw_add (&cp_cdevsw); 2678#endif 2679 timeout_handle = timeout (cp_timeout, 0, hz*5); 2680 break; 2681 case MOD_UNLOAD: 2682 if (load_count == 1) { 2683 printf ("Removing device entry for Tau-PCI\n"); 2684#if __FreeBSD_version <= 500000 2685 cdevsw_remove (&cp_cdevsw); 2686#endif 2687#if __FreeBSD_version >= 500000 && defined NETGRAPH 2688 ng_rmtype (&typestruct); 2689#endif 2690 } 2691 untimeout (cp_timeout, 0, timeout_handle); 2692 --load_count; 2693 break; 2694 case MOD_SHUTDOWN: 2695 break; 2696 } 2697 return 0; 2698} 2699#endif /* __FreeBSD_version < 400000 */ 2700 2701#ifdef NETGRAPH 2702static struct ng_type typestruct = { 2703 .version = NG_ABI_VERSION, 2704 .name = NG_CP_NODE_TYPE, 2705 .constructor = ng_cp_constructor, 2706 .rcvmsg = ng_cp_rcvmsg, 2707 .shutdown = ng_cp_rmnode, 2708 .newhook = ng_cp_newhook, 2709 .connect = ng_cp_connect, 2710 .rcvdata = ng_cp_rcvdata, 2711 .disconnect = ng_cp_disconnect, 2712}; 2713#if __FreeBSD_version < 400000 2714NETGRAPH_INIT_ORDERED (cp, &typestruct, SI_SUB_DRIVERS,\ 2715 SI_ORDER_MIDDLE + CDEV_MAJOR); 2716#endif 2717#endif /*NETGRAPH*/ 2718 2719#if __FreeBSD_version >= 500000 2720#ifdef NETGRAPH 2721MODULE_DEPEND (ng_cp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 2722#else 2723MODULE_DEPEND (cp, sppp, 1, 1, 1); 2724#endif 2725#ifdef KLD_MODULE 2726DRIVER_MODULE (cpmod, pci, cp_driver, cp_devclass, cp_modevent, NULL); 2727#else 2728DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL); 2729#endif 2730#elif __FreeBSD_version >= 400000 2731#ifdef NETGRAPH 2732DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, ng_mod_event, &typestruct); 2733#else 2734DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL); 2735#endif 2736#else /* __FreeBSD_version < 400000 */ 2737#ifdef KLD_MODULE 2738#ifndef NETGRAPH 2739static moduledata_t cpmod = { "cp", cp_modevent, NULL}; 2740DECLARE_MODULE (cp, cpmod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR); 2741#endif 2742#else /* KLD_MODULE */ 2743 2744/* 2745 * Now for some driver initialisation. 2746 * Occurs ONCE during boot (very early). 2747 * This is if we are NOT a loadable module. 2748 */ 2749static void cp_drvinit (void *unused) 2750{ 2751 dev_t dev; 2752 2753 dev = makedev (CDEV_MAJOR, 0); 2754 cdevsw_add (&dev, &cp_cdevsw, 0); 2755 2756 /* Activate the timeout routine. */ 2757 timeout_handle = timeout (cp_timeout, 0, hz); 2758#ifdef NETGRAPH 2759#if 0 2760 /* Register our node type in netgraph */ 2761 if (ng_newtype (&typestruct)) 2762 printf ("Failed to register ng_cp\n"); 2763#endif 2764#endif 2765} 2766 2767SYSINIT (cpdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, cp_drvinit, 0) 2768#endif /* KLD_MODULE */ 2769#endif /* __FreeBSD_version < 400000 */ 2770#endif /* NPCI */ 2771