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

Cache object: b55c1b54317a844759a176b42519d2f7


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