Home | History | Annotate | Line # | Download | only in ir
      1 /*	$NetBSD: sir.c,v 1.6 2013/05/27 16:23:20 kiyohara Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Lennart Augustsson (lennart (at) augustsson.net) and Tommy Bohlin
      9  * (tommy (at) gatespace.com).
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Framing originally written by Tommy Bohlin.
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: sir.c,v 1.6 2013/05/27 16:23:20 kiyohara Exp $");
     39 
     40 #include <sys/param.h>
     41 #include <sys/conf.h>
     42 #include <sys/systm.h>
     43 
     44 #include <dev/ir/sir.h>
     45 
     46 /*
     47  * CRC computation table
     48  */
     49 const uint16_t irda_fcstab[] = {
     50 	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
     51 	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
     52 	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
     53 	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
     54 	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
     55 	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
     56 	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
     57 	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
     58 	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
     59 	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
     60 	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
     61 	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
     62 	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
     63 	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
     64 	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
     65 	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
     66 	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
     67 	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
     68 	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
     69 	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
     70 	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
     71 	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
     72 	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
     73 	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
     74 	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
     75 	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
     76 	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
     77 	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
     78 	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
     79 	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
     80 	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
     81 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
     82 };
     83 
     84 #define MAX_IRDA_FRAME 5000	/* XXX what is it? */
     85 
     86 #define PUTC(c) if (p < end) *p++ = (c)
     87 #define PUTESC(c) \
     88 	if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) { \
     89 		PUTC(SIR_CE); \
     90 		PUTC(SIR_ESC_BIT^c); \
     91 	} else { \
     92 		PUTC(c); \
     93 	}
     94 
     95 #define CHUNK 512
     96 
     97 int
     98 irda_sir_frame(uint8_t *obuf, u_int maxlen, struct uio *uio, u_int ebofs)
     99 {
    100 	uint8_t ibuf[CHUNK];
    101 	uint8_t *p, *end, *cp;
    102 	size_t n;
    103 	int error;
    104 	int i;
    105 	int c;
    106 	uint16_t ofcs;
    107 
    108 	p = obuf;
    109 	end = p + maxlen;
    110 
    111 	for (i = 0; i < ebofs; i++)
    112 		PUTC(SIR_EXTRA_BOF);
    113 	PUTC(SIR_BOF);
    114 
    115 	ofcs = INITFCS;
    116 	while (uio->uio_resid > 0) {
    117 		n = uio->uio_resid;
    118 		if (n > CHUNK)
    119 			n = CHUNK;
    120 		error = uiomove(ibuf, n, uio);
    121 		if (error)
    122 			return (-error);
    123 
    124 		cp = ibuf;
    125 		while (n-- > 0) {
    126 			c = *cp++;
    127 			ofcs = updateFCS(ofcs, c);
    128 			PUTESC(c);
    129 		}
    130 	}
    131 
    132 	ofcs = ~ofcs;
    133 	c = ofcs & 0xff;
    134 	PUTESC(c);
    135 	c = (ofcs >> 8) & 0xff;
    136 	PUTESC(c);
    137 	PUTC(SIR_EOF);
    138 
    139 	if (p < end)
    140 		return (p - obuf);
    141 	else
    142 		return (-EINVAL);
    143 }
    144 
    145 void
    146 deframe_init(struct framestate *fstate, uint8_t *buf, size_t buflen)
    147 {
    148 
    149 	fstate->buffer = buf;
    150 	fstate->buflen = buflen;
    151 
    152 	deframe_clear(fstate);
    153 }
    154 
    155 void
    156 deframe_clear(struct framestate *fstate)
    157 {
    158 
    159 	fstate->bufindex = 0;
    160 	fstate->fsmstate = FSTATE_END_OF_FRAME;
    161 	fstate->escaped = 0;
    162 }
    163 
    164 enum frameresult
    165 deframe_process(struct framestate *fstate, uint8_t const **bptr, size_t *blen)
    166 {
    167 	uint8_t const *cptr;
    168 	size_t ibuflen, obufindex, obuflen;
    169 	enum framefsmstate fsmstate;
    170 	enum frameresult result;
    171 
    172 	cptr = *bptr;
    173 	fsmstate = fstate->fsmstate;
    174 	obufindex = fstate->bufindex;
    175 	obuflen = fstate->buflen;
    176 	ibuflen = *blen;
    177 
    178 	while (ibuflen-- > 0) {
    179 		uint8_t chr;
    180 
    181 		chr = *cptr++;
    182 
    183 		if (fstate->escaped) {
    184 			fstate->escaped = 0;
    185 			chr ^= SIR_ESC_BIT;
    186 		} else if (chr == SIR_CE) {
    187 			fstate->escaped = 1;
    188 			continue;
    189 		}
    190 
    191 		switch (fsmstate) {
    192 		case FSTATE_IN_DATA:
    193 			if (chr == SIR_EOF) {
    194 				fsmstate = FSTATE_IN_END;
    195 				fstate->state_index = 1;
    196 				goto state_in_end;
    197 			}
    198 			if (obufindex >= obuflen) {
    199 				result = FR_BUFFEROVERRUN;
    200 				fsmstate = FSTATE_END_OF_FRAME;
    201 				goto complete;
    202 			}
    203 			fstate->buffer[obufindex++] = chr;
    204 			break;
    205 
    206 		state_in_end:
    207 			/* FALLTHROUGH */
    208 
    209 		case FSTATE_IN_END:
    210 			if (--fstate->state_index == 0) {
    211 				uint32_t crc;
    212 				const size_t fcslen = 2;
    213 
    214 				fsmstate = FSTATE_END_OF_FRAME;
    215 
    216 				if (obufindex < fcslen) {
    217 					result = FR_FRAMEMALFORMED;
    218 					goto complete;
    219 				}
    220 
    221 				crc = crc_ccitt_16(INITFCS, fstate->buffer,
    222 				    obufindex);
    223 
    224 				/* Remove check bytes from buffer length */
    225 				obufindex -= fcslen;
    226 
    227 				if (crc == GOODFCS)
    228 					result = FR_FRAMEOK;
    229 				else
    230 					result = FR_FRAMEBADFCS;
    231 
    232 				goto complete;
    233 			}
    234 			break;
    235 
    236 		case FSTATE_END_OF_FRAME:
    237 			if (chr != SIR_BOF)
    238 				break;
    239 
    240 			fsmstate = FSTATE_START_OF_FRAME;
    241 			fstate->state_index = 1;
    242 			/* FALLTHROUGH */
    243 		case FSTATE_START_OF_FRAME:
    244 			if (--fstate->state_index == 0) {
    245 				fsmstate = FSTATE_IN_DATA;
    246 				obufindex = 0;
    247 			}
    248 			break;
    249 		}
    250 	}
    251 
    252 	result = (fsmstate == FSTATE_END_OF_FRAME) ? FR_IDLE : FR_INPROGRESS;
    253 
    254  complete:
    255 	fstate->bufindex = obufindex;
    256 	fstate->fsmstate = fsmstate;
    257 	*blen = ibuflen;
    258 
    259 	return result;
    260 }
    261 
    262 uint32_t
    263 crc_ccitt_16(uint32_t crcinit, uint8_t const *buf, size_t blen)
    264 {
    265 
    266 	while (blen-- > 0) {
    267 		uint8_t chr;
    268 		chr = *buf++;
    269 		crcinit = updateFCS(crcinit, chr);
    270 	}
    271 	return crcinit;
    272 }
    273