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