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