The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/loran.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * ----------------------------------------------------------------------------
    3  * "THE BEER-WARE LICENSE" (Revision 42):
    4  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
    5  * can do whatever you want with this stuff. If we meet some day, and you think
    6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
    7  * ----------------------------------------------------------------------------
    8  *
    9  * $FreeBSD$
   10  *
   11  * This device-driver helps the userland controlprogram for a LORAN-C
   12  * receiver avoid monopolizing the CPU.
   13  *
   14  * This is clearly a candidate for the "most weird hardware support in
   15  * FreeBSD" prize.  At this time only two copies of the receiver are
   16  * known to exist in the entire world.
   17  *
   18  * Details can be found at:
   19  *     ftp://ftp.eecis.udel.edu/pub/ntp/loran.tar.Z
   20  *
   21  */
   22 
   23 #ifdef KERNEL
   24 #include <sys/param.h>
   25 #include <sys/systm.h>
   26 #include <sys/sysctl.h>
   27 #include <sys/conf.h>
   28 #include <sys/kernel.h>
   29 #include <sys/uio.h>
   30 #include <sys/malloc.h>
   31 
   32 #include <i386/isa/isa_device.h>
   33 #endif /* KERNEL */
   34 
   35 typedef TAILQ_HEAD(, datapoint) dphead_t;
   36 
   37 struct datapoint {
   38         /* Fields used by kernel */
   39         u_int64_t               scheduled;
   40         u_int                   code;
   41         u_int                   fri;
   42         u_int                   agc;
   43         u_int                   phase;
   44         u_int                   width;
   45         u_int                   par;
   46         u_int                   isig;
   47         u_int                   qsig;
   48         u_int                   ssig;
   49         u_int64_t               epoch;
   50         TAILQ_ENTRY(datapoint)  list;
   51         u_char                  status;
   52         int                     vco;
   53         int                     bounce;
   54         pid_t                   pid;
   55         struct timespec         when;
   56 
   57         int                     priority;
   58         dphead_t                *home;
   59 
   60         /* Fields used only in userland */
   61         void                    *ident;
   62         int                     index;
   63         double                  ival;
   64         double                  qval;
   65         double                  sval;
   66         double                  mval;
   67 
   68 };
   69 
   70 /*
   71  * Mode register (PAR) hardware definitions
   72  */
   73     #define INTEG 0x03          /* integrator mask */
   74         #define INTEG_1000us    0
   75         #define INTEG_264us     1
   76         #define INTEG_36us      2
   77         #define INTEG_SHORT     3
   78     #define GATE 0x0C           /* gate source mask */
   79         #define GATE_OPEN       0x0
   80         #define GATE_GRI        0x4
   81         #define GATE_PCI        0x8
   82         #define GATE_STB        0xc
   83     #define MSB 0x10            /* load dac high-order bits */
   84     #define IEN 0x20            /* enable interrupt bit */
   85     #define EN5 0x40            /* enable counter 5 bit */
   86     #define ENG 0x80            /* enable gri bit */
   87 
   88 #define VCO_SHIFT 8             /* bits of fraction on VCO value */
   89 #define VCO (2048 << VCO_SHIFT) /* initial vco dac (0 V)*/
   90 
   91 
   92 #define PGUARD 990             /* program guard time (cycle) (990!) */
   93 
   94 
   95 #ifdef KERNEL
   96 
   97 #define NLORAN  10              /* Allow ten minor devices */
   98 
   99 #define NDUMMY 4                /* How many idlers we want */
  100 
  101 #define PORT 0x0300             /* controller port address */
  102 
  103 
  104 #define GRI 800                 /* pulse-group gate (cycle) */
  105 
  106 /*
  107  * Analog/digital converter (ADC) hardware definitions
  108  */
  109 #define ADC PORT+2              /* adc buffer (r)/address (w) */
  110 #define ADCGO PORT+3            /* adc status (r)/adc start (w) */
  111     #define ADC_START 0x01      /* converter start bit (w) */
  112     #define ADC_BUSY 0x01       /* converter busy bit (r) */
  113     #define ADC_DONE 0x80       /* converter done bit (r) */
  114     #define ADC_I 0             /* i channel (phase) */
  115     #define ADC_Q 1             /* q channel (amplitude) */
  116     #define ADC_S 2             /* s channel (agc) */
  117 
  118 /*
  119  * Digital/analog converter (DAC) hardware definitions
  120  * Note: output voltage increases with value programmed; the buffer
  121  * is loaded in two 8-bit bytes, the lsb 8 bits with the MSB bit off in
  122  * the PAR register, the msb 4 bits with the MSB on.
  123  */
  124 #define DACA PORT+4             /* vco (dac a) buffer (w) */
  125 #define DACB PORT+5             /* agc (dac b) buffer (w) */
  126 
  127 #define LOAD_DAC(dac, val) if (0) { } else {                            \
  128         par &= ~MSB; outb(PAR, par); outb((dac), (val) & 0xff);         \
  129         par |=  MSB; outb(PAR, par); outb((dac), ((val) >> 8) & 0xff);  \
  130         }
  131 
  132 /*
  133  * Pulse-code generator (CODE) hardware definitions
  134  * Note: bits are shifted out from the lsb first
  135  */
  136 #define CODE PORT+6             /* pulse-code buffer (w) */
  137     #define MPCA 0xCA           /* LORAN-C master pulse code group a */
  138     #define MPCB 0x9F           /* LORAN-C master pulse code group b */
  139     #define SPCA 0xF9           /* LORAN-C slave pulse code group a */
  140     #define SPCB 0xAC           /* LORAN-C slave pulse code group b */
  141 
  142 /*
  143  * Mode register (PAR) hardware definitions
  144  */
  145 #define PAR PORT+7              /* parameter buffer (w) */
  146 
  147 #define TGC PORT+0              /* stc control port (r/w) */
  148 #define TGD PORT+1              /* stc data port (r/w) */
  149 
  150 /*
  151  * Timing generator (STC) hardware commands
  152  */
  153 /* argument sssss = counter numbers 5-1 */
  154 #define TG_LOADDP 0x00             /* load data pointer */
  155     /* argument ee = element (all groups except ggg = 000 or 111) */
  156     #define MODEREG 0x00        /* mode register */
  157     #define LOADREG 0x08        /* load register */
  158     #define HOLDREG 0x10        /* hold register */
  159     #define HOLDINC 0x18        /* hold register (hold cycle increm) */
  160     /* argument ee = element (group ggg = 111) */
  161     #define ALARM1 0x07         /* alarm register 1 */
  162     #define ALARM2 0x0F         /* alarm register 2 */
  163     #define MASTER 0x17         /* master mode register */
  164     #define STATUS 0x1F         /* status register */
  165 #define ARM 0x20                /* arm counters */
  166 #define LOAD 0x40               /* load counters */
  167 #define TG_LOADARM 0x60            /* load and arm counters */
  168 #define DISSAVE 0x80            /* disarm and save counters */
  169 #define TG_SAVE 0xA0               /* save counters */
  170 #define DISARM 0xC0             /* disarm counters */
  171 /* argument nnn = counter number */
  172 #define SETTOG 0xE8             /* set toggle output HIGH for counter */
  173 #define CLRTOG 0xE0             /* set toggle output LOW for counter */
  174 #define STEP 0xF0               /* step counter */
  175 /* argument eeggg, where ee = element, ggg - counter group */
  176 /* no arguments */
  177 #define ENABDPS 0xE0            /* enable data pointer sequencing */
  178 #define ENABFOUT 0xE6           /* enable fout */
  179 #define ENAB8 0xE7              /* enable 8-bit data bus */
  180 #define DSABDPS 0xE8            /* disable data pointer sequencing */
  181 #define ENAB16 0xEF             /* enable 16-bit data bus */
  182 #define DSABFOUT 0xEE           /* disable fout */
  183 #define ENABPFW 0xF8            /* enable prefetch for write */
  184 #define DSABPFW 0xF9            /* disable prefetch for write */
  185 #define TG_RESET 0xFF              /* master reset */
  186 
  187 #define LOAD_9513(index, val) if (0) {} else {          \
  188         outb(TGC, TG_LOADDP + (index));                 \
  189         outb(TGD, (val) & 0xff);                                        \
  190         outb(TGD, ((val) >> 8) & 0xff);                         \
  191         }
  192 
  193 #define NENV 40                 /* size of envelope filter */
  194 #define CLOCK 50                /* clock period (clock) */
  195 #define CYCLE 10                /* carrier period (us) */
  196 #define PCX (NENV * CLOCK)      /* envelope gate (clock) */
  197 #define STROBE 50               /* strobe gate (clock) */
  198 
  199 /**********************************************************************/
  200 
  201 dphead_t minors[NLORAN], working, holding;
  202 
  203 static struct datapoint dummy[NDUMMY];
  204 
  205 static u_int64_t ticker;
  206 
  207 static u_char par;
  208 
  209 static MALLOC_DEFINE(M_LORAN, "Loran", "Loran datapoints");
  210 
  211 static int loranerror;
  212 static char lorantext[80];
  213 
  214 static u_int vco_is;
  215 static u_int vco_should;
  216 static u_int vco_want;
  217 static u_int64_t vco_when;
  218 static int64_t vco_error;
  219 
  220 /**********************************************************************/
  221 
  222 static  int             loranprobe (struct isa_device *dvp);
  223 extern  void            init_tgc (void);
  224 static  int             loranattach (struct isa_device *isdp);
  225 static  void            loranenqueue (struct datapoint *);
  226 static  d_open_t        loranopen;
  227 static  d_close_t       loranclose;
  228 static  d_read_t        loranread;
  229 static  d_write_t       loranwrite;
  230 static  ointhand2_t     loranintr;
  231 extern  struct timecounter loran_timecounter;
  232 
  233 /**********************************************************************/
  234 
  235 int
  236 loranprobe(struct isa_device *dvp)
  237 {
  238         /* We need to be a "fast-intr" */
  239         dvp->id_ri_flags |= RI_FAST;
  240 
  241         dvp->id_iobase = PORT;
  242         return (8);
  243 }
  244 
  245 u_short tg_init[] = {                   /* stc initialization vector    */
  246         0x0562,      12,         13,    /* counter 1 (p0)  Mode J       */
  247         0x0262,  PGUARD,        GRI,    /* counter 2 (gri) Mode J       */
  248         0x8562,     PCX, 5000 - PCX,    /* counter 3 (pcx)              */
  249         0xc562,       0,     STROBE,    /* counter 4 (stb) Mode L       */
  250         0x052a,       0,          0     /* counter 5 (out)              */
  251 };
  252 
  253 void
  254 init_tgc(void)
  255 {
  256         int i;
  257 
  258         /* Initialize the 9513A */
  259         outb(TGC, TG_RESET);         outb(TGC, LOAD+0x1f); /* reset STC chip */
  260         LOAD_9513(MASTER, 0x8af0);
  261         outb(TGC, TG_LOADDP+1);
  262         tg_init[4] = 7499 - GRI;
  263         for (i = 0; i < 5*3; i++) {
  264                 outb(TGD, tg_init[i]);
  265                 outb(TGD, tg_init[i] >> 8);
  266         }
  267         outb(TGC, TG_LOADARM+0x1f);    /* let the good times roll */
  268 }
  269 
  270 int
  271 loranattach(struct isa_device *isdp)
  272 {
  273         int i;
  274 
  275         isdp->id_ointr = loranintr;
  276 
  277         /* We need to be a "fast-intr" */
  278         isdp->id_ri_flags |= RI_FAST;
  279 
  280         printf("loran0: LORAN-C Receiver\n");
  281 
  282         vco_should = VCO;
  283         vco_is = vco_should >> VCO_SHIFT;
  284         LOAD_DAC(DACA, vco_is);
  285          
  286         init_tgc();
  287 
  288         init_timecounter(&loran_timecounter);
  289 
  290         TAILQ_INIT(&working);
  291         TAILQ_INIT(&holding);
  292         for (i = 0; i < NLORAN; i++) {
  293                 TAILQ_INIT(&minors[i]);
  294                 
  295         }
  296 
  297         for (i = 0; i < NDUMMY; i++) {
  298                 dummy[i].agc = 4095;
  299                 dummy[i].code = 0xac;
  300                 dummy[i].fri = PGUARD;
  301                 dummy[i].phase = 50;
  302                 dummy[i].width = 50;
  303                 dummy[i].priority = 9999;
  304                 TAILQ_INSERT_TAIL(&working, &dummy[i], list);
  305         }
  306 
  307         inb(ADC);               /* Flush any old result */
  308         outb(ADC, ADC_S);
  309 
  310         par = ENG|IEN;
  311         outb(PAR, par);
  312 
  313         return (1);
  314 }
  315 
  316 static  int
  317 loranopen (dev_t dev, int flags, int fmt, struct proc *p)
  318 {
  319         int idx;
  320 
  321         idx = minor(dev);
  322         if (idx >= NLORAN) 
  323                 return (ENODEV);
  324 
  325         return(0);
  326 }
  327 
  328 static  int
  329 loranclose(dev_t dev, int flags, int fmt, struct proc *p)
  330 {
  331         return(0);
  332 }
  333 
  334 static  int
  335 loranread(dev_t dev, struct uio * uio, int ioflag)
  336 {
  337         u_long ef;
  338         struct datapoint *this;
  339         int err, c;
  340         int idx;
  341 
  342         idx = minor(dev);
  343         
  344         if (loranerror) {
  345                 printf("Loran0: %s", lorantext);
  346                 return(EIO);
  347         }
  348         if (TAILQ_EMPTY(&minors[idx])) 
  349                 tsleep ((caddr_t)&minors[idx], PZERO + 8 |PCATCH, "loranrd", hz*2);
  350         if (TAILQ_EMPTY(&minors[idx])) 
  351                 return(0);
  352         this = TAILQ_FIRST(&minors[idx]);
  353         ef = read_eflags();
  354         disable_intr();
  355         TAILQ_REMOVE(&minors[idx], this, list);
  356         write_eflags(ef);
  357 
  358         c = imin(uio->uio_resid, (int)sizeof *this);
  359         err = uiomove((caddr_t)this, c, uio);        
  360         FREE(this, M_LORAN);
  361         return(err);
  362 }
  363 
  364 static void
  365 loranenqueue(struct datapoint *dp)
  366 {
  367         struct datapoint *dpp, *dpn;
  368 
  369         while(dp) {
  370                 /*
  371                  * The first two elements on "working" are sacred,
  372                  * they're already partly setup in hardware, so the
  373                  * earliest slot we can use is #3
  374                  */
  375                 dpp = TAILQ_FIRST(&working);
  376                 dpp = TAILQ_NEXT(dpp, list);
  377                 dpn = TAILQ_NEXT(dpp, list);
  378                 while (1) {
  379                         /* 
  380                          * We cannot bump "dpp", so if "dp" overlaps it
  381                          * skip a beat.
  382                          * XXX: should use better algorithm ?
  383                          */
  384                         if (dpp->scheduled + PGUARD > dp->scheduled) {
  385                                 dp->scheduled += dp->fri;
  386                                 continue;
  387                         }               
  388 
  389                         /*
  390                          * If "dpn" will be done before "dp" wants to go,
  391                          * we must look further down the list.
  392                          */
  393                         if (dpn && dpn->scheduled + PGUARD < dp->scheduled) {
  394                                 dpp = dpn;
  395                                 dpn = TAILQ_NEXT(dpp, list);
  396                                 continue;
  397                         }
  398 
  399                         /* 
  400                          * If at end of list, put "dp" there
  401                          */
  402                         if (!dpn) {
  403                                 TAILQ_INSERT_AFTER(&working, dpp, dp, list);
  404                                 break;
  405                         }
  406 
  407                         /*
  408                          * If "dp" fits before "dpn", insert it there
  409                          */
  410                         if (dpn->scheduled > dp->scheduled + PGUARD) {
  411                                 TAILQ_INSERT_AFTER(&working, dpp, dp, list);
  412                                 break;
  413                         }
  414 
  415                         /*
  416                          * If "dpn" is less important, bump it.
  417                          */
  418                         if (dp->priority < dpn->priority) {
  419                                 TAILQ_REMOVE(&working, dpn, list);
  420                                 TAILQ_INSERT_TAIL(&holding, dpn, list);
  421                                 dpn = TAILQ_NEXT(dpp, list);
  422                                 continue;
  423                         }
  424 
  425                         /*
  426                          * "dpn" was more or equally important, "dp" must
  427                          * take yet turn.
  428                          */
  429                         dp->scheduled += dp->fri;
  430                 }
  431 
  432                 do {
  433                         /*
  434                          * If anything was bumped, put it back as best we can
  435                          */
  436                         if (TAILQ_EMPTY(&holding)) {
  437                                 dp = 0;
  438                                 break;
  439                         }
  440                         dp = TAILQ_FIRST(&holding);
  441                         TAILQ_REMOVE(&holding, dp, list);
  442                         if (dp->home) {
  443                                 if (!--dp->bounce) {
  444                                         TAILQ_INSERT_TAIL(dp->home, dp, list);
  445                                         wakeup((caddr_t)dp->home);
  446                                         dp = 0;
  447                                 }
  448                         }
  449                 } while (!dp);
  450         }
  451 }
  452 
  453 static  int
  454 loranwrite(dev_t dev, struct uio * uio, int ioflag)
  455 {
  456         u_long ef;
  457         int err = 0, c;
  458         struct datapoint *this;
  459         int idx;
  460         u_int64_t dt;
  461 
  462         idx = minor(dev);
  463 
  464         MALLOC(this, struct datapoint *, sizeof *this, M_LORAN, M_WAITOK);
  465         c = imin(uio->uio_resid, (int)sizeof *this);
  466         err = uiomove((caddr_t)this, c, uio);        
  467         if (!err && this->fri == 0)
  468                 err = EINVAL;
  469         /* XXX more checks */
  470         this->home = &minors[idx];
  471         this->priority = idx;
  472         if (ticker > this->scheduled) {
  473                 dt = ticker - this->scheduled;
  474                 dt -= dt % this->fri;
  475                 this->scheduled += dt;
  476         }
  477         if (!err) {
  478                 ef = read_eflags();
  479                 disable_intr();
  480                 loranenqueue(this);
  481                 write_eflags(ef);
  482                 if (this->vco >= 0)
  483                         vco_want = this->vco;
  484         } else {
  485                 FREE(this, M_LORAN);
  486         }
  487         return(err);
  488 }
  489 
  490 static void
  491 loranintr(int unit)
  492 {
  493         u_long ef;
  494         int status = 0, count = 0, i;
  495         struct datapoint *this, *next;
  496         int delay;
  497 
  498         ef = read_eflags();
  499         disable_intr();
  500 
  501         this = TAILQ_FIRST(&working);
  502         TAILQ_REMOVE(&working, this, list);
  503 
  504         nanotime(&this->when);
  505         this->ssig = inb(ADC);
  506 
  507         par &= ~(ENG | IEN);
  508         outb(PAR, par);
  509 
  510         outb(ADC, ADC_I);
  511         outb(ADCGO, ADC_START);
  512         while (!(inb(ADCGO) & ADC_DONE))
  513                 continue;
  514         this->isig = inb(ADC);
  515 
  516         outb(ADC, ADC_Q);
  517         outb(ADCGO, ADC_START);
  518         while (!(inb(ADCGO) & ADC_DONE))
  519                 continue;
  520         this->qsig = inb(ADC);
  521 
  522         outb(ADC, ADC_S);
  523 
  524         this->epoch = ticker;
  525         this->vco = vco_is;
  526 
  527         if (this->home) {
  528                 TAILQ_INSERT_TAIL(this->home, this, list);
  529                 wakeup((caddr_t)this->home);
  530         } else {
  531                 loranenqueue(this);
  532         }
  533 
  534         this = TAILQ_FIRST(&working);
  535         next = TAILQ_NEXT(this, list);
  536 
  537         delay = next->scheduled - this->scheduled;
  538         delay -= GRI;
  539 
  540         /* load this->params */
  541         par &= ~(INTEG|GATE);
  542         par |= this->par & (INTEG|GATE);
  543 
  544         LOAD_DAC(DACB, this->agc);
  545 
  546         outb(CODE, this->code);
  547 
  548         LOAD_9513(0x0a, delay);
  549 
  550         /*
  551          * We need to load this from the opposite register * due to some 
  552          * weirdness which you can read about in in the 9513 manual on 
  553          * page 1-26 under "LOAD"
  554          */
  555         LOAD_9513(0x0c, this->phase);
  556         LOAD_9513(0x14, this->phase);
  557         outb(TGC, TG_LOADARM + 0x08);
  558         LOAD_9513(0x14, this->width);
  559 
  560         vco_error += ((vco_is << VCO_SHIFT) - vco_should) * (ticker - vco_when);
  561         vco_should = vco_want;
  562         i = vco_should >> VCO_SHIFT;
  563         if (vco_error < 0)
  564                 i++;
  565         
  566         if (vco_is != i) {
  567                 LOAD_DAC(DACA, i);
  568                 vco_is = i;
  569         }
  570         vco_when = ticker;
  571 
  572         this->status = inb(TGC);
  573 #if 1
  574         /* Check if we overran */
  575         status = this->status & 0x1c;
  576 
  577         if (status) {
  578                 outb(TGC, TG_SAVE + 2);         /* save counter #2 */
  579                 outb(TGC, TG_LOADDP + 0x12);    /* hold counter #2 */
  580                 count = inb(TGD);
  581                 count |= inb(TGD) << 8;
  582                 LOAD_9513(0x12, GRI)
  583         }
  584 #endif
  585 
  586         par |= ENG | IEN;
  587         outb(PAR, par);
  588 
  589         if (status) {
  590                 snprintf(lorantext, sizeof(lorantext),
  591                     "Missed: %02x %d %d this:%p next:%p (dummy=%p)\n", 
  592                     status, count, delay, this, next, &dummy);
  593                 loranerror = 1;
  594         }
  595 
  596         ticker = this->scheduled;
  597 
  598         write_eflags(ef);
  599 }
  600 
  601 /**********************************************************************/
  602 
  603 static unsigned
  604 loran_get_timecount(struct timecounter *tc)
  605 {
  606         unsigned count;
  607         u_long ef;
  608 
  609         ef = read_eflags();
  610         disable_intr();
  611 
  612         outb(TGC, TG_SAVE + 0x10);      /* save counter #5 */
  613         outb(TGC, TG_LOADDP +0x15);     /* hold counter #5 */
  614         count = inb(TGD);
  615         count |= inb(TGD) << 8;
  616 
  617         write_eflags(ef);
  618         return (count);
  619 }
  620 
  621 static struct timecounter loran_timecounter = {
  622         loran_get_timecount,    /* get_timecount */
  623         0,                      /* no pps_poll */
  624         0xffff,                 /* counter_mask */
  625         5000000,                /* frequency */
  626         "loran"                 /* name */
  627 };
  628 
  629 SYSCTL_OPAQUE(_debug, OID_AUTO, loran_timecounter, CTLFLAG_RD, 
  630         &loran_timecounter, sizeof(loran_timecounter), "S,timecounter", "");
  631 
  632 
  633 /**********************************************************************/
  634 
  635 struct  isa_driver lorandriver = {
  636         loranprobe, loranattach, "loran"
  637 };
  638 
  639 #define CDEV_MAJOR 94
  640 static struct cdevsw loran_cdevsw = 
  641         { loranopen,    loranclose,     loranread,      loranwrite,
  642           noioctl,      nullstop,       nullreset,      nodevtotty,
  643           seltrue,      nommap,         nostrat,        "loran",
  644           NULL,         -1 };
  645 
  646 
  647 static loran_devsw_installed = 0;
  648 
  649 static void     loran_drvinit(void *unused)
  650 {
  651         dev_t dev;
  652 
  653         if(!loran_devsw_installed) {
  654                 dev = makedev(CDEV_MAJOR, 0);
  655                 cdevsw_add(&dev,&loran_cdevsw, NULL);
  656                 loran_devsw_installed = 1;
  657         }
  658 }
  659 
  660 SYSINIT(lorandev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,loran_drvinit,NULL)
  661 
  662 #endif /* KERNEL */

Cache object: b596c6dafd7a0e1365078b1596f1b6ed


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.