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