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