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