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