xref: /openbmc/linux/lib/842/842_decompress.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22da572c9SDan Streetman /*
32da572c9SDan Streetman  * 842 Software Decompression
42da572c9SDan Streetman  *
52da572c9SDan Streetman  * Copyright (C) 2015 Dan Streetman, IBM Corp
62da572c9SDan Streetman  *
72da572c9SDan Streetman  * See 842.h for details of the 842 compressed format.
82da572c9SDan Streetman  */
92da572c9SDan Streetman 
102da572c9SDan Streetman #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
112da572c9SDan Streetman #define MODULE_NAME "842_decompress"
122da572c9SDan Streetman 
132da572c9SDan Streetman #include "842.h"
142da572c9SDan Streetman #include "842_debugfs.h"
152da572c9SDan Streetman 
162da572c9SDan Streetman /* rolling fifo sizes */
172da572c9SDan Streetman #define I2_FIFO_SIZE	(2 * (1 << I2_BITS))
182da572c9SDan Streetman #define I4_FIFO_SIZE	(4 * (1 << I4_BITS))
192da572c9SDan Streetman #define I8_FIFO_SIZE	(8 * (1 << I8_BITS))
202da572c9SDan Streetman 
212da572c9SDan Streetman static u8 decomp_ops[OPS_MAX][4] = {
222da572c9SDan Streetman 	{ D8, N0, N0, N0 },
232da572c9SDan Streetman 	{ D4, D2, I2, N0 },
242da572c9SDan Streetman 	{ D4, I2, D2, N0 },
252da572c9SDan Streetman 	{ D4, I2, I2, N0 },
262da572c9SDan Streetman 	{ D4, I4, N0, N0 },
272da572c9SDan Streetman 	{ D2, I2, D4, N0 },
282da572c9SDan Streetman 	{ D2, I2, D2, I2 },
292da572c9SDan Streetman 	{ D2, I2, I2, D2 },
302da572c9SDan Streetman 	{ D2, I2, I2, I2 },
312da572c9SDan Streetman 	{ D2, I2, I4, N0 },
322da572c9SDan Streetman 	{ I2, D2, D4, N0 },
332da572c9SDan Streetman 	{ I2, D4, I2, N0 },
342da572c9SDan Streetman 	{ I2, D2, I2, D2 },
352da572c9SDan Streetman 	{ I2, D2, I2, I2 },
362da572c9SDan Streetman 	{ I2, D2, I4, N0 },
372da572c9SDan Streetman 	{ I2, I2, D4, N0 },
382da572c9SDan Streetman 	{ I2, I2, D2, I2 },
392da572c9SDan Streetman 	{ I2, I2, I2, D2 },
402da572c9SDan Streetman 	{ I2, I2, I2, I2 },
412da572c9SDan Streetman 	{ I2, I2, I4, N0 },
422da572c9SDan Streetman 	{ I4, D4, N0, N0 },
432da572c9SDan Streetman 	{ I4, D2, I2, N0 },
442da572c9SDan Streetman 	{ I4, I2, D2, N0 },
452da572c9SDan Streetman 	{ I4, I2, I2, N0 },
462da572c9SDan Streetman 	{ I4, I4, N0, N0 },
472da572c9SDan Streetman 	{ I8, N0, N0, N0 }
482da572c9SDan Streetman };
492da572c9SDan Streetman 
502da572c9SDan Streetman struct sw842_param {
512da572c9SDan Streetman 	u8 *in;
522da572c9SDan Streetman 	u8 bit;
532da572c9SDan Streetman 	u64 ilen;
542da572c9SDan Streetman 	u8 *out;
552da572c9SDan Streetman 	u8 *ostart;
562da572c9SDan Streetman 	u64 olen;
572da572c9SDan Streetman };
582da572c9SDan Streetman 
592da572c9SDan Streetman #define beN_to_cpu(d, s)					\
602da572c9SDan Streetman 	((s) == 2 ? be16_to_cpu(get_unaligned((__be16 *)d)) :	\
612da572c9SDan Streetman 	 (s) == 4 ? be32_to_cpu(get_unaligned((__be32 *)d)) :	\
622da572c9SDan Streetman 	 (s) == 8 ? be64_to_cpu(get_unaligned((__be64 *)d)) :	\
635ca636b9SDan Streetman 	 0)
642da572c9SDan Streetman 
652da572c9SDan Streetman static int next_bits(struct sw842_param *p, u64 *d, u8 n);
662da572c9SDan Streetman 
__split_next_bits(struct sw842_param * p,u64 * d,u8 n,u8 s)672da572c9SDan Streetman static int __split_next_bits(struct sw842_param *p, u64 *d, u8 n, u8 s)
682da572c9SDan Streetman {
692da572c9SDan Streetman 	u64 tmp = 0;
702da572c9SDan Streetman 	int ret;
712da572c9SDan Streetman 
722da572c9SDan Streetman 	if (n <= s) {
732da572c9SDan Streetman 		pr_debug("split_next_bits invalid n %u s %u\n", n, s);
742da572c9SDan Streetman 		return -EINVAL;
752da572c9SDan Streetman 	}
762da572c9SDan Streetman 
772da572c9SDan Streetman 	ret = next_bits(p, &tmp, n - s);
782da572c9SDan Streetman 	if (ret)
792da572c9SDan Streetman 		return ret;
802da572c9SDan Streetman 	ret = next_bits(p, d, s);
812da572c9SDan Streetman 	if (ret)
822da572c9SDan Streetman 		return ret;
832da572c9SDan Streetman 	*d |= tmp << s;
842da572c9SDan Streetman 	return 0;
852da572c9SDan Streetman }
862da572c9SDan Streetman 
next_bits(struct sw842_param * p,u64 * d,u8 n)872da572c9SDan Streetman static int next_bits(struct sw842_param *p, u64 *d, u8 n)
882da572c9SDan Streetman {
892da572c9SDan Streetman 	u8 *in = p->in, b = p->bit, bits = b + n;
902da572c9SDan Streetman 
912da572c9SDan Streetman 	if (n > 64) {
922da572c9SDan Streetman 		pr_debug("next_bits invalid n %u\n", n);
932da572c9SDan Streetman 		return -EINVAL;
942da572c9SDan Streetman 	}
952da572c9SDan Streetman 
962da572c9SDan Streetman 	/* split this up if reading > 8 bytes, or if we're at the end of
972da572c9SDan Streetman 	 * the input buffer and would read past the end
982da572c9SDan Streetman 	 */
992da572c9SDan Streetman 	if (bits > 64)
1002da572c9SDan Streetman 		return __split_next_bits(p, d, n, 32);
1012da572c9SDan Streetman 	else if (p->ilen < 8 && bits > 32 && bits <= 56)
1022da572c9SDan Streetman 		return __split_next_bits(p, d, n, 16);
1032da572c9SDan Streetman 	else if (p->ilen < 4 && bits > 16 && bits <= 24)
1042da572c9SDan Streetman 		return __split_next_bits(p, d, n, 8);
1052da572c9SDan Streetman 
1062da572c9SDan Streetman 	if (DIV_ROUND_UP(bits, 8) > p->ilen)
1072da572c9SDan Streetman 		return -EOVERFLOW;
1082da572c9SDan Streetman 
1092da572c9SDan Streetman 	if (bits <= 8)
1102da572c9SDan Streetman 		*d = *in >> (8 - bits);
1112da572c9SDan Streetman 	else if (bits <= 16)
1122da572c9SDan Streetman 		*d = be16_to_cpu(get_unaligned((__be16 *)in)) >> (16 - bits);
1132da572c9SDan Streetman 	else if (bits <= 32)
1142da572c9SDan Streetman 		*d = be32_to_cpu(get_unaligned((__be32 *)in)) >> (32 - bits);
1152da572c9SDan Streetman 	else
1162da572c9SDan Streetman 		*d = be64_to_cpu(get_unaligned((__be64 *)in)) >> (64 - bits);
1172da572c9SDan Streetman 
1182da572c9SDan Streetman 	*d &= GENMASK_ULL(n - 1, 0);
1192da572c9SDan Streetman 
1202da572c9SDan Streetman 	p->bit += n;
1212da572c9SDan Streetman 
1222da572c9SDan Streetman 	if (p->bit > 7) {
1232da572c9SDan Streetman 		p->in += p->bit / 8;
1242da572c9SDan Streetman 		p->ilen -= p->bit / 8;
1252da572c9SDan Streetman 		p->bit %= 8;
1262da572c9SDan Streetman 	}
1272da572c9SDan Streetman 
1282da572c9SDan Streetman 	return 0;
1292da572c9SDan Streetman }
1302da572c9SDan Streetman 
do_data(struct sw842_param * p,u8 n)1312da572c9SDan Streetman static int do_data(struct sw842_param *p, u8 n)
1322da572c9SDan Streetman {
1332da572c9SDan Streetman 	u64 v;
1342da572c9SDan Streetman 	int ret;
1352da572c9SDan Streetman 
1362da572c9SDan Streetman 	if (n > p->olen)
1372da572c9SDan Streetman 		return -ENOSPC;
1382da572c9SDan Streetman 
1392da572c9SDan Streetman 	ret = next_bits(p, &v, n * 8);
1402da572c9SDan Streetman 	if (ret)
1412da572c9SDan Streetman 		return ret;
1422da572c9SDan Streetman 
1432da572c9SDan Streetman 	switch (n) {
1442da572c9SDan Streetman 	case 2:
1452da572c9SDan Streetman 		put_unaligned(cpu_to_be16((u16)v), (__be16 *)p->out);
1462da572c9SDan Streetman 		break;
1472da572c9SDan Streetman 	case 4:
1482da572c9SDan Streetman 		put_unaligned(cpu_to_be32((u32)v), (__be32 *)p->out);
1492da572c9SDan Streetman 		break;
1502da572c9SDan Streetman 	case 8:
1512da572c9SDan Streetman 		put_unaligned(cpu_to_be64((u64)v), (__be64 *)p->out);
1522da572c9SDan Streetman 		break;
1532da572c9SDan Streetman 	default:
1542da572c9SDan Streetman 		return -EINVAL;
1552da572c9SDan Streetman 	}
1562da572c9SDan Streetman 
1572da572c9SDan Streetman 	p->out += n;
1582da572c9SDan Streetman 	p->olen -= n;
1592da572c9SDan Streetman 
1602da572c9SDan Streetman 	return 0;
1612da572c9SDan Streetman }
1622da572c9SDan Streetman 
__do_index(struct sw842_param * p,u8 size,u8 bits,u64 fsize)1632da572c9SDan Streetman static int __do_index(struct sw842_param *p, u8 size, u8 bits, u64 fsize)
1642da572c9SDan Streetman {
1652da572c9SDan Streetman 	u64 index, offset, total = round_down(p->out - p->ostart, 8);
1662da572c9SDan Streetman 	int ret;
1672da572c9SDan Streetman 
1682da572c9SDan Streetman 	ret = next_bits(p, &index, bits);
1692da572c9SDan Streetman 	if (ret)
1702da572c9SDan Streetman 		return ret;
1712da572c9SDan Streetman 
1722da572c9SDan Streetman 	offset = index * size;
1732da572c9SDan Streetman 
1742da572c9SDan Streetman 	/* a ring buffer of fsize is used; correct the offset */
1752da572c9SDan Streetman 	if (total > fsize) {
1762da572c9SDan Streetman 		/* this is where the current fifo is */
1772da572c9SDan Streetman 		u64 section = round_down(total, fsize);
1782da572c9SDan Streetman 		/* the current pos in the fifo */
179ca7fc7e9SDan Streetman 		u64 pos = total - section;
1802da572c9SDan Streetman 
1812da572c9SDan Streetman 		/* if the offset is past/at the pos, we need to
1822da572c9SDan Streetman 		 * go back to the last fifo section
1832da572c9SDan Streetman 		 */
1842da572c9SDan Streetman 		if (offset >= pos)
1852da572c9SDan Streetman 			section -= fsize;
1862da572c9SDan Streetman 
1872da572c9SDan Streetman 		offset += section;
1882da572c9SDan Streetman 	}
1892da572c9SDan Streetman 
1902da572c9SDan Streetman 	if (offset + size > total) {
1912da572c9SDan Streetman 		pr_debug("index%x %lx points past end %lx\n", size,
1922da572c9SDan Streetman 			 (unsigned long)offset, (unsigned long)total);
1932da572c9SDan Streetman 		return -EINVAL;
1942da572c9SDan Streetman 	}
1952da572c9SDan Streetman 
1965ca636b9SDan Streetman 	if (size != 2 && size != 4 && size != 8)
1975ca636b9SDan Streetman 		WARN(1, "__do_index invalid size %x\n", size);
1985ca636b9SDan Streetman 	else
1992da572c9SDan Streetman 		pr_debug("index%x to %lx off %lx adjoff %lx tot %lx data %lx\n",
2005ca636b9SDan Streetman 			 size, (unsigned long)index,
2015ca636b9SDan Streetman 			 (unsigned long)(index * size), (unsigned long)offset,
2025ca636b9SDan Streetman 			 (unsigned long)total,
2032da572c9SDan Streetman 			 (unsigned long)beN_to_cpu(&p->ostart[offset], size));
2042da572c9SDan Streetman 
2052da572c9SDan Streetman 	memcpy(p->out, &p->ostart[offset], size);
2062da572c9SDan Streetman 	p->out += size;
2072da572c9SDan Streetman 	p->olen -= size;
2082da572c9SDan Streetman 
2092da572c9SDan Streetman 	return 0;
2102da572c9SDan Streetman }
2112da572c9SDan Streetman 
do_index(struct sw842_param * p,u8 n)212f7ead7b4SDan Streetman static int do_index(struct sw842_param *p, u8 n)
2132da572c9SDan Streetman {
2142da572c9SDan Streetman 	switch (n) {
2152da572c9SDan Streetman 	case 2:
2162da572c9SDan Streetman 		return __do_index(p, 2, I2_BITS, I2_FIFO_SIZE);
2172da572c9SDan Streetman 	case 4:
2182da572c9SDan Streetman 		return __do_index(p, 4, I4_BITS, I4_FIFO_SIZE);
2192da572c9SDan Streetman 	case 8:
2202da572c9SDan Streetman 		return __do_index(p, 8, I8_BITS, I8_FIFO_SIZE);
2212da572c9SDan Streetman 	default:
2222da572c9SDan Streetman 		return -EINVAL;
2232da572c9SDan Streetman 	}
2242da572c9SDan Streetman }
2252da572c9SDan Streetman 
do_op(struct sw842_param * p,u8 o)226f7ead7b4SDan Streetman static int do_op(struct sw842_param *p, u8 o)
2272da572c9SDan Streetman {
2282da572c9SDan Streetman 	int i, ret = 0;
2292da572c9SDan Streetman 
2302da572c9SDan Streetman 	if (o >= OPS_MAX)
2312da572c9SDan Streetman 		return -EINVAL;
2322da572c9SDan Streetman 
2332da572c9SDan Streetman 	for (i = 0; i < 4; i++) {
2342da572c9SDan Streetman 		u8 op = decomp_ops[o][i];
2352da572c9SDan Streetman 
2362da572c9SDan Streetman 		pr_debug("op is %x\n", op);
2372da572c9SDan Streetman 
2382da572c9SDan Streetman 		switch (op & OP_ACTION) {
2392da572c9SDan Streetman 		case OP_ACTION_DATA:
2402da572c9SDan Streetman 			ret = do_data(p, op & OP_AMOUNT);
2412da572c9SDan Streetman 			break;
2422da572c9SDan Streetman 		case OP_ACTION_INDEX:
2432da572c9SDan Streetman 			ret = do_index(p, op & OP_AMOUNT);
2442da572c9SDan Streetman 			break;
2452da572c9SDan Streetman 		case OP_ACTION_NOOP:
2462da572c9SDan Streetman 			break;
2472da572c9SDan Streetman 		default:
248fc4fa6e1SMasanari Iida 			pr_err("Internal error, invalid op %x\n", op);
2492da572c9SDan Streetman 			return -EINVAL;
2502da572c9SDan Streetman 		}
2512da572c9SDan Streetman 
2522da572c9SDan Streetman 		if (ret)
2532da572c9SDan Streetman 			return ret;
2542da572c9SDan Streetman 	}
2552da572c9SDan Streetman 
2562da572c9SDan Streetman 	if (sw842_template_counts)
2572da572c9SDan Streetman 		atomic_inc(&template_count[o]);
2582da572c9SDan Streetman 
2592da572c9SDan Streetman 	return 0;
2602da572c9SDan Streetman }
2612da572c9SDan Streetman 
2622da572c9SDan Streetman /**
2632da572c9SDan Streetman  * sw842_decompress
2642da572c9SDan Streetman  *
2652da572c9SDan Streetman  * Decompress the 842-compressed buffer of length @ilen at @in
2662da572c9SDan Streetman  * to the output buffer @out, using no more than @olen bytes.
2672da572c9SDan Streetman  *
2682da572c9SDan Streetman  * The compressed buffer must be only a single 842-compressed buffer,
2692da572c9SDan Streetman  * with the standard format described in the comments in 842.h
2702da572c9SDan Streetman  * Processing will stop when the 842 "END" template is detected,
2712da572c9SDan Streetman  * not the end of the buffer.
2722da572c9SDan Streetman  *
2732da572c9SDan Streetman  * Returns: 0 on success, error on failure.  The @olen parameter
2742da572c9SDan Streetman  * will contain the number of output bytes written on success, or
2752da572c9SDan Streetman  * 0 on error.
2762da572c9SDan Streetman  */
sw842_decompress(const u8 * in,unsigned int ilen,u8 * out,unsigned int * olen)2772da572c9SDan Streetman int sw842_decompress(const u8 *in, unsigned int ilen,
2782da572c9SDan Streetman 		     u8 *out, unsigned int *olen)
2792da572c9SDan Streetman {
2802da572c9SDan Streetman 	struct sw842_param p;
2812da572c9SDan Streetman 	int ret;
2822da572c9SDan Streetman 	u64 op, rep, tmp, bytes, total;
283ea0b3984SHaren Myneni 	u64 crc;
2842da572c9SDan Streetman 
2852da572c9SDan Streetman 	p.in = (u8 *)in;
2862da572c9SDan Streetman 	p.bit = 0;
2872da572c9SDan Streetman 	p.ilen = ilen;
2882da572c9SDan Streetman 	p.out = out;
2892da572c9SDan Streetman 	p.ostart = out;
2902da572c9SDan Streetman 	p.olen = *olen;
2912da572c9SDan Streetman 
2922da572c9SDan Streetman 	total = p.olen;
2932da572c9SDan Streetman 
2942da572c9SDan Streetman 	*olen = 0;
2952da572c9SDan Streetman 
2962da572c9SDan Streetman 	do {
2972da572c9SDan Streetman 		ret = next_bits(&p, &op, OP_BITS);
2982da572c9SDan Streetman 		if (ret)
2992da572c9SDan Streetman 			return ret;
3002da572c9SDan Streetman 
3012da572c9SDan Streetman 		pr_debug("template is %lx\n", (unsigned long)op);
3022da572c9SDan Streetman 
3032da572c9SDan Streetman 		switch (op) {
3042da572c9SDan Streetman 		case OP_REPEAT:
3052da572c9SDan Streetman 			ret = next_bits(&p, &rep, REPEAT_BITS);
3062da572c9SDan Streetman 			if (ret)
3072da572c9SDan Streetman 				return ret;
3082da572c9SDan Streetman 
3092da572c9SDan Streetman 			if (p.out == out) /* no previous bytes */
3102da572c9SDan Streetman 				return -EINVAL;
3112da572c9SDan Streetman 
3122da572c9SDan Streetman 			/* copy rep + 1 */
3132da572c9SDan Streetman 			rep++;
3142da572c9SDan Streetman 
3152da572c9SDan Streetman 			if (rep * 8 > p.olen)
3162da572c9SDan Streetman 				return -ENOSPC;
3172da572c9SDan Streetman 
3182da572c9SDan Streetman 			while (rep-- > 0) {
3192da572c9SDan Streetman 				memcpy(p.out, p.out - 8, 8);
3202da572c9SDan Streetman 				p.out += 8;
3212da572c9SDan Streetman 				p.olen -= 8;
3222da572c9SDan Streetman 			}
3232da572c9SDan Streetman 
3242da572c9SDan Streetman 			if (sw842_template_counts)
3252da572c9SDan Streetman 				atomic_inc(&template_repeat_count);
3262da572c9SDan Streetman 
3272da572c9SDan Streetman 			break;
3282da572c9SDan Streetman 		case OP_ZEROS:
3292da572c9SDan Streetman 			if (8 > p.olen)
3302da572c9SDan Streetman 				return -ENOSPC;
3312da572c9SDan Streetman 
3322da572c9SDan Streetman 			memset(p.out, 0, 8);
3332da572c9SDan Streetman 			p.out += 8;
3342da572c9SDan Streetman 			p.olen -= 8;
3352da572c9SDan Streetman 
3362da572c9SDan Streetman 			if (sw842_template_counts)
3372da572c9SDan Streetman 				atomic_inc(&template_zeros_count);
3382da572c9SDan Streetman 
3392da572c9SDan Streetman 			break;
3402da572c9SDan Streetman 		case OP_SHORT_DATA:
3412da572c9SDan Streetman 			ret = next_bits(&p, &bytes, SHORT_DATA_BITS);
3422da572c9SDan Streetman 			if (ret)
3432da572c9SDan Streetman 				return ret;
3442da572c9SDan Streetman 
3452da572c9SDan Streetman 			if (!bytes || bytes > SHORT_DATA_BITS_MAX)
3462da572c9SDan Streetman 				return -EINVAL;
3472da572c9SDan Streetman 
3482da572c9SDan Streetman 			while (bytes-- > 0) {
3492da572c9SDan Streetman 				ret = next_bits(&p, &tmp, 8);
3502da572c9SDan Streetman 				if (ret)
3512da572c9SDan Streetman 					return ret;
3522da572c9SDan Streetman 				*p.out = (u8)tmp;
3532da572c9SDan Streetman 				p.out++;
3542da572c9SDan Streetman 				p.olen--;
3552da572c9SDan Streetman 			}
3562da572c9SDan Streetman 
3572da572c9SDan Streetman 			if (sw842_template_counts)
3582da572c9SDan Streetman 				atomic_inc(&template_short_data_count);
3592da572c9SDan Streetman 
3602da572c9SDan Streetman 			break;
3612da572c9SDan Streetman 		case OP_END:
3622da572c9SDan Streetman 			if (sw842_template_counts)
3632da572c9SDan Streetman 				atomic_inc(&template_end_count);
3642da572c9SDan Streetman 
3652da572c9SDan Streetman 			break;
3662da572c9SDan Streetman 		default: /* use template */
3672da572c9SDan Streetman 			ret = do_op(&p, op);
3682da572c9SDan Streetman 			if (ret)
3692da572c9SDan Streetman 				return ret;
3702da572c9SDan Streetman 			break;
3712da572c9SDan Streetman 		}
3722da572c9SDan Streetman 	} while (op != OP_END);
3732da572c9SDan Streetman 
374ea0b3984SHaren Myneni 	/*
375ea0b3984SHaren Myneni 	 * crc(0:31) is saved in compressed data starting with the
376ea0b3984SHaren Myneni 	 * next bit after End of stream template.
377ea0b3984SHaren Myneni 	 */
378ea0b3984SHaren Myneni 	ret = next_bits(&p, &crc, CRC_BITS);
379ea0b3984SHaren Myneni 	if (ret)
380ea0b3984SHaren Myneni 		return ret;
381ea0b3984SHaren Myneni 
382ea0b3984SHaren Myneni 	/*
383ea0b3984SHaren Myneni 	 * Validate CRC saved in compressed data.
384ea0b3984SHaren Myneni 	 */
385ea0b3984SHaren Myneni 	if (crc != (u64)crc32_be(0, out, total - p.olen)) {
386ea0b3984SHaren Myneni 		pr_debug("CRC mismatch for decompression\n");
387ea0b3984SHaren Myneni 		return -EINVAL;
388ea0b3984SHaren Myneni 	}
389ea0b3984SHaren Myneni 
3902da572c9SDan Streetman 	if (unlikely((total - p.olen) > UINT_MAX))
3912da572c9SDan Streetman 		return -ENOSPC;
3922da572c9SDan Streetman 
3932da572c9SDan Streetman 	*olen = total - p.olen;
3942da572c9SDan Streetman 
3952da572c9SDan Streetman 	return 0;
3962da572c9SDan Streetman }
3972da572c9SDan Streetman EXPORT_SYMBOL_GPL(sw842_decompress);
3982da572c9SDan Streetman 
sw842_init(void)3992da572c9SDan Streetman static int __init sw842_init(void)
4002da572c9SDan Streetman {
4012da572c9SDan Streetman 	if (sw842_template_counts)
4022da572c9SDan Streetman 		sw842_debugfs_create();
4032da572c9SDan Streetman 
4042da572c9SDan Streetman 	return 0;
4052da572c9SDan Streetman }
4062da572c9SDan Streetman module_init(sw842_init);
4072da572c9SDan Streetman 
sw842_exit(void)4082da572c9SDan Streetman static void __exit sw842_exit(void)
4092da572c9SDan Streetman {
4102da572c9SDan Streetman 	if (sw842_template_counts)
4112da572c9SDan Streetman 		sw842_debugfs_remove();
4122da572c9SDan Streetman }
4132da572c9SDan Streetman module_exit(sw842_exit);
4142da572c9SDan Streetman 
4152da572c9SDan Streetman MODULE_LICENSE("GPL");
4162da572c9SDan Streetman MODULE_DESCRIPTION("Software 842 Decompressor");
4172da572c9SDan Streetman MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
418