]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ce/if_ce.c
Upgrade our copy of llvm/clang to 3.4 release. This version supports
[FreeBSD/FreeBSD.git] / sys / dev / ce / if_ce.c
1 /*
2  * Cronyx-Tau32-PCI adapter driver for FreeBSD.
3  *
4  * Copyright (C) 2003-2005 Cronyx Engineering.
5  * Copyright (C) 2003-2005 Kurakin Roman, <rik@FreeBSD.org>
6  *
7  * This software is distributed with NO WARRANTIES, not even the implied
8  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9  *
10  * Authors grant any other persons or organisations a permission to use,
11  * modify and redistribute this software in source and binary forms,
12  * as long as this message is kept with the software, all derivative
13  * works or modified versions.
14  *
15  * $Cronyx: if_ce.c,v 1.9.2.8 2005/11/21 14:17:44 rik Exp $
16  */
17
18 #include <sys/cdefs.h>
19 __FBSDID("$FreeBSD$");
20
21 #include <sys/param.h>
22
23 #if __FreeBSD_version >= 500000
24 #   define NPCI 1
25 #else
26 #   include "pci.h"
27 #endif
28
29 #if NPCI > 0
30
31 #include <sys/ucred.h>
32 #include <sys/priv.h>
33 #include <sys/proc.h>
34 #include <sys/systm.h>
35 #include <sys/mbuf.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/conf.h>
39 #include <sys/malloc.h>
40 #include <sys/socket.h>
41 #include <sys/sockio.h>
42 #if __FreeBSD_version >= 504000
43 #include <sys/sysctl.h>
44 #endif
45 #include <sys/tty.h>
46 #include <sys/bus.h>
47 #include <vm/vm.h>
48 #include <vm/pmap.h>
49 #include <net/if.h>
50 #include <net/if_var.h>
51 #if __FreeBSD_version > 501000
52 #   include <dev/pci/pcivar.h>
53 #   include <dev/pci/pcireg.h>
54 #else
55 #   include <pci/pcivar.h>
56 #   include <pci/pcireg.h>
57 #endif
58 #include <machine/bus.h>
59 #include <sys/rman.h>
60 #include "opt_ng_cronyx.h"
61 #ifdef NETGRAPH_CRONYX
62 #   include "opt_netgraph.h"
63 #   ifndef NETGRAPH
64 #       error #option   NETGRAPH missed from configuration
65 #   endif
66 #   include <netgraph/ng_message.h>
67 #   include <netgraph/netgraph.h>
68 #   include <dev/ce/ng_ce.h>
69 #else
70 #   include <net/if_types.h>
71 #   include <net/if_sppp.h>
72 #   define PP_CISCO IFF_LINK2
73 #   include <net/bpf.h>
74 #endif
75 #include <dev/cx/machdep.h>
76 #include <dev/ce/ceddk.h>
77 #include <machine/cserial.h>
78 #include <machine/resource.h>
79 #include <machine/pmap.h>
80
81 /* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
82 #ifndef PP_FR
83 #define PP_FR 0
84 #endif
85
86 #ifndef IFP2SP
87 #define IFP2SP(ifp)     ((struct sppp*)ifp)
88 #endif
89 #ifndef SP2IFP
90 #define SP2IFP(sp)      ((struct ifnet*)sp)
91 #endif
92
93 #ifndef PCIR_BAR
94 #define PCIR_BAR(x)     (PCIR_MAPS + (x) * 4)
95 #endif
96
97 /* define as our previous return value */
98 #ifndef BUS_PROBE_DEFAULT
99 #define BUS_PROBE_DEFAULT 0
100 #endif
101
102 #define CE_DEBUG(d,s)   ({if (d->chan->debug) {\
103                                 printf ("%s: ", d->name); printf s;}})
104 #define CE_DEBUG2(d,s)  ({if (d->chan->debug>1) {\
105                                 printf ("%s: ", d->name); printf s;}})
106
107 #ifndef CALLOUT_MPSAFE
108 #define CALLOUT_MPSAFE          0
109 #endif
110
111 #ifndef IF_DRAIN
112 #define IF_DRAIN(ifq) do {              \
113         struct mbuf *m;                 \
114         for (;;) {                      \
115                 IF_DEQUEUE(ifq, m);     \
116                 if (m == NULL)          \
117                         break;          \
118                 m_freem(m);             \
119         }                               \
120 } while (0)
121 #endif
122
123 #ifndef _IF_QLEN
124 #define _IF_QLEN(ifq)   ((ifq)->ifq_len)
125 #endif
126
127 #ifndef callout_drain
128 #define callout_drain callout_stop
129 #endif
130
131 #define CE_LOCK_NAME            "ceX"
132
133 #define CE_LOCK(_bd)            mtx_lock (&(_bd)->ce_mtx)
134 #define CE_UNLOCK(_bd)          mtx_unlock (&(_bd)->ce_mtx)
135 #define CE_LOCK_ASSERT(_bd)     mtx_assert (&(_bd)->ce_mtx, MA_OWNED)
136
137 #define CDEV_MAJOR      185
138
139 static  int ce_probe            __P((device_t));
140 static  int ce_attach           __P((device_t));
141 static  int ce_detach           __P((device_t));
142
143 static  device_method_t ce_methods[] = {
144         /* Device interface */
145         DEVMETHOD(device_probe,         ce_probe),
146         DEVMETHOD(device_attach,        ce_attach),
147         DEVMETHOD(device_detach,        ce_detach),
148
149         DEVMETHOD_END
150 };
151
152 typedef struct _ce_dma_mem_t {
153         unsigned long   phys;
154         void            *virt;
155         size_t          size;
156 #if __FreeBSD_version >= 500000
157         bus_dma_tag_t   dmat;
158         bus_dmamap_t    mapp;
159 #endif
160 } ce_dma_mem_t;
161
162 typedef struct _drv_t {
163         char    name [8];
164         int     running;
165         ce_board_t      *board;
166         ce_chan_t       *chan;
167         struct ifqueue  rqueue;
168 #ifdef NETGRAPH
169         char    nodename [NG_NODESIZE];
170         hook_p  hook;
171         hook_p  debug_hook;
172         node_p  node;
173         struct  ifqueue queue;
174         struct  ifqueue hi_queue;
175 #else
176         struct  ifnet *ifp;
177 #endif
178         short   timeout;
179         struct  callout timeout_handle;
180 #if __FreeBSD_version >= 500000
181         struct  cdev *devt;
182 #else /* __FreeBSD_version < 500000 */
183         dev_t   devt;
184 #endif
185         ce_dma_mem_t dmamem;
186 } drv_t;
187
188 typedef struct _bdrv_t {
189         ce_board_t      *board;
190         struct resource *ce_res;
191         struct resource *ce_irq;
192         void            *ce_intrhand;
193         ce_dma_mem_t    dmamem;
194         drv_t           channel [NCHAN];
195 #if __FreeBSD_version >= 504000
196         struct mtx      ce_mtx;
197 #endif
198 } bdrv_t;
199
200 static  driver_t ce_driver = {
201         "ce",
202         ce_methods,
203         sizeof(bdrv_t),
204 };
205
206 static  devclass_t ce_devclass;
207
208 static void ce_receive (ce_chan_t *c, unsigned char *data, int len);
209 static void ce_transmit (ce_chan_t *c, void *attachment, int len);
210 static void ce_error (ce_chan_t *c, int data);
211 static void ce_up (drv_t *d);
212 static void ce_start (drv_t *d);
213 static void ce_down (drv_t *d);
214 static void ce_watchdog (drv_t *d);
215 static void ce_watchdog_timer (void *arg);
216 #ifdef NETGRAPH
217 extern struct ng_type typestruct;
218 #else
219 static void ce_ifstart (struct ifnet *ifp);
220 static void ce_tlf (struct sppp *sp);
221 static void ce_tls (struct sppp *sp);
222 static int ce_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
223 static void ce_initialize (void *softc);
224 #endif
225
226 static ce_board_t *adapter [NBRD];
227 static drv_t *channel [NBRD*NCHAN];
228 static struct callout led_timo [NBRD];
229 static struct callout timeout_handle;
230
231 static int ce_destroy = 0;
232
233 #if __FreeBSD_version < 500000
234 static int ce_open (dev_t dev, int oflags, int devtype, struct proc *p);
235 static int ce_close (dev_t dev, int fflag, int devtype, struct proc *p);
236 static int ce_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p);
237 #else
238 static int ce_open (struct cdev *dev, int oflags, int devtype, struct thread *td);
239 static int ce_close (struct cdev *dev, int fflag, int devtype, struct thread *td);
240 static int ce_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td);
241 #endif
242 #if __FreeBSD_version < 500000
243 static struct cdevsw ce_cdevsw = {
244         ce_open,        ce_close,       noread,         nowrite,
245         ce_ioctl,       nopoll,         nommap,         nostrategy,
246         "ce",           CDEV_MAJOR,     nodump,         nopsize,
247         D_NAGGED,       -1
248         };
249 #elif __FreeBSD_version == 500000
250 static struct cdevsw ce_cdevsw = {
251         ce_open,        ce_close,       noread,         nowrite,
252         ce_ioctl,       nopoll,         nommap,         nostrategy,
253         "ce",           CDEV_MAJOR,     nodump,         nopsize,
254         D_NAGGED,
255         };
256 #elif __FreeBSD_version <= 501000
257 static struct cdevsw ce_cdevsw = {
258         .d_open     = ce_open,
259         .d_close    = ce_close,
260         .d_read     = noread,
261         .d_write    = nowrite,
262         .d_ioctl    = ce_ioctl,
263         .d_poll     = nopoll,
264         .d_mmap     = nommap,
265         .d_strategy = nostrategy,
266         .d_name     = "ce",
267         .d_maj      = CDEV_MAJOR,
268         .d_dump     = nodump,
269         .d_flags    = D_NAGGED,
270 };
271 #elif __FreeBSD_version < 502103
272 static struct cdevsw ce_cdevsw = {
273         .d_open     = ce_open,
274         .d_close    = ce_close,
275         .d_ioctl    = ce_ioctl,
276         .d_name     = "ce",
277         .d_maj      = CDEV_MAJOR,
278         .d_flags    = D_NAGGED,
279 };
280 #elif __FreeBSD_version < 600000
281 static struct cdevsw ce_cdevsw = {
282         .d_version  = D_VERSION,
283         .d_open     = ce_open,
284         .d_close    = ce_close,
285         .d_ioctl    = ce_ioctl,
286         .d_name     = "ce",
287         .d_maj      = CDEV_MAJOR,
288         .d_flags    = D_NEEDGIANT,
289 };
290 #else /* __FreeBSD_version >= 600000 */
291 static struct cdevsw ce_cdevsw = {
292         .d_version  = D_VERSION,
293         .d_open     = ce_open,
294         .d_close    = ce_close,
295         .d_ioctl    = ce_ioctl,
296         .d_name     = "ce",
297 };
298 #endif
299
300 /*
301  * Print the mbuf chain, for debug purposes only.
302  */
303 static void printmbuf (struct mbuf *m)
304 {
305         printf ("mbuf:");
306         for (; m; m=m->m_next) {
307                 if (m->m_flags & M_PKTHDR)
308                         printf (" HDR %d:", m->m_pkthdr.len);
309                 if (m->m_flags & M_EXT)
310                         printf (" EXT:");
311                 printf (" %d", m->m_len);
312         }
313         printf ("\n");
314 }
315
316 /*
317  * Make an mbuf from data.
318  */
319 static struct mbuf *makembuf (void *buf, unsigned len)
320 {
321         struct mbuf *m;
322
323         MGETHDR (m, M_NOWAIT, MT_DATA);
324         if (! m)
325                 return 0;
326         MCLGET (m, M_NOWAIT);
327         if (! (m->m_flags & M_EXT)) {
328                 m_freem (m);
329                 return 0;
330         }
331         m->m_pkthdr.len = m->m_len = len;
332         bcopy (buf, mtod (m, caddr_t), len);
333         return m;
334 }
335
336 static int ce_probe (device_t dev)
337 {
338         if ((pci_get_vendor (dev) == TAU32_PCI_VENDOR_ID) &&
339             (pci_get_device (dev) == TAU32_PCI_DEVICE_ID)) {
340                 device_set_desc (dev, "Cronyx-Tau32-PCI serial adapter");
341                 return BUS_PROBE_DEFAULT;
342         }
343         return ENXIO;
344 }
345
346 static void ce_timeout (void *arg)
347 {
348         drv_t *d;
349         int s, i, k;
350
351         for (i = 0; i < NBRD; ++i) {
352                 if (adapter[i] == NULL)
353                         continue;
354                 for (k = 0; k < NCHAN; ++k) {
355                         s = splimp ();
356                         if (ce_destroy) {
357                                 splx (s);
358                                 return;
359                         }
360                         d = channel[i * NCHAN + k];
361                         if (!d) {
362                                 splx (s);
363                                 continue;
364                         }
365                         CE_LOCK ((bdrv_t *)d->board->sys);
366                         switch (d->chan->type) {
367                         case T_E1:
368                                 ce_e1_timer (d->chan);
369                                 break;
370                         default:
371                                 break;
372                         }
373                         CE_UNLOCK ((bdrv_t *)d->board->sys);
374                         splx (s);
375                 }
376         }
377         s = splimp ();
378         if (!ce_destroy)
379                 callout_reset (&timeout_handle, hz, ce_timeout, 0);
380         splx (s);
381 }
382
383 static void ce_led_off (void *arg)
384 {
385         ce_board_t *b = arg;
386         bdrv_t *bd = (bdrv_t *) b->sys;
387         int s;
388         s = splimp ();
389         if (ce_destroy) {
390                 splx (s);
391                 return;
392         }
393         CE_LOCK (bd);
394         TAU32_LedSet (b->ddk.pControllerObject, 0);
395         CE_UNLOCK (bd);
396         splx (s);
397 }
398
399 static void ce_intr (void *arg)
400 {
401         bdrv_t *bd = arg;
402         ce_board_t *b = bd->board;
403         int s;
404         int i;
405 #if __FreeBSD_version >= 500000 && defined NETGRAPH
406         int error;
407 #endif
408         s = splimp ();
409         if (ce_destroy) {
410                 splx (s);
411                 return;
412         }
413         CE_LOCK (bd);
414         /* Turn LED on. */
415         TAU32_LedSet (b->ddk.pControllerObject, 1);
416
417         TAU32_HandleInterrupt (b->ddk.pControllerObject);
418
419         /* Turn LED off 50 msec later. */
420         callout_reset (&led_timo[b->num], hz/20, ce_led_off, b);
421         CE_UNLOCK (bd);
422         splx (s);
423
424         /* Pass packets in a lock-free state */
425         for (i = 0; i < NCHAN && b->chan[i].type; i++) {
426                 drv_t *d = b->chan[i].sys;
427                 struct mbuf *m;
428                 if (!d || !d->running)
429                         continue;
430                 while (_IF_QLEN(&d->rqueue)) {
431                         IF_DEQUEUE (&d->rqueue,m);
432                         if (!m)
433                                 continue;
434 #ifdef NETGRAPH
435                         if (d->hook) {
436 #if __FreeBSD_version >= 500000
437                                 NG_SEND_DATA_ONLY (error, d->hook, m);
438 #else
439                                 ng_queue_data (d->hook, m, 0);
440 #endif
441                         } else {
442                                 IF_DRAIN (&d->rqueue);
443                         }
444 #else
445                         sppp_input (d->ifp, m); 
446 #endif
447                 }
448         }
449 }
450
451 #if __FreeBSD_version >= 500000
452 static void
453 ce_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
454 {
455         unsigned long *addr;
456
457         if (error)
458                 return;
459
460         KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
461         addr = arg;
462         *addr = segs->ds_addr;
463 }
464
465 #ifndef BUS_DMA_ZERO
466 #define BUS_DMA_ZERO 0
467 #endif
468
469 static int
470 ce_bus_dma_mem_alloc (int bnum, int cnum, ce_dma_mem_t *dmem)
471 {
472         int error;
473
474         error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT,
475                 BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
476                 dmem->size, 0,
477 #if __FreeBSD_version >= 502000
478                 NULL, NULL,
479 #endif
480                 &dmem->dmat);
481         if (error) {
482                 if (cnum >= 0)  printf ("ce%d-%d: ", bnum, cnum);
483                 else            printf ("ce%d: ", bnum);
484                 printf ("couldn't allocate tag for dma memory\n");
485                 return 0;
486         }
487         error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
488                 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
489         if (error) {
490                 if (cnum >= 0)  printf ("ce%d-%d: ", bnum, cnum);
491                 else            printf ("ce%d: ", bnum);
492                 printf ("couldn't allocate mem for dma memory\n");
493                 bus_dma_tag_destroy (dmem->dmat);
494                 return 0;
495         }
496         error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
497                 dmem->size, ce_bus_dmamap_addr, &dmem->phys, 0);
498         if (error) {
499                 if (cnum >= 0)  printf ("ce%d-%d: ", bnum, cnum);
500                 else            printf ("ce%d: ", bnum);
501                 printf ("couldn't load mem map for dma memory\n");
502                 bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
503                 bus_dma_tag_destroy (dmem->dmat);
504                 return 0;
505         }
506 #if __FreeBSD_version >= 502000
507         bzero (dmem->virt, dmem->size);
508 #endif
509         return 1;
510 }
511
512 static void
513 ce_bus_dma_mem_free (ce_dma_mem_t *dmem)
514 {
515         bus_dmamap_unload (dmem->dmat, dmem->mapp);
516         bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
517         bus_dma_tag_destroy (dmem->dmat);
518 }
519 #else
520 static int
521 ce_bus_dma_mem_alloc (int bnum, int cnum, ce_dma_mem_t *dmem)
522 {
523         dmem->virt = contigmalloc (dmem->size, M_DEVBUF, M_WAITOK,
524                                    0x100000, 0xffffffff, 16, 0);
525         if (dmem->virt == NULL) {
526                 if (cnum >= 0)  printf ("ce%d-%d: ", bnum, cnum);
527                 else            printf ("ce%d: ", bnum);
528                 printf ("couldn't allocate dma memory\n");
529                 return 0;
530         }
531         dmem->phys = vtophys (dmem->virt);
532         bzero (dmem->virt, dmem->size);
533         return 1;
534 }
535
536 static void
537 ce_bus_dma_mem_free (ce_dma_mem_t *dmem)
538 {
539         contigfree (dmem->virt, dmem->size, M_DEVBUF);
540 }
541 #endif
542
543 /*
544  * Called if the probe succeeded.
545  */
546 static int ce_attach (device_t dev)
547 {
548         bdrv_t *bd = device_get_softc (dev);
549         int unit = device_get_unit (dev);
550 #if __FreeBSD_version >= 504000
551         char *ce_ln = CE_LOCK_NAME;
552 #endif
553         vm_offset_t vbase;
554         int rid, error;
555         ce_board_t *b;
556         ce_chan_t *c;
557         drv_t *d;
558         int s;
559                 
560         b = malloc (sizeof(ce_board_t), M_DEVBUF, M_WAITOK);
561         if (!b) {
562                 printf ("ce%d: couldn't allocate memory\n", unit);
563                 return (ENXIO);
564         }
565         bzero (b, sizeof(ce_board_t));
566
567         b->ddk.sys = &b;
568
569 #if __FreeBSD_version >= 440000
570         pci_enable_busmaster (dev);
571 #endif
572
573         bd->dmamem.size = TAU32_ControllerObjectSize;
574         if (! ce_bus_dma_mem_alloc (unit, -1, &bd->dmamem)) {
575                 free (b, M_DEVBUF);
576                 return (ENXIO);
577         }
578         b->ddk.pControllerObject = bd->dmamem.virt;
579
580         bd->board = b;
581         b->sys = bd;
582         rid = PCIR_BAR(0);
583         bd->ce_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid,
584                         0, ~0, 1, RF_ACTIVE);
585         if (! bd->ce_res) {
586                 printf ("ce%d: cannot map memory\n", unit);
587                 ce_bus_dma_mem_free (&bd->dmamem);
588                 free (b, M_DEVBUF);
589                 return (ENXIO);
590         }
591         vbase = (vm_offset_t) rman_get_virtual (bd->ce_res);
592
593         b->ddk.PciBar1VirtualAddress = (void *)vbase;
594         b->ddk.ControllerObjectPhysicalAddress = bd->dmamem.phys;
595         b->ddk.pErrorNotifyCallback = ce_error_callback;
596         b->ddk.pStatusNotifyCallback = ce_status_callback;
597         b->num = unit;
598
599         TAU32_BeforeReset(&b->ddk);
600         pci_write_config (dev, TAU32_PCI_RESET_ADDRESS, TAU32_PCI_RESET_ON, 4);
601         pci_write_config (dev, TAU32_PCI_RESET_ADDRESS, TAU32_PCI_RESET_OFF, 4);
602
603         if(!TAU32_Initialize(&b->ddk, 0))
604         {
605                 printf ("ce%d: init adapter error 0x%08x, bus dead bits 0x%08lx\n",
606                         unit, b->ddk.InitErrors, b->ddk.DeadBits);
607                 bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->ce_res);
608                 ce_bus_dma_mem_free (&bd->dmamem);
609                 free (b, M_DEVBUF);
610                 return (ENXIO);
611         }
612
613         s = splimp ();
614
615         ce_init_board (b);
616
617         rid = 0;
618         bd->ce_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
619                         RF_SHAREABLE | RF_ACTIVE);
620         if (! bd->ce_irq) {
621                 printf ("ce%d: cannot map interrupt\n", unit);
622                 bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->ce_res);
623                 ce_bus_dma_mem_free (&bd->dmamem);
624                 free (b, M_DEVBUF);
625                 splx (s);
626                 return (ENXIO);
627         }
628 #if __FreeBSD_version >= 500000
629         callout_init (&led_timo[unit], CALLOUT_MPSAFE);
630 #else
631         callout_init (&led_timo[unit]);
632 #endif
633         error  = bus_setup_intr (dev, bd->ce_irq,
634 #if __FreeBSD_version >= 500013
635                                 INTR_TYPE_NET|INTR_MPSAFE,
636 #else
637                                 INTR_TYPE_NET,
638 #endif
639                                 NULL, ce_intr, bd, &bd->ce_intrhand);
640         if (error) {
641                 printf ("ce%d: cannot set up irq\n", unit);
642                 bus_release_resource (dev, SYS_RES_IRQ, 0, bd->ce_irq);
643                 bus_release_resource (dev, SYS_RES_MEMORY,
644                                 PCIR_BAR(0), bd->ce_res);
645                 ce_bus_dma_mem_free (&bd->dmamem);
646                 free (b, M_DEVBUF);
647                 splx (s);
648                 return (ENXIO);
649         }
650
651         switch (b->ddk.Model) {
652         case 1:         strcpy (b->name, TAU32_BASE_NAME);      break;
653         case 2:         strcpy (b->name, TAU32_LITE_NAME);      break;
654         case 3:         strcpy (b->name, TAU32_ADPCM_NAME);     break;
655         default:        strcpy (b->name, TAU32_UNKNOWN_NAME);   break;
656         }
657
658         printf ("ce%d: %s\n", unit, b->name);
659
660         for (c = b->chan; c < b->chan + NCHAN; ++c) {
661                 c->num = (c - b->chan);
662                 c->board = b;
663
664                 d = &bd->channel[c->num];
665                 d->dmamem.size = sizeof(ce_buf_t);
666                 if (! ce_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
667                         continue;
668
669                 channel [b->num * NCHAN + c->num] = d;
670                 sprintf (d->name, "ce%d.%d", b->num, c->num);
671                 d->board = b;
672                 d->chan = c;
673                 c->sys = d;
674         }
675
676         for (c = b->chan; c < b->chan + NCHAN; ++c) {
677                 if (c->sys == NULL)
678                         continue;
679                 d = c->sys;
680
681                 callout_init (&d->timeout_handle, CALLOUT_MPSAFE);
682 #ifdef NETGRAPH
683                 if (ng_make_node_common (&typestruct, &d->node) != 0) {
684                         printf ("%s: cannot make common node\n", d->name);
685                         d->node = NULL;
686                         continue;
687                 }
688 #if __FreeBSD_version >= 500000
689                 NG_NODE_SET_PRIVATE (d->node, d);
690 #else
691                 d->node->private = d;
692 #endif
693                 sprintf (d->nodename, "%s%d", NG_CE_NODE_TYPE,
694                          c->board->num * NCHAN + c->num);
695                 if (ng_name_node (d->node, d->nodename)) {
696                         printf ("%s: cannot name node\n", d->nodename);
697 #if __FreeBSD_version >= 500000
698                         NG_NODE_UNREF (d->node);
699 #else
700                         ng_rmnode (d->node);
701                         ng_unref (d->node);
702 #endif
703                         continue;
704                 }
705                 d->queue.ifq_maxlen     = ifqmaxlen;
706                 d->hi_queue.ifq_maxlen  = ifqmaxlen;
707                 d->rqueue.ifq_maxlen    = ifqmaxlen;
708 #if __FreeBSD_version >= 500000
709                 mtx_init (&d->queue.ifq_mtx, "ce_queue", NULL, MTX_DEF);
710                 mtx_init (&d->hi_queue.ifq_mtx, "ce_queue_hi", NULL, MTX_DEF);
711                 mtx_init (&d->rqueue.ifq_mtx, "ce_rqueue", NULL, MTX_DEF);
712 #endif          
713 #else /*NETGRAPH*/
714 #if __FreeBSD_version >= 600031
715                 d->ifp = if_alloc(IFT_PPP);
716 #else
717                 d->ifp = malloc (sizeof(struct sppp), M_DEVBUF, M_WAITOK);
718                 bzero (d->ifp, sizeof(struct sppp));
719 #endif
720                 if (!d->ifp) {
721                         printf ("%s: cannot if_alloc() interface\n", d->name);
722                         continue;
723                 }
724                 d->ifp->if_softc        = d;
725 #if __FreeBSD_version > 501000
726                 if_initname (d->ifp, "ce", b->num * NCHAN + c->num);
727 #else
728                 d->ifp->if_unit         = b->num * NCHAN + c->num;
729                 d->ifp->if_name         = "ce";
730 #endif
731                 d->ifp->if_mtu          = PP_MTU;
732                 d->ifp->if_flags        = IFF_POINTOPOINT | IFF_MULTICAST;
733                 d->ifp->if_ioctl        = ce_sioctl;
734                 d->ifp->if_start        = ce_ifstart;
735                 d->ifp->if_init         = ce_initialize;
736                 d->rqueue.ifq_maxlen    = ifqmaxlen;
737 #if __FreeBSD_version >= 500000
738                 mtx_init (&d->rqueue.ifq_mtx, "ce_rqueue", NULL, MTX_DEF);
739 #endif          
740                 sppp_attach (d->ifp);
741                 if_attach (d->ifp);
742                 IFP2SP(d->ifp)->pp_tlf  = ce_tlf;
743                 IFP2SP(d->ifp)->pp_tls  = ce_tls;
744                 /* If BPF is in the kernel, call the attach for it.
745                  * The header size of PPP or Cisco/HDLC is 4 bytes. */
746                 bpfattach (d->ifp, DLT_PPP, 4);
747 #endif /*NETGRAPH*/
748                 ce_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys);
749
750                 /* Register callback functions. */
751                 ce_register_transmit (c, &ce_transmit);
752                 ce_register_receive (c, &ce_receive);
753                 ce_register_error (c, &ce_error);
754                 d->devt = make_dev (&ce_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
755                                 GID_WHEEL, 0600, "ce%d", b->num*NCHAN+c->num);
756         }
757
758 #if __FreeBSD_version >= 504000
759         ce_ln[2] = '0' + unit;
760         mtx_init (&bd->ce_mtx, ce_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
761 #endif
762         CE_LOCK (bd);
763         TAU32_EnableInterrupts(b->ddk.pControllerObject);
764         adapter[unit] = b;
765         CE_UNLOCK (bd);
766         splx (s);
767
768         return 0;
769 }
770
771 static int ce_detach (device_t dev)
772 {
773         bdrv_t *bd = device_get_softc (dev);
774         ce_board_t *b = bd->board;
775         ce_chan_t *c;
776         int s;
777
778 #if __FreeBSD_version >= 504000
779         KASSERT (mtx_initialized (&bd->ce_mtx), ("ce mutex not initialized"));
780 #endif
781         s = splimp ();
782         CE_LOCK (bd);
783         /* Check if the device is busy (open). */
784         for (c = b->chan; c < b->chan + NCHAN; ++c) {
785                 drv_t *d = (drv_t*) c->sys;
786
787                 /* XXX Non existen chan! */
788                 if (! d || ! d->chan)
789                         continue;
790                 if (d->running) {
791                         CE_UNLOCK (bd);
792                         splx (s);
793                         return EBUSY;
794                 }
795         }
796
797         /* Ok, we can unload driver */
798         /* At first we should disable interrupts */
799         ce_destroy = 1;
800         TAU32_DisableInterrupts(b->ddk.pControllerObject);
801
802         callout_stop (&led_timo[b->num]);
803
804         for (c = b->chan; c < b->chan + NCHAN; ++c) {
805                 drv_t *d = (drv_t*) c->sys;
806
807                 if (! d || ! d->chan)
808                         continue;
809                 callout_stop (&d->timeout_handle);
810 #ifndef NETGRAPH
811                 /* Detach from the packet filter list of interfaces. */
812                 bpfdetach (d->ifp);
813
814                 /* Detach from the sync PPP list. */
815                 sppp_detach (d->ifp);
816
817                 /* Detach from the system list of interfaces. */
818                 if_detach (d->ifp);
819 #if __FreeBSD_version > 600031
820                 if_free(d->ifp);
821 #else
822                 free (d->ifp, M_DEVBUF);
823 #endif
824
825                 IF_DRAIN (&d->rqueue);
826 #if __FreeBSD_version >= 500000
827                 mtx_destroy (&d->rqueue.ifq_mtx);
828 #endif
829 #else
830 #if __FreeBSD_version >= 500000
831                 if (d->node) {
832                         ng_rmnode_self (d->node);
833                         NG_NODE_UNREF (d->node);
834                         d->node = NULL;
835                 }
836                 IF_DRAIN (&d->rqueue);
837                 mtx_destroy (&d->queue.ifq_mtx);
838                 mtx_destroy (&d->hi_queue.ifq_mtx);
839                 mtx_destroy (&d->rqueue.ifq_mtx);
840 #else
841                 ng_rmnode (d->node);
842                 d->node = 0;
843 #endif
844 #endif
845                 destroy_dev (d->devt);
846         }
847
848         CE_UNLOCK (bd);
849         splx (s);
850
851         callout_drain (&led_timo[b->num]);
852
853         /* Disable the interrupt request. */
854         bus_teardown_intr (dev, bd->ce_irq, bd->ce_intrhand);
855         bus_release_resource (dev, SYS_RES_IRQ, 0, bd->ce_irq);
856         TAU32_DestructiveHalt (b->ddk.pControllerObject, 0);
857         bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->ce_res);
858
859         for (c = b->chan; c < b->chan + NCHAN; ++c) {
860                 drv_t *d = (drv_t*) c->sys;
861
862                 if (! d || ! d->chan)
863                         continue;
864                 callout_drain (&d->timeout_handle);
865                 channel [b->num * NCHAN + c->num] = 0;
866                 /* Deallocate buffers. */
867                 ce_bus_dma_mem_free (&d->dmamem);
868         }
869         adapter [b->num] = 0;
870         ce_bus_dma_mem_free (&bd->dmamem);
871         free (b, M_DEVBUF);
872 #if __FreeBSD_version >= 504000
873         mtx_destroy (&bd->ce_mtx);
874 #endif
875         return 0;
876 }
877
878 #ifndef NETGRAPH
879 static void ce_ifstart (struct ifnet *ifp)
880 {
881         drv_t *d = ifp->if_softc;
882         bdrv_t *bd = d->board->sys;
883
884         CE_LOCK (bd);
885         ce_start (d);
886         CE_UNLOCK (bd);
887 }
888
889 static void ce_tlf (struct sppp *sp)
890 {
891         drv_t *d = SP2IFP(sp)->if_softc;
892
893         CE_DEBUG2 (d, ("ce_tlf\n"));
894         sp->pp_down (sp);
895 }
896
897 static void ce_tls (struct sppp *sp)
898 {
899         drv_t *d = SP2IFP(sp)->if_softc;
900
901         CE_DEBUG2 (d, ("ce_tls\n"));
902         sp->pp_up (sp);
903 }
904
905 /*
906  * Process an ioctl request.
907  */
908 static int ce_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
909 {
910         drv_t *d = ifp->if_softc;
911         bdrv_t *bd = d->board->sys;
912         int error, s, was_up, should_be_up;
913
914 #if __FreeBSD_version >= 600034
915         was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
916 #else
917         was_up = (ifp->if_flags & IFF_RUNNING) != 0;
918 #endif
919         error = sppp_ioctl (ifp, cmd, data);
920
921         if (error)
922                 return error;
923
924         if (! (ifp->if_flags & IFF_DEBUG))
925                 d->chan->debug = 0;
926         else
927                 d->chan->debug = d->chan->debug_shadow;
928
929         switch (cmd) {
930         default:           CE_DEBUG2 (d, ("ioctl 0x%lx\n", cmd));   return 0;
931         case SIOCADDMULTI: CE_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0;
932         case SIOCDELMULTI: CE_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0;
933         case SIOCSIFFLAGS: CE_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break;
934         case SIOCSIFADDR:  CE_DEBUG2 (d, ("ioctl SIOCSIFADDR\n"));  break;
935         }
936
937         /* We get here only in case of SIFFLAGS or SIFADDR. */
938         s = splimp ();
939         CE_LOCK (bd);
940 #if __FreeBSD_version >= 600034
941         should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
942 #else
943         should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
944 #endif
945         if (! was_up && should_be_up) {
946                 /* Interface goes up -- start it. */
947                 ce_up (d);
948                 ce_start (d);
949         } else if (was_up && ! should_be_up) {
950                 /* Interface is going down -- stop it. */
951 /*              if ((IFP2SP(ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
952                 ce_down (d);
953         }
954         CE_DEBUG (d, ("ioctl 0x%lx p4\n", cmd));
955         CE_UNLOCK (bd);
956         splx (s);
957         return 0;
958 }
959
960 /*
961  * Initialization of interface.
962  * It seems to be never called by upper level?
963  */
964 static void ce_initialize (void *softc)
965 {
966         drv_t *d = softc;
967
968         CE_DEBUG (d, ("ce_initialize\n"));
969 }
970 #endif /*NETGRAPH*/
971
972 /*
973  * Stop the interface.  Called on splimp().
974  */
975 static void ce_down (drv_t *d)
976 {
977         CE_DEBUG (d, ("ce_down\n"));
978         /* Interface is going down -- stop it. */
979         ce_set_dtr (d->chan, 0);
980         ce_set_rts (d->chan, 0);
981
982         d->running = 0;
983         callout_stop (&d->timeout_handle);
984 }
985
986 /*
987  * Start the interface.  Called on splimp().
988  */
989 static void ce_up (drv_t *d)
990 {
991         CE_DEBUG (d, ("ce_up\n"));
992         ce_set_dtr (d->chan, 1);
993         ce_set_rts (d->chan, 1);
994
995         d->running = 1;
996 }
997
998 /*
999  * Start output on the interface.  Get another datagram to send
1000  * off of the interface queue, and copy it to the interface
1001  * before starting the output.
1002  */
1003 static void ce_send (drv_t *d)
1004 {
1005         struct mbuf *m;
1006         u_short len;
1007
1008         CE_DEBUG2 (d, ("ce_send\n"));
1009
1010         /* No output if the interface is down. */
1011         if (! d->running)
1012                 return;
1013
1014         while (ce_transmit_space (d->chan)) {
1015                 /* Get the packet to send. */
1016 #ifdef NETGRAPH
1017                 IF_DEQUEUE (&d->hi_queue, m);
1018                 if (! m)
1019                         IF_DEQUEUE (&d->queue, m);
1020 #else
1021                 m = sppp_dequeue (d->ifp);
1022 #endif
1023                 if (! m)
1024                         return;
1025 #ifndef NETGRAPH
1026 #if __FreeBSD_version >= 500000
1027                 BPF_MTAP (d->ifp, m);
1028 #else
1029                 if (d->ifp->if_bpf)
1030                         bpf_mtap (d->ifp, m);
1031 #endif
1032 #endif
1033 #if __FreeBSD_version >= 490000
1034                 len = m_length (m, NULL);
1035 #else
1036                 len = m->m_pkthdr.len;
1037 #endif
1038                 if (len >= BUFSZ)
1039                         printf ("%s: too long packet: %d bytes: ",
1040                                 d->name, len);
1041                 else if (! m->m_next)
1042                         ce_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0);
1043                 else {
1044                         ce_buf_item_t *item = (ce_buf_item_t*)d->chan->tx_queue;
1045                         m_copydata (m, 0, len, item->buf);
1046                         ce_send_packet (d->chan, item->buf, len, 0);
1047                 }
1048                 m_freem (m);
1049                 /* Set up transmit timeout, if the transmit ring is not empty.*/
1050                 d->timeout = 10;
1051         }
1052 #ifndef NETGRAPH
1053 #if __FreeBSD_version >= 600034
1054         d->ifp->if_flags |= IFF_DRV_OACTIVE;
1055 #else
1056         d->ifp->if_flags |= IFF_OACTIVE;
1057 #endif
1058 #endif
1059 }
1060
1061 /*
1062  * Start output on the interface.
1063  * Always called on splimp().
1064  */
1065 static void ce_start (drv_t *d)
1066 {
1067         if (d->running) {
1068                 if (! d->chan->dtr)
1069                         ce_set_dtr (d->chan, 1);
1070                 if (! d->chan->rts)
1071                         ce_set_rts (d->chan, 1);
1072                 ce_send (d);
1073                 callout_reset (&d->timeout_handle, hz, ce_watchdog_timer, d);
1074         }
1075 }
1076
1077 /*
1078  * Handle transmit timeouts.
1079  * Recover after lost transmit interrupts.
1080  * Always called on splimp().
1081  */
1082 static void ce_watchdog (drv_t *d)
1083 {
1084         CE_DEBUG (d, ("device timeout\n"));
1085         if (d->running) {
1086                 ce_set_dtr (d->chan, 0);
1087                 ce_set_rts (d->chan, 0);
1088 /*              ce_stop_chan (d->chan);*/
1089 /*              ce_start_chan (d->chan, 1, 1, 0, 0);*/
1090                 ce_set_dtr (d->chan, 1);
1091                 ce_set_rts (d->chan, 1);
1092                 ce_start (d);
1093         }
1094 }
1095
1096 static void ce_watchdog_timer (void *arg)
1097 {
1098         drv_t *d = arg;
1099         bdrv_t *bd = d->board->sys;
1100
1101         CE_LOCK(bd);
1102         if (d->timeout == 1)
1103                 ce_watchdog (d);
1104         if (d->timeout)
1105                 d->timeout--;
1106         callout_reset (&d->timeout_handle, hz, ce_watchdog_timer, d);
1107         CE_UNLOCK(bd);
1108 }
1109
1110 static void ce_transmit (ce_chan_t *c, void *attachment, int len)
1111 {
1112         drv_t *d = c->sys;
1113
1114         d->timeout = 0;
1115 #ifndef NETGRAPH
1116         ++d->ifp->if_opackets;
1117 #if __FreeBSD_version >=  600034
1118         d->ifp->if_flags &= ~IFF_DRV_OACTIVE;
1119 #else
1120         d->ifp->if_flags &= ~IFF_OACTIVE;
1121 #endif
1122 #endif
1123         ce_start (d);
1124 }
1125
1126 static void ce_receive (ce_chan_t *c, unsigned char *data, int len)
1127 {
1128         drv_t *d = c->sys;
1129         struct mbuf *m;
1130
1131         if (! d->running)
1132                 return;
1133
1134         m = makembuf (data, len);
1135         if (! m) {
1136                 CE_DEBUG (d, ("no memory for packet\n"));
1137 #ifndef NETGRAPH
1138                 ++d->ifp->if_iqdrops;
1139 #endif
1140                 return;
1141         }
1142         if (c->debug > 1)
1143                 printmbuf (m);
1144 #ifdef NETGRAPH
1145         m->m_pkthdr.rcvif = 0;
1146         IF_ENQUEUE(&d->rqueue, m);
1147 #else
1148         ++d->ifp->if_ipackets;
1149         m->m_pkthdr.rcvif = d->ifp;
1150         /* Check if there's a BPF listener on this interface.
1151          * If so, hand off the raw packet to bpf. */
1152 #if __FreeBSD_version >= 500000
1153         BPF_TAP (d->ifp, data, len);
1154 #else
1155         if (d->ifp->if_bpf)
1156                 bpf_tap (d->ifp, data, len);
1157 #endif
1158         IF_ENQUEUE(&d->rqueue, m);
1159 #endif
1160 }
1161
1162 static void ce_error (ce_chan_t *c, int data)
1163 {
1164         drv_t *d = c->sys;
1165
1166         switch (data) {
1167         case CE_FRAME:
1168                 CE_DEBUG (d, ("frame error\n"));
1169 #ifndef NETGRAPH
1170                 ++d->ifp->if_ierrors;
1171 #endif
1172                 break;
1173         case CE_CRC:
1174                 CE_DEBUG (d, ("crc error\n"));
1175 #ifndef NETGRAPH
1176                 ++d->ifp->if_ierrors;
1177 #endif
1178                 break;
1179         case CE_OVERRUN:
1180                 CE_DEBUG (d, ("overrun error\n"));
1181 #ifndef NETGRAPH
1182                 ++d->ifp->if_collisions;
1183                 ++d->ifp->if_ierrors;
1184 #endif
1185                 break;
1186         case CE_OVERFLOW:
1187                 CE_DEBUG (d, ("overflow error\n"));
1188 #ifndef NETGRAPH
1189                 ++d->ifp->if_ierrors;
1190 #endif
1191                 break;
1192         case CE_UNDERRUN:
1193                 CE_DEBUG (d, ("underrun error\n"));
1194                 d->timeout = 0;
1195 #ifndef NETGRAPH
1196                 ++d->ifp->if_oerrors;
1197 #if __FreeBSD_version >= 600034
1198                 d->ifp->if_flags &= ~IFF_DRV_OACTIVE;
1199 #else
1200                 d->ifp->if_flags &= ~IFF_OACTIVE;
1201 #endif
1202 #endif
1203                 ce_start (d);
1204                 break;
1205         default:
1206                 CE_DEBUG (d, ("error #%d\n", data));
1207                 break;
1208         }
1209 }
1210
1211 /*
1212  * You also need read, write, open, close routines.
1213  * This should get you started
1214  */
1215 #if __FreeBSD_version < 500000
1216 static int ce_open (dev_t dev, int oflags, int devtype, struct proc *p)
1217 #else
1218 static int ce_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
1219 #endif
1220 {
1221         int unit = dev2unit (dev);
1222         drv_t *d;
1223
1224         if (unit >= NBRD*NCHAN || ! (d = channel[unit]))
1225                 return ENXIO;
1226         CE_DEBUG2 (d, ("ce_open\n"));
1227         return 0;
1228 }
1229
1230 /*
1231  * Only called on the LAST close.
1232  */
1233 #if __FreeBSD_version < 500000
1234 static int ce_close (dev_t dev, int fflag, int devtype, struct proc *p)
1235 #else
1236 static int ce_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
1237 #endif
1238 {
1239         drv_t *d = channel [dev2unit (dev)];
1240
1241         CE_DEBUG2 (d, ("ce_close\n"));
1242         return 0;
1243 }
1244
1245 static int ce_modem_status (ce_chan_t *c)
1246 {
1247         drv_t *d = c->sys;
1248         bdrv_t *bd = d->board->sys;
1249         int status, s;
1250
1251         status = d->running ? TIOCM_LE : 0;
1252         s = splimp ();
1253         CE_LOCK (bd);
1254         if (ce_get_cd  (c)) status |= TIOCM_CD;
1255         if (ce_get_cts (c)) status |= TIOCM_CTS;
1256         if (ce_get_dsr (c)) status |= TIOCM_DSR;
1257         if (c->dtr)         status |= TIOCM_DTR;
1258         if (c->rts)         status |= TIOCM_RTS;
1259         CE_UNLOCK (bd);
1260         splx (s);
1261         return status;
1262 }
1263
1264 #if __FreeBSD_version < 500000
1265 static int ce_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1266 #else
1267 static int ce_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1268 #endif
1269 {
1270         drv_t *d = channel [dev2unit (dev)];
1271         bdrv_t *bd = d->board->sys;
1272         ce_chan_t *c = d->chan;
1273         struct serial_statistics *st;
1274         struct e1_statistics *opte1;
1275         int error, s;
1276         char mask[16];
1277
1278         switch (cmd) {
1279         case SERIAL_GETREGISTERED:
1280                 CE_DEBUG2 (d, ("ioctl: getregistered\n"));
1281                 bzero (mask, sizeof(mask));
1282                 for (s=0; s<NBRD*NCHAN; ++s)
1283                         if (channel [s])
1284                                 mask [s/8] |= 1 << (s & 7);
1285                 bcopy (mask, data, sizeof (mask));
1286                 return 0;
1287
1288 #ifndef NETGRAPH
1289         case SERIAL_GETPROTO:
1290                 CE_DEBUG2 (d, ("ioctl: getproto\n"));
1291                 strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
1292                         (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
1293                 return 0;
1294
1295         case SERIAL_SETPROTO:
1296                 CE_DEBUG2 (d, ("ioctl: setproto\n"));
1297                 /* Only for superuser! */
1298 #if __FreeBSD_version < 500000
1299                 error = suser (p);
1300 #elif __FreeBSD_version < 700000
1301                 error = suser (td);
1302 #else
1303                 error = priv_check (td, PRIV_DRIVER);
1304 #endif
1305                 if (error)
1306                         return error;
1307 #if __FreeBSD_version >= 600034
1308                 if (d->ifp->if_flags & IFF_DRV_RUNNING)
1309 #else
1310                 if (d->ifp->if_flags & IFF_RUNNING)
1311 #endif
1312                         return EBUSY;
1313                 if (! strcmp ("cisco", (char*)data)) {
1314                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
1315                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1316                         d->ifp->if_flags |= PP_CISCO;
1317 #if PP_FR != 0
1318                 } else if (! strcmp ("fr", (char*)data)) {
1319                         d->ifp->if_flags &= ~(PP_CISCO);
1320                         IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
1321 #endif
1322                 } else if (! strcmp ("ppp", (char*)data)) {
1323                         IFP2SP(d->ifp)->pp_flags &= ~PP_FR;
1324                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1325                         d->ifp->if_flags &= ~(PP_CISCO);
1326                 } else
1327                         return EINVAL;
1328                 return 0;
1329
1330         case SERIAL_GETKEEPALIVE:
1331                 CE_DEBUG2 (d, ("ioctl: getkeepalive\n"));
1332                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1333                         (d->ifp->if_flags & PP_CISCO))
1334                         return EINVAL;
1335                 *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
1336                 return 0;
1337
1338         case SERIAL_SETKEEPALIVE:
1339                 CE_DEBUG2 (d, ("ioctl: setkeepalive\n"));
1340                 /* Only for superuser! */
1341 #if __FreeBSD_version < 500000
1342                 error = suser (p);
1343 #elif __FreeBSD_version < 700000
1344                 error = suser (td);
1345 #else
1346                 error = priv_check (td, PRIV_DRIVER);
1347 #endif
1348                 if (error)
1349                         return error;
1350                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1351                         (d->ifp->if_flags & PP_CISCO))
1352                         return EINVAL;
1353                 s = splimp ();
1354                 CE_LOCK (bd);
1355                 if (*(int*)data)
1356                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1357                 else
1358                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1359                 CE_UNLOCK (bd);
1360                 splx (s);
1361                 return 0;
1362 #endif /*NETGRAPH*/
1363
1364         case SERIAL_GETMODE:
1365                 CE_DEBUG2 (d, ("ioctl: getmode\n"));
1366                 *(int*)data = SERIAL_HDLC;
1367                 return 0;
1368
1369         case SERIAL_SETMODE:
1370                 /* Only for superuser! */
1371 #if __FreeBSD_version < 500000
1372                 error = suser (p);
1373 #elif __FreeBSD_version < 700000
1374                 error = suser (td);
1375 #else
1376                 error = priv_check (td, PRIV_DRIVER);
1377 #endif
1378                 if (error)
1379                         return error;
1380                 if (*(int*)data != SERIAL_HDLC)
1381                         return EINVAL;
1382                 return 0;
1383
1384         case SERIAL_GETCFG:
1385                 CE_DEBUG2 (d, ("ioctl: getcfg\n"));
1386                 *(char*)data = 'c';
1387                 return 0;
1388
1389         case SERIAL_SETCFG:
1390                 CE_DEBUG2 (d, ("ioctl: setcfg\n"));
1391 #if __FreeBSD_version < 500000
1392                 error = suser (p);
1393 #elif __FreeBSD_version < 700000
1394                 error = suser (td);
1395 #else
1396                 error = priv_check (td, PRIV_DRIVER);
1397 #endif
1398                 if (error)
1399                         return error;
1400                 if (*((char*)data) != 'c')
1401                         return EINVAL;
1402                 return 0;
1403
1404         case SERIAL_GETSTAT:
1405                 CE_DEBUG2 (d, ("ioctl: getstat\n"));
1406                 st = (struct serial_statistics*) data;
1407                 st->rintr  = c->rintr;
1408                 st->tintr  = c->tintr;
1409                 st->mintr  = 0;
1410                 st->ibytes = c->ibytes;
1411                 st->ipkts  = c->ipkts;
1412                 st->obytes = c->obytes;
1413                 st->opkts  = c->opkts;
1414                 st->ierrs  = c->overrun + c->frame + c->crc;
1415                 st->oerrs  = c->underrun;
1416                 return 0;
1417
1418         case SERIAL_GETESTAT:
1419                 CE_DEBUG2 (d, ("ioctl: getestat\n"));
1420                 if (c->type != T_E1)
1421                         return EINVAL;
1422                 opte1 = (struct e1_statistics*) data;
1423
1424                 opte1->status      = 0;
1425                 if (c->status & ESTS_NOALARM)
1426                         opte1->status |= E1_NOALARM;
1427                 if (c->status & ESTS_LOS)
1428                         opte1->status |= E1_LOS;
1429                 if (c->status & ESTS_LOF)
1430                         opte1->status |= E1_LOF;
1431                 if (c->status & ESTS_AIS)
1432                         opte1->status |= E1_AIS;
1433                 if (c->status & ESTS_LOMF)
1434                         opte1->status |= E1_LOMF;
1435                 if (c->status & ESTS_AIS16)
1436                         opte1->status |= E1_AIS16;
1437                 if (c->status & ESTS_FARLOF)
1438                         opte1->status |= E1_FARLOF;
1439                 if (c->status & ESTS_FARLOMF)
1440                         opte1->status |= E1_FARLOMF;
1441                 if (c->status & ESTS_TSTREQ)
1442                         opte1->status |= E1_TSTREQ;
1443                 if (c->status & ESTS_TSTERR)
1444                         opte1->status |= E1_TSTERR;
1445
1446                 opte1->cursec       = c->cursec;
1447                 opte1->totsec       = c->totsec + c->cursec;
1448
1449                 opte1->currnt.bpv   = c->currnt.bpv;
1450                 opte1->currnt.fse   = c->currnt.fse;
1451                 opte1->currnt.crce  = c->currnt.crce;
1452                 opte1->currnt.rcrce = c->currnt.rcrce;
1453                 opte1->currnt.uas   = c->currnt.uas;
1454                 opte1->currnt.les   = c->currnt.les;
1455                 opte1->currnt.es    = c->currnt.es;
1456                 opte1->currnt.bes   = c->currnt.bes;
1457                 opte1->currnt.ses   = c->currnt.ses;
1458                 opte1->currnt.oofs  = c->currnt.oofs;
1459                 opte1->currnt.css   = c->currnt.css;
1460                 opte1->currnt.dm    = c->currnt.dm;
1461
1462                 opte1->total.bpv    = c->total.bpv   + c->currnt.bpv;
1463                 opte1->total.fse    = c->total.fse   + c->currnt.fse;
1464                 opte1->total.crce   = c->total.crce  + c->currnt.crce;
1465                 opte1->total.rcrce  = c->total.rcrce + c->currnt.rcrce;
1466                 opte1->total.uas    = c->total.uas   + c->currnt.uas;
1467                 opte1->total.les    = c->total.les   + c->currnt.les;
1468                 opte1->total.es     = c->total.es    + c->currnt.es;
1469                 opte1->total.bes    = c->total.bes   + c->currnt.bes;
1470                 opte1->total.ses    = c->total.ses   + c->currnt.ses;
1471                 opte1->total.oofs   = c->total.oofs  + c->currnt.oofs;
1472                 opte1->total.css    = c->total.css   + c->currnt.css;
1473                 opte1->total.dm     = c->total.dm    + c->currnt.dm;
1474                 for (s=0; s<48; ++s) {
1475                         opte1->interval[s].bpv   = c->interval[s].bpv;
1476                         opte1->interval[s].fse   = c->interval[s].fse;
1477                         opte1->interval[s].crce  = c->interval[s].crce;
1478                         opte1->interval[s].rcrce = c->interval[s].rcrce;
1479                         opte1->interval[s].uas   = c->interval[s].uas;
1480                         opte1->interval[s].les   = c->interval[s].les;
1481                         opte1->interval[s].es    = c->interval[s].es;
1482                         opte1->interval[s].bes   = c->interval[s].bes;
1483                         opte1->interval[s].ses   = c->interval[s].ses;
1484                         opte1->interval[s].oofs  = c->interval[s].oofs;
1485                         opte1->interval[s].css   = c->interval[s].css;
1486                         opte1->interval[s].dm    = c->interval[s].dm;
1487                 }
1488                 return 0;
1489
1490         case SERIAL_CLRSTAT:
1491                 CE_DEBUG2 (d, ("ioctl: clrstat\n"));
1492                 /* Only for superuser! */
1493 #if __FreeBSD_version < 500000
1494                 error = suser (p);
1495 #elif __FreeBSD_version < 700000
1496                 error = suser (td);
1497 #else
1498                 error = priv_check (td, PRIV_DRIVER);
1499 #endif
1500                 if (error)
1501                         return error;
1502                 c->rintr    = 0;
1503                 c->tintr    = 0;
1504                 c->ibytes   = 0;
1505                 c->obytes   = 0;
1506                 c->ipkts    = 0;
1507                 c->opkts    = 0;
1508                 c->overrun  = 0;
1509                 c->frame    = 0;
1510                 c->crc      = 0;
1511                 c->underrun = 0;
1512                 bzero (&c->currnt, sizeof (c->currnt));
1513                 bzero (&c->total, sizeof (c->total));
1514                 bzero (c->interval, sizeof (c->interval));
1515                 return 0;
1516
1517         case SERIAL_GETLOOP:
1518                 CE_DEBUG2 (d, ("ioctl: getloop\n"));
1519                 if (c->type != T_E1)
1520                         return EINVAL;
1521                 *(int*)data = c->lloop;
1522                 return 0;
1523
1524         case SERIAL_SETLOOP:
1525                 CE_DEBUG2 (d, ("ioctl: setloop\n"));
1526                 if (c->type != T_E1)
1527                         return EINVAL;
1528                 /* Only for superuser! */
1529 #if __FreeBSD_version < 500000
1530                 error = suser (p);
1531 #elif __FreeBSD_version < 700000
1532                 error = suser (td);
1533 #else
1534                 error = priv_check (td, PRIV_DRIVER);
1535 #endif
1536                 if (error)
1537                         return error;
1538                 s = splimp ();
1539                 CE_LOCK (bd);
1540                 ce_set_lloop (c, *(int*)data);
1541                 CE_UNLOCK (bd);
1542                 splx (s);
1543                 return 0;
1544
1545         case SERIAL_GETRLOOP:
1546                 CE_DEBUG2 (d, ("ioctl: getrloop\n"));
1547                 if (c->type != T_E1)
1548                         return EINVAL;
1549                 *(int*)data = c->rloop;
1550                 return 0;
1551
1552         case SERIAL_SETRLOOP:
1553                 CE_DEBUG2 (d, ("ioctl: setloop\n"));
1554                 if (c->type != T_E1)
1555                         return EINVAL;
1556                 /* Only for superuser! */
1557 #if __FreeBSD_version < 500000
1558                 error = suser (p);
1559 #elif __FreeBSD_version < 700000
1560                 error = suser (td);
1561 #else
1562                 error = priv_check (td, PRIV_DRIVER);
1563 #endif
1564                 if (error)
1565                         return error;
1566                 s = splimp ();
1567                 CE_LOCK (bd);
1568                 ce_set_rloop (c, *(int*)data);
1569                 CE_UNLOCK (bd);
1570                 splx (s);
1571                 return 0;
1572
1573         case SERIAL_GETDEBUG:
1574                 CE_DEBUG2 (d, ("ioctl: getdebug\n"));
1575                 *(int*)data = d->chan->debug;
1576                 return 0;
1577
1578         case SERIAL_SETDEBUG:
1579                 CE_DEBUG2 (d, ("ioctl: setdebug\n"));
1580                 /* Only for superuser! */
1581 #if __FreeBSD_version < 500000
1582                 error = suser (p);
1583 #elif __FreeBSD_version < 700000
1584                 error = suser (td);
1585 #else
1586                 error = priv_check (td, PRIV_DRIVER);
1587 #endif
1588                 if (error)
1589                         return error;
1590 #ifndef NETGRAPH
1591                 /*
1592                  * The debug_shadow is always greater than zero for logic 
1593                  * simplicity.  For switching debug off the IFF_DEBUG is
1594                  * responsible.
1595                  */
1596                 d->chan->debug_shadow = (*(int*)data) ? (*(int*)data) : 1;
1597                 if (d->ifp->if_flags & IFF_DEBUG)
1598                         d->chan->debug = d->chan->debug_shadow;
1599 #else
1600                 d->chan->debug = *(int*)data;
1601 #endif
1602                 return 0;
1603
1604         case SERIAL_GETBAUD:
1605                 CE_DEBUG2 (d, ("ioctl: getbaud\n"));
1606                 *(long*)data = c->baud;
1607                 return 0;
1608
1609         case SERIAL_SETBAUD:
1610                 CE_DEBUG2 (d, ("ioctl: setbaud\n"));
1611                 if (c->type != T_E1 || !c->unfram)
1612                         return EINVAL;
1613                 /* Only for superuser! */
1614 #if __FreeBSD_version < 500000
1615                 error = suser (p);
1616 #elif __FreeBSD_version < 700000
1617                 error = suser (td);
1618 #else
1619                 error = priv_check (td, PRIV_DRIVER);
1620 #endif
1621                 if (error)
1622                         return error;
1623                 s = splimp ();
1624                 CE_LOCK (bd);
1625                 ce_set_baud (c, *(long*)data);
1626                 CE_UNLOCK (bd);
1627                 splx (s);
1628                 return 0;
1629
1630         case SERIAL_GETTIMESLOTS:
1631                 CE_DEBUG2 (d, ("ioctl: gettimeslots\n"));
1632                 if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1633                         return EINVAL;
1634                 *(u_long*)data = c->ts;
1635                 return 0;
1636
1637         case SERIAL_SETTIMESLOTS:
1638                 CE_DEBUG2 (d, ("ioctl: settimeslots\n"));
1639                 /* Only for superuser! */
1640 #if __FreeBSD_version < 500000
1641                 error = suser (p);
1642 #elif __FreeBSD_version < 700000
1643                 error = suser (td);
1644 #else
1645                 error = priv_check (td, PRIV_DRIVER);
1646 #endif
1647                 if (error)
1648                         return error;
1649                 if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1650                         return EINVAL;
1651                 s = splimp ();
1652                 CE_LOCK (bd);
1653                 ce_set_ts (c, *(u_long*)data);
1654                 CE_UNLOCK (bd);
1655                 splx (s);
1656                 return 0;
1657
1658         case SERIAL_GETHIGAIN:
1659                 CE_DEBUG2 (d, ("ioctl: gethigain\n"));
1660                 if (c->type != T_E1)
1661                         return EINVAL;
1662                 *(int*)data = c->higain;
1663                 return 0;
1664
1665         case SERIAL_SETHIGAIN:
1666                 CE_DEBUG2 (d, ("ioctl: sethigain\n"));
1667                 if (c->type != T_E1)
1668                         return EINVAL;
1669                 /* Only for superuser! */
1670 #if __FreeBSD_version < 500000
1671                 error = suser (p);
1672 #elif __FreeBSD_version < 700000
1673                 error = suser (td);
1674 #else
1675                 error = priv_check (td, PRIV_DRIVER);
1676 #endif
1677                 if (error)
1678                         return error;
1679                 s = splimp ();
1680                 CE_LOCK (bd);
1681                 ce_set_higain (c, *(int*)data);
1682                 CE_UNLOCK (bd);
1683                 splx (s);
1684                 return 0;
1685
1686         case SERIAL_GETPHONY:
1687                 CE_DEBUG2 (d, ("ioctl: getphony\n"));
1688                 *(int*)data = c->phony;
1689                 return 0;
1690
1691         case SERIAL_SETPHONY:
1692                 CE_DEBUG2 (d, ("ioctl: setphony\n"));
1693                 /* Only for superuser! */
1694 #if __FreeBSD_version < 500000
1695                 error = suser (p);
1696 #elif __FreeBSD_version < 700000
1697                 error = suser (td);
1698 #else
1699                 error = priv_check (td, PRIV_DRIVER);
1700 #endif
1701                 if (error)
1702                         return error;
1703                 s = splimp ();
1704                 CE_LOCK (bd);
1705                 ce_set_phony (c, *(int*)data);
1706                 CE_UNLOCK (bd);
1707                 splx (s);
1708                 return 0;
1709
1710         case SERIAL_GETUNFRAM:
1711                 CE_DEBUG2 (d, ("ioctl: getunfram\n"));
1712                 if (c->type != T_E1 || c->num != 0)
1713                         return EINVAL;
1714                 *(int*)data = c->unfram;
1715                 return 0;
1716
1717         case SERIAL_SETUNFRAM:
1718                 CE_DEBUG2 (d, ("ioctl: setunfram\n"));
1719                 if (c->type != T_E1 || c->num != 0)
1720                         return EINVAL;
1721                 /* Only for superuser! */
1722 #if __FreeBSD_version < 500000
1723                 error = suser (p);
1724 #elif __FreeBSD_version < 700000
1725                 error = suser (td);
1726 #else
1727                 error = priv_check (td, PRIV_DRIVER);
1728 #endif
1729                 if (error)
1730                         return error;
1731                 s = splimp ();
1732                 CE_LOCK (bd);
1733                 ce_set_unfram (c, *(int*)data);
1734                 CE_UNLOCK (bd);
1735                 splx (s);
1736                 return 0;
1737
1738         case SERIAL_GETSCRAMBLER:
1739                 CE_DEBUG2 (d, ("ioctl: getscrambler\n"));
1740                 if (!c->unfram)
1741                         return EINVAL;
1742                 *(int*)data = c->scrambler;
1743                 return 0;
1744
1745         case SERIAL_SETSCRAMBLER:
1746                 CE_DEBUG2 (d, ("ioctl: setscrambler\n"));
1747                 /* Only for superuser! */
1748 #if __FreeBSD_version < 500000
1749                 error = suser (p);
1750 #elif __FreeBSD_version < 700000
1751                 error = suser (td);
1752 #else
1753                 error = priv_check (td, PRIV_DRIVER);
1754 #endif
1755                 if (error)
1756                         return error;
1757                 if (!c->unfram)
1758                         return EINVAL;
1759                 s = splimp ();
1760                 CE_LOCK (bd);
1761                 ce_set_scrambler (c, *(int*)data);
1762                 CE_UNLOCK (bd);
1763                 splx (s);
1764                 return 0;
1765
1766         case SERIAL_GETMONITOR:
1767                 CE_DEBUG2 (d, ("ioctl: getmonitor\n"));
1768                 if (c->type != T_E1)
1769                         return EINVAL;
1770                 *(int*)data = c->monitor;
1771                 return 0;
1772
1773         case SERIAL_SETMONITOR:
1774                 CE_DEBUG2 (d, ("ioctl: setmonitor\n"));
1775                 /* Only for superuser! */
1776 #if __FreeBSD_version < 500000
1777                 error = suser (p);
1778 #elif __FreeBSD_version < 700000
1779                 error = suser (td);
1780 #else
1781                 error = priv_check (td, PRIV_DRIVER);
1782 #endif
1783                 if (error)
1784                         return error;
1785                 if (c->type != T_E1)
1786                         return EINVAL;
1787                 s = splimp ();
1788                 CE_LOCK (bd);
1789                 ce_set_monitor (c, *(int*)data);
1790                 CE_UNLOCK (bd);
1791                 splx (s);
1792                 return 0;
1793
1794         case SERIAL_GETUSE16:
1795                 CE_DEBUG2 (d, ("ioctl: getuse16\n"));
1796                 if (c->type != T_E1 || c->unfram)
1797                         return EINVAL;
1798                 *(int*)data = c->use16;
1799                 return 0;
1800
1801         case SERIAL_SETUSE16:
1802                 CE_DEBUG2 (d, ("ioctl: setuse16\n"));
1803                 /* Only for superuser! */
1804 #if __FreeBSD_version < 500000
1805                 error = suser (p);
1806 #elif __FreeBSD_version < 700000
1807                 error = suser (td);
1808 #else
1809                 error = priv_check (td, PRIV_DRIVER);
1810 #endif
1811                 if (error)
1812                         return error;
1813                 if (c->type != T_E1)
1814                         return EINVAL;
1815                 s = splimp ();
1816                 CE_LOCK (bd);
1817                 ce_set_use16 (c, *(int*)data);
1818                 CE_UNLOCK (bd);
1819                 splx (s);
1820                 return 0;
1821
1822         case SERIAL_GETCRC4:
1823                 CE_DEBUG2 (d, ("ioctl: getcrc4\n"));
1824                 if (c->type != T_E1 || c->unfram)
1825                         return EINVAL;
1826                 *(int*)data = c->crc4;
1827                 return 0;
1828
1829         case SERIAL_SETCRC4:
1830                 CE_DEBUG2 (d, ("ioctl: setcrc4\n"));
1831                 /* Only for superuser! */
1832 #if __FreeBSD_version < 500000
1833                 error = suser (p);
1834 #elif __FreeBSD_version < 700000
1835                 error = suser (td);
1836 #else
1837                 error = priv_check (td, PRIV_DRIVER);
1838 #endif
1839                 if (error)
1840                         return error;
1841                 if (c->type != T_E1 || c->unfram)
1842                         return EINVAL;
1843                 s = splimp ();
1844                 CE_LOCK (bd);
1845                 ce_set_crc4 (c, *(int*)data);
1846                 CE_UNLOCK (bd);
1847                 splx (s);
1848                 return 0;
1849
1850         case SERIAL_GETCLK:
1851                 CE_DEBUG2 (d, ("ioctl: getclk\n"));
1852                 if (c->type != T_E1)
1853                         return EINVAL;
1854                 switch (c->gsyn) {
1855                 default:        *(int*)data = E1CLK_INTERNAL;           break;
1856                 case GSYN_RCV:  *(int*)data = E1CLK_RECEIVE;            break;
1857                 case GSYN_RCV0: *(int*)data = E1CLK_RECEIVE_CHAN0;      break;
1858                 case GSYN_RCV1: *(int*)data = E1CLK_RECEIVE_CHAN1;      break;
1859                 }
1860                 return 0;
1861
1862         case SERIAL_SETCLK:
1863                 CE_DEBUG2 (d, ("ioctl: setclk\n"));
1864                 /* Only for superuser! */
1865 #if __FreeBSD_version < 500000
1866                 error = suser (p);
1867 #elif __FreeBSD_version < 700000
1868                 error = suser (td);
1869 #else
1870                 error = priv_check (td, PRIV_DRIVER);
1871 #endif
1872                 if (error)
1873                         return error;
1874                 if (c->type != T_E1)
1875                         return EINVAL;
1876                 s = splimp ();
1877                 CE_LOCK (bd);
1878                 switch (*(int*)data) {
1879                 default:                  ce_set_gsyn (c, GSYN_INT);  break;
1880                 case E1CLK_RECEIVE:       ce_set_gsyn (c, GSYN_RCV);  break;
1881                 case E1CLK_RECEIVE_CHAN0: ce_set_gsyn (c, GSYN_RCV0); break;
1882                 case E1CLK_RECEIVE_CHAN1: ce_set_gsyn (c, GSYN_RCV1); break;
1883                 }
1884                 CE_UNLOCK (bd);
1885                 splx (s);
1886                 return 0;
1887
1888 #if 0
1889         case SERIAL_RESET:
1890                 CE_DEBUG2 (d, ("ioctl: reset\n"));
1891                 /* Only for superuser! */
1892 #if __FreeBSD_version < 500000
1893                 error = suser (p);
1894 #elif __FreeBSD_version < 700000
1895                 error = suser (td);
1896 #else
1897                 error = priv_check (td, PRIV_DRIVER);
1898 #endif
1899                 if (error)
1900                         return error;
1901                 s = splimp ();
1902                 CE_LOCK (bd);
1903 /*              ce_reset (c->board, 0, 0);*/
1904                 CE_UNLOCK (bd);
1905                 splx (s);
1906                 return 0;
1907
1908         case SERIAL_HARDRESET:
1909                 CE_DEBUG2 (d, ("ioctl: hardreset\n"));
1910                 /* Only for superuser! */
1911 #if __FreeBSD_version < 500000
1912                 error = suser (p);
1913 #elif __FreeBSD_version < 700000
1914                 error = suser (td);
1915 #else
1916                 error = priv_check (td, PRIV_DRIVER);
1917 #endif
1918                 if (error)
1919                         return error;
1920                 s = splimp ();
1921                 CE_LOCK (bd);
1922                 /* hard_reset (c->board); */
1923                 CE_UNLOCK (bd);
1924                 splx (s);
1925                 return 0;
1926 #endif
1927
1928         case SERIAL_GETCABLE:
1929                 CE_DEBUG2 (d, ("ioctl: getcable\n"));
1930                 if (c->type != T_E1)
1931                         return EINVAL;
1932                 s = splimp ();
1933                 CE_LOCK (bd);
1934                 *(int*)data = CABLE_TP;
1935                 CE_UNLOCK (bd);
1936                 splx (s);
1937                 return 0;
1938
1939         case SERIAL_GETDIR:
1940                 CE_DEBUG2 (d, ("ioctl: getdir\n"));
1941                 if (c->type != T_E1 && c->type != T_DATA)
1942                         return EINVAL;
1943                 *(int*)data = c->dir;
1944                 return 0;
1945
1946         case SERIAL_SETDIR:
1947                 CE_DEBUG2 (d, ("ioctl: setdir\n"));
1948                 /* Only for superuser! */
1949 #if __FreeBSD_version < 500000
1950                 error = suser (p);
1951 #elif __FreeBSD_version < 700000
1952                 error = suser (td);
1953 #else
1954                 error = priv_check (td, PRIV_DRIVER);
1955 #endif
1956                 if (error)
1957                         return error;
1958                 s = splimp ();
1959                 CE_LOCK (bd);
1960                 ce_set_dir (c, *(int*)data);
1961                 CE_UNLOCK (bd);
1962                 splx (s);
1963                 return 0;
1964
1965         case TIOCSDTR:          /* Set DTR */
1966                 s = splimp ();
1967                 CE_LOCK (bd);
1968                 ce_set_dtr (c, 1);
1969                 CE_UNLOCK (bd);
1970                 splx (s);
1971                 return 0;
1972
1973         case TIOCCDTR:          /* Clear DTR */
1974                 s = splimp ();
1975                 CE_LOCK (bd);
1976                 ce_set_dtr (c, 0);
1977                 CE_UNLOCK (bd);
1978                 splx (s);
1979                 return 0;
1980
1981         case TIOCMSET:          /* Set DTR/RTS */
1982                 s = splimp ();
1983                 CE_LOCK (bd);
1984                 ce_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1985                 ce_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1986                 CE_UNLOCK (bd);
1987                 splx (s);
1988                 return 0;
1989
1990         case TIOCMBIS:          /* Add DTR/RTS */
1991                 s = splimp ();
1992                 CE_LOCK (bd);
1993                 if (*(int*)data & TIOCM_DTR) ce_set_dtr (c, 1);
1994                 if (*(int*)data & TIOCM_RTS) ce_set_rts (c, 1);
1995                 CE_UNLOCK (bd);
1996                 splx (s);
1997                 return 0;
1998
1999         case TIOCMBIC:          /* Clear DTR/RTS */
2000                 s = splimp ();
2001                 CE_LOCK (bd);
2002                 if (*(int*)data & TIOCM_DTR) ce_set_dtr (c, 0);
2003                 if (*(int*)data & TIOCM_RTS) ce_set_rts (c, 0);
2004                 CE_UNLOCK (bd);
2005                 splx (s);
2006                 return 0;
2007
2008         case TIOCMGET:          /* Get modem status */
2009                 *(int*)data = ce_modem_status (c);
2010                 return 0;
2011         }
2012         return ENOTTY;
2013 }
2014
2015 #ifdef NETGRAPH
2016 #if __FreeBSD_version >= 500000
2017 static int ng_ce_constructor (node_p node)
2018 {
2019         drv_t *d = NG_NODE_PRIVATE (node);
2020 #else
2021 static int ng_ce_constructor (node_p *node)
2022 {
2023         drv_t *d = (*node)->private;
2024 #endif
2025         CE_DEBUG (d, ("Constructor\n"));
2026         return EINVAL;
2027 }
2028
2029 static int ng_ce_newhook (node_p node, hook_p hook, const char *name)
2030 {
2031         int s;
2032 #if __FreeBSD_version >= 500000
2033         drv_t *d = NG_NODE_PRIVATE (node);
2034 #else
2035         drv_t *d = node->private;
2036 #endif
2037         bdrv_t *bd = d->board->sys;
2038
2039         CE_DEBUG (d, ("Newhook\n"));
2040         /* Attach debug hook */
2041         if (strcmp (name, NG_CE_HOOK_DEBUG) == 0) {
2042 #if __FreeBSD_version >= 500000
2043                 NG_HOOK_SET_PRIVATE (hook, NULL);
2044 #else
2045                 hook->private = 0;
2046 #endif
2047                 d->debug_hook = hook;
2048                 return 0;
2049         }
2050
2051         /* Check for raw hook */
2052         if (strcmp (name, NG_CE_HOOK_RAW) != 0)
2053                 return EINVAL;
2054
2055 #if __FreeBSD_version >= 500000
2056         NG_HOOK_SET_PRIVATE (hook, d);
2057 #else
2058         hook->private = d;
2059 #endif
2060         d->hook = hook;
2061         s = splimp ();
2062         CE_LOCK (bd);
2063         ce_up (d);
2064         CE_UNLOCK (bd);
2065         splx (s);
2066         return 0;
2067 }
2068
2069 static char *format_timeslots (u_long s)
2070 {
2071         static char buf [100];
2072         char *p = buf;
2073         int i;
2074
2075         for (i=1; i<32; ++i)
2076                 if ((s >> i) & 1) {
2077                         int prev = (i > 1)  & (s >> (i-1));
2078                         int next = (i < 31) & (s >> (i+1));
2079
2080                         if (prev) {
2081                                 if (next)
2082                                         continue;
2083                                 *p++ = '-';
2084                         } else if (p > buf)
2085                                 *p++ = ',';
2086
2087                         if (i >= 10)
2088                                 *p++ = '0' + i / 10;
2089                         *p++ = '0' + i % 10;
2090                 }
2091         *p = 0;
2092         return buf;
2093 }
2094
2095 static int print_modems (char *s, ce_chan_t *c, int need_header)
2096 {
2097         int status = ce_modem_status (c);
2098         int length = 0;
2099
2100         if (need_header)
2101                 length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
2102         length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
2103                 status & TIOCM_LE  ? "On" : "-",
2104                 status & TIOCM_DTR ? "On" : "-",
2105                 status & TIOCM_DSR ? "On" : "-",
2106                 status & TIOCM_RTS ? "On" : "-",
2107                 status & TIOCM_CTS ? "On" : "-",
2108                 status & TIOCM_CD  ? "On" : "-");
2109         return length;
2110 }
2111
2112 static int print_stats (char *s, ce_chan_t *c, int need_header)
2113 {
2114         int length = 0;
2115
2116         if (need_header)
2117                 length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
2118         length += sprintf (s + length, "%7ld %7ld %7ld %8lu %7ld %7ld %8lu %7ld %7ld\n",
2119                 c->rintr, c->tintr, 0l, (unsigned long) c->ibytes,
2120                 c->ipkts, c->overrun + c->frame + c->crc,
2121                 (unsigned long) c->obytes, c->opkts, c->underrun);
2122         return length;
2123 }
2124
2125 static char *format_e1_status (u_char status)
2126 {
2127         static char buf [80];
2128
2129         if (status & E1_NOALARM)
2130                 return "Ok";
2131         buf[0] = 0;
2132         if (status & E1_LOS)     strcat (buf, ",LOS");
2133         if (status & E1_AIS)     strcat (buf, ",AIS");
2134         if (status & E1_LOF)     strcat (buf, ",LOF");
2135         if (status & E1_LOMF)    strcat (buf, ",LOMF");
2136         if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
2137         if (status & E1_AIS16)   strcat (buf, ",AIS16");
2138         if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
2139         if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
2140         if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
2141         if (buf[0] == ',')
2142                 return buf+1;
2143         return "Unknown";
2144 }
2145
2146 static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
2147 {
2148         int n, length = 0;
2149
2150         if (numerator < 1 || divider < 1) {
2151                 length += sprintf (s+length, leftalign ? "/-   " : "    -");
2152                 return length;
2153         }
2154         n = (int) (0.5 + 1000.0 * numerator / divider);
2155         if (n < 1000) {
2156                 length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
2157                 return length;
2158         }
2159         *(s + length) = leftalign ? '/' : ' ';
2160         length ++;
2161
2162         if      (n >= 1000000) n = (n+500) / 1000 * 1000;
2163         else if (n >= 100000)  n = (n+50)  / 100 * 100;
2164         else if (n >= 10000)   n = (n+5)   / 10 * 10;
2165
2166         switch (n) {
2167         case 1000:    length += printf (s+length, ".999"); return length;
2168         case 10000:   n = 9990;   break;
2169         case 100000:  n = 99900;  break;
2170         case 1000000: n = 999000; break;
2171         }
2172         if (n < 10000)        length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
2173         else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
2174         else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
2175         else                  length += sprintf (s+length, "%d", n/1000);
2176
2177         return length;
2178 }
2179
2180 static int print_e1_stats (char *s, ce_chan_t *c)
2181 {
2182         struct e1_counters total;
2183         u_long totsec;
2184         int length = 0;
2185
2186         totsec          = c->totsec + c->cursec;
2187         total.bpv       = c->total.bpv   + c->currnt.bpv;
2188         total.fse       = c->total.fse   + c->currnt.fse;
2189         total.crce      = c->total.crce  + c->currnt.crce;
2190         total.rcrce     = c->total.rcrce + c->currnt.rcrce;
2191         total.uas       = c->total.uas   + c->currnt.uas;
2192         total.les       = c->total.les   + c->currnt.les;
2193         total.es        = c->total.es    + c->currnt.es;
2194         total.bes       = c->total.bes   + c->currnt.bes;
2195         total.ses       = c->total.ses   + c->currnt.ses;
2196         total.oofs      = c->total.oofs  + c->currnt.oofs;
2197         total.css       = c->total.css   + c->currnt.css;
2198         total.dm        = c->total.dm    + c->currnt.dm;
2199
2200         length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
2201
2202         /* Unavailable seconds, degraded minutes */
2203         length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
2204         length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
2205
2206         /* Bipolar violations, frame sync errors */
2207         length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
2208         length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
2209
2210         /* CRC errors, remote CRC errors (E-bit) */
2211         length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
2212         length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
2213
2214         /* Errored seconds, line errored seconds */
2215         length += print_frac (s + length, 0, c->currnt.es, c->cursec);
2216         length += print_frac (s + length, 1, c->currnt.les, c->cursec);
2217
2218         /* Severely errored seconds, burst errored seconds */
2219         length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
2220         length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
2221
2222         /* Out of frame seconds, controlled slip seconds */
2223         length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
2224         length += print_frac (s + length, 1, c->currnt.css, c->cursec);
2225
2226         length += sprintf (s + length, " %s\n", format_e1_status (c->status));
2227
2228         /* Print total statistics. */
2229         length += print_frac (s + length, 0, total.uas, totsec);
2230         length += print_frac (s + length, 1, 60 * total.dm, totsec);
2231
2232         length += print_frac (s + length, 0, total.bpv, totsec);
2233         length += print_frac (s + length, 1, total.fse, totsec);
2234
2235         length += print_frac (s + length, 0, total.crce, totsec);
2236         length += print_frac (s + length, 1, total.rcrce, totsec);
2237
2238         length += print_frac (s + length, 0, total.es, totsec);
2239         length += print_frac (s + length, 1, total.les, totsec);
2240
2241         length += print_frac (s + length, 0, total.ses, totsec);
2242         length += print_frac (s + length, 1, total.bes, totsec);
2243
2244         length += print_frac (s + length, 0, total.oofs, totsec);
2245         length += print_frac (s + length, 1, total.css, totsec);
2246
2247         length += sprintf (s + length, " -- Total\n");
2248         return length;
2249 }
2250
2251 static int print_chan (char *s, ce_chan_t *c)
2252 {
2253         drv_t *d = c->sys;
2254         int length = 0;
2255
2256         length += sprintf (s + length, "ce%d", c->board->num * NCHAN + c->num);
2257         if (d->chan->debug)
2258                 length += sprintf (s + length, " debug=%d", d->chan->debug);
2259
2260         if (c->board->mux) {
2261                 length += sprintf (s + length, " cfg=C");
2262         } else {
2263                 length += sprintf (s + length, " cfg=A");
2264         }
2265
2266         if (c->baud)
2267                 length += sprintf (s + length, " %ld", c->baud);
2268         else
2269                 length += sprintf (s + length, " extclock");
2270
2271         if (c->type == T_E1)
2272                 switch (c->gsyn) {
2273                 case GSYN_INT   : length += sprintf (s + length, " syn=int");     break;
2274                 case GSYN_RCV   : length += sprintf (s + length, " syn=rcv");     break;
2275                 case GSYN_RCV0  : length += sprintf (s + length, " syn=rcv0");    break;
2276                 case GSYN_RCV1  : length += sprintf (s + length, " syn=rcv1");    break;
2277                 }
2278         if (c->type == T_E1)
2279                 length += sprintf (s + length, " higain=%s", c->higain ? "on" : "off");
2280
2281         length += sprintf (s + length, " loop=%s", c->lloop ? "on" : "off");
2282
2283         if (c->type == T_E1)
2284                 length += sprintf (s + length, " ts=%s", format_timeslots (c->ts));
2285         length += sprintf (s + length, "\n");
2286         return length;
2287 }
2288
2289 #if __FreeBSD_version >= 500000
2290 static int ng_ce_rcvmsg (node_p node, item_p item, hook_p lasthook)
2291 {
2292         drv_t *d = NG_NODE_PRIVATE (node);
2293         struct ng_mesg *msg;
2294 #else
2295 static int ng_ce_rcvmsg (node_p node, struct ng_mesg *msg,
2296         const char *retaddr, struct ng_mesg **rptr)
2297 {
2298         drv_t *d = node->private;
2299 #endif
2300         struct ng_mesg *resp = NULL;
2301         int error = 0;
2302
2303         CE_DEBUG (d, ("Rcvmsg\n"));
2304 #if __FreeBSD_version >= 500000
2305         NGI_GET_MSG (item, msg);
2306 #endif
2307         switch (msg->header.typecookie) {
2308         default:
2309                 error = EINVAL;
2310                 break;
2311
2312         case NGM_CE_COOKIE:
2313                 printf ("Not implemented yet\n");
2314                 error = EINVAL;
2315                 break;
2316
2317         case NGM_GENERIC_COOKIE:
2318                 switch (msg->header.cmd) {
2319                 default:
2320                         error = EINVAL;
2321                         break;
2322
2323                 case NGM_TEXT_STATUS: {
2324                         char *s;
2325                         int l = 0;
2326                         int dl = sizeof (struct ng_mesg) + 730;
2327
2328 #if __FreeBSD_version >= 500000 
2329                         NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2330                         if (! resp) {
2331                                 error = ENOMEM;
2332                                 break;
2333                         }
2334 #else
2335                         resp = malloc (M_NETGRAPH, M_NOWAIT);
2336                         if (! resp) {
2337                                 error = ENOMEM;
2338                                 break;
2339                         }
2340                         bzero (resp, dl);
2341 #endif
2342                         s = (resp)->data;
2343                         if (d) {
2344                         l += print_chan (s + l, d->chan);
2345                         l += print_stats (s + l, d->chan, 1);
2346                         l += print_modems (s + l, d->chan, 1);
2347                         l += print_e1_stats (s + l, d->chan);
2348                         } else
2349                                 l += sprintf (s + l, "Error: node not connect to channel");
2350 #if __FreeBSD_version < 500000
2351                         (resp)->header.version = NG_VERSION;
2352                         (resp)->header.arglen = strlen (s) + 1;
2353                         (resp)->header.token = msg->header.token;
2354                         (resp)->header.typecookie = NGM_CE_COOKIE;
2355                         (resp)->header.cmd = msg->header.cmd;
2356 #endif
2357                         strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRSIZ);
2358                         }
2359                         break;
2360                 }
2361                 break;
2362         }
2363 #if __FreeBSD_version >= 500000
2364         NG_RESPOND_MSG (error, node, item, resp);
2365         NG_FREE_MSG (msg);
2366 #else
2367         *rptr = resp;
2368         free (msg, M_NETGRAPH);
2369 #endif
2370         return error;
2371 }
2372
2373 #if __FreeBSD_version >= 500000
2374 static int ng_ce_rcvdata (hook_p hook, item_p item)
2375 {
2376         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2377         struct mbuf *m;
2378 #if __FreeBSD_version < 502120
2379         meta_p meta;
2380 #else
2381         struct ng_tag_prio *ptag;
2382 #endif
2383 #else
2384 static int ng_ce_rcvdata (hook_p hook, struct mbuf *m, meta_p meta)
2385 {
2386         drv_t *d = hook->node->private;
2387 #endif
2388         bdrv_t *bd = d->board->sys;
2389         struct ifqueue *q;
2390         int s;
2391
2392         CE_DEBUG2 (d, ("Rcvdata\n"));
2393 #if __FreeBSD_version >= 500000
2394         NGI_GET_M (item, m);
2395 #if __FreeBSD_version < 502120
2396         NGI_GET_META (item, meta);
2397 #endif
2398         NG_FREE_ITEM (item);
2399         if (! NG_HOOK_PRIVATE (hook) || ! d) {
2400                 NG_FREE_M (m);
2401 #if __FreeBSD_version < 502120
2402                 NG_FREE_META (meta);
2403 #endif
2404 #else
2405         if (! hook->private || ! d) {
2406                 NG_FREE_DATA (m,meta);
2407 #endif
2408                 return ENETDOWN;
2409         }
2410
2411 #if __FreeBSD_version >= 502120
2412         /* Check for high priority data */
2413         if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
2414             NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
2415                 q = &d->hi_queue;
2416         else
2417                 q = &d->queue;
2418 #else
2419         q = (meta && meta->priority > 0) ? &d->hi_queue : &d->queue;
2420 #endif
2421
2422         s = splimp ();
2423         CE_LOCK (bd);
2424 #if __FreeBSD_version >= 500000
2425         IF_LOCK (q);
2426         if (_IF_QFULL (q)) {
2427                 _IF_DROP (q);
2428                 IF_UNLOCK (q);
2429                 CE_UNLOCK (bd);
2430                 splx (s);
2431                 NG_FREE_M (m);
2432 #if __FreeBSD_version < 502120
2433                 NG_FREE_META (meta);
2434 #endif
2435                 return ENOBUFS;
2436         }
2437         _IF_ENQUEUE (q, m);
2438         IF_UNLOCK (q);
2439 #else
2440         if (IF_QFULL (q)) {
2441                 IF_DROP (q);
2442                 CE_UNLOCK (bd);
2443                 splx (s);
2444                 NG_FREE_DATA (m, meta);
2445                 return ENOBUFS;
2446         }
2447         IF_ENQUEUE (q, m);
2448 #endif
2449         ce_start (d);
2450         CE_UNLOCK (bd);
2451         splx (s);
2452         return 0;
2453 }
2454
2455 static int ng_ce_rmnode (node_p node)
2456 {
2457 #if __FreeBSD_version >= 500000
2458         drv_t *d = NG_NODE_PRIVATE (node);
2459
2460         CE_DEBUG (d, ("Rmnode\n"));
2461         if (d && d->running) {
2462                 bdrv_t *bd = d->board->sys;
2463                 int s = splimp ();
2464                 CE_LOCK (bd);
2465                 ce_down (d);
2466                 CE_UNLOCK (bd);
2467                 splx (s);
2468         }
2469 #ifdef  KLD_MODULE
2470 #if __FreeBSD_version >= 502120
2471         if (node->nd_flags & NGF_REALLY_DIE) {
2472 #else
2473         if (node->nd_flags & NG_REALLY_DIE) {
2474 #endif
2475                 NG_NODE_SET_PRIVATE (node, NULL);
2476                 NG_NODE_UNREF (node);
2477         }
2478 #if __FreeBSD_version >= 502120
2479         NG_NODE_REVIVE(node);           /* Persistant node */
2480 #else
2481         node->nd_flags &= ~NG_INVALID;
2482 #endif
2483 #endif
2484 #else /* __FreeBSD_version < 500000 */
2485         drv_t *d = node->private;
2486
2487         if (d && d->running) {
2488                 bdrv_t *bd = d->board->sys;
2489                 int s = splimp ();
2490                 CE_LOCK (bd);
2491                 ce_down (d);
2492                 CE_UNLOCK (bd);
2493                 splx (s);
2494         }
2495
2496         node->flags |= NG_INVALID;
2497         ng_cutlinks (node);
2498 #ifdef  KLD_MODULE
2499         ng_unname (node);
2500         ng_unref (node);
2501 #endif
2502 #endif
2503         return 0;
2504 }
2505
2506 static int ng_ce_connect (hook_p hook)
2507 {
2508 #if __FreeBSD_version >= 500000
2509         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2510 #else
2511         drv_t *d = hook->node->private;
2512 #endif
2513
2514         if (d) {
2515                 CE_DEBUG (d, ("Connect\n"));
2516                 callout_reset (&d->timeout_handle, hz, ce_watchdog_timer, d);
2517         }
2518         
2519         return 0;
2520 }
2521
2522 static int ng_ce_disconnect (hook_p hook)
2523 {
2524 #if __FreeBSD_version >= 500000
2525         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2526 #else
2527         drv_t *d = hook->node->private;
2528 #endif
2529
2530         if (d) {
2531                 CE_DEBUG (d, ("Disconnect\n"));
2532 #if __FreeBSD_version >= 500000
2533                 if (NG_HOOK_PRIVATE (hook))
2534 #else
2535                 if (hook->private)
2536 #endif
2537                 {
2538                         bdrv_t *bd = d->board->sys;
2539                         int s = splimp ();
2540                         CE_LOCK (bd);
2541                         ce_down (d);
2542                         CE_UNLOCK (bd);
2543                         splx (s);
2544                 }
2545                 /* If we were wait it than it reasserted now, just stop it. */
2546                 if (!callout_drain (&d->timeout_handle))
2547                         callout_stop (&d->timeout_handle);
2548         }
2549         return 0;
2550 }
2551 #endif
2552
2553 static int ce_modevent (module_t mod, int type, void *unused)
2554 {
2555 #if __FreeBSD_version < 500000
2556         dev_t dev;
2557         struct cdevsw *cdsw;
2558 #endif
2559         static int load_count = 0;
2560
2561 #if __FreeBSD_version < 500000
2562         dev = makedev (CDEV_MAJOR, 0);
2563 #endif
2564
2565         switch (type) {
2566         case MOD_LOAD:
2567 #if __FreeBSD_version < 500000
2568                 if (dev != NODEV &&
2569                     (cdsw = devsw (dev)) &&
2570                     cdsw->d_maj == CDEV_MAJOR) {
2571                         printf ("Tau32-PCI driver is already in system\n");
2572                         return (ENXIO);
2573                 }
2574 #endif
2575 #if __FreeBSD_version >= 500000 && defined NETGRAPH
2576                 if (ng_newtype (&typestruct))
2577                         printf ("Failed to register ng_ce\n");
2578 #endif
2579                 ++load_count;
2580 #if __FreeBSD_version <= 500000
2581                 cdevsw_add (&ce_cdevsw);
2582 #endif
2583 #if __FreeBSD_version >= 500000
2584                 callout_init (&timeout_handle, CALLOUT_MPSAFE);
2585 #else
2586                 callout_init (&timeout_handle);
2587 #endif
2588                 callout_reset (&timeout_handle, hz*5, ce_timeout, 0);
2589                 break;
2590         case MOD_UNLOAD:
2591                 if (load_count == 1) {
2592                         printf ("Removing device entry for Tau32-PCI\n");
2593 #if __FreeBSD_version <= 500000
2594                         cdevsw_remove (&ce_cdevsw);
2595 #endif
2596 #if __FreeBSD_version >= 500000 && defined NETGRAPH
2597                         ng_rmtype (&typestruct);
2598 #endif                  
2599                 }
2600                 /* If we were wait it than it reasserted now, just stop it.
2601                  * Actually we shouldn't get this condition. But code could be
2602                  * changed in the future, so just be a litle paranoid.
2603                  */
2604                 if (!callout_drain (&timeout_handle))
2605                         callout_stop (&timeout_handle);
2606                 --load_count;
2607                 break;
2608         case MOD_SHUTDOWN:
2609                 break;
2610         }
2611         return 0;
2612 }
2613
2614 #ifdef NETGRAPH
2615 #if __FreeBSD_version >= 502100
2616 static struct ng_type typestruct = {
2617         .version        = NG_ABI_VERSION,
2618         .name           = NG_CE_NODE_TYPE,
2619         .constructor    = ng_ce_constructor,
2620         .rcvmsg         = ng_ce_rcvmsg,
2621         .shutdown       = ng_ce_rmnode,
2622         .newhook        = ng_ce_newhook,
2623         .connect        = ng_ce_connect,
2624         .rcvdata        = ng_ce_rcvdata,
2625         .disconnect     = ng_ce_disconnect,
2626 };
2627 #else /* __FreeBSD_version < 502100 */
2628 static struct ng_type typestruct = {
2629 #if __FreeBSD_version >= 500000
2630         NG_ABI_VERSION,
2631 #else
2632         NG_VERSION,
2633 #endif
2634         NG_CE_NODE_TYPE,
2635         ce_modevent,
2636         ng_ce_constructor,
2637         ng_ce_rcvmsg,
2638         ng_ce_rmnode,
2639         ng_ce_newhook,
2640         NULL,
2641         ng_ce_connect,
2642         ng_ce_rcvdata,
2643 #if __FreeBSD_version < 500000
2644         NULL,
2645 #endif
2646         ng_ce_disconnect,
2647         NULL
2648 };
2649 #endif /* __FreeBSD_version < 502100 */
2650
2651 #endif /*NETGRAPH*/
2652
2653 #if __FreeBSD_version >= 500000
2654 #ifdef NETGRAPH
2655 MODULE_DEPEND (ng_ce, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2656 #else
2657 MODULE_DEPEND (ce, sppp, 1, 1, 1);
2658 #endif
2659 #ifdef KLD_MODULE
2660 DRIVER_MODULE (cemod, pci, ce_driver, ce_devclass, ce_modevent, NULL);
2661 #else
2662 DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ce_modevent, NULL);
2663 #endif
2664 #else /* if __FreeBSD_version < 500000*/
2665 #ifdef NETGRAPH
2666 DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ng_mod_event, &typestruct);
2667 #else
2668 DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ce_modevent, NULL);
2669 #endif
2670 #endif /* __FreeBSD_version < 500000 */
2671 #endif /* NPCI */