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