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/tw.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  * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Eugene W. Stark.
   16  * 4. The name of the author may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 #include "tw.h"
   33 #if NTW > 0
   34 
   35 /*
   36  * Driver configuration parameters
   37  */
   38 
   39 /*
   40  * Time for 1/2 of a power line cycle, in microseconds.
   41  * Change this to 10000 for 50Hz power.  Phil Sampson
   42  * (vk2jnt@gw.vk2jnt.ampr.org OR sampson@gidday.enet.dec.com)
   43  * reports that this works (at least in Australia) using a
   44  * TW7223 module (a local version of the TW523).
   45  */
   46 #define HALFCYCLE 8333                  /* 1/2 cycle = 8333us at 60Hz */
   47 
   48 /*
   49  * Undefine the following if you don't have the high-resolution "microtime"
   50  * routines (leave defined for FreeBSD, which has them).
   51  */
   52 #define HIRESTIME
   53 
   54 /*
   55  * End of driver configuration parameters
   56  */
   57 
   58 /*
   59  * FreeBSD Device Driver for X-10 POWERHOUSE (tm)
   60  * Two-Way Power Line Interface, Model #TW523
   61  *
   62  * written by Eugene W. Stark (stark@cs.sunysb.edu)
   63  * December 2, 1992
   64  *
   65  * NOTES:
   66  *
   67  * The TW523 is a carrier-current modem for home control/automation purposes.
   68  * It is made by:
   69  *
   70  *      X-10 Inc.
   71  *      185A LeGrand Ave.
   72  *      Northvale, NJ 07647
   73  *      USA
   74  *      (201) 784-9700 or 1-800-526-0027
   75  *
   76  *      X-10 Home Controls Inc.
   77  *      1200 Aerowood Drive, Unit 20
   78  *      Mississauga, Ontario
   79  *      (416) 624-4446 or 1-800-387-3346
   80  *
   81  * The TW523 is designed for communications using the X-10 protocol,
   82  * which is compatible with a number of home control systems, including
   83  * Radio Shack "Plug 'n Power(tm)" and Stanley "Lightmaker(tm)."
   84  * I bought my TW523 from:
   85  *
   86  *      Home Control Concepts
   87  *      9353-C Activity Road
   88  *      San Diego, CA 92126
   89  *      (619) 693-8887
   90  *
   91  * They supplied me with the TW523 (which has an RJ-11 four-wire modular
   92  * telephone connector), a modular cable, an RJ-11 to DB-25 connector with
   93  * internal wiring, documentation from X-10 on the TW523 (very good),
   94  * an instruction manual by Home Control Concepts (not very informative),
   95  * and a floppy disk containing binary object code of some demonstration/test
   96  * programs and of a C function library suitable for controlling the TW523
   97  * by an IBM PC under MS-DOS (not useful to me other than to verify that
   98  * the unit worked).  I suggest saving money and buying the bare TW523
   99  * rather than the TW523 development kit (what I bought), because if you
  100  * are running FreeBSD you don't really care about the DOS binaries.
  101  *
  102  * The interface to the TW-523 consists of four wires on the RJ-11 connector,
  103  * which are jumpered to somewhat more wires on the DB-25 connector, which
  104  * in turn is intended to plug into the PC parallel printer port.  I dismantled
  105  * the DB-25 connector to find out what they had done:
  106  *
  107  *      Signal          RJ-11 pin       DB-25 pin(s)    Parallel Port
  108  *      Transmit TX       4 (Y)         2, 4, 6, 8      Data out
  109  *      Receive RX        3 (G)         10, 14          -ACK, -AutoFeed
  110  *      Common            2 (R)         25              Common
  111  *      Zero crossing     1 (B)         17 or 12        -Select or +PaperEnd
  112  *
  113  * NOTE: In the original cable I have (which I am still using, May, 1997)
  114  * the Zero crossing signal goes to pin 17 (-Select) on the parallel port.
  115  * In retrospect, this doesn't make a whole lot of sense, given that the
  116  * -Select signal propagates the other direction.  Indeed, some people have
  117  * reported problems with this, and have had success using pin 12 (+PaperEnd)
  118  * instead.  This driver searches for the zero crossing signal on either
  119  * pin 17 or pin 12, so it should work with either cable configuration.
  120  * My suggestion would be to start by making the cable so that the zero
  121  * crossing signal goes to pin 12 on the parallel port.
  122  *
  123  * The zero crossing signal is used to synchronize transmission to the
  124  * zero crossings of the AC line, as detailed in the X-10 documentation.
  125  * It would be nice if one could generate interrupts with this signal,
  126  * however one needs interrupts on both the rising and falling edges,
  127  * and the -ACK signal to the parallel port interrupts only on the falling
  128  * edge, so it can't be done without additional hardware.
  129  *
  130  * In this driver, the transmit function is performed in a non-interrupt-driven
  131  * fashion, by polling the zero crossing signal to determine when a transition
  132  * has occurred.  This wastes CPU time during transmission, but it seems like
  133  * the best that can be done without additional hardware.  One problem with
  134  * the scheme is that preemption of the CPU during transmission can cause loss
  135  * of sync.  The driver tries to catch this, by noticing that a long delay
  136  * loop has somehow become foreshortened, and the transmission is aborted with
  137  * an error return.  It is up to the user level software to handle this
  138  * situation (most likely by retrying the transmission).
  139  */
  140 
  141 #include <sys/param.h>
  142 #include <sys/systm.h>
  143 #include <sys/proc.h>
  144 #include <sys/conf.h>
  145 #include <sys/buf.h>
  146 #include <sys/kernel.h>
  147 #include <sys/ioctl.h>
  148 #include <sys/uio.h>
  149 #include <sys/syslog.h>
  150 #include <sys/select.h>
  151 #ifdef DEVFS
  152 #include <sys/devfsext.h>
  153 #endif /*DEVFS*/
  154 
  155 #define MIN(a,b)        ((a)<(b)?(a):(b))
  156 
  157 #ifdef HIRESTIME
  158 #include <sys/time.h>
  159 #endif /* HIRESTIME */
  160 
  161 #include <i386/isa/isa_device.h>
  162 
  163 /*
  164  * Transmission is done by calling write() to send three byte packets of data.
  165  * The first byte contains a four bit house code (0=A to 15=P).
  166  * The second byte contains five bit unit/key code (0=unit 1 to 15=unit 16,
  167  * 16=All Units Off to 31 = Status Request).  The third byte specifies
  168  * the number of times the packet is to be transmitted without any
  169  * gaps between successive transmissions.  Normally this is 2, as per
  170  * the X-10 documentation, but sometimes (e.g. for bright and dim codes)
  171  * it can be another value.  Each call to write can specify an arbitrary
  172  * number of data bytes.  An incomplete packet is buffered until a subsequent
  173  * call to write() provides data to complete it.  At most one packet will
  174  * actually be processed in any call to write().  Successive calls to write()
  175  * leave a three-cycle gap between transmissions, per the X-10 documentation.
  176  *
  177  * Reception is done using read().
  178  * The driver produces a series of three-character packets.
  179  * In each packet, the first character consists of flags,
  180  * the second character is a four bit house code (0-15),
  181  * and the third character is a five bit key/function code (0-31).
  182  * The flags are the following:
  183  */
  184 
  185 #define TW_RCV_LOCAL    1  /* The packet arrived during a local transmission */
  186 #define TW_RCV_ERROR    2  /* An invalid/corrupted packet was received */
  187 
  188 /*
  189  * IBM PC parallel port definitions relevant to TW523
  190  */
  191 
  192 #define tw_data 0                       /* Data to tw523 (R/W) */
  193 
  194 #define tw_status 1                     /* Status of tw523 (R) */
  195 #define TWS_RDATA               0x40    /* tw523 receive data */
  196 #define TWS_OUT                 0x20    /* pin 12, out of paper */
  197 
  198 #define tw_control 2                    /* Control tw523 (R/W) */
  199 #define TWC_SYNC                0x08    /* tw523 sync (pin 17) */
  200 #define TWC_ENA                 0x10    /* tw523 interrupt enable */
  201 
  202 /*
  203  * Miscellaneous defines
  204  */
  205 
  206 #define TWUNIT(dev)     (minor(dev))    /* Extract unit number from device */
  207 #define TWPRI           (PZERO+8)       /* I don't know any better, so let's */
  208                                         /* use the same as the line printer */
  209 
  210 static int twprobe(struct isa_device *idp);
  211 static int twattach(struct isa_device *idp);
  212 
  213 struct isa_driver twdriver = {
  214   twprobe, twattach, "tw"
  215 };
  216 
  217 static  d_open_t        twopen;
  218 static  d_close_t       twclose;
  219 static  d_read_t        twread;
  220 static  d_write_t       twwrite;
  221 static  d_select_t      twselect;
  222 
  223 #define CDEV_MAJOR 19
  224 static struct cdevsw tw_cdevsw = 
  225         { twopen,       twclose,        twread,         twwrite,        /*19*/
  226           noioc,        nullstop,       nullreset,      nodevtotty, /* tw */
  227           twselect,     nommap,         nostrat,        "tw",   NULL,   -1 };
  228 
  229 /*
  230  * Software control structure for TW523
  231  */
  232 
  233 #define TWS_XMITTING     1      /* Transmission in progress */
  234 #define TWS_RCVING       2      /* Reception in progress */
  235 #define TWS_WANT         4      /* A process wants received data */
  236 #define TWS_OPEN         8      /* Is it currently open? */
  237 
  238 #define TW_SIZE         3*60    /* Enough for about 10 sec. of input */
  239 #define TW_MIN_DELAY    1500    /* Ignore interrupts of lesser latency */
  240 
  241 static struct tw_sc {
  242   u_int sc_port;                /* I/O Port */
  243   u_int sc_state;               /* Current software control state */
  244   struct selinfo sc_selp;       /* Information for select() */
  245   u_char sc_xphase;             /* Current state of sync (for transmitter) */
  246   u_char sc_rphase;             /* Current state of sync (for receiver) */
  247   u_char sc_flags;              /* Flags for current reception */
  248   short sc_rcount;              /* Number of bits received so far */
  249   int sc_bits;                  /* Bits received so far */
  250   u_char sc_pkt[3];             /* Packet not yet transmitted */
  251   short sc_pktsize;             /* How many bytes in the packet? */
  252   u_char sc_buf[TW_SIZE];       /* We buffer our own input */
  253   int sc_nextin;                /* Next free slot in circular buffer */
  254   int sc_nextout;               /* First used slot in circular buffer */
  255 #ifdef HIRESTIME
  256   int sc_xtimes[22];            /* Times for bits in current xmit packet */
  257   int sc_rtimes[22];            /* Times for bits in current rcv packet */
  258   int sc_no_rcv;                /* number of interrupts received */
  259 #define SC_RCV_TIME_LEN 128
  260   int sc_rcv_time[SC_RCV_TIME_LEN]; /* usec time stamp on interrupt */
  261 #endif /* HIRESTIME */
  262 #ifdef  DEVFS
  263   void  *devfs_token;           /* store the devfs handle */
  264 #endif
  265 } tw_sc[NTW];
  266 
  267 static int tw_zcport;           /* offset of port for zero crossing signal */
  268 static int tw_zcmask;           /* mask for the zero crossing signal */
  269 
  270 static void twdelay25(void);
  271 static void twdelayn(int n);
  272 static void twsetuptimes(int *a);
  273 static int wait_for_zero(struct tw_sc *sc);
  274 static int twputpkt(struct tw_sc *sc, u_char *p);
  275 static int twgetbytes(struct tw_sc *sc, u_char *p, int cnt);
  276 static void twabortrcv(struct tw_sc *sc);
  277 static int twsend(struct tw_sc *sc, int h, int k, int cnt);
  278 static int next_zero(struct tw_sc *sc);
  279 static int twchecktime(int target, int tol);
  280 static void twdebugtimes(struct tw_sc *sc);
  281 
  282 /*
  283  * Counter value for delay loop.
  284  * It is adjusted by twprobe so that the delay loop takes about 25us.
  285  */
  286 
  287 #define TWDELAYCOUNT 161                /* Works on my 486DX/33 */
  288 static int twdelaycount;
  289 
  290 /*
  291  * Twdelay25 is used for very short delays of about 25us.
  292  * It is implemented with a calibrated delay loop, and should be
  293  * fairly accurate ... unless we are preempted by an interrupt.
  294  *
  295  * We use this to wait for zero crossings because the X-10 specs say we
  296  * are supposed to assert carrier within 25us when one happens.
  297  * I don't really believe we can do this, but the X-10 devices seem to be
  298  * fairly forgiving.
  299  */
  300 
  301 static void twdelay25(void)
  302 {
  303   int cnt;
  304   for(cnt = twdelaycount; cnt; cnt--);  /* Should take about 25us */
  305 }
  306 
  307 /*
  308  * Twdelayn is used to time the length of the 1ms carrier pulse.
  309  * This is not very critical, but if we have high-resolution time-of-day
  310  * we check it every apparent 200us to make sure we don't get too far off
  311  * if we happen to be interrupted during the delay.
  312  */
  313 
  314 static void twdelayn(int n)
  315 {
  316 #ifdef HIRESTIME
  317   int t, d;
  318   struct timeval tv;
  319   microtime(&tv);
  320   t = tv.tv_usec;
  321   t += n;
  322 #endif /* HIRESTIME */
  323   while(n > 0) {
  324     twdelay25();
  325     n -= 25;
  326 #ifdef HIRESTIME
  327     if((n & 0x7) == 0) {
  328       microtime(&tv);
  329       d = tv.tv_usec - t;
  330       if(d >= 0 && d < 1000000) return;
  331     }
  332 #endif /* HIRESTIME */
  333   }
  334 }
  335 
  336 static int twprobe(idp)
  337      struct isa_device *idp;
  338 {
  339   struct tw_sc sc;
  340   int d;
  341   int tries;
  342 
  343   sc.sc_port = idp->id_iobase;
  344   /* Search for the zero crossing signal at ports, bit combinations. */
  345   tw_zcport = tw_control;
  346   tw_zcmask = TWC_SYNC;
  347   sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  348   if(wait_for_zero(&sc) < 0) {
  349     tw_zcport = tw_status;
  350     tw_zcmask = TWS_OUT;
  351     sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  352   }
  353   if(wait_for_zero(&sc) < 0)
  354     return(0);
  355   /*
  356    * Iteratively check the timing of a few sync transitions, and adjust
  357    * the loop delay counter, if necessary, to bring the timing reported
  358    * by wait_for_zero() close to HALFCYCLE.  Give up if anything
  359    * ridiculous happens.
  360    */
  361   if(twdelaycount == 0) {  /* Only adjust timing for first unit */
  362     twdelaycount = TWDELAYCOUNT;
  363     for(tries = 0; tries < 10; tries++) {
  364       sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  365       if(wait_for_zero(&sc) >= 0) {
  366         d = wait_for_zero(&sc);
  367         if(d <= HALFCYCLE/100 || d >= HALFCYCLE*100) {
  368           twdelaycount = 0;
  369           return(0);
  370         }
  371         twdelaycount = (twdelaycount * d)/HALFCYCLE;
  372       }
  373     }
  374   }
  375   /*
  376    * Now do a final check, just to make sure
  377    */
  378   sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  379   if(wait_for_zero(&sc) >= 0) {
  380     d = wait_for_zero(&sc);
  381     if(d <= (HALFCYCLE * 110)/100 && d >= (HALFCYCLE * 90)/100) return(8);
  382   }
  383   return(0);
  384 }
  385 
  386 static int twattach(idp)
  387         struct isa_device *idp;
  388 {
  389   struct tw_sc *sc;
  390   int   unit;
  391 
  392   sc = &tw_sc[unit = idp->id_unit];
  393   sc->sc_port = idp->id_iobase;
  394   sc->sc_state = 0;
  395   sc->sc_rcount = 0;
  396 
  397 #ifdef DEVFS
  398         sc->devfs_token = 
  399                 devfs_add_devswf(&tw_cdevsw, unit, DV_CHR, 0, 0, 
  400                                  0600, "tw%d", unit);
  401 #endif
  402 
  403   return (1);
  404 }
  405 
  406 int twopen(dev, flag, mode, p)
  407      dev_t dev;
  408      int flag;
  409      int mode;
  410      struct proc *p;
  411 {
  412   struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
  413   int s;
  414   int port;
  415 
  416   s = spltty();
  417   if(sc->sc_state == 0) {
  418     sc->sc_state = TWS_OPEN;
  419     sc->sc_nextin = sc->sc_nextout = 0;
  420     sc->sc_pktsize = 0;
  421     outb(sc->sc_port+tw_control, TWC_ENA);
  422   }
  423   splx(s);
  424   return(0);
  425 }
  426 
  427 int twclose(dev, flag, mode, p)
  428      dev_t dev;
  429      int flag;
  430      int mode;
  431      struct proc *p;
  432 {
  433   struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
  434   int s;
  435   int port = sc->sc_port;
  436 
  437   s = spltty();
  438   sc->sc_state = 0;
  439   outb(sc->sc_port+tw_control, 0);
  440   splx(s);
  441   return(0);
  442 }
  443 
  444 int twread(dev, uio, ioflag)
  445      dev_t dev;
  446      struct uio *uio;
  447      int ioflag;
  448 {
  449   u_char buf[3];
  450   struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
  451   int error, cnt, s;
  452 
  453   s = spltty();
  454   cnt = MIN(uio->uio_resid, 3);
  455   if((error = twgetbytes(sc, buf, cnt)) == 0) {
  456     error = uiomove(buf, cnt, uio);
  457   }
  458   splx(s);
  459   return(error);
  460 }
  461 
  462 int twwrite(dev, uio, ioflag)
  463      dev_t dev;
  464      struct uio *uio;
  465      int ioflag;
  466 {
  467   struct tw_sc *sc;
  468   int house, key, reps;
  469   int s, error;
  470   int cnt;
  471 
  472   sc = &tw_sc[TWUNIT(dev)];
  473   /*
  474    * Note: Although I had intended to allow concurrent transmitters,
  475    * there is a potential problem here if two processes both write
  476    * into the sc_pkt buffer at the same time.  The following code
  477    * is an additional critical section that needs to be synchronized.
  478    */
  479   s = spltty();
  480   cnt = MIN(3 - sc->sc_pktsize, uio->uio_resid);
  481   if(error = uiomove(&(sc->sc_pkt[sc->sc_pktsize]), cnt, uio)) {
  482     splx(s);
  483     return(error);
  484   }
  485   sc->sc_pktsize += cnt;
  486   if(sc->sc_pktsize < 3) {  /* Only transmit 3-byte packets */
  487     splx(s);
  488     return(0);
  489   }
  490   sc->sc_pktsize = 0;
  491   /*
  492    * Collect house code, key code, and rep count, and check for sanity.
  493    */
  494   house = sc->sc_pkt[0];
  495   key = sc->sc_pkt[1];
  496   reps = sc->sc_pkt[2];
  497   if(house >= 16 || key >= 32) {
  498     splx(s);
  499     return(ENODEV);
  500   }
  501   /*
  502    * Synchronize with the receiver operating in the bottom half, and
  503    * also with concurrent transmitters.
  504    * We don't want to interfere with a packet currently being received,
  505    * and we would like the receiver to recognize when a packet has
  506    * originated locally.
  507    */
  508   while(sc->sc_state & (TWS_RCVING | TWS_XMITTING)) {
  509     if(error = tsleep((caddr_t)sc, TWPRI|PCATCH, "twwrite", 0)) {
  510       splx(s);
  511       return(error);
  512     }
  513   }
  514   sc->sc_state |= TWS_XMITTING;
  515   /*
  516    * Everything looks OK, let's do the transmission.
  517    */
  518   splx(s);  /* Enable interrupts because this takes a LONG time */
  519   error = twsend(sc, house, key, reps);
  520   s = spltty();
  521   sc->sc_state &= ~TWS_XMITTING;
  522   wakeup((caddr_t)sc);
  523   splx(s);
  524   if(error) return(EIO);
  525   else return(0);
  526 }
  527 
  528 /*
  529  * Determine if there is data available for reading
  530  */
  531 
  532 int twselect(dev, rw, p)
  533      dev_t dev;
  534      int rw;
  535      struct proc *p;
  536 {
  537   struct tw_sc *sc;
  538   struct proc *pp;
  539   int s, i;
  540 
  541   sc = &tw_sc[TWUNIT(dev)];
  542   s = spltty();
  543   if(sc->sc_nextin != sc->sc_nextout) {
  544     splx(s);
  545     return(1);
  546   }
  547   selrecord(p, &sc->sc_selp);
  548   splx(s);
  549   return(0);
  550 }
  551 
  552 /*
  553  * X-10 Protocol
  554  */
  555 
  556 #define X10_START_LENGTH 4
  557 static char X10_START[] = { 1, 1, 1, 0 };
  558 
  559 /*
  560  * Each bit of the 4-bit house code and 5-bit key code
  561  * is transmitted twice, once in true form, and then in
  562  * complemented form.  This is already taken into account
  563  * in the following tables.
  564  */
  565 
  566 #define X10_HOUSE_LENGTH 8
  567 static char X10_HOUSE[16][8] = {
  568         0, 1, 1, 0, 1, 0, 0, 1,         /* A = 0110 */
  569         1, 0, 1, 0, 1, 0, 0, 1,         /* B = 1110 */
  570         0, 1, 0, 1, 1, 0, 0, 1,         /* C = 0010 */
  571         1, 0, 0, 1, 1, 0, 0, 1,         /* D = 1010 */
  572         0, 1, 0, 1, 0, 1, 1, 0,         /* E = 0001 */
  573         1, 0, 0, 1, 0, 1, 1, 0,         /* F = 1001 */
  574         0, 1, 1, 0, 0, 1, 1, 0,         /* G = 0101 */
  575         1, 0, 1, 0, 0, 1, 1, 0,         /* H = 1101 */
  576         0, 1, 1, 0, 1, 0, 1, 0,         /* I = 0111 */
  577         1, 0, 1, 0, 1, 0, 1, 0,         /* J = 1111 */
  578         0, 1, 0, 1, 1, 0, 1, 0,         /* K = 0011 */
  579         1, 0, 0, 1, 1, 0, 1, 0,         /* L = 1011 */
  580         0, 1, 0, 1, 0, 1, 0, 1,         /* M = 0000 */
  581         1, 0, 0, 1, 0, 1, 0, 1,         /* N = 1000 */
  582         0, 1, 1, 0, 0, 1, 0, 1,         /* O = 0100 */
  583         1, 0, 1, 0, 0, 1, 0, 1          /* P = 1100 */
  584 };
  585 
  586 #define X10_KEY_LENGTH 10
  587 static char X10_KEY[32][10] = {
  588         0, 1, 1, 0, 1, 0, 0, 1, 0, 1,   /* 01100 => 1 */
  589         1, 0, 1, 0, 1, 0, 0, 1, 0, 1,   /* 11100 => 2 */
  590         0, 1, 0, 1, 1, 0, 0, 1, 0, 1,   /* 00100 => 3 */
  591         1, 0, 0, 1, 1, 0, 0, 1, 0, 1,   /* 10100 => 4 */
  592         0, 1, 0, 1, 0, 1, 1, 0, 0, 1,   /* 00010 => 5 */
  593         1, 0, 0, 1, 0, 1, 1, 0, 0, 1,   /* 10010 => 6 */
  594         0, 1, 1, 0, 0, 1, 1, 0, 0, 1,   /* 01010 => 7 */
  595         1, 0, 1, 0, 0, 1, 1, 0, 0, 1,   /* 11010 => 8 */
  596         0, 1, 1, 0, 1, 0, 1, 0, 0, 1,   /* 01110 => 9 */
  597         1, 0, 1, 0, 1, 0, 1, 0, 0, 1,   /* 11110 => 10 */
  598         0, 1, 0, 1, 1, 0, 1, 0, 0, 1,   /* 00110 => 11 */
  599         1, 0, 0, 1, 1, 0, 1, 0, 0, 1,   /* 10110 => 12 */
  600         0, 1, 0, 1, 0, 1, 0, 1, 0, 1,   /* 00000 => 13 */
  601         1, 0, 0, 1, 0, 1, 0, 1, 0, 1,   /* 10000 => 14 */
  602         0, 1, 1, 0, 0, 1, 0, 1, 0, 1,   /* 01000 => 15 */
  603         1, 0, 1, 0, 0, 1, 0, 1, 0, 1,   /* 11000 => 16 */
  604         0, 1, 0, 1, 0, 1, 0, 1, 1, 0,   /* 00001 => All Units Off */
  605         0, 1, 0, 1, 0, 1, 1, 0, 1, 0,   /* 00011 => All Units On */
  606         0, 1, 0, 1, 1, 0, 0, 1, 1, 0,   /* 00101 => On */
  607         0, 1, 0, 1, 1, 0, 1, 0, 1, 0,   /* 00111 => Off */
  608         0, 1, 1, 0, 0, 1, 0, 1, 1, 0,   /* 01001 => Dim */
  609         0, 1, 1, 0, 0, 1, 1, 0, 1, 0,   /* 01011 => Bright */
  610         0, 1, 1, 0, 1, 0, 0, 1, 1, 0,   /* 01101 => All LIGHTS Off */
  611         0, 1, 1, 0, 1, 0, 1, 0, 1, 0,   /* 01111 => Extended Code */
  612         1, 0, 0, 1, 0, 1, 0, 1, 1, 0,   /* 10001 => Hail Request */
  613         1, 0, 0, 1, 0, 1, 1, 0, 1, 0,   /* 10011 => Hail Acknowledge */
  614         1, 0, 0, 1, 1, 0, 0, 1, 1, 0,   /* 10101 => Preset Dim 0 */
  615         1, 0, 0, 1, 1, 0, 1, 0, 1, 0,   /* 10111 => Preset Dim 1 */
  616         1, 0, 1, 0, 0, 1, 0, 1, 0, 1,   /* 11000 => Extended Data (analog) */
  617         1, 0, 1, 0, 0, 1, 1, 0, 1, 0,   /* 11011 => Status = on */
  618         1, 0, 1, 0, 1, 0, 0, 1, 1, 0,   /* 11101 => Status = off */
  619         1, 0, 1, 0, 1, 0, 1, 0, 1, 0    /* 11111 => Status request */
  620 };
  621 
  622 /*
  623  * Tables for mapping received X-10 code back to house/key number.
  624  */
  625 
  626 static short X10_HOUSE_INV[16] = {
  627       12,  4,  2, 10, 14,  6,  0,  8,
  628       13,  5,  3, 11, 15,  7,  1,  9
  629 };
  630 
  631 static short X10_KEY_INV[32] = { 
  632       12, 16,  4, 17,  2, 18, 10, 19,
  633       14, 20,  6, 21,  0, 22,  8, 23,
  634       13, 24,  5, 25,  3, 26, 11, 27,
  635       15, 28,  7, 29,  1, 30,  9, 31
  636 };
  637 
  638 static char *X10_KEY_LABEL[32] = {
  639  "1",
  640  "2",
  641  "3",
  642  "4",
  643  "5",
  644  "6",
  645  "7",
  646  "8",
  647  "9",
  648  "10",
  649  "11",
  650  "12",
  651  "13",
  652  "14",
  653  "15",
  654  "16",
  655  "All Units Off",
  656  "All Units On",
  657  "On",
  658  "Off",
  659  "Dim",
  660  "Bright",
  661  "All LIGHTS Off",
  662  "Extended Code",
  663  "Hail Request",
  664  "Hail Acknowledge",
  665  "Preset Dim 0",
  666  "Preset Dim 1",
  667  "Extended Data (analog)",
  668  "Status = on",
  669  "Status = off",
  670  "Status request"
  671 };
  672 /*
  673  * Transmit a packet containing house code h and key code k
  674  */
  675 
  676 #define TWRETRY         10              /* Try 10 times to sync with AC line */
  677 
  678 static int twsend(sc, h, k, cnt)
  679 struct tw_sc *sc;
  680 int h, k, cnt;
  681 {
  682   int i;
  683   int port = sc->sc_port;
  684 
  685   /*
  686    * Make sure we get a reliable sync with a power line zero crossing
  687    */
  688   for(i = 0; i < TWRETRY; i++) {
  689     if(wait_for_zero(sc) > 100) goto insync;
  690   }
  691   log(LOG_ERR, "TWXMIT: failed to sync.\n");
  692   return(-1);
  693 
  694  insync:
  695   /*
  696    * Be sure to leave 3 cycles space between transmissions
  697    */
  698   for(i = 6; i > 0; i--)
  699         if(next_zero(sc) < 0) return(-1);
  700   /*
  701    * The packet is transmitted cnt times, with no gaps.
  702    */
  703   while(cnt--) {
  704     /*
  705      * Transmit the start code
  706      */
  707     for(i = 0; i < X10_START_LENGTH; i++) {
  708       outb(port+tw_data, X10_START[i] ? 0xff : 0x00);  /* Waste no time! */
  709 #ifdef HIRESTIME
  710       if(i == 0) twsetuptimes(sc->sc_xtimes);
  711       if(twchecktime(sc->sc_xtimes[i], HALFCYCLE/20) == 0) {
  712         outb(port+tw_data, 0);
  713         return(-1);
  714       }
  715 #endif /* HIRESTIME */
  716       twdelayn(1000);   /* 1ms pulse width */
  717       outb(port+tw_data, 0);
  718       if(next_zero(sc) < 0) return(-1);
  719     }
  720     /*
  721      * Transmit the house code
  722      */
  723     for(i = 0; i < X10_HOUSE_LENGTH; i++) {
  724       outb(port+tw_data, X10_HOUSE[h][i] ? 0xff : 0x00);  /* Waste no time! */
  725 #ifdef HIRESTIME
  726       if(twchecktime(sc->sc_xtimes[i+X10_START_LENGTH], HALFCYCLE/20) == 0) {
  727         outb(port+tw_data, 0);
  728         return(-1);
  729       }
  730 #endif /* HIRESTIME */
  731       twdelayn(1000);   /* 1ms pulse width */
  732       outb(port+tw_data, 0);
  733       if(next_zero(sc) < 0) return(-1);
  734     }
  735     /*
  736      * Transmit the unit/key code
  737      */
  738     for(i = 0; i < X10_KEY_LENGTH; i++) {
  739       outb(port+tw_data, X10_KEY[k][i] ? 0xff : 0x00);
  740 #ifdef HIRESTIME
  741       if(twchecktime(sc->sc_xtimes[i+X10_START_LENGTH+X10_HOUSE_LENGTH],
  742                         HALFCYCLE/20) == 0) {
  743         outb(port+tw_data, 0);
  744         return(-1);
  745       }
  746 #endif /* HIRESTIME */
  747       twdelayn(1000);   /* 1ms pulse width */
  748       outb(port+tw_data, 0);
  749       if(next_zero(sc) < 0) return(-1);
  750     }
  751   }
  752   return(0);
  753 }
  754 
  755 /*
  756  * Waste CPU cycles to get in sync with a power line zero crossing.
  757  * The value returned is roughly how many microseconds we wasted before
  758  * seeing the transition.  To avoid wasting time forever, we give up after
  759  * waiting patiently for 1/4 sec (15 power line cycles at 60 Hz),
  760  * which is more than the 11 cycles it takes to transmit a full
  761  * X-10 packet.
  762  */
  763 
  764 static int wait_for_zero(sc)
  765 struct tw_sc *sc;
  766 {
  767   int i, old, new, max;
  768   int port = sc->sc_port + tw_zcport;
  769 
  770   old = sc->sc_xphase;
  771   max = 10000;          /* 10000 * 25us = 0.25 sec */
  772   i = 0;
  773   while(max--) {
  774     new = inb(port) & tw_zcmask;
  775     if(new != old) {
  776       sc->sc_xphase = new;
  777       return(i*25);
  778     }
  779     i++;
  780     twdelay25();
  781   }
  782   return(-1);
  783 }
  784 
  785 /*
  786  * Wait for the next zero crossing transition, and if we don't have
  787  * high-resolution time-of-day, check to see that the zero crossing
  788  * appears to be arriving on schedule.
  789  * We expect to be waiting almost a full half-cycle (8.333ms-1ms = 7.333ms).
  790  * If we don't seem to wait very long, something is wrong (like we got
  791  * preempted!) and we should abort the transmission because
  792  * there's no telling how long it's really been since the
  793  * last bit was transmitted.
  794  */
  795 
  796 static int next_zero(sc)
  797 struct tw_sc *sc;
  798 {
  799   int d;
  800 #ifdef HIRESTIME
  801   if((d = wait_for_zero(sc)) < 0) {
  802 #else
  803   if((d = wait_for_zero(sc)) < 6000 || d > 8500) {
  804         /* No less than 6.0ms, no more than 8.5ms */
  805 #endif /* HIRESTIME */
  806     log(LOG_ERR, "TWXMIT framing error: %d\n", d);
  807     return(-1);
  808   }
  809   return(0);
  810 }
  811 
  812 /*
  813  * Put a three-byte packet into the circular buffer
  814  * Should be called at priority spltty()
  815  */
  816 
  817 static int twputpkt(sc, p)
  818 struct tw_sc *sc;
  819 u_char *p;
  820 {
  821   int i, next;
  822 
  823   for(i = 0; i < 3; i++) {
  824     next = sc->sc_nextin+1;
  825     if(next >= TW_SIZE) next = 0;
  826     if(next == sc->sc_nextout) {  /* Buffer full */
  827 /*
  828       log(LOG_ERR, "TWRCV: Buffer overrun\n");
  829  */
  830       return(1);
  831     }
  832     sc->sc_buf[sc->sc_nextin] = *p++;
  833     sc->sc_nextin = next;
  834   }
  835   if(sc->sc_state & TWS_WANT) {
  836     sc->sc_state &= ~TWS_WANT;
  837     wakeup((caddr_t)(&sc->sc_buf));
  838   }
  839   selwakeup(&sc->sc_selp);
  840   return(0);
  841 }
  842 
  843 /*
  844  * Get bytes from the circular buffer
  845  * Should be called at priority spltty()
  846  */
  847 
  848 static int twgetbytes(sc, p, cnt)
  849 struct tw_sc *sc;
  850 u_char *p;
  851 int cnt;
  852 {
  853   int error;
  854 
  855   while(cnt--) {
  856     while(sc->sc_nextin == sc->sc_nextout) {  /* Buffer empty */
  857       sc->sc_state |= TWS_WANT;
  858       if(error = tsleep((caddr_t)(&sc->sc_buf), TWPRI|PCATCH, "twread", 0)) {
  859         return(error);
  860       }
  861     }
  862     *p++ = sc->sc_buf[sc->sc_nextout++];
  863     if(sc->sc_nextout >= TW_SIZE) sc->sc_nextout = 0;
  864   }
  865   return(0);
  866 }
  867 
  868 /*
  869  * Abort reception that has failed to complete in the required time.
  870  */
  871 
  872 static void twabortrcv(sc)
  873 struct tw_sc *sc;
  874 {
  875   int s;
  876   u_char pkt[3];
  877 
  878   s = spltty();
  879   sc->sc_state &= ~TWS_RCVING;
  880   /* simply ignore single isolated interrupts. */
  881   if (sc->sc_no_rcv > 1) {
  882       sc->sc_flags |= TW_RCV_ERROR;
  883       pkt[0] = sc->sc_flags;
  884       pkt[1] = pkt[2] = 0;
  885       twputpkt(sc, pkt);
  886       log(LOG_ERR, "TWRCV: aborting (%x, %d)\n", sc->sc_bits, sc->sc_rcount);
  887       twdebugtimes(sc);
  888   }
  889   wakeup((caddr_t)sc);
  890   splx(s);
  891 }
  892 
  893 static int
  894 tw_is_within(int value, int expected, int tolerance)
  895 {
  896   int diff;
  897   diff = value - expected;
  898   if (diff < 0)
  899     diff *= -1;
  900   if (diff < tolerance)
  901     return 1;
  902   return 0;
  903 }
  904 
  905 /*
  906  * This routine handles interrupts that occur when there is a falling
  907  * transition on the RX input.  There isn't going to be a transition
  908  * on every bit (some are zero), but if we are smart and keep track of
  909  * how long it's been since the last interrupt (via the zero crossing
  910  * detect line and/or high-resolution time-of-day routine), we can
  911  * reconstruct the transmission without having to poll.
  912  */
  913 
  914 void twintr(unit)
  915 int unit;
  916 {
  917   struct tw_sc *sc = &tw_sc[unit];
  918   int port;
  919   int newphase;
  920   u_char pkt[3];
  921   int delay = 0;
  922   struct timeval tv;
  923 
  924   port = sc->sc_port;
  925   /*
  926    * Ignore any interrupts that occur if the device is not open.
  927    */
  928   if(sc->sc_state == 0) return;
  929   newphase = inb(port + tw_zcport) & tw_zcmask;
  930   microtime(&tv);
  931 
  932   /*
  933    * NEW PACKET:
  934    * If we aren't currently receiving a packet, set up a new packet
  935    * and put in the first "1" bit that has just arrived.
  936    * Arrange for the reception to be aborted if too much time goes by.
  937    */
  938   if((sc->sc_state & TWS_RCVING) == 0) {
  939 #ifdef HIRESTIME
  940     twsetuptimes(sc->sc_rtimes);
  941 #endif /* HIRESTIME */
  942     sc->sc_state |= TWS_RCVING;
  943     sc->sc_rcount = 1;
  944     if(sc->sc_state & TWS_XMITTING) sc->sc_flags = TW_RCV_LOCAL;
  945     else sc->sc_flags = 0;
  946     sc->sc_bits = 0;
  947     sc->sc_rphase = newphase;
  948     /* 3 cycles of silence = 3/60 = 1/20 = 50 msec */
  949     timeout((timeout_func_t)twabortrcv, (caddr_t)sc, hz/20);
  950     sc->sc_rcv_time[0] = tv.tv_usec;
  951     sc->sc_no_rcv = 1;
  952     return;
  953   }
  954   untimeout((timeout_func_t)twabortrcv, (caddr_t)sc);
  955   timeout((timeout_func_t)twabortrcv, (caddr_t)sc, hz/20);
  956   newphase = inb(port + tw_zcport) & tw_zcmask;
  957 
  958   /* enforce a minimum delay since the last interrupt */
  959   delay = tv.tv_usec - sc->sc_rcv_time[sc->sc_no_rcv - 1];
  960   if (delay < 0)
  961     delay += 1000000;
  962   if (delay < TW_MIN_DELAY)
  963     return;
  964 
  965   sc->sc_rcv_time[sc->sc_no_rcv] = tv.tv_usec;
  966   if (sc->sc_rcv_time[sc->sc_no_rcv] < sc->sc_rcv_time[0])
  967     sc->sc_rcv_time[sc->sc_no_rcv] += 1000000;
  968   sc->sc_no_rcv++;
  969 
  970   /*
  971    * START CODE:
  972    * The second and third bits are a special case.
  973    */
  974   if (sc->sc_rcount < 3) {
  975     if (
  976 #ifdef HIRESTIME
  977         tw_is_within(delay, HALFCYCLE, HALFCYCLE / 6)
  978 #else
  979         newphase != sc->sc_rphase
  980 #endif
  981         ) {
  982       sc->sc_rcount++;
  983     } else {
  984       /*
  985        * Invalid start code -- abort reception.
  986        */
  987       sc->sc_state &= ~TWS_RCVING;
  988       sc->sc_flags |= TW_RCV_ERROR;
  989       untimeout((timeout_func_t)twabortrcv, (caddr_t)sc);
  990       log(LOG_ERR, "TWRCV: Invalid start code\n");
  991       twdebugtimes(sc);
  992       sc->sc_no_rcv = 0;
  993       return;
  994     }
  995     if(sc->sc_rcount == 3) {
  996       /*
  997        * We've gotten three "1" bits in a row.  The start code
  998        * is really 1110, but this might be followed by a zero
  999        * bit from the house code, so if we wait any longer we
 1000        * might be confused about the first house code bit.
 1001        * So, we guess that the start code is correct and insert
 1002        * the trailing zero without actually having seen it.
 1003        * We don't change sc_rphase in this case, because two
 1004        * bit arrivals in a row preserve parity.
 1005        */
 1006       sc->sc_rcount++;
 1007       return;
 1008     }
 1009     /*
 1010      * Update sc_rphase to the current phase before returning.
 1011      */
 1012     sc->sc_rphase = newphase;
 1013     return;
 1014   }
 1015   /*
 1016    * GENERAL CASE:
 1017    * Now figure out what the current bit is that just arrived.
 1018    * The X-10 protocol transmits each data bit twice: once in
 1019    * true form and once in complemented form on the next half
 1020    * cycle.  So, there will be at least one interrupt per bit.
 1021    * By comparing the phase we see at the time of the interrupt
 1022    * with the saved sc_rphase, we can tell on which half cycle
 1023    * the interrupt occrred.  This assumes, of course, that the
 1024    * packet is well-formed.  We do the best we can at trying to
 1025    * catch errors by aborting if too much time has gone by, and
 1026    * by tossing out a packet if too many bits arrive, but the
 1027    * whole scheme is probably not as robust as if we had a nice
 1028    * interrupt on every half cycle of the power line.
 1029    * If we have high-resolution time-of-day routines, then we
 1030    * can do a bit more sanity checking.
 1031    */
 1032 
 1033   /*
 1034    * A complete packet is 22 half cycles.
 1035    */
 1036   if(sc->sc_rcount <= 20) {
 1037 #ifdef HIRESTIME
 1038     int bit = 0, last_bit;
 1039     if (sc->sc_rcount == 4)
 1040       last_bit = 1;             /* Start (1110) ends in 10, a 'one' code. */
 1041     else
 1042       last_bit = sc->sc_bits & 0x1;
 1043     if (   (   (last_bit == 1)
 1044             && (tw_is_within(delay, HALFCYCLE * 2, HALFCYCLE / 6)))
 1045         || (   (last_bit == 0)
 1046             && (tw_is_within(delay, HALFCYCLE * 1, HALFCYCLE / 6))))
 1047       bit = 1;
 1048     else if (   (   (last_bit == 1)
 1049                  && (tw_is_within(delay, HALFCYCLE * 3, HALFCYCLE / 6)))
 1050              || (   (last_bit == 0)
 1051                  && (tw_is_within(delay, HALFCYCLE * 2, HALFCYCLE / 6))))
 1052       bit = 0;
 1053     else {
 1054       sc->sc_flags |= TW_RCV_ERROR;
 1055       log(LOG_ERR, "TWRCV: %d cycle after %d bit, delay %d%%\n",
 1056           sc->sc_rcount, last_bit, 100 * delay / HALFCYCLE);
 1057     }
 1058     sc->sc_bits = (sc->sc_bits << 1) | bit;
 1059 #else
 1060     sc->sc_bits = (sc->sc_bits << 1)
 1061       | ((newphase == sc->sc_rphase) ? 0x0 : 0x1);
 1062 #endif /* HIRESTIME */
 1063     sc->sc_rcount += 2;
 1064   }
 1065   if(sc->sc_rcount >= 22 || sc->sc_flags & TW_RCV_ERROR) {
 1066     if(sc->sc_rcount != 22) {
 1067       sc->sc_flags |= TW_RCV_ERROR;
 1068       pkt[0] = sc->sc_flags;
 1069       pkt[1] = pkt[2] = 0;
 1070     } else {
 1071       pkt[0] = sc->sc_flags;
 1072       pkt[1] = X10_HOUSE_INV[(sc->sc_bits & 0x1e0) >> 5];
 1073       pkt[2] = X10_KEY_INV[sc->sc_bits & 0x1f];
 1074     }
 1075     sc->sc_state &= ~TWS_RCVING;
 1076     twputpkt(sc, pkt);
 1077     untimeout((timeout_func_t)twabortrcv, (caddr_t)sc);
 1078     if(sc->sc_flags & TW_RCV_ERROR) {
 1079       log(LOG_ERR, "TWRCV: invalid packet: (%d, %x) %c %d\n",
 1080           sc->sc_rcount, sc->sc_bits, 'A' + pkt[1], X10_KEY_LABEL[pkt[2]]);
 1081       twdebugtimes(sc);
 1082     } else {
 1083 /*      log(LOG_ERR, "TWRCV: valid packet: (%d, %x) %c %s\n",
 1084           sc->sc_rcount, sc->sc_bits, 'A' + pkt[1], X10_KEY_LABEL[pkt[2]]); */
 1085     }
 1086     sc->sc_rcount = 0;
 1087     wakeup((caddr_t)sc);
 1088   }
 1089 }
 1090 
 1091 static void twdebugtimes(struct tw_sc *sc)
 1092 {
 1093     int i;
 1094     for (i = 0; (i < sc->sc_no_rcv) && (i < SC_RCV_TIME_LEN); i++)
 1095         log(LOG_ERR, "TWRCV: interrupt %2d: %d\t%d%%\n", i, sc->sc_rcv_time[i],
 1096             (sc->sc_rcv_time[i] - sc->sc_rcv_time[(i?i-1:0)])*100/HALFCYCLE);
 1097 }
 1098 
 1099 #ifdef HIRESTIME
 1100 /*
 1101  * Initialize an array of 22 times, starting from the current
 1102  * microtime and continuing for the next 21 half cycles.
 1103  * We use the times as a reference to make sure transmission
 1104  * or reception is on schedule.
 1105  */
 1106 
 1107 static void twsetuptimes(int *a)
 1108 {
 1109   struct timeval tv;
 1110   int i, t;
 1111 
 1112   microtime(&tv);
 1113   t = tv.tv_usec;
 1114   for(i = 0; i < 22; i++) {
 1115     *a++ = t;
 1116     t += HALFCYCLE;
 1117     if(t >= 1000000) t -= 1000000;
 1118   }
 1119 }
 1120 
 1121 /*
 1122  * Check the current time against a slot in a previously set up
 1123  * timing array, and make sure that it looks like we are still
 1124  * on schedule.
 1125  */
 1126 
 1127 static int twchecktime(int target, int tol)
 1128 {
 1129   struct timeval tv;
 1130   int t, d;
 1131 
 1132   microtime(&tv);
 1133   t = tv.tv_usec;
 1134   d = (target - t) >= 0 ? (target - t) : (t - target);
 1135   if(d > 500000) d = 1000000-d;
 1136   if(d <= tol && d >= -tol) {
 1137     return(1);
 1138   } else {
 1139     return(0);
 1140   }
 1141 }
 1142 #endif /* HIRESTIME */
 1143 
 1144 
 1145 static tw_devsw_installed = 0;
 1146 
 1147 static void     tw_drvinit(void *unused)
 1148 {
 1149         dev_t dev;
 1150 
 1151         if( ! tw_devsw_installed ) {
 1152                 dev = makedev(CDEV_MAJOR, 0);
 1153                 cdevsw_add(&dev,&tw_cdevsw, NULL);
 1154                 tw_devsw_installed = 1;
 1155         }
 1156 }
 1157 
 1158 SYSINIT(twdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,tw_drvinit,NULL)
 1159 
 1160 
 1161 #endif NTW

Cache object: a2a980f6e80ba0ba3023efbf203411bf


[ 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.