if_cx.c revision 130971
1228753Smm/* 2228753Smm * Cronyx-Sigma adapter driver for FreeBSD. 3228753Smm * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode, 4228753Smm * and asyncronous channels with full modem control. 5228753Smm * Keepalive protocol implemented in both Cisco and PPP modes. 6228753Smm * 7228753Smm * Copyright (C) 1994-2002 Cronyx Engineering. 8228753Smm * Author: Serge Vakulenko, <vak@cronyx.ru> 9228753Smm * 10228753Smm * Copyright (C) 1999-2004 Cronyx Engineering. 11228753Smm * Rewritten on DDK, ported to NETGRAPH, rewritten for FreeBSD 3.x-5.x by 12228753Smm * Kurakin Roman, <rik@cronyx.ru> 13228753Smm * 14228753Smm * This software is distributed with NO WARRANTIES, not even the implied 15228753Smm * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16228753Smm * 17228753Smm * Authors grant any other persons or organisations a permission to use, 18228753Smm * modify and redistribute this software in source and binary forms, 19228753Smm * as long as this message is kept with the software, all derivative 20228753Smm * works or modified versions. 21228753Smm * 22228753Smm * Cronyx Id: if_cx.c,v 1.1.2.23 2004/02/26 17:56:40 rik Exp $ 23228753Smm */ 24228753Smm#include <sys/cdefs.h> 25228753Smm__FBSDID("$FreeBSD: head/sys/dev/cx/if_cx.c 130971 2004-06-23 11:23:54Z rik $"); 26228753Smm 27228753Smm#include <sys/param.h> 28228753Smm 29228753Smm#if __FreeBSD_version >= 500000 30228753Smm# define NCX 1 31228753Smm#else 32228753Smm# include "cx.h" 33228753Smm#endif 34228753Smm 35228753Smm#if NCX > 0 36228753Smm#include <sys/systm.h> 37228753Smm#include <sys/kernel.h> 38228753Smm#include <sys/module.h> 39228753Smm#include <sys/proc.h> 40228753Smm#include <sys/mbuf.h> 41228753Smm#include <sys/sockio.h> 42228753Smm#include <sys/malloc.h> 43238856Smm#include <sys/socket.h> 44238856Smm#include <sys/conf.h> 45302001Smm#include <sys/errno.h> 46228753Smm#include <sys/tty.h> 47302001Smm#include <sys/bus.h> 48302001Smm#include <machine/bus.h> 49302001Smm#include <sys/rman.h> 50302001Smm#include <isa/isavar.h> 51302001Smm#include <sys/fcntl.h> 52302001Smm#include <sys/interrupt.h> 53302001Smm#include <vm/vm.h> 54302001Smm#include <vm/pmap.h> 55302001Smm#include <net/if.h> 56302001Smm#include <machine/cpufunc.h> 57302001Smm#include <machine/cserial.h> 58302001Smm#include <machine/clock.h> 59302001Smm#if __FreeBSD_version < 500000 60302001Smm#include <machine/ipl.h> 61302001Smm#include <i386/isa/isa_device.h> 62302001Smm#endif 63302001Smm#include <machine/resource.h> 64302001Smm#if __FreeBSD_version <= 501000 65302001Smm# include <i386/isa/intr_machdep.h> 66302001Smm#endif 67302001Smm#include <dev/cx/machdep.h> 68302001Smm#include <dev/cx/cxddk.h> 69302001Smm#include <dev/cx/cronyxfw.h> 70302001Smm#include "opt_ng_cronyx.h" 71228753Smm#ifdef NETGRAPH_CRONYX 72228753Smm# include "opt_netgraph.h" 73228753Smm# include <netgraph/ng_message.h> 74228753Smm# include <netgraph/netgraph.h> 75228753Smm# include <dev/cx/ng_cx.h> 76228753Smm#else 77228753Smm# include <net/if_types.h> 78228753Smm# if __FreeBSD_version < 500000 79228753Smm# include "sppp.h" 80228753Smm# if NSPPP <= 0 81228753Smm# error The device cx requires sppp or netgraph. 82228753Smm# endif 83228753Smm# endif 84228753Smm# include <net/if_sppp.h> 85228753Smm# define PP_CISCO IFF_LINK2 86228753Smm# if __FreeBSD_version < 500000 87228753Smm# include <bpf.h> 88228753Smm# endif 89228753Smm# include <net/bpf.h> 90228753Smm# define NBPFILTER NBPF 91228753Smm#endif 92228753Smm 93228753Smm#if __FreeBSD_version < 502113 94228753Smm#define ttyld_modem(foo, bar) ((*linesw[(foo)->t_line].l_modem)((foo), (bar))) 95228753Smm#define ttyld_rint(foo, bar) ((*linesw[(foo)->t_line].l_rint)((bar), (foo))) 96228753Smm#define ttyld_start(foo) ((*linesw[(foo)->t_line].l_start)((foo))) 97228753Smm#define ttyld_open(foo, bar) ((*linesw[(foo)->t_line].l_open) ((bar), (foo))) 98228753Smm#define ttyld_close(foo, bar) ((*linesw[(foo)->t_line].l_close) ((foo), (bar))) 99228753Smm#define ttyld_read(foo, bar, barf) ((*linesw[(foo)->t_line].l_read) ((foo), (bar), (barf))) 100228753Smm#define ttyld_write(foo, bar, barf) ((*linesw[(foo)->t_line].l_write) ((foo), (bar), (barf))) 101#endif 102 103/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */ 104#ifndef PP_FR 105#define PP_FR 0 106#endif 107 108#define CX_DEBUG(d,s) ({if (d->chan->debug) {\ 109 printf ("%s: ", d->name); printf s;}}) 110#define CX_DEBUG2(d,s) ({if (d->chan->debug>1) {\ 111 printf ("%s: ", d->name); printf s;}}) 112 113#define UNIT(d) (minor(d) & 0x3f) 114#define IF_CUNIT(d) (minor(d) & 0x40) 115#define UNIT_CTL 0x3f 116#define CALLOUT(d) (minor(d) & 0x80) 117#define CDEV_MAJOR 42 118 119typedef struct _async_q { 120 int beg; 121 int end; 122 #define BF_SZ 14400 123 int buf[BF_SZ+1]; 124} async_q; 125 126#define AQ_GSZ(q) ((BF_SZ + (q)->end - (q)->beg)%BF_SZ) 127#define AQ_PUSH(q,c) {*((q)->buf + (q)->end) = c;\ 128 (q)->end = ((q)->end + 1)%BF_SZ;} 129#define AQ_POP(q,c) {c = *((q)->buf + (q)->beg);\ 130 (q)->beg = ((q)->beg + 1)%BF_SZ;} 131 132static void cx_identify __P((driver_t *, device_t)); 133static int cx_probe __P((device_t)); 134static int cx_attach __P((device_t)); 135static int cx_detach __P((device_t)); 136 137static device_method_t cx_isa_methods [] = { 138 DEVMETHOD(device_identify, cx_identify), 139 DEVMETHOD(device_probe, cx_probe), 140 DEVMETHOD(device_attach, cx_attach), 141 DEVMETHOD(device_detach, cx_detach), 142 {0, 0} 143}; 144 145typedef struct _bdrv_t { 146 cx_board_t *board; 147 struct resource *base_res; 148 struct resource *drq_res; 149 struct resource *irq_res; 150 int base_rid; 151 int drq_rid; 152 int irq_rid; 153 void *intrhand; 154} bdrv_t; 155 156static driver_t cx_isa_driver = { 157 "cx", 158 cx_isa_methods, 159 sizeof (bdrv_t), 160}; 161 162static devclass_t cx_devclass; 163 164typedef struct _drv_t { 165 char name [8]; 166 cx_chan_t *chan; 167 cx_board_t *board; 168 cx_buf_t buf; 169 struct tty *tty; 170 struct callout_handle dcd_timeout_handle; 171 unsigned dtrwait; 172 unsigned dtroff; 173 unsigned callout; 174 unsigned lock; 175 int open_dev; 176 int cd; 177 int running; 178 struct callout_handle dtr_timeout_handle; 179#ifdef NETGRAPH 180 char nodename [NG_NODELEN+1]; 181 hook_p hook; 182 hook_p debug_hook; 183 node_p node; 184 struct ifqueue lo_queue; 185 struct ifqueue hi_queue; 186 short timeout; 187 struct callout_handle timeout_handle; 188#else 189 struct sppp pp; 190#endif 191 struct cdev *devt[3]; 192 async_q aqueue; 193#define CX_READ 1 194#define CX_WRITE 2 195 int intr_action; 196 short atimeout; 197} drv_t; 198 199extern long csigma_fw_len; 200extern const char *csigma_fw_version; 201extern const char *csigma_fw_date; 202extern const char *csigma_fw_copyright; 203extern const cr_dat_tst_t csigma_fw_tvec[]; 204extern const u_char csigma_fw_data[]; 205static void cx_oproc (struct tty *tp); 206static int cx_param (struct tty *tp, struct termios *t); 207static void cx_stop (struct tty *tp, int flag); 208static void cx_dtrwakeup (void *a); 209static void cx_receive (cx_chan_t *c, char *data, int len); 210static void cx_transmit (cx_chan_t *c, void *attachment, int len); 211static void cx_error (cx_chan_t *c, int data); 212static void cx_modem (cx_chan_t *c); 213static void cx_up (drv_t *d); 214static void cx_start (drv_t *d); 215#if __FreeBSD_version < 502113 216static void ttyldoptim(struct tty *tp); 217#endif 218#if __FreeBSD_version < 500000 219static swihand_t cx_softintr; 220#else 221static void cx_softintr (void *); 222static void *cx_fast_ih; 223#endif 224static void cx_down (drv_t *d); 225static void cx_watchdog (drv_t *d); 226static void cx_carrier (void *arg); 227 228#ifdef NETGRAPH 229extern struct ng_type typestruct; 230#else 231static void cx_ifstart (struct ifnet *ifp); 232static void cx_tlf (struct sppp *sp); 233static void cx_tls (struct sppp *sp); 234static void cx_ifwatchdog (struct ifnet *ifp); 235static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 236static void cx_initialize (void *softc); 237#endif 238 239static cx_board_t *adapter [NCX]; 240static drv_t *channel [NCX*NCHAN]; 241static struct callout_handle led_timo [NCX]; 242static struct callout_handle timeout_handle; 243extern struct cdevsw cx_cdevsw; 244 245static int MY_SOFT_INTR; 246 247/* 248 * Print the mbuf chain, for debug purposes only. 249 */ 250static void printmbuf (struct mbuf *m) 251{ 252 printf ("mbuf:"); 253 for (; m; m=m->m_next) { 254 if (m->m_flags & M_PKTHDR) 255 printf (" HDR %d:", m->m_pkthdr.len); 256 if (m->m_flags & M_EXT) 257 printf (" EXT:"); 258 printf (" %d", m->m_len); 259 } 260 printf ("\n"); 261} 262 263/* 264 * Make an mbuf from data. 265 */ 266static struct mbuf *makembuf (void *buf, u_int len) 267{ 268 struct mbuf *m, *o, *p; 269 270 MGETHDR (m, M_DONTWAIT, MT_DATA); 271 272 if (! m) 273 return 0; 274 275 if (len >= MINCLSIZE) 276 MCLGET (m, M_DONTWAIT); 277 278 m->m_pkthdr.len = len; 279 m->m_len = 0; 280 281 p = m; 282 while (len) { 283 u_int n = M_TRAILINGSPACE (p); 284 if (n > len) 285 n = len; 286 if (! n) { 287 /* Allocate new mbuf. */ 288 o = p; 289 MGET (p, M_DONTWAIT, MT_DATA); 290 if (! p) { 291 m_freem (m); 292 return 0; 293 } 294 if (len >= MINCLSIZE) 295 MCLGET (p, M_DONTWAIT); 296 p->m_len = 0; 297 o->m_next = p; 298 299 n = M_TRAILINGSPACE (p); 300 if (n > len) 301 n = len; 302 } 303 bcopy (buf, mtod (p, caddr_t) + p->m_len, n); 304 305 p->m_len += n; 306 buf = n + (char*) buf; 307 len -= n; 308 } 309 return m; 310} 311 312/* 313 * Recover after lost transmit interrupts. 314 */ 315static void cx_timeout (void *arg) 316{ 317 drv_t *d; 318 int s, i; 319 320 for (i=0; i<NCX*NCHAN; ++i) { 321 d = channel[i]; 322 if (! d) 323 continue; 324 s = splhigh (); 325 if (d->atimeout == 1 && d->tty && d->tty->t_state & TS_BUSY) { 326 d->tty->t_state &= ~TS_BUSY; 327 if (d->tty->t_dev) { 328 d->intr_action |= CX_WRITE; 329 MY_SOFT_INTR = 1; 330#if __FreeBSD_version >= 500000 331 swi_sched (cx_fast_ih, 0); 332#else 333 setsofttty (); 334#endif 335 } 336 CX_DEBUG (d, ("cx_timeout\n")); 337 } 338 if (d->atimeout) 339 d->atimeout--; 340 splx (s); 341 } 342 timeout_handle = timeout (cx_timeout, 0, hz*5); 343} 344 345static void cx_led_off (void *arg) 346{ 347 cx_board_t *b = arg; 348 int s = splhigh (); 349 350 cx_led (b, 0); 351 led_timo[b->num].callout = 0; 352 splx (s); 353} 354 355/* 356 * Activate interupt handler from DDK. 357 */ 358static void cx_intr (void *arg) 359{ 360 bdrv_t *bd = arg; 361 cx_board_t *b = bd->board; 362 int s = splhigh (); 363 364 /* Turn LED on. */ 365 cx_led (b, 1); 366 367 cx_int_handler (b); 368 369 /* Turn LED off 50 msec later. */ 370 if (! led_timo[b->num].callout) 371 led_timo[b->num] = timeout (cx_led_off, b, hz/20); 372 splx (s); 373} 374 375static int probe_irq (cx_board_t *b, int irq) 376{ 377 int mask, busy, cnt; 378 379 /* Clear pending irq, if any. */ 380 cx_probe_irq (b, -irq); 381 DELAY (100); 382 for (cnt=0; cnt<5; ++cnt) { 383 /* Get the mask of pending irqs, assuming they are busy. 384 * Activate the adapter on given irq. */ 385 busy = cx_probe_irq (b, irq); 386 DELAY (100); 387 388 /* Get the mask of active irqs. 389 * Deactivate our irq. */ 390 mask = cx_probe_irq (b, -irq); 391 DELAY (100); 392 if ((mask & ~busy) == 1 << irq) { 393 cx_probe_irq (b, 0); 394 /* printf ("cx%d: irq %d ok, mask=0x%04x, busy=0x%04x\n", 395 b->num, irq, mask, busy); */ 396 return 1; 397 } 398 } 399 /* printf ("cx%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n", 400 b->num, irq, mask, busy); */ 401 cx_probe_irq (b, 0); 402 return 0; 403} 404 405static short porttab [] = { 406 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 407 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 408}; 409static char dmatab [] = { 7, 6, 5, 0 }; 410static char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 }; 411 412static int cx_is_free_res (device_t dev, int rid, int type, u_long start, 413 u_long end, u_long count) 414{ 415 struct resource *res; 416 417 if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count, 418 RF_ALLOCATED))) 419 return 0; 420 421 bus_release_resource (dev, type, rid, res); 422 423 return 1; 424} 425 426static void cx_identify (driver_t *driver, device_t dev) 427{ 428 u_long iobase, rescount; 429 int devcount; 430 device_t *devices; 431 device_t child; 432 devclass_t my_devclass; 433 int i, k; 434 435 if ((my_devclass = devclass_find ("cx")) == NULL) 436 return; 437 438 devclass_get_devices (my_devclass, &devices, &devcount); 439 440 if (devcount == 0) { 441 /* We should find all devices by our self. We could alter other 442 * devices, but we don't have a choise 443 */ 444 for (i = 0; (iobase = porttab [i]) != 0; i++) { 445 if (!cx_is_free_res (dev, 1, SYS_RES_IOPORT, 446 iobase, iobase + NPORT, NPORT)) 447 continue; 448 if (cx_probe_board (iobase, -1, -1) == 0) 449 continue; 450 451 devcount++; 452 453 child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "cx", 454 -1); 455 456 if (child == NULL) 457 return; 458 459 device_set_desc_copy (child, "Cronyx Sigma"); 460 device_set_driver (child, driver); 461 bus_set_resource (child, SYS_RES_IOPORT, 0, 462 iobase, NPORT); 463 464 if (devcount >= NCX) 465 break; 466 } 467 } else { 468 static short porttab [] = { 469 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 470 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 471 }; 472 /* Lets check user choise. 473 */ 474 for (k = 0; k < devcount; k++) { 475 if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, 476 &iobase, &rescount) != 0) 477 continue; 478 479 for (i = 0; porttab [i] != 0; i++) { 480 if (porttab [i] != iobase) 481 continue; 482 if (!cx_is_free_res (devices[k], 1, SYS_RES_IOPORT, 483 iobase, iobase + NPORT, NPORT)) 484 continue; 485 if (cx_probe_board (iobase, -1, -1) == 0) 486 continue; 487 porttab [i] = -1; 488 device_set_desc_copy (devices[k], "Cronyx Sigma"); 489 break; 490 } 491 492 if (porttab [i] == 0) { 493 device_delete_child ( 494 device_get_parent (devices[k]), 495 devices [k]); 496 devices[k] = 0; 497 continue; 498 } 499 } 500 for (k = 0; k < devcount; k++) { 501 if (devices[k] == 0) 502 continue; 503 if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0, 504 &iobase, &rescount) == 0) 505 continue; 506 for (i = 0; (iobase = porttab [i]) != 0; i++) { 507 if (porttab [i] == -1) { 508 continue; 509 } 510 if (!cx_is_free_res (devices[k], 1, SYS_RES_IOPORT, 511 iobase, iobase + NPORT, NPORT)) 512 continue; 513 if (cx_probe_board (iobase, -1, -1) == 0) 514 continue; 515 516 bus_set_resource (devices[k], SYS_RES_IOPORT, 0, 517 iobase, NPORT); 518 porttab [i] = -1; 519 device_set_desc_copy (devices[k], "Cronyx Sigma"); 520 break; 521 } 522 if (porttab [i] == 0) { 523 device_delete_child ( 524 device_get_parent (devices[k]), 525 devices [k]); 526 } 527 } 528 free (devices, M_TEMP); 529 } 530 531 return; 532} 533 534static int cx_probe (device_t dev) 535{ 536 int unit = device_get_unit (dev); 537 int i; 538 u_long iobase, rescount; 539 540 if (!device_get_desc (dev) || 541 strcmp (device_get_desc (dev), "Cronyx Sigma")) 542 return ENXIO; 543 544 if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) { 545 printf ("cx%d: Couldn't get IOPORT\n", unit); 546 return ENXIO; 547 } 548 549 if (!cx_is_free_res (dev, 1, SYS_RES_IOPORT, 550 iobase, iobase + NPORT, NPORT)) { 551 printf ("cx%d: Resource IOPORT isn't free %lx\n", unit, iobase); 552 return ENXIO; 553 } 554 555 for (i = 0; porttab [i] != 0; i++) { 556 if (porttab [i] == iobase) { 557 porttab [i] = -1; 558 break; 559 } 560 } 561 562 if (porttab [i] == 0) { 563 return ENXIO; 564 } 565 566 if (!cx_probe_board (iobase, -1, -1)) { 567 printf ("cx%d: probing for Sigma at %lx faild\n", unit, iobase); 568 return ENXIO; 569 } 570 571 return 0; 572} 573 574/* 575 * The adapter is present, initialize the driver structures. 576 */ 577static int cx_attach (device_t dev) 578{ 579 bdrv_t *bd = device_get_softc (dev); 580 u_long iobase, drq, irq, rescount; 581 int unit = device_get_unit (dev); 582 cx_board_t *b; 583 cx_chan_t *c; 584 drv_t *d; 585 int i; 586 int s; 587 588 KASSERT ((bd != NULL), ("cx%d: NULL device softc\n", unit)); 589 590 bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount); 591 bd->base_rid = 0; 592 bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid, 593 iobase, iobase + NPORT, NPORT, RF_ACTIVE); 594 if (! bd->base_res) { 595 printf ("cx%d: cannot allocate base address\n", unit); 596 return ENXIO; 597 } 598 599 if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) { 600 for (i = 0; (drq = dmatab [i]) != 0; i++) { 601 if (!cx_is_free_res (dev, 1, SYS_RES_DRQ, 602 drq, drq + 1, 1)) 603 continue; 604 bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1); 605 break; 606 } 607 608 if (dmatab[i] == 0) { 609 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 610 bd->base_res); 611 printf ("cx%d: Couldn't get DRQ\n", unit); 612 return ENXIO; 613 } 614 } 615 616 bd->drq_rid = 0; 617 bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid, 618 drq, drq + 1, 1, RF_ACTIVE); 619 if (! bd->drq_res) { 620 printf ("cx%d: cannot allocate drq\n", unit); 621 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 622 bd->base_res); 623 return ENXIO; 624 } 625 626 if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) { 627 for (i = 0; (irq = irqtab [i]) != 0; i++) { 628 if (!cx_is_free_res (dev, 1, SYS_RES_IRQ, 629 irq, irq + 1, 1)) 630 continue; 631 bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1); 632 break; 633 } 634 635 if (irqtab[i] == 0) { 636 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 637 bd->drq_res); 638 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 639 bd->base_res); 640 printf ("cx%d: Couldn't get IRQ\n", unit); 641 return ENXIO; 642 } 643 } 644 645 bd->irq_rid = 0; 646 bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid, 647 irq, irq + 1, 1, RF_ACTIVE); 648 if (! bd->irq_res) { 649 printf ("cx%d: Couldn't allocate irq\n", unit); 650 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 651 bd->drq_res); 652 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 653 bd->base_res); 654 return ENXIO; 655 } 656 657 b = malloc (sizeof (cx_board_t), M_DEVBUF, M_WAITOK); 658 if (!b) { 659 printf ("cx:%d: Couldn't allocate memory\n", unit); 660 return (ENXIO); 661 } 662 adapter[unit] = b; 663 bzero (b, sizeof(cx_board_t)); 664 665 if (! cx_open_board (b, unit, iobase, irq, drq)) { 666 printf ("cx%d: error loading firmware\n", unit); 667 free (b, M_DEVBUF); 668 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 669 bd->irq_res); 670 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 671 bd->drq_res); 672 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 673 bd->base_res); 674 return ENXIO; 675 } 676 677 bd->board = b; 678 679 if (! probe_irq (b, irq)) { 680 printf ("cx%d: irq %ld not functional\n", unit, irq); 681 bd->board = 0; 682 adapter [unit] = 0; 683 free (b, M_DEVBUF); 684 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 685 bd->irq_res); 686 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 687 bd->drq_res); 688 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 689 bd->base_res); 690 return ENXIO; 691 } 692 693 s = splhigh (); 694 if (bus_setup_intr (dev, bd->irq_res, INTR_TYPE_NET, cx_intr, bd, 695 &bd->intrhand)) { 696 printf ("cx%d: Can't setup irq %ld\n", unit, irq); 697 bd->board = 0; 698 adapter [unit] = 0; 699 free (b, M_DEVBUF); 700 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, 701 bd->irq_res); 702 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, 703 bd->drq_res); 704 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, 705 bd->base_res); 706 splx (s); 707 return ENXIO; 708 } 709 710 cx_init (b, b->num, b->port, irq, drq); 711 cx_setup_board (b, 0, 0, 0); 712 713 printf ("cx%d: <Cronyx-Sigma-%s>\n", b->num, b->name); 714 715 for (c=b->chan; c<b->chan+NCHAN; ++c) { 716 char *dnmt="tty %x"; 717 char *dnmc="cua %x"; 718 if (c->type == T_NONE) 719 continue; 720 d = contigmalloc (sizeof(drv_t), M_DEVBUF, M_WAITOK, 721 0x100000, 0x1000000, 16, 0); 722 channel [b->num*NCHAN + c->num] = d; 723 bzero (d, sizeof(drv_t)); 724 sprintf (d->name, "cx%d.%d", b->num, c->num); 725 d->board = b; 726 d->chan = c; 727 d->dtrwait = 3 * hz; /* Default DTR off timeout is 3 seconds. */ 728 d->open_dev = 0; 729 c->sys = d; 730 731 switch (c->type) { 732 case T_SYNC_RS232: 733 case T_SYNC_V35: 734 case T_SYNC_RS449: 735 case T_UNIV: 736 case T_UNIV_RS232: 737 case T_UNIV_RS449: 738 case T_UNIV_V35: 739#ifdef NETGRAPH 740 if (ng_make_node_common (&typestruct, &d->node) != 0) { 741 printf ("%s: cannot make common node\n", d->name); 742 channel [b->num*NCHAN + c->num] = 0; 743 c->sys = 0; 744 contigfree (d, sizeof (*d), M_DEVBUF); 745 continue; 746 } 747#if __FreeBSD_version >= 500000 748 NG_NODE_SET_PRIVATE (d->node, d); 749#else 750 d->node->private = d; 751#endif 752 sprintf (d->nodename, "%s%d", NG_CX_NODE_TYPE, 753 c->board->num*NCHAN + c->num); 754 if (ng_name_node (d->node, d->nodename)) { 755 printf ("%s: cannot name node\n", d->nodename); 756#if __FreeBSD_version >= 500000 757 NG_NODE_UNREF (d->node); 758#else 759 ng_rmnode (d->node); 760 ng_unref (d->node); 761#endif 762 channel [b->num*NCHAN + c->num] = 0; 763 c->sys = 0; 764 contigfree (d, sizeof (*d), M_DEVBUF); 765 continue; 766 } 767 d->lo_queue.ifq_maxlen = IFQ_MAXLEN; 768 d->hi_queue.ifq_maxlen = IFQ_MAXLEN; 769#if __FreeBSD_version >= 500000 770 mtx_init (&d->lo_queue.ifq_mtx, "cx_queue_lo", NULL, MTX_DEF); 771 mtx_init (&d->hi_queue.ifq_mtx, "cx_queue_hi", NULL, MTX_DEF); 772#endif 773#else /*NETGRAPH*/ 774 d->pp.pp_if.if_softc = d; 775#if __FreeBSD_version > 501000 776 if_initname (&d->pp.pp_if, "cx", b->num * NCHAN + c->num); 777#else 778 d->pp.pp_if.if_unit = b->num * NCHAN + c->num; 779 d->pp.pp_if.if_name = "cx"; 780#endif 781 d->pp.pp_if.if_mtu = PP_MTU; 782 d->pp.pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 783 d->pp.pp_if.if_ioctl = cx_sioctl; 784 d->pp.pp_if.if_start = cx_ifstart; 785 d->pp.pp_if.if_watchdog = cx_ifwatchdog; 786 d->pp.pp_if.if_init = cx_initialize; 787 sppp_attach (&d->pp.pp_if); 788 if_attach (&d->pp.pp_if); 789 d->pp.pp_tlf = cx_tlf; 790 d->pp.pp_tls = cx_tls; 791 /* If BPF is in the kernel, call the attach for it. 792 * Size of PPP header is 4 bytes. */ 793 bpfattach (&d->pp.pp_if, DLT_PPP, 4); 794#endif /*NETGRAPH*/ 795 } 796 cx_start_chan (c, &d->buf, vtophys (&d->buf)); 797 cx_register_receive (c, &cx_receive); 798 cx_register_transmit (c, &cx_transmit); 799 cx_register_error (c, &cx_error); 800 cx_register_modem (c, &cx_modem); 801 dnmt[3] = 'x'+b->num; 802 dnmc[3] = 'x'+b->num; 803 d->devt[0] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num, UID_ROOT, GID_WHEEL, 0644, dnmt, b->num*NCHAN + c->num); 804 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); 805 d->devt[2] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 128, UID_ROOT, GID_WHEEL, 0660, dnmc, b->num*NCHAN + c->num); 806 } 807 splx (s); 808 809 return 0; 810} 811 812static int cx_detach (device_t dev) 813{ 814 bdrv_t *bd = device_get_softc (dev); 815 cx_board_t *b = bd->board; 816 cx_chan_t *c; 817 int s = splhigh (); 818 819 /* Check if the device is busy (open). */ 820 for (c = b->chan; c < b->chan + NCHAN; ++c) { 821 drv_t *d = (drv_t*) c->sys; 822 823 if (!d || d->chan->type == T_NONE) 824 continue; 825 if (d->lock) { 826 splx (s); 827 return EBUSY; 828 } 829 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 830 (d->open_dev|0x2)) { 831 splx (s); 832 return EBUSY; 833 } 834 if (d->running) { 835 splx (s); 836 return EBUSY; 837 } 838 } 839 840 /* Deactivate the timeout routine. And soft interrupt*/ 841 if (led_timo[b->num].callout) 842 untimeout (cx_led_off, b, led_timo[b->num]); 843 844 for (c = b->chan; c < b->chan + NCHAN; ++c) { 845 drv_t *d = c->sys; 846 847 if (!d || d->chan->type == T_NONE) 848 continue; 849 850 if (d->dtr_timeout_handle.callout) 851 untimeout (cx_dtrwakeup, d, d->dtr_timeout_handle); 852 if (d->dcd_timeout_handle.callout) 853 untimeout (cx_carrier, c, d->dcd_timeout_handle); 854 } 855 bus_teardown_intr (dev, bd->irq_res, bd->intrhand); 856 bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); 857 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); 858 859 bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); 860 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); 861 862 bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res); 863 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res); 864 865 cx_close_board (b); 866 867 /* Detach the interfaces, free buffer memory. */ 868 for (c = b->chan; c < b->chan + NCHAN; ++c) { 869 drv_t *d = (drv_t*) c->sys; 870 871 if (!d || d->chan->type == T_NONE) 872 continue; 873 874#if __FreeBSD_version >= 502113 875 if (d->tty) { 876 ttyrel (d->tty); 877 d->tty = NULL; 878 } 879#endif 880 881#ifdef NETGRAPH 882#if __FreeBSD_version >= 500000 883 if (d->node) { 884 ng_rmnode_self (d->node); 885 NG_NODE_UNREF (d->node); 886 d->node = NULL; 887 } 888 mtx_destroy (&d->lo_queue.ifq_mtx); 889 mtx_destroy (&d->hi_queue.ifq_mtx); 890#else 891 ng_rmnode (d->node); 892 d->node = NULL; 893#endif 894#else 895#if __FreeBSD_version >= 410000 && NBPFILTER > 0 896 /* Detach from the packet filter list of interfaces. */ 897 bpfdetach (&d->pp.pp_if); 898#endif 899 /* Detach from the sync PPP list. */ 900 sppp_detach (&d->pp.pp_if); 901 902 if_detach (&d->pp.pp_if); 903#endif 904 destroy_dev (d->devt[0]); 905 destroy_dev (d->devt[1]); 906 destroy_dev (d->devt[2]); 907 } 908 909 cx_led_off (b); 910 if (led_timo[b->num].callout) 911 untimeout (cx_led_off, b, led_timo[b->num]); 912 splx (s); 913 914 s = splhigh (); 915 for (c = b->chan; c < b->chan + NCHAN; ++c) { 916 drv_t *d = (drv_t*) c->sys; 917 918 if (!d || d->chan->type == T_NONE) 919 continue; 920 921 /* Deallocate buffers. */ 922 contigfree (d, sizeof (*d), M_DEVBUF); 923 } 924 bd->board = 0; 925 adapter [b->num] = 0; 926 free (b, M_DEVBUF); 927 splx (s); 928 929 return 0; 930} 931 932#ifndef NETGRAPH 933static void cx_ifstart (struct ifnet *ifp) 934{ 935 drv_t *d = ifp->if_softc; 936 937 cx_start (d); 938} 939 940static void cx_ifwatchdog (struct ifnet *ifp) 941{ 942 drv_t *d = ifp->if_softc; 943 944 cx_watchdog (d); 945} 946 947static void cx_tlf (struct sppp *sp) 948{ 949 drv_t *d = sp->pp_if.if_softc; 950 951 CX_DEBUG (d, ("cx_tlf\n")); 952/* cx_set_dtr (d->chan, 0);*/ 953/* cx_set_rts (d->chan, 0);*/ 954 sp->pp_down (sp); 955} 956 957static void cx_tls (struct sppp *sp) 958{ 959 drv_t *d = sp->pp_if.if_softc; 960 961 CX_DEBUG (d, ("cx_tls\n")); 962 sp->pp_up (sp); 963} 964 965/* 966 * Initialization of interface. 967 * It seems to be never called by upper level. 968 */ 969static void cx_initialize (void *softc) 970{ 971 drv_t *d = softc; 972 973 CX_DEBUG (d, ("cx_initialize\n")); 974} 975 976/* 977 * Process an ioctl request. 978 */ 979static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 980{ 981 drv_t *d = ifp->if_softc; 982 int error, s, was_up, should_be_up; 983 984 /* No socket ioctls while the channel is in async mode. */ 985 if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC) 986 return EBUSY; 987 988 /* Socket ioctls on slave subchannels are not allowed. */ 989 was_up = (ifp->if_flags & IFF_RUNNING) != 0; 990 error = sppp_ioctl (ifp, cmd, data); 991 if (error) 992 return error; 993 994 if (! (ifp->if_flags & IFF_DEBUG)) 995 d->chan->debug = 0; 996 else if (! d->chan->debug) 997 d->chan->debug = 1; 998 999 switch (cmd) { 1000 default: CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; 1001 case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n")); return 0; 1002 case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n")); return 0; 1003 case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n")); break; 1004 case SIOCSIFADDR: CX_DEBUG2 (d, ("SIOCSIFADDR\n")); break; 1005 } 1006 1007 /* We get here only in case of SIFFLAGS or SIFADDR. */ 1008 s = splhigh (); 1009 should_be_up = (ifp->if_flags & IFF_RUNNING) != 0; 1010 if (!was_up && should_be_up) { 1011 /* Interface goes up -- start it. */ 1012 cx_up (d); 1013 cx_start (d); 1014 } else if (was_up && !should_be_up) { 1015 /* Interface is going down -- stop it. */ 1016 /* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ 1017 cx_down (d); 1018 } 1019 splx (s); 1020 return 0; 1021} 1022#endif /*NETGRAPH*/ 1023 1024/* 1025 * Stop the interface. Called on splimp(). 1026 */ 1027static void cx_down (drv_t *d) 1028{ 1029 int s = splhigh (); 1030 CX_DEBUG (d, ("cx_down\n")); 1031 cx_set_dtr (d->chan, 0); 1032 cx_set_rts (d->chan, 0); 1033 d->running = 0; 1034 splx (s); 1035} 1036 1037/* 1038 * Start the interface. Called on splimp(). 1039 */ 1040static void cx_up (drv_t *d) 1041{ 1042 int s = splhigh (); 1043 CX_DEBUG (d, ("cx_up\n")); 1044 cx_set_dtr (d->chan, 1); 1045 cx_set_rts (d->chan, 1); 1046 d->running = 1; 1047 splx (s); 1048} 1049 1050/* 1051 * Start output on the (slave) interface. Get another datagram to send 1052 * off of the interface queue, and copy it to the interface 1053 * before starting the output. 1054 */ 1055static void cx_send (drv_t *d) 1056{ 1057 struct mbuf *m; 1058 u_short len; 1059 1060 CX_DEBUG2 (d, ("cx_send\n")); 1061 1062 /* No output if the interface is down. */ 1063 if (! d->running) 1064 return; 1065 1066 /* No output if the modem is off. */ 1067 if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan)) 1068 return; 1069 1070 if (cx_buf_free (d->chan)) { 1071 /* Get the packet to send. */ 1072#ifdef NETGRAPH 1073 IF_DEQUEUE (&d->hi_queue, m); 1074 if (! m) 1075 IF_DEQUEUE (&d->lo_queue, m); 1076#else 1077 m = sppp_dequeue (&d->pp.pp_if); 1078#endif 1079 if (! m) 1080 return; 1081#ifndef NETGRAPH 1082 if (d->pp.pp_if.if_bpf) 1083#if __FreeBSD_version >= 500000 1084 BPF_MTAP (&d->pp.pp_if, m); 1085#else 1086 bpf_mtap (&d->pp.pp_if, m); 1087#endif 1088#endif 1089 len = m->m_pkthdr.len; 1090 if (! m->m_next) 1091 cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t), 1092 len, 0); 1093 else { 1094 u_char buf [DMABUFSZ]; 1095 m_copydata (m, 0, len, buf); 1096 cx_send_packet (d->chan, buf, len, 0); 1097 } 1098 m_freem (m); 1099 1100 /* Set up transmit timeout, 10 seconds. */ 1101#ifdef NETGRAPH 1102 d->timeout = 10; 1103#else 1104 d->pp.pp_if.if_timer = 10; 1105#endif 1106 } 1107#ifndef NETGRAPH 1108 d->pp.pp_if.if_flags |= IFF_OACTIVE; 1109#endif 1110} 1111 1112/* 1113 * Start output on the interface. 1114 * Always called on splimp(). 1115 */ 1116static void cx_start (drv_t *d) 1117{ 1118 int s = splhigh (); 1119 if (d->running) { 1120 if (! d->chan->dtr) 1121 cx_set_dtr (d->chan, 1); 1122 if (! d->chan->rts) 1123 cx_set_rts (d->chan, 1); 1124 cx_send (d); 1125 } 1126 splx (s); 1127} 1128 1129/* 1130 * Handle transmit timeouts. 1131 * Recover after lost transmit interrupts. 1132 * Always called on splimp(). 1133 */ 1134static void cx_watchdog (drv_t *d) 1135{ 1136 int s = splhigh (); 1137 CX_DEBUG (d, ("device timeout\n")); 1138 if (d->running) { 1139 cx_setup_chan (d->chan); 1140 cx_start_chan (d->chan, 0, 0); 1141 cx_set_dtr (d->chan, 1); 1142 cx_set_rts (d->chan, 1); 1143 cx_start (d); 1144 } 1145 splx (s); 1146} 1147 1148/* 1149 * Transmit callback function. 1150 */ 1151static void cx_transmit (cx_chan_t *c, void *attachment, int len) 1152{ 1153 drv_t *d = c->sys; 1154 1155 if (!d) 1156 return; 1157 1158 if (c->mode == M_ASYNC && d->tty) { 1159 d->tty->t_state &= ~(TS_BUSY | TS_FLUSH); 1160 d->atimeout = 0; 1161 if (d->tty->t_dev) { 1162 d->intr_action |= CX_WRITE; 1163 MY_SOFT_INTR = 1; 1164#if __FreeBSD_version >= 500000 1165 swi_sched (cx_fast_ih, 0); 1166#else 1167 setsofttty (); 1168#endif 1169 } 1170 return; 1171 } 1172#ifdef NETGRAPH 1173 d->timeout = 0; 1174#else 1175 ++d->pp.pp_if.if_opackets; 1176 d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 1177 d->pp.pp_if.if_timer = 0; 1178#endif 1179 cx_start (d); 1180} 1181 1182/* 1183 * Process the received packet. 1184 */ 1185static void cx_receive (cx_chan_t *c, char *data, int len) 1186{ 1187 drv_t *d = c->sys; 1188 struct mbuf *m; 1189 char *cc = data; 1190#if __FreeBSD_version >= 500000 && defined NETGRAPH 1191 int error; 1192#endif 1193 1194 if (!d) 1195 return; 1196 1197 if (c->mode == M_ASYNC && d->tty) { 1198 if (d->tty->t_state & TS_ISOPEN) { 1199 async_q *q = &d->aqueue; 1200 int size = BF_SZ - 1 - AQ_GSZ (q); 1201 1202 if (len <= 0 && !size) 1203 return; 1204 1205 if (len > size) { 1206 c->ierrs++; 1207 cx_error (c, CX_OVERRUN); 1208 len = size - 1; 1209 } 1210 1211 while (len--) { 1212 AQ_PUSH (q, *(unsigned char *)cc); 1213 cc++; 1214 } 1215 1216 d->intr_action |= CX_READ; 1217 MY_SOFT_INTR = 1; 1218#if __FreeBSD_version >= 500000 1219 swi_sched (cx_fast_ih, 0); 1220#else 1221 setsofttty (); 1222#endif 1223 } 1224 return; 1225 } 1226 if (! d->running) 1227 return; 1228 1229 m = makembuf (data, len); 1230 if (! m) { 1231 CX_DEBUG (d, ("no memory for packet\n")); 1232#ifndef NETGRAPH 1233 ++d->pp.pp_if.if_iqdrops; 1234#endif 1235 return; 1236 } 1237 if (c->debug > 1) 1238 printmbuf (m); 1239#ifdef NETGRAPH 1240 m->m_pkthdr.rcvif = 0; 1241#if __FreeBSD_version >= 500000 1242 NG_SEND_DATA_ONLY (error, d->hook, m); 1243#else 1244 ng_queue_data (d->hook, m, 0); 1245#endif 1246#else 1247 ++d->pp.pp_if.if_ipackets; 1248 m->m_pkthdr.rcvif = &d->pp.pp_if; 1249 /* Check if there's a BPF listener on this interface. 1250 * If so, hand off the raw packet to bpf. */ 1251 if (d->pp.pp_if.if_bpf) 1252#if __FreeBSD_version >= 500000 1253 BPF_TAP (&d->pp.pp_if, data, len); 1254#else 1255 bpf_tap (&d->pp.pp_if, data, len); 1256#endif 1257 sppp_input (&d->pp.pp_if, m); 1258#endif 1259} 1260 1261#if __FreeBSD_version < 502113 1262#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ 1263 && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ 1264 && (!(tp->t_iflag & PARMRK)\ 1265 || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ 1266 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ 1267 && linesw[tp->t_line].l_rint == ttyinput) 1268#else 1269#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ 1270 && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ 1271 && (!(tp->t_iflag & PARMRK)\ 1272 || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ 1273 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ 1274 && linesw[tp->t_line]->l_rint == ttyinput) 1275#endif 1276 1277/* 1278 * Error callback function. 1279 */ 1280static void cx_error (cx_chan_t *c, int data) 1281{ 1282 drv_t *d = c->sys; 1283 async_q *q; 1284 1285 if (!d) 1286 return; 1287 1288 q = &(d->aqueue); 1289 1290 switch (data) { 1291 case CX_FRAME: 1292 CX_DEBUG (d, ("frame error\n")); 1293 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1294 && (AQ_GSZ (q) < BF_SZ - 1) 1295 && (!CONDITION((&d->tty->t_termios), (d->tty)) 1296 || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { 1297 AQ_PUSH (q, TTY_FE); 1298 d->intr_action |= CX_READ; 1299 MY_SOFT_INTR = 1; 1300#if __FreeBSD_version >= 500000 1301 swi_sched (cx_fast_ih, 0); 1302#else 1303 setsofttty (); 1304#endif 1305 } 1306#ifndef NETGRAPH 1307 else 1308 ++d->pp.pp_if.if_ierrors; 1309#endif 1310 break; 1311 case CX_CRC: 1312 CX_DEBUG (d, ("crc error\n")); 1313 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1314 && (AQ_GSZ (q) < BF_SZ - 1) 1315 && (!CONDITION((&d->tty->t_termios), (d->tty)) 1316 || !(d->tty->t_iflag & INPCK) 1317 || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { 1318 AQ_PUSH (q, TTY_PE); 1319 d->intr_action |= CX_READ; 1320 MY_SOFT_INTR = 1; 1321#if __FreeBSD_version >= 500000 1322 swi_sched (cx_fast_ih, 0); 1323#else 1324 setsofttty (); 1325#endif 1326 } 1327#ifndef NETGRAPH 1328 else 1329 ++d->pp.pp_if.if_ierrors; 1330#endif 1331 break; 1332 case CX_OVERRUN: 1333 CX_DEBUG (d, ("overrun error\n")); 1334#ifdef TTY_OE 1335 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1336 && (AQ_GSZ (q) < BF_SZ - 1) 1337 && (!CONDITION((&d->tty->t_termios), (d->tty)))) { 1338 AQ_PUSH (q, TTY_OE); 1339 d->intr_action |= CX_READ; 1340 MY_SOFT_INTR = 1; 1341#if __FreeBSD_version >= 500000 1342 swi_sched (cx_fast_ih, 0); 1343#else 1344 setsofttty (); 1345#endif 1346 } 1347#endif 1348#ifndef NETGRAPH 1349 else { 1350 ++d->pp.pp_if.if_collisions; 1351 ++d->pp.pp_if.if_ierrors; 1352 } 1353#endif 1354 break; 1355 case CX_OVERFLOW: 1356 CX_DEBUG (d, ("overflow error\n")); 1357#ifndef NETGRAPH 1358 if (c->mode != M_ASYNC) 1359 ++d->pp.pp_if.if_ierrors; 1360#endif 1361 break; 1362 case CX_UNDERRUN: 1363 CX_DEBUG (d, ("underrun error\n")); 1364 if (c->mode != M_ASYNC) { 1365#ifdef NETGRAPH 1366 d->timeout = 0; 1367#else 1368 ++d->pp.pp_if.if_oerrors; 1369 d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 1370 d->pp.pp_if.if_timer = 0; 1371 cx_start (d); 1372#endif 1373 } 1374 break; 1375 case CX_BREAK: 1376 CX_DEBUG (d, ("break error\n")); 1377 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1378 && (AQ_GSZ (q) < BF_SZ - 1) 1379 && (!CONDITION((&d->tty->t_termios), (d->tty)) 1380 || !(d->tty->t_iflag & (IGNBRK | BRKINT | PARMRK)))) { 1381 AQ_PUSH (q, TTY_BI); 1382 d->intr_action |= CX_READ; 1383 MY_SOFT_INTR = 1; 1384#if __FreeBSD_version >= 500000 1385 swi_sched (cx_fast_ih, 0); 1386#else 1387 setsofttty (); 1388#endif 1389 } 1390#ifndef NETGRAPH 1391 else 1392 ++d->pp.pp_if.if_ierrors; 1393#endif 1394 break; 1395 default: 1396 CX_DEBUG (d, ("error #%d\n", data)); 1397 } 1398} 1399 1400#if __FreeBSD_version < 500000 1401static int cx_open (dev_t dev, int flag, int mode, struct proc *p) 1402#else 1403static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td) 1404#endif 1405{ 1406 int unit = UNIT (dev); 1407 drv_t *d; 1408 int error; 1409 1410 if (unit >= NCX*NCHAN || ! (d = channel[unit])) 1411 return ENXIO; 1412 CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n", 1413 unit, flag, mode)); 1414 1415 if (d->chan->mode != M_ASYNC || IF_CUNIT(dev)) { 1416 d->open_dev |= 0x1; 1417 return 0; 1418 } 1419 if (!d->tty) { 1420 d->tty = ttymalloc (d->tty); 1421 d->tty->t_oproc = cx_oproc; 1422 d->tty->t_param = cx_param; 1423 d->tty->t_stop = cx_stop; 1424 } 1425 dev->si_tty = d->tty; 1426 d->tty->t_dev = dev; 1427again: 1428 if (d->dtroff) { 1429 error = tsleep (&d->dtrwait, TTIPRI | PCATCH, "cxdtr", 0); 1430 if (error) 1431 return error; 1432 goto again; 1433 } 1434 1435 if ((d->tty->t_state & TS_ISOPEN) && (d->tty->t_state & TS_XCLUDE) && 1436#if __FreeBSD_version >= 500000 1437 suser (td)) 1438#else 1439 p->p_ucred->cr_uid != 0) 1440#endif 1441 return EBUSY; 1442 1443 if (d->tty->t_state & TS_ISOPEN) { 1444 /* 1445 * Cannot open /dev/cua if /dev/tty already opened. 1446 */ 1447 if (CALLOUT (dev) && ! d->callout) 1448 return EBUSY; 1449 1450 /* 1451 * Opening /dev/tty when /dev/cua is already opened. 1452 * Wait for close, then try again. 1453 */ 1454 if (! CALLOUT (dev) && d->callout) { 1455 if (flag & O_NONBLOCK) 1456 return EBUSY; 1457 error = tsleep (d, TTIPRI | PCATCH, "cxbi", 0); 1458 if (error) 1459 return error; 1460 goto again; 1461 } 1462 } else if (d->lock && ! CALLOUT (dev) && (flag & O_NONBLOCK)) 1463 /* 1464 * We try to open /dev/tty in non-blocking mode 1465 * while somebody is already waiting for carrier on it. 1466 */ 1467 return EBUSY; 1468 else { 1469 ttychars (d->tty); 1470 if (d->tty->t_ispeed == 0) { 1471 d->tty->t_iflag = 0; 1472 d->tty->t_oflag = 0; 1473 d->tty->t_lflag = 0; 1474 d->tty->t_cflag = CREAD | CS8 | HUPCL; 1475 d->tty->t_ispeed = d->chan->rxbaud; 1476 d->tty->t_ospeed = d->chan->txbaud; 1477 } 1478 if (CALLOUT (dev)) 1479 d->tty->t_cflag |= CLOCAL; 1480 else 1481 d->tty->t_cflag &= ~CLOCAL; 1482 cx_param (d->tty, &d->tty->t_termios); 1483 ttsetwater (d->tty); 1484 } 1485 1486 splhigh (); 1487 if (! (d->tty->t_state & TS_ISOPEN)) { 1488 cx_start_chan (d->chan, 0, 0); 1489 cx_set_dtr (d->chan, 1); 1490 cx_set_rts (d->chan, 1); 1491 d->cd = cx_get_cd (d->chan); 1492 if (CALLOUT (dev) || cx_get_cd (d->chan)) 1493 ttyld_modem(d->tty, 1); 1494 } 1495 1496 if (! (flag & O_NONBLOCK) && ! (d->tty->t_cflag & CLOCAL) && 1497 ! (d->tty->t_state & TS_CARR_ON)) { 1498 /* Lock the channel against cxconfig while we are 1499 * waiting for carrier. */ 1500 d->lock++; 1501 error = tsleep (&d->tty->t_rawq, TTIPRI | PCATCH, "cxdcd", 0); 1502 /* Unlock the channel. */ 1503 d->lock--; 1504 spl0 (); 1505 if (error) 1506 goto failed; 1507 goto again; 1508 } 1509 1510 error = ttyld_open (d->tty, dev); 1511 ttyldoptim (d->tty); 1512 spl0 (); 1513 if (error) { 1514failed: if (! (d->tty->t_state & TS_ISOPEN)) { 1515 splhigh (); 1516 cx_set_dtr (d->chan, 0); 1517 cx_set_rts (d->chan, 0); 1518 if (d->dtrwait) { 1519 d->dtr_timeout_handle = 1520 timeout (cx_dtrwakeup, d, d->dtrwait); 1521 d->dtroff = 1; 1522 } 1523 spl0 (); 1524 } 1525 return error; 1526 } 1527 1528 if (d->tty->t_state & TS_ISOPEN) 1529 d->callout = CALLOUT (dev) ? 1 : 0; 1530 1531 d->open_dev |= 0x2; 1532 CX_DEBUG2 (d, ("cx_open done\n")); 1533 return 0; 1534} 1535 1536#if __FreeBSD_version < 500000 1537static int cx_close (dev_t dev, int flag, int mode, struct proc *p) 1538#else 1539static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td) 1540#endif 1541{ 1542 drv_t *d = channel [UNIT (dev)]; 1543 int s; 1544 1545 CX_DEBUG2 (d, ("cx_close\n")); 1546 if ((!(d->open_dev&0x2)) || IF_CUNIT(dev)){ 1547 d->open_dev &= ~0x1; 1548 return 0; 1549 } 1550 s = splhigh (); 1551 ttyld_close(d->tty, flag); 1552 ttyldoptim (d->tty); 1553 1554 /* Disable receiver. 1555 * Transmitter continues sending the queued data. */ 1556 cx_enable_receive (d->chan, 0); 1557 1558 /* Clear DTR and RTS. */ 1559 if ((d->tty->t_cflag & HUPCL) || ! (d->tty->t_state & TS_ISOPEN)) { 1560 cx_set_dtr (d->chan, 0); 1561 cx_set_rts (d->chan, 0); 1562 if (d->dtrwait) { 1563 d->dtr_timeout_handle = 1564 timeout (cx_dtrwakeup, d, d->dtrwait); 1565 d->dtroff = 1; 1566 } 1567 } 1568 ttyclose (d->tty); 1569 splx (s); 1570 d->callout = 0; 1571 1572 /* 1573 * Wake up bidirectional opens. 1574 * Since we may be opened twice we couldn't call ttyrel() here. 1575 * So just keep d->tty for future use. It would be freed by 1576 * ttyrel() at cx_detach(). 1577 */ 1578 1579 wakeup (d); 1580 d->open_dev &= ~0x2; 1581 1582 return 0; 1583} 1584 1585static int cx_read (struct cdev *dev, struct uio *uio, int flag) 1586{ 1587 drv_t *d = channel [UNIT (dev)]; 1588 1589 if (d) CX_DEBUG2 (d, ("cx_read\n")); 1590 if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev) || !d->tty) 1591 return EBADF; 1592 1593 return ttyld_read (d->tty, uio, flag); 1594} 1595 1596static int cx_write (struct cdev *dev, struct uio *uio, int flag) 1597{ 1598 drv_t *d = channel [UNIT (dev)]; 1599 1600 if (d) CX_DEBUG2 (d, ("cx_write\n")); 1601 if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev) || !d->tty) 1602 return EBADF; 1603 1604 return ttyld_write (d->tty, uio, flag); 1605} 1606 1607static int cx_modem_status (drv_t *d) 1608{ 1609 int status = 0, s = splhigh (); 1610 /* Already opened by someone or network interface is up? */ 1611 if ((d->chan->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 1612 (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running)) 1613 status = TIOCM_LE; /* always enabled while open */ 1614 1615 if (cx_get_dsr (d->chan)) status |= TIOCM_DSR; 1616 if (cx_get_cd (d->chan)) status |= TIOCM_CD; 1617 if (cx_get_cts (d->chan)) status |= TIOCM_CTS; 1618 if (d->chan->dtr) status |= TIOCM_DTR; 1619 if (d->chan->rts) status |= TIOCM_RTS; 1620 splx (s); 1621 return status; 1622} 1623 1624#if __FreeBSD_version < 500000 1625static int cx_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1626#else 1627static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1628#endif 1629{ 1630 drv_t *d = channel [UNIT (dev)]; 1631 cx_chan_t *c; 1632 struct serial_statistics *st; 1633 int error, s; 1634 char mask[16]; 1635 1636 if (!d || !(c = d->chan)) 1637 return EINVAL; 1638 1639 switch (cmd) { 1640 case SERIAL_GETREGISTERED: 1641 CX_DEBUG2 (d, ("ioctl: getregistered\n")); 1642 bzero (mask, sizeof(mask)); 1643 for (s=0; s<NCX*NCHAN; ++s) 1644 if (channel [s]) 1645 mask [s/8] |= 1 << (s & 7); 1646 bcopy (mask, data, sizeof (mask)); 1647 return 0; 1648 1649 case SERIAL_GETPORT: 1650 CX_DEBUG2 (d, ("ioctl: getport\n")); 1651 s = splhigh (); 1652 *(int *)data = cx_get_port (c); 1653 splx (s); 1654 if (*(int *)data<0) 1655 return (EINVAL); 1656 else 1657 return 0; 1658 1659 case SERIAL_SETPORT: 1660 CX_DEBUG2 (d, ("ioctl: setproto\n")); 1661 /* Only for superuser! */ 1662#if __FreeBSD_version < 500000 1663 error = suser (p); 1664#else /* __FreeBSD_version >= 500000 */ 1665 error = suser (td); 1666#endif /* __FreeBSD_version >= 500000 */ 1667 if (error) 1668 return error; 1669 1670 s = splhigh (); 1671 cx_set_port (c, *(int *)data); 1672 splx (s); 1673 return 0; 1674 1675#ifndef NETGRAPH 1676 case SERIAL_GETPROTO: 1677 CX_DEBUG2 (d, ("ioctl: getproto\n")); 1678 s = splhigh (); 1679 strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" : 1680 (d->pp.pp_flags & PP_FR) ? "fr" : 1681 (d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp"); 1682 splx (s); 1683 return 0; 1684 1685 case SERIAL_SETPROTO: 1686 CX_DEBUG2 (d, ("ioctl: setproto\n")); 1687 /* Only for superuser! */ 1688#if __FreeBSD_version < 500000 1689 error = suser (p); 1690#else /* __FreeBSD_version >= 500000 */ 1691 error = suser (td); 1692#endif /* __FreeBSD_version >= 500000 */ 1693 if (error) 1694 return error; 1695 if (c->mode == M_ASYNC) 1696 return EBUSY; 1697 if (d->pp.pp_if.if_flags & IFF_RUNNING) 1698 return EBUSY; 1699 if (! strcmp ("cisco", (char*)data)) { 1700 d->pp.pp_flags &= ~(PP_FR); 1701 d->pp.pp_flags |= PP_KEEPALIVE; 1702 d->pp.pp_if.if_flags |= PP_CISCO; 1703 } else if (! strcmp ("fr", (char*)data)) { 1704 d->pp.pp_if.if_flags &= ~(PP_CISCO); 1705 d->pp.pp_flags |= PP_FR | PP_KEEPALIVE; 1706 } else if (! strcmp ("ppp", (char*)data)) { 1707 d->pp.pp_flags &= ~(PP_FR | PP_KEEPALIVE); 1708 d->pp.pp_if.if_flags &= ~(PP_CISCO); 1709 } else 1710 return EINVAL; 1711 return 0; 1712 1713 case SERIAL_GETKEEPALIVE: 1714 CX_DEBUG2 (d, ("ioctl: getkeepalive\n")); 1715 if ((d->pp.pp_flags & PP_FR) || 1716 (d->pp.pp_if.if_flags & PP_CISCO) || 1717 (c->mode == M_ASYNC)) 1718 return EINVAL; 1719 s = splhigh (); 1720 *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0; 1721 splx (s); 1722 return 0; 1723 1724 case SERIAL_SETKEEPALIVE: 1725 CX_DEBUG2 (d, ("ioctl: setkeepalive\n")); 1726 /* Only for superuser! */ 1727#if __FreeBSD_version < 500000 1728 error = suser (p); 1729#else /* __FreeBSD_version >= 500000 */ 1730 error = suser (td); 1731#endif /* __FreeBSD_version >= 500000 */ 1732 if (error) 1733 return error; 1734 if ((d->pp.pp_flags & PP_FR) || 1735 (d->pp.pp_if.if_flags & PP_CISCO)) 1736 return EINVAL; 1737 s = splhigh (); 1738 if (*(int*)data) 1739 d->pp.pp_flags |= PP_KEEPALIVE; 1740 else 1741 d->pp.pp_flags &= ~PP_KEEPALIVE; 1742 splx (s); 1743 return 0; 1744#endif /*NETGRAPH*/ 1745 1746 case SERIAL_GETMODE: 1747 CX_DEBUG2 (d, ("ioctl: getmode\n")); 1748 s = splhigh (); 1749 *(int*)data = (c->mode == M_ASYNC) ? 1750 SERIAL_ASYNC : SERIAL_HDLC; 1751 splx (s); 1752 return 0; 1753 1754 case SERIAL_SETMODE: 1755 CX_DEBUG2 (d, ("ioctl: setmode\n")); 1756 /* Only for superuser! */ 1757#if __FreeBSD_version < 500000 1758 error = suser (p); 1759#else /* __FreeBSD_version >= 500000 */ 1760 error = suser (td); 1761#endif /* __FreeBSD_version >= 500000 */ 1762 if (error) 1763 return error; 1764 1765 /* Somebody is waiting for carrier? */ 1766 if (d->lock) 1767 return EBUSY; 1768 /* /dev/ttyXX is already opened by someone? */ 1769 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 1770 (d->open_dev|0x2)) 1771 return EBUSY; 1772 /* Network interface is up? 1773 * Cannot change to async mode. */ 1774 if (c->mode != M_ASYNC && d->running && 1775 (*(int*)data == SERIAL_ASYNC)) 1776 return EBUSY; 1777 1778 s = splhigh (); 1779 if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) { 1780 cx_set_mode (c, M_ASYNC); 1781 cx_enable_receive (c, 0); 1782 cx_enable_transmit (c, 0); 1783 } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) { 1784 cx_set_mode (c, M_HDLC); 1785 cx_enable_receive (c, 1); 1786 cx_enable_transmit (c, 1); 1787 } 1788 splx (s); 1789 return 0; 1790 1791 case SERIAL_GETSTAT: 1792 CX_DEBUG2 (d, ("ioctl: getestat\n")); 1793 st = (struct serial_statistics*) data; 1794 s = splhigh (); 1795 st->rintr = c->rintr; 1796 st->tintr = c->tintr; 1797 st->mintr = c->mintr; 1798 st->ibytes = c->ibytes; 1799 st->ipkts = c->ipkts; 1800 st->ierrs = c->ierrs; 1801 st->obytes = c->obytes; 1802 st->opkts = c->opkts; 1803 st->oerrs = c->oerrs; 1804 splx (s); 1805 return 0; 1806 1807 case SERIAL_CLRSTAT: 1808 CX_DEBUG2 (d, ("ioctl: clrstat\n")); 1809 /* Only for superuser! */ 1810#if __FreeBSD_version < 500000 1811 error = suser (p); 1812#else /* __FreeBSD_version >= 500000 */ 1813 error = suser (td); 1814#endif /* __FreeBSD_version >= 500000 */ 1815 if (error) 1816 return error; 1817 s = splhigh (); 1818 c->rintr = 0; 1819 c->tintr = 0; 1820 c->mintr = 0; 1821 c->ibytes = 0; 1822 c->ipkts = 0; 1823 c->ierrs = 0; 1824 c->obytes = 0; 1825 c->opkts = 0; 1826 c->oerrs = 0; 1827 splx (s); 1828 return 0; 1829 1830 case SERIAL_GETBAUD: 1831 CX_DEBUG2 (d, ("ioctl: getbaud\n")); 1832 if (c->mode == M_ASYNC) 1833 return EINVAL; 1834 s = splhigh (); 1835 *(long*)data = cx_get_baud(c); 1836 splx (s); 1837 return 0; 1838 1839 case SERIAL_SETBAUD: 1840 CX_DEBUG2 (d, ("ioctl: setbaud\n")); 1841 /* Only for superuser! */ 1842#if __FreeBSD_version < 500000 1843 error = suser (p); 1844#else /* __FreeBSD_version >= 500000 */ 1845 error = suser (td); 1846#endif /* __FreeBSD_version >= 500000 */ 1847 if (error) 1848 return error; 1849 if (c->mode == M_ASYNC) 1850 return EINVAL; 1851 s = splhigh (); 1852 cx_set_baud (c, *(long*)data); 1853 splx (s); 1854 return 0; 1855 1856 case SERIAL_GETLOOP: 1857 CX_DEBUG2 (d, ("ioctl: getloop\n")); 1858 if (c->mode == M_ASYNC) 1859 return EINVAL; 1860 s = splhigh (); 1861 *(int*)data = cx_get_loop (c); 1862 splx (s); 1863 return 0; 1864 1865 case SERIAL_SETLOOP: 1866 CX_DEBUG2 (d, ("ioctl: setloop\n")); 1867 /* Only for superuser! */ 1868#if __FreeBSD_version < 500000 1869 error = suser (p); 1870#else /* __FreeBSD_version >= 500000 */ 1871 error = suser (td); 1872#endif /* __FreeBSD_version >= 500000 */ 1873 if (error) 1874 return error; 1875 if (c->mode == M_ASYNC) 1876 return EINVAL; 1877 s = splhigh (); 1878 cx_set_loop (c, *(int*)data); 1879 splx (s); 1880 return 0; 1881 1882 case SERIAL_GETDPLL: 1883 CX_DEBUG2 (d, ("ioctl: getdpll\n")); 1884 if (c->mode == M_ASYNC) 1885 return EINVAL; 1886 s = splhigh (); 1887 *(int*)data = cx_get_dpll (c); 1888 splx (s); 1889 return 0; 1890 1891 case SERIAL_SETDPLL: 1892 CX_DEBUG2 (d, ("ioctl: setdpll\n")); 1893 /* Only for superuser! */ 1894#if __FreeBSD_version < 500000 1895 error = suser (p); 1896#else /* __FreeBSD_version >= 500000 */ 1897 error = suser (td); 1898#endif /* __FreeBSD_version >= 500000 */ 1899 if (error) 1900 return error; 1901 if (c->mode == M_ASYNC) 1902 return EINVAL; 1903 s = splhigh (); 1904 cx_set_dpll (c, *(int*)data); 1905 splx (s); 1906 return 0; 1907 1908 case SERIAL_GETNRZI: 1909 CX_DEBUG2 (d, ("ioctl: getnrzi\n")); 1910 if (c->mode == M_ASYNC) 1911 return EINVAL; 1912 s = splhigh (); 1913 *(int*)data = cx_get_nrzi (c); 1914 splx (s); 1915 return 0; 1916 1917 case SERIAL_SETNRZI: 1918 CX_DEBUG2 (d, ("ioctl: setnrzi\n")); 1919 /* Only for superuser! */ 1920#if __FreeBSD_version < 500000 1921 error = suser (p); 1922#else /* __FreeBSD_version >= 500000 */ 1923 error = suser (td); 1924#endif /* __FreeBSD_version >= 500000 */ 1925 if (error) 1926 return error; 1927 if (c->mode == M_ASYNC) 1928 return EINVAL; 1929 s = splhigh (); 1930 cx_set_nrzi (c, *(int*)data); 1931 splx (s); 1932 return 0; 1933 1934 case SERIAL_GETDEBUG: 1935 CX_DEBUG2 (d, ("ioctl: getdebug\n")); 1936 s = splhigh (); 1937 *(int*)data = c->debug; 1938 splx (s); 1939 return 0; 1940 1941 case SERIAL_SETDEBUG: 1942 CX_DEBUG2 (d, ("ioctl: setdebug\n")); 1943 /* Only for superuser! */ 1944#if __FreeBSD_version < 500000 1945 error = suser (p); 1946#else /* __FreeBSD_version >= 500000 */ 1947 error = suser (td); 1948#endif /* __FreeBSD_version >= 500000 */ 1949 if (error) 1950 return error; 1951 s = splhigh (); 1952 c->debug = *(int*)data; 1953 splx (s); 1954#ifndef NETGRAPH 1955 if (d->chan->debug) 1956 d->pp.pp_if.if_flags |= IFF_DEBUG; 1957 else 1958 d->pp.pp_if.if_flags &= (~IFF_DEBUG); 1959#endif 1960 return 0; 1961 } 1962 1963 if (c->mode == M_ASYNC && !IF_CUNIT(dev) && d->tty) { 1964#if __FreeBSD_version >= 502113 1965 error = ttyioctl (dev, cmd, data, flag, td); 1966 ttyldoptim (d->tty); 1967 if (error != ENOTTY) { 1968 if (error) 1969 CX_DEBUG2 (d, ("ttioctl: 0x%lx, error %d\n", cmd, error)); 1970 return error; 1971 } 1972#else 1973#if __FreeBSD_version >= 500000 1974 error = (*linesw[d->tty->t_line].l_ioctl) (d->tty, cmd, data, flag, td); 1975#else 1976 error = (*linesw[d->tty->t_line].l_ioctl) (d->tty, cmd, data, flag, p); 1977#endif 1978 ttyldoptim (d->tty); 1979 if (error != ENOIOCTL) { 1980 if (error) 1981 CX_DEBUG2 (d, ("l_ioctl: 0x%lx, error %d\n", cmd, error)); 1982 return error; 1983 } 1984 error = ttioctl (d->tty, cmd, data, flag); 1985 ttyldoptim (d->tty); 1986 if (error != ENOIOCTL) { 1987 if (error) 1988 CX_DEBUG2 (d, ("ttioctl: 0x%lx, error %d\n", cmd, error)); 1989 return error; 1990 } 1991#endif 1992 } 1993 1994 switch (cmd) { 1995 case TIOCSBRK: /* Start sending line break */ 1996 CX_DEBUG2 (d, ("ioctl: tiocsbrk\n")); 1997 s = splhigh (); 1998 cx_send_break (c, 500); 1999 splx (s); 2000 return 0; 2001 2002 case TIOCCBRK: /* Stop sending line break */ 2003 CX_DEBUG2 (d, ("ioctl: tioccbrk\n")); 2004 return 0; 2005 2006 case TIOCSDTR: /* Set DTR */ 2007 CX_DEBUG2 (d, ("ioctl: tiocsdtr\n")); 2008 s = splhigh (); 2009 cx_set_dtr (c, 1); 2010 splx (s); 2011 return 0; 2012 2013 case TIOCCDTR: /* Clear DTR */ 2014 CX_DEBUG2 (d, ("ioctl: tioccdtr\n")); 2015 s = splhigh (); 2016 cx_set_dtr (c, 0); 2017 splx (s); 2018 return 0; 2019 2020 case TIOCMSET: /* Set DTR/RTS */ 2021 CX_DEBUG2 (d, ("ioctl: tiocmset\n")); 2022 s = splhigh (); 2023 cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); 2024 cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); 2025 splx (s); 2026 return 0; 2027 2028 case TIOCMBIS: /* Add DTR/RTS */ 2029 CX_DEBUG2 (d, ("ioctl: tiocmbis\n")); 2030 s = splhigh (); 2031 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1); 2032 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1); 2033 splx (s); 2034 return 0; 2035 2036 case TIOCMBIC: /* Clear DTR/RTS */ 2037 CX_DEBUG2 (d, ("ioctl: tiocmbic\n")); 2038 s = splhigh (); 2039 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0); 2040 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0); 2041 splx (s); 2042 return 0; 2043 2044 case TIOCMGET: /* Get modem status */ 2045 CX_DEBUG2 (d, ("ioctl: tiocmget\n")); 2046 *(int*)data = cx_modem_status (d); 2047 return 0; 2048 2049#ifdef TIOCMSDTRWAIT 2050 case TIOCMSDTRWAIT: 2051 CX_DEBUG2 (d, ("ioctl: tiocmsdtrwait\n")); 2052 /* Only for superuser! */ 2053#if __FreeBSD_version < 500000 2054 error = suser (p); 2055#else /* __FreeBSD_version >= 500000 */ 2056 error = suser (td); 2057#endif /* __FreeBSD_version >= 500000 */ 2058 if (error) 2059 return error; 2060 s = splhigh (); 2061 d->dtrwait = *(int*)data * hz / 100; 2062 splx (s); 2063 return 0; 2064#endif 2065 2066#ifdef TIOCMGDTRWAIT 2067 case TIOCMGDTRWAIT: 2068 CX_DEBUG2 (d, ("ioctl: tiocmgdtrwait\n")); 2069 s = splhigh (); 2070 *(int*)data = d->dtrwait * 100 / hz; 2071 splx (s); 2072 return 0; 2073#endif 2074 } 2075 CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd)); 2076 return ENOTTY; 2077} 2078 2079/* 2080 * Wake up opens() waiting for DTR ready. 2081 */ 2082static void cx_dtrwakeup (void *arg) 2083{ 2084 drv_t *d = arg; 2085 2086 d->dtroff = 0; 2087 wakeup (&d->dtrwait); 2088} 2089 2090 2091#if __FreeBSD_version < 502113 2092static void 2093ttyldoptim(tp) 2094 struct tty *tp; 2095{ 2096 struct termios *t; 2097 2098 t = &tp->t_termios; 2099 if (CONDITION(t,tp)) 2100 tp->t_state |= TS_CAN_BYPASS_L_RINT; 2101 else 2102 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2103} 2104#endif 2105 2106#if __FreeBSD_version >= 500000 2107void cx_softintr (void *unused) 2108#else 2109void cx_softintr () 2110#endif 2111{ 2112 drv_t *d; 2113 async_q *q; 2114 int i, s, ic, k; 2115 while (MY_SOFT_INTR) { 2116 MY_SOFT_INTR = 0; 2117 for (i=0; i<NCX*NCHAN; ++i) { 2118 d = channel [i]; 2119 if (!d || !d->chan || d->chan->type == T_NONE 2120 || d->chan->mode != M_ASYNC || !d->tty 2121 || !d->tty->t_dev) 2122 continue; 2123 s = splhigh (); 2124 if (d->intr_action & CX_READ) { 2125 q = &(d->aqueue); 2126 if (d->tty->t_state & TS_CAN_BYPASS_L_RINT) { 2127 k = AQ_GSZ(q); 2128 if (d->tty->t_rawq.c_cc + k > 2129 d->tty->t_ihiwat 2130 && (d->tty->t_cflag & CRTS_IFLOW 2131 || d->tty->t_iflag & IXOFF) 2132 && !(d->tty->t_state & TS_TBLOCK)) 2133 ttyblock(d->tty); 2134 d->tty->t_rawcc += k; 2135 while (k>0) { 2136 k--; 2137 AQ_POP (q, ic); 2138 splx (s); 2139 putc (ic, &d->tty->t_rawq); 2140 s = splhigh (); 2141 } 2142 ttwakeup(d->tty); 2143 if (d->tty->t_state & TS_TTSTOP 2144 && (d->tty->t_iflag & IXANY 2145 || d->tty->t_cc[VSTART] == 2146 d->tty->t_cc[VSTOP])) { 2147 d->tty->t_state &= ~TS_TTSTOP; 2148 d->tty->t_lflag &= ~FLUSHO; 2149 d->intr_action |= CX_WRITE; 2150 } 2151 } else { 2152 while (q->end != q->beg) { 2153 AQ_POP (q, ic); 2154 splx (s); 2155 ttyld_rint (d->tty, ic); 2156 s = splhigh (); 2157 } 2158 } 2159 d->intr_action &= ~CX_READ; 2160 } 2161 splx (s); 2162 2163 s = splhigh (); 2164 if (d->intr_action & CX_WRITE) { 2165 if (d->tty->t_line) 2166 ttyld_start (d->tty); 2167 else 2168 cx_oproc (d->tty); 2169 d->intr_action &= ~CX_WRITE; 2170 } 2171 splx (s); 2172 2173 } 2174 } 2175} 2176 2177/* 2178 * Fill transmitter buffer with data. 2179 */ 2180static void cx_oproc (struct tty *tp) 2181{ 2182 int s = splhigh (), k; 2183 drv_t *d = channel [UNIT (tp->t_dev)]; 2184 static u_char buf[DMABUFSZ]; 2185 u_char *p; 2186 u_short len = 0, sublen = 0; 2187 2188 if (!d) { 2189 splx (s); 2190 return; 2191 } 2192 2193 CX_DEBUG2 (d, ("cx_oproc\n")); 2194 if (tp->t_cflag & CRTSCTS && (tp->t_state & TS_TBLOCK) && d->chan->rts) 2195 cx_set_rts (d->chan, 0); 2196 else if (tp->t_cflag & CRTSCTS && ! (tp->t_state & TS_TBLOCK) && ! d->chan->rts) 2197 cx_set_rts (d->chan, 1); 2198 2199 if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) { 2200 /* Start transmitter. */ 2201 cx_enable_transmit (d->chan, 1); 2202 2203 /* Is it busy? */ 2204 if (! cx_buf_free (d->chan)) { 2205 tp->t_state |= TS_BUSY; 2206 splx (s); 2207 return; 2208 } 2209 if (tp->t_iflag & IXOFF) { 2210 p = (buf + (DMABUFSZ/2)); 2211 sublen = q_to_b (&tp->t_outq, p, (DMABUFSZ/2)); 2212 k = sublen; 2213 while (k--) { 2214 /* Send XON/XOFF out of band. */ 2215 if (*p == tp->t_cc[VSTOP]) { 2216 cx_xflow_ctl (d->chan, 0); 2217 p++; 2218 continue; 2219 } 2220 if (*p == tp->t_cc[VSTART]) { 2221 cx_xflow_ctl (d->chan, 1); 2222 p++; 2223 continue; 2224 } 2225 buf[len] = *p; 2226 len++; 2227 p++; 2228 } 2229 } else { 2230 p = buf; 2231 len = q_to_b (&tp->t_outq, p, (DMABUFSZ/2)); 2232 } 2233 if (len) { 2234 cx_send_packet (d->chan, buf, len, 0); 2235 tp->t_state |= TS_BUSY; 2236 d->atimeout = 10; 2237 CX_DEBUG2 (d, ("out %d bytes\n", len)); 2238 } 2239 } 2240 ttwwakeup (tp); 2241 splx (s); 2242} 2243 2244static int cx_param (struct tty *tp, struct termios *t) 2245{ 2246 drv_t *d = channel [UNIT (tp->t_dev)]; 2247 int s, bits, parity; 2248 2249 if (!d) 2250 return EINVAL; 2251 2252 s = splhigh (); 2253 if (t->c_ospeed == 0) { 2254 /* Clear DTR and RTS. */ 2255 cx_set_dtr (d->chan, 0); 2256 splx (s); 2257 CX_DEBUG2 (d, ("cx_param (hangup)\n")); 2258 return 0; 2259 } 2260 CX_DEBUG2 (d, ("cx_param\n")); 2261 2262 /* Check requested parameters. */ 2263 if (t->c_ospeed < 300 || t->c_ospeed > 256*1024) { 2264 splx (s); 2265 return EINVAL; 2266 } 2267 if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024)) { 2268 splx (s); 2269 return EINVAL; 2270 } 2271 2272 /* And copy them to tty and channel structures. */ 2273 tp->t_ispeed = t->c_ispeed = tp->t_ospeed = t->c_ospeed; 2274 tp->t_cflag = t->c_cflag; 2275 2276 /* Set character length and parity mode. */ 2277 switch (t->c_cflag & CSIZE) { 2278 default: 2279 case CS8: bits = 8; break; 2280 case CS7: bits = 7; break; 2281 case CS6: bits = 6; break; 2282 case CS5: bits = 5; break; 2283 } 2284 2285 parity = ((t->c_cflag & PARENB) ? 1 : 0) * 2286 (1 + ((t->c_cflag & PARODD) ? 0 : 1)); 2287 2288 /* Set current channel number. */ 2289 if (! d->chan->dtr) 2290 cx_set_dtr (d->chan, 1); 2291 2292 ttyldoptim (tp); 2293 cx_set_async_param (d->chan, t->c_ospeed, bits, parity, (t->c_cflag & CSTOPB), 2294 !(t->c_cflag & PARENB), (t->c_cflag & CRTSCTS), 2295 (t->c_iflag & IXON), (t->c_iflag & IXANY), 2296 t->c_cc[VSTART], t->c_cc[VSTOP]); 2297 splx (s); 2298 return 0; 2299} 2300 2301/* 2302 * Stop output on a line 2303 */ 2304static void cx_stop (struct tty *tp, int flag) 2305{ 2306 drv_t *d = channel [UNIT (tp->t_dev)]; 2307 int s; 2308 2309 if (!d) 2310 return; 2311 2312 s = splhigh (); 2313 2314 if (tp->t_state & TS_BUSY) { 2315 /* Stop transmitter */ 2316 CX_DEBUG2 (d, ("cx_stop\n")); 2317 cx_transmitter_ctl (d->chan, 0); 2318 } 2319 splx (s); 2320} 2321 2322/* 2323 * Process the (delayed) carrier signal setup. 2324 */ 2325static void cx_carrier (void *arg) 2326{ 2327 drv_t *d = arg; 2328 cx_chan_t *c = d->chan; 2329 int s, cd; 2330 2331 s = splhigh (); 2332 cd = cx_get_cd (c); 2333 if (d->cd != cd) { 2334 if (cd) { 2335 CX_DEBUG (d, ("carrier on\n")); 2336 d->cd = 1; 2337 splx (s); 2338 if (d->tty) 2339 ttyld_modem(d->tty, 1); 2340 } else { 2341 CX_DEBUG (d, ("carrier loss\n")); 2342 d->cd = 0; 2343 splx (s); 2344 if (d->tty) 2345 ttyld_modem(d->tty, 0); 2346 } 2347 } 2348} 2349 2350/* 2351 * Modem signal callback function. 2352 */ 2353static void cx_modem (cx_chan_t *c) 2354{ 2355 drv_t *d = c->sys; 2356 2357 if (!d || c->mode != M_ASYNC) 2358 return; 2359 /* Handle carrier detect/loss. */ 2360 untimeout (cx_carrier, c, d->dcd_timeout_handle); 2361 /* Carrier changed - delay processing DCD for a while 2362 * to give both sides some time to initialize. */ 2363 d->dcd_timeout_handle = timeout (cx_carrier, d, hz/2); 2364} 2365 2366#if __FreeBSD_version < 500000 2367static struct cdevsw cx_cdevsw = { 2368 cx_open, cx_close, cx_read, cx_write, 2369 cx_ioctl, ttypoll, nommap, nostrategy, 2370 "cx", CDEV_MAJOR, nodump, nopsize, 2371 D_TTY, -1 2372}; 2373#elif __FreeBSD_version == 500000 2374static struct cdevsw cx_cdevsw = { 2375 cx_open, cx_close, cx_read, cx_write, 2376 cx_ioctl, ttypoll, nommap, nostrategy, 2377 "cx", CDEV_MAJOR, nodump, nopsize, 2378 D_TTY, 2379 }; 2380#elif __FreeBSD_version <= 501000 2381static struct cdevsw cx_cdevsw = { 2382 .d_open = cx_open, 2383 .d_close = cx_close, 2384 .d_read = cx_read, 2385 .d_write = cx_write, 2386 .d_ioctl = cx_ioctl, 2387 .d_poll = ttypoll, 2388 .d_mmap = nommap, 2389 .d_strategy = nostrategy, 2390 .d_name = "cx", 2391 .d_maj = CDEV_MAJOR, 2392 .d_dump = nodump, 2393 .d_flags = D_TTY, 2394}; 2395#elif __FreeBSD_version < 502103 2396static struct cdevsw cx_cdevsw = { 2397 .d_open = cx_open, 2398 .d_close = cx_close, 2399 .d_read = cx_read, 2400 .d_write = cx_write, 2401 .d_ioctl = cx_ioctl, 2402 .d_poll = ttypoll, 2403 .d_name = "cx", 2404 .d_maj = CDEV_MAJOR, 2405 .d_flags = D_TTY, 2406}; 2407#else /* __FreeBSD_version >= 502103 */ 2408static struct cdevsw cx_cdevsw = { 2409 .d_version = D_VERSION, 2410 .d_open = cx_open, 2411 .d_close = cx_close, 2412 .d_read = cx_read, 2413 .d_write = cx_write, 2414 .d_ioctl = cx_ioctl, 2415 .d_name = "cx", 2416 .d_maj = CDEV_MAJOR, 2417 .d_flags = D_TTY | D_NEEDGIANT, 2418}; 2419#endif 2420 2421#ifdef NETGRAPH 2422#if __FreeBSD_version >= 500000 2423static int ng_cx_constructor (node_p node) 2424{ 2425 drv_t *d = NG_NODE_PRIVATE (node); 2426#else 2427static int ng_cx_constructor (node_p *node) 2428{ 2429 drv_t *d = (*node)->private; 2430#endif 2431 CX_DEBUG (d, ("Constructor\n")); 2432 return EINVAL; 2433} 2434 2435static int ng_cx_newhook (node_p node, hook_p hook, const char *name) 2436{ 2437 int s; 2438#if __FreeBSD_version >= 500000 2439 drv_t *d = NG_NODE_PRIVATE (node); 2440#else 2441 drv_t *d = node->private; 2442#endif 2443 2444 if (d->chan->mode == M_ASYNC) 2445 return EINVAL; 2446 2447 /* Attach debug hook */ 2448 if (strcmp (name, NG_CX_HOOK_DEBUG) == 0) { 2449#if __FreeBSD_version >= 500000 2450 NG_HOOK_SET_PRIVATE (hook, NULL); 2451#else 2452 hook->private = 0; 2453#endif 2454 d->debug_hook = hook; 2455 return 0; 2456 } 2457 2458 /* Check for raw hook */ 2459 if (strcmp (name, NG_CX_HOOK_RAW) != 0) 2460 return EINVAL; 2461 2462#if __FreeBSD_version >= 500000 2463 NG_HOOK_SET_PRIVATE (hook, d); 2464#else 2465 hook->private = d; 2466#endif 2467 d->hook = hook; 2468 s = splhigh (); 2469 cx_up (d); 2470 splx (s); 2471 return 0; 2472} 2473 2474static int print_modems (char *s, cx_chan_t *c, int need_header) 2475{ 2476 int status = cx_modem_status (c->sys); 2477 int length = 0; 2478 2479 if (need_header) 2480 length += sprintf (s + length, " LE DTR DSR RTS CTS CD\n"); 2481 length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n", 2482 status & TIOCM_LE ? "On" : "-", 2483 status & TIOCM_DTR ? "On" : "-", 2484 status & TIOCM_DSR ? "On" : "-", 2485 status & TIOCM_RTS ? "On" : "-", 2486 status & TIOCM_CTS ? "On" : "-", 2487 status & TIOCM_CD ? "On" : "-"); 2488 return length; 2489} 2490 2491static int print_stats (char *s, cx_chan_t *c, int need_header) 2492{ 2493 int length = 0; 2494 2495 if (need_header) 2496 length += sprintf (s + length, " Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); 2497 length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n", 2498 c->rintr, c->tintr, c->mintr, c->ibytes, c->ipkts, 2499 c->ierrs, c->obytes, c->opkts, c->oerrs); 2500 return length; 2501} 2502 2503static int print_chan (char *s, cx_chan_t *c) 2504{ 2505 drv_t *d = c->sys; 2506 int length = 0; 2507 2508 length += sprintf (s + length, "cx%d", c->board->num * NCHAN + c->num); 2509 if (d->chan->debug) 2510 length += sprintf (s + length, " debug=%d", d->chan->debug); 2511 2512 if (cx_get_baud (c)) 2513 length += sprintf (s + length, " %ld", cx_get_baud (c)); 2514 else 2515 length += sprintf (s + length, " extclock"); 2516 2517 if (c->mode == M_HDLC) { 2518 length += sprintf (s + length, " dpll=%s", cx_get_dpll (c) ? "on" : "off"); 2519 length += sprintf (s + length, " nrzi=%s", cx_get_nrzi (c) ? "on" : "off"); 2520 } 2521 2522 length += sprintf (s + length, " loop=%s", cx_get_loop (c) ? "on\n" : "off\n"); 2523 return length; 2524} 2525 2526#if __FreeBSD_version >= 500000 2527static int ng_cx_rcvmsg (node_p node, item_p item, hook_p lasthook) 2528{ 2529 drv_t *d = NG_NODE_PRIVATE (node); 2530 struct ng_mesg *msg; 2531#else 2532static int ng_cx_rcvmsg (node_p node, struct ng_mesg *msg, 2533 const char *retaddr, struct ng_mesg **rptr) 2534{ 2535 drv_t *d = node->private; 2536#endif 2537 struct ng_mesg *resp = NULL; 2538 int error = 0; 2539 2540 if (!d) 2541 return EINVAL; 2542 2543 CX_DEBUG (d, ("Rcvmsg\n")); 2544#if __FreeBSD_version >= 500000 2545 NGI_GET_MSG (item, msg); 2546#endif 2547 switch (msg->header.typecookie) { 2548 default: 2549 error = EINVAL; 2550 break; 2551 2552 case NGM_CX_COOKIE: 2553 printf ("Don't forget to implement\n"); 2554 error = EINVAL; 2555 break; 2556 2557 case NGM_GENERIC_COOKIE: 2558 switch (msg->header.cmd) { 2559 default: 2560 error = EINVAL; 2561 break; 2562 2563 case NGM_TEXT_STATUS: { 2564 char *s; 2565 int l = 0; 2566 int dl = sizeof (struct ng_mesg) + 730; 2567 2568#if __FreeBSD_version >= 500000 2569 NG_MKRESPONSE (resp, msg, dl, M_NOWAIT); 2570 if (! resp) { 2571 error = ENOMEM; 2572 break; 2573 } 2574#else 2575 MALLOC (resp, struct ng_mesg *, dl, 2576 M_NETGRAPH, M_NOWAIT); 2577 if (! resp) { 2578 error = ENOMEM; 2579 break; 2580 } 2581#endif 2582 bzero (resp, dl); 2583 s = (resp)->data; 2584 l += print_chan (s + l, d->chan); 2585 l += print_stats (s + l, d->chan, 1); 2586 l += print_modems (s + l, d->chan, 1); 2587#if __FreeBSD_version < 500000 2588 (resp)->header.version = NG_VERSION; 2589 (resp)->header.arglen = strlen (s) + 1; 2590 (resp)->header.token = msg->header.token; 2591 (resp)->header.typecookie = NGM_CX_COOKIE; 2592 (resp)->header.cmd = msg->header.cmd; 2593#endif 2594 strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN); 2595 } 2596 break; 2597 } 2598 break; 2599 } 2600#if __FreeBSD_version >= 500000 2601 NG_RESPOND_MSG (error, node, item, resp); 2602 NG_FREE_MSG (msg); 2603#else 2604 *rptr = resp; 2605 FREE (msg, M_NETGRAPH); 2606#endif 2607 return error; 2608} 2609 2610#if __FreeBSD_version >= 500000 2611static int ng_cx_rcvdata (hook_p hook, item_p item) 2612{ 2613 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook)); 2614 struct mbuf *m; 2615 meta_p meta; 2616#else 2617static int ng_cx_rcvdata (hook_p hook, struct mbuf *m, meta_p meta) 2618{ 2619 drv_t *d = hook->node->private; 2620#endif 2621 struct ifqueue *q; 2622 int s; 2623 2624#if __FreeBSD_version >= 500000 2625 NGI_GET_M (item, m); 2626 NGI_GET_META (item, meta); 2627 NG_FREE_ITEM (item); 2628 if (! NG_HOOK_PRIVATE (hook) || ! d) { 2629 NG_FREE_M (m); 2630 NG_FREE_META (meta); 2631#else 2632 if (! hook->private || ! d) { 2633 NG_FREE_DATA (m,meta); 2634#endif 2635 return ENETDOWN; 2636 } 2637 q = (meta && meta->priority > 0) ? &d->hi_queue : &d->lo_queue; 2638 s = splhigh (); 2639#if __FreeBSD_version >= 500000 2640 IF_LOCK (q); 2641 if (_IF_QFULL (q)) { 2642 _IF_DROP (q); 2643 IF_UNLOCK (q); 2644 splx (s); 2645 NG_FREE_M (m); 2646 NG_FREE_META (meta); 2647 return ENOBUFS; 2648 } 2649 _IF_ENQUEUE (q, m); 2650 IF_UNLOCK (q); 2651#else 2652 if (IF_QFULL (q)) { 2653 IF_DROP (q); 2654 splx (s); 2655 NG_FREE_DATA (m, meta); 2656 return ENOBUFS; 2657 } 2658 IF_ENQUEUE (q, m); 2659#endif 2660 cx_start (d); 2661 splx (s); 2662 return 0; 2663} 2664 2665static int ng_cx_rmnode (node_p node) 2666{ 2667#if __FreeBSD_version >= 500000 2668 drv_t *d = NG_NODE_PRIVATE (node); 2669 2670 CX_DEBUG (d, ("Rmnode\n")); 2671 if (d && d->running) { 2672 int s = splhigh (); 2673 cx_down (d); 2674 splx (s); 2675 } 2676#ifdef KLD_MODULE 2677 if (node->nd_flags & NG_REALLY_DIE) { 2678 NG_NODE_SET_PRIVATE (node, NULL); 2679 NG_NODE_UNREF (node); 2680 } 2681 node->nd_flags &= ~NG_INVALID; 2682#endif 2683#else /* __FreeBSD_version < 500000 */ 2684 drv_t *d = node->private; 2685 int s; 2686 2687 s = splhigh (); 2688 cx_down (d); 2689 splx (s); 2690 node->flags |= NG_INVALID; 2691 ng_cutlinks (node); 2692#ifdef KLD_MODULE 2693 ng_unname (node); 2694 ng_unref (node); 2695#else 2696 node->flags &= ~NG_INVALID; 2697#endif 2698#endif 2699 return 0; 2700} 2701 2702static void ng_cx_watchdog (void *arg) 2703{ 2704 drv_t *d = arg; 2705 2706 if (d->timeout == 1) 2707 cx_watchdog (d); 2708 if (d->timeout) 2709 d->timeout--; 2710 d->timeout_handle = timeout (ng_cx_watchdog, d, hz); 2711} 2712 2713static int ng_cx_connect (hook_p hook) 2714{ 2715#if __FreeBSD_version >= 500000 2716 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2717#else 2718 drv_t *d = hook->node->private; 2719#endif 2720 2721 d->timeout_handle = timeout (ng_cx_watchdog, d, hz); 2722 return 0; 2723} 2724 2725static int ng_cx_disconnect (hook_p hook) 2726{ 2727#if __FreeBSD_version >= 500000 2728 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2729#else 2730 drv_t *d = hook->node->private; 2731#endif 2732 int s; 2733 2734 s = splhigh (); 2735#if __FreeBSD_version >= 500000 2736 if (NG_HOOK_PRIVATE (hook)) 2737#else 2738 if (hook->private) 2739#endif 2740 cx_down (d); 2741 splx (s); 2742 untimeout (ng_cx_watchdog, d, d->timeout_handle); 2743 return 0; 2744} 2745#endif /*NETGRAPH*/ 2746 2747static int cx_modevent (module_t mod, int type, void *unused) 2748{ 2749 struct cdev *dev; 2750 static int load_count = 0; 2751 struct cdevsw *cdsw; 2752 2753#if __FreeBSD_version >= 502103 2754 dev = findcdev (makedev(CDEV_MAJOR, 0)); 2755#else 2756 dev = makedev (CDEV_MAJOR, 0); 2757#endif 2758 switch (type) { 2759 case MOD_LOAD: 2760 if (dev != NULL && 2761 (cdsw = devsw (dev)) && 2762 cdsw->d_maj == CDEV_MAJOR) { 2763 printf ("Sigma driver is already in system\n"); 2764 return (EEXIST); 2765 } 2766#if __FreeBSD_version >= 500000 && defined NETGRAPH 2767 if (ng_newtype (&typestruct)) 2768 printf ("Failed to register ng_cx\n"); 2769#endif 2770 ++load_count; 2771#if __FreeBSD_version <= 500000 2772 cdevsw_add (&cx_cdevsw); 2773#endif 2774 timeout_handle = timeout (cx_timeout, 0, hz*5); 2775 /* Software interrupt. */ 2776#if __FreeBSD_version < 500000 2777 register_swi (SWI_TTY, cx_softintr); 2778#else 2779 swi_add(&tty_ithd, "tty:cx", cx_softintr, NULL, SWI_TTY, 0, 2780 &cx_fast_ih); 2781#endif 2782 break; 2783 case MOD_UNLOAD: 2784 if (load_count == 1) { 2785 printf ("Removing device entry for Sigma\n"); 2786#if __FreeBSD_version <= 500000 2787 cdevsw_remove (&cx_cdevsw); 2788#endif 2789#if __FreeBSD_version >= 500000 && defined NETGRAPH 2790 ng_rmtype (&typestruct); 2791#endif 2792 } 2793 if (timeout_handle.callout) 2794 untimeout (cx_timeout, 0, timeout_handle); 2795#if __FreeBSD_version >= 500000 2796 ithread_remove_handler (cx_fast_ih); 2797#else 2798 unregister_swi (SWI_TTY, cx_softintr); 2799#endif 2800 --load_count; 2801 break; 2802 case MOD_SHUTDOWN: 2803 break; 2804 } 2805 return 0; 2806} 2807 2808#ifdef NETGRAPH 2809static struct ng_type typestruct = { 2810 .version = NG_ABI_VERSION, 2811 .name = NG_CX_NODE_TYPE, 2812 .constructor = ng_cx_constructor, 2813 .rcvmsg = ng_cx_rcvmsg, 2814 .shutdown = ng_cx_rmnode, 2815 .newhook = ng_cx_newhook, 2816 .connect = ng_cx_connect, 2817 .rcvdata = ng_cx_rcvdata, 2818 .disconnect = ng_cx_disconnect 2819}; 2820 2821#endif /*NETGRAPH*/ 2822 2823#if __FreeBSD_version >= 500000 2824#ifdef NETGRAPH 2825MODULE_DEPEND (ng_cx, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 2826#else 2827MODULE_DEPEND (isa_cx, sppp, 1, 1, 1); 2828#endif 2829#ifdef KLD_MODULE 2830DRIVER_MODULE (cxmod, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL); 2831#else 2832DRIVER_MODULE (cx, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL); 2833#endif 2834#elif __FreeBSD_version >= 400000 2835#ifdef NETGRAPH 2836DRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, ng_mod_event, &typestruct); 2837#else 2838DRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, cx_modevent, 0); 2839#endif 2840#endif /* __FreeBSD_version >= 400000 */ 2841#endif /* NCX */ 2842