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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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  * $FreeBSD: releng/5.0/sys/i386/isa/tw.c 105224 2002-10-16 10:16:17Z phk $
   32  *
   33  */
   34 
   35 #include "tw.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/kernel.h>
  146 #include <sys/conf.h>
  147 #include <sys/uio.h>
  148 #include <sys/syslog.h>
  149 #include <sys/selinfo.h>
  150 #include <sys/poll.h>
  151 #include <sys/bus.h>
  152 #define MIN(a,b)        ((a)<(b)?(a):(b))
  153 
  154 #ifdef HIRESTIME
  155 #include <sys/time.h>
  156 #endif /* HIRESTIME */
  157 
  158 #include <i386/isa/isa_device.h>
  159 
  160 #ifndef COMPAT_OLDISA
  161 #error "The tw device requires the old isa compatibility shims"
  162 #endif
  163 
  164 /*
  165  * Transmission is done by calling write() to send three byte packets of data.
  166  * The first byte contains a four bit house code (0=A to 15=P).
  167  * The second byte contains five bit unit/key code (0=unit 1 to 15=unit 16,
  168  * 16=All Units Off to 31 = Status Request).  The third byte specifies
  169  * the number of times the packet is to be transmitted without any
  170  * gaps between successive transmissions.  Normally this is 2, as per
  171  * the X-10 documentation, but sometimes (e.g. for bright and dim codes)
  172  * it can be another value.  Each call to write can specify an arbitrary
  173  * number of data bytes.  An incomplete packet is buffered until a subsequent
  174  * call to write() provides data to complete it.  At most one packet will
  175  * actually be processed in any call to write().  Successive calls to write()
  176  * leave a three-cycle gap between transmissions, per the X-10 documentation.
  177  *
  178  * Reception is done using read().
  179  * The driver produces a series of three-character packets.
  180  * In each packet, the first character consists of flags,
  181  * the second character is a four bit house code (0-15),
  182  * and the third character is a five bit key/function code (0-31).
  183  * The flags are the following:
  184  */
  185 
  186 #define TW_RCV_LOCAL    1  /* The packet arrived during a local transmission */
  187 #define TW_RCV_ERROR    2  /* An invalid/corrupted packet was received */
  188 
  189 /*
  190  * IBM PC parallel port definitions relevant to TW523
  191  */
  192 
  193 #define tw_data 0                       /* Data to tw523 (R/W) */
  194 
  195 #define tw_status 1                     /* Status of tw523 (R) */
  196 #define TWS_RDATA               0x40    /* tw523 receive data */
  197 #define TWS_OUT                 0x20    /* pin 12, out of paper */
  198 
  199 #define tw_control 2                    /* Control tw523 (R/W) */
  200 #define TWC_SYNC                0x08    /* tw523 sync (pin 17) */
  201 #define TWC_ENA                 0x10    /* tw523 interrupt enable */
  202 
  203 /*
  204  * Miscellaneous defines
  205  */
  206 
  207 #define TWUNIT(dev)     (minor(dev))    /* Extract unit number from device */
  208 #define TWPRI           (PZERO+8)       /* I don't know any better, so let's */
  209                                         /* use the same as the line printer */
  210 
  211 static int twprobe(struct isa_device *idp);
  212 static int twattach(struct isa_device *idp);
  213 
  214 struct isa_driver twdriver = {
  215         INTR_TYPE_TTY,
  216         twprobe,
  217         twattach,
  218         "tw"
  219 };
  220 COMPAT_ISA_DRIVER(tw, twdriver);
  221 
  222 static  d_open_t        twopen;
  223 static  d_close_t       twclose;
  224 static  d_read_t        twread;
  225 static  d_write_t       twwrite;
  226 static  d_poll_t        twpoll;
  227 
  228 #define CDEV_MAJOR 19
  229 static struct cdevsw tw_cdevsw = {
  230         /* open */      twopen,
  231         /* close */     twclose,
  232         /* read */      twread,
  233         /* write */     twwrite,
  234         /* ioctl */     noioctl,
  235         /* poll */      twpoll,
  236         /* mmap */      nommap,
  237         /* strategy */  nostrategy,
  238         /* name */      "tw",
  239         /* maj */       CDEV_MAJOR,
  240         /* dump */      nodump,
  241         /* psize */     nopsize,
  242         /* flags */     0,
  243 };
  244 
  245 /*
  246  * Software control structure for TW523
  247  */
  248 
  249 #define TWS_XMITTING     1      /* Transmission in progress */
  250 #define TWS_RCVING       2      /* Reception in progress */
  251 #define TWS_WANT         4      /* A process wants received data */
  252 #define TWS_OPEN         8      /* Is it currently open? */
  253 
  254 #define TW_SIZE         3*60    /* Enough for about 10 sec. of input */
  255 #define TW_MIN_DELAY    1500    /* Ignore interrupts of lesser latency */
  256 
  257 static struct tw_sc {
  258   u_int sc_port;                /* I/O Port */
  259   u_int sc_state;               /* Current software control state */
  260   struct selinfo sc_selp;       /* Information for select() */
  261   u_char sc_xphase;             /* Current state of sync (for transmitter) */
  262   u_char sc_rphase;             /* Current state of sync (for receiver) */
  263   u_char sc_flags;              /* Flags for current reception */
  264   short sc_rcount;              /* Number of bits received so far */
  265   int sc_bits;                  /* Bits received so far */
  266   u_char sc_pkt[3];             /* Packet not yet transmitted */
  267   short sc_pktsize;             /* How many bytes in the packet? */
  268   u_char sc_buf[TW_SIZE];       /* We buffer our own input */
  269   int sc_nextin;                /* Next free slot in circular buffer */
  270   int sc_nextout;               /* First used slot in circular buffer */
  271                                 /* Callout for canceling our abortrcv timeout */
  272   struct callout_handle abortrcv_ch;
  273 #ifdef HIRESTIME
  274   int sc_xtimes[22];            /* Times for bits in current xmit packet */
  275   int sc_rtimes[22];            /* Times for bits in current rcv packet */
  276   int sc_no_rcv;                /* number of interrupts received */
  277 #define SC_RCV_TIME_LEN 128
  278   int sc_rcv_time[SC_RCV_TIME_LEN]; /* usec time stamp on interrupt */
  279 #endif /* HIRESTIME */
  280 } tw_sc[NTW];
  281 
  282 static int tw_zcport;           /* offset of port for zero crossing signal */
  283 static int tw_zcmask;           /* mask for the zero crossing signal */
  284 
  285 static void twdelay25(void);
  286 static void twdelayn(int n);
  287 static void twsetuptimes(int *a);
  288 static int wait_for_zero(struct tw_sc *sc);
  289 static int twputpkt(struct tw_sc *sc, u_char *p);
  290 static ointhand2_t twintr;
  291 static int twgetbytes(struct tw_sc *sc, u_char *p, int cnt);
  292 static timeout_t twabortrcv;
  293 static int twsend(struct tw_sc *sc, int h, int k, int cnt);
  294 static int next_zero(struct tw_sc *sc);
  295 static int twchecktime(int target, int tol);
  296 static void twdebugtimes(struct tw_sc *sc);
  297 
  298 /*
  299  * Counter value for delay loop.
  300  * It is adjusted by twprobe so that the delay loop takes about 25us.
  301  */
  302 
  303 #define TWDELAYCOUNT 161                /* Works on my 486DX/33 */
  304 static int twdelaycount;
  305 
  306 /*
  307  * Twdelay25 is used for very short delays of about 25us.
  308  * It is implemented with a calibrated delay loop, and should be
  309  * fairly accurate ... unless we are preempted by an interrupt.
  310  *
  311  * We use this to wait for zero crossings because the X-10 specs say we
  312  * are supposed to assert carrier within 25us when one happens.
  313  * I don't really believe we can do this, but the X-10 devices seem to be
  314  * fairly forgiving.
  315  */
  316 
  317 static void twdelay25(void)
  318 {
  319   int cnt;
  320   for(cnt = twdelaycount; cnt; cnt--);  /* Should take about 25us */
  321 }
  322 
  323 /*
  324  * Twdelayn is used to time the length of the 1ms carrier pulse.
  325  * This is not very critical, but if we have high-resolution time-of-day
  326  * we check it every apparent 200us to make sure we don't get too far off
  327  * if we happen to be interrupted during the delay.
  328  */
  329 
  330 static void twdelayn(int n)
  331 {
  332 #ifdef HIRESTIME
  333   int t, d;
  334   struct timeval tv;
  335   microtime(&tv);
  336   t = tv.tv_usec;
  337   t += n;
  338 #endif /* HIRESTIME */
  339   while(n > 0) {
  340     twdelay25();
  341     n -= 25;
  342 #ifdef HIRESTIME
  343     if((n & 0x7) == 0) {
  344       microtime(&tv);
  345       d = tv.tv_usec - t;
  346       if(d >= 0 && d < 1000000) return;
  347     }
  348 #endif /* HIRESTIME */
  349   }
  350 }
  351 
  352 static int twprobe(idp)
  353      struct isa_device *idp;
  354 {
  355   struct tw_sc sc;
  356   int d;
  357   int tries;
  358 
  359   sc.sc_port = idp->id_iobase;
  360   /* Search for the zero crossing signal at ports, bit combinations. */
  361   tw_zcport = tw_control;
  362   tw_zcmask = TWC_SYNC;
  363   sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  364   if(wait_for_zero(&sc) < 0) {
  365     tw_zcport = tw_status;
  366     tw_zcmask = TWS_OUT;
  367     sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  368   }
  369   if(wait_for_zero(&sc) < 0)
  370     return(0);
  371   /*
  372    * Iteratively check the timing of a few sync transitions, and adjust
  373    * the loop delay counter, if necessary, to bring the timing reported
  374    * by wait_for_zero() close to HALFCYCLE.  Give up if anything
  375    * ridiculous happens.
  376    */
  377   if(twdelaycount == 0) {  /* Only adjust timing for first unit */
  378     twdelaycount = TWDELAYCOUNT;
  379     for(tries = 0; tries < 10; tries++) {
  380       sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  381       if(wait_for_zero(&sc) >= 0) {
  382         d = wait_for_zero(&sc);
  383         if(d <= HALFCYCLE/100 || d >= HALFCYCLE*100) {
  384           twdelaycount = 0;
  385           return(0);
  386         }
  387         twdelaycount = (twdelaycount * d)/HALFCYCLE;
  388       }
  389     }
  390   }
  391   /*
  392    * Now do a final check, just to make sure
  393    */
  394   sc.sc_xphase = inb(idp->id_iobase + tw_zcport) & tw_zcmask;
  395   if(wait_for_zero(&sc) >= 0) {
  396     d = wait_for_zero(&sc);
  397     if(d <= (HALFCYCLE * 110)/100 && d >= (HALFCYCLE * 90)/100) return(8);
  398   }
  399   return(0);
  400 }
  401 
  402 static int twattach(idp)
  403         struct isa_device *idp;
  404 {
  405   struct tw_sc *sc;
  406   int   unit;
  407 
  408   idp->id_ointr = twintr;
  409   sc = &tw_sc[unit = idp->id_unit];
  410   sc->sc_port = idp->id_iobase;
  411   sc->sc_state = 0;
  412   sc->sc_rcount = 0;
  413   callout_handle_init(&sc->abortrcv_ch);
  414   make_dev(&tw_cdevsw, unit, 0, 0, 0600, "tw%d", unit);
  415   return (1);
  416 }
  417 
  418 static int
  419 twopen(dev, flag, mode, td)
  420      dev_t dev;
  421      int flag;
  422      int mode;
  423      struct thread *td;
  424 {
  425   struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
  426   int s;
  427 
  428   s = spltty();
  429   if(sc->sc_state == 0) {
  430     sc->sc_state = TWS_OPEN;
  431     sc->sc_nextin = sc->sc_nextout = 0;
  432     sc->sc_pktsize = 0;
  433     outb(sc->sc_port+tw_control, TWC_ENA);
  434   }
  435   splx(s);
  436   return(0);
  437 }
  438 
  439 static int
  440 twclose(dev, flag, mode, td)
  441      dev_t dev;
  442      int flag;
  443      int mode;
  444      struct thread *td;
  445 {
  446   struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
  447   int s;
  448 
  449   s = spltty();
  450   sc->sc_state = 0;
  451   outb(sc->sc_port+tw_control, 0);
  452   splx(s);
  453   return(0);
  454 }
  455 
  456 static int
  457 twread(dev, uio, ioflag)
  458      dev_t dev;
  459      struct uio *uio;
  460      int ioflag;
  461 {
  462   u_char buf[3];
  463   struct tw_sc *sc = &tw_sc[TWUNIT(dev)];
  464   int error, cnt, s;
  465 
  466   s = spltty();
  467   cnt = MIN(uio->uio_resid, 3);
  468   if((error = twgetbytes(sc, buf, cnt)) == 0) {
  469     error = uiomove(buf, cnt, uio);
  470   }
  471   splx(s);
  472   return(error);
  473 }
  474 
  475 static int
  476 twwrite(dev, uio, ioflag)
  477      dev_t dev;
  478      struct uio *uio;
  479      int ioflag;
  480 {
  481   struct tw_sc *sc;
  482   int house, key, reps;
  483   int s, error;
  484   int cnt;
  485 
  486   sc = &tw_sc[TWUNIT(dev)];
  487   /*
  488    * Note: Although I had intended to allow concurrent transmitters,
  489    * there is a potential problem here if two processes both write
  490    * into the sc_pkt buffer at the same time.  The following code
  491    * is an additional critical section that needs to be synchronized.
  492    */
  493   s = spltty();
  494   cnt = MIN(3 - sc->sc_pktsize, uio->uio_resid);
  495   error = uiomove(&(sc->sc_pkt[sc->sc_pktsize]), cnt, uio);
  496   if(error) {
  497     splx(s);
  498     return(error);
  499   }
  500   sc->sc_pktsize += cnt;
  501   if(sc->sc_pktsize < 3) {  /* Only transmit 3-byte packets */
  502     splx(s);
  503     return(0);
  504   }
  505   sc->sc_pktsize = 0;
  506   /*
  507    * Collect house code, key code, and rep count, and check for sanity.
  508    */
  509   house = sc->sc_pkt[0];
  510   key = sc->sc_pkt[1];
  511   reps = sc->sc_pkt[2];
  512   if(house >= 16 || key >= 32) {
  513     splx(s);
  514     return(ENODEV);
  515   }
  516   /*
  517    * Synchronize with the receiver operating in the bottom half, and
  518    * also with concurrent transmitters.
  519    * We don't want to interfere with a packet currently being received,
  520    * and we would like the receiver to recognize when a packet has
  521    * originated locally.
  522    */
  523   while(sc->sc_state & (TWS_RCVING | TWS_XMITTING)) {
  524     error = tsleep((caddr_t)sc, TWPRI|PCATCH, "twwrite", 0);
  525     if(error) {
  526       splx(s);
  527       return(error);
  528     }
  529   }
  530   sc->sc_state |= TWS_XMITTING;
  531   /*
  532    * Everything looks OK, let's do the transmission.
  533    */
  534   splx(s);  /* Enable interrupts because this takes a LONG time */
  535   error = twsend(sc, house, key, reps);
  536   s = spltty();
  537   sc->sc_state &= ~TWS_XMITTING;
  538   wakeup((caddr_t)sc);
  539   splx(s);
  540   if(error) return(EIO);
  541   else return(0);
  542 }
  543 
  544 /*
  545  * Determine if there is data available for reading
  546  */
  547 
  548 static int
  549 twpoll(dev, events, td)
  550      dev_t dev;
  551      int events;
  552      struct thread *td;
  553 {
  554   struct tw_sc *sc;
  555   int s;
  556   int revents = 0;
  557 
  558   sc = &tw_sc[TWUNIT(dev)];
  559   s = spltty();
  560   /* XXX is this correct?  the original code didn't test select rw mode!! */
  561   if (events & (POLLIN | POLLRDNORM)) {
  562     if(sc->sc_nextin != sc->sc_nextout)
  563       revents |= events & (POLLIN | POLLRDNORM);
  564     else
  565       selrecord(td, &sc->sc_selp);
  566   }
  567   splx(s);
  568   return(revents);
  569 }
  570 
  571 /*
  572  * X-10 Protocol
  573  */
  574 
  575 #define X10_START_LENGTH 4
  576 static char X10_START[] = { 1, 1, 1, 0 };
  577 
  578 /*
  579  * Each bit of the 4-bit house code and 5-bit key code
  580  * is transmitted twice, once in true form, and then in
  581  * complemented form.  This is already taken into account
  582  * in the following tables.
  583  */
  584 
  585 #define X10_HOUSE_LENGTH 8
  586 static char X10_HOUSE[16][8] = {
  587         { 0, 1, 1, 0, 1, 0, 0, 1 },             /* A = 0110 */
  588         { 1, 0, 1, 0, 1, 0, 0, 1 },             /* B = 1110 */
  589         { 0, 1, 0, 1, 1, 0, 0, 1 },             /* C = 0010 */
  590         { 1, 0, 0, 1, 1, 0, 0, 1 },             /* D = 1010 */
  591         { 0, 1, 0, 1, 0, 1, 1, 0 },             /* E = 0001 */
  592         { 1, 0, 0, 1, 0, 1, 1, 0 },             /* F = 1001 */
  593         { 0, 1, 1, 0, 0, 1, 1, 0 },             /* G = 0101 */
  594         { 1, 0, 1, 0, 0, 1, 1, 0 },             /* H = 1101 */
  595         { 0, 1, 1, 0, 1, 0, 1, 0 },             /* I = 0111 */
  596         { 1, 0, 1, 0, 1, 0, 1, 0 },             /* J = 1111 */
  597         { 0, 1, 0, 1, 1, 0, 1, 0 },             /* K = 0011 */
  598         { 1, 0, 0, 1, 1, 0, 1, 0 },             /* L = 1011 */
  599         { 0, 1, 0, 1, 0, 1, 0, 1 },             /* M = 0000 */
  600         { 1, 0, 0, 1, 0, 1, 0, 1 },             /* N = 1000 */
  601         { 0, 1, 1, 0, 0, 1, 0, 1 },             /* O = 0100 */
  602         { 1, 0, 1, 0, 0, 1, 0, 1 }              /* P = 1100 */
  603 };
  604 
  605 #define X10_KEY_LENGTH 10
  606 static char X10_KEY[32][10] = {
  607         { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1 },       /* 01100 => 1 */
  608         { 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },       /* 11100 => 2 */
  609         { 0, 1, 0, 1, 1, 0, 0, 1, 0, 1 },       /* 00100 => 3 */
  610         { 1, 0, 0, 1, 1, 0, 0, 1, 0, 1 },       /* 10100 => 4 */
  611         { 0, 1, 0, 1, 0, 1, 1, 0, 0, 1 },       /* 00010 => 5 */
  612         { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1 },       /* 10010 => 6 */
  613         { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1 },       /* 01010 => 7 */
  614         { 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },       /* 11010 => 8 */
  615         { 0, 1, 1, 0, 1, 0, 1, 0, 0, 1 },       /* 01110 => 9 */
  616         { 1, 0, 1, 0, 1, 0, 1, 0, 0, 1 },       /* 11110 => 10 */
  617         { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },       /* 00110 => 11 */
  618         { 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 },       /* 10110 => 12 */
  619         { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },       /* 00000 => 13 */
  620         { 1, 0, 0, 1, 0, 1, 0, 1, 0, 1 },       /* 10000 => 14 */
  621         { 0, 1, 1, 0, 0, 1, 0, 1, 0, 1 },       /* 01000 => 15 */
  622         { 1, 0, 1, 0, 0, 1, 0, 1, 0, 1 },       /* 11000 => 16 */
  623         { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0 },       /* 00001 => All Units Off */
  624         { 0, 1, 0, 1, 0, 1, 1, 0, 1, 0 },       /* 00011 => All Units On */
  625         { 0, 1, 0, 1, 1, 0, 0, 1, 1, 0 },       /* 00101 => On */
  626         { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0 },       /* 00111 => Off */
  627         { 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },       /* 01001 => Dim */
  628         { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0 },       /* 01011 => Bright */
  629         { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0 },       /* 01101 => All LIGHTS Off */
  630         { 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },       /* 01111 => Extended Code */
  631         { 1, 0, 0, 1, 0, 1, 0, 1, 1, 0 },       /* 10001 => Hail Request */
  632         { 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },       /* 10011 => Hail Acknowledge */
  633         { 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },       /* 10101 => Preset Dim 0 */
  634         { 1, 0, 0, 1, 1, 0, 1, 0, 1, 0 },       /* 10111 => Preset Dim 1 */
  635         { 1, 0, 1, 0, 0, 1, 0, 1, 0, 1 },       /* 11000 => Ext Data (analog) */
  636         { 1, 0, 1, 0, 0, 1, 1, 0, 1, 0 },       /* 11011 => Status = on */
  637         { 1, 0, 1, 0, 1, 0, 0, 1, 1, 0 },       /* 11101 => Status = off */
  638         { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 }        /* 11111 => Status request */
  639 };
  640 
  641 /*
  642  * Tables for mapping received X-10 code back to house/key number.
  643  */
  644 
  645 static short X10_HOUSE_INV[16] = {
  646       12,  4,  2, 10, 14,  6,  0,  8,
  647       13,  5,  3, 11, 15,  7,  1,  9
  648 };
  649 
  650 static short X10_KEY_INV[32] = { 
  651       12, 16,  4, 17,  2, 18, 10, 19,
  652       14, 20,  6, 21,  0, 22,  8, 23,
  653       13, 24,  5, 25,  3, 26, 11, 27,
  654       15, 28,  7, 29,  1, 30,  9, 31
  655 };
  656 
  657 static char *X10_KEY_LABEL[32] = {
  658  "1",
  659  "2",
  660  "3",
  661  "4",
  662  "5",
  663  "6",
  664  "7",
  665  "8",
  666  "9",
  667  "10",
  668  "11",
  669  "12",
  670  "13",
  671  "14",
  672  "15",
  673  "16",
  674  "All Units Off",
  675  "All Units On",
  676  "On",
  677  "Off",
  678  "Dim",
  679  "Bright",
  680  "All LIGHTS Off",
  681  "Extended Code",
  682  "Hail Request",
  683  "Hail Acknowledge",
  684  "Preset Dim 0",
  685  "Preset Dim 1",
  686  "Extended Data (analog)",
  687  "Status = on",
  688  "Status = off",
  689  "Status request"
  690 };
  691 /*
  692  * Transmit a packet containing house code h and key code k
  693  */
  694 
  695 #define TWRETRY         10              /* Try 10 times to sync with AC line */
  696 
  697 static int twsend(sc, h, k, cnt)
  698 struct tw_sc *sc;
  699 int h, k, cnt;
  700 {
  701   int i;
  702   int port = sc->sc_port;
  703 
  704   /*
  705    * Make sure we get a reliable sync with a power line zero crossing
  706    */
  707   for(i = 0; i < TWRETRY; i++) {
  708     if(wait_for_zero(sc) > 100) goto insync;
  709   }
  710   log(LOG_ERR, "TWXMIT: failed to sync.\n");
  711   return(-1);
  712 
  713  insync:
  714   /*
  715    * Be sure to leave 3 cycles space between transmissions
  716    */
  717   for(i = 6; i > 0; i--)
  718         if(next_zero(sc) < 0) return(-1);
  719   /*
  720    * The packet is transmitted cnt times, with no gaps.
  721    */
  722   while(cnt--) {
  723     /*
  724      * Transmit the start code
  725      */
  726     for(i = 0; i < X10_START_LENGTH; i++) {
  727       outb(port+tw_data, X10_START[i] ? 0xff : 0x00);  /* Waste no time! */
  728 #ifdef HIRESTIME
  729       if(i == 0) twsetuptimes(sc->sc_xtimes);
  730       if(twchecktime(sc->sc_xtimes[i], HALFCYCLE/20) == 0) {
  731         outb(port+tw_data, 0);
  732         return(-1);
  733       }
  734 #endif /* HIRESTIME */
  735       twdelayn(1000);   /* 1ms pulse width */
  736       outb(port+tw_data, 0);
  737       if(next_zero(sc) < 0) return(-1);
  738     }
  739     /*
  740      * Transmit the house code
  741      */
  742     for(i = 0; i < X10_HOUSE_LENGTH; i++) {
  743       outb(port+tw_data, X10_HOUSE[h][i] ? 0xff : 0x00);  /* Waste no time! */
  744 #ifdef HIRESTIME
  745       if(twchecktime(sc->sc_xtimes[i+X10_START_LENGTH], HALFCYCLE/20) == 0) {
  746         outb(port+tw_data, 0);
  747         return(-1);
  748       }
  749 #endif /* HIRESTIME */
  750       twdelayn(1000);   /* 1ms pulse width */
  751       outb(port+tw_data, 0);
  752       if(next_zero(sc) < 0) return(-1);
  753     }
  754     /*
  755      * Transmit the unit/key code
  756      */
  757     for(i = 0; i < X10_KEY_LENGTH; i++) {
  758       outb(port+tw_data, X10_KEY[k][i] ? 0xff : 0x00);
  759 #ifdef HIRESTIME
  760       if(twchecktime(sc->sc_xtimes[i+X10_START_LENGTH+X10_HOUSE_LENGTH],
  761                         HALFCYCLE/20) == 0) {
  762         outb(port+tw_data, 0);
  763         return(-1);
  764       }
  765 #endif /* HIRESTIME */
  766       twdelayn(1000);   /* 1ms pulse width */
  767       outb(port+tw_data, 0);
  768       if(next_zero(sc) < 0) return(-1);
  769     }
  770   }
  771   return(0);
  772 }
  773 
  774 /*
  775  * Waste CPU cycles to get in sync with a power line zero crossing.
  776  * The value returned is roughly how many microseconds we wasted before
  777  * seeing the transition.  To avoid wasting time forever, we give up after
  778  * waiting patiently for 1/4 sec (15 power line cycles at 60 Hz),
  779  * which is more than the 11 cycles it takes to transmit a full
  780  * X-10 packet.
  781  */
  782 
  783 static int wait_for_zero(sc)
  784 struct tw_sc *sc;
  785 {
  786   int i, old, new, max;
  787   int port = sc->sc_port + tw_zcport;
  788 
  789   old = sc->sc_xphase;
  790   max = 10000;          /* 10000 * 25us = 0.25 sec */
  791   i = 0;
  792   while(max--) {
  793     new = inb(port) & tw_zcmask;
  794     if(new != old) {
  795       sc->sc_xphase = new;
  796       return(i*25);
  797     }
  798     i++;
  799     twdelay25();
  800   }
  801   return(-1);
  802 }
  803 
  804 /*
  805  * Wait for the next zero crossing transition, and if we don't have
  806  * high-resolution time-of-day, check to see that the zero crossing
  807  * appears to be arriving on schedule.
  808  * We expect to be waiting almost a full half-cycle (8.333ms-1ms = 7.333ms).
  809  * If we don't seem to wait very long, something is wrong (like we got
  810  * preempted!) and we should abort the transmission because
  811  * there's no telling how long it's really been since the
  812  * last bit was transmitted.
  813  */
  814 
  815 static int next_zero(sc)
  816 struct tw_sc *sc;
  817 {
  818   int d;
  819 #ifdef HIRESTIME
  820   if((d = wait_for_zero(sc)) < 0) {
  821 #else
  822   if((d = wait_for_zero(sc)) < 6000 || d > 8500) {
  823         /* No less than 6.0ms, no more than 8.5ms */
  824 #endif /* HIRESTIME */
  825     log(LOG_ERR, "TWXMIT framing error: %d\n", d);
  826     return(-1);
  827   }
  828   return(0);
  829 }
  830 
  831 /*
  832  * Put a three-byte packet into the circular buffer
  833  * Should be called at priority spltty()
  834  */
  835 
  836 static int twputpkt(sc, p)
  837 struct tw_sc *sc;
  838 u_char *p;
  839 {
  840   int i, next;
  841 
  842   for(i = 0; i < 3; i++) {
  843     next = sc->sc_nextin+1;
  844     if(next >= TW_SIZE) next = 0;
  845     if(next == sc->sc_nextout) {  /* Buffer full */
  846 /*
  847       log(LOG_ERR, "TWRCV: Buffer overrun\n");
  848  */
  849       return(1);
  850     }
  851     sc->sc_buf[sc->sc_nextin] = *p++;
  852     sc->sc_nextin = next;
  853   }
  854   if(sc->sc_state & TWS_WANT) {
  855     sc->sc_state &= ~TWS_WANT;
  856     wakeup((caddr_t)(&sc->sc_buf));
  857   }
  858   selwakeup(&sc->sc_selp);
  859   return(0);
  860 }
  861 
  862 /*
  863  * Get bytes from the circular buffer
  864  * Should be called at priority spltty()
  865  */
  866 
  867 static int twgetbytes(sc, p, cnt)
  868 struct tw_sc *sc;
  869 u_char *p;
  870 int cnt;
  871 {
  872   int error;
  873 
  874   while(cnt--) {
  875     while(sc->sc_nextin == sc->sc_nextout) {  /* Buffer empty */
  876       sc->sc_state |= TWS_WANT;
  877       error = tsleep((caddr_t)(&sc->sc_buf), TWPRI|PCATCH, "twread", 0);
  878       if(error) {
  879         return(error);
  880       }
  881     }
  882     *p++ = sc->sc_buf[sc->sc_nextout++];
  883     if(sc->sc_nextout >= TW_SIZE) sc->sc_nextout = 0;
  884   }
  885   return(0);
  886 }
  887 
  888 /*
  889  * Abort reception that has failed to complete in the required time.
  890  */
  891 
  892 static void
  893 twabortrcv(arg)
  894         void *arg;
  895 {
  896   struct tw_sc *sc = arg;
  897   int s;
  898   u_char pkt[3];
  899 
  900   s = spltty();
  901   sc->sc_state &= ~TWS_RCVING;
  902   /* simply ignore single isolated interrupts. */
  903   if (sc->sc_no_rcv > 1) {
  904       sc->sc_flags |= TW_RCV_ERROR;
  905       pkt[0] = sc->sc_flags;
  906       pkt[1] = pkt[2] = 0;
  907       twputpkt(sc, pkt);
  908       log(LOG_ERR, "TWRCV: aborting (%x, %d)\n", sc->sc_bits, sc->sc_rcount);
  909       twdebugtimes(sc);
  910   }
  911   wakeup((caddr_t)sc);
  912   splx(s);
  913 }
  914 
  915 static int
  916 tw_is_within(int value, int expected, int tolerance)
  917 {
  918   int diff;
  919   diff = value - expected;
  920   if (diff < 0)
  921     diff *= -1;
  922   if (diff < tolerance)
  923     return 1;
  924   return 0;
  925 }
  926 
  927 /*
  928  * This routine handles interrupts that occur when there is a falling
  929  * transition on the RX input.  There isn't going to be a transition
  930  * on every bit (some are zero), but if we are smart and keep track of
  931  * how long it's been since the last interrupt (via the zero crossing
  932  * detect line and/or high-resolution time-of-day routine), we can
  933  * reconstruct the transmission without having to poll.
  934  */
  935 
  936 static void twintr(unit)
  937 int unit;
  938 {
  939   struct tw_sc *sc = &tw_sc[unit];
  940   int port;
  941   int newphase;
  942   u_char pkt[3];
  943   int delay = 0;
  944   struct timeval tv;
  945 
  946   port = sc->sc_port;
  947   /*
  948    * Ignore any interrupts that occur if the device is not open.
  949    */
  950   if(sc->sc_state == 0) return;
  951   newphase = inb(port + tw_zcport) & tw_zcmask;
  952   microtime(&tv);
  953 
  954   /*
  955    * NEW PACKET:
  956    * If we aren't currently receiving a packet, set up a new packet
  957    * and put in the first "1" bit that has just arrived.
  958    * Arrange for the reception to be aborted if too much time goes by.
  959    */
  960   if((sc->sc_state & TWS_RCVING) == 0) {
  961 #ifdef HIRESTIME
  962     twsetuptimes(sc->sc_rtimes);
  963 #endif /* HIRESTIME */
  964     sc->sc_state |= TWS_RCVING;
  965     sc->sc_rcount = 1;
  966     if(sc->sc_state & TWS_XMITTING) sc->sc_flags = TW_RCV_LOCAL;
  967     else sc->sc_flags = 0;
  968     sc->sc_bits = 0;
  969     sc->sc_rphase = newphase;
  970     /* 3 cycles of silence = 3/60 = 1/20 = 50 msec */
  971     sc->abortrcv_ch = timeout(twabortrcv, (caddr_t)sc, hz/20);
  972     sc->sc_rcv_time[0] = tv.tv_usec;
  973     sc->sc_no_rcv = 1;
  974     return;
  975   }
  976   untimeout(twabortrcv, (caddr_t)sc, sc->abortrcv_ch);
  977   sc->abortrcv_ch = timeout(twabortrcv, (caddr_t)sc, hz/20);
  978   newphase = inb(port + tw_zcport) & tw_zcmask;
  979 
  980   /* enforce a minimum delay since the last interrupt */
  981   delay = tv.tv_usec - sc->sc_rcv_time[sc->sc_no_rcv - 1];
  982   if (delay < 0)
  983     delay += 1000000;
  984   if (delay < TW_MIN_DELAY)
  985     return;
  986 
  987   sc->sc_rcv_time[sc->sc_no_rcv] = tv.tv_usec;
  988   if (sc->sc_rcv_time[sc->sc_no_rcv] < sc->sc_rcv_time[0])
  989     sc->sc_rcv_time[sc->sc_no_rcv] += 1000000;
  990   sc->sc_no_rcv++;
  991 
  992   /*
  993    * START CODE:
  994    * The second and third bits are a special case.
  995    */
  996   if (sc->sc_rcount < 3) {
  997     if (
  998 #ifdef HIRESTIME
  999         tw_is_within(delay, HALFCYCLE, HALFCYCLE / 6)
 1000 #else
 1001         newphase != sc->sc_rphase
 1002 #endif
 1003         ) {
 1004       sc->sc_rcount++;
 1005     } else {
 1006       /*
 1007        * Invalid start code -- abort reception.
 1008        */
 1009       sc->sc_state &= ~TWS_RCVING;
 1010       sc->sc_flags |= TW_RCV_ERROR;
 1011       untimeout(twabortrcv, (caddr_t)sc, sc->abortrcv_ch);
 1012       log(LOG_ERR, "TWRCV: Invalid start code\n");
 1013       twdebugtimes(sc);
 1014       sc->sc_no_rcv = 0;
 1015       return;
 1016     }
 1017     if(sc->sc_rcount == 3) {
 1018       /*
 1019        * We've gotten three "1" bits in a row.  The start code
 1020        * is really 1110, but this might be followed by a zero
 1021        * bit from the house code, so if we wait any longer we
 1022        * might be confused about the first house code bit.
 1023        * So, we guess that the start code is correct and insert
 1024        * the trailing zero without actually having seen it.
 1025        * We don't change sc_rphase in this case, because two
 1026        * bit arrivals in a row preserve parity.
 1027        */
 1028       sc->sc_rcount++;
 1029       return;
 1030     }
 1031     /*
 1032      * Update sc_rphase to the current phase before returning.
 1033      */
 1034     sc->sc_rphase = newphase;
 1035     return;
 1036   }
 1037   /*
 1038    * GENERAL CASE:
 1039    * Now figure out what the current bit is that just arrived.
 1040    * The X-10 protocol transmits each data bit twice: once in
 1041    * true form and once in complemented form on the next half
 1042    * cycle.  So, there will be at least one interrupt per bit.
 1043    * By comparing the phase we see at the time of the interrupt
 1044    * with the saved sc_rphase, we can tell on which half cycle
 1045    * the interrupt occrred.  This assumes, of course, that the
 1046    * packet is well-formed.  We do the best we can at trying to
 1047    * catch errors by aborting if too much time has gone by, and
 1048    * by tossing out a packet if too many bits arrive, but the
 1049    * whole scheme is probably not as robust as if we had a nice
 1050    * interrupt on every half cycle of the power line.
 1051    * If we have high-resolution time-of-day routines, then we
 1052    * can do a bit more sanity checking.
 1053    */
 1054 
 1055   /*
 1056    * A complete packet is 22 half cycles.
 1057    */
 1058   if(sc->sc_rcount <= 20) {
 1059 #ifdef HIRESTIME
 1060     int bit = 0, last_bit;
 1061     if (sc->sc_rcount == 4)
 1062       last_bit = 1;             /* Start (1110) ends in 10, a 'one' code. */
 1063     else
 1064       last_bit = sc->sc_bits & 0x1;
 1065     if (   (   (last_bit == 1)
 1066             && (tw_is_within(delay, HALFCYCLE * 2, HALFCYCLE / 6)))
 1067         || (   (last_bit == 0)
 1068             && (tw_is_within(delay, HALFCYCLE * 1, HALFCYCLE / 6))))
 1069       bit = 1;
 1070     else if (   (   (last_bit == 1)
 1071                  && (tw_is_within(delay, HALFCYCLE * 3, HALFCYCLE / 6)))
 1072              || (   (last_bit == 0)
 1073                  && (tw_is_within(delay, HALFCYCLE * 2, HALFCYCLE / 6))))
 1074       bit = 0;
 1075     else {
 1076       sc->sc_flags |= TW_RCV_ERROR;
 1077       log(LOG_ERR, "TWRCV: %d cycle after %d bit, delay %d%%\n",
 1078           sc->sc_rcount, last_bit, 100 * delay / HALFCYCLE);
 1079     }
 1080     sc->sc_bits = (sc->sc_bits << 1) | bit;
 1081 #else
 1082     sc->sc_bits = (sc->sc_bits << 1)
 1083       | ((newphase == sc->sc_rphase) ? 0x0 : 0x1);
 1084 #endif /* HIRESTIME */
 1085     sc->sc_rcount += 2;
 1086   }
 1087   if(sc->sc_rcount >= 22 || sc->sc_flags & TW_RCV_ERROR) {
 1088     if(sc->sc_rcount != 22) {
 1089       sc->sc_flags |= TW_RCV_ERROR;
 1090       pkt[0] = sc->sc_flags;
 1091       pkt[1] = pkt[2] = 0;
 1092     } else {
 1093       pkt[0] = sc->sc_flags;
 1094       pkt[1] = X10_HOUSE_INV[(sc->sc_bits & 0x1e0) >> 5];
 1095       pkt[2] = X10_KEY_INV[sc->sc_bits & 0x1f];
 1096     }
 1097     sc->sc_state &= ~TWS_RCVING;
 1098     twputpkt(sc, pkt);
 1099     untimeout(twabortrcv, (caddr_t)sc, sc->abortrcv_ch);
 1100     if(sc->sc_flags & TW_RCV_ERROR) {
 1101       log(LOG_ERR, "TWRCV: invalid packet: (%d, %x) %c %s\n",
 1102           sc->sc_rcount, sc->sc_bits, 'A' + pkt[1], X10_KEY_LABEL[pkt[2]]);
 1103       twdebugtimes(sc);
 1104     } else {
 1105 /*      log(LOG_ERR, "TWRCV: valid packet: (%d, %x) %c %s\n",
 1106           sc->sc_rcount, sc->sc_bits, 'A' + pkt[1], X10_KEY_LABEL[pkt[2]]); */
 1107     }
 1108     sc->sc_rcount = 0;
 1109     wakeup((caddr_t)sc);
 1110   }
 1111 }
 1112 
 1113 static void twdebugtimes(struct tw_sc *sc)
 1114 {
 1115     int i;
 1116     for (i = 0; (i < sc->sc_no_rcv) && (i < SC_RCV_TIME_LEN); i++)
 1117         log(LOG_ERR, "TWRCV: interrupt %2d: %d\t%d%%\n", i, sc->sc_rcv_time[i],
 1118             (sc->sc_rcv_time[i] - sc->sc_rcv_time[(i?i-1:0)])*100/HALFCYCLE);
 1119 }
 1120 
 1121 #ifdef HIRESTIME
 1122 /*
 1123  * Initialize an array of 22 times, starting from the current
 1124  * microtime and continuing for the next 21 half cycles.
 1125  * We use the times as a reference to make sure transmission
 1126  * or reception is on schedule.
 1127  */
 1128 
 1129 static void twsetuptimes(int *a)
 1130 {
 1131   struct timeval tv;
 1132   int i, t;
 1133 
 1134   microtime(&tv);
 1135   t = tv.tv_usec;
 1136   for(i = 0; i < 22; i++) {
 1137     *a++ = t;
 1138     t += HALFCYCLE;
 1139     if(t >= 1000000) t -= 1000000;
 1140   }
 1141 }
 1142 
 1143 /*
 1144  * Check the current time against a slot in a previously set up
 1145  * timing array, and make sure that it looks like we are still
 1146  * on schedule.
 1147  */
 1148 
 1149 static int twchecktime(int target, int tol)
 1150 {
 1151   struct timeval tv;
 1152   int t, d;
 1153 
 1154   microtime(&tv);
 1155   t = tv.tv_usec;
 1156   d = (target - t) >= 0 ? (target - t) : (t - target);
 1157   if(d > 500000) d = 1000000-d;
 1158   if(d <= tol && d >= -tol) {
 1159     return(1);
 1160   } else {
 1161     return(0);
 1162   }
 1163 }
 1164 #endif /* HIRESTIME */

Cache object: ecec65b4dfbae41c4a41bbb27d3ec578


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