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