if_cx.c revision 134412
1234353Sdim/* 2224133Sdim * Cronyx-Sigma adapter driver for FreeBSD. 3224133Sdim * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode, 4224133Sdim * and asyncronous channels with full modem control. 5224133Sdim * Keepalive protocol implemented in both Cisco and PPP modes. 6224133Sdim * 7224133Sdim * Copyright (C) 1994-2002 Cronyx Engineering. 8224133Sdim * Author: Serge Vakulenko, <vak@cronyx.ru> 9224133Sdim * 10224133Sdim * Copyright (C) 1999-2004 Cronyx Engineering. 11224133Sdim * Rewritten on DDK, ported to NETGRAPH, rewritten for FreeBSD 3.x-5.x by 12224133Sdim * Kurakin Roman, <rik@cronyx.ru> 13224133Sdim * 14224133Sdim * This software is distributed with NO WARRANTIES, not even the implied 15224133Sdim * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16224133Sdim * 17263508Sdim * Authors grant any other persons or organisations a permission to use, 18224133Sdim * modify and redistribute this software in source and binary forms, 19224133Sdim * as long as this message is kept with the software, all derivative 20263763Sdim * works or modified versions. 21224133Sdim * 22263763Sdim * Cronyx Id: if_cx.c,v 1.1.2.34 2004/06/23 17:09:13 rik Exp $ 23263763Sdim */ 24263763Sdim 25263763Sdim#include <sys/cdefs.h> 26263763Sdim__FBSDID("$FreeBSD: head/sys/dev/cx/if_cx.c 134412 2004-08-27 22:14:26Z rik $"); 27263763Sdim 28263763Sdim#include <sys/param.h> 29263763Sdim 30263763Sdim#if __FreeBSD_version >= 500000 31263763Sdim# define NCX 1 32224133Sdim#else 33263763Sdim# include "cx.h" 34263763Sdim#endif 35224133Sdim 36224133Sdim#if NCX > 0 37224133Sdim#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, 0, 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], 0, 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], 0, 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, 0, 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, 0, 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, 0, 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 IFF_NEEDSGIANT; 872 d->pp.pp_if.if_ioctl = cx_sioctl; 873 d->pp.pp_if.if_start = cx_ifstart; 874 d->pp.pp_if.if_watchdog = cx_ifwatchdog; 875 d->pp.pp_if.if_init = cx_initialize; 876 sppp_attach (&d->pp.pp_if); 877 if_attach (&d->pp.pp_if); 878 d->pp.pp_tlf = cx_tlf; 879 d->pp.pp_tls = cx_tls; 880 /* If BPF is in the kernel, call the attach for it. 881 * Size of PPP header is 4 bytes. */ 882 bpfattach (&d->pp.pp_if, DLT_PPP, 4); 883#endif /*NETGRAPH*/ 884 } 885 cx_start_chan (c, d->dmamem.virt, d->dmamem.phys); 886 cx_register_receive (c, &cx_receive); 887 cx_register_transmit (c, &cx_transmit); 888 cx_register_error (c, &cx_error); 889 cx_register_modem (c, &cx_modem); 890 dnmt[3] = 'x'+b->num; 891 dnmc[3] = 'x'+b->num; 892 d->devt[0] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num, UID_ROOT, GID_WHEEL, 0644, dnmt, b->num*NCHAN + c->num); 893 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); 894 d->devt[2] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 128, UID_ROOT, GID_WHEEL, 0660, dnmc, b->num*NCHAN + c->num); 895 } 896 splx (s); 897 898 return 0; 899} 900 901static int cx_detach (device_t dev) 902{ 903 bdrv_t *bd = device_get_softc (dev); 904 cx_board_t *b = bd->board; 905 cx_chan_t *c; 906 int s = splhigh (); 907 908 /* Check if the device is busy (open). */ 909 for (c = b->chan; c < b->chan + NCHAN; ++c) { 910 drv_t *d = (drv_t*) c->sys; 911 912 if (!d || d->chan->type == T_NONE) 913 continue; 914 if (d->lock) { 915 splx (s); 916 return EBUSY; 917 } 918 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 919 (d->open_dev|0x2)) { 920 splx (s); 921 return EBUSY; 922 } 923 if (d->running) { 924 splx (s); 925 return EBUSY; 926 } 927 } 928 929 /* Deactivate the timeout routine. And soft interrupt*/ 930 if (led_timo[b->num].callout) 931 untimeout (cx_led_off, b, led_timo[b->num]); 932 933 for (c = b->chan; c < b->chan + NCHAN; ++c) { 934 drv_t *d = c->sys; 935 936 if (!d || d->chan->type == T_NONE) 937 continue; 938 939 if (d->dcd_timeout_handle.callout) 940 untimeout (cx_carrier, c, d->dcd_timeout_handle); 941 } 942 bus_teardown_intr (dev, bd->irq_res, bd->intrhand); 943 bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); 944 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res); 945 946 bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); 947 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res); 948 949 bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res); 950 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res); 951 952 cx_close_board (b); 953 954 /* Detach the interfaces, free buffer memory. */ 955 for (c = b->chan; c < b->chan + NCHAN; ++c) { 956 drv_t *d = (drv_t*) c->sys; 957 958 if (!d || d->chan->type == T_NONE) 959 continue; 960 961#if __FreeBSD_version >= 502113 962 if (d->tty) { 963 ttyrel (d->tty); 964 d->tty = NULL; 965 } 966#endif 967 968#ifdef NETGRAPH 969#if __FreeBSD_version >= 500000 970 if (d->node) { 971 ng_rmnode_self (d->node); 972 NG_NODE_UNREF (d->node); 973 d->node = NULL; 974 } 975 mtx_destroy (&d->lo_queue.ifq_mtx); 976 mtx_destroy (&d->hi_queue.ifq_mtx); 977#else 978 ng_rmnode (d->node); 979 d->node = NULL; 980#endif 981#else 982#if __FreeBSD_version >= 410000 && NBPFILTER > 0 983 /* Detach from the packet filter list of interfaces. */ 984 bpfdetach (&d->pp.pp_if); 985#endif 986 /* Detach from the sync PPP list. */ 987 sppp_detach (&d->pp.pp_if); 988 989 if_detach (&d->pp.pp_if); 990#endif 991 destroy_dev (d->devt[0]); 992 destroy_dev (d->devt[1]); 993 destroy_dev (d->devt[2]); 994 } 995 996 cx_led_off (b); 997 if (led_timo[b->num].callout) 998 untimeout (cx_led_off, b, led_timo[b->num]); 999 splx (s); 1000 1001 s = splhigh (); 1002 for (c = b->chan; c < b->chan + NCHAN; ++c) { 1003 drv_t *d = (drv_t*) c->sys; 1004 1005 if (!d || d->chan->type == T_NONE) 1006 continue; 1007 1008 /* Deallocate buffers. */ 1009 cx_bus_dma_mem_free (&d->dmamem); 1010 } 1011 bd->board = 0; 1012 adapter [b->num] = 0; 1013 free (b, M_DEVBUF); 1014 splx (s); 1015 1016 return 0; 1017} 1018 1019#ifndef NETGRAPH 1020static void cx_ifstart (struct ifnet *ifp) 1021{ 1022 drv_t *d = ifp->if_softc; 1023 1024 cx_start (d); 1025} 1026 1027static void cx_ifwatchdog (struct ifnet *ifp) 1028{ 1029 drv_t *d = ifp->if_softc; 1030 1031 cx_watchdog (d); 1032} 1033 1034static void cx_tlf (struct sppp *sp) 1035{ 1036 drv_t *d = sp->pp_if.if_softc; 1037 1038 CX_DEBUG (d, ("cx_tlf\n")); 1039/* cx_set_dtr (d->chan, 0);*/ 1040/* cx_set_rts (d->chan, 0);*/ 1041 sp->pp_down (sp); 1042} 1043 1044static void cx_tls (struct sppp *sp) 1045{ 1046 drv_t *d = sp->pp_if.if_softc; 1047 1048 CX_DEBUG (d, ("cx_tls\n")); 1049 sp->pp_up (sp); 1050} 1051 1052/* 1053 * Initialization of interface. 1054 * It seems to be never called by upper level. 1055 */ 1056static void cx_initialize (void *softc) 1057{ 1058 drv_t *d = softc; 1059 1060 CX_DEBUG (d, ("cx_initialize\n")); 1061} 1062 1063/* 1064 * Process an ioctl request. 1065 */ 1066static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 1067{ 1068 drv_t *d = ifp->if_softc; 1069 int error, s, was_up, should_be_up; 1070 1071 /* No socket ioctls while the channel is in async mode. */ 1072 if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC) 1073 return EBUSY; 1074 1075 /* Socket ioctls on slave subchannels are not allowed. */ 1076 was_up = (ifp->if_flags & IFF_RUNNING) != 0; 1077 error = sppp_ioctl (ifp, cmd, data); 1078 if (error) 1079 return error; 1080 1081 if (! (ifp->if_flags & IFF_DEBUG)) 1082 d->chan->debug = 0; 1083 else if (! d->chan->debug) 1084 d->chan->debug = 1; 1085 1086 switch (cmd) { 1087 default: CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; 1088 case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n")); return 0; 1089 case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n")); return 0; 1090 case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n")); break; 1091 case SIOCSIFADDR: CX_DEBUG2 (d, ("SIOCSIFADDR\n")); break; 1092 } 1093 1094 /* We get here only in case of SIFFLAGS or SIFADDR. */ 1095 s = splhigh (); 1096 should_be_up = (ifp->if_flags & IFF_RUNNING) != 0; 1097 if (!was_up && should_be_up) { 1098 /* Interface goes up -- start it. */ 1099 cx_up (d); 1100 cx_start (d); 1101 } else if (was_up && !should_be_up) { 1102 /* Interface is going down -- stop it. */ 1103 /* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ 1104 cx_down (d); 1105 } 1106 splx (s); 1107 return 0; 1108} 1109#endif /*NETGRAPH*/ 1110 1111/* 1112 * Stop the interface. Called on splimp(). 1113 */ 1114static void cx_down (drv_t *d) 1115{ 1116 int s = splhigh (); 1117 CX_DEBUG (d, ("cx_down\n")); 1118 cx_set_dtr (d->chan, 0); 1119 cx_set_rts (d->chan, 0); 1120 d->running = 0; 1121 splx (s); 1122} 1123 1124/* 1125 * Start the interface. Called on splimp(). 1126 */ 1127static void cx_up (drv_t *d) 1128{ 1129 int s = splhigh (); 1130 CX_DEBUG (d, ("cx_up\n")); 1131 cx_set_dtr (d->chan, 1); 1132 cx_set_rts (d->chan, 1); 1133 d->running = 1; 1134 splx (s); 1135} 1136 1137/* 1138 * Start output on the (slave) interface. Get another datagram to send 1139 * off of the interface queue, and copy it to the interface 1140 * before starting the output. 1141 */ 1142static void cx_send (drv_t *d) 1143{ 1144 struct mbuf *m; 1145 u_short len; 1146 1147 CX_DEBUG2 (d, ("cx_send\n")); 1148 1149 /* No output if the interface is down. */ 1150 if (! d->running) 1151 return; 1152 1153 /* No output if the modem is off. */ 1154 if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan)) 1155 return; 1156 1157 if (cx_buf_free (d->chan)) { 1158 /* Get the packet to send. */ 1159#ifdef NETGRAPH 1160 IF_DEQUEUE (&d->hi_queue, m); 1161 if (! m) 1162 IF_DEQUEUE (&d->lo_queue, m); 1163#else 1164 m = sppp_dequeue (&d->pp.pp_if); 1165#endif 1166 if (! m) 1167 return; 1168#ifndef NETGRAPH 1169 if (d->pp.pp_if.if_bpf) 1170#if __FreeBSD_version >= 500000 1171 BPF_MTAP (&d->pp.pp_if, m); 1172#else 1173 bpf_mtap (&d->pp.pp_if, m); 1174#endif 1175#endif 1176 len = m->m_pkthdr.len; 1177 if (! m->m_next) 1178 cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t), 1179 len, 0); 1180 else { 1181 u_char buf [DMABUFSZ]; 1182 m_copydata (m, 0, len, buf); 1183 cx_send_packet (d->chan, buf, len, 0); 1184 } 1185 m_freem (m); 1186 1187 /* Set up transmit timeout, 10 seconds. */ 1188#ifdef NETGRAPH 1189 d->timeout = 10; 1190#else 1191 d->pp.pp_if.if_timer = 10; 1192#endif 1193 } 1194#ifndef NETGRAPH 1195 d->pp.pp_if.if_flags |= IFF_OACTIVE; 1196#endif 1197} 1198 1199/* 1200 * Start output on the interface. 1201 * Always called on splimp(). 1202 */ 1203static void cx_start (drv_t *d) 1204{ 1205 int s = splhigh (); 1206 if (d->running) { 1207 if (! d->chan->dtr) 1208 cx_set_dtr (d->chan, 1); 1209 if (! d->chan->rts) 1210 cx_set_rts (d->chan, 1); 1211 cx_send (d); 1212 } 1213 splx (s); 1214} 1215 1216/* 1217 * Handle transmit timeouts. 1218 * Recover after lost transmit interrupts. 1219 * Always called on splimp(). 1220 */ 1221static void cx_watchdog (drv_t *d) 1222{ 1223 int s = splhigh (); 1224 CX_DEBUG (d, ("device timeout\n")); 1225 if (d->running) { 1226 cx_setup_chan (d->chan); 1227 cx_start_chan (d->chan, 0, 0); 1228 cx_set_dtr (d->chan, 1); 1229 cx_set_rts (d->chan, 1); 1230 cx_start (d); 1231 } 1232 splx (s); 1233} 1234 1235/* 1236 * Transmit callback function. 1237 */ 1238static void cx_transmit (cx_chan_t *c, void *attachment, int len) 1239{ 1240 drv_t *d = c->sys; 1241 1242 if (!d) 1243 return; 1244 1245 if (c->mode == M_ASYNC && d->tty) { 1246 d->tty->t_state &= ~(TS_BUSY | TS_FLUSH); 1247 d->atimeout = 0; 1248 if (d->tty->t_dev) { 1249 d->intr_action |= CX_WRITE; 1250 MY_SOFT_INTR = 1; 1251#if __FreeBSD_version >= 500000 1252 swi_sched (cx_fast_ih, 0); 1253#else 1254 setsofttty (); 1255#endif 1256 } 1257 return; 1258 } 1259#ifdef NETGRAPH 1260 d->timeout = 0; 1261#else 1262 ++d->pp.pp_if.if_opackets; 1263 d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 1264 d->pp.pp_if.if_timer = 0; 1265#endif 1266 cx_start (d); 1267} 1268 1269/* 1270 * Process the received packet. 1271 */ 1272static void cx_receive (cx_chan_t *c, char *data, int len) 1273{ 1274 drv_t *d = c->sys; 1275 struct mbuf *m; 1276 char *cc = data; 1277#if __FreeBSD_version >= 500000 && defined NETGRAPH 1278 int error; 1279#endif 1280 1281 if (!d) 1282 return; 1283 1284 if (c->mode == M_ASYNC && d->tty) { 1285 if (d->tty->t_state & TS_ISOPEN) { 1286 async_q *q = &d->aqueue; 1287 int size = BF_SZ - 1 - AQ_GSZ (q); 1288 1289 if (len <= 0 && !size) 1290 return; 1291 1292 if (len > size) { 1293 c->ierrs++; 1294 cx_error (c, CX_OVERRUN); 1295 len = size - 1; 1296 } 1297 1298 while (len--) { 1299 AQ_PUSH (q, *(unsigned char *)cc); 1300 cc++; 1301 } 1302 1303 d->intr_action |= CX_READ; 1304 MY_SOFT_INTR = 1; 1305#if __FreeBSD_version >= 500000 1306 swi_sched (cx_fast_ih, 0); 1307#else 1308 setsofttty (); 1309#endif 1310 } 1311 return; 1312 } 1313 if (! d->running) 1314 return; 1315 1316 m = makembuf (data, len); 1317 if (! m) { 1318 CX_DEBUG (d, ("no memory for packet\n")); 1319#ifndef NETGRAPH 1320 ++d->pp.pp_if.if_iqdrops; 1321#endif 1322 return; 1323 } 1324 if (c->debug > 1) 1325 printmbuf (m); 1326#ifdef NETGRAPH 1327 m->m_pkthdr.rcvif = 0; 1328#if __FreeBSD_version >= 500000 1329 NG_SEND_DATA_ONLY (error, d->hook, m); 1330#else 1331 ng_queue_data (d->hook, m, 0); 1332#endif 1333#else 1334 ++d->pp.pp_if.if_ipackets; 1335 m->m_pkthdr.rcvif = &d->pp.pp_if; 1336 /* Check if there's a BPF listener on this interface. 1337 * If so, hand off the raw packet to bpf. */ 1338 if (d->pp.pp_if.if_bpf) 1339#if __FreeBSD_version >= 500000 1340 BPF_TAP (&d->pp.pp_if, data, len); 1341#else 1342 bpf_tap (&d->pp.pp_if, data, len); 1343#endif 1344 sppp_input (&d->pp.pp_if, m); 1345#endif 1346} 1347 1348#if __FreeBSD_version < 502113 1349#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ 1350 && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ 1351 && (!(tp->t_iflag & PARMRK)\ 1352 || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ 1353 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ 1354 && linesw[tp->t_line].l_rint == ttyinput) 1355#else 1356#define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\ 1357 && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\ 1358 && (!(tp->t_iflag & PARMRK)\ 1359 || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\ 1360 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\ 1361 && linesw[tp->t_line]->l_rint == ttyinput) 1362#endif 1363 1364/* 1365 * Error callback function. 1366 */ 1367static void cx_error (cx_chan_t *c, int data) 1368{ 1369 drv_t *d = c->sys; 1370 async_q *q; 1371 1372 if (!d) 1373 return; 1374 1375 q = &(d->aqueue); 1376 1377 switch (data) { 1378 case CX_FRAME: 1379 CX_DEBUG (d, ("frame error\n")); 1380 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1381 && (AQ_GSZ (q) < BF_SZ - 1) 1382 && (!CONDITION((&d->tty->t_termios), (d->tty)) 1383 || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { 1384 AQ_PUSH (q, TTY_FE); 1385 d->intr_action |= CX_READ; 1386 MY_SOFT_INTR = 1; 1387#if __FreeBSD_version >= 500000 1388 swi_sched (cx_fast_ih, 0); 1389#else 1390 setsofttty (); 1391#endif 1392 } 1393#ifndef NETGRAPH 1394 else 1395 ++d->pp.pp_if.if_ierrors; 1396#endif 1397 break; 1398 case CX_CRC: 1399 CX_DEBUG (d, ("crc error\n")); 1400 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1401 && (AQ_GSZ (q) < BF_SZ - 1) 1402 && (!CONDITION((&d->tty->t_termios), (d->tty)) 1403 || !(d->tty->t_iflag & INPCK) 1404 || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) { 1405 AQ_PUSH (q, TTY_PE); 1406 d->intr_action |= CX_READ; 1407 MY_SOFT_INTR = 1; 1408#if __FreeBSD_version >= 500000 1409 swi_sched (cx_fast_ih, 0); 1410#else 1411 setsofttty (); 1412#endif 1413 } 1414#ifndef NETGRAPH 1415 else 1416 ++d->pp.pp_if.if_ierrors; 1417#endif 1418 break; 1419 case CX_OVERRUN: 1420 CX_DEBUG (d, ("overrun error\n")); 1421#ifdef TTY_OE 1422 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1423 && (AQ_GSZ (q) < BF_SZ - 1) 1424 && (!CONDITION((&d->tty->t_termios), (d->tty)))) { 1425 AQ_PUSH (q, TTY_OE); 1426 d->intr_action |= CX_READ; 1427 MY_SOFT_INTR = 1; 1428#if __FreeBSD_version >= 500000 1429 swi_sched (cx_fast_ih, 0); 1430#else 1431 setsofttty (); 1432#endif 1433 } 1434#endif 1435#ifndef NETGRAPH 1436 else { 1437 ++d->pp.pp_if.if_collisions; 1438 ++d->pp.pp_if.if_ierrors; 1439 } 1440#endif 1441 break; 1442 case CX_OVERFLOW: 1443 CX_DEBUG (d, ("overflow error\n")); 1444#ifndef NETGRAPH 1445 if (c->mode != M_ASYNC) 1446 ++d->pp.pp_if.if_ierrors; 1447#endif 1448 break; 1449 case CX_UNDERRUN: 1450 CX_DEBUG (d, ("underrun error\n")); 1451 if (c->mode != M_ASYNC) { 1452#ifdef NETGRAPH 1453 d->timeout = 0; 1454#else 1455 ++d->pp.pp_if.if_oerrors; 1456 d->pp.pp_if.if_flags &= ~IFF_OACTIVE; 1457 d->pp.pp_if.if_timer = 0; 1458 cx_start (d); 1459#endif 1460 } 1461 break; 1462 case CX_BREAK: 1463 CX_DEBUG (d, ("break error\n")); 1464 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) 1465 && (AQ_GSZ (q) < BF_SZ - 1) 1466 && (!CONDITION((&d->tty->t_termios), (d->tty)) 1467 || !(d->tty->t_iflag & (IGNBRK | BRKINT | PARMRK)))) { 1468 AQ_PUSH (q, TTY_BI); 1469 d->intr_action |= CX_READ; 1470 MY_SOFT_INTR = 1; 1471#if __FreeBSD_version >= 500000 1472 swi_sched (cx_fast_ih, 0); 1473#else 1474 setsofttty (); 1475#endif 1476 } 1477#ifndef NETGRAPH 1478 else 1479 ++d->pp.pp_if.if_ierrors; 1480#endif 1481 break; 1482 default: 1483 CX_DEBUG (d, ("error #%d\n", data)); 1484 } 1485} 1486 1487#if __FreeBSD_version < 500000 1488static int cx_open (dev_t dev, int flag, int mode, struct proc *p) 1489#else 1490static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td) 1491#endif 1492{ 1493 int unit = UNIT (dev); 1494 drv_t *d; 1495 int error; 1496 1497 if (unit >= NCX*NCHAN || ! (d = channel[unit])) 1498 return ENXIO; 1499 CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n", 1500 unit, flag, mode)); 1501 1502 if (d->chan->mode != M_ASYNC || IF_CUNIT(dev)) { 1503 d->open_dev |= 0x1; 1504 return 0; 1505 } 1506 if (!d->tty) { 1507 d->tty = ttymalloc (d->tty); 1508 d->tty->t_oproc = cx_oproc; 1509 d->tty->t_param = cx_param; 1510 d->tty->t_stop = cx_stop; 1511 } 1512 dev->si_tty = d->tty; 1513 d->tty->t_dev = dev; 1514again: 1515 error = ttydtrwaitsleep(d->tty); 1516 if (error) 1517 return error; 1518 1519 if ((d->tty->t_state & TS_ISOPEN) && (d->tty->t_state & TS_XCLUDE) && 1520#if __FreeBSD_version >= 500000 1521 suser (td)) 1522#else 1523 p->p_ucred->cr_uid != 0) 1524#endif 1525 return EBUSY; 1526 1527 if (d->tty->t_state & TS_ISOPEN) { 1528 /* 1529 * Cannot open /dev/cua if /dev/tty already opened. 1530 */ 1531 if (CALLOUT (dev) && ! d->callout) 1532 return EBUSY; 1533 1534 /* 1535 * Opening /dev/tty when /dev/cua is already opened. 1536 * Wait for close, then try again. 1537 */ 1538 if (! CALLOUT (dev) && d->callout) { 1539 if (flag & O_NONBLOCK) 1540 return EBUSY; 1541 error = tsleep (d, TTIPRI | PCATCH, "cxbi", 0); 1542 if (error) 1543 return error; 1544 goto again; 1545 } 1546 } else if (d->lock && ! CALLOUT (dev) && (flag & O_NONBLOCK)) 1547 /* 1548 * We try to open /dev/tty in non-blocking mode 1549 * while somebody is already waiting for carrier on it. 1550 */ 1551 return EBUSY; 1552 else { 1553 ttychars (d->tty); 1554 if (d->tty->t_ispeed == 0) { 1555 d->tty->t_iflag = 0; 1556 d->tty->t_oflag = 0; 1557 d->tty->t_lflag = 0; 1558 d->tty->t_cflag = CREAD | CS8 | HUPCL; 1559 d->tty->t_ispeed = d->chan->rxbaud; 1560 d->tty->t_ospeed = d->chan->txbaud; 1561 } 1562 if (CALLOUT (dev)) 1563 d->tty->t_cflag |= CLOCAL; 1564 else 1565 d->tty->t_cflag &= ~CLOCAL; 1566 cx_param (d->tty, &d->tty->t_termios); 1567 ttsetwater (d->tty); 1568 } 1569 1570 splhigh (); 1571 if (! (d->tty->t_state & TS_ISOPEN)) { 1572 cx_start_chan (d->chan, 0, 0); 1573 cx_set_dtr (d->chan, 1); 1574 cx_set_rts (d->chan, 1); 1575 d->cd = cx_get_cd (d->chan); 1576 if (CALLOUT (dev) || cx_get_cd (d->chan)) 1577 ttyld_modem(d->tty, 1); 1578 } 1579 1580 if (! (flag & O_NONBLOCK) && ! (d->tty->t_cflag & CLOCAL) && 1581 ! (d->tty->t_state & TS_CARR_ON)) { 1582 /* Lock the channel against cxconfig while we are 1583 * waiting for carrier. */ 1584 d->lock++; 1585 error = tsleep (&d->tty->t_rawq, TTIPRI | PCATCH, "cxdcd", 0); 1586 /* Unlock the channel. */ 1587 d->lock--; 1588 spl0 (); 1589 if (error) 1590 goto failed; 1591 goto again; 1592 } 1593 1594 error = ttyld_open (d->tty, dev); 1595 ttyldoptim (d->tty); 1596 spl0 (); 1597 if (error) { 1598failed: if (! (d->tty->t_state & TS_ISOPEN)) { 1599 splhigh (); 1600 cx_set_dtr (d->chan, 0); 1601 cx_set_rts (d->chan, 0); 1602 ttydtrwaitstart(d->tty); 1603 spl0 (); 1604 } 1605 return error; 1606 } 1607 1608 if (d->tty->t_state & TS_ISOPEN) 1609 d->callout = CALLOUT (dev) ? 1 : 0; 1610 1611 d->open_dev |= 0x2; 1612 CX_DEBUG2 (d, ("cx_open done\n")); 1613 return 0; 1614} 1615 1616#if __FreeBSD_version < 500000 1617static int cx_close (dev_t dev, int flag, int mode, struct proc *p) 1618#else 1619static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td) 1620#endif 1621{ 1622 drv_t *d = channel [UNIT (dev)]; 1623 int s; 1624 1625 CX_DEBUG2 (d, ("cx_close\n")); 1626 if ((!(d->open_dev&0x2)) || IF_CUNIT(dev)){ 1627 d->open_dev &= ~0x1; 1628 return 0; 1629 } 1630 s = splhigh (); 1631 ttyld_close(d->tty, flag); 1632 ttyldoptim (d->tty); 1633 1634 /* Disable receiver. 1635 * Transmitter continues sending the queued data. */ 1636 cx_enable_receive (d->chan, 0); 1637 1638 /* Clear DTR and RTS. */ 1639 if ((d->tty->t_cflag & HUPCL) || ! (d->tty->t_state & TS_ISOPEN)) { 1640 cx_set_dtr (d->chan, 0); 1641 cx_set_rts (d->chan, 0); 1642 ttydtrwaitstart(d->tty); 1643 } 1644 tty_close (d->tty); 1645 splx (s); 1646 d->callout = 0; 1647 1648 /* 1649 * Wake up bidirectional opens. 1650 * Since we may be opened twice we couldn't call ttyrel() here. 1651 * So just keep d->tty for future use. It would be freed by 1652 * ttyrel() at cx_detach(). 1653 */ 1654 1655 wakeup (d); 1656 d->open_dev &= ~0x2; 1657 1658 return 0; 1659} 1660 1661static int cx_read (struct cdev *dev, struct uio *uio, int flag) 1662{ 1663 drv_t *d = channel [UNIT (dev)]; 1664 1665 if (d) CX_DEBUG2 (d, ("cx_read\n")); 1666 if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev) || !d->tty) 1667 return EBADF; 1668 1669 return ttyld_read (d->tty, uio, flag); 1670} 1671 1672static int cx_write (struct cdev *dev, struct uio *uio, int flag) 1673{ 1674 drv_t *d = channel [UNIT (dev)]; 1675 1676 if (d) CX_DEBUG2 (d, ("cx_write\n")); 1677 if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev) || !d->tty) 1678 return EBADF; 1679 1680 return ttyld_write (d->tty, uio, flag); 1681} 1682 1683static int cx_modem_status (drv_t *d) 1684{ 1685 int status = 0, s = splhigh (); 1686 /* Already opened by someone or network interface is up? */ 1687 if ((d->chan->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 1688 (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running)) 1689 status = TIOCM_LE; /* always enabled while open */ 1690 1691 if (cx_get_dsr (d->chan)) status |= TIOCM_DSR; 1692 if (cx_get_cd (d->chan)) status |= TIOCM_CD; 1693 if (cx_get_cts (d->chan)) status |= TIOCM_CTS; 1694 if (d->chan->dtr) status |= TIOCM_DTR; 1695 if (d->chan->rts) status |= TIOCM_RTS; 1696 splx (s); 1697 return status; 1698} 1699 1700#if __FreeBSD_version < 500000 1701static int cx_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1702#else 1703static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1704#endif 1705{ 1706 drv_t *d = channel [UNIT (dev)]; 1707 cx_chan_t *c; 1708 struct serial_statistics *st; 1709 int error, s; 1710 char mask[16]; 1711 1712 if (!d || !(c = d->chan)) 1713 return EINVAL; 1714 1715 switch (cmd) { 1716 case SERIAL_GETREGISTERED: 1717 CX_DEBUG2 (d, ("ioctl: getregistered\n")); 1718 bzero (mask, sizeof(mask)); 1719 for (s=0; s<NCX*NCHAN; ++s) 1720 if (channel [s]) 1721 mask [s/8] |= 1 << (s & 7); 1722 bcopy (mask, data, sizeof (mask)); 1723 return 0; 1724 1725 case SERIAL_GETPORT: 1726 CX_DEBUG2 (d, ("ioctl: getport\n")); 1727 s = splhigh (); 1728 *(int *)data = cx_get_port (c); 1729 splx (s); 1730 if (*(int *)data<0) 1731 return (EINVAL); 1732 else 1733 return 0; 1734 1735 case SERIAL_SETPORT: 1736 CX_DEBUG2 (d, ("ioctl: setproto\n")); 1737 /* Only for superuser! */ 1738#if __FreeBSD_version < 500000 1739 error = suser (p); 1740#else /* __FreeBSD_version >= 500000 */ 1741 error = suser (td); 1742#endif /* __FreeBSD_version >= 500000 */ 1743 if (error) 1744 return error; 1745 1746 s = splhigh (); 1747 cx_set_port (c, *(int *)data); 1748 splx (s); 1749 return 0; 1750 1751#ifndef NETGRAPH 1752 case SERIAL_GETPROTO: 1753 CX_DEBUG2 (d, ("ioctl: getproto\n")); 1754 s = splhigh (); 1755 strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" : 1756 (d->pp.pp_flags & PP_FR) ? "fr" : 1757 (d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp"); 1758 splx (s); 1759 return 0; 1760 1761 case SERIAL_SETPROTO: 1762 CX_DEBUG2 (d, ("ioctl: setproto\n")); 1763 /* Only for superuser! */ 1764#if __FreeBSD_version < 500000 1765 error = suser (p); 1766#else /* __FreeBSD_version >= 500000 */ 1767 error = suser (td); 1768#endif /* __FreeBSD_version >= 500000 */ 1769 if (error) 1770 return error; 1771 if (c->mode == M_ASYNC) 1772 return EBUSY; 1773 if (d->pp.pp_if.if_flags & IFF_RUNNING) 1774 return EBUSY; 1775 if (! strcmp ("cisco", (char*)data)) { 1776 d->pp.pp_flags &= ~(PP_FR); 1777 d->pp.pp_flags |= PP_KEEPALIVE; 1778 d->pp.pp_if.if_flags |= PP_CISCO; 1779 } else if (! strcmp ("fr", (char*)data)) { 1780 d->pp.pp_if.if_flags &= ~(PP_CISCO); 1781 d->pp.pp_flags |= PP_FR | PP_KEEPALIVE; 1782 } else if (! strcmp ("ppp", (char*)data)) { 1783 d->pp.pp_flags &= ~(PP_FR | PP_KEEPALIVE); 1784 d->pp.pp_if.if_flags &= ~(PP_CISCO); 1785 } else 1786 return EINVAL; 1787 return 0; 1788 1789 case SERIAL_GETKEEPALIVE: 1790 CX_DEBUG2 (d, ("ioctl: getkeepalive\n")); 1791 if ((d->pp.pp_flags & PP_FR) || 1792 (d->pp.pp_if.if_flags & PP_CISCO) || 1793 (c->mode == M_ASYNC)) 1794 return EINVAL; 1795 s = splhigh (); 1796 *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0; 1797 splx (s); 1798 return 0; 1799 1800 case SERIAL_SETKEEPALIVE: 1801 CX_DEBUG2 (d, ("ioctl: setkeepalive\n")); 1802 /* Only for superuser! */ 1803#if __FreeBSD_version < 500000 1804 error = suser (p); 1805#else /* __FreeBSD_version >= 500000 */ 1806 error = suser (td); 1807#endif /* __FreeBSD_version >= 500000 */ 1808 if (error) 1809 return error; 1810 if ((d->pp.pp_flags & PP_FR) || 1811 (d->pp.pp_if.if_flags & PP_CISCO)) 1812 return EINVAL; 1813 s = splhigh (); 1814 if (*(int*)data) 1815 d->pp.pp_flags |= PP_KEEPALIVE; 1816 else 1817 d->pp.pp_flags &= ~PP_KEEPALIVE; 1818 splx (s); 1819 return 0; 1820#endif /*NETGRAPH*/ 1821 1822 case SERIAL_GETMODE: 1823 CX_DEBUG2 (d, ("ioctl: getmode\n")); 1824 s = splhigh (); 1825 *(int*)data = (c->mode == M_ASYNC) ? 1826 SERIAL_ASYNC : SERIAL_HDLC; 1827 splx (s); 1828 return 0; 1829 1830 case SERIAL_SETMODE: 1831 CX_DEBUG2 (d, ("ioctl: setmode\n")); 1832 /* Only for superuser! */ 1833#if __FreeBSD_version < 500000 1834 error = suser (p); 1835#else /* __FreeBSD_version >= 500000 */ 1836 error = suser (td); 1837#endif /* __FreeBSD_version >= 500000 */ 1838 if (error) 1839 return error; 1840 1841 /* Somebody is waiting for carrier? */ 1842 if (d->lock) 1843 return EBUSY; 1844 /* /dev/ttyXX is already opened by someone? */ 1845 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) && 1846 (d->open_dev|0x2)) 1847 return EBUSY; 1848 /* Network interface is up? 1849 * Cannot change to async mode. */ 1850 if (c->mode != M_ASYNC && d->running && 1851 (*(int*)data == SERIAL_ASYNC)) 1852 return EBUSY; 1853 1854 s = splhigh (); 1855 if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) { 1856 cx_set_mode (c, M_ASYNC); 1857 cx_enable_receive (c, 0); 1858 cx_enable_transmit (c, 0); 1859 } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) { 1860 cx_set_mode (c, M_HDLC); 1861 cx_enable_receive (c, 1); 1862 cx_enable_transmit (c, 1); 1863 } 1864 splx (s); 1865 return 0; 1866 1867 case SERIAL_GETSTAT: 1868 CX_DEBUG2 (d, ("ioctl: getestat\n")); 1869 st = (struct serial_statistics*) data; 1870 s = splhigh (); 1871 st->rintr = c->rintr; 1872 st->tintr = c->tintr; 1873 st->mintr = c->mintr; 1874 st->ibytes = c->ibytes; 1875 st->ipkts = c->ipkts; 1876 st->ierrs = c->ierrs; 1877 st->obytes = c->obytes; 1878 st->opkts = c->opkts; 1879 st->oerrs = c->oerrs; 1880 splx (s); 1881 return 0; 1882 1883 case SERIAL_CLRSTAT: 1884 CX_DEBUG2 (d, ("ioctl: clrstat\n")); 1885 /* Only for superuser! */ 1886#if __FreeBSD_version < 500000 1887 error = suser (p); 1888#else /* __FreeBSD_version >= 500000 */ 1889 error = suser (td); 1890#endif /* __FreeBSD_version >= 500000 */ 1891 if (error) 1892 return error; 1893 s = splhigh (); 1894 c->rintr = 0; 1895 c->tintr = 0; 1896 c->mintr = 0; 1897 c->ibytes = 0; 1898 c->ipkts = 0; 1899 c->ierrs = 0; 1900 c->obytes = 0; 1901 c->opkts = 0; 1902 c->oerrs = 0; 1903 splx (s); 1904 return 0; 1905 1906 case SERIAL_GETBAUD: 1907 CX_DEBUG2 (d, ("ioctl: getbaud\n")); 1908 if (c->mode == M_ASYNC) 1909 return EINVAL; 1910 s = splhigh (); 1911 *(long*)data = cx_get_baud(c); 1912 splx (s); 1913 return 0; 1914 1915 case SERIAL_SETBAUD: 1916 CX_DEBUG2 (d, ("ioctl: setbaud\n")); 1917 /* Only for superuser! */ 1918#if __FreeBSD_version < 500000 1919 error = suser (p); 1920#else /* __FreeBSD_version >= 500000 */ 1921 error = suser (td); 1922#endif /* __FreeBSD_version >= 500000 */ 1923 if (error) 1924 return error; 1925 if (c->mode == M_ASYNC) 1926 return EINVAL; 1927 s = splhigh (); 1928 cx_set_baud (c, *(long*)data); 1929 splx (s); 1930 return 0; 1931 1932 case SERIAL_GETLOOP: 1933 CX_DEBUG2 (d, ("ioctl: getloop\n")); 1934 if (c->mode == M_ASYNC) 1935 return EINVAL; 1936 s = splhigh (); 1937 *(int*)data = cx_get_loop (c); 1938 splx (s); 1939 return 0; 1940 1941 case SERIAL_SETLOOP: 1942 CX_DEBUG2 (d, ("ioctl: setloop\n")); 1943 /* Only for superuser! */ 1944#if __FreeBSD_version < 500000 1945 error = suser (p); 1946#else /* __FreeBSD_version >= 500000 */ 1947 error = suser (td); 1948#endif /* __FreeBSD_version >= 500000 */ 1949 if (error) 1950 return error; 1951 if (c->mode == M_ASYNC) 1952 return EINVAL; 1953 s = splhigh (); 1954 cx_set_loop (c, *(int*)data); 1955 splx (s); 1956 return 0; 1957 1958 case SERIAL_GETDPLL: 1959 CX_DEBUG2 (d, ("ioctl: getdpll\n")); 1960 if (c->mode == M_ASYNC) 1961 return EINVAL; 1962 s = splhigh (); 1963 *(int*)data = cx_get_dpll (c); 1964 splx (s); 1965 return 0; 1966 1967 case SERIAL_SETDPLL: 1968 CX_DEBUG2 (d, ("ioctl: setdpll\n")); 1969 /* Only for superuser! */ 1970#if __FreeBSD_version < 500000 1971 error = suser (p); 1972#else /* __FreeBSD_version >= 500000 */ 1973 error = suser (td); 1974#endif /* __FreeBSD_version >= 500000 */ 1975 if (error) 1976 return error; 1977 if (c->mode == M_ASYNC) 1978 return EINVAL; 1979 s = splhigh (); 1980 cx_set_dpll (c, *(int*)data); 1981 splx (s); 1982 return 0; 1983 1984 case SERIAL_GETNRZI: 1985 CX_DEBUG2 (d, ("ioctl: getnrzi\n")); 1986 if (c->mode == M_ASYNC) 1987 return EINVAL; 1988 s = splhigh (); 1989 *(int*)data = cx_get_nrzi (c); 1990 splx (s); 1991 return 0; 1992 1993 case SERIAL_SETNRZI: 1994 CX_DEBUG2 (d, ("ioctl: setnrzi\n")); 1995 /* Only for superuser! */ 1996#if __FreeBSD_version < 500000 1997 error = suser (p); 1998#else /* __FreeBSD_version >= 500000 */ 1999 error = suser (td); 2000#endif /* __FreeBSD_version >= 500000 */ 2001 if (error) 2002 return error; 2003 if (c->mode == M_ASYNC) 2004 return EINVAL; 2005 s = splhigh (); 2006 cx_set_nrzi (c, *(int*)data); 2007 splx (s); 2008 return 0; 2009 2010 case SERIAL_GETDEBUG: 2011 CX_DEBUG2 (d, ("ioctl: getdebug\n")); 2012 s = splhigh (); 2013 *(int*)data = c->debug; 2014 splx (s); 2015 return 0; 2016 2017 case SERIAL_SETDEBUG: 2018 CX_DEBUG2 (d, ("ioctl: setdebug\n")); 2019 /* Only for superuser! */ 2020#if __FreeBSD_version < 500000 2021 error = suser (p); 2022#else /* __FreeBSD_version >= 500000 */ 2023 error = suser (td); 2024#endif /* __FreeBSD_version >= 500000 */ 2025 if (error) 2026 return error; 2027 s = splhigh (); 2028 c->debug = *(int*)data; 2029 splx (s); 2030#ifndef NETGRAPH 2031 if (d->chan->debug) 2032 d->pp.pp_if.if_flags |= IFF_DEBUG; 2033 else 2034 d->pp.pp_if.if_flags &= (~IFF_DEBUG); 2035#endif 2036 return 0; 2037 } 2038 2039 if (c->mode == M_ASYNC && !IF_CUNIT(dev) && d->tty) { 2040#if __FreeBSD_version >= 502113 2041 error = ttyioctl (dev, cmd, data, flag, td); 2042 ttyldoptim (d->tty); 2043 if (error != ENOTTY) { 2044 if (error) 2045 CX_DEBUG2 (d, ("ttioctl: 0x%lx, error %d\n", cmd, error)); 2046 return error; 2047 } 2048#else 2049#if __FreeBSD_version >= 500000 2050 error = (*linesw[d->tty->t_line].l_ioctl) (d->tty, cmd, data, flag, td); 2051#else 2052 error = (*linesw[d->tty->t_line].l_ioctl) (d->tty, cmd, data, flag, p); 2053#endif 2054 ttyldoptim (d->tty); 2055 if (error != ENOIOCTL) { 2056 if (error) 2057 CX_DEBUG2 (d, ("l_ioctl: 0x%lx, error %d\n", cmd, error)); 2058 return error; 2059 } 2060 error = ttioctl (d->tty, cmd, data, flag); 2061 ttyldoptim (d->tty); 2062 if (error != ENOIOCTL) { 2063 if (error) 2064 CX_DEBUG2 (d, ("ttioctl: 0x%lx, error %d\n", cmd, error)); 2065 return error; 2066 } 2067#endif 2068 } 2069 2070 switch (cmd) { 2071 case TIOCSBRK: /* Start sending line break */ 2072 CX_DEBUG2 (d, ("ioctl: tiocsbrk\n")); 2073 s = splhigh (); 2074 cx_send_break (c, 500); 2075 splx (s); 2076 return 0; 2077 2078 case TIOCCBRK: /* Stop sending line break */ 2079 CX_DEBUG2 (d, ("ioctl: tioccbrk\n")); 2080 return 0; 2081 2082 case TIOCSDTR: /* Set DTR */ 2083 CX_DEBUG2 (d, ("ioctl: tiocsdtr\n")); 2084 s = splhigh (); 2085 cx_set_dtr (c, 1); 2086 splx (s); 2087 return 0; 2088 2089 case TIOCCDTR: /* Clear DTR */ 2090 CX_DEBUG2 (d, ("ioctl: tioccdtr\n")); 2091 s = splhigh (); 2092 cx_set_dtr (c, 0); 2093 splx (s); 2094 return 0; 2095 2096 case TIOCMSET: /* Set DTR/RTS */ 2097 CX_DEBUG2 (d, ("ioctl: tiocmset\n")); 2098 s = splhigh (); 2099 cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0); 2100 cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0); 2101 splx (s); 2102 return 0; 2103 2104 case TIOCMBIS: /* Add DTR/RTS */ 2105 CX_DEBUG2 (d, ("ioctl: tiocmbis\n")); 2106 s = splhigh (); 2107 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1); 2108 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1); 2109 splx (s); 2110 return 0; 2111 2112 case TIOCMBIC: /* Clear DTR/RTS */ 2113 CX_DEBUG2 (d, ("ioctl: tiocmbic\n")); 2114 s = splhigh (); 2115 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0); 2116 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0); 2117 splx (s); 2118 return 0; 2119 2120 case TIOCMGET: /* Get modem status */ 2121 CX_DEBUG2 (d, ("ioctl: tiocmget\n")); 2122 *(int*)data = cx_modem_status (d); 2123 return 0; 2124 2125 } 2126 CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd)); 2127 return ENOTTY; 2128} 2129 2130#if __FreeBSD_version < 502113 2131static void 2132ttyldoptim(tp) 2133 struct tty *tp; 2134{ 2135 struct termios *t; 2136 2137 t = &tp->t_termios; 2138 if (CONDITION(t,tp)) 2139 tp->t_state |= TS_CAN_BYPASS_L_RINT; 2140 else 2141 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2142} 2143#endif 2144 2145#if __FreeBSD_version >= 500000 2146void cx_softintr (void *unused) 2147#else 2148void cx_softintr () 2149#endif 2150{ 2151 drv_t *d; 2152 async_q *q; 2153 int i, s, ic, k; 2154 while (MY_SOFT_INTR) { 2155 MY_SOFT_INTR = 0; 2156 for (i=0; i<NCX*NCHAN; ++i) { 2157 d = channel [i]; 2158 if (!d || !d->chan || d->chan->type == T_NONE 2159 || d->chan->mode != M_ASYNC || !d->tty 2160 || !d->tty->t_dev) 2161 continue; 2162 s = splhigh (); 2163 if (d->intr_action & CX_READ) { 2164 q = &(d->aqueue); 2165 if (d->tty->t_state & TS_CAN_BYPASS_L_RINT) { 2166 k = AQ_GSZ(q); 2167 if (d->tty->t_rawq.c_cc + k > 2168 d->tty->t_ihiwat 2169 && (d->tty->t_cflag & CRTS_IFLOW 2170 || d->tty->t_iflag & IXOFF) 2171 && !(d->tty->t_state & TS_TBLOCK)) 2172 ttyblock(d->tty); 2173 d->tty->t_rawcc += k; 2174 while (k>0) { 2175 k--; 2176 AQ_POP (q, ic); 2177 splx (s); 2178 putc (ic, &d->tty->t_rawq); 2179 s = splhigh (); 2180 } 2181 ttwakeup(d->tty); 2182 if (d->tty->t_state & TS_TTSTOP 2183 && (d->tty->t_iflag & IXANY 2184 || d->tty->t_cc[VSTART] == 2185 d->tty->t_cc[VSTOP])) { 2186 d->tty->t_state &= ~TS_TTSTOP; 2187 d->tty->t_lflag &= ~FLUSHO; 2188 d->intr_action |= CX_WRITE; 2189 } 2190 } else { 2191 while (q->end != q->beg) { 2192 AQ_POP (q, ic); 2193 splx (s); 2194 ttyld_rint (d->tty, ic); 2195 s = splhigh (); 2196 } 2197 } 2198 d->intr_action &= ~CX_READ; 2199 } 2200 splx (s); 2201 2202 s = splhigh (); 2203 if (d->intr_action & CX_WRITE) { 2204 if (d->tty->t_line) 2205 ttyld_start (d->tty); 2206 else 2207 cx_oproc (d->tty); 2208 d->intr_action &= ~CX_WRITE; 2209 } 2210 splx (s); 2211 2212 } 2213 } 2214} 2215 2216/* 2217 * Fill transmitter buffer with data. 2218 */ 2219static void cx_oproc (struct tty *tp) 2220{ 2221 int s = splhigh (), k; 2222 drv_t *d = channel [UNIT (tp->t_dev)]; 2223 static u_char buf[DMABUFSZ]; 2224 u_char *p; 2225 u_short len = 0, sublen = 0; 2226 2227 if (!d) { 2228 splx (s); 2229 return; 2230 } 2231 2232 CX_DEBUG2 (d, ("cx_oproc\n")); 2233 if (tp->t_cflag & CRTSCTS && (tp->t_state & TS_TBLOCK) && d->chan->rts) 2234 cx_set_rts (d->chan, 0); 2235 else if (tp->t_cflag & CRTSCTS && ! (tp->t_state & TS_TBLOCK) && ! d->chan->rts) 2236 cx_set_rts (d->chan, 1); 2237 2238 if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) { 2239 /* Start transmitter. */ 2240 cx_enable_transmit (d->chan, 1); 2241 2242 /* Is it busy? */ 2243 if (! cx_buf_free (d->chan)) { 2244 tp->t_state |= TS_BUSY; 2245 splx (s); 2246 return; 2247 } 2248 if (tp->t_iflag & IXOFF) { 2249 p = (buf + (DMABUFSZ/2)); 2250 sublen = q_to_b (&tp->t_outq, p, (DMABUFSZ/2)); 2251 k = sublen; 2252 while (k--) { 2253 /* Send XON/XOFF out of band. */ 2254 if (*p == tp->t_cc[VSTOP]) { 2255 cx_xflow_ctl (d->chan, 0); 2256 p++; 2257 continue; 2258 } 2259 if (*p == tp->t_cc[VSTART]) { 2260 cx_xflow_ctl (d->chan, 1); 2261 p++; 2262 continue; 2263 } 2264 buf[len] = *p; 2265 len++; 2266 p++; 2267 } 2268 } else { 2269 p = buf; 2270 len = q_to_b (&tp->t_outq, p, (DMABUFSZ/2)); 2271 } 2272 if (len) { 2273 cx_send_packet (d->chan, buf, len, 0); 2274 tp->t_state |= TS_BUSY; 2275 d->atimeout = 10; 2276 CX_DEBUG2 (d, ("out %d bytes\n", len)); 2277 } 2278 } 2279 ttwwakeup (tp); 2280 splx (s); 2281} 2282 2283static int cx_param (struct tty *tp, struct termios *t) 2284{ 2285 drv_t *d = channel [UNIT (tp->t_dev)]; 2286 int s, bits, parity; 2287 2288 if (!d) 2289 return EINVAL; 2290 2291 s = splhigh (); 2292 if (t->c_ospeed == 0) { 2293 /* Clear DTR and RTS. */ 2294 cx_set_dtr (d->chan, 0); 2295 splx (s); 2296 CX_DEBUG2 (d, ("cx_param (hangup)\n")); 2297 return 0; 2298 } 2299 CX_DEBUG2 (d, ("cx_param\n")); 2300 2301 /* Check requested parameters. */ 2302 if (t->c_ospeed < 300 || t->c_ospeed > 256*1024) { 2303 splx (s); 2304 return EINVAL; 2305 } 2306 if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024)) { 2307 splx (s); 2308 return EINVAL; 2309 } 2310 2311 /* And copy them to tty and channel structures. */ 2312 tp->t_ispeed = t->c_ispeed = tp->t_ospeed = t->c_ospeed; 2313 tp->t_cflag = t->c_cflag; 2314 2315 /* Set character length and parity mode. */ 2316 switch (t->c_cflag & CSIZE) { 2317 default: 2318 case CS8: bits = 8; break; 2319 case CS7: bits = 7; break; 2320 case CS6: bits = 6; break; 2321 case CS5: bits = 5; break; 2322 } 2323 2324 parity = ((t->c_cflag & PARENB) ? 1 : 0) * 2325 (1 + ((t->c_cflag & PARODD) ? 0 : 1)); 2326 2327 /* Set current channel number. */ 2328 if (! d->chan->dtr) 2329 cx_set_dtr (d->chan, 1); 2330 2331 ttyldoptim (tp); 2332 cx_set_async_param (d->chan, t->c_ospeed, bits, parity, (t->c_cflag & CSTOPB), 2333 !(t->c_cflag & PARENB), (t->c_cflag & CRTSCTS), 2334 (t->c_iflag & IXON), (t->c_iflag & IXANY), 2335 t->c_cc[VSTART], t->c_cc[VSTOP]); 2336 splx (s); 2337 return 0; 2338} 2339 2340/* 2341 * Stop output on a line 2342 */ 2343static void cx_stop (struct tty *tp, int flag) 2344{ 2345 drv_t *d = channel [UNIT (tp->t_dev)]; 2346 int s; 2347 2348 if (!d) 2349 return; 2350 2351 s = splhigh (); 2352 2353 if (tp->t_state & TS_BUSY) { 2354 /* Stop transmitter */ 2355 CX_DEBUG2 (d, ("cx_stop\n")); 2356 cx_transmitter_ctl (d->chan, 0); 2357 } 2358 splx (s); 2359} 2360 2361/* 2362 * Process the (delayed) carrier signal setup. 2363 */ 2364static void cx_carrier (void *arg) 2365{ 2366 drv_t *d = arg; 2367 cx_chan_t *c = d->chan; 2368 int s, cd; 2369 2370 s = splhigh (); 2371 cd = cx_get_cd (c); 2372 if (d->cd != cd) { 2373 if (cd) { 2374 CX_DEBUG (d, ("carrier on\n")); 2375 d->cd = 1; 2376 splx (s); 2377 if (d->tty) 2378 ttyld_modem(d->tty, 1); 2379 } else { 2380 CX_DEBUG (d, ("carrier loss\n")); 2381 d->cd = 0; 2382 splx (s); 2383 if (d->tty) 2384 ttyld_modem(d->tty, 0); 2385 } 2386 } 2387} 2388 2389/* 2390 * Modem signal callback function. 2391 */ 2392static void cx_modem (cx_chan_t *c) 2393{ 2394 drv_t *d = c->sys; 2395 2396 if (!d || c->mode != M_ASYNC) 2397 return; 2398 /* Handle carrier detect/loss. */ 2399 untimeout (cx_carrier, c, d->dcd_timeout_handle); 2400 /* Carrier changed - delay processing DCD for a while 2401 * to give both sides some time to initialize. */ 2402 d->dcd_timeout_handle = timeout (cx_carrier, d, hz/2); 2403} 2404 2405#if __FreeBSD_version < 500000 2406static struct cdevsw cx_cdevsw = { 2407 cx_open, cx_close, cx_read, cx_write, 2408 cx_ioctl, ttypoll, nommap, nostrategy, 2409 "cx", CDEV_MAJOR, nodump, nopsize, 2410 D_TTY, -1 2411}; 2412#elif __FreeBSD_version == 500000 2413static struct cdevsw cx_cdevsw = { 2414 cx_open, cx_close, cx_read, cx_write, 2415 cx_ioctl, ttypoll, nommap, nostrategy, 2416 "cx", CDEV_MAJOR, nodump, nopsize, 2417 D_TTY, 2418 }; 2419#elif __FreeBSD_version <= 501000 2420static struct cdevsw cx_cdevsw = { 2421 .d_open = cx_open, 2422 .d_close = cx_close, 2423 .d_read = cx_read, 2424 .d_write = cx_write, 2425 .d_ioctl = cx_ioctl, 2426 .d_poll = ttypoll, 2427 .d_mmap = nommap, 2428 .d_strategy = nostrategy, 2429 .d_name = "cx", 2430 .d_maj = CDEV_MAJOR, 2431 .d_dump = nodump, 2432 .d_flags = D_TTY, 2433}; 2434#elif __FreeBSD_version < 502103 2435static struct cdevsw cx_cdevsw = { 2436 .d_open = cx_open, 2437 .d_close = cx_close, 2438 .d_read = cx_read, 2439 .d_write = cx_write, 2440 .d_ioctl = cx_ioctl, 2441 .d_poll = ttypoll, 2442 .d_name = "cx", 2443 .d_maj = CDEV_MAJOR, 2444 .d_flags = D_TTY, 2445}; 2446#else /* __FreeBSD_version >= 502103 */ 2447static struct cdevsw cx_cdevsw = { 2448 .d_version = D_VERSION, 2449 .d_open = cx_open, 2450 .d_close = cx_close, 2451 .d_read = cx_read, 2452 .d_write = cx_write, 2453 .d_ioctl = cx_ioctl, 2454 .d_name = "cx", 2455 .d_maj = CDEV_MAJOR, 2456 .d_flags = D_TTY | D_NEEDGIANT, 2457}; 2458#endif 2459 2460#ifdef NETGRAPH 2461#if __FreeBSD_version >= 500000 2462static int ng_cx_constructor (node_p node) 2463{ 2464 drv_t *d = NG_NODE_PRIVATE (node); 2465#else 2466static int ng_cx_constructor (node_p *node) 2467{ 2468 drv_t *d = (*node)->private; 2469#endif 2470 CX_DEBUG (d, ("Constructor\n")); 2471 return EINVAL; 2472} 2473 2474static int ng_cx_newhook (node_p node, hook_p hook, const char *name) 2475{ 2476 int s; 2477#if __FreeBSD_version >= 500000 2478 drv_t *d = NG_NODE_PRIVATE (node); 2479#else 2480 drv_t *d = node->private; 2481#endif 2482 2483 if (d->chan->mode == M_ASYNC) 2484 return EINVAL; 2485 2486 /* Attach debug hook */ 2487 if (strcmp (name, NG_CX_HOOK_DEBUG) == 0) { 2488#if __FreeBSD_version >= 500000 2489 NG_HOOK_SET_PRIVATE (hook, NULL); 2490#else 2491 hook->private = 0; 2492#endif 2493 d->debug_hook = hook; 2494 return 0; 2495 } 2496 2497 /* Check for raw hook */ 2498 if (strcmp (name, NG_CX_HOOK_RAW) != 0) 2499 return EINVAL; 2500 2501#if __FreeBSD_version >= 500000 2502 NG_HOOK_SET_PRIVATE (hook, d); 2503#else 2504 hook->private = d; 2505#endif 2506 d->hook = hook; 2507 s = splhigh (); 2508 cx_up (d); 2509 splx (s); 2510 return 0; 2511} 2512 2513static int print_modems (char *s, cx_chan_t *c, int need_header) 2514{ 2515 int status = cx_modem_status (c->sys); 2516 int length = 0; 2517 2518 if (need_header) 2519 length += sprintf (s + length, " LE DTR DSR RTS CTS CD\n"); 2520 length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n", 2521 status & TIOCM_LE ? "On" : "-", 2522 status & TIOCM_DTR ? "On" : "-", 2523 status & TIOCM_DSR ? "On" : "-", 2524 status & TIOCM_RTS ? "On" : "-", 2525 status & TIOCM_CTS ? "On" : "-", 2526 status & TIOCM_CD ? "On" : "-"); 2527 return length; 2528} 2529 2530static int print_stats (char *s, cx_chan_t *c, int need_header) 2531{ 2532 int length = 0; 2533 2534 if (need_header) 2535 length += sprintf (s + length, " Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); 2536 length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n", 2537 c->rintr, c->tintr, c->mintr, c->ibytes, c->ipkts, 2538 c->ierrs, c->obytes, c->opkts, c->oerrs); 2539 return length; 2540} 2541 2542static int print_chan (char *s, cx_chan_t *c) 2543{ 2544 drv_t *d = c->sys; 2545 int length = 0; 2546 2547 length += sprintf (s + length, "cx%d", c->board->num * NCHAN + c->num); 2548 if (d->chan->debug) 2549 length += sprintf (s + length, " debug=%d", d->chan->debug); 2550 2551 if (cx_get_baud (c)) 2552 length += sprintf (s + length, " %ld", cx_get_baud (c)); 2553 else 2554 length += sprintf (s + length, " extclock"); 2555 2556 if (c->mode == M_HDLC) { 2557 length += sprintf (s + length, " dpll=%s", cx_get_dpll (c) ? "on" : "off"); 2558 length += sprintf (s + length, " nrzi=%s", cx_get_nrzi (c) ? "on" : "off"); 2559 } 2560 2561 length += sprintf (s + length, " loop=%s", cx_get_loop (c) ? "on\n" : "off\n"); 2562 return length; 2563} 2564 2565#if __FreeBSD_version >= 500000 2566static int ng_cx_rcvmsg (node_p node, item_p item, hook_p lasthook) 2567{ 2568 drv_t *d = NG_NODE_PRIVATE (node); 2569 struct ng_mesg *msg; 2570#else 2571static int ng_cx_rcvmsg (node_p node, struct ng_mesg *msg, 2572 const char *retaddr, struct ng_mesg **rptr) 2573{ 2574 drv_t *d = node->private; 2575#endif 2576 struct ng_mesg *resp = NULL; 2577 int error = 0; 2578 2579 if (!d) 2580 return EINVAL; 2581 2582 CX_DEBUG (d, ("Rcvmsg\n")); 2583#if __FreeBSD_version >= 500000 2584 NGI_GET_MSG (item, msg); 2585#endif 2586 switch (msg->header.typecookie) { 2587 default: 2588 error = EINVAL; 2589 break; 2590 2591 case NGM_CX_COOKIE: 2592 printf ("Don't forget to implement\n"); 2593 error = EINVAL; 2594 break; 2595 2596 case NGM_GENERIC_COOKIE: 2597 switch (msg->header.cmd) { 2598 default: 2599 error = EINVAL; 2600 break; 2601 2602 case NGM_TEXT_STATUS: { 2603 char *s; 2604 int l = 0; 2605 int dl = sizeof (struct ng_mesg) + 730; 2606 2607#if __FreeBSD_version >= 500000 2608 NG_MKRESPONSE (resp, msg, dl, M_NOWAIT); 2609 if (! resp) { 2610 error = ENOMEM; 2611 break; 2612 } 2613#else 2614 MALLOC (resp, struct ng_mesg *, dl, 2615 M_NETGRAPH, M_NOWAIT); 2616 if (! resp) { 2617 error = ENOMEM; 2618 break; 2619 } 2620#endif 2621 bzero (resp, dl); 2622 s = (resp)->data; 2623 l += print_chan (s + l, d->chan); 2624 l += print_stats (s + l, d->chan, 1); 2625 l += print_modems (s + l, d->chan, 1); 2626#if __FreeBSD_version < 500000 2627 (resp)->header.version = NG_VERSION; 2628 (resp)->header.arglen = strlen (s) + 1; 2629 (resp)->header.token = msg->header.token; 2630 (resp)->header.typecookie = NGM_CX_COOKIE; 2631 (resp)->header.cmd = msg->header.cmd; 2632#endif 2633 strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN); 2634 } 2635 break; 2636 } 2637 break; 2638 } 2639#if __FreeBSD_version >= 500000 2640 NG_RESPOND_MSG (error, node, item, resp); 2641 NG_FREE_MSG (msg); 2642#else 2643 *rptr = resp; 2644 FREE (msg, M_NETGRAPH); 2645#endif 2646 return error; 2647} 2648 2649#if __FreeBSD_version >= 500000 2650static int ng_cx_rcvdata (hook_p hook, item_p item) 2651{ 2652 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook)); 2653 struct mbuf *m; 2654 struct ng_tag_prio *ptag; 2655#else 2656static int ng_cx_rcvdata (hook_p hook, struct mbuf *m, meta_p meta) 2657{ 2658 drv_t *d = hook->node->private; 2659#endif 2660 struct ifqueue *q; 2661 int s; 2662 2663#if __FreeBSD_version >= 500000 2664 NGI_GET_M (item, m); 2665 NG_FREE_ITEM (item); 2666 if (! NG_HOOK_PRIVATE (hook) || ! d) { 2667 NG_FREE_M (m); 2668#else 2669 if (! hook->private || ! d) { 2670 NG_FREE_DATA (m,meta); 2671#endif 2672 return ENETDOWN; 2673 } 2674 2675 /* Check for high priority data */ 2676 if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE, 2677 NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) ) 2678 q = &d->hi_queue; 2679 else 2680 q = &d->lo_queue; 2681 2682 s = splhigh (); 2683#if __FreeBSD_version >= 500000 2684 IF_LOCK (q); 2685 if (_IF_QFULL (q)) { 2686 _IF_DROP (q); 2687 IF_UNLOCK (q); 2688 splx (s); 2689 NG_FREE_M (m); 2690 return ENOBUFS; 2691 } 2692 _IF_ENQUEUE (q, m); 2693 IF_UNLOCK (q); 2694#else 2695 if (IF_QFULL (q)) { 2696 IF_DROP (q); 2697 splx (s); 2698 NG_FREE_DATA (m, meta); 2699 return ENOBUFS; 2700 } 2701 IF_ENQUEUE (q, m); 2702#endif 2703 cx_start (d); 2704 splx (s); 2705 return 0; 2706} 2707 2708static int ng_cx_rmnode (node_p node) 2709{ 2710#if __FreeBSD_version >= 500000 2711 drv_t *d = NG_NODE_PRIVATE (node); 2712 2713 CX_DEBUG (d, ("Rmnode\n")); 2714 if (d && d->running) { 2715 int s = splhigh (); 2716 cx_down (d); 2717 splx (s); 2718 } 2719#ifdef KLD_MODULE 2720 if (node->nd_flags & NGF_REALLY_DIE) { 2721 NG_NODE_SET_PRIVATE (node, NULL); 2722 NG_NODE_UNREF (node); 2723 } 2724 NG_NODE_REVIVE(node); /* Persistant node */ 2725#endif 2726#else /* __FreeBSD_version < 500000 */ 2727 drv_t *d = node->private; 2728 int s; 2729 2730 s = splhigh (); 2731 cx_down (d); 2732 splx (s); 2733 node->flags |= NG_INVALID; 2734 ng_cutlinks (node); 2735#ifdef KLD_MODULE 2736 ng_unname (node); 2737 ng_unref (node); 2738#else 2739 node->flags &= ~NG_INVALID; 2740#endif 2741#endif 2742 return 0; 2743} 2744 2745static void ng_cx_watchdog (void *arg) 2746{ 2747 drv_t *d = arg; 2748 2749 if (d->timeout == 1) 2750 cx_watchdog (d); 2751 if (d->timeout) 2752 d->timeout--; 2753 d->timeout_handle = timeout (ng_cx_watchdog, d, hz); 2754} 2755 2756static int ng_cx_connect (hook_p hook) 2757{ 2758#if __FreeBSD_version >= 500000 2759 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2760#else 2761 drv_t *d = hook->node->private; 2762#endif 2763 2764 d->timeout_handle = timeout (ng_cx_watchdog, d, hz); 2765 return 0; 2766} 2767 2768static int ng_cx_disconnect (hook_p hook) 2769{ 2770#if __FreeBSD_version >= 500000 2771 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 2772#else 2773 drv_t *d = hook->node->private; 2774#endif 2775 int s; 2776 2777 s = splhigh (); 2778#if __FreeBSD_version >= 500000 2779 if (NG_HOOK_PRIVATE (hook)) 2780#else 2781 if (hook->private) 2782#endif 2783 cx_down (d); 2784 splx (s); 2785 untimeout (ng_cx_watchdog, d, d->timeout_handle); 2786 return 0; 2787} 2788#endif /*NETGRAPH*/ 2789 2790static int cx_modevent (module_t mod, int type, void *unused) 2791{ 2792 struct cdev *dev; 2793 static int load_count = 0; 2794 struct cdevsw *cdsw; 2795 2796#if __FreeBSD_version >= 502103 2797 dev = findcdev (makedev(CDEV_MAJOR, 0)); 2798#else 2799 dev = makedev (CDEV_MAJOR, 0); 2800#endif 2801 switch (type) { 2802 case MOD_LOAD: 2803 if (dev != NULL && 2804 (cdsw = devsw (dev)) && 2805 cdsw->d_maj == CDEV_MAJOR) { 2806 printf ("Sigma driver is already in system\n"); 2807 return (EEXIST); 2808 } 2809#if __FreeBSD_version >= 500000 && defined NETGRAPH 2810 if (ng_newtype (&typestruct)) 2811 printf ("Failed to register ng_cx\n"); 2812#endif 2813 ++load_count; 2814#if __FreeBSD_version <= 500000 2815 cdevsw_add (&cx_cdevsw); 2816#endif 2817 timeout_handle = timeout (cx_timeout, 0, hz*5); 2818 /* Software interrupt. */ 2819#if __FreeBSD_version < 500000 2820 register_swi (SWI_TTY, cx_softintr); 2821#else 2822 swi_add(&tty_ithd, "cx", cx_softintr, NULL, SWI_TTY, 0, 2823 &cx_fast_ih); 2824#endif 2825 break; 2826 case MOD_UNLOAD: 2827 if (load_count == 1) { 2828 printf ("Removing device entry for Sigma\n"); 2829#if __FreeBSD_version <= 500000 2830 cdevsw_remove (&cx_cdevsw); 2831#endif 2832#if __FreeBSD_version >= 500000 && defined NETGRAPH 2833 ng_rmtype (&typestruct); 2834#endif 2835 } 2836 if (timeout_handle.callout) 2837 untimeout (cx_timeout, 0, timeout_handle); 2838#if __FreeBSD_version >= 500000 2839 ithread_remove_handler (cx_fast_ih); 2840#else 2841 unregister_swi (SWI_TTY, cx_softintr); 2842#endif 2843 --load_count; 2844 break; 2845 case MOD_SHUTDOWN: 2846 break; 2847 } 2848 return 0; 2849} 2850 2851#ifdef NETGRAPH 2852static struct ng_type typestruct = { 2853 .version = NG_ABI_VERSION, 2854 .name = NG_CX_NODE_TYPE, 2855 .constructor = ng_cx_constructor, 2856 .rcvmsg = ng_cx_rcvmsg, 2857 .shutdown = ng_cx_rmnode, 2858 .newhook = ng_cx_newhook, 2859 .connect = ng_cx_connect, 2860 .rcvdata = ng_cx_rcvdata, 2861 .disconnect = ng_cx_disconnect, 2862}; 2863#endif /*NETGRAPH*/ 2864 2865#if __FreeBSD_version >= 500000 2866#ifdef NETGRAPH 2867MODULE_DEPEND (ng_cx, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 2868#else 2869MODULE_DEPEND (isa_cx, sppp, 1, 1, 1); 2870#endif 2871#ifdef KLD_MODULE 2872DRIVER_MODULE (cxmod, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL); 2873#else 2874DRIVER_MODULE (cx, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL); 2875#endif 2876#elif __FreeBSD_version >= 400000 2877#ifdef NETGRAPH 2878DRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, ng_mod_event, &typestruct); 2879#else 2880DRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, cx_modevent, 0); 2881#endif 2882#endif /* __FreeBSD_version >= 400000 */ 2883#endif /* NCX */ 2884