]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/cp/if_cp.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / cp / if_cp.c
1 /*-
2  * Cronyx-Tau-PCI adapter driver for FreeBSD.
3  * Supports PPP/HDLC, Cisco/HDLC and FrameRelay 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) 1999-2004 Cronyx Engineering.
8  * Author: Kurakin Roman, <rik@cronyx.ru>
9  *
10  * Copyright (C) 1999-2002 Cronyx Engineering.
11  * Author: Serge Vakulenko, <vak@cronyx.ru>
12  *
13  * This software is distributed with NO WARRANTIES, not even the implied
14  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * Authors grant any other persons or organisations a permission to use,
17  * modify and redistribute this software in source and binary forms,
18  * as long as this message is kept with the software, all derivative
19  * works or modified versions.
20  *
21  * Cronyx Id: if_cp.c,v 1.1.2.41 2004/06/23 17:09:13 rik Exp $
22  */
23
24 #include <sys/cdefs.h>
25 __FBSDID("$FreeBSD$");
26
27 #include <sys/param.h>
28 #include <sys/ucred.h>
29 #include <sys/proc.h>
30 #include <sys/systm.h>
31 #include <sys/mbuf.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/conf.h>
35 #include <sys/malloc.h>
36 #include <sys/priv.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/sysctl.h>
40 #include <sys/tty.h>
41 #include <sys/bus.h>
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44 #include <net/if.h>
45 #include <dev/pci/pcivar.h>
46 #include <dev/pci/pcireg.h>
47 #include <machine/bus.h>
48 #include <sys/rman.h>
49 #include "opt_ng_cronyx.h"
50 #ifdef NETGRAPH_CRONYX
51 #   include "opt_netgraph.h"
52 #   ifndef NETGRAPH
53 #       error #option   NETGRAPH missed from configuration
54 #   endif
55 #   include <netgraph/ng_message.h>
56 #   include <netgraph/netgraph.h>
57 #   include <dev/cp/ng_cp.h>
58 #else
59 #   include <net/if_sppp.h>
60 #   include <net/if_types.h>
61 #include <dev/pci/pcivar.h>
62 #   define PP_CISCO IFF_LINK2
63 #   include <net/bpf.h>
64 #endif
65 #include <dev/cx/machdep.h>
66 #include <dev/cp/cpddk.h>
67 #include <machine/cserial.h>
68 #include <machine/resource.h>
69 #include <machine/pmap.h>
70
71 /* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
72 #ifndef PP_FR
73 #define PP_FR 0
74 #endif
75
76 #define CP_DEBUG(d,s)   ({if (d->chan->debug) {\
77                                 printf ("%s: ", d->name); printf s;}})
78 #define CP_DEBUG2(d,s)  ({if (d->chan->debug>1) {\
79                                 printf ("%s: ", d->name); printf s;}})
80 #define CP_LOCK_NAME    "cpX"
81
82 static  int     cp_mpsafenet = 1;
83 TUNABLE_INT("debug.cp.mpsafenet", &cp_mpsafenet);
84 SYSCTL_NODE(_debug, OID_AUTO, cp, CTLFLAG_RD, 0, "Cronyx Tau-PCI Adapters");
85 SYSCTL_INT(_debug_cp, OID_AUTO, mpsafenet, CTLFLAG_RD, &cp_mpsafenet, 0,
86         "Enable/disable MPSAFE network support for Cronyx Tau-PCI Adapters");
87
88 #define CP_LOCK(_bd)            do { \
89                                     if (cp_mpsafenet) \
90                                         mtx_lock (&(_bd)->cp_mtx); \
91                                 } while (0)
92 #define CP_UNLOCK(_bd)          do { \
93                                     if (cp_mpsafenet) \
94                                         mtx_unlock (&(_bd)->cp_mtx); \
95                                 } while (0)
96
97 #define CP_LOCK_ASSERT(_bd)     do { \
98                                     if (cp_mpsafenet) \
99                                         mtx_assert (&(_bd)->cp_mtx, MA_OWNED); \
100                                 } while (0)
101
102 static  int cp_probe            __P((device_t));
103 static  int cp_attach           __P((device_t));
104 static  int cp_detach           __P((device_t));
105
106 static  device_method_t cp_methods[] = {
107         /* Device interface */
108         DEVMETHOD(device_probe,         cp_probe),
109         DEVMETHOD(device_attach,        cp_attach),
110         DEVMETHOD(device_detach,        cp_detach),
111
112         {0, 0}
113 };
114
115 typedef struct _cp_dma_mem_t {
116         unsigned long   phys;
117         void            *virt;
118         size_t          size;
119         bus_dma_tag_t   dmat;
120         bus_dmamap_t    mapp;
121 } cp_dma_mem_t;
122
123 typedef struct _drv_t {
124         char    name [8];
125         int     running;
126         cp_chan_t       *chan;
127         cp_board_t      *board;
128         cp_dma_mem_t    dmamem;
129 #ifdef NETGRAPH
130         char    nodename [NG_NODELEN+1];
131         hook_p  hook;
132         hook_p  debug_hook;
133         node_p  node;
134         struct  ifqueue queue;
135         struct  ifqueue hi_queue;
136         short   timeout;
137         struct  callout timeout_handle;
138 #else
139         struct  ifqueue queue;
140         struct  ifnet *ifp;
141 #endif
142         struct  cdev *devt;
143 } drv_t;
144
145 typedef struct _bdrv_t {
146         cp_board_t      *board;
147         struct resource *cp_res;
148         struct resource *cp_irq;
149         void            *cp_intrhand;
150         cp_dma_mem_t    dmamem;
151         drv_t           channel [NCHAN];
152         struct mtx      cp_mtx;
153 } bdrv_t;
154
155 static  driver_t cp_driver = {
156         "cp",
157         cp_methods,
158         sizeof(bdrv_t),
159 };
160
161 static  devclass_t cp_devclass;
162
163 static void cp_receive (cp_chan_t *c, unsigned char *data, int len);
164 static void cp_transmit (cp_chan_t *c, void *attachment, int len);
165 static void cp_error (cp_chan_t *c, int data);
166 static void cp_up (drv_t *d);
167 static void cp_start (drv_t *d);
168 static void cp_down (drv_t *d);
169 static void cp_watchdog (drv_t *d);
170 #ifdef NETGRAPH
171 extern struct ng_type typestruct;
172 #else
173 static void cp_ifstart (struct ifnet *ifp);
174 static void cp_tlf (struct sppp *sp);
175 static void cp_tls (struct sppp *sp);
176 static void cp_ifwatchdog (struct ifnet *ifp);
177 static int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
178 static void cp_initialize (void *softc);
179 #endif
180
181 static cp_board_t *adapter [NBRD];
182 static drv_t *channel [NBRD*NCHAN];
183 static struct callout led_timo [NBRD];
184 static struct callout timeout_handle;
185
186 static int cp_destroy = 0;
187
188 static int cp_open (struct cdev *dev, int oflags, int devtype, struct thread *td);
189 static int cp_close (struct cdev *dev, int fflag, int devtype, struct thread *td);
190 static int cp_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td);
191 static struct cdevsw cp_cdevsw = {
192         .d_version  = D_VERSION,
193         .d_open     = cp_open,
194         .d_close    = cp_close,
195         .d_ioctl    = cp_ioctl,
196         .d_name     = "cp",
197         .d_flags    = D_NEEDGIANT,
198 };
199
200 /*
201  * Print the mbuf chain, for debug purposes only.
202  */
203 static void printmbuf (struct mbuf *m)
204 {
205         printf ("mbuf:");
206         for (; m; m=m->m_next) {
207                 if (m->m_flags & M_PKTHDR)
208                         printf (" HDR %d:", m->m_pkthdr.len);
209                 if (m->m_flags & M_EXT)
210                         printf (" EXT:");
211                 printf (" %d", m->m_len);
212         }
213         printf ("\n");
214 }
215
216 /*
217  * Make an mbuf from data.
218  */
219 static struct mbuf *makembuf (void *buf, unsigned len)
220 {
221         struct mbuf *m;
222
223         MGETHDR (m, M_DONTWAIT, MT_DATA);
224         if (! m)
225                 return 0;
226         MCLGET (m, M_DONTWAIT);
227         if (! (m->m_flags & M_EXT)) {
228                 m_freem (m);
229                 return 0;
230         }
231         m->m_pkthdr.len = m->m_len = len;
232         bcopy (buf, mtod (m, caddr_t), len);
233         return m;
234 }
235
236 static int cp_probe (device_t dev)
237 {
238         if ((pci_get_vendor (dev) == cp_vendor_id) &&
239             (pci_get_device (dev) == cp_device_id)) {
240                 device_set_desc (dev, "Cronyx-Tau-PCI serial adapter");
241                 return BUS_PROBE_DEFAULT;
242         }
243         return ENXIO;
244 }
245
246 static void cp_timeout (void *arg)
247 {
248         drv_t *d;
249         int s, i, k;
250
251         for (i = 0; i < NBRD; ++i) {
252                 if (adapter[i] == NULL)
253                         continue;
254                 for (k = 0; k < NCHAN; ++k) {
255                         s = splimp ();
256                         if (cp_destroy) {
257                                 splx (s);
258                                 return;
259                         }
260                         d = channel[i * NCHAN + k];
261                         if (!d) {
262                                 splx (s);
263                                 continue;
264                         }
265                         CP_LOCK ((bdrv_t *)d->board->sys);
266                         switch (d->chan->type) {
267                         case T_G703:
268                                 cp_g703_timer (d->chan);
269                                 break;
270                         case T_E1:
271                                 cp_e1_timer (d->chan);
272                                 break;
273                         case T_E3:
274                         case T_T3:
275                         case T_STS1:
276                                 cp_e3_timer (d->chan);
277                                 break;
278                         default:
279                                 break;
280                         }
281                         CP_UNLOCK ((bdrv_t *)d->board->sys);
282                         splx (s);
283                 }
284         }
285         s = splimp ();
286         if (!cp_destroy)
287                 callout_reset (&timeout_handle, hz, cp_timeout, 0);
288         splx (s);
289 }
290
291 static void cp_led_off (void *arg)
292 {
293         cp_board_t *b = arg;
294         bdrv_t *bd = (bdrv_t *) b->sys;
295         int s;
296         s = splimp ();
297         if (cp_destroy) {
298                 splx (s);
299                 return;
300         }
301         CP_LOCK (bd);
302         cp_led (b, 0);
303         CP_UNLOCK (bd);
304         splx (s);
305 }
306
307 static void cp_intr (void *arg)
308 {
309         bdrv_t *bd = arg;
310         cp_board_t *b = bd->board;
311 #ifndef NETGRAPH
312         int i;
313 #endif
314         int s = splimp ();
315         if (cp_destroy) {
316                 splx (s);
317                 return;
318         }
319         CP_LOCK (bd);
320         /* Check if we are ready */
321         if (b->sys == NULL) {
322                 /* Not we are not, just cleanup. */
323                 cp_interrupt_poll (b, 1);
324                 CP_UNLOCK (bd);
325                 return;
326         }
327         /* Turn LED on. */
328         cp_led (b, 1);
329
330         cp_interrupt (b);
331
332         /* Turn LED off 50 msec later. */
333         callout_reset (&led_timo[b->num], hz/20, cp_led_off, b);
334         CP_UNLOCK (bd);
335         splx (s);
336
337 #ifndef NETGRAPH
338         /* Pass packets in a lock-free state */
339         for (i = 0; i < NCHAN && b->chan[i].type; i++) {
340                 drv_t *d = b->chan[i].sys;
341                 struct mbuf *m;
342                 if (!d || !d->running)
343                         continue;
344                 while (_IF_QLEN(&d->queue)) {
345                         IF_DEQUEUE (&d->queue,m);
346                         if (!m)
347                                 continue;
348                         sppp_input (d->ifp, m); 
349                 }
350         }
351 #endif
352 }
353
354 static void
355 cp_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
356 {
357         unsigned long *addr;
358
359         if (error)
360                 return;
361
362         KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
363         addr = arg;
364         *addr = segs->ds_addr;
365 }
366
367 static int
368 cp_bus_dma_mem_alloc (int bnum, int cnum, cp_dma_mem_t *dmem)
369 {
370         int error;
371
372         error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT,
373                 BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
374                 dmem->size, 0, NULL, NULL, &dmem->dmat);
375         if (error) {
376                 if (cnum >= 0)  printf ("cp%d-%d: ", bnum, cnum);
377                 else            printf ("cp%d: ", bnum);
378                 printf ("couldn't allocate tag for dma memory\n");
379                 return 0;
380         }
381         error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
382                 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
383         if (error) {
384                 if (cnum >= 0)  printf ("cp%d-%d: ", bnum, cnum);
385                 else            printf ("cp%d: ", bnum);
386                 printf ("couldn't allocate mem for dma memory\n");
387                 bus_dma_tag_destroy (dmem->dmat);
388                 return 0;
389         }
390         error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
391                 dmem->size, cp_bus_dmamap_addr, &dmem->phys, 0);
392         if (error) {
393                 if (cnum >= 0)  printf ("cp%d-%d: ", bnum, cnum);
394                 else            printf ("cp%d: ", bnum);
395                 printf ("couldn't load mem map for dma memory\n");
396                 bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
397                 bus_dma_tag_destroy (dmem->dmat);
398                 return 0;
399         }
400         return 1;
401 }
402
403 static void
404 cp_bus_dma_mem_free (cp_dma_mem_t *dmem)
405 {
406         bus_dmamap_unload (dmem->dmat, dmem->mapp);
407         bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
408         bus_dma_tag_destroy (dmem->dmat);
409 }
410
411 /*
412  * Called if the probe succeeded.
413  */
414 static int cp_attach (device_t dev)
415 {
416         bdrv_t *bd = device_get_softc (dev);
417         int unit = device_get_unit (dev);
418         char *cp_ln = CP_LOCK_NAME;
419         unsigned short res;
420         vm_offset_t vbase;
421         int rid, error;
422         cp_board_t *b;
423         cp_chan_t *c;
424         drv_t *d;
425         int s = splimp ();
426
427         b = malloc (sizeof(cp_board_t), M_DEVBUF, M_WAITOK);
428         if (!b) {
429                 printf ("cp%d: couldn't allocate memory\n", unit);              
430                 splx (s);
431                 return (ENXIO);
432         }
433         bzero (b, sizeof(cp_board_t));
434
435         bd->board = b;
436         rid = PCIR_BAR(0);
437         bd->cp_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid,
438                         0, ~0, 1, RF_ACTIVE);
439         if (! bd->cp_res) {
440                 printf ("cp%d: cannot map memory\n", unit);
441                 free (b, M_DEVBUF);
442                 splx (s);
443                 return (ENXIO);
444         }
445         vbase = (vm_offset_t) rman_get_virtual (bd->cp_res);
446
447         cp_ln[2] = '0' + unit;
448         mtx_init (&bd->cp_mtx, cp_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
449         res = cp_init (b, unit, (u_char*) vbase);
450         if (res) {
451                 printf ("cp%d: can't init, error code:%x\n", unit, res);
452                 bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res);
453                 free (b, M_DEVBUF);
454                 splx (s);
455                 return (ENXIO);
456         }
457
458         bd->dmamem.size = sizeof(cp_qbuf_t);
459         if (! cp_bus_dma_mem_alloc (unit, -1, &bd->dmamem)) {
460                 free (b, M_DEVBUF);
461                 splx (s);
462                 return (ENXIO);
463         }
464         CP_LOCK (bd);
465         cp_reset (b, bd->dmamem.virt, bd->dmamem.phys);
466         CP_UNLOCK (bd);
467
468         rid = 0;
469         bd->cp_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
470                         RF_SHAREABLE | RF_ACTIVE);
471         if (! bd->cp_irq) {
472                 cp_destroy = 1;
473                 printf ("cp%d: cannot map interrupt\n", unit);  
474                 bus_release_resource (dev, SYS_RES_MEMORY,
475                                 PCIR_BAR(0), bd->cp_res);
476                 mtx_destroy (&bd->cp_mtx);
477                 free (b, M_DEVBUF);
478                 splx (s);
479                 return (ENXIO);
480         }
481         callout_init (&led_timo[unit], cp_mpsafenet ? CALLOUT_MPSAFE : 0);
482         error  = bus_setup_intr (dev, bd->cp_irq,
483                                 INTR_TYPE_NET|(cp_mpsafenet?INTR_MPSAFE:0),
484                                 NULL, cp_intr, bd, &bd->cp_intrhand);
485         if (error) {
486                 cp_destroy = 1;
487                 printf ("cp%d: cannot set up irq\n", unit);
488                 bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq);
489                 bus_release_resource (dev, SYS_RES_MEMORY,
490                                 PCIR_BAR(0), bd->cp_res);
491                 mtx_destroy (&bd->cp_mtx);
492                 free (b, M_DEVBUF);
493                 splx (s);
494                 return (ENXIO);
495         }
496         printf ("cp%d: %s, clock %ld MHz\n", unit, b->name, b->osc / 1000000);
497
498         for (c = b->chan; c < b->chan + NCHAN; ++c) {
499                 if (! c->type)
500                         continue;
501                 d = &bd->channel[c->num];
502                 d->dmamem.size = sizeof(cp_buf_t);
503                 if (! cp_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
504                         continue;
505                 channel [b->num*NCHAN + c->num] = d;
506                 sprintf (d->name, "cp%d.%d", b->num, c->num);
507                 d->board = b;
508                 d->chan = c;
509                 c->sys = d;
510 #ifdef NETGRAPH
511                 if (ng_make_node_common (&typestruct, &d->node) != 0) {
512                         printf ("%s: cannot make common node\n", d->name);
513                         d->node = NULL;
514                         continue;
515                 }
516                 NG_NODE_SET_PRIVATE (d->node, d);
517                 sprintf (d->nodename, "%s%d", NG_CP_NODE_TYPE,
518                          c->board->num*NCHAN + c->num);
519                 if (ng_name_node (d->node, d->nodename)) {
520                         printf ("%s: cannot name node\n", d->nodename);
521                         NG_NODE_UNREF (d->node);
522                         continue;
523                 }
524                 d->queue.ifq_maxlen = IFQ_MAXLEN;
525                 d->hi_queue.ifq_maxlen = IFQ_MAXLEN;
526                 mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF);
527                 mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF);
528                 callout_init (&d->timeout_handle,
529                              cp_mpsafenet ? CALLOUT_MPSAFE : 0);
530 #else /*NETGRAPH*/
531                 d->ifp = if_alloc(IFT_PPP);
532                 if (d->ifp == NULL) {
533                         printf ("%s: cannot if_alloc() interface\n", d->name);
534                         continue;
535                 }
536                 d->ifp->if_softc        = d;
537                 if_initname (d->ifp, "cp", b->num * NCHAN + c->num);
538                 d->ifp->if_mtu          = PP_MTU;
539                 d->ifp->if_flags        = IFF_POINTOPOINT | IFF_MULTICAST;
540                 if (!cp_mpsafenet)
541                         d->ifp->if_flags |= IFF_NEEDSGIANT;
542                 d->ifp->if_ioctl        = cp_sioctl;
543                 d->ifp->if_start        = cp_ifstart;
544                 d->ifp->if_watchdog     = cp_ifwatchdog;
545                 d->ifp->if_init         = cp_initialize;
546                 d->queue.ifq_maxlen     = NRBUF;
547                 mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF);
548                 sppp_attach (d->ifp);
549                 if_attach (d->ifp);
550                 IFP2SP(d->ifp)->pp_tlf  = cp_tlf;
551                 IFP2SP(d->ifp)->pp_tls  = cp_tls;
552                 /* If BPF is in the kernel, call the attach for it.
553                  * The header size of PPP or Cisco/HDLC is 4 bytes. */
554                 bpfattach (d->ifp, DLT_PPP, 4);
555 #endif /*NETGRAPH*/
556                 cp_start_e1 (c);
557                 cp_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys);
558
559                 /* Register callback functions. */
560                 cp_register_transmit (c, &cp_transmit);
561                 cp_register_receive (c, &cp_receive);
562                 cp_register_error (c, &cp_error);
563                 d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
564                                 GID_WHEEL, 0600, "cp%d", b->num*NCHAN+c->num);
565         }
566         CP_LOCK (bd);
567         b->sys = bd;
568         adapter[unit] = b;
569         CP_UNLOCK (bd);
570         splx (s);
571         return 0;
572 }
573
574 static int cp_detach (device_t dev)
575 {
576         bdrv_t *bd = device_get_softc (dev);
577         cp_board_t *b = bd->board;
578         cp_chan_t *c;
579         int s;
580
581         KASSERT (mtx_initialized (&bd->cp_mtx), ("cp mutex not initialized"));
582         s = splimp ();
583         CP_LOCK (bd);
584         /* Check if the device is busy (open). */
585         for (c = b->chan; c < b->chan + NCHAN; ++c) {
586                 drv_t *d = (drv_t*) c->sys;
587
588                 if (! d || ! d->chan->type)
589                         continue;
590                 if (d->running) {
591                         CP_UNLOCK (bd);
592                         splx (s);
593                         return EBUSY;
594                 }
595         }
596
597         /* Ok, we can unload driver */
598         /* At first we should stop all channels */
599         for (c = b->chan; c < b->chan + NCHAN; ++c) {
600                 drv_t *d = (drv_t*) c->sys;
601
602                 if (! d || ! d->chan->type)
603                         continue;
604
605                 cp_stop_chan (c);
606                 cp_stop_e1 (c);
607                 cp_set_dtr (d->chan, 0);
608                 cp_set_rts (d->chan, 0);
609         }
610
611         /* Reset the adapter. */
612         cp_destroy = 1;
613         cp_interrupt_poll (b, 1);
614         cp_led_off (b);
615         cp_reset (b, 0 ,0);
616         callout_stop (&led_timo[b->num]);
617
618         /* Disable the interrupt request. */
619         bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand);
620
621         for (c=b->chan; c<b->chan+NCHAN; ++c) {
622                 drv_t *d = (drv_t*) c->sys;
623
624                 if (! d || ! d->chan->type)
625                         continue;
626 #ifndef NETGRAPH
627                 /* Detach from the packet filter list of interfaces. */
628                 bpfdetach (d->ifp);
629
630                 /* Detach from the sync PPP list. */
631                 sppp_detach (d->ifp);
632
633                 /* Detach from the system list of interfaces. */
634                 if_detach (d->ifp);
635                 if_free (d->ifp);
636                 IF_DRAIN (&d->queue);
637                 mtx_destroy (&d->queue.ifq_mtx);
638 #else
639                 if (d->node) {
640                         ng_rmnode_self (d->node);
641                         NG_NODE_UNREF (d->node);
642                         d->node = NULL;
643                 }
644                 mtx_destroy (&d->queue.ifq_mtx);
645                 mtx_destroy (&d->hi_queue.ifq_mtx);
646 #endif
647                 destroy_dev (d->devt);
648         }
649
650         b->sys = NULL;
651         CP_UNLOCK (bd);
652
653         bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq);
654         bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res);
655
656         CP_LOCK (bd);
657         cp_led_off (b);
658         CP_UNLOCK (bd);
659         callout_drain (&led_timo[b->num]);
660         splx (s);
661
662         s = splimp ();
663         for (c = b->chan; c < b->chan + NCHAN; ++c) {
664                 drv_t *d = (drv_t*) c->sys;
665
666                 if (! d || ! d->chan->type)
667                         continue;
668                 channel [b->num*NCHAN + c->num] = 0;
669                 /* Deallocate buffers. */
670                 cp_bus_dma_mem_free (&d->dmamem);
671         }
672         adapter [b->num] = 0;
673         cp_bus_dma_mem_free (&bd->dmamem);
674         free (b, M_DEVBUF);
675         splx (s);
676         mtx_destroy (&bd->cp_mtx);
677         return 0;
678 }
679
680 #ifndef NETGRAPH
681 static void cp_ifstart (struct ifnet *ifp)
682 {
683         drv_t *d = ifp->if_softc;
684         bdrv_t *bd = d->board->sys;
685
686         CP_LOCK (bd);
687         cp_start (d);
688         CP_UNLOCK (bd);
689 }
690
691 static void cp_ifwatchdog (struct ifnet *ifp)
692 {
693         drv_t *d = ifp->if_softc;
694
695         cp_watchdog (d);
696 }
697
698 static void cp_tlf (struct sppp *sp)
699 {
700         drv_t *d = SP2IFP(sp)->if_softc;
701
702         CP_DEBUG2 (d, ("cp_tlf\n"));
703         /* XXXRIK: Don't forget to protect them by LOCK, or kill them. */
704 /*      cp_set_dtr (d->chan, 0);*/
705 /*      cp_set_rts (d->chan, 0);*/
706         if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
707                 sp->pp_down (sp);
708 }
709
710 static void cp_tls (struct sppp *sp)
711 {
712         drv_t *d = SP2IFP(sp)->if_softc;
713
714         CP_DEBUG2 (d, ("cp_tls\n"));
715         if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
716                 sp->pp_up (sp);
717 }
718
719 /*
720  * Process an ioctl request.
721  */
722 static int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
723 {
724         drv_t *d = ifp->if_softc;
725         bdrv_t *bd = d->board->sys;
726         int error, s, was_up, should_be_up;
727
728         was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
729         error = sppp_ioctl (ifp, cmd, data);
730
731         if (error)
732                 return error;
733
734         if (! (ifp->if_flags & IFF_DEBUG))
735                 d->chan->debug = 0;
736         else
737                 d->chan->debug = d->chan->debug_shadow;
738
739         switch (cmd) {
740         default:           CP_DEBUG2 (d, ("ioctl 0x%lx\n", cmd));   return 0;
741         case SIOCADDMULTI: CP_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0;
742         case SIOCDELMULTI: CP_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0;
743         case SIOCSIFFLAGS: CP_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break;
744         case SIOCSIFADDR:  CP_DEBUG2 (d, ("ioctl SIOCSIFADDR\n"));  break;
745         }
746
747         /* We get here only in case of SIFFLAGS or SIFADDR. */
748         s = splimp ();
749         CP_LOCK (bd);
750         should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
751         if (! was_up && should_be_up) {
752                 /* Interface goes up -- start it. */
753                 cp_up (d);
754                 cp_start (d);
755         } else if (was_up && ! should_be_up) {
756                 /* Interface is going down -- stop it. */
757 /*              if ((IFP2SP(ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
758                 cp_down (d);
759         }
760         CP_DEBUG (d, ("ioctl 0x%lx p4\n", cmd));
761         CP_UNLOCK (bd);
762         splx (s);
763         return 0;
764 }
765
766 /*
767  * Initialization of interface.
768  * It seems to be never called by upper level?
769  */
770 static void cp_initialize (void *softc)
771 {
772         drv_t *d = softc;
773
774         CP_DEBUG (d, ("cp_initialize\n"));
775 }
776 #endif /*NETGRAPH*/
777
778 /*
779  * Stop the interface.  Called on splimp().
780  */
781 static void cp_down (drv_t *d)
782 {
783         CP_DEBUG (d, ("cp_down\n"));
784         /* Interface is going down -- stop it. */
785         cp_set_dtr (d->chan, 0);
786         cp_set_rts (d->chan, 0);
787
788         d->running = 0;
789 }
790
791 /*
792  * Start the interface.  Called on splimp().
793  */
794 static void cp_up (drv_t *d)
795 {
796         CP_DEBUG (d, ("cp_up\n"));
797         cp_set_dtr (d->chan, 1);
798         cp_set_rts (d->chan, 1);
799         d->running = 1;
800 }
801
802 /*
803  * Start output on the interface.  Get another datagram to send
804  * off of the interface queue, and copy it to the interface
805  * before starting the output.
806  */
807 static void cp_send (drv_t *d)
808 {
809         struct mbuf *m;
810         u_short len;
811
812         CP_DEBUG2 (d, ("cp_send, tn=%d te=%d\n", d->chan->tn, d->chan->te));
813
814         /* No output if the interface is down. */
815         if (! d->running)
816                 return;
817
818         /* No output if the modem is off. */
819         if (! (d->chan->lloop || d->chan->type != T_SERIAL ||
820                 cp_get_dsr (d->chan)))
821                 return;
822
823         while (cp_transmit_space (d->chan)) {
824                 /* Get the packet to send. */
825 #ifdef NETGRAPH
826                 IF_DEQUEUE (&d->hi_queue, m);
827                 if (! m)
828                         IF_DEQUEUE (&d->queue, m);
829 #else
830                 m = sppp_dequeue (d->ifp);
831 #endif
832                 if (! m)
833                         return;
834 #ifndef NETGRAPH
835                 BPF_MTAP (d->ifp, m);
836 #endif
837                 len = m_length (m, NULL);
838                 if (len >= BUFSZ)
839                         printf ("%s: too long packet: %d bytes: ",
840                                 d->name, len);
841                 else if (! m->m_next)
842                         cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0);
843                 else {
844                         u_char *buf = d->chan->tbuf[d->chan->te];
845                         m_copydata (m, 0, len, buf);
846                         cp_send_packet (d->chan, buf, len, 0);
847                 }
848                 m_freem (m);
849                 /* Set up transmit timeout, if the transmit ring is not empty.*/
850 #ifdef NETGRAPH
851                 d->timeout = 10;
852 #else
853                 d->ifp->if_timer = 10;
854 #endif
855         }
856 #ifndef NETGRAPH
857         d->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
858 #endif
859 }
860
861 /*
862  * Start output on the interface.
863  * Always called on splimp().
864  */
865 static void cp_start (drv_t *d)
866 {
867         if (d->running) {
868                 if (! d->chan->dtr)
869                         cp_set_dtr (d->chan, 1);
870                 if (! d->chan->rts)
871                         cp_set_rts (d->chan, 1);
872                 cp_send (d);
873         }
874 }
875
876 /*
877  * Handle transmit timeouts.
878  * Recover after lost transmit interrupts.
879  * Always called on splimp().
880  */
881 static void cp_watchdog (drv_t *d)
882 {
883         bdrv_t *bd = d->board->sys;
884         CP_DEBUG (d, ("device timeout\n"));
885         if (d->running) {
886                 int s = splimp ();
887
888                 CP_LOCK (bd);
889                 cp_stop_chan (d->chan);
890                 cp_stop_e1 (d->chan);
891                 cp_start_e1 (d->chan);
892                 cp_start_chan (d->chan, 1, 1, 0, 0);
893                 cp_set_dtr (d->chan, 1);
894                 cp_set_rts (d->chan, 1);
895                 cp_start (d);
896                 CP_UNLOCK (bd);
897                 splx (s);
898         }
899 }
900
901 static void cp_transmit (cp_chan_t *c, void *attachment, int len)
902 {
903         drv_t *d = c->sys;
904
905 #ifdef NETGRAPH
906         d->timeout = 0;
907 #else
908         ++d->ifp->if_opackets;
909         d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
910         d->ifp->if_timer = 0;
911 #endif
912         cp_start (d);
913 }
914
915 static void cp_receive (cp_chan_t *c, unsigned char *data, int len)
916 {
917         drv_t *d = c->sys;
918         struct mbuf *m;
919 #ifdef NETGRAPH
920         int error;
921 #endif
922
923         if (! d->running)
924                 return;
925
926         m = makembuf (data, len);
927         if (! m) {
928                 CP_DEBUG (d, ("no memory for packet\n"));
929 #ifndef NETGRAPH
930                 ++d->ifp->if_iqdrops;
931 #endif
932                 return;
933         }
934         if (c->debug > 1)
935                 printmbuf (m);
936 #ifdef NETGRAPH
937         m->m_pkthdr.rcvif = 0;
938         NG_SEND_DATA_ONLY (error, d->hook, m);
939 #else
940         ++d->ifp->if_ipackets;
941         m->m_pkthdr.rcvif = d->ifp;
942         /* Check if there's a BPF listener on this interface.
943          * If so, hand off the raw packet to bpf. */
944         BPF_TAP (d->ifp, data, len);
945         IF_ENQUEUE (&d->queue, m);
946 #endif
947 }
948
949 static void cp_error (cp_chan_t *c, int data)
950 {
951         drv_t *d = c->sys;
952
953         switch (data) {
954         case CP_FRAME:
955                 CP_DEBUG (d, ("frame error\n"));
956 #ifndef NETGRAPH
957                 ++d->ifp->if_ierrors;
958 #endif
959                 break;
960         case CP_CRC:
961                 CP_DEBUG (d, ("crc error\n"));
962 #ifndef NETGRAPH
963                 ++d->ifp->if_ierrors;
964 #endif
965                 break;
966         case CP_OVERRUN:
967                 CP_DEBUG (d, ("overrun error\n"));
968 #ifndef NETGRAPH
969                 ++d->ifp->if_collisions;
970                 ++d->ifp->if_ierrors;
971 #endif
972                 break;
973         case CP_OVERFLOW:
974                 CP_DEBUG (d, ("overflow error\n"));
975 #ifndef NETGRAPH
976                 ++d->ifp->if_ierrors;
977 #endif
978                 break;
979         case CP_UNDERRUN:
980                 CP_DEBUG (d, ("underrun error\n"));
981 #ifdef NETGRAPH
982                 d->timeout = 0;
983 #else
984                 ++d->ifp->if_oerrors;
985                 d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
986                 d->ifp->if_timer = 0;
987 #endif
988                 cp_start (d);
989                 break;
990         default:
991                 CP_DEBUG (d, ("error #%d\n", data));
992                 break;
993         }
994 }
995
996 /*
997  * You also need read, write, open, close routines.
998  * This should get you started
999  */
1000 static int cp_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
1001 {
1002         int unit = minor (dev);
1003         drv_t *d;
1004
1005         if (unit >= NBRD*NCHAN || ! (d = channel[unit]))
1006                 return ENXIO;
1007         CP_DEBUG2 (d, ("cp_open\n"));
1008         return 0;
1009 }
1010
1011 /*
1012  * Only called on the LAST close.
1013  */
1014 static int cp_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
1015 {
1016         drv_t *d = channel [minor (dev)];
1017
1018         CP_DEBUG2 (d, ("cp_close\n"));
1019         return 0;
1020 }
1021
1022 static int cp_modem_status (cp_chan_t *c)
1023 {
1024         drv_t *d = c->sys;
1025         bdrv_t *bd = d->board->sys;
1026         int status, s;
1027
1028         status = d->running ? TIOCM_LE : 0;
1029         s = splimp ();
1030         CP_LOCK (bd);
1031         if (cp_get_cd  (c)) status |= TIOCM_CD;
1032         if (cp_get_cts (c)) status |= TIOCM_CTS;
1033         if (cp_get_dsr (c)) status |= TIOCM_DSR;
1034         if (c->dtr)         status |= TIOCM_DTR;
1035         if (c->rts)         status |= TIOCM_RTS;
1036         CP_UNLOCK (bd);
1037         splx (s);
1038         return status;
1039 }
1040
1041 static int cp_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1042 {
1043         drv_t *d = channel [minor (dev)];
1044         bdrv_t *bd = d->board->sys;
1045         cp_chan_t *c = d->chan;
1046         struct serial_statistics *st;
1047         struct e1_statistics *opte1;
1048         struct e3_statistics *opte3;
1049         int error, s;
1050         char mask[16];
1051
1052         switch (cmd) {
1053         case SERIAL_GETREGISTERED:
1054                 CP_DEBUG2 (d, ("ioctl: getregistered\n"));
1055                 bzero (mask, sizeof(mask));
1056                 for (s=0; s<NBRD*NCHAN; ++s)
1057                         if (channel [s])
1058                                 mask [s/8] |= 1 << (s & 7);
1059                 bcopy (mask, data, sizeof (mask));
1060                 return 0;
1061
1062 #ifndef NETGRAPH
1063         case SERIAL_GETPROTO:
1064                 CP_DEBUG2 (d, ("ioctl: getproto\n"));
1065                 strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
1066                         (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
1067                 return 0;
1068
1069         case SERIAL_SETPROTO:
1070                 CP_DEBUG2 (d, ("ioctl: setproto\n"));
1071                 /* Only for superuser! */
1072                 error = priv_check (td, PRIV_DRIVER);
1073                 if (error)
1074                         return error;
1075                 if (d->ifp->if_drv_flags & IFF_DRV_RUNNING)
1076                         return EBUSY;
1077                 if (! strcmp ("cisco", (char*)data)) {
1078                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
1079                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1080                         d->ifp->if_flags |= PP_CISCO;
1081                 } else if (! strcmp ("fr", (char*)data) && PP_FR) {
1082                         d->ifp->if_flags &= ~(PP_CISCO);
1083                         IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
1084                 } else if (! strcmp ("ppp", (char*)data)) {
1085                         IFP2SP(d->ifp)->pp_flags &= ~PP_FR;
1086                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1087                         d->ifp->if_flags &= ~(PP_CISCO);
1088                 } else
1089                         return EINVAL;
1090                 return 0;
1091
1092         case SERIAL_GETKEEPALIVE:
1093                 CP_DEBUG2 (d, ("ioctl: getkeepalive\n"));
1094                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1095                         (d->ifp->if_flags & PP_CISCO))
1096                         return EINVAL;
1097                 *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
1098                 return 0;
1099
1100         case SERIAL_SETKEEPALIVE:
1101                 CP_DEBUG2 (d, ("ioctl: setkeepalive\n"));
1102                 /* Only for superuser! */
1103                 error = priv_check (td, PRIV_DRIVER);
1104                 if (error)
1105                         return error;
1106                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1107                         (d->ifp->if_flags & PP_CISCO))
1108                         return EINVAL;
1109                 s = splimp ();
1110                 CP_LOCK (bd);
1111                 if (*(int*)data)
1112                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1113                 else
1114                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1115                 CP_UNLOCK (bd);
1116                 splx (s);
1117                 return 0;
1118 #endif /*NETGRAPH*/
1119
1120         case SERIAL_GETMODE:
1121                 CP_DEBUG2 (d, ("ioctl: getmode\n"));
1122                 *(int*)data = SERIAL_HDLC;
1123                 return 0;
1124
1125         case SERIAL_SETMODE:
1126                 /* Only for superuser! */
1127                 error = priv_check (td, PRIV_DRIVER);
1128                 if (error)
1129                         return error;
1130                 if (*(int*)data != SERIAL_HDLC)
1131                         return EINVAL;
1132                 return 0;
1133
1134         case SERIAL_GETCFG:
1135                 CP_DEBUG2 (d, ("ioctl: getcfg\n"));
1136                 if (c->type != T_E1 || c->unfram)
1137                         return EINVAL;
1138                 *(char*)data = c->board->mux ? 'c' : 'a';
1139                 return 0;
1140
1141         case SERIAL_SETCFG:
1142                 CP_DEBUG2 (d, ("ioctl: setcfg\n"));
1143                 error = priv_check (td, PRIV_DRIVER);
1144                 if (error)
1145                         return error;
1146                 if (c->type != T_E1)
1147                         return EINVAL;
1148                 s = splimp ();
1149                 CP_LOCK (bd);
1150                 cp_set_mux (c->board, *((char*)data) == 'c');
1151                 CP_UNLOCK (bd);
1152                 splx (s);
1153                 return 0;
1154
1155         case SERIAL_GETSTAT:
1156                 CP_DEBUG2 (d, ("ioctl: getstat\n"));
1157                 st = (struct serial_statistics*) data;
1158                 st->rintr  = c->rintr;
1159                 st->tintr  = c->tintr;
1160                 st->mintr  = 0;
1161                 st->ibytes = c->ibytes;
1162                 st->ipkts  = c->ipkts;
1163                 st->obytes = c->obytes;
1164                 st->opkts  = c->opkts;
1165                 st->ierrs  = c->overrun + c->frame + c->crc;
1166                 st->oerrs  = c->underrun;
1167                 return 0;
1168
1169         case SERIAL_GETESTAT:
1170                 CP_DEBUG2 (d, ("ioctl: getestat\n"));
1171                 if (c->type != T_E1 && c->type != T_G703)
1172                         return EINVAL;
1173                 opte1 = (struct e1_statistics*) data;
1174                 opte1->status       = c->status;
1175                 opte1->cursec       = c->cursec;
1176                 opte1->totsec       = c->totsec + c->cursec;
1177
1178                 opte1->currnt.bpv   = c->currnt.bpv;
1179                 opte1->currnt.fse   = c->currnt.fse;
1180                 opte1->currnt.crce  = c->currnt.crce;
1181                 opte1->currnt.rcrce = c->currnt.rcrce;
1182                 opte1->currnt.uas   = c->currnt.uas;
1183                 opte1->currnt.les   = c->currnt.les;
1184                 opte1->currnt.es    = c->currnt.es;
1185                 opte1->currnt.bes   = c->currnt.bes;
1186                 opte1->currnt.ses   = c->currnt.ses;
1187                 opte1->currnt.oofs  = c->currnt.oofs;
1188                 opte1->currnt.css   = c->currnt.css;
1189                 opte1->currnt.dm    = c->currnt.dm;
1190
1191                 opte1->total.bpv    = c->total.bpv   + c->currnt.bpv;
1192                 opte1->total.fse    = c->total.fse   + c->currnt.fse;
1193                 opte1->total.crce   = c->total.crce  + c->currnt.crce;
1194                 opte1->total.rcrce  = c->total.rcrce + c->currnt.rcrce;
1195                 opte1->total.uas    = c->total.uas   + c->currnt.uas;
1196                 opte1->total.les    = c->total.les   + c->currnt.les;
1197                 opte1->total.es     = c->total.es    + c->currnt.es;
1198                 opte1->total.bes    = c->total.bes   + c->currnt.bes;
1199                 opte1->total.ses    = c->total.ses   + c->currnt.ses;
1200                 opte1->total.oofs   = c->total.oofs  + c->currnt.oofs;
1201                 opte1->total.css    = c->total.css   + c->currnt.css;
1202                 opte1->total.dm     = c->total.dm    + c->currnt.dm;
1203                 for (s=0; s<48; ++s) {
1204                         opte1->interval[s].bpv   = c->interval[s].bpv;
1205                         opte1->interval[s].fse   = c->interval[s].fse;
1206                         opte1->interval[s].crce  = c->interval[s].crce;
1207                         opte1->interval[s].rcrce = c->interval[s].rcrce;
1208                         opte1->interval[s].uas   = c->interval[s].uas;
1209                         opte1->interval[s].les   = c->interval[s].les;
1210                         opte1->interval[s].es    = c->interval[s].es;
1211                         opte1->interval[s].bes   = c->interval[s].bes;
1212                         opte1->interval[s].ses   = c->interval[s].ses;
1213                         opte1->interval[s].oofs  = c->interval[s].oofs;
1214                         opte1->interval[s].css   = c->interval[s].css;
1215                         opte1->interval[s].dm    = c->interval[s].dm;
1216                 }
1217                 return 0;
1218
1219         case SERIAL_GETE3STAT:
1220                 CP_DEBUG2 (d, ("ioctl: gete3stat\n"));
1221                 if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1)
1222                         return EINVAL;
1223                 opte3 = (struct e3_statistics*) data;
1224
1225                 opte3->status = c->e3status;
1226                 opte3->cursec = (c->e3csec_5 * 2 + 1) / 10;
1227                 opte3->totsec = c->e3tsec + opte3->cursec;
1228
1229                 opte3->ccv = c->e3ccv;
1230                 opte3->tcv = c->e3tcv + opte3->ccv;
1231
1232                 for (s = 0; s < 48; ++s) {
1233                         opte3->icv[s] = c->e3icv[s];
1234                 }
1235                 return 0;
1236                 
1237         case SERIAL_CLRSTAT:
1238                 CP_DEBUG2 (d, ("ioctl: clrstat\n"));
1239                 /* Only for superuser! */
1240                 error = priv_check (td, PRIV_DRIVER);
1241                 if (error)
1242                         return error;
1243                 c->rintr    = 0;
1244                 c->tintr    = 0;
1245                 c->ibytes   = 0;
1246                 c->obytes   = 0;
1247                 c->ipkts    = 0;
1248                 c->opkts    = 0;
1249                 c->overrun  = 0;
1250                 c->frame    = 0;
1251                 c->crc      = 0;
1252                 c->underrun = 0;
1253                 bzero (&c->currnt, sizeof (c->currnt));
1254                 bzero (&c->total, sizeof (c->total));
1255                 bzero (c->interval, sizeof (c->interval));
1256                 c->e3ccv    = 0;
1257                 c->e3tcv    = 0;
1258                 bzero (c->e3icv, sizeof (c->e3icv));
1259                 return 0;
1260
1261         case SERIAL_GETBAUD:
1262                 CP_DEBUG2 (d, ("ioctl: getbaud\n"));
1263                 *(long*)data = c->baud;
1264                 return 0;
1265
1266         case SERIAL_SETBAUD:
1267                 CP_DEBUG2 (d, ("ioctl: setbaud\n"));
1268                 /* Only for superuser! */
1269                 error = priv_check (td, PRIV_DRIVER);
1270                 if (error)
1271                         return error;
1272                 s = splimp ();
1273                 CP_LOCK (bd);
1274                 cp_set_baud (c, *(long*)data);
1275                 CP_UNLOCK (bd);
1276                 splx (s);
1277                 return 0;
1278
1279         case SERIAL_GETLOOP:
1280                 CP_DEBUG2 (d, ("ioctl: getloop\n"));
1281                 *(int*)data = c->lloop;
1282                 return 0;
1283
1284         case SERIAL_SETLOOP:
1285                 CP_DEBUG2 (d, ("ioctl: setloop\n"));
1286                 /* Only for superuser! */
1287                 error = priv_check (td, PRIV_DRIVER);
1288                 if (error)
1289                         return error;
1290                 s = splimp ();
1291                 CP_LOCK (bd);
1292                 cp_set_lloop (c, *(int*)data);
1293                 CP_UNLOCK (bd);
1294                 splx (s);
1295                 return 0;
1296
1297         case SERIAL_GETDPLL:
1298                 CP_DEBUG2 (d, ("ioctl: getdpll\n"));
1299                 if (c->type != T_SERIAL)
1300                         return EINVAL;
1301                 *(int*)data = c->dpll;
1302                 return 0;
1303
1304         case SERIAL_SETDPLL:
1305                 CP_DEBUG2 (d, ("ioctl: setdpll\n"));
1306                 /* Only for superuser! */
1307                 error = priv_check (td, PRIV_DRIVER);
1308                 if (error)
1309                         return error;
1310                 if (c->type != T_SERIAL)
1311                         return EINVAL;
1312                 s = splimp ();
1313                 CP_LOCK (bd);
1314                 cp_set_dpll (c, *(int*)data);
1315                 CP_UNLOCK (bd);
1316                 splx (s);
1317                 return 0;
1318
1319         case SERIAL_GETNRZI:
1320                 CP_DEBUG2 (d, ("ioctl: getnrzi\n"));
1321                 if (c->type != T_SERIAL)
1322                         return EINVAL;
1323                 *(int*)data = c->nrzi;
1324                 return 0;
1325
1326         case SERIAL_SETNRZI:
1327                 CP_DEBUG2 (d, ("ioctl: setnrzi\n"));
1328                 /* Only for superuser! */
1329                 error = priv_check (td, PRIV_DRIVER);
1330                 if (error)
1331                         return error;
1332                 if (c->type != T_SERIAL)
1333                         return EINVAL;
1334                 s = splimp ();
1335                 CP_LOCK (bd);
1336                 cp_set_nrzi (c, *(int*)data);
1337                 CP_UNLOCK (bd);
1338                 splx (s);
1339                 return 0;
1340
1341         case SERIAL_GETDEBUG:
1342                 CP_DEBUG2 (d, ("ioctl: getdebug\n"));
1343                 *(int*)data = d->chan->debug;
1344                 return 0;
1345
1346         case SERIAL_SETDEBUG:
1347                 CP_DEBUG2 (d, ("ioctl: setdebug\n"));
1348                 /* Only for superuser! */
1349                 error = priv_check (td, PRIV_DRIVER);
1350                 if (error)
1351                         return error;
1352 #ifndef NETGRAPH
1353                 /*
1354                  * The debug_shadow is always greater than zero for logic 
1355                  * simplicity.  For switching debug off the IFF_DEBUG is
1356                  * responsible.
1357                  */
1358                 d->chan->debug_shadow = (*(int*)data) ? (*(int*)data) : 1;
1359                 if (d->ifp->if_flags & IFF_DEBUG)
1360                         d->chan->debug = d->chan->debug_shadow;
1361 #else
1362                 d->chan->debug = *(int*)data;
1363 #endif
1364                 return 0;
1365
1366         case SERIAL_GETHIGAIN:
1367                 CP_DEBUG2 (d, ("ioctl: gethigain\n"));
1368                 if (c->type != T_E1)
1369                         return EINVAL;
1370                 *(int*)data = c->higain;
1371                 return 0;
1372
1373         case SERIAL_SETHIGAIN:
1374                 CP_DEBUG2 (d, ("ioctl: sethigain\n"));
1375                 /* Only for superuser! */
1376                 error = priv_check (td, PRIV_DRIVER);
1377                 if (error)
1378                         return error;
1379                 if (c->type != T_E1)
1380                         return EINVAL;
1381                 s = splimp ();
1382                 CP_LOCK (bd);
1383                 cp_set_higain (c, *(int*)data);
1384                 CP_UNLOCK (bd);
1385                 splx (s);
1386                 return 0;
1387
1388         case SERIAL_GETPHONY:
1389                 CP_DEBUG2 (d, ("ioctl: getphony\n"));
1390                 if (c->type != T_E1)
1391                         return EINVAL;
1392                 *(int*)data = c->phony;
1393                 return 0;
1394
1395         case SERIAL_SETPHONY:
1396                 CP_DEBUG2 (d, ("ioctl: setphony\n"));
1397                 /* Only for superuser! */
1398                 error = priv_check (td, PRIV_DRIVER);
1399                 if (error)
1400                         return error;
1401                 if (c->type != T_E1)
1402                         return EINVAL;
1403                 s = splimp ();
1404                 CP_LOCK (bd);
1405                 cp_set_phony (c, *(int*)data);
1406                 CP_UNLOCK (bd);
1407                 splx (s);
1408                 return 0;
1409
1410         case SERIAL_GETUNFRAM:
1411                 CP_DEBUG2 (d, ("ioctl: getunfram\n"));
1412                 if (c->type != T_E1)
1413                         return EINVAL;
1414                 *(int*)data = c->unfram;
1415                 return 0;
1416
1417         case SERIAL_SETUNFRAM:
1418                 CP_DEBUG2 (d, ("ioctl: setunfram\n"));
1419                 /* Only for superuser! */
1420                 error = priv_check (td, PRIV_DRIVER);
1421                 if (error)
1422                         return error;
1423                 if (c->type != T_E1)
1424                         return EINVAL;
1425                 s = splimp ();
1426                 CP_LOCK (bd);
1427                 cp_set_unfram (c, *(int*)data);
1428                 CP_UNLOCK (bd);
1429                 splx (s);
1430                 return 0;
1431
1432         case SERIAL_GETSCRAMBLER:
1433                 CP_DEBUG2 (d, ("ioctl: getscrambler\n"));
1434                 if (c->type != T_G703 && !c->unfram)
1435                         return EINVAL;
1436                 *(int*)data = c->scrambler;
1437                 return 0;
1438
1439         case SERIAL_SETSCRAMBLER:
1440                 CP_DEBUG2 (d, ("ioctl: setscrambler\n"));
1441                 /* Only for superuser! */
1442                 error = priv_check (td, PRIV_DRIVER);
1443                 if (error)
1444                         return error;
1445                 if (c->type != T_G703 && !c->unfram)
1446                         return EINVAL;
1447                 s = splimp ();
1448                 CP_LOCK (bd);
1449                 cp_set_scrambler (c, *(int*)data);
1450                 CP_UNLOCK (bd);
1451                 splx (s);
1452                 return 0;
1453
1454         case SERIAL_GETMONITOR:
1455                 CP_DEBUG2 (d, ("ioctl: getmonitor\n"));
1456                 if (c->type != T_E1 &&
1457                     c->type != T_E3 &&
1458                     c->type != T_T3 &&
1459                     c->type != T_STS1)
1460                         return EINVAL;
1461                 *(int*)data = c->monitor;
1462                 return 0;
1463
1464         case SERIAL_SETMONITOR:
1465                 CP_DEBUG2 (d, ("ioctl: setmonitor\n"));
1466                 /* Only for superuser! */
1467                 error = priv_check (td, PRIV_DRIVER);
1468                 if (error)
1469                         return error;
1470                 if (c->type != T_E1)
1471                         return EINVAL;
1472                 s = splimp ();
1473                 CP_LOCK (bd);
1474                 cp_set_monitor (c, *(int*)data);
1475                 CP_UNLOCK (bd);
1476                 splx (s);
1477                 return 0;
1478
1479         case SERIAL_GETUSE16:
1480                 CP_DEBUG2 (d, ("ioctl: getuse16\n"));
1481                 if (c->type != T_E1 || c->unfram)
1482                         return EINVAL;
1483                 *(int*)data = c->use16;
1484                 return 0;
1485
1486         case SERIAL_SETUSE16:
1487                 CP_DEBUG2 (d, ("ioctl: setuse16\n"));
1488                 /* Only for superuser! */
1489                 error = priv_check (td, PRIV_DRIVER);
1490                 if (error)
1491                         return error;
1492                 if (c->type != T_E1)
1493                         return EINVAL;
1494                 s = splimp ();
1495                 CP_LOCK (bd);
1496                 cp_set_use16 (c, *(int*)data);
1497                 CP_UNLOCK (bd);
1498                 splx (s);
1499                 return 0;
1500
1501         case SERIAL_GETCRC4:
1502                 CP_DEBUG2 (d, ("ioctl: getcrc4\n"));
1503                 if (c->type != T_E1 || c->unfram)
1504                         return EINVAL;
1505                 *(int*)data = c->crc4;
1506                 return 0;
1507
1508         case SERIAL_SETCRC4:
1509                 CP_DEBUG2 (d, ("ioctl: setcrc4\n"));
1510                 /* Only for superuser! */
1511                 error = priv_check (td, PRIV_DRIVER);
1512                 if (error)
1513                         return error;
1514                 if (c->type != T_E1)
1515                         return EINVAL;
1516                 s = splimp ();
1517                 CP_LOCK (bd);
1518                 cp_set_crc4 (c, *(int*)data);
1519                 CP_UNLOCK (bd);
1520                 splx (s);
1521                 return 0;
1522
1523         case SERIAL_GETCLK:
1524                 CP_DEBUG2 (d, ("ioctl: getclk\n"));
1525                 if (c->type != T_E1 &&
1526                     c->type != T_G703 &&
1527                     c->type != T_E3 &&
1528                     c->type != T_T3 &&
1529                     c->type != T_STS1)
1530                         return EINVAL;
1531                 switch (c->gsyn) {
1532                 default:        *(int*)data = E1CLK_INTERNAL;           break;
1533                 case GSYN_RCV:  *(int*)data = E1CLK_RECEIVE;            break;
1534                 case GSYN_RCV0: *(int*)data = E1CLK_RECEIVE_CHAN0;      break;
1535                 case GSYN_RCV1: *(int*)data = E1CLK_RECEIVE_CHAN1;      break;
1536                 case GSYN_RCV2: *(int*)data = E1CLK_RECEIVE_CHAN2;      break;
1537                 case GSYN_RCV3: *(int*)data = E1CLK_RECEIVE_CHAN3;      break;
1538                 }
1539                 return 0;
1540
1541         case SERIAL_SETCLK:
1542                 CP_DEBUG2 (d, ("ioctl: setclk\n"));
1543                 /* Only for superuser! */
1544                 error = priv_check (td, PRIV_DRIVER);
1545                 if (error)
1546                         return error;
1547                 if (c->type != T_E1 &&
1548                     c->type != T_G703 &&
1549                     c->type != T_E3 &&
1550                     c->type != T_T3 &&
1551                     c->type != T_STS1)
1552                         return EINVAL;
1553                 s = splimp ();
1554                 CP_LOCK (bd);
1555                 switch (*(int*)data) {
1556                 default:                  cp_set_gsyn (c, GSYN_INT);  break;
1557                 case E1CLK_RECEIVE:       cp_set_gsyn (c, GSYN_RCV);  break;
1558                 case E1CLK_RECEIVE_CHAN0: cp_set_gsyn (c, GSYN_RCV0); break;
1559                 case E1CLK_RECEIVE_CHAN1: cp_set_gsyn (c, GSYN_RCV1); break;
1560                 case E1CLK_RECEIVE_CHAN2: cp_set_gsyn (c, GSYN_RCV2); break;
1561                 case E1CLK_RECEIVE_CHAN3: cp_set_gsyn (c, GSYN_RCV3); break;
1562                 }
1563                 CP_UNLOCK (bd);
1564                 splx (s);
1565                 return 0;
1566
1567         case SERIAL_GETTIMESLOTS:
1568                 CP_DEBUG2 (d, ("ioctl: gettimeslots\n"));
1569                 if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1570                         return EINVAL;
1571                 *(u_long*)data = c->ts;
1572                 return 0;
1573
1574         case SERIAL_SETTIMESLOTS:
1575                 CP_DEBUG2 (d, ("ioctl: settimeslots\n"));
1576                 /* Only for superuser! */
1577                 error = priv_check (td, PRIV_DRIVER);
1578                 if (error)
1579                         return error;
1580                 if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1581                         return EINVAL;
1582                 s = splimp ();
1583                 CP_LOCK (bd);
1584                 cp_set_ts (c, *(u_long*)data);
1585                 CP_UNLOCK (bd);
1586                 splx (s);
1587                 return 0;
1588
1589         case SERIAL_GETINVCLK:
1590                 CP_DEBUG2 (d, ("ioctl: getinvclk\n"));
1591 #if 1
1592                 return EINVAL;
1593 #else
1594                 if (c->type != T_SERIAL)
1595                         return EINVAL;
1596                 *(int*)data = c->invtxc;
1597                 return 0;
1598 #endif
1599
1600         case SERIAL_SETINVCLK:
1601                 CP_DEBUG2 (d, ("ioctl: setinvclk\n"));
1602                 /* Only for superuser! */
1603                 error = priv_check (td, PRIV_DRIVER);
1604                 if (error)
1605                         return error;
1606                 if (c->type != T_SERIAL)
1607                         return EINVAL;
1608                 s = splimp ();
1609                 CP_LOCK (bd);
1610                 cp_set_invtxc (c, *(int*)data);
1611                 cp_set_invrxc (c, *(int*)data);
1612                 CP_UNLOCK (bd);
1613                 splx (s);
1614                 return 0;
1615
1616         case SERIAL_GETINVTCLK:
1617                 CP_DEBUG2 (d, ("ioctl: getinvtclk\n"));
1618                 if (c->type != T_SERIAL)
1619                         return EINVAL;
1620                 *(int*)data = c->invtxc;
1621                 return 0;
1622
1623         case SERIAL_SETINVTCLK:
1624                 CP_DEBUG2 (d, ("ioctl: setinvtclk\n"));
1625                 /* Only for superuser! */
1626                 error = priv_check (td, PRIV_DRIVER);
1627                 if (error)
1628                         return error;
1629                 if (c->type != T_SERIAL)
1630                         return EINVAL;
1631                 s = splimp ();
1632                 CP_LOCK (bd);
1633                 cp_set_invtxc (c, *(int*)data);
1634                 CP_UNLOCK (bd);
1635                 splx (s);
1636                 return 0;
1637
1638         case SERIAL_GETINVRCLK:
1639                 CP_DEBUG2 (d, ("ioctl: getinvrclk\n"));
1640                 if (c->type != T_SERIAL)
1641                         return EINVAL;
1642                 *(int*)data = c->invrxc;
1643                 return 0;
1644
1645         case SERIAL_SETINVRCLK:
1646                 CP_DEBUG2 (d, ("ioctl: setinvrclk\n"));
1647                 /* Only for superuser! */
1648                 error = priv_check (td, PRIV_DRIVER);
1649                 if (error)
1650                         return error;
1651                 if (c->type != T_SERIAL)
1652                         return EINVAL;
1653                 s = splimp ();
1654                 CP_LOCK (bd);
1655                 cp_set_invrxc (c, *(int*)data);
1656                 CP_UNLOCK (bd);
1657                 splx (s);
1658                 return 0;
1659
1660         case SERIAL_GETLEVEL:
1661                 CP_DEBUG2 (d, ("ioctl: getlevel\n"));
1662                 if (c->type != T_G703)
1663                         return EINVAL;
1664                 s = splimp ();
1665                 CP_LOCK (bd);
1666                 *(int*)data = cp_get_lq (c);
1667                 CP_UNLOCK (bd);
1668                 splx (s);
1669                 return 0;
1670
1671 #if 0
1672         case SERIAL_RESET:
1673                 CP_DEBUG2 (d, ("ioctl: reset\n"));
1674                 /* Only for superuser! */
1675                 error = priv_check (td, PRIV_DRIVER);
1676                 if (error)
1677                         return error;
1678                 s = splimp ();
1679                 CP_LOCK (bd);
1680                 cp_reset (c->board, 0, 0);
1681                 CP_UNLOCK (bd);
1682                 splx (s);
1683                 return 0;
1684
1685         case SERIAL_HARDRESET:
1686                 CP_DEBUG2 (d, ("ioctl: hardreset\n"));
1687                 /* Only for superuser! */
1688                 error = priv_check (td, PRIV_DRIVER);
1689                 if (error)
1690                         return error;
1691                 s = splimp ();
1692                 CP_LOCK (bd);
1693                 /* hard_reset (c->board); */
1694                 CP_UNLOCK (bd);
1695                 splx (s);
1696                 return 0;
1697 #endif
1698
1699         case SERIAL_GETCABLE:
1700                 CP_DEBUG2 (d, ("ioctl: getcable\n"));
1701                 if (c->type != T_SERIAL)
1702                         return EINVAL;
1703                 s = splimp ();
1704                 CP_LOCK (bd);
1705                 *(int*)data = cp_get_cable (c);
1706                 CP_UNLOCK (bd);
1707                 splx (s);
1708                 return 0;
1709
1710         case SERIAL_GETDIR:
1711                 CP_DEBUG2 (d, ("ioctl: getdir\n"));
1712                 if (c->type != T_E1 && c->type != T_DATA)
1713                         return EINVAL;
1714                 *(int*)data = c->dir;
1715                 return 0;
1716
1717         case SERIAL_SETDIR:
1718                 CP_DEBUG2 (d, ("ioctl: setdir\n"));
1719                 /* Only for superuser! */
1720                 error = priv_check (td, PRIV_DRIVER);
1721                 if (error)
1722                         return error;
1723                 s = splimp ();
1724                 CP_LOCK (bd);
1725                 cp_set_dir (c, *(int*)data);
1726                 CP_UNLOCK (bd);
1727                 splx (s);
1728                 return 0;
1729
1730         case SERIAL_GETRLOOP:
1731                 CP_DEBUG2 (d, ("ioctl: getrloop\n"));
1732                 if (c->type != T_G703 &&
1733                     c->type != T_E3 &&
1734                     c->type != T_T3 &&
1735                     c->type != T_STS1)
1736                         return EINVAL;
1737                 *(int*)data = cp_get_rloop (c);
1738                 return 0;
1739
1740         case SERIAL_SETRLOOP:
1741                 CP_DEBUG2 (d, ("ioctl: setloop\n"));
1742                 if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1)
1743                         return EINVAL;
1744                 /* Only for superuser! */
1745                 error = priv_check (td, PRIV_DRIVER);
1746                 if (error)
1747                         return error;
1748                 s = splimp ();
1749                 CP_LOCK (bd);
1750                 cp_set_rloop (c, *(int*)data);
1751                 CP_UNLOCK (bd);
1752                 splx (s);
1753                 return 0;
1754
1755         case SERIAL_GETCABLEN:
1756                 CP_DEBUG2 (d, ("ioctl: getcablen\n"));
1757                 if (c->type != T_T3 && c->type != T_STS1)
1758                         return EINVAL;
1759                 *(int*)data = c->cablen;
1760                 return 0;
1761
1762         case SERIAL_SETCABLEN:
1763                 CP_DEBUG2 (d, ("ioctl: setloop\n"));
1764                 if (c->type != T_T3 && c->type != T_STS1)
1765                         return EINVAL;
1766                 /* Only for superuser! */
1767                 error = priv_check (td, PRIV_DRIVER);
1768                 if (error)
1769                         return error;
1770                 s = splimp ();
1771                 CP_LOCK (bd);
1772                 cp_set_cablen (c, *(int*)data);
1773                 CP_UNLOCK (bd);
1774                 splx (s);
1775                 return 0;
1776
1777         case TIOCSDTR:  /* Set DTR */
1778                 s = splimp ();
1779                 CP_LOCK (bd);
1780                 cp_set_dtr (c, 1);
1781                 CP_UNLOCK (bd);
1782                 splx (s);
1783                 return 0;
1784
1785         case TIOCCDTR:  /* Clear DTR */
1786                 s = splimp ();
1787                 CP_LOCK (bd);
1788                 cp_set_dtr (c, 0);
1789                 CP_UNLOCK (bd);
1790                 splx (s);
1791                 return 0;
1792
1793         case TIOCMSET:  /* Set DTR/RTS */
1794                 s = splimp ();
1795                 CP_LOCK (bd);
1796                 cp_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1797                 cp_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1798                 CP_UNLOCK (bd);
1799                 splx (s);
1800                 return 0;
1801
1802         case TIOCMBIS:  /* Add DTR/RTS */
1803                 s = splimp ();
1804                 CP_LOCK (bd);
1805                 if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 1);
1806                 if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 1);
1807                 CP_UNLOCK (bd);
1808                 splx (s);
1809                 return 0;
1810
1811         case TIOCMBIC:  /* Clear DTR/RTS */
1812                 s = splimp ();
1813                 CP_LOCK (bd);
1814                 if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 0);
1815                 if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 0);
1816                 CP_UNLOCK (bd);
1817                 splx (s);
1818                 return 0;
1819
1820         case TIOCMGET:  /* Get modem status */
1821                 *(int*)data = cp_modem_status (c);
1822                 return 0;
1823         }
1824         return ENOTTY;
1825 }
1826
1827 #ifdef NETGRAPH
1828 static int ng_cp_constructor (node_p node)
1829 {
1830         drv_t *d = NG_NODE_PRIVATE (node);
1831         CP_DEBUG (d, ("Constructor\n"));
1832         return EINVAL;
1833 }
1834
1835 static int ng_cp_newhook (node_p node, hook_p hook, const char *name)
1836 {
1837         int s;
1838         drv_t *d = NG_NODE_PRIVATE (node);
1839         bdrv_t *bd = d->board->sys;
1840
1841         CP_DEBUG (d, ("Newhook\n"));
1842         /* Attach debug hook */
1843         if (strcmp (name, NG_CP_HOOK_DEBUG) == 0) {
1844                 NG_HOOK_SET_PRIVATE (hook, NULL);
1845                 d->debug_hook = hook;
1846                 return 0;
1847         }
1848
1849         /* Check for raw hook */
1850         if (strcmp (name, NG_CP_HOOK_RAW) != 0)
1851                 return EINVAL;
1852
1853         NG_HOOK_SET_PRIVATE (hook, d);
1854         d->hook = hook;
1855         s = splimp ();
1856         CP_LOCK (bd);
1857         cp_up (d);
1858         CP_UNLOCK (bd);
1859         splx (s);
1860         return 0;
1861 }
1862
1863 static char *format_timeslots (u_long s)
1864 {
1865         static char buf [100];
1866         char *p = buf;
1867         int i;
1868
1869         for (i=1; i<32; ++i)
1870                 if ((s >> i) & 1) {
1871                         int prev = (i > 1)  & (s >> (i-1));
1872                         int next = (i < 31) & (s >> (i+1));
1873
1874                         if (prev) {
1875                                 if (next)
1876                                         continue;
1877                                 *p++ = '-';
1878                         } else if (p > buf)
1879                                 *p++ = ',';
1880
1881                         if (i >= 10)
1882                                 *p++ = '0' + i / 10;
1883                         *p++ = '0' + i % 10;
1884                 }
1885         *p = 0;
1886         return buf;
1887 }
1888
1889 static int print_modems (char *s, cp_chan_t *c, int need_header)
1890 {
1891         int status = cp_modem_status (c);
1892         int length = 0;
1893
1894         if (need_header)
1895                 length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
1896         length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
1897                 status & TIOCM_LE  ? "On" : "-",
1898                 status & TIOCM_DTR ? "On" : "-",
1899                 status & TIOCM_DSR ? "On" : "-",
1900                 status & TIOCM_RTS ? "On" : "-",
1901                 status & TIOCM_CTS ? "On" : "-",
1902                 status & TIOCM_CD  ? "On" : "-");
1903         return length;
1904 }
1905
1906 static int print_stats (char *s, cp_chan_t *c, int need_header)
1907 {
1908         int length = 0;
1909
1910         if (need_header)
1911                 length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
1912         length += sprintf (s + length, "%7ld %7ld %7ld %8lu %7ld %7ld %8lu %7ld %7ld\n",
1913                 c->rintr, c->tintr, 0l, (unsigned long) c->ibytes,
1914                 c->ipkts, c->overrun + c->frame + c->crc,
1915                 (unsigned long) c->obytes, c->opkts, c->underrun);
1916         return length;
1917 }
1918
1919 static char *format_e1_status (u_char status)
1920 {
1921         static char buf [80];
1922
1923         if (status & E1_NOALARM)
1924                 return "Ok";
1925         buf[0] = 0;
1926         if (status & E1_LOS)     strcat (buf, ",LOS");
1927         if (status & E1_AIS)     strcat (buf, ",AIS");
1928         if (status & E1_LOF)     strcat (buf, ",LOF");
1929         if (status & E1_LOMF)    strcat (buf, ",LOMF");
1930         if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
1931         if (status & E1_AIS16)   strcat (buf, ",AIS16");
1932         if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
1933         if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
1934         if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
1935         if (buf[0] == ',')
1936                 return buf+1;
1937         return "Unknown";
1938 }
1939
1940 static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
1941 {
1942         int n, length = 0;
1943
1944         if (numerator < 1 || divider < 1) {
1945                 length += sprintf (s+length, leftalign ? "/-   " : "    -");
1946                 return length;
1947         }
1948         n = (int) (0.5 + 1000.0 * numerator / divider);
1949         if (n < 1000) {
1950                 length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
1951                 return length;
1952         }
1953         *(s + length) = leftalign ? '/' : ' ';
1954         length ++;
1955
1956         if      (n >= 1000000) n = (n+500) / 1000 * 1000;
1957         else if (n >= 100000)  n = (n+50)  / 100 * 100;
1958         else if (n >= 10000)   n = (n+5)   / 10 * 10;
1959
1960         switch (n) {
1961         case 1000:    length += printf (s+length, ".999"); return length;
1962         case 10000:   n = 9990;   break;
1963         case 100000:  n = 99900;  break;
1964         case 1000000: n = 999000; break;
1965         }
1966         if (n < 10000)        length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
1967         else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
1968         else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
1969         else                  length += sprintf (s+length, "%d", n/1000);
1970
1971         return length;
1972 }
1973
1974 static int print_e1_stats (char *s, cp_chan_t *c)
1975 {
1976         struct e1_counters total;
1977         u_long totsec;
1978         int length = 0;
1979
1980         totsec          = c->totsec + c->cursec;
1981         total.bpv       = c->total.bpv   + c->currnt.bpv;
1982         total.fse       = c->total.fse   + c->currnt.fse;
1983         total.crce      = c->total.crce  + c->currnt.crce;
1984         total.rcrce     = c->total.rcrce + c->currnt.rcrce;
1985         total.uas       = c->total.uas   + c->currnt.uas;
1986         total.les       = c->total.les   + c->currnt.les;
1987         total.es        = c->total.es    + c->currnt.es;
1988         total.bes       = c->total.bes   + c->currnt.bes;
1989         total.ses       = c->total.ses   + c->currnt.ses;
1990         total.oofs      = c->total.oofs  + c->currnt.oofs;
1991         total.css       = c->total.css   + c->currnt.css;
1992         total.dm        = c->total.dm    + c->currnt.dm;
1993
1994         length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
1995
1996         /* Unavailable seconds, degraded minutes */
1997         length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
1998         length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
1999
2000         /* Bipolar violations, frame sync errors */
2001         length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
2002         length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
2003
2004         /* CRC errors, remote CRC errors (E-bit) */
2005         length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
2006         length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
2007
2008         /* Errored seconds, line errored seconds */
2009         length += print_frac (s + length, 0, c->currnt.es, c->cursec);
2010         length += print_frac (s + length, 1, c->currnt.les, c->cursec);
2011
2012         /* Severely errored seconds, burst errored seconds */
2013         length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
2014         length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
2015
2016         /* Out of frame seconds, controlled slip seconds */
2017         length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
2018         length += print_frac (s + length, 1, c->currnt.css, c->cursec);
2019
2020         length += sprintf (s + length, " %s\n", format_e1_status (c->status));
2021
2022         /* Print total statistics. */
2023         length += print_frac (s + length, 0, total.uas, totsec);
2024         length += print_frac (s + length, 1, 60 * total.dm, totsec);
2025
2026         length += print_frac (s + length, 0, total.bpv, totsec);
2027         length += print_frac (s + length, 1, total.fse, totsec);
2028
2029         length += print_frac (s + length, 0, total.crce, totsec);
2030         length += print_frac (s + length, 1, total.rcrce, totsec);
2031
2032         length += print_frac (s + length, 0, total.es, totsec);
2033         length += print_frac (s + length, 1, total.les, totsec);
2034
2035         length += print_frac (s + length, 0, total.ses, totsec);
2036         length += print_frac (s + length, 1, total.bes, totsec);
2037
2038         length += print_frac (s + length, 0, total.oofs, totsec);
2039         length += print_frac (s + length, 1, total.css, totsec);
2040
2041         length += sprintf (s + length, " -- Total\n");
2042         return length;
2043 }
2044
2045 static int print_chan (char *s, cp_chan_t *c)
2046 {
2047         drv_t *d = c->sys;
2048         bdrv_t *bd = d->board->sys;
2049         int length = 0;
2050
2051         length += sprintf (s + length, "cp%d", c->board->num * NCHAN + c->num);
2052         if (d->chan->debug)
2053                 length += sprintf (s + length, " debug=%d", d->chan->debug);
2054
2055         if (c->board->mux) {
2056                 length += sprintf (s + length, " cfg=C");
2057         } else {
2058                 length += sprintf (s + length, " cfg=A");
2059         }
2060
2061         if (c->baud)
2062                 length += sprintf (s + length, " %ld", c->baud);
2063         else
2064                 length += sprintf (s + length, " extclock");
2065
2066         if (c->type == T_E1 || c->type == T_G703)
2067                 switch (c->gsyn) {
2068                 case GSYN_INT   : length += sprintf (s + length, " syn=int");     break;
2069                 case GSYN_RCV   : length += sprintf (s + length, " syn=rcv");     break;
2070                 case GSYN_RCV0  : length += sprintf (s + length, " syn=rcv0");    break;
2071                 case GSYN_RCV1  : length += sprintf (s + length, " syn=rcv1");    break;
2072                 case GSYN_RCV2  : length += sprintf (s + length, " syn=rcv2");    break;
2073                 case GSYN_RCV3  : length += sprintf (s + length, " syn=rcv3");    break;
2074                 }
2075         if (c->type == T_SERIAL) {
2076                 length += sprintf (s + length, " dpll=%s",   c->dpll   ? "on" : "off");
2077                 length += sprintf (s + length, " nrzi=%s",   c->nrzi   ? "on" : "off");
2078                 length += sprintf (s + length, " invclk=%s", c->invtxc ? "on" : "off");
2079         }
2080         if (c->type == T_E1)
2081                 length += sprintf (s + length, " higain=%s", c->higain ? "on" : "off");
2082
2083         length += sprintf (s + length, " loop=%s", c->lloop ? "on" : "off");
2084
2085         if (c->type == T_E1)
2086                 length += sprintf (s + length, " ts=%s", format_timeslots (c->ts));
2087         if (c->type == T_G703) {
2088                 int lq, x;
2089
2090                 x = splimp ();
2091                 CP_LOCK (bd);
2092                 lq = cp_get_lq (c);
2093                 CP_UNLOCK (bd);
2094                 splx (x);
2095                 length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2096         }
2097         length += sprintf (s + length, "\n");
2098         return length;
2099 }
2100
2101 static int ng_cp_rcvmsg (node_p node, item_p item, hook_p lasthook)
2102 {
2103         drv_t *d = NG_NODE_PRIVATE (node);
2104         struct ng_mesg *msg;
2105         struct ng_mesg *resp = NULL;
2106         int error = 0;
2107
2108         CP_DEBUG (d, ("Rcvmsg\n"));
2109         NGI_GET_MSG (item, msg);
2110         switch (msg->header.typecookie) {
2111         default:
2112                 error = EINVAL;
2113                 break;
2114
2115         case NGM_CP_COOKIE:
2116                 printf ("Not implemented yet\n");
2117                 error = EINVAL;
2118                 break;
2119
2120         case NGM_GENERIC_COOKIE:
2121                 switch (msg->header.cmd) {
2122                 default:
2123                         error = EINVAL;
2124                         break;
2125
2126                 case NGM_TEXT_STATUS: {
2127                         char *s;
2128                         int l = 0;
2129                         int dl = sizeof (struct ng_mesg) + 730;
2130
2131                         NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2132                         if (! resp) {
2133                                 error = ENOMEM;
2134                                 break;
2135                         }
2136                         s = (resp)->data;
2137                         if (d) {
2138                         l += print_chan (s + l, d->chan);
2139                         l += print_stats (s + l, d->chan, 1);
2140                         l += print_modems (s + l, d->chan, 1);
2141                         l += print_e1_stats (s + l, d->chan);
2142                         } else
2143                                 l += sprintf (s + l, "Error: node not connect to channel");
2144                         strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN);
2145                         }
2146                         break;
2147                 }
2148                 break;
2149         }
2150         NG_RESPOND_MSG (error, node, item, resp);
2151         NG_FREE_MSG (msg);
2152         return error;
2153 }
2154
2155 static int ng_cp_rcvdata (hook_p hook, item_p item)
2156 {
2157         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2158         struct mbuf *m;
2159         struct ng_tag_prio *ptag;
2160         bdrv_t *bd = d->board->sys;
2161         struct ifqueue *q;
2162         int s;
2163
2164         CP_DEBUG2 (d, ("Rcvdata\n"));
2165         NGI_GET_M (item, m);
2166         NG_FREE_ITEM (item);
2167         if (! NG_HOOK_PRIVATE (hook) || ! d) {
2168                 NG_FREE_M (m);
2169                 return ENETDOWN;
2170         }
2171
2172         /* Check for high priority data */
2173         if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
2174             NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
2175                 q = &d->hi_queue;
2176         else
2177                 q = &d->queue;
2178
2179         s = splimp ();
2180         CP_LOCK (bd);
2181         IF_LOCK (q);
2182         if (_IF_QFULL (q)) {
2183                 _IF_DROP (q);
2184                 IF_UNLOCK (q);
2185                 CP_UNLOCK (bd);
2186                 splx (s);
2187                 NG_FREE_M (m);
2188                 return ENOBUFS;
2189         }
2190         _IF_ENQUEUE (q, m);
2191         IF_UNLOCK (q);
2192         cp_start (d);
2193         CP_UNLOCK (bd);
2194         splx (s);
2195         return 0;
2196 }
2197
2198 static int ng_cp_rmnode (node_p node)
2199 {
2200         drv_t *d = NG_NODE_PRIVATE (node);
2201
2202         CP_DEBUG (d, ("Rmnode\n"));
2203         if (d && d->running) {
2204                 bdrv_t *bd = d->board->sys;
2205                 int s = splimp ();
2206                 CP_LOCK (bd);
2207                 cp_down (d);
2208                 CP_UNLOCK (bd);
2209                 splx (s);
2210         }
2211 #ifdef  KLD_MODULE
2212         if (node->nd_flags & NGF_REALLY_DIE) {
2213                 NG_NODE_SET_PRIVATE (node, NULL);
2214                 NG_NODE_UNREF (node);
2215         }
2216         NG_NODE_REVIVE(node);           /* Persistant node */
2217 #endif
2218         return 0;
2219 }
2220
2221 static void ng_cp_watchdog (void *arg)
2222 {
2223         drv_t *d = arg;
2224
2225         if (d) {
2226                 if (d->timeout == 1)
2227                         cp_watchdog (d);
2228                 if (d->timeout)
2229                         d->timeout--;
2230                 callout_reset (&d->timeout_handle, hz, ng_cp_watchdog, d);
2231         }
2232 }
2233
2234 static int ng_cp_connect (hook_p hook)
2235 {
2236         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2237
2238         if (d) {
2239                 CP_DEBUG (d, ("Connect\n"));
2240                 callout_reset (&d->timeout_handle, hz, ng_cp_watchdog, d);
2241         }
2242         
2243         return 0;
2244 }
2245
2246 static int ng_cp_disconnect (hook_p hook)
2247 {
2248         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2249
2250         if (d) {
2251                 CP_DEBUG (d, ("Disconnect\n"));
2252                 if (NG_HOOK_PRIVATE (hook))
2253                 {
2254                         bdrv_t *bd = d->board->sys;
2255                         int s = splimp ();
2256                         CP_LOCK (bd);
2257                         cp_down (d);
2258                         CP_UNLOCK (bd);
2259                         splx (s);
2260                 }
2261                 /* If we were wait it than it reasserted now, just stop it. */
2262                 if (!callout_drain (&d->timeout_handle))
2263                         callout_stop (&d->timeout_handle);
2264         }
2265         return 0;
2266 }
2267 #endif
2268
2269 static int cp_modevent (module_t mod, int type, void *unused)
2270 {
2271         static int load_count = 0;
2272
2273         if (cp_mpsafenet)
2274                 cp_cdevsw.d_flags &= ~D_NEEDGIANT;
2275
2276         switch (type) {
2277         case MOD_LOAD:
2278 #ifdef NETGRAPH
2279                 if (ng_newtype (&typestruct))
2280                         printf ("Failed to register ng_cp\n");
2281 #endif
2282                 ++load_count;
2283                 callout_init (&timeout_handle, cp_mpsafenet?CALLOUT_MPSAFE:0);
2284                 callout_reset (&timeout_handle, hz*5, cp_timeout, 0);
2285                 break;
2286         case MOD_UNLOAD:
2287                 if (load_count == 1) {
2288                         printf ("Removing device entry for Tau-PCI\n");
2289 #ifdef NETGRAPH
2290                         ng_rmtype (&typestruct);
2291 #endif                  
2292                 }
2293                 /* If we were wait it than it reasserted now, just stop it.
2294                  * Actually we shouldn't get this condition. But code could be
2295                  * changed in the future, so just be a litle paranoid.
2296                  */
2297                 if (!callout_drain (&timeout_handle))
2298                         callout_stop (&timeout_handle);
2299                 --load_count;
2300                 break;
2301         case MOD_SHUTDOWN:
2302                 break;
2303         }
2304         return 0;
2305 }
2306
2307 #ifdef NETGRAPH
2308 static struct ng_type typestruct = {
2309         .version        = NG_ABI_VERSION,
2310         .name           = NG_CP_NODE_TYPE,
2311         .constructor    = ng_cp_constructor,
2312         .rcvmsg         = ng_cp_rcvmsg,
2313         .shutdown       = ng_cp_rmnode,
2314         .newhook        = ng_cp_newhook,
2315         .connect        = ng_cp_connect,
2316         .rcvdata        = ng_cp_rcvdata,
2317         .disconnect     = ng_cp_disconnect,
2318 };
2319 #endif /*NETGRAPH*/
2320
2321 #ifdef NETGRAPH
2322 MODULE_DEPEND (ng_cp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2323 #else
2324 MODULE_DEPEND (cp, sppp, 1, 1, 1);
2325 #endif
2326 DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL);
2327 MODULE_VERSION (cp, 1);