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