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