if_cx.c revision 131108
1123120Simp/* 2123120Simp * Cronyx-Sigma adapter driver for FreeBSD. 3123120Simp * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode, 4123120Simp * and asyncronous channels with full modem control. 5123120Simp * Keepalive protocol implemented in both Cisco and PPP modes. 6123120Simp * 7123120Simp * Copyright (C) 1994-2002 Cronyx Engineering. 8123120Simp * Author: Serge Vakulenko, <vak@cronyx.ru> 9123120Simp * 10125813Srik * Copyright (C) 1999-2004 Cronyx Engineering. 11123120Simp * Rewritten on DDK, ported to NETGRAPH, rewritten for FreeBSD 3.x-5.x by 12123120Simp * Kurakin Roman, <rik@cronyx.ru> 13123120Simp * 14123120Simp * This software is distributed with NO WARRANTIES, not even the implied 15123120Simp * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16123120Simp * 17123120Simp * Authors grant any other persons or organisations a permission to use, 18123120Simp * modify and redistribute this software in source and binary forms, 19123120Simp * as long as this message is kept with the software, all derivative 20123120Simp * works or modified versions. 21123120Simp * 22130985Srik * Cronyx Id: if_cx.c,v 1.1.2.34 2004/06/23 17:09:13 rik Exp $ 23123120Simp */ 24130985Srik 25123120Simp#include <sys/cdefs.h> 26123120Simp__FBSDID("$FreeBSD: head/sys/dev/cx/if_cx.c 131108 2004-06-25 19:22:05Z julian $"); 27123120Simp 28123120Simp#include <sys/param.h> 29123120Simp 30123120Simp#if __FreeBSD_version >= 500000 31123120Simp# define NCX 1 32123120Simp#else 33123120Simp# include "cx.h" 34123120Simp#endif 35123120Simp 36123120Simp#if NCX > 0 37123120Simp#include <sys/systm.h> 38123120Simp#include <sys/kernel.h> 39129879Sphk#include <sys/module.h> 40123120Simp#include <sys/proc.h> 41123120Simp#include <sys/mbuf.h> 42123120Simp#include <sys/sockio.h> 43123120Simp#include <sys/malloc.h> 44123120Simp#include <sys/socket.h> 45123120Simp#include <sys/conf.h> 46123120Simp#include <sys/errno.h> 47123120Simp#include <sys/tty.h> 48130971Srik#include <sys/bus.h> 49130971Srik#include <machine/bus.h> 50130971Srik#include <sys/rman.h> 51130971Srik#include <isa/isavar.h> 52123120Simp#include <sys/fcntl.h> 53123120Simp#include <sys/interrupt.h> 54123120Simp#include <vm/vm.h> 55123120Simp#include <vm/pmap.h> 56123120Simp#include <net/if.h> 57123120Simp#include <machine/cpufunc.h> 58123120Simp#include <machine/cserial.h> 59123120Simp#include <machine/clock.h> 60123120Simp#if __FreeBSD_version < 500000 61130985Srik# include <machine/ipl.h> 62130985Srik# include <i386/isa/isa_device.h> 63123120Simp#endif 64130971Srik#include <machine/resource.h> 65130971Srik#if __FreeBSD_version <= 501000 66130971Srik# include <i386/isa/intr_machdep.h> 67123120Simp#endif 68130971Srik#include <dev/cx/machdep.h> 69130971Srik#include <dev/cx/cxddk.h> 70130971Srik#include <dev/cx/cronyxfw.h> 71123120Simp#include "opt_ng_cronyx.h" 72123120Simp#ifdef NETGRAPH_CRONYX 73123120Simp# include "opt_netgraph.h" 74123120Simp# include <netgraph/ng_message.h> 75123120Simp# include <netgraph/netgraph.h> 76130971Srik# include <dev/cx/ng_cx.h> 77123120Simp#else 78123120Simp# include <net/if_types.h> 79123120Simp# if __FreeBSD_version < 500000 80123120Simp# include "sppp.h" 81123120Simp# if NSPPP <= 0 82129027Srik# error The device cx requires sppp or netgraph. 83123120Simp# endif 84123120Simp# endif 85123120Simp# include <net/if_sppp.h> 86123120Simp# define PP_CISCO IFF_LINK2 87123120Simp# if __FreeBSD_version < 500000 88123120Simp# include <bpf.h> 89123120Simp# endif 90123120Simp# include <net/bpf.h> 91123120Simp# define NBPFILTER NBPF 92123120Simp#endif 93123120Simp 94130095Sphk#if __FreeBSD_version < 502113 95130095Sphk#define ttyld_modem(foo, bar) ((*linesw[(foo)->t_line].l_modem)((foo), (bar))) 96130095Sphk#define ttyld_rint(foo, bar) ((*linesw[(foo)->t_line].l_rint)((bar), (foo))) 97130095Sphk#define ttyld_start(foo) ((*linesw[(foo)->t_line].l_start)((foo))) 98130095Sphk#define ttyld_open(foo, bar) ((*linesw[(foo)->t_line].l_open) ((bar), (foo))) 99130095Sphk#define ttyld_close(foo, bar) ((*linesw[(foo)->t_line].l_close) ((foo), (bar))) 100130095Sphk#define ttyld_read(foo, bar, barf) ((*linesw[(foo)->t_line].l_read) ((foo), (bar), (barf))) 101130095Sphk#define ttyld_write(foo, bar, barf) ((*linesw[(foo)->t_line].l_write) ((foo), (bar), (barf))) 102130095Sphk#endif 103130095Sphk 104129029Srik/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */ 105129029Srik#ifndef PP_FR 106129029Srik#define PP_FR 0 107129029Srik#endif 108129029Srik 109123120Simp#define CX_DEBUG(d,s) ({if (d->chan->debug) {\ 110123120Simp printf ("%s: ", d->name); printf s;}}) 111123120Simp#define CX_DEBUG2(d,s) ({if (d->chan->debug>1) {\ 112123120Simp printf ("%s: ", d->name); printf s;}}) 113123120Simp 114123120Simp#define UNIT(d) (minor(d) & 0x3f) 115123120Simp#define IF_CUNIT(d) (minor(d) & 0x40) 116123120Simp#define UNIT_CTL 0x3f 117123120Simp#define CALLOUT(d) (minor(d) & 0x80) 118123120Simp#define CDEV_MAJOR 42 119123120Simp 120123120Simptypedef struct _async_q { 121123120Simp int beg; 122123120Simp int end; 123123120Simp #define BF_SZ 14400 124123120Simp int buf[BF_SZ+1]; 125123120Simp} async_q; 126123120Simp 127123120Simp#define AQ_GSZ(q) ((BF_SZ + (q)->end - (q)->beg)%BF_SZ) 128123120Simp#define AQ_PUSH(q,c) {*((q)->buf + (q)->end) = c;\ 129123120Simp (q)->end = ((q)->end + 1)%BF_SZ;} 130123120Simp#define AQ_POP(q,c) {c = *((q)->buf + (q)->beg);\ 131123120Simp (q)->beg = ((q)->beg + 1)%BF_SZ;} 132123120Simp 133123120Simpstatic void cx_identify __P((driver_t *, device_t)); 134123120Simpstatic int cx_probe __P((device_t)); 135123120Simpstatic int cx_attach __P((device_t)); 136123120Simpstatic int cx_detach __P((device_t)); 137123120Simp 138123120Simpstatic device_method_t cx_isa_methods [] = { 139123120Simp DEVMETHOD(device_identify, cx_identify), 140123120Simp DEVMETHOD(device_probe, cx_probe), 141123120Simp DEVMETHOD(device_attach, cx_attach), 142123120Simp DEVMETHOD(device_detach, cx_detach), 143123120Simp {0, 0} 144123120Simp}; 145123120Simp 146130985Sriktypedef struct _cx_dma_mem_t { 147130985Srik unsigned long phys; 148130985Srik void *virt; 149130985Srik size_t size; 150130985Srik#if __FreeBSD_version >= 500000 151130985Srik bus_dma_tag_t dmat; 152130985Srik bus_dmamap_t mapp; 153130985Srik#endif 154130985Srik} cx_dma_mem_t; 155123120Simp 156123120Simptypedef struct _drv_t { 157123120Simp char name [8]; 158123120Simp cx_chan_t *chan; 159123120Simp cx_board_t *board; 160130985Srik cx_dma_mem_t dmamem; 161130240Srik struct tty *tty; 162123120Simp struct callout_handle dcd_timeout_handle; 163123120Simp unsigned dtrwait; 164123120Simp unsigned dtroff; 165123120Simp unsigned callout; 166123120Simp unsigned lock; 167123120Simp int open_dev; 168123120Simp int cd; 169123120Simp int running; 170123120Simp struct callout_handle dtr_timeout_handle; 171123120Simp#ifdef NETGRAPH 172123120Simp char nodename [NG_NODELEN+1]; 173123120Simp hook_p hook; 174123120Simp hook_p debug_hook; 175123120Simp node_p node; 176123120Simp struct ifqueue lo_queue; 177123120Simp struct ifqueue hi_queue; 178123120Simp short timeout; 179123120Simp struct callout_handle timeout_handle; 180123120Simp#else 181123120Simp struct sppp pp; 182123120Simp#endif 183130585Sphk struct cdev *devt[3]; 184123120Simp async_q aqueue; 185130971Srik#define CX_READ 1 186130971Srik#define CX_WRITE 2 187123120Simp int intr_action; 188123120Simp short atimeout; 189123120Simp} drv_t; 190123120Simp 191130985Sriktypedef struct _bdrv_t { 192130985Srik cx_board_t *board; 193130985Srik struct resource *base_res; 194130985Srik struct resource *drq_res; 195130985Srik struct resource *irq_res; 196130985Srik int base_rid; 197130985Srik int drq_rid; 198130985Srik int irq_rid; 199130985Srik void *intrhand; 200130985Srik drv_t channel [NCHAN]; 201130985Srik} bdrv_t; 202130985Srik 203130985Srikstatic driver_t cx_isa_driver = { 204130985Srik "cx", 205130985Srik cx_isa_methods, 206130985Srik sizeof (bdrv_t), 207130985Srik}; 208130985Srik 209130985Srikstatic devclass_t cx_devclass; 210130985Srik 211123120Simpextern long csigma_fw_len; 212123120Simpextern const char *csigma_fw_version; 213123120Simpextern const char *csigma_fw_date; 214123120Simpextern const char *csigma_fw_copyright; 215123120Simpextern const cr_dat_tst_t csigma_fw_tvec[]; 216123120Simpextern const u_char csigma_fw_data[]; 217123120Simpstatic void cx_oproc (struct tty *tp); 218123120Simpstatic int cx_param (struct tty *tp, struct termios *t); 219123120Simpstatic void cx_stop (struct tty *tp, int flag); 220123120Simpstatic void cx_dtrwakeup (void *a); 221123120Simpstatic void cx_receive (cx_chan_t *c, char *data, int len); 222123120Simpstatic void cx_transmit (cx_chan_t *c, void *attachment, int len); 223123120Simpstatic void cx_error (cx_chan_t *c, int data); 224123120Simpstatic void cx_modem (cx_chan_t *c); 225123120Simpstatic void cx_up (drv_t *d); 226123120Simpstatic void cx_start (drv_t *d); 227130096Sphk#if __FreeBSD_version < 502113 228130096Sphkstatic void ttyldoptim(struct tty *tp); 229130096Sphk#endif 230123120Simp#if __FreeBSD_version < 500000 231123120Simpstatic swihand_t cx_softintr; 232123120Simp#else 233123120Simpstatic void cx_softintr (void *); 234123120Simpstatic void *cx_fast_ih; 235123120Simp#endif 236123120Simpstatic void cx_down (drv_t *d); 237123120Simpstatic void cx_watchdog (drv_t *d); 238123120Simpstatic void cx_carrier (void *arg); 239123120Simp 240123120Simp#ifdef NETGRAPH 241123120Simpextern struct ng_type typestruct; 242123120Simp#else 243123120Simpstatic void cx_ifstart (struct ifnet *ifp); 244123120Simpstatic void cx_tlf (struct sppp *sp); 245123120Simpstatic void cx_tls (struct sppp *sp); 246123120Simpstatic void cx_ifwatchdog (struct ifnet *ifp); 247123120Simpstatic int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 248123120Simpstatic void cx_initialize (void *softc); 249123120Simp#endif 250123120Simp 251123120Simpstatic cx_board_t *adapter [NCX]; 252123120Simpstatic drv_t *channel [NCX*NCHAN]; 253123120Simpstatic struct callout_handle led_timo [NCX]; 254123120Simpstatic struct callout_handle timeout_handle; 255130971Srikextern struct cdevsw cx_cdevsw; 256123120Simp 257123120Simpstatic int MY_SOFT_INTR; 258123120Simp 259123120Simp/* 260123120Simp * Print the mbuf chain, for debug purposes only. 261123120Simp */ 262123120Simpstatic void printmbuf (struct mbuf *m) 263123120Simp{ 264123120Simp printf ("mbuf:"); 265123120Simp for (; m; m=m->m_next) { 266123120Simp if (m->m_flags & M_PKTHDR) 267123120Simp printf (" HDR %d:", m->m_pkthdr.len); 268123120Simp if (m->m_flags & M_EXT) 269123120Simp printf (" EXT:"); 270123120Simp printf (" %d", m->m_len); 271123120Simp } 272123120Simp printf ("\n"); 273123120Simp} 274123120Simp 275123120Simp/* 276123120Simp * Make an mbuf from data. 277123120Simp */ 278123120Simpstatic struct mbuf *makembuf (void *buf, u_int len) 279123120Simp{ 280123120Simp struct mbuf *m, *o, *p; 281123120Simp 282123120Simp MGETHDR (m, M_DONTWAIT, MT_DATA); 283123120Simp 284123120Simp if (! m) 285123120Simp return 0; 286123120Simp 287123120Simp if (len >= MINCLSIZE) 288123120Simp MCLGET (m, M_DONTWAIT); 289123120Simp 290123120Simp m->m_pkthdr.len = len; 291123120Simp m->m_len = 0; 292123120Simp 293123120Simp p = m; 294123120Simp while (len) { 295123120Simp u_int n = M_TRAILINGSPACE (p); 296123120Simp if (n > len) 297123120Simp n = len; 298123120Simp if (! n) { 299123120Simp /* Allocate new mbuf. */ 300123120Simp o = p; 301123120Simp MGET (p, M_DONTWAIT, MT_DATA); 302123120Simp if (! p) { 303123120Simp m_freem (m); 304123120Simp return 0; 305123120Simp } 306123120Simp if (len >= MINCLSIZE) 307123120Simp MCLGET (p, M_DONTWAIT); 308123120Simp p->m_len = 0; 309123120Simp o->m_next = p; 310123120Simp 311123120Simp n = M_TRAILINGSPACE (p); 312123120Simp if (n > len) 313123120Simp n = len; 314123120Simp } 315123120Simp bcopy (buf, mtod (p, caddr_t) + p->m_len, n); 316123120Simp 317123120Simp p->m_len += n; 318123120Simp buf = n + (char*) buf; 319123120Simp len -= n; 320123120Simp } 321123120Simp return m; 322123120Simp} 323123120Simp 324123120Simp/* 325123120Simp * Recover after lost transmit interrupts. 326123120Simp */ 327123120Simpstatic void cx_timeout (void *arg) 328123120Simp{ 329123120Simp drv_t *d; 330123120Simp int s, i; 331123120Simp 332123120Simp for (i=0; i<NCX*NCHAN; ++i) { 333123120Simp d = channel[i]; 334123120Simp if (! d) 335123120Simp continue; 336123120Simp s = splhigh (); 337130240Srik if (d->atimeout == 1 && d->tty && d->tty->t_state & TS_BUSY) { 338130240Srik d->tty->t_state &= ~TS_BUSY; 339130240Srik if (d->tty->t_dev) { 340123120Simp d->intr_action |= CX_WRITE; 341123120Simp MY_SOFT_INTR = 1; 342123120Simp#if __FreeBSD_version >= 500000 343123120Simp swi_sched (cx_fast_ih, 0); 344123120Simp#else 345123120Simp setsofttty (); 346123120Simp#endif 347123120Simp } 348123120Simp CX_DEBUG (d, ("cx_timeout\n")); 349123120Simp } 350123120Simp if (d->atimeout) 351123120Simp d->atimeout--; 352123120Simp splx (s); 353123120Simp } 354123120Simp timeout_handle = timeout (cx_timeout, 0, hz*5); 355123120Simp} 356123120Simp 357123120Simpstatic void cx_led_off (void *arg) 358123120Simp{ 359123120Simp cx_board_t *b = arg; 360123120Simp int s = splhigh (); 361123120Simp 362123120Simp cx_led (b, 0); 363123120Simp led_timo[b->num].callout = 0; 364123120Simp splx (s); 365123120Simp} 366123120Simp 367123120Simp/* 368123120Simp * Activate interupt handler from DDK. 369123120Simp */ 370123120Simpstatic void cx_intr (void *arg) 371123120Simp{ 372123120Simp bdrv_t *bd = arg; 373123120Simp cx_board_t *b = bd->board; 374123120Simp int s = splhigh (); 375123120Simp 376123120Simp /* Turn LED on. */ 377123120Simp cx_led (b, 1); 378123120Simp 379123120Simp cx_int_handler (b); 380123120Simp 381123120Simp /* Turn LED off 50 msec later. */ 382123120Simp if (! led_timo[b->num].callout) 383123120Simp led_timo[b->num] = timeout (cx_led_off, b, hz/20); 384123120Simp splx (s); 385123120Simp} 386123120Simp 387123120Simpstatic int probe_irq (cx_board_t *b, int irq) 388123120Simp{ 389123120Simp int mask, busy, cnt; 390123120Simp 391123120Simp /* Clear pending irq, if any. */ 392123120Simp cx_probe_irq (b, -irq); 393123120Simp DELAY (100); 394123120Simp for (cnt=0; cnt<5; ++cnt) { 395123120Simp /* Get the mask of pending irqs, assuming they are busy. 396123120Simp * Activate the adapter on given irq. */ 397123120Simp busy = cx_probe_irq (b, irq); 398123120Simp DELAY (100); 399123120Simp 400123120Simp /* Get the mask of active irqs. 401123120Simp * Deactivate our irq. */ 402123120Simp mask = cx_probe_irq (b, -irq); 403123120Simp DELAY (100); 404123120Simp if ((mask & ~busy) == 1 << irq) { 405123120Simp cx_probe_irq (b, 0); 406123120Simp /* printf ("cx%d: irq %d ok, mask=0x%04x, busy=0x%04x\n", 407123120Simp b->num, irq, mask, busy); */ 408123120Simp return 1; 409123120Simp } 410123120Simp } 411123120Simp /* printf ("cx%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n", 412123120Simp b->num, irq, mask, busy); */ 413123120Simp cx_probe_irq (b, 0); 414123120Simp return 0; 415123120Simp} 416123120Simp 417123120Simpstatic short porttab [] = { 418123120Simp 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 419123120Simp 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 420123120Simp}; 421123120Simpstatic char dmatab [] = { 7, 6, 5, 0 }; 422123120Simpstatic char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 }; 423123120Simp 424123120Simpstatic int cx_is_free_res (device_t dev, int rid, int type, u_long start, 425123120Simp u_long end, u_long count) 426123120Simp{ 427123120Simp struct resource *res; 428123120Simp 429123120Simp if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count, 430123120Simp RF_ALLOCATED))) 431123120Simp return 0; 432123120Simp 433123120Simp bus_release_resource (dev, type, rid, res); 434123120Simp 435123120Simp return 1; 436123120Simp} 437123120Simp 438123120Simpstatic void cx_identify (driver_t *driver, device_t dev) 439123120Simp{ 440123120Simp u_long iobase, rescount; 441123120Simp int devcount; 442123120Simp device_t *devices; 443123120Simp device_t child; 444123120Simp devclass_t my_devclass; 445123120Simp int i, k; 446123120Simp 447123120Simp if ((my_devclass = devclass_find ("cx")) == NULL) 448123120Simp return; 449123120Simp 450123120Simp devclass_get_devices (my_devclass, &devices, &devcount); 451123120Simp 452123120Simp if (devcount == 0) { 453123120Simp /* We should find all devices by our self. We could alter other 454123120Simp * devices, but we don't have a choise 455123120Simp */ 456123120Simp for (i = 0; (iobase = porttab [i]) != 0; i++) { 457123120Simp if (!cx_is_free_res (dev, 1, SYS_RES_IOPORT, 458123120Simp iobase, iobase + NPORT, NPORT)) 459123120Simp continue; 460123120Simp if (cx_probe_board (iobase, -1, -1) == 0) 461123120Simp continue; 462123120Simp 463123120Simp devcount++; 464123120Simp 465123120Simp child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "cx", 466123120Simp -1); 467123120Simp 468123120Simp if (child == NULL) 469123120Simp return; 470123120Simp 471123120Simp device_set_desc_copy (child, "Cronyx Sigma"); 472123120Simp device_set_driver (child, driver); 473123120Simp bus_set_resource (child, SYS_RES_IOPORT, 0, 474123120Simp iobase, NPORT); 475123120Simp 476123120Simp if (devcount >= NCX) 477123120Simp break; 478123120Simp } 479123120Simp } else { 480123120Simp static short porttab [] = { 481123120Simp 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 482123120Simp 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 483123120Simp }; 484123120Simp /* Lets check user choise. 485123120Simp */ 486123120Simp for (k = 0; k < devcount; k++) { 487123120Simp if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, 488123120Simp &iobase, &rescount) != 0) 489123120Simp continue; 490123120Simp 491123120Simp for (i = 0; porttab [i] != 0; i++) { 492123120Simp if (porttab [i] != iobase) 493123120Simp continue; 494123120Simp if (!cx_is_free_res (devices[k], 1, SYS_RES_IOPORT, 495123120Simp iobase, iobase + NPORT, NPORT)) 496123120Simp continue; 497123120Simp if (cx_probe_board (iobase, -1, -1) == 0) 498123120Simp continue; 499123120Simp porttab [i] = -1; 500123120Simp device_set_desc_copy (devices[k], "Cronyx Sigma"); 501123120Simp break; 502123120Simp } 503123120Simp 504123120Simp if (porttab [i] == 0) { 505123120Simp device_delete_child ( 506123120Simp device_get_parent (devices[k]), 507123120Simp devices [k]); 508123120Simp devices[k] = 0; 509123120Simp continue; 510123120Simp } 511123120Simp } 512123120Simp for (k = 0; k < devcount; k++) { 513123120Simp if (devices[k] == 0) 514123120Simp continue; 515123120Simp if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, 516123120Simp &iobase, &rescount) == 0) 517123120Simp continue; 518123120Simp for (i = 0; (iobase = porttab [i]) != 0; i++) { 519123120Simp if (porttab [i] == -1) { 520123120Simp continue; 521123120Simp } 522123120Simp if (!cx_is_free_res (devices[k], 1, SYS_RES_IOPORT, 523123120Simp iobase, iobase + NPORT, NPORT)) 524123120Simp continue; 525123120Simp if (cx_probe_board (iobase, -1, -1) == 0) 526123120Simp continue; 527123120Simp 528123120Simp bus_set_resource (devices[k], SYS_RES_IOPORT, 0, 529123120Simp iobase, NPORT); 530123120Simp porttab [i] = -1; 531123120Simp device_set_desc_copy (devices[k], "Cronyx Sigma"); 532123120Simp break; 533123120Simp } 534123120Simp if (porttab [i] == 0) { 535123120Simp device_delete_child ( 536123120Simp device_get_parent (devices[k]), 537123120Simp devices [k]); 538123120Simp } 539123120Simp } 540123120Simp free (devices, M_TEMP); 541123120Simp } 542123120Simp 543123120Simp return; 544123120Simp} 545123120Simp 546123120Simpstatic int cx_probe (device_t dev) 547123120Simp{ 548123120Simp int unit = device_get_unit (dev); 549123120Simp int i; 550123120Simp u_long iobase, rescount; 551123120Simp 552123120Simp if (!device_get_desc (dev) || 553123120Simp strcmp (device_get_desc (dev), "Cronyx Sigma")) 554123120Simp return ENXIO; 555123120Simp 556123120Simp if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) { 557123120Simp printf ("cx%d: Couldn't get IOPORT\n", unit); 558123120Simp return ENXIO; 559123120Simp } 560123120Simp 561123120Simp if (!cx_is_free_res (dev, 1, SYS_RES_IOPORT, 562123120Simp iobase, iobase + NPORT, NPORT)) { 563123120Simp printf ("cx%d: Resource IOPORT isn't free %lx\n", unit, iobase); 564123120Simp return ENXIO; 565123120Simp } 566123120Simp 567123120Simp for (i = 0; porttab [i] != 0; i++) { 568123120Simp if (porttab [i] == iobase) { 569123120Simp porttab [i] = -1; 570123120Simp break; 571123120Simp } 572123120Simp } 573123120Simp 574123120Simp if (porttab [i] == 0) { 575123120Simp return ENXIO; 576123120Simp } 577123120Simp 578123120Simp if (!cx_probe_board (iobase, -1, -1)) { 579123120Simp printf ("cx%d: probing for Sigma at %lx faild\n", unit, iobase); 580123120Simp return ENXIO; 581123120Simp } 582123120Simp 583123120Simp return 0; 584123120Simp} 585123120Simp 586130985Srik#if __FreeBSD_version >= 500000 587130985Srikstatic void 588130985Srikcx_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) 589130985Srik{ 590130985Srik unsigned long *addr; 591130985Srik 592130985Srik if (error) 593130985Srik return; 594130985Srik 595130985Srik KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 596130985Srik addr = arg; 597130985Srik *addr = segs->ds_addr; 598130985Srik} 599130985Srik 600130985Srikstatic int 601130985Srikcx_bus_dma_mem_alloc (int bnum, int cnum, cx_dma_mem_t *dmem) 602130985Srik{ 603130985Srik int error; 604130985Srik 605130985Srik error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT, 606130985Srik BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1, 607130985Srik dmem->size, 0, NULL, NULL, &dmem->dmat); 608130985Srik if (error) { 609130985Srik if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); 610130985Srik else printf ("cx%d: ", bnum); 611130985Srik printf ("couldn't allocate tag for dma memory\n"); 612130985Srik return 0; 613130985Srik } 614130985Srik error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt, 615130985Srik BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp); 616130985Srik if (error) { 617130985Srik if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); 618130985Srik else printf ("cx%d: ", bnum); 619130985Srik printf ("couldn't allocate mem for dma memory\n"); 620130985Srik bus_dma_tag_destroy (dmem->dmat); 621130985Srik return 0; 622130985Srik } 623130985Srik error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt, 624130985Srik dmem->size, cx_bus_dmamap_addr, &dmem->phys, 0); 625130985Srik if (error) { 626130985Srik if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); 627130985Srik else printf ("cx%d: ", bnum); 628130985Srik printf ("couldn't load mem map for dma memory\n"); 629130985Srik bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); 630130985Srik bus_dma_tag_destroy (dmem->dmat); 631130985Srik return 0; 632130985Srik } 633130985Srik return 1; 634130985Srik} 635130985Srik 636130985Srikstatic void 637130985Srikcx_bus_dma_mem_free (cx_dma_mem_t *dmem) 638130985Srik{ 639130985Srik bus_dmamap_unload (dmem->dmat, dmem->mapp); 640130985Srik bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp); 641130985Srik bus_dma_tag_destroy (dmem->dmat); 642130985Srik} 643130985Srik#else 644130985Srikstatic int 645130985Srikcx_bus_dma_mem_alloc (int bnum, int cnum, cx_dma_mem_t *dmem) 646130985Srik{ 647130985Srik dmem->virt = contigmalloc (dmem->size, M_DEVBUF, M_WAITOK, 648130985Srik 0x100000, 0x1000000, 16, 0); 649130985Srik if (dmem->virt == NULL) { 650130985Srik if (cnum >= 0) printf ("cx%d-%d: ", bnum, cnum); 651130985Srik else printf ("cx%d: ", bnum); 652130985Srik printf ("couldn't allocate memory for dma memory\n", unit); 653130985Srik return 0; 654130985Srik } 655130985Srik dmem->phys = vtophys (dmem->virt); 656130985Srik return 1; 657130985Srik} 658130985Srik 659130985Srikstatic void 660130985Srikcx_bus_dma_mem_free (cx_dma_mem_t *dmem) 661130985Srik{ 662130985Srik contigfree (dmem->virt, dmem->size, M_DEVBUF); 663130985Srik} 664130985Srik#endif 665130985Srik 666123120Simp/* 667123120Simp * The adapter is present, initialize the driver structures. 668123120Simp */ 669123120Simpstatic int cx_attach (device_t dev) 670123120Simp{ 671123120Simp bdrv_t *bd = device_get_softc (dev); 672123120Simp u_long iobase, drq, irq, rescount; 673123120Simp int unit = device_get_unit (dev); 674123120Simp cx_board_t *b; 675123120Simp cx_chan_t *c; 676123120Simp drv_t *d; 677130971Srik int i; 678130971Srik int s; 679123120Simp 680123120Simp KASSERT ((bd != NULL), ("cx%d: NULL device softc\n", unit)); 681123120Simp 682123120Simp bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount); 683123120Simp bd->base_rid = 0; 684123120Simp bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid, 685123120Simp iobase, iobase + NPORT, NPORT, RF_ACTIVE); 686123120Simp if (! bd->base_res) { 687123120Simp printf ("cx%d: cannot allocate base address\n", unit); 688123120Simp return ENXIO; 689123120Simp } 690123120Simp 691123120Simp if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) { 692123120Simp for (i = 0; (drq = dmatab [i]) != 0; i++) { 693123120Simp if (!cx_is_free_res (dev, 1, SYS_RES_DRQ, 694123120Simp drq, drq + 1, 1)) 695123120Simp continue; 696123120Simp bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1); 697123120Simp break; 698123120Simp } 699123120Simp 700123120Simp if (dmatab[i] == 0) { 701123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 702123120Simp bd->base_res); 703123120Simp printf ("cx%d: Couldn't get DRQ\n", unit); 704123120Simp return ENXIO; 705123120Simp } 706123120Simp } 707123120Simp 708123120Simp bd->drq_rid = 0; 709123120Simp bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid, 710123120Simp drq, drq + 1, 1, RF_ACTIVE); 711123120Simp if (! bd->drq_res) { 712123120Simp printf ("cx%d: cannot allocate drq\n", unit); 713123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 714123120Simp bd->base_res); 715123120Simp return ENXIO; 716123120Simp } 717123120Simp 718123120Simp if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) { 719123120Simp for (i = 0; (irq = irqtab [i]) != 0; i++) { 720123120Simp if (!cx_is_free_res (dev, 1, SYS_RES_IRQ, 721123120Simp irq, irq + 1, 1)) 722123120Simp continue; 723123120Simp bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1); 724123120Simp break; 725123120Simp } 726123120Simp 727123120Simp if (irqtab[i] == 0) { 728123120Simp bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 729123120Simp bd->drq_res); 730123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 731123120Simp bd->base_res); 732123120Simp printf ("cx%d: Couldn't get IRQ\n", unit); 733123120Simp return ENXIO; 734123120Simp } 735123120Simp } 736123120Simp 737123120Simp bd->irq_rid = 0; 738123120Simp bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid, 739123120Simp irq, irq + 1, 1, RF_ACTIVE); 740123120Simp if (! bd->irq_res) { 741123120Simp printf ("cx%d: Couldn't allocate irq\n", unit); 742123120Simp bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 743123120Simp bd->drq_res); 744123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 745123120Simp bd->base_res); 746123120Simp return ENXIO; 747123120Simp } 748123120Simp 749123120Simp b = malloc (sizeof (cx_board_t), M_DEVBUF, M_WAITOK); 750123120Simp if (!b) { 751123120Simp printf ("cx:%d: Couldn't allocate memory\n", unit); 752123120Simp return (ENXIO); 753123120Simp } 754123120Simp adapter[unit] = b; 755123120Simp bzero (b, sizeof(cx_board_t)); 756123120Simp 757123120Simp if (! cx_open_board (b, unit, iobase, irq, drq)) { 758123120Simp printf ("cx%d: error loading firmware\n", unit); 759123120Simp free (b, M_DEVBUF); 760123120Simp bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 761123120Simp bd->irq_res); 762123120Simp bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 763123120Simp bd->drq_res); 764123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 765123120Simp bd->base_res); 766123120Simp return ENXIO; 767123120Simp } 768123120Simp 769123120Simp bd->board = b; 770123120Simp 771123120Simp if (! probe_irq (b, irq)) { 772123120Simp printf ("cx%d: irq %ld not functional\n", unit, irq); 773123120Simp bd->board = 0; 774123120Simp adapter [unit] = 0; 775123120Simp free (b, M_DEVBUF); 776123120Simp bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 777123120Simp bd->irq_res); 778123120Simp bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 779123120Simp bd->drq_res); 780123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 781123120Simp bd->base_res); 782123120Simp return ENXIO; 783123120Simp } 784123120Simp 785123120Simp s = splhigh (); 786123120Simp if (bus_setup_intr (dev, bd->irq_res, INTR_TYPE_NET, cx_intr, bd, 787123120Simp &bd->intrhand)) { 788123120Simp printf ("cx%d: Can't setup irq %ld\n", unit, irq); 789123120Simp bd->board = 0; 790123120Simp adapter [unit] = 0; 791123120Simp free (b, M_DEVBUF); 792123120Simp bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 793123120Simp bd->irq_res); 794123120Simp bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 795123120Simp bd->drq_res); 796123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 797123120Simp bd->base_res); 798123120Simp splx (s); 799123120Simp return ENXIO; 800123120Simp } 801123120Simp 802123120Simp cx_init (b, b->num, b->port, irq, drq); 803123120Simp cx_setup_board (b, 0, 0, 0); 804123120Simp 805123120Simp printf ("cx%d: <Cronyx-Sigma-%s>\n", b->num, b->name); 806123120Simp 807123120Simp for (c=b->chan; c<b->chan+NCHAN; ++c) { 808123120Simp char *dnmt="tty %x"; 809123120Simp char *dnmc="cua %x"; 810123120Simp if (c->type == T_NONE) 811123120Simp continue; 812130985Srik d = &bd->channel[c->num]; 813130985Srik d->dmamem.size = sizeof(cx_buf_t); 814130985Srik if (! cx_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) 815130985Srik continue; 816123120Simp channel [b->num*NCHAN + c->num] = d; 817123120Simp sprintf (d->name, "cx%d.%d", b->num, c->num); 818123120Simp d->board = b; 819123120Simp d->chan = c; 820123120Simp d->dtrwait = 3 * hz; /* Default DTR off timeout is 3 seconds. */ 821123120Simp d->open_dev = 0; 822123120Simp c->sys = d; 823123120Simp 824123120Simp switch (c->type) { 825123120Simp case T_SYNC_RS232: 826123120Simp case T_SYNC_V35: 827123120Simp case T_SYNC_RS449: 828123120Simp case T_UNIV: 829123120Simp case T_UNIV_RS232: 830123120Simp case T_UNIV_RS449: 831123120Simp case T_UNIV_V35: 832123120Simp#ifdef NETGRAPH 833123120Simp if (ng_make_node_common (&typestruct, &d->node) != 0) { 834123120Simp printf ("%s: cannot make common node\n", d->name); 835123120Simp channel [b->num*NCHAN + c->num] = 0; 836123120Simp c->sys = 0; 837130985Srik cx_bus_dma_mem_free (&d->dmamem); 838123120Simp continue; 839123120Simp } 840123120Simp#if __FreeBSD_version >= 500000 841123120Simp NG_NODE_SET_PRIVATE (d->node, d); 842123120Simp#else 843123120Simp d->node->private = d; 844123120Simp#endif 845123120Simp sprintf (d->nodename, "%s%d", NG_CX_NODE_TYPE, 846123120Simp c->board->num*NCHAN + c->num); 847123120Simp if (ng_name_node (d->node, d->nodename)) { 848123120Simp printf ("%s: cannot name node\n", d->nodename); 849123120Simp#if __FreeBSD_version >= 500000 850123120Simp NG_NODE_UNREF (d->node); 851123120Simp#else 852123120Simp ng_rmnode (d->node); 853123120Simp ng_unref (d->node); 854123120Simp#endif 855123120Simp channel [b->num*NCHAN + c->num] = 0; 856123120Simp c->sys = 0; 857130985Srik cx_bus_dma_mem_free (&d->dmamem); 858123120Simp continue; 859123120Simp } 860123120Simp d->lo_queue.ifq_maxlen = IFQ_MAXLEN; 861123120Simp d->hi_queue.ifq_maxlen = IFQ_MAXLEN; 862123120Simp#if __FreeBSD_version >= 500000 863123120Simp mtx_init (&d->lo_queue.ifq_mtx, "cx_queue_lo", NULL, MTX_DEF); 864123120Simp mtx_init (&d->hi_queue.ifq_mtx, "cx_queue_hi", NULL, MTX_DEF); 865123120Simp#endif 866123120Simp#else /*NETGRAPH*/ 867123120Simp d->pp.pp_if.if_softc = d; 868123120Simp#if __FreeBSD_version > 501000 869123120Simp if_initname (&d->pp.pp_if, "cx", b->num * NCHAN + c->num); 870123120Simp#else 871123120Simp d->pp.pp_if.if_unit = b->num * NCHAN + c->num; 872123120Simp d->pp.pp_if.if_name = "cx"; 873123120Simp#endif 874123120Simp d->pp.pp_if.if_mtu = PP_MTU; 875123120Simp d->pp.pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 876123120Simp d->pp.pp_if.if_ioctl = cx_sioctl; 877123120Simp d->pp.pp_if.if_start = cx_ifstart; 878123120Simp d->pp.pp_if.if_watchdog = cx_ifwatchdog; 879123120Simp d->pp.pp_if.if_init = cx_initialize; 880123120Simp sppp_attach (&d->pp.pp_if); 881123120Simp if_attach (&d->pp.pp_if); 882123120Simp d->pp.pp_tlf = cx_tlf; 883123120Simp d->pp.pp_tls = cx_tls; 884123120Simp /* If BPF is in the kernel, call the attach for it. 885123120Simp * Size of PPP header is 4 bytes. */ 886123120Simp bpfattach (&d->pp.pp_if, DLT_PPP, 4); 887123120Simp#endif /*NETGRAPH*/ 888123120Simp } 889130985Srik cx_start_chan (c, d->dmamem.virt, d->dmamem.phys); 890123120Simp cx_register_receive (c, &cx_receive); 891123120Simp cx_register_transmit (c, &cx_transmit); 892123120Simp cx_register_error (c, &cx_error); 893123120Simp cx_register_modem (c, &cx_modem); 894123120Simp dnmt[3] = 'x'+b->num; 895123120Simp dnmc[3] = 'x'+b->num; 896123120Simp d->devt[0] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num, UID_ROOT, GID_WHEEL, 0644, dnmt, b->num*NCHAN + c->num); 897123120Simp d->devt[1] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 64, UID_ROOT, GID_WHEEL, 0600, "cx%d", b->num*NCHAN + c->num); 898123120Simp d->devt[2] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 128, UID_ROOT, GID_WHEEL, 0660, dnmc, b->num*NCHAN + c->num); 899123120Simp } 900123120Simp splx (s); 901123120Simp 902123120Simp return 0; 903123120Simp} 904123120Simp 905123120Simpstatic int cx_detach (device_t dev) 906123120Simp{ 907123120Simp bdrv_t *bd = device_get_softc (dev); 908123120Simp cx_board_t *b = bd->board; 909123120Simp cx_chan_t *c; 910123120Simp int s = splhigh (); 911123120Simp 912123120Simp /* Check if the device is busy (open). */ 913123120Simp for (c = b->chan; c < b->chan + NCHAN; ++c) { 914123120Simp drv_t *d = (drv_t*) c->sys; 915123120Simp 916123120Simp if (!d || d->chan->type == T_NONE) 917123120Simp continue; 918123120Simp if (d->lock) { 919123120Simp splx (s); 920123120Simp return EBUSY; 921123120Simp } 922130240Srik if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 923123120Simp (d->open_dev|0x2)) { 924123120Simp splx (s); 925123120Simp return EBUSY; 926123120Simp } 927123120Simp if (d->running) { 928123120Simp splx (s); 929123120Simp return EBUSY; 930123120Simp } 931123120Simp } 932123120Simp 933123120Simp /* Deactivate the timeout routine. And soft interrupt*/ 934123120Simp if (led_timo[b->num].callout) 935123120Simp untimeout (cx_led_off, b, led_timo[b->num]); 936123120Simp 937123120Simp for (c = b->chan; c < b->chan + NCHAN; ++c) { 938123120Simp drv_t *d = c->sys; 939123120Simp 940123120Simp if (!d || d->chan->type == T_NONE) 941123120Simp continue; 942123120Simp 943123120Simp if (d->dtr_timeout_handle.callout) 944123120Simp untimeout (cx_dtrwakeup, d, d->dtr_timeout_handle); 945123120Simp if (d->dcd_timeout_handle.callout) 946123120Simp untimeout (cx_carrier, c, d->dcd_timeout_handle); 947123120Simp } 948123120Simp bus_teardown_intr (dev, bd->irq_res, bd->intrhand); 949123120Simp bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); 950123120Simp bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); 951123120Simp 952123120Simp bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); 953123120Simp bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); 954123120Simp 955123120Simp bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res); 956123120Simp bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res); 957123120Simp 958123120Simp cx_close_board (b); 959123120Simp 960123120Simp /* Detach the interfaces, free buffer memory. */ 961123120Simp for (c = b->chan; c < b->chan + NCHAN; ++c) { 962123120Simp drv_t *d = (drv_t*) c->sys; 963123120Simp 964123120Simp if (!d || d->chan->type == T_NONE) 965123120Simp continue; 966130301Srik 967130301Srik#if __FreeBSD_version >= 502113 968130301Srik if (d->tty) { 969130301Srik ttyrel (d->tty); 970130301Srik d->tty = NULL; 971130301Srik } 972130301Srik#endif 973130301Srik 974123120Simp#ifdef NETGRAPH 975123120Simp#if __FreeBSD_version >= 500000 976123120Simp if (d->node) { 977123120Simp ng_rmnode_self (d->node); 978123120Simp NG_NODE_UNREF (d->node); 979123120Simp d->node = NULL; 980123120Simp } 981123120Simp mtx_destroy (&d->lo_queue.ifq_mtx); 982123120Simp mtx_destroy (&d->hi_queue.ifq_mtx); 983123120Simp#else 984123120Simp ng_rmnode (d->node); 985123120Simp d->node = NULL; 986123120Simp#endif 987123120Simp#else 988123120Simp#if __FreeBSD_version >= 410000 && NBPFILTER > 0 989123120Simp /* Detach from the packet filter list of interfaces. */ 990123120Simp bpfdetach (&d->pp.pp_if); 991123120Simp#endif 992123120Simp /* Detach from the sync PPP list. */ 993123120Simp sppp_detach (&d->pp.pp_if); 994123120Simp 995123120Simp if_detach (&d->pp.pp_if); 996123120Simp#endif 997123120Simp destroy_dev (d->devt[0]); 998123120Simp destroy_dev (d->devt[1]); 999123120Simp destroy_dev (d->devt[2]); 1000123120Simp } 1001123120Simp 1002123120Simp cx_led_off (b); 1003123120Simp if (led_timo[b->num].callout) 1004123120Simp untimeout (cx_led_off, b, led_timo[b->num]); 1005123120Simp splx (s); 1006123120Simp 1007123120Simp s = splhigh (); 1008123120Simp for (c = b->chan; c < b->chan + NCHAN; ++c) { 1009123120Simp drv_t *d = (drv_t*) c->sys; 1010123120Simp 1011123120Simp if (!d || d->chan->type == T_NONE) 1012123120Simp continue; 1013123120Simp 1014123120Simp /* Deallocate buffers. */ 1015130985Srik cx_bus_dma_mem_free (&d->dmamem); 1016123120Simp } 1017123120Simp bd->board = 0; 1018123120Simp adapter [b->num] = 0; 1019123120Simp free (b, M_DEVBUF); 1020123120Simp splx (s); 1021123120Simp 1022123120Simp return 0; 1023123120Simp} 1024123120Simp 1025123120Simp#ifndef NETGRAPH 1026123120Simpstatic void cx_ifstart (struct ifnet *ifp) 1027123120Simp{ 1028123120Simp drv_t *d = ifp->if_softc; 1029123120Simp 1030123120Simp cx_start (d); 1031123120Simp} 1032123120Simp 1033123120Simpstatic void cx_ifwatchdog (struct ifnet *ifp) 1034123120Simp{ 1035123120Simp drv_t *d = ifp->if_softc; 1036123120Simp 1037123120Simp cx_watchdog (d); 1038123120Simp} 1039123120Simp 1040123120Simpstatic void cx_tlf (struct sppp *sp) 1041123120Simp{ 1042123120Simp drv_t *d = sp->pp_if.if_softc; 1043123120Simp 1044123120Simp CX_DEBUG (d, ("cx_tlf\n")); 1045123120Simp/* cx_set_dtr (d->chan, 0);*/ 1046123120Simp/* cx_set_rts (d->chan, 0);*/ 1047123120Simp sp->pp_down (sp); 1048123120Simp} 1049123120Simp 1050123120Simpstatic void cx_tls (struct sppp *sp) 1051123120Simp{ 1052123120Simp drv_t *d = sp->pp_if.if_softc; 1053123120Simp 1054123120Simp CX_DEBUG (d, ("cx_tls\n")); 1055123120Simp sp->pp_up (sp); 1056123120Simp} 1057123120Simp 1058123120Simp/* 1059123120Simp * Initialization of interface. 1060123120Simp * It seems to be never called by upper level. 1061123120Simp */ 1062123120Simpstatic void cx_initialize (void *softc) 1063123120Simp{ 1064123120Simp drv_t *d = softc; 1065123120Simp 1066123120Simp CX_DEBUG (d, ("cx_initialize\n")); 1067123120Simp} 1068123120Simp 1069123120Simp/* 1070123120Simp * Process an ioctl request. 1071123120Simp */ 1072123120Simpstatic int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 1073123120Simp{ 1074123120Simp drv_t *d = ifp->if_softc; 1075123120Simp int error, s, was_up, should_be_up; 1076123120Simp 1077123120Simp /* No socket ioctls while the channel is in async mode. */ 1078123120Simp if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC) 1079123120Simp return EBUSY; 1080123120Simp 1081123120Simp /* Socket ioctls on slave subchannels are not allowed. */ 1082123120Simp was_up = (ifp->if_flags & IFF_RUNNING) != 0; 1083123120Simp error = sppp_ioctl (ifp, cmd, data); 1084123120Simp if (error) 1085123120Simp return error; 1086123120Simp 1087123120Simp if (! (ifp->if_flags & IFF_DEBUG)) 1088123120Simp d->chan->debug = 0; 1089123120Simp else if (! d->chan->debug) 1090123120Simp d->chan->debug = 1; 1091123120Simp 1092123120Simp switch (cmd) { 1093123120Simp default: CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; 1094123120Simp case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n")); return 0; 1095123120Simp case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n")); return 0; 1096123120Simp case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n")); break; 1097123120Simp case SIOCSIFADDR: CX_DEBUG2 (d, ("SIOCSIFADDR\n")); break; 1098123120Simp } 1099123120Simp 1100123120Simp /* We get here only in case of SIFFLAGS or SIFADDR. */ 1101123120Simp s = splhigh (); 1102123120Simp should_be_up = (ifp->if_flags & IFF_RUNNING) != 0; 1103123120Simp if (!was_up && should_be_up) { 1104123120Simp /* Interface goes up -- start it. */ 1105123120Simp cx_up (d); 1106123120Simp cx_start (d); 1107123120Simp } else if (was_up && !should_be_up) { 1108123120Simp /* Interface is going down -- stop it. */ 1109123120Simp /* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ 1110123120Simp cx_down (d); 1111123120Simp } 1112123120Simp splx (s); 1113123120Simp return 0; 1114123120Simp} 1115123120Simp#endif /*NETGRAPH*/ 1116123120Simp 1117123120Simp/* 1118123120Simp * Stop the interface. Called on splimp(). 1119123120Simp */ 1120123120Simpstatic void cx_down (drv_t *d) 1121123120Simp{ 1122123120Simp int s = splhigh (); 1123123120Simp CX_DEBUG (d, ("cx_down\n")); 1124123120Simp cx_set_dtr (d->chan, 0); 1125123120Simp cx_set_rts (d->chan, 0); 1126123120Simp d->running = 0; 1127123120Simp splx (s); 1128123120Simp} 1129123120Simp 1130123120Simp/* 1131123120Simp * Start the interface. Called on splimp(). 1132123120Simp */ 1133123120Simpstatic void cx_up (drv_t *d) 1134123120Simp{ 1135123120Simp int s = splhigh (); 1136123120Simp CX_DEBUG (d, ("cx_up\n")); 1137123120Simp cx_set_dtr (d->chan, 1); 1138123120Simp cx_set_rts (d->chan, 1); 1139123120Simp d->running = 1; 1140123120Simp splx (s); 1141123120Simp} 1142123120Simp 1143123120Simp/* 1144123120Simp * Start output on the (slave) interface. Get another datagram to send 1145123120Simp * off of the interface queue, and copy it to the interface 1146123120Simp * before starting the output. 1147123120Simp */ 1148123120Simpstatic void cx_send (drv_t *d) 1149123120Simp{ 1150123120Simp struct mbuf *m; 1151123120Simp u_short len; 1152123120Simp 1153123120Simp CX_DEBUG2 (d, ("cx_send\n")); 1154123120Simp 1155123120Simp /* No output if the interface is down. */ 1156123120Simp if (! d->running) 1157123120Simp return; 1158123120Simp 1159123120Simp /* No output if the modem is off. */ 1160123120Simp if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan)) 1161123120Simp return; 1162123120Simp 1163123120Simp if (cx_buf_free (d->chan)) { 1164123120Simp /* Get the packet to send. */ 1165123120Simp#ifdef NETGRAPH 1166123120Simp IF_DEQUEUE (&d->hi_queue, m); 1167123120Simp if (! m) 1168123120Simp IF_DEQUEUE (&d->lo_queue, m); 1169123120Simp#else 1170123120Simp m = sppp_dequeue (&d->pp.pp_if); 1171123120Simp#endif 1172123120Simp if (! m) 1173123120Simp return; 1174130971Srik#ifndef NETGRAPH 1175123120Simp if (d->pp.pp_if.if_bpf) 1176123120Simp#if __FreeBSD_version >= 500000 1177123120Simp BPF_MTAP (&d->pp.pp_if, m); 1178123120Simp#else 1179123120Simp bpf_mtap (&d->pp.pp_if, m); 1180123120Simp#endif 1181123120Simp#endif 1182123120Simp len = m->m_pkthdr.len; 1183123120Simp if (! m->m_next) 1184123120Simp cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t), 1185123120Simp len, 0); 1186123120Simp else { 1187123120Simp u_char buf [DMABUFSZ]; 1188123120Simp m_copydata (m, 0, len, buf); 1189123120Simp cx_send_packet (d->chan, buf, len, 0); 1190123120Simp } 1191123120Simp m_freem (m); 1192123120Simp 1193123120Simp /* Set up transmit timeout, 10 seconds. */ 1194123120Simp#ifdef NETGRAPH 1195123120Simp d->timeout = 10; 1196123120Simp#else 1197123120Simp d->pp.pp_if.if_timer = 10; 1198123120Simp#endif 1199123120Simp } 1200123120Simp#ifndef NETGRAPH 1201123120Simp d->pp.pp_if.if_flags |= IFF_OACTIVE; 1202123120Simp#endif 1203123120Simp} 1204123120Simp 1205123120Simp/* 1206123120Simp * Start output on the interface. 1207123120Simp * Always called on splimp(). 1208123120Simp */ 1209123120Simpstatic void cx_start (drv_t *d) 1210123120Simp{ 1211123120Simp int s = splhigh (); 1212123120Simp if (d->running) { 1213123120Simp if (! d->chan->dtr) 1214123120Simp cx_set_dtr (d->chan, 1); 1215123120Simp if (! d->chan->rts) 1216123120Simp cx_set_rts (d->chan, 1); 1217123120Simp cx_send (d); 1218123120Simp } 1219123120Simp splx (s); 1220123120Simp} 1221123120Simp 1222123120Simp/* 1223123120Simp * Handle transmit timeouts. 1224123120Simp * Recover after lost transmit interrupts. 1225123120Simp * Always called on splimp(). 1226123120Simp */ 1227123120Simpstatic void cx_watchdog (drv_t *d) 1228123120Simp{ 1229123120Simp int s = splhigh (); 1230123120Simp CX_DEBUG (d, ("device timeout\n")); 1231123120Simp if (d->running) { 1232123120Simp cx_setup_chan (d->chan); 1233123120Simp cx_start_chan (d->chan, 0, 0); 1234123120Simp cx_set_dtr (d->chan, 1); 1235123120Simp cx_set_rts (d->chan, 1); 1236123120Simp cx_start (d); 1237123120Simp } 1238123120Simp splx (s); 1239123120Simp} 1240123120Simp 1241123120Simp/* 1242123120Simp * Transmit callback function. 1243123120Simp */ 1244123120Simpstatic void cx_transmit (cx_chan_t *c, void *attachment, int len) 1245123120Simp{ 1246123120Simp drv_t *d = c->sys; 1247123120Simp 1248123120Simp if (!d) 1249123120Simp return; 1250123120Simp 1251130240Srik if (c->mode == M_ASYNC && d->tty) { 1252130240Srik d->tty->t_state &= ~(TS_BUSY | TS_FLUSH); 1253123120Simp d->atimeout = 0; 1254130240Srik if (d->tty->t_dev) { 1255123120Simp d->intr_action |= CX_WRITE; 1256123120Simp MY_SOFT_INTR = 1; 1257123120Simp#if __FreeBSD_version >= 500000 1258123120Simp swi_sched (cx_fast_ih, 0); 1259123120Simp#else 1260123120Simp setsofttty (); 1261123120Simp#endif 1262123120Simp } 1263123120Simp return; 1264123120Simp } 1265123120Simp#ifdef NETGRAPH 1266123120Simp d->timeout = 0; 1267123120Simp#else 1268123120Simp ++d->pp.pp_if.if_opackets; 1269123120Simp d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 1270123120Simp d->pp.pp_if.if_timer = 0; 1271123120Simp#endif 1272123120Simp cx_start (d); 1273123120Simp} 1274123120Simp 1275123120Simp/* 1276123120Simp * Process the received packet. 1277123120Simp */ 1278123120Simpstatic void cx_receive (cx_chan_t *c, char *data, int len) 1279123120Simp{ 1280123120Simp drv_t *d = c->sys; 1281123120Simp struct mbuf *m; 1282123120Simp char *cc = data; 1283123120Simp#if __FreeBSD_version >= 500000 && defined NETGRAPH 1284123120Simp int error; 1285123120Simp#endif 1286123120Simp 1287123120Simp if (!d) 1288123120Simp return; 1289123120Simp 1290130240Srik if (c->mode == M_ASYNC && d->tty) { 1291130240Srik if (d->tty->t_state & TS_ISOPEN) { 1292123120Simp async_q *q = &d->aqueue; 1293123120Simp int size = BF_SZ - 1 - AQ_GSZ (q); 1294123120Simp 1295123120Simp if (len <= 0 && !size) 1296123120Simp return; 1297123120Simp 1298123120Simp if (len > size) { 1299123120Simp c->ierrs++; 1300123120Simp cx_error (c, CX_OVERRUN); 1301123120Simp len = size - 1; 1302123120Simp } 1303123120Simp 1304123120Simp while (len--) { 1305123120Simp AQ_PUSH (q, *(unsigned char *)cc); 1306123120Simp cc++; 1307123120Simp } 1308123120Simp 1309123120Simp d->intr_action |= CX_READ; 1310123120Simp MY_SOFT_INTR = 1; 1311123120Simp#if __FreeBSD_version >= 500000 1312123120Simp swi_sched (cx_fast_ih, 0); 1313123120Simp#else 1314123120Simp setsofttty (); 1315123120Simp#endif 1316123120Simp } 1317123120Simp return; 1318123120Simp } 1319123120Simp if (! d->running) 1320123120Simp return; 1321123120Simp 1322123120Simp m = makembuf (data, len); 1323123120Simp if (! m) { 1324123120Simp CX_DEBUG (d, ("no memory for packet\n")); 1325123120Simp#ifndef NETGRAPH 1326123120Simp ++d->pp.pp_if.if_iqdrops; 1327123120Simp#endif 1328123120Simp return; 1329123120Simp } 1330123120Simp if (c->debug > 1) 1331123120Simp printmbuf (m); 1332123120Simp#ifdef NETGRAPH 1333123120Simp m->m_pkthdr.rcvif = 0; 1334123120Simp#if __FreeBSD_version >= 500000 1335123120Simp NG_SEND_DATA_ONLY (error, d->hook, m); 1336123120Simp#else 1337123120Simp ng_queue_data (d->hook, m, 0); 1338123120Simp#endif 1339123120Simp#else 1340123120Simp ++d->pp.pp_if.if_ipackets; 1341123120Simp m->m_pkthdr.rcvif = &d->pp.pp_if; 1342123120Simp /* Check if there's a BPF listener on this interface. 1343123120Simp * If so, hand off the raw packet to bpf. */ 1344123120Simp if (d->pp.pp_if.if_bpf) 1345123120Simp#if __FreeBSD_version >= 500000 1346123120Simp BPF_TAP (&d->pp.pp_if, data, len); 1347123120Simp#else 1348123120Simp bpf_tap (&d->pp.pp_if, data, len); 1349123120Simp#endif 1350123120Simp sppp_input (&d->pp.pp_if, m); 1351123120Simp#endif 1352123120Simp} 1353123120Simp 1354130240Srik#if __FreeBSD_version < 502113 1355123120Simp#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ 1356123120Simp && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ 1357123120Simp && (!(tp->t_iflag & PARMRK)\ 1358123120Simp || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ 1359123120Simp && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ 1360130240Srik && linesw[tp->t_line].l_rint == ttyinput) 1361130240Srik#else 1362130240Srik#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ 1363130240Srik && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ 1364130240Srik && (!(tp->t_iflag & PARMRK)\ 1365130240Srik || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ 1366130240Srik && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ 1367130203Sphk && linesw[tp->t_line]->l_rint == ttyinput) 1368130240Srik#endif 1369123120Simp 1370123120Simp/* 1371123120Simp * Error callback function. 1372123120Simp */ 1373123120Simpstatic void cx_error (cx_chan_t *c, int data) 1374123120Simp{ 1375123120Simp drv_t *d = c->sys; 1376123120Simp async_q *q; 1377123120Simp 1378123120Simp if (!d) 1379123120Simp return; 1380123120Simp 1381123120Simp q = &(d->aqueue); 1382123120Simp 1383123120Simp switch (data) { 1384123120Simp case CX_FRAME: 1385123120Simp CX_DEBUG (d, ("frame error\n")); 1386130240Srik if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1387123120Simp && (AQ_GSZ (q) < BF_SZ - 1) 1388130240Srik && (!CONDITION((&d->tty->t_termios), (d->tty)) 1389130240Srik || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { 1390123120Simp AQ_PUSH (q, TTY_FE); 1391123120Simp d->intr_action |= CX_READ; 1392123120Simp MY_SOFT_INTR = 1; 1393123120Simp#if __FreeBSD_version >= 500000 1394123120Simp swi_sched (cx_fast_ih, 0); 1395123120Simp#else 1396123120Simp setsofttty (); 1397123120Simp#endif 1398123120Simp } 1399123120Simp#ifndef NETGRAPH 1400123120Simp else 1401123120Simp ++d->pp.pp_if.if_ierrors; 1402123120Simp#endif 1403123120Simp break; 1404123120Simp case CX_CRC: 1405123120Simp CX_DEBUG (d, ("crc error\n")); 1406130240Srik if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1407123120Simp && (AQ_GSZ (q) < BF_SZ - 1) 1408130240Srik && (!CONDITION((&d->tty->t_termios), (d->tty)) 1409130240Srik || !(d->tty->t_iflag & INPCK) 1410130240Srik || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { 1411123120Simp AQ_PUSH (q, TTY_PE); 1412123120Simp d->intr_action |= CX_READ; 1413123120Simp MY_SOFT_INTR = 1; 1414123120Simp#if __FreeBSD_version >= 500000 1415123120Simp swi_sched (cx_fast_ih, 0); 1416123120Simp#else 1417123120Simp setsofttty (); 1418123120Simp#endif 1419123120Simp } 1420123120Simp#ifndef NETGRAPH 1421123120Simp else 1422123120Simp ++d->pp.pp_if.if_ierrors; 1423123120Simp#endif 1424123120Simp break; 1425123120Simp case CX_OVERRUN: 1426123120Simp CX_DEBUG (d, ("overrun error\n")); 1427123120Simp#ifdef TTY_OE 1428130240Srik if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1429123120Simp && (AQ_GSZ (q) < BF_SZ - 1) 1430130240Srik && (!CONDITION((&d->tty->t_termios), (d->tty)))) { 1431123120Simp AQ_PUSH (q, TTY_OE); 1432123120Simp d->intr_action |= CX_READ; 1433123120Simp MY_SOFT_INTR = 1; 1434123120Simp#if __FreeBSD_version >= 500000 1435123120Simp swi_sched (cx_fast_ih, 0); 1436123120Simp#else 1437123120Simp setsofttty (); 1438123120Simp#endif 1439123120Simp } 1440123120Simp#endif 1441123120Simp#ifndef NETGRAPH 1442123120Simp else { 1443123120Simp ++d->pp.pp_if.if_collisions; 1444123120Simp ++d->pp.pp_if.if_ierrors; 1445123120Simp } 1446123120Simp#endif 1447123120Simp break; 1448123120Simp case CX_OVERFLOW: 1449123120Simp CX_DEBUG (d, ("overflow error\n")); 1450123120Simp#ifndef NETGRAPH 1451123120Simp if (c->mode != M_ASYNC) 1452123120Simp ++d->pp.pp_if.if_ierrors; 1453123120Simp#endif 1454123120Simp break; 1455123120Simp case CX_UNDERRUN: 1456123120Simp CX_DEBUG (d, ("underrun error\n")); 1457123120Simp if (c->mode != M_ASYNC) { 1458123120Simp#ifdef NETGRAPH 1459123120Simp d->timeout = 0; 1460123120Simp#else 1461123120Simp ++d->pp.pp_if.if_oerrors; 1462123120Simp d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 1463123120Simp d->pp.pp_if.if_timer = 0; 1464123120Simp cx_start (d); 1465123120Simp#endif 1466123120Simp } 1467123120Simp break; 1468123120Simp case CX_BREAK: 1469123120Simp CX_DEBUG (d, ("break error\n")); 1470130240Srik if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1471123120Simp && (AQ_GSZ (q) < BF_SZ - 1) 1472130240Srik && (!CONDITION((&d->tty->t_termios), (d->tty)) 1473130240Srik || !(d->tty->t_iflag & (IGNBRK | BRKINT | PARMRK)))) { 1474123120Simp AQ_PUSH (q, TTY_BI); 1475123120Simp d->intr_action |= CX_READ; 1476123120Simp MY_SOFT_INTR = 1; 1477123120Simp#if __FreeBSD_version >= 500000 1478123120Simp swi_sched (cx_fast_ih, 0); 1479123120Simp#else 1480123120Simp setsofttty (); 1481123120Simp#endif 1482123120Simp } 1483123120Simp#ifndef NETGRAPH 1484123120Simp else 1485123120Simp ++d->pp.pp_if.if_ierrors; 1486123120Simp#endif 1487123120Simp break; 1488123120Simp default: 1489123120Simp CX_DEBUG (d, ("error #%d\n", data)); 1490123120Simp } 1491123120Simp} 1492123120Simp 1493123120Simp#if __FreeBSD_version < 500000 1494123120Simpstatic int cx_open (dev_t dev, int flag, int mode, struct proc *p) 1495123120Simp#else 1496130585Sphkstatic int cx_open (struct cdev *dev, int flag, int mode, struct thread *td) 1497123120Simp#endif 1498123120Simp{ 1499123120Simp int unit = UNIT (dev); 1500123120Simp drv_t *d; 1501123120Simp int error; 1502123120Simp 1503123120Simp if (unit >= NCX*NCHAN || ! (d = channel[unit])) 1504123120Simp return ENXIO; 1505123120Simp CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n", 1506123120Simp unit, flag, mode)); 1507123120Simp 1508123120Simp if (d->chan->mode != M_ASYNC || IF_CUNIT(dev)) { 1509123120Simp d->open_dev |= 0x1; 1510123120Simp return 0; 1511123120Simp } 1512130240Srik if (!d->tty) { 1513130240Srik d->tty = ttymalloc (d->tty); 1514130240Srik d->tty->t_oproc = cx_oproc; 1515130240Srik d->tty->t_param = cx_param; 1516130240Srik d->tty->t_stop = cx_stop; 1517130240Srik } 1518130240Srik dev->si_tty = d->tty; 1519130240Srik d->tty->t_dev = dev; 1520123120Simpagain: 1521123120Simp if (d->dtroff) { 1522123120Simp error = tsleep (&d->dtrwait, TTIPRI | PCATCH, "cxdtr", 0); 1523123120Simp if (error) 1524123120Simp return error; 1525123120Simp goto again; 1526123120Simp } 1527123120Simp 1528130240Srik if ((d->tty->t_state & TS_ISOPEN) && (d->tty->t_state & TS_XCLUDE) && 1529123120Simp#if __FreeBSD_version >= 500000 1530123120Simp suser (td)) 1531123120Simp#else 1532123120Simp p->p_ucred->cr_uid != 0) 1533123120Simp#endif 1534123120Simp return EBUSY; 1535123120Simp 1536130240Srik if (d->tty->t_state & TS_ISOPEN) { 1537123120Simp /* 1538123120Simp * Cannot open /dev/cua if /dev/tty already opened. 1539123120Simp */ 1540123120Simp if (CALLOUT (dev) && ! d->callout) 1541123120Simp return EBUSY; 1542123120Simp 1543123120Simp /* 1544123120Simp * Opening /dev/tty when /dev/cua is already opened. 1545123120Simp * Wait for close, then try again. 1546123120Simp */ 1547123120Simp if (! CALLOUT (dev) && d->callout) { 1548123120Simp if (flag & O_NONBLOCK) 1549123120Simp return EBUSY; 1550123120Simp error = tsleep (d, TTIPRI | PCATCH, "cxbi", 0); 1551123120Simp if (error) 1552123120Simp return error; 1553123120Simp goto again; 1554123120Simp } 1555123120Simp } else if (d->lock && ! CALLOUT (dev) && (flag & O_NONBLOCK)) 1556123120Simp /* 1557123120Simp * We try to open /dev/tty in non-blocking mode 1558123120Simp * while somebody is already waiting for carrier on it. 1559123120Simp */ 1560123120Simp return EBUSY; 1561123120Simp else { 1562130240Srik ttychars (d->tty); 1563130240Srik if (d->tty->t_ispeed == 0) { 1564130240Srik d->tty->t_iflag = 0; 1565130240Srik d->tty->t_oflag = 0; 1566130240Srik d->tty->t_lflag = 0; 1567130240Srik d->tty->t_cflag = CREAD | CS8 | HUPCL; 1568130240Srik d->tty->t_ispeed = d->chan->rxbaud; 1569130240Srik d->tty->t_ospeed = d->chan->txbaud; 1570123120Simp } 1571123120Simp if (CALLOUT (dev)) 1572130240Srik d->tty->t_cflag |= CLOCAL; 1573123120Simp else 1574130240Srik d->tty->t_cflag &= ~CLOCAL; 1575130240Srik cx_param (d->tty, &d->tty->t_termios); 1576130240Srik ttsetwater (d->tty); 1577123120Simp } 1578123120Simp 1579123120Simp splhigh (); 1580130240Srik if (! (d->tty->t_state & TS_ISOPEN)) { 1581123120Simp cx_start_chan (d->chan, 0, 0); 1582123120Simp cx_set_dtr (d->chan, 1); 1583123120Simp cx_set_rts (d->chan, 1); 1584123120Simp d->cd = cx_get_cd (d->chan); 1585123120Simp if (CALLOUT (dev) || cx_get_cd (d->chan)) 1586130240Srik ttyld_modem(d->tty, 1); 1587123120Simp } 1588123120Simp 1589130240Srik if (! (flag & O_NONBLOCK) && ! (d->tty->t_cflag & CLOCAL) && 1590130240Srik ! (d->tty->t_state & TS_CARR_ON)) { 1591123120Simp /* Lock the channel against cxconfig while we are 1592123120Simp * waiting for carrier. */ 1593123120Simp d->lock++; 1594130240Srik error = tsleep (&d->tty->t_rawq, TTIPRI | PCATCH, "cxdcd", 0); 1595123120Simp /* Unlock the channel. */ 1596123120Simp d->lock--; 1597123120Simp spl0 (); 1598123120Simp if (error) 1599123120Simp goto failed; 1600123120Simp goto again; 1601123120Simp } 1602123120Simp 1603130240Srik error = ttyld_open (d->tty, dev); 1604130240Srik ttyldoptim (d->tty); 1605123120Simp spl0 (); 1606123120Simp if (error) { 1607130240Srikfailed: if (! (d->tty->t_state & TS_ISOPEN)) { 1608123120Simp splhigh (); 1609123120Simp cx_set_dtr (d->chan, 0); 1610123120Simp cx_set_rts (d->chan, 0); 1611123120Simp if (d->dtrwait) { 1612123120Simp d->dtr_timeout_handle = 1613123120Simp timeout (cx_dtrwakeup, d, d->dtrwait); 1614123120Simp d->dtroff = 1; 1615123120Simp } 1616123120Simp spl0 (); 1617123120Simp } 1618123120Simp return error; 1619123120Simp } 1620123120Simp 1621130240Srik if (d->tty->t_state & TS_ISOPEN) 1622123120Simp d->callout = CALLOUT (dev) ? 1 : 0; 1623123120Simp 1624123120Simp d->open_dev |= 0x2; 1625123120Simp CX_DEBUG2 (d, ("cx_open done\n")); 1626123120Simp return 0; 1627123120Simp} 1628123120Simp 1629123120Simp#if __FreeBSD_version < 500000 1630123120Simpstatic int cx_close (dev_t dev, int flag, int mode, struct proc *p) 1631123120Simp#else 1632130585Sphkstatic int cx_close (struct cdev *dev, int flag, int mode, struct thread *td) 1633123120Simp#endif 1634123120Simp{ 1635123120Simp drv_t *d = channel [UNIT (dev)]; 1636123120Simp int s; 1637123120Simp 1638123120Simp CX_DEBUG2 (d, ("cx_close\n")); 1639123120Simp if ((!(d->open_dev&0x2)) || IF_CUNIT(dev)){ 1640123120Simp d->open_dev &= ~0x1; 1641123120Simp return 0; 1642123120Simp } 1643123120Simp s = splhigh (); 1644130240Srik ttyld_close(d->tty, flag); 1645130240Srik ttyldoptim (d->tty); 1646123120Simp 1647123120Simp /* Disable receiver. 1648123120Simp * Transmitter continues sending the queued data. */ 1649123120Simp cx_enable_receive (d->chan, 0); 1650123120Simp 1651123120Simp /* Clear DTR and RTS. */ 1652130240Srik if ((d->tty->t_cflag & HUPCL) || ! (d->tty->t_state & TS_ISOPEN)) { 1653123120Simp cx_set_dtr (d->chan, 0); 1654123120Simp cx_set_rts (d->chan, 0); 1655123120Simp if (d->dtrwait) { 1656123120Simp d->dtr_timeout_handle = 1657123120Simp timeout (cx_dtrwakeup, d, d->dtrwait); 1658123120Simp d->dtroff = 1; 1659123120Simp } 1660123120Simp } 1661130240Srik ttyclose (d->tty); 1662123120Simp splx (s); 1663123120Simp d->callout = 0; 1664123120Simp 1665130301Srik /* 1666130301Srik * Wake up bidirectional opens. 1667130301Srik * Since we may be opened twice we couldn't call ttyrel() here. 1668130301Srik * So just keep d->tty for future use. It would be freed by 1669130301Srik * ttyrel() at cx_detach(). 1670130301Srik */ 1671130301Srik 1672123120Simp wakeup (d); 1673123120Simp d->open_dev &= ~0x2; 1674123120Simp 1675123120Simp return 0; 1676123120Simp} 1677123120Simp 1678130585Sphkstatic int cx_read (struct cdev *dev, struct uio *uio, int flag) 1679123120Simp{ 1680123120Simp drv_t *d = channel [UNIT (dev)]; 1681123120Simp 1682123120Simp if (d) CX_DEBUG2 (d, ("cx_read\n")); 1683130240Srik if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev) || !d->tty) 1684123120Simp return EBADF; 1685123120Simp 1686130240Srik return ttyld_read (d->tty, uio, flag); 1687123120Simp} 1688123120Simp 1689130585Sphkstatic int cx_write (struct cdev *dev, struct uio *uio, int flag) 1690123120Simp{ 1691123120Simp drv_t *d = channel [UNIT (dev)]; 1692123120Simp 1693123120Simp if (d) CX_DEBUG2 (d, ("cx_write\n")); 1694130240Srik if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev) || !d->tty) 1695123120Simp return EBADF; 1696123120Simp 1697130240Srik return ttyld_write (d->tty, uio, flag); 1698123120Simp} 1699123120Simp 1700123120Simpstatic int cx_modem_status (drv_t *d) 1701123120Simp{ 1702123120Simp int status = 0, s = splhigh (); 1703123120Simp /* Already opened by someone or network interface is up? */ 1704130240Srik if ((d->chan->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 1705123120Simp (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running)) 1706123120Simp status = TIOCM_LE; /* always enabled while open */ 1707123120Simp 1708123120Simp if (cx_get_dsr (d->chan)) status |= TIOCM_DSR; 1709123120Simp if (cx_get_cd (d->chan)) status |= TIOCM_CD; 1710123120Simp if (cx_get_cts (d->chan)) status |= TIOCM_CTS; 1711123120Simp if (d->chan->dtr) status |= TIOCM_DTR; 1712123120Simp if (d->chan->rts) status |= TIOCM_RTS; 1713123120Simp splx (s); 1714123120Simp return status; 1715123120Simp} 1716123120Simp 1717123120Simp#if __FreeBSD_version < 500000 1718123120Simpstatic int cx_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1719123120Simp#else 1720130585Sphkstatic int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1721123120Simp#endif 1722123120Simp{ 1723123120Simp drv_t *d = channel [UNIT (dev)]; 1724123120Simp cx_chan_t *c; 1725123120Simp struct serial_statistics *st; 1726123120Simp int error, s; 1727123120Simp char mask[16]; 1728123120Simp 1729123120Simp if (!d || !(c = d->chan)) 1730123120Simp return EINVAL; 1731123120Simp 1732123120Simp switch (cmd) { 1733123120Simp case SERIAL_GETREGISTERED: 1734123120Simp CX_DEBUG2 (d, ("ioctl: getregistered\n")); 1735123120Simp bzero (mask, sizeof(mask)); 1736123120Simp for (s=0; s<NCX*NCHAN; ++s) 1737123120Simp if (channel [s]) 1738123120Simp mask [s/8] |= 1 << (s & 7); 1739123120Simp bcopy (mask, data, sizeof (mask)); 1740123120Simp return 0; 1741123120Simp 1742123120Simp case SERIAL_GETPORT: 1743123120Simp CX_DEBUG2 (d, ("ioctl: getport\n")); 1744123120Simp s = splhigh (); 1745123120Simp *(int *)data = cx_get_port (c); 1746123120Simp splx (s); 1747123120Simp if (*(int *)data<0) 1748123120Simp return (EINVAL); 1749123120Simp else 1750123120Simp return 0; 1751123120Simp 1752123120Simp case SERIAL_SETPORT: 1753123120Simp CX_DEBUG2 (d, ("ioctl: setproto\n")); 1754123120Simp /* Only for superuser! */ 1755130971Srik#if __FreeBSD_version < 500000 1756123120Simp error = suser (p); 1757123120Simp#else /* __FreeBSD_version >= 500000 */ 1758123120Simp error = suser (td); 1759123120Simp#endif /* __FreeBSD_version >= 500000 */ 1760123120Simp if (error) 1761123120Simp return error; 1762123120Simp 1763123120Simp s = splhigh (); 1764123120Simp cx_set_port (c, *(int *)data); 1765123120Simp splx (s); 1766123120Simp return 0; 1767123120Simp 1768123120Simp#ifndef NETGRAPH 1769123120Simp case SERIAL_GETPROTO: 1770123120Simp CX_DEBUG2 (d, ("ioctl: getproto\n")); 1771123120Simp s = splhigh (); 1772123120Simp strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" : 1773129029Srik (d->pp.pp_flags & PP_FR) ? "fr" : 1774123120Simp (d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp"); 1775123120Simp splx (s); 1776123120Simp return 0; 1777123120Simp 1778123120Simp case SERIAL_SETPROTO: 1779123120Simp CX_DEBUG2 (d, ("ioctl: setproto\n")); 1780123120Simp /* Only for superuser! */ 1781130971Srik#if __FreeBSD_version < 500000 1782123120Simp error = suser (p); 1783123120Simp#else /* __FreeBSD_version >= 500000 */ 1784123120Simp error = suser (td); 1785123120Simp#endif /* __FreeBSD_version >= 500000 */ 1786123120Simp if (error) 1787123120Simp return error; 1788123120Simp if (c->mode == M_ASYNC) 1789123120Simp return EBUSY; 1790123120Simp if (d->pp.pp_if.if_flags & IFF_RUNNING) 1791123120Simp return EBUSY; 1792123120Simp if (! strcmp ("cisco", (char*)data)) { 1793129029Srik d->pp.pp_flags &= ~(PP_FR); 1794123120Simp d->pp.pp_flags |= PP_KEEPALIVE; 1795123120Simp d->pp.pp_if.if_flags |= PP_CISCO; 1796129029Srik } else if (! strcmp ("fr", (char*)data)) { 1797129029Srik d->pp.pp_if.if_flags &= ~(PP_CISCO); 1798129029Srik d->pp.pp_flags |= PP_FR | PP_KEEPALIVE; 1799123120Simp } else if (! strcmp ("ppp", (char*)data)) { 1800129029Srik d->pp.pp_flags &= ~(PP_FR | PP_KEEPALIVE); 1801123120Simp d->pp.pp_if.if_flags &= ~(PP_CISCO); 1802123120Simp } else 1803123120Simp return EINVAL; 1804123120Simp return 0; 1805123120Simp 1806123120Simp case SERIAL_GETKEEPALIVE: 1807123120Simp CX_DEBUG2 (d, ("ioctl: getkeepalive\n")); 1808129029Srik if ((d->pp.pp_flags & PP_FR) || 1809123120Simp (d->pp.pp_if.if_flags & PP_CISCO) || 1810123120Simp (c->mode == M_ASYNC)) 1811123120Simp return EINVAL; 1812123120Simp s = splhigh (); 1813123120Simp *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0; 1814123120Simp splx (s); 1815123120Simp return 0; 1816123120Simp 1817123120Simp case SERIAL_SETKEEPALIVE: 1818123120Simp CX_DEBUG2 (d, ("ioctl: setkeepalive\n")); 1819123120Simp /* Only for superuser! */ 1820130971Srik#if __FreeBSD_version < 500000 1821123120Simp error = suser (p); 1822123120Simp#else /* __FreeBSD_version >= 500000 */ 1823123120Simp error = suser (td); 1824123120Simp#endif /* __FreeBSD_version >= 500000 */ 1825123120Simp if (error) 1826123120Simp return error; 1827129029Srik if ((d->pp.pp_flags & PP_FR) || 1828123120Simp (d->pp.pp_if.if_flags & PP_CISCO)) 1829123120Simp return EINVAL; 1830123120Simp s = splhigh (); 1831123120Simp if (*(int*)data) 1832123120Simp d->pp.pp_flags |= PP_KEEPALIVE; 1833123120Simp else 1834123120Simp d->pp.pp_flags &= ~PP_KEEPALIVE; 1835123120Simp splx (s); 1836123120Simp return 0; 1837123120Simp#endif /*NETGRAPH*/ 1838123120Simp 1839123120Simp case SERIAL_GETMODE: 1840123120Simp CX_DEBUG2 (d, ("ioctl: getmode\n")); 1841123120Simp s = splhigh (); 1842123120Simp *(int*)data = (c->mode == M_ASYNC) ? 1843123120Simp SERIAL_ASYNC : SERIAL_HDLC; 1844123120Simp splx (s); 1845123120Simp return 0; 1846123120Simp 1847123120Simp case SERIAL_SETMODE: 1848123120Simp CX_DEBUG2 (d, ("ioctl: setmode\n")); 1849123120Simp /* Only for superuser! */ 1850130971Srik#if __FreeBSD_version < 500000 1851123120Simp error = suser (p); 1852123120Simp#else /* __FreeBSD_version >= 500000 */ 1853123120Simp error = suser (td); 1854123120Simp#endif /* __FreeBSD_version >= 500000 */ 1855123120Simp if (error) 1856123120Simp return error; 1857123120Simp 1858123120Simp /* Somebody is waiting for carrier? */ 1859123120Simp if (d->lock) 1860123120Simp return EBUSY; 1861123120Simp /* /dev/ttyXX is already opened by someone? */ 1862130240Srik if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 1863123120Simp (d->open_dev|0x2)) 1864123120Simp return EBUSY; 1865123120Simp /* Network interface is up? 1866123120Simp * Cannot change to async mode. */ 1867123120Simp if (c->mode != M_ASYNC && d->running && 1868123120Simp (*(int*)data == SERIAL_ASYNC)) 1869123120Simp return EBUSY; 1870123120Simp 1871123120Simp s = splhigh (); 1872123120Simp if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) { 1873123120Simp cx_set_mode (c, M_ASYNC); 1874123120Simp cx_enable_receive (c, 0); 1875123120Simp cx_enable_transmit (c, 0); 1876123120Simp } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) { 1877123120Simp cx_set_mode (c, M_HDLC); 1878123120Simp cx_enable_receive (c, 1); 1879123120Simp cx_enable_transmit (c, 1); 1880123120Simp } 1881123120Simp splx (s); 1882123120Simp return 0; 1883123120Simp 1884123120Simp case SERIAL_GETSTAT: 1885123120Simp CX_DEBUG2 (d, ("ioctl: getestat\n")); 1886123120Simp st = (struct serial_statistics*) data; 1887123120Simp s = splhigh (); 1888123120Simp st->rintr = c->rintr; 1889123120Simp st->tintr = c->tintr; 1890123120Simp st->mintr = c->mintr; 1891123120Simp st->ibytes = c->ibytes; 1892123120Simp st->ipkts = c->ipkts; 1893123120Simp st->ierrs = c->ierrs; 1894123120Simp st->obytes = c->obytes; 1895123120Simp st->opkts = c->opkts; 1896123120Simp st->oerrs = c->oerrs; 1897123120Simp splx (s); 1898123120Simp return 0; 1899123120Simp 1900123120Simp case SERIAL_CLRSTAT: 1901123120Simp CX_DEBUG2 (d, ("ioctl: clrstat\n")); 1902123120Simp /* Only for superuser! */ 1903130971Srik#if __FreeBSD_version < 500000 1904123120Simp error = suser (p); 1905123120Simp#else /* __FreeBSD_version >= 500000 */ 1906123120Simp error = suser (td); 1907123120Simp#endif /* __FreeBSD_version >= 500000 */ 1908123120Simp if (error) 1909123120Simp return error; 1910123120Simp s = splhigh (); 1911123120Simp c->rintr = 0; 1912123120Simp c->tintr = 0; 1913123120Simp c->mintr = 0; 1914123120Simp c->ibytes = 0; 1915123120Simp c->ipkts = 0; 1916123120Simp c->ierrs = 0; 1917123120Simp c->obytes = 0; 1918123120Simp c->opkts = 0; 1919123120Simp c->oerrs = 0; 1920123120Simp splx (s); 1921123120Simp return 0; 1922123120Simp 1923123120Simp case SERIAL_GETBAUD: 1924123120Simp CX_DEBUG2 (d, ("ioctl: getbaud\n")); 1925123120Simp if (c->mode == M_ASYNC) 1926123120Simp return EINVAL; 1927123120Simp s = splhigh (); 1928123120Simp *(long*)data = cx_get_baud(c); 1929123120Simp splx (s); 1930123120Simp return 0; 1931123120Simp 1932123120Simp case SERIAL_SETBAUD: 1933123120Simp CX_DEBUG2 (d, ("ioctl: setbaud\n")); 1934123120Simp /* Only for superuser! */ 1935130971Srik#if __FreeBSD_version < 500000 1936123120Simp error = suser (p); 1937123120Simp#else /* __FreeBSD_version >= 500000 */ 1938123120Simp error = suser (td); 1939123120Simp#endif /* __FreeBSD_version >= 500000 */ 1940123120Simp if (error) 1941123120Simp return error; 1942123120Simp if (c->mode == M_ASYNC) 1943123120Simp return EINVAL; 1944123120Simp s = splhigh (); 1945123120Simp cx_set_baud (c, *(long*)data); 1946123120Simp splx (s); 1947123120Simp return 0; 1948123120Simp 1949123120Simp case SERIAL_GETLOOP: 1950123120Simp CX_DEBUG2 (d, ("ioctl: getloop\n")); 1951123120Simp if (c->mode == M_ASYNC) 1952123120Simp return EINVAL; 1953123120Simp s = splhigh (); 1954123120Simp *(int*)data = cx_get_loop (c); 1955123120Simp splx (s); 1956123120Simp return 0; 1957123120Simp 1958123120Simp case SERIAL_SETLOOP: 1959123120Simp CX_DEBUG2 (d, ("ioctl: setloop\n")); 1960123120Simp /* Only for superuser! */ 1961130971Srik#if __FreeBSD_version < 500000 1962123120Simp error = suser (p); 1963123120Simp#else /* __FreeBSD_version >= 500000 */ 1964123120Simp error = suser (td); 1965123120Simp#endif /* __FreeBSD_version >= 500000 */ 1966123120Simp if (error) 1967123120Simp return error; 1968123120Simp if (c->mode == M_ASYNC) 1969123120Simp return EINVAL; 1970123120Simp s = splhigh (); 1971123120Simp cx_set_loop (c, *(int*)data); 1972123120Simp splx (s); 1973123120Simp return 0; 1974123120Simp 1975123120Simp case SERIAL_GETDPLL: 1976123120Simp CX_DEBUG2 (d, ("ioctl: getdpll\n")); 1977123120Simp if (c->mode == M_ASYNC) 1978123120Simp return EINVAL; 1979123120Simp s = splhigh (); 1980123120Simp *(int*)data = cx_get_dpll (c); 1981123120Simp splx (s); 1982123120Simp return 0; 1983123120Simp 1984123120Simp case SERIAL_SETDPLL: 1985123120Simp CX_DEBUG2 (d, ("ioctl: setdpll\n")); 1986123120Simp /* Only for superuser! */ 1987130971Srik#if __FreeBSD_version < 500000 1988123120Simp error = suser (p); 1989123120Simp#else /* __FreeBSD_version >= 500000 */ 1990123120Simp error = suser (td); 1991123120Simp#endif /* __FreeBSD_version >= 500000 */ 1992123120Simp if (error) 1993123120Simp return error; 1994123120Simp if (c->mode == M_ASYNC) 1995123120Simp return EINVAL; 1996123120Simp s = splhigh (); 1997123120Simp cx_set_dpll (c, *(int*)data); 1998123120Simp splx (s); 1999123120Simp return 0; 2000123120Simp 2001123120Simp case SERIAL_GETNRZI: 2002123120Simp CX_DEBUG2 (d, ("ioctl: getnrzi\n")); 2003123120Simp if (c->mode == M_ASYNC) 2004123120Simp return EINVAL; 2005123120Simp s = splhigh (); 2006123120Simp *(int*)data = cx_get_nrzi (c); 2007123120Simp splx (s); 2008123120Simp return 0; 2009123120Simp 2010123120Simp case SERIAL_SETNRZI: 2011123120Simp CX_DEBUG2 (d, ("ioctl: setnrzi\n")); 2012123120Simp /* Only for superuser! */ 2013130971Srik#if __FreeBSD_version < 500000 2014123120Simp error = suser (p); 2015123120Simp#else /* __FreeBSD_version >= 500000 */ 2016123120Simp error = suser (td); 2017123120Simp#endif /* __FreeBSD_version >= 500000 */ 2018123120Simp if (error) 2019123120Simp return error; 2020123120Simp if (c->mode == M_ASYNC) 2021123120Simp return EINVAL; 2022123120Simp s = splhigh (); 2023123120Simp cx_set_nrzi (c, *(int*)data); 2024123120Simp splx (s); 2025123120Simp return 0; 2026123120Simp 2027123120Simp case SERIAL_GETDEBUG: 2028123120Simp CX_DEBUG2 (d, ("ioctl: getdebug\n")); 2029123120Simp s = splhigh (); 2030123120Simp *(int*)data = c->debug; 2031123120Simp splx (s); 2032123120Simp return 0; 2033123120Simp 2034123120Simp case SERIAL_SETDEBUG: 2035123120Simp CX_DEBUG2 (d, ("ioctl: setdebug\n")); 2036123120Simp /* Only for superuser! */ 2037130971Srik#if __FreeBSD_version < 500000 2038123120Simp error = suser (p); 2039123120Simp#else /* __FreeBSD_version >= 500000 */ 2040123120Simp error = suser (td); 2041123120Simp#endif /* __FreeBSD_version >= 500000 */ 2042123120Simp if (error) 2043123120Simp return error; 2044123120Simp s = splhigh (); 2045123120Simp c->debug = *(int*)data; 2046123120Simp splx (s); 2047123120Simp#ifndef NETGRAPH 2048123120Simp if (d->chan->debug) 2049123120Simp d->pp.pp_if.if_flags |= IFF_DEBUG; 2050123120Simp else 2051123120Simp d->pp.pp_if.if_flags &= (~IFF_DEBUG); 2052123120Simp#endif 2053123120Simp return 0; 2054123120Simp } 2055123120Simp 2056130277Srik if (c->mode == M_ASYNC && !IF_CUNIT(dev) && d->tty) { 2057130057Sphk#if __FreeBSD_version >= 502113 2058130057Sphk error = ttyioctl (dev, cmd, data, flag, td); 2059130240Srik ttyldoptim (d->tty); 2060130057Sphk if (error != ENOTTY) { 2061130057Sphk if (error) 2062130057Sphk CX_DEBUG2 (d, ("ttioctl: 0x%lx, error %d\n", cmd, error)); 2063130057Sphk return error; 2064130057Sphk } 2065130057Sphk#else 2066123120Simp#if __FreeBSD_version >= 500000 2067130240Srik error = (*linesw[d->tty->t_line].l_ioctl) (d->tty, cmd, data, flag, td); 2068123120Simp#else 2069130240Srik error = (*linesw[d->tty->t_line].l_ioctl) (d->tty, cmd, data, flag, p); 2070123120Simp#endif 2071130240Srik ttyldoptim (d->tty); 2072123120Simp if (error != ENOIOCTL) { 2073123120Simp if (error) 2074123120Simp CX_DEBUG2 (d, ("l_ioctl: 0x%lx, error %d\n", cmd, error)); 2075123120Simp return error; 2076123120Simp } 2077130240Srik error = ttioctl (d->tty, cmd, data, flag); 2078130240Srik ttyldoptim (d->tty); 2079123120Simp if (error != ENOIOCTL) { 2080123120Simp if (error) 2081123120Simp CX_DEBUG2 (d, ("ttioctl: 0x%lx, error %d\n", cmd, error)); 2082123120Simp return error; 2083123120Simp } 2084130057Sphk#endif 2085123120Simp } 2086123120Simp 2087123120Simp switch (cmd) { 2088123120Simp case TIOCSBRK: /* Start sending line break */ 2089123120Simp CX_DEBUG2 (d, ("ioctl: tiocsbrk\n")); 2090123120Simp s = splhigh (); 2091123120Simp cx_send_break (c, 500); 2092123120Simp splx (s); 2093123120Simp return 0; 2094123120Simp 2095123120Simp case TIOCCBRK: /* Stop sending line break */ 2096123120Simp CX_DEBUG2 (d, ("ioctl: tioccbrk\n")); 2097123120Simp return 0; 2098123120Simp 2099123120Simp case TIOCSDTR: /* Set DTR */ 2100123120Simp CX_DEBUG2 (d, ("ioctl: tiocsdtr\n")); 2101123120Simp s = splhigh (); 2102123120Simp cx_set_dtr (c, 1); 2103123120Simp splx (s); 2104123120Simp return 0; 2105123120Simp 2106123120Simp case TIOCCDTR: /* Clear DTR */ 2107123120Simp CX_DEBUG2 (d, ("ioctl: tioccdtr\n")); 2108123120Simp s = splhigh (); 2109123120Simp cx_set_dtr (c, 0); 2110123120Simp splx (s); 2111123120Simp return 0; 2112123120Simp 2113123120Simp case TIOCMSET: /* Set DTR/RTS */ 2114123120Simp CX_DEBUG2 (d, ("ioctl: tiocmset\n")); 2115123120Simp s = splhigh (); 2116123120Simp cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); 2117123120Simp cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); 2118123120Simp splx (s); 2119123120Simp return 0; 2120123120Simp 2121123120Simp case TIOCMBIS: /* Add DTR/RTS */ 2122123120Simp CX_DEBUG2 (d, ("ioctl: tiocmbis\n")); 2123123120Simp s = splhigh (); 2124123120Simp if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1); 2125123120Simp if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1); 2126123120Simp splx (s); 2127123120Simp return 0; 2128123120Simp 2129123120Simp case TIOCMBIC: /* Clear DTR/RTS */ 2130123120Simp CX_DEBUG2 (d, ("ioctl: tiocmbic\n")); 2131123120Simp s = splhigh (); 2132123120Simp if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0); 2133123120Simp if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0); 2134123120Simp splx (s); 2135123120Simp return 0; 2136123120Simp 2137123120Simp case TIOCMGET: /* Get modem status */ 2138123120Simp CX_DEBUG2 (d, ("ioctl: tiocmget\n")); 2139123120Simp *(int*)data = cx_modem_status (d); 2140123120Simp return 0; 2141123120Simp 2142123120Simp#ifdef TIOCMSDTRWAIT 2143123120Simp case TIOCMSDTRWAIT: 2144123120Simp CX_DEBUG2 (d, ("ioctl: tiocmsdtrwait\n")); 2145123120Simp /* Only for superuser! */ 2146130971Srik#if __FreeBSD_version < 500000 2147123120Simp error = suser (p); 2148123120Simp#else /* __FreeBSD_version >= 500000 */ 2149123120Simp error = suser (td); 2150123120Simp#endif /* __FreeBSD_version >= 500000 */ 2151123120Simp if (error) 2152123120Simp return error; 2153123120Simp s = splhigh (); 2154123120Simp d->dtrwait = *(int*)data * hz / 100; 2155123120Simp splx (s); 2156123120Simp return 0; 2157123120Simp#endif 2158123120Simp 2159123120Simp#ifdef TIOCMGDTRWAIT 2160123120Simp case TIOCMGDTRWAIT: 2161123120Simp CX_DEBUG2 (d, ("ioctl: tiocmgdtrwait\n")); 2162123120Simp s = splhigh (); 2163123120Simp *(int*)data = d->dtrwait * 100 / hz; 2164123120Simp splx (s); 2165123120Simp return 0; 2166123120Simp#endif 2167123120Simp } 2168123120Simp CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd)); 2169123120Simp return ENOTTY; 2170123120Simp} 2171123120Simp 2172123120Simp/* 2173123120Simp * Wake up opens() waiting for DTR ready. 2174123120Simp */ 2175123120Simpstatic void cx_dtrwakeup (void *arg) 2176123120Simp{ 2177123120Simp drv_t *d = arg; 2178123120Simp 2179123120Simp d->dtroff = 0; 2180123120Simp wakeup (&d->dtrwait); 2181123120Simp} 2182123120Simp 2183123120Simp 2184130096Sphk#if __FreeBSD_version < 502113 2185123120Simpstatic void 2186130096Sphkttyldoptim(tp) 2187123120Simp struct tty *tp; 2188130096Sphk{ 2189123120Simp struct termios *t; 2190130096Sphk 2191130096Sphk t = &tp->t_termios; 2192123120Simp if (CONDITION(t,tp)) 2193123120Simp tp->t_state |= TS_CAN_BYPASS_L_RINT; 2194123120Simp else 2195123120Simp tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2196123120Simp} 2197130096Sphk#endif 2198123120Simp 2199123120Simp#if __FreeBSD_version >= 500000 2200123120Simpvoid cx_softintr (void *unused) 2201123120Simp#else 2202123120Simpvoid cx_softintr () 2203123120Simp#endif 2204123120Simp{ 2205123120Simp drv_t *d; 2206123120Simp async_q *q; 2207123120Simp int i, s, ic, k; 2208123120Simp while (MY_SOFT_INTR) { 2209123120Simp MY_SOFT_INTR = 0; 2210123120Simp for (i=0; i<NCX*NCHAN; ++i) { 2211123120Simp d = channel [i]; 2212123120Simp if (!d || !d->chan || d->chan->type == T_NONE 2213130240Srik || d->chan->mode != M_ASYNC || !d->tty 2214130240Srik || !d->tty->t_dev) 2215123120Simp continue; 2216123120Simp s = splhigh (); 2217123120Simp if (d->intr_action & CX_READ) { 2218123120Simp q = &(d->aqueue); 2219130240Srik if (d->tty->t_state & TS_CAN_BYPASS_L_RINT) { 2220123120Simp k = AQ_GSZ(q); 2221130240Srik if (d->tty->t_rawq.c_cc + k > 2222130240Srik d->tty->t_ihiwat 2223130240Srik && (d->tty->t_cflag & CRTS_IFLOW 2224130240Srik || d->tty->t_iflag & IXOFF) 2225130240Srik && !(d->tty->t_state & TS_TBLOCK)) 2226130240Srik ttyblock(d->tty); 2227130240Srik d->tty->t_rawcc += k; 2228123120Simp while (k>0) { 2229123120Simp k--; 2230123120Simp AQ_POP (q, ic); 2231123120Simp splx (s); 2232130240Srik putc (ic, &d->tty->t_rawq); 2233123120Simp s = splhigh (); 2234123120Simp } 2235130240Srik ttwakeup(d->tty); 2236130240Srik if (d->tty->t_state & TS_TTSTOP 2237130240Srik && (d->tty->t_iflag & IXANY 2238130240Srik || d->tty->t_cc[VSTART] == 2239130240Srik d->tty->t_cc[VSTOP])) { 2240130240Srik d->tty->t_state &= ~TS_TTSTOP; 2241130240Srik d->tty->t_lflag &= ~FLUSHO; 2242123120Simp d->intr_action |= CX_WRITE; 2243123120Simp } 2244123120Simp } else { 2245123120Simp while (q->end != q->beg) { 2246123120Simp AQ_POP (q, ic); 2247123120Simp splx (s); 2248130240Srik ttyld_rint (d->tty, ic); 2249123120Simp s = splhigh (); 2250123120Simp } 2251123120Simp } 2252123120Simp d->intr_action &= ~CX_READ; 2253123120Simp } 2254123120Simp splx (s); 2255123120Simp 2256123120Simp s = splhigh (); 2257123120Simp if (d->intr_action & CX_WRITE) { 2258130240Srik if (d->tty->t_line) 2259130240Srik ttyld_start (d->tty); 2260123120Simp else 2261130240Srik cx_oproc (d->tty); 2262123120Simp d->intr_action &= ~CX_WRITE; 2263123120Simp } 2264123120Simp splx (s); 2265123120Simp 2266123120Simp } 2267123120Simp } 2268123120Simp} 2269123120Simp 2270123120Simp/* 2271123120Simp * Fill transmitter buffer with data. 2272123120Simp */ 2273123120Simpstatic void cx_oproc (struct tty *tp) 2274123120Simp{ 2275123120Simp int s = splhigh (), k; 2276123120Simp drv_t *d = channel [UNIT (tp->t_dev)]; 2277123120Simp static u_char buf[DMABUFSZ]; 2278123120Simp u_char *p; 2279123120Simp u_short len = 0, sublen = 0; 2280123120Simp 2281123120Simp if (!d) { 2282123120Simp splx (s); 2283123120Simp return; 2284123120Simp } 2285123120Simp 2286123120Simp CX_DEBUG2 (d, ("cx_oproc\n")); 2287123120Simp if (tp->t_cflag & CRTSCTS && (tp->t_state & TS_TBLOCK) && d->chan->rts) 2288123120Simp cx_set_rts (d->chan, 0); 2289123120Simp else if (tp->t_cflag & CRTSCTS && ! (tp->t_state & TS_TBLOCK) && ! d->chan->rts) 2290123120Simp cx_set_rts (d->chan, 1); 2291123120Simp 2292123120Simp if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) { 2293123120Simp /* Start transmitter. */ 2294123120Simp cx_enable_transmit (d->chan, 1); 2295123120Simp 2296123120Simp /* Is it busy? */ 2297123120Simp if (! cx_buf_free (d->chan)) { 2298123120Simp tp->t_state |= TS_BUSY; 2299123120Simp splx (s); 2300123120Simp return; 2301123120Simp } 2302123120Simp if (tp->t_iflag & IXOFF) { 2303123120Simp p = (buf + (DMABUFSZ/2)); 2304123120Simp sublen = q_to_b (&tp->t_outq, p, (DMABUFSZ/2)); 2305123120Simp k = sublen; 2306123120Simp while (k--) { 2307123120Simp /* Send XON/XOFF out of band. */ 2308123120Simp if (*p == tp->t_cc[VSTOP]) { 2309123120Simp cx_xflow_ctl (d->chan, 0); 2310123120Simp p++; 2311123120Simp continue; 2312123120Simp } 2313123120Simp if (*p == tp->t_cc[VSTART]) { 2314123120Simp cx_xflow_ctl (d->chan, 1); 2315123120Simp p++; 2316123120Simp continue; 2317123120Simp } 2318123120Simp buf[len] = *p; 2319123120Simp len++; 2320123120Simp p++; 2321123120Simp } 2322123120Simp } else { 2323123120Simp p = buf; 2324123120Simp len = q_to_b (&tp->t_outq, p, (DMABUFSZ/2)); 2325123120Simp } 2326123120Simp if (len) { 2327123120Simp cx_send_packet (d->chan, buf, len, 0); 2328123120Simp tp->t_state |= TS_BUSY; 2329123120Simp d->atimeout = 10; 2330123120Simp CX_DEBUG2 (d, ("out %d bytes\n", len)); 2331123120Simp } 2332123120Simp } 2333123120Simp ttwwakeup (tp); 2334123120Simp splx (s); 2335123120Simp} 2336123120Simp 2337123120Simpstatic int cx_param (struct tty *tp, struct termios *t) 2338123120Simp{ 2339123120Simp drv_t *d = channel [UNIT (tp->t_dev)]; 2340123120Simp int s, bits, parity; 2341123120Simp 2342123120Simp if (!d) 2343123120Simp return EINVAL; 2344123120Simp 2345123120Simp s = splhigh (); 2346123120Simp if (t->c_ospeed == 0) { 2347123120Simp /* Clear DTR and RTS. */ 2348123120Simp cx_set_dtr (d->chan, 0); 2349123120Simp splx (s); 2350123120Simp CX_DEBUG2 (d, ("cx_param (hangup)\n")); 2351123120Simp return 0; 2352123120Simp } 2353123120Simp CX_DEBUG2 (d, ("cx_param\n")); 2354123120Simp 2355123120Simp /* Check requested parameters. */ 2356123120Simp if (t->c_ospeed < 300 || t->c_ospeed > 256*1024) { 2357123120Simp splx (s); 2358123120Simp return EINVAL; 2359123120Simp } 2360123120Simp if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024)) { 2361123120Simp splx (s); 2362123120Simp return EINVAL; 2363123120Simp } 2364123120Simp 2365123120Simp /* And copy them to tty and channel structures. */ 2366123120Simp tp->t_ispeed = t->c_ispeed = tp->t_ospeed = t->c_ospeed; 2367123120Simp tp->t_cflag = t->c_cflag; 2368123120Simp 2369123120Simp /* Set character length and parity mode. */ 2370123120Simp switch (t->c_cflag & CSIZE) { 2371123120Simp default: 2372123120Simp case CS8: bits = 8; break; 2373123120Simp case CS7: bits = 7; break; 2374123120Simp case CS6: bits = 6; break; 2375123120Simp case CS5: bits = 5; break; 2376123120Simp } 2377123120Simp 2378123120Simp parity = ((t->c_cflag & PARENB) ? 1 : 0) * 2379123120Simp (1 + ((t->c_cflag & PARODD) ? 0 : 1)); 2380123120Simp 2381123120Simp /* Set current channel number. */ 2382123120Simp if (! d->chan->dtr) 2383123120Simp cx_set_dtr (d->chan, 1); 2384123120Simp 2385130240Srik ttyldoptim (tp); 2386123120Simp cx_set_async_param (d->chan, t->c_ospeed, bits, parity, (t->c_cflag & CSTOPB), 2387123120Simp !(t->c_cflag & PARENB), (t->c_cflag & CRTSCTS), 2388123120Simp (t->c_iflag & IXON), (t->c_iflag & IXANY), 2389123120Simp t->c_cc[VSTART], t->c_cc[VSTOP]); 2390123120Simp splx (s); 2391123120Simp return 0; 2392123120Simp} 2393123120Simp 2394123120Simp/* 2395123120Simp * Stop output on a line 2396123120Simp */ 2397123120Simpstatic void cx_stop (struct tty *tp, int flag) 2398123120Simp{ 2399123120Simp drv_t *d = channel [UNIT (tp->t_dev)]; 2400123120Simp int s; 2401123120Simp 2402123120Simp if (!d) 2403123120Simp return; 2404123120Simp 2405123120Simp s = splhigh (); 2406123120Simp 2407123120Simp if (tp->t_state & TS_BUSY) { 2408123120Simp /* Stop transmitter */ 2409123120Simp CX_DEBUG2 (d, ("cx_stop\n")); 2410123120Simp cx_transmitter_ctl (d->chan, 0); 2411123120Simp } 2412123120Simp splx (s); 2413123120Simp} 2414123120Simp 2415123120Simp/* 2416123120Simp * Process the (delayed) carrier signal setup. 2417123120Simp */ 2418123120Simpstatic void cx_carrier (void *arg) 2419123120Simp{ 2420123120Simp drv_t *d = arg; 2421123120Simp cx_chan_t *c = d->chan; 2422123120Simp int s, cd; 2423123120Simp 2424123120Simp s = splhigh (); 2425123120Simp cd = cx_get_cd (c); 2426123120Simp if (d->cd != cd) { 2427123120Simp if (cd) { 2428123120Simp CX_DEBUG (d, ("carrier on\n")); 2429123120Simp d->cd = 1; 2430123120Simp splx (s); 2431130240Srik if (d->tty) 2432130240Srik ttyld_modem(d->tty, 1); 2433123120Simp } else { 2434123120Simp CX_DEBUG (d, ("carrier loss\n")); 2435123120Simp d->cd = 0; 2436123120Simp splx (s); 2437130240Srik if (d->tty) 2438130240Srik ttyld_modem(d->tty, 0); 2439123120Simp } 2440123120Simp } 2441123120Simp} 2442123120Simp 2443123120Simp/* 2444123120Simp * Modem signal callback function. 2445123120Simp */ 2446123120Simpstatic void cx_modem (cx_chan_t *c) 2447123120Simp{ 2448123120Simp drv_t *d = c->sys; 2449123120Simp 2450123120Simp if (!d || c->mode != M_ASYNC) 2451123120Simp return; 2452123120Simp /* Handle carrier detect/loss. */ 2453123120Simp untimeout (cx_carrier, c, d->dcd_timeout_handle); 2454123120Simp /* Carrier changed - delay processing DCD for a while 2455123120Simp * to give both sides some time to initialize. */ 2456123120Simp d->dcd_timeout_handle = timeout (cx_carrier, d, hz/2); 2457123120Simp} 2458123120Simp 2459130971Srik#if __FreeBSD_version < 500000 2460123120Simpstatic struct cdevsw cx_cdevsw = { 2461123120Simp cx_open, cx_close, cx_read, cx_write, 2462123120Simp cx_ioctl, ttypoll, nommap, nostrategy, 2463123120Simp "cx", CDEV_MAJOR, nodump, nopsize, 2464123120Simp D_TTY, -1 2465123120Simp}; 2466123120Simp#elif __FreeBSD_version == 500000 2467123120Simpstatic struct cdevsw cx_cdevsw = { 2468123120Simp cx_open, cx_close, cx_read, cx_write, 2469123120Simp cx_ioctl, ttypoll, nommap, nostrategy, 2470123120Simp "cx", CDEV_MAJOR, nodump, nopsize, 2471123120Simp D_TTY, 2472123120Simp }; 2473123120Simp#elif __FreeBSD_version <= 501000 2474123120Simpstatic struct cdevsw cx_cdevsw = { 2475123120Simp .d_open = cx_open, 2476123120Simp .d_close = cx_close, 2477123120Simp .d_read = cx_read, 2478123120Simp .d_write = cx_write, 2479123120Simp .d_ioctl = cx_ioctl, 2480123120Simp .d_poll = ttypoll, 2481123120Simp .d_mmap = nommap, 2482123120Simp .d_strategy = nostrategy, 2483123120Simp .d_name = "cx", 2484123120Simp .d_maj = CDEV_MAJOR, 2485123120Simp .d_dump = nodump, 2486123120Simp .d_flags = D_TTY, 2487123120Simp}; 2488126492Srik#elif __FreeBSD_version < 502103 2489123120Simpstatic struct cdevsw cx_cdevsw = { 2490123120Simp .d_open = cx_open, 2491123120Simp .d_close = cx_close, 2492123120Simp .d_read = cx_read, 2493123120Simp .d_write = cx_write, 2494123120Simp .d_ioctl = cx_ioctl, 2495126492Srik .d_poll = ttypoll, 2496123120Simp .d_name = "cx", 2497123120Simp .d_maj = CDEV_MAJOR, 2498126492Srik .d_flags = D_TTY, 2499126492Srik}; 2500126492Srik#else /* __FreeBSD_version >= 502103 */ 2501126492Srikstatic struct cdevsw cx_cdevsw = { 2502126492Srik .d_version = D_VERSION, 2503126492Srik .d_open = cx_open, 2504126492Srik .d_close = cx_close, 2505126492Srik .d_read = cx_read, 2506126492Srik .d_write = cx_write, 2507126492Srik .d_ioctl = cx_ioctl, 2508126492Srik .d_name = "cx", 2509126492Srik .d_maj = CDEV_MAJOR, 2510126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 2511123120Simp}; 2512123120Simp#endif 2513123120Simp 2514123120Simp#ifdef NETGRAPH 2515123120Simp#if __FreeBSD_version >= 500000 2516123120Simpstatic int ng_cx_constructor (node_p node) 2517123120Simp{ 2518123120Simp drv_t *d = NG_NODE_PRIVATE (node); 2519123120Simp#else 2520123120Simpstatic int ng_cx_constructor (node_p *node) 2521123120Simp{ 2522123120Simp drv_t *d = (*node)->private; 2523123120Simp#endif 2524123120Simp CX_DEBUG (d, ("Constructor\n")); 2525123120Simp return EINVAL; 2526123120Simp} 2527123120Simp 2528123120Simpstatic int ng_cx_newhook (node_p node, hook_p hook, const char *name) 2529123120Simp{ 2530123120Simp int s; 2531123120Simp#if __FreeBSD_version >= 500000 2532123120Simp drv_t *d = NG_NODE_PRIVATE (node); 2533123120Simp#else 2534123120Simp drv_t *d = node->private; 2535123120Simp#endif 2536123120Simp 2537123120Simp if (d->chan->mode == M_ASYNC) 2538123120Simp return EINVAL; 2539123120Simp 2540123120Simp /* Attach debug hook */ 2541123120Simp if (strcmp (name, NG_CX_HOOK_DEBUG) == 0) { 2542123120Simp#if __FreeBSD_version >= 500000 2543123120Simp NG_HOOK_SET_PRIVATE (hook, NULL); 2544123120Simp#else 2545123120Simp hook->private = 0; 2546123120Simp#endif 2547123120Simp d->debug_hook = hook; 2548123120Simp return 0; 2549123120Simp } 2550123120Simp 2551123120Simp /* Check for raw hook */ 2552123120Simp if (strcmp (name, NG_CX_HOOK_RAW) != 0) 2553123120Simp return EINVAL; 2554123120Simp 2555123120Simp#if __FreeBSD_version >= 500000 2556123120Simp NG_HOOK_SET_PRIVATE (hook, d); 2557123120Simp#else 2558123120Simp hook->private = d; 2559123120Simp#endif 2560123120Simp d->hook = hook; 2561123120Simp s = splhigh (); 2562123120Simp cx_up (d); 2563123120Simp splx (s); 2564123120Simp return 0; 2565123120Simp} 2566123120Simp 2567123120Simpstatic int print_modems (char *s, cx_chan_t *c, int need_header) 2568123120Simp{ 2569123120Simp int status = cx_modem_status (c->sys); 2570123120Simp int length = 0; 2571123120Simp 2572123120Simp if (need_header) 2573123120Simp length += sprintf (s + length, " LE DTR DSR RTS CTS CD\n"); 2574123120Simp length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n", 2575123120Simp status & TIOCM_LE ? "On" : "-", 2576123120Simp status & TIOCM_DTR ? "On" : "-", 2577123120Simp status & TIOCM_DSR ? "On" : "-", 2578123120Simp status & TIOCM_RTS ? "On" : "-", 2579123120Simp status & TIOCM_CTS ? "On" : "-", 2580123120Simp status & TIOCM_CD ? "On" : "-"); 2581123120Simp return length; 2582123120Simp} 2583123120Simp 2584123120Simpstatic int print_stats (char *s, cx_chan_t *c, int need_header) 2585123120Simp{ 2586123120Simp int length = 0; 2587123120Simp 2588123120Simp if (need_header) 2589123120Simp length += sprintf (s + length, " Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); 2590123120Simp length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n", 2591123120Simp c->rintr, c->tintr, c->mintr, c->ibytes, c->ipkts, 2592123120Simp c->ierrs, c->obytes, c->opkts, c->oerrs); 2593123120Simp return length; 2594123120Simp} 2595123120Simp 2596123120Simpstatic int print_chan (char *s, cx_chan_t *c) 2597123120Simp{ 2598123120Simp drv_t *d = c->sys; 2599123120Simp int length = 0; 2600123120Simp 2601123120Simp length += sprintf (s + length, "cx%d", c->board->num * NCHAN + c->num); 2602123120Simp if (d->chan->debug) 2603123120Simp length += sprintf (s + length, " debug=%d", d->chan->debug); 2604123120Simp 2605123120Simp if (cx_get_baud (c)) 2606123120Simp length += sprintf (s + length, " %ld", cx_get_baud (c)); 2607123120Simp else 2608123120Simp length += sprintf (s + length, " extclock"); 2609123120Simp 2610123120Simp if (c->mode == M_HDLC) { 2611123120Simp length += sprintf (s + length, " dpll=%s", cx_get_dpll (c) ? "on" : "off"); 2612123120Simp length += sprintf (s + length, " nrzi=%s", cx_get_nrzi (c) ? "on" : "off"); 2613123120Simp } 2614123120Simp 2615123120Simp length += sprintf (s + length, " loop=%s", cx_get_loop (c) ? "on\n" : "off\n"); 2616123120Simp return length; 2617123120Simp} 2618123120Simp 2619123120Simp#if __FreeBSD_version >= 500000 2620123120Simpstatic int ng_cx_rcvmsg (node_p node, item_p item, hook_p lasthook) 2621123120Simp{ 2622123120Simp drv_t *d = NG_NODE_PRIVATE (node); 2623123120Simp struct ng_mesg *msg; 2624123120Simp#else 2625123120Simpstatic int ng_cx_rcvmsg (node_p node, struct ng_mesg *msg, 2626123120Simp const char *retaddr, struct ng_mesg **rptr) 2627123120Simp{ 2628123120Simp drv_t *d = node->private; 2629123120Simp#endif 2630123120Simp struct ng_mesg *resp = NULL; 2631123120Simp int error = 0; 2632123120Simp 2633123120Simp if (!d) 2634123120Simp return EINVAL; 2635123120Simp 2636123120Simp CX_DEBUG (d, ("Rcvmsg\n")); 2637123120Simp#if __FreeBSD_version >= 500000 2638123120Simp NGI_GET_MSG (item, msg); 2639123120Simp#endif 2640123120Simp switch (msg->header.typecookie) { 2641123120Simp default: 2642123120Simp error = EINVAL; 2643123120Simp break; 2644123120Simp 2645123120Simp case NGM_CX_COOKIE: 2646123120Simp printf ("Don't forget to implement\n"); 2647123120Simp error = EINVAL; 2648123120Simp break; 2649123120Simp 2650123120Simp case NGM_GENERIC_COOKIE: 2651123120Simp switch (msg->header.cmd) { 2652123120Simp default: 2653123120Simp error = EINVAL; 2654123120Simp break; 2655123120Simp 2656123120Simp case NGM_TEXT_STATUS: { 2657123120Simp char *s; 2658123120Simp int l = 0; 2659123120Simp int dl = sizeof (struct ng_mesg) + 730; 2660123120Simp 2661123120Simp#if __FreeBSD_version >= 500000 2662123120Simp NG_MKRESPONSE (resp, msg, dl, M_NOWAIT); 2663123120Simp if (! resp) { 2664123120Simp error = ENOMEM; 2665123120Simp break; 2666123120Simp } 2667123120Simp#else 2668123120Simp MALLOC (resp, struct ng_mesg *, dl, 2669123120Simp M_NETGRAPH, M_NOWAIT); 2670123120Simp if (! resp) { 2671123120Simp error = ENOMEM; 2672123120Simp break; 2673123120Simp } 2674123120Simp#endif 2675123120Simp bzero (resp, dl); 2676123120Simp s = (resp)->data; 2677123120Simp l += print_chan (s + l, d->chan); 2678123120Simp l += print_stats (s + l, d->chan, 1); 2679123120Simp l += print_modems (s + l, d->chan, 1); 2680123120Simp#if __FreeBSD_version < 500000 2681123120Simp (resp)->header.version = NG_VERSION; 2682123120Simp (resp)->header.arglen = strlen (s) + 1; 2683123120Simp (resp)->header.token = msg->header.token; 2684123120Simp (resp)->header.typecookie = NGM_CX_COOKIE; 2685123120Simp (resp)->header.cmd = msg->header.cmd; 2686123120Simp#endif 2687123120Simp strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN); 2688123120Simp } 2689123120Simp break; 2690123120Simp } 2691123120Simp break; 2692123120Simp } 2693123120Simp#if __FreeBSD_version >= 500000 2694123120Simp NG_RESPOND_MSG (error, node, item, resp); 2695123120Simp NG_FREE_MSG (msg); 2696123120Simp#else 2697123120Simp *rptr = resp; 2698123120Simp FREE (msg, M_NETGRAPH); 2699123120Simp#endif 2700123120Simp return error; 2701123120Simp} 2702123120Simp 2703123120Simp#if __FreeBSD_version >= 500000 2704123120Simpstatic int ng_cx_rcvdata (hook_p hook, item_p item) 2705123120Simp{ 2706123120Simp drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook)); 2707123120Simp struct mbuf *m; 2708131108Sjulian struct ng_tag_prio *ptag; 2709123120Simp#else 2710123120Simpstatic int ng_cx_rcvdata (hook_p hook, struct mbuf *m, meta_p meta) 2711123120Simp{ 2712123120Simp drv_t *d = hook->node->private; 2713123120Simp#endif 2714123120Simp struct ifqueue *q; 2715123120Simp int s; 2716123120Simp 2717123120Simp#if __FreeBSD_version >= 500000 2718123120Simp NGI_GET_M (item, m); 2719123120Simp NG_FREE_ITEM (item); 2720123120Simp if (! NG_HOOK_PRIVATE (hook) || ! d) { 2721123120Simp NG_FREE_M (m); 2722123120Simp#else 2723123120Simp if (! hook->private || ! d) { 2724123120Simp NG_FREE_DATA (m,meta); 2725123120Simp#endif 2726123120Simp return ENETDOWN; 2727123120Simp } 2728131108Sjulian 2729131108Sjulian /* Check for high priority data */ 2730131108Sjulian if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE, 2731131108Sjulian NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) ) 2732131108Sjulian q = &d->hi_queue; 2733131108Sjulian else 2734131108Sjulian q = &d->lo_queue; 2735131108Sjulian 2736123120Simp s = splhigh (); 2737123120Simp#if __FreeBSD_version >= 500000 2738123120Simp IF_LOCK (q); 2739123120Simp if (_IF_QFULL (q)) { 2740123120Simp _IF_DROP (q); 2741123120Simp IF_UNLOCK (q); 2742123120Simp splx (s); 2743123120Simp NG_FREE_M (m); 2744123120Simp return ENOBUFS; 2745123120Simp } 2746123120Simp _IF_ENQUEUE (q, m); 2747123120Simp IF_UNLOCK (q); 2748123120Simp#else 2749123120Simp if (IF_QFULL (q)) { 2750123120Simp IF_DROP (q); 2751123120Simp splx (s); 2752123120Simp NG_FREE_DATA (m, meta); 2753123120Simp return ENOBUFS; 2754123120Simp } 2755123120Simp IF_ENQUEUE (q, m); 2756123120Simp#endif 2757123120Simp cx_start (d); 2758123120Simp splx (s); 2759123120Simp return 0; 2760123120Simp} 2761123120Simp 2762123120Simpstatic int ng_cx_rmnode (node_p node) 2763123120Simp{ 2764123120Simp#if __FreeBSD_version >= 500000 2765123120Simp drv_t *d = NG_NODE_PRIVATE (node); 2766123120Simp 2767123120Simp CX_DEBUG (d, ("Rmnode\n")); 2768123120Simp if (d && d->running) { 2769123120Simp int s = splhigh (); 2770123120Simp cx_down (d); 2771123120Simp splx (s); 2772123120Simp } 2773123120Simp#ifdef KLD_MODULE 2774123120Simp if (node->nd_flags & NG_REALLY_DIE) { 2775123120Simp NG_NODE_SET_PRIVATE (node, NULL); 2776123120Simp NG_NODE_UNREF (node); 2777123120Simp } 2778123120Simp node->nd_flags &= ~NG_INVALID; 2779123120Simp#endif 2780123120Simp#else /* __FreeBSD_version < 500000 */ 2781123120Simp drv_t *d = node->private; 2782123120Simp int s; 2783123120Simp 2784123120Simp s = splhigh (); 2785123120Simp cx_down (d); 2786123120Simp splx (s); 2787123120Simp node->flags |= NG_INVALID; 2788123120Simp ng_cutlinks (node); 2789123120Simp#ifdef KLD_MODULE 2790123120Simp ng_unname (node); 2791123120Simp ng_unref (node); 2792123120Simp#else 2793123120Simp node->flags &= ~NG_INVALID; 2794123120Simp#endif 2795123120Simp#endif 2796123120Simp return 0; 2797123120Simp} 2798123120Simp 2799123120Simpstatic void ng_cx_watchdog (void *arg) 2800123120Simp{ 2801123120Simp drv_t *d = arg; 2802123120Simp 2803123120Simp if (d->timeout == 1) 2804123120Simp cx_watchdog (d); 2805123120Simp if (d->timeout) 2806123120Simp d->timeout--; 2807123120Simp d->timeout_handle = timeout (ng_cx_watchdog, d, hz); 2808123120Simp} 2809123120Simp 2810123120Simpstatic int ng_cx_connect (hook_p hook) 2811123120Simp{ 2812123120Simp#if __FreeBSD_version >= 500000 2813123120Simp drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2814123120Simp#else 2815123120Simp drv_t *d = hook->node->private; 2816123120Simp#endif 2817123120Simp 2818123120Simp d->timeout_handle = timeout (ng_cx_watchdog, d, hz); 2819123120Simp return 0; 2820123120Simp} 2821123120Simp 2822123120Simpstatic int ng_cx_disconnect (hook_p hook) 2823123120Simp{ 2824123120Simp#if __FreeBSD_version >= 500000 2825123120Simp drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2826123120Simp#else 2827123120Simp drv_t *d = hook->node->private; 2828123120Simp#endif 2829123120Simp int s; 2830123120Simp 2831123120Simp s = splhigh (); 2832123120Simp#if __FreeBSD_version >= 500000 2833123120Simp if (NG_HOOK_PRIVATE (hook)) 2834123120Simp#else 2835123120Simp if (hook->private) 2836123120Simp#endif 2837123120Simp cx_down (d); 2838123120Simp splx (s); 2839123120Simp untimeout (ng_cx_watchdog, d, d->timeout_handle); 2840123120Simp return 0; 2841123120Simp} 2842123120Simp#endif /*NETGRAPH*/ 2843123120Simp 2844123120Simpstatic int cx_modevent (module_t mod, int type, void *unused) 2845123120Simp{ 2846130585Sphk struct cdev *dev; 2847123120Simp static int load_count = 0; 2848123120Simp struct cdevsw *cdsw; 2849123120Simp 2850126492Srik#if __FreeBSD_version >= 502103 2851130640Sphk dev = findcdev (makedev(CDEV_MAJOR, 0)); 2852126492Srik#else 2853126492Srik dev = makedev (CDEV_MAJOR, 0); 2854126492Srik#endif 2855123120Simp switch (type) { 2856123120Simp case MOD_LOAD: 2857130640Sphk if (dev != NULL && 2858126492Srik (cdsw = devsw (dev)) && 2859126492Srik cdsw->d_maj == CDEV_MAJOR) { 2860123120Simp printf ("Sigma driver is already in system\n"); 2861123120Simp return (EEXIST); 2862123120Simp } 2863123120Simp#if __FreeBSD_version >= 500000 && defined NETGRAPH 2864123120Simp if (ng_newtype (&typestruct)) 2865123120Simp printf ("Failed to register ng_cx\n"); 2866123120Simp#endif 2867123120Simp ++load_count; 2868123120Simp#if __FreeBSD_version <= 500000 2869123120Simp cdevsw_add (&cx_cdevsw); 2870123120Simp#endif 2871123120Simp timeout_handle = timeout (cx_timeout, 0, hz*5); 2872123120Simp /* Software interrupt. */ 2873123120Simp#if __FreeBSD_version < 500000 2874123120Simp register_swi (SWI_TTY, cx_softintr); 2875123120Simp#else 2876123120Simp swi_add(&tty_ithd, "tty:cx", cx_softintr, NULL, SWI_TTY, 0, 2877123120Simp &cx_fast_ih); 2878123120Simp#endif 2879123120Simp break; 2880123120Simp case MOD_UNLOAD: 2881123120Simp if (load_count == 1) { 2882123120Simp printf ("Removing device entry for Sigma\n"); 2883123120Simp#if __FreeBSD_version <= 500000 2884123120Simp cdevsw_remove (&cx_cdevsw); 2885123120Simp#endif 2886123120Simp#if __FreeBSD_version >= 500000 && defined NETGRAPH 2887123120Simp ng_rmtype (&typestruct); 2888123120Simp#endif 2889123120Simp } 2890123120Simp if (timeout_handle.callout) 2891123120Simp untimeout (cx_timeout, 0, timeout_handle); 2892123120Simp#if __FreeBSD_version >= 500000 2893123120Simp ithread_remove_handler (cx_fast_ih); 2894123120Simp#else 2895123120Simp unregister_swi (SWI_TTY, cx_softintr); 2896123120Simp#endif 2897123120Simp --load_count; 2898123120Simp break; 2899123120Simp case MOD_SHUTDOWN: 2900123120Simp break; 2901123120Simp } 2902123120Simp return 0; 2903123120Simp} 2904123120Simp 2905123120Simp#ifdef NETGRAPH 2906123120Simpstatic struct ng_type typestruct = { 2907129837Srik .version = NG_ABI_VERSION, 2908129837Srik .name = NG_CX_NODE_TYPE, 2909129837Srik .constructor = ng_cx_constructor, 2910129837Srik .rcvmsg = ng_cx_rcvmsg, 2911129837Srik .shutdown = ng_cx_rmnode, 2912129837Srik .newhook = ng_cx_newhook, 2913129837Srik .connect = ng_cx_connect, 2914129837Srik .rcvdata = ng_cx_rcvdata, 2915130985Srik .disconnect = ng_cx_disconnect, 2916123120Simp}; 2917123120Simp#endif /*NETGRAPH*/ 2918123120Simp 2919123120Simp#if __FreeBSD_version >= 500000 2920123120Simp#ifdef NETGRAPH 2921123120SimpMODULE_DEPEND (ng_cx, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 2922123120Simp#else 2923123120SimpMODULE_DEPEND (isa_cx, sppp, 1, 1, 1); 2924123120Simp#endif 2925123120Simp#ifdef KLD_MODULE 2926123120SimpDRIVER_MODULE (cxmod, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL); 2927123120Simp#else 2928123120SimpDRIVER_MODULE (cx, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL); 2929123120Simp#endif 2930123120Simp#elif __FreeBSD_version >= 400000 2931123120Simp#ifdef NETGRAPH 2932123120SimpDRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, ng_mod_event, &typestruct); 2933123120Simp#else 2934123120SimpDRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, cx_modevent, 0); 2935123120Simp#endif 2936130971Srik#endif /* __FreeBSD_version >= 400000 */ 2937123120Simp#endif /* NCX */ 2938