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