diff options
Diffstat (limited to 'lib/reed_solomon')
| -rw-r--r-- | lib/reed_solomon/Makefile | 2 | ||||
| -rw-r--r-- | lib/reed_solomon/decode_rs.c | 41 | ||||
| -rw-r--r-- | lib/reed_solomon/encode_rs.c | 14 | ||||
| -rw-r--r-- | lib/reed_solomon/reed_solomon.c | 171 |
4 files changed, 138 insertions, 90 deletions
diff --git a/lib/reed_solomon/Makefile b/lib/reed_solomon/Makefile index 747a2de2934..c3d7136827e 100644 --- a/lib/reed_solomon/Makefile +++ b/lib/reed_solomon/Makefile @@ -1,5 +1,5 @@ # -# This is a modified version of reed solomon lib, +# This is a modified version of reed solomon lib, # obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o diff --git a/lib/reed_solomon/decode_rs.c b/lib/reed_solomon/decode_rs.c index d401decd628..0ec3f257ffd 100644 --- a/lib/reed_solomon/decode_rs.c +++ b/lib/reed_solomon/decode_rs.c @@ -1,22 +1,22 @@ -/* +/* * lib/reed_solomon/decode_rs.c * * Overview: * Generic Reed Solomon encoder / decoder library - * + * * Copyright 2002, Phil Karn, KA9Q * May be used under the terms of the GNU General Public License (GPL) * * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) * - * $Id: decode_rs.c,v 1.6 2004/10/22 15:41:47 gleixner Exp $ + * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $ * */ -/* Generic data width independent code which is included by the +/* Generic data width independent code which is included by the * wrappers. */ -{ +{ int deg_lambda, el, deg_omega; int i, j, r, k, pad; int nn = rs->nn; @@ -39,11 +39,10 @@ /* Check length parameter for validity */ pad = nn - nroots - len; - if (pad < 0 || pad >= nn) - return -ERANGE; - + BUG_ON(pad < 0 || pad >= nn); + /* Does the caller provide the syndrome ? */ - if (s != NULL) + if (s != NULL) goto decode; /* form the syndromes; i.e., evaluate data(x) at roots of @@ -54,11 +53,11 @@ for (j = 1; j < len; j++) { for (i = 0; i < nroots; i++) { if (syn[i] == 0) { - syn[i] = (((uint16_t) data[j]) ^ + syn[i] = (((uint16_t) data[j]) ^ invmsk) & msk; } else { syn[i] = ((((uint16_t) data[j]) ^ - invmsk) & msk) ^ + invmsk) & msk) ^ alpha_to[rs_modnn(rs, index_of[syn[i]] + (fcr + i) * prim)]; } @@ -70,7 +69,7 @@ if (syn[i] == 0) { syn[i] = ((uint16_t) par[j]) & msk; } else { - syn[i] = (((uint16_t) par[j]) & msk) ^ + syn[i] = (((uint16_t) par[j]) & msk) ^ alpha_to[rs_modnn(rs, index_of[syn[i]] + (fcr+i)*prim)]; } @@ -99,14 +98,14 @@ if (no_eras > 0) { /* Init lambda to be the erasure locator polynomial */ - lambda[1] = alpha_to[rs_modnn(rs, + lambda[1] = alpha_to[rs_modnn(rs, prim * (nn - 1 - eras_pos[0]))]; for (i = 1; i < no_eras; i++) { u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i])); for (j = i + 1; j > 0; j--) { tmp = index_of[lambda[j - 1]]; if (tmp != nn) { - lambda[j] ^= + lambda[j] ^= alpha_to[rs_modnn(rs, u + tmp)]; } } @@ -127,8 +126,8 @@ discr_r = 0; for (i = 0; i < r; i++) { if ((lambda[i] != 0) && (s[r - i - 1] != nn)) { - discr_r ^= - alpha_to[rs_modnn(rs, + discr_r ^= + alpha_to[rs_modnn(rs, index_of[lambda[i]] + s[r - i - 1])]; } @@ -143,7 +142,7 @@ t[0] = lambda[0]; for (i = 0; i < nroots; i++) { if (b[i] != nn) { - t[i + 1] = lambda[i + 1] ^ + t[i + 1] = lambda[i + 1] ^ alpha_to[rs_modnn(rs, discr_r + b[i])]; } else @@ -203,7 +202,7 @@ * deg(lambda) unequal to number of roots => uncorrectable * error detected */ - count = -1; + count = -EBADMSG; goto finish; } /* @@ -229,7 +228,7 @@ num1 = 0; for (i = deg_omega; i >= 0; i--) { if (omega[i] != nn) - num1 ^= alpha_to[rs_modnn(rs, omega[i] + + num1 ^= alpha_to[rs_modnn(rs, omega[i] + i * root[j])]; } num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)]; @@ -239,13 +238,13 @@ * lambda_pr of lambda[i] */ for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) { if (lambda[i + 1] != nn) { - den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + + den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + i * root[j])]; } } /* Apply error to data */ if (num1 != 0 && loc[j] >= pad) { - uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + + uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + index_of[num2] + nn - index_of[den])]; /* Store the error correction pattern, if a diff --git a/lib/reed_solomon/encode_rs.c b/lib/reed_solomon/encode_rs.c index 237bf65ae88..0b5b1a6728e 100644 --- a/lib/reed_solomon/encode_rs.c +++ b/lib/reed_solomon/encode_rs.c @@ -1,19 +1,19 @@ -/* +/* * lib/reed_solomon/encode_rs.c * * Overview: * Generic Reed Solomon encoder / decoder library - * + * * Copyright 2002, Phil Karn, KA9Q * May be used under the terms of the GNU General Public License (GPL) * * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) * - * $Id: encode_rs.c,v 1.4 2004/10/22 15:41:47 gleixner Exp $ + * $Id: encode_rs.c,v 1.5 2005/11/07 11:14:59 gleixner Exp $ * */ -/* Generic data width independent code which is included by the +/* Generic data width independent code which is included by the * wrappers. * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par) */ @@ -35,16 +35,16 @@ for (i = 0; i < len; i++) { fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]]; /* feedback term is non-zero */ - if (fb != nn) { + if (fb != nn) { for (j = 1; j < nroots; j++) { - par[j] ^= alpha_to[rs_modnn(rs, fb + + par[j] ^= alpha_to[rs_modnn(rs, fb + genpoly[nroots - j])]; } } /* Shift */ memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1)); if (fb != nn) { - par[nroots - 1] = alpha_to[rs_modnn(rs, + par[nroots - 1] = alpha_to[rs_modnn(rs, fb + genpoly[0])]; } else { par[nroots - 1] = 0; diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c index 6604e3b1940..06d04cfa933 100644 --- a/lib/reed_solomon/reed_solomon.c +++ b/lib/reed_solomon/reed_solomon.c @@ -1,22 +1,22 @@ -/* - * lib/reed_solomon/rslib.c +/* + * lib/reed_solomon/reed_solomon.c * * Overview: * Generic Reed Solomon encoder / decoder library - * + * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * * Reed Solomon code lifted from reed solomon library written by Phil Karn * Copyright 2002 Phil Karn, KA9Q * - * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 gleixner Exp $ + * $Id: rslib.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Description: - * + * * The generic Reed Solomon library provides runtime configurable * encoding / decoding of RS codes. * Each user must call init_rs to get a pointer to a rs_control @@ -25,11 +25,11 @@ * If a structure is generated then the polynomial arrays for * fast encoding / decoding are built. This can take some time so * make sure not to call this function from a time critical path. - * Usually a module / driver should initialize the necessary + * Usually a module / driver should initialize the necessary * rs_control structure on module / driver init and release it * on exit. - * The encoding puts the calculated syndrome into a given syndrome - * buffer. + * The encoding puts the calculated syndrome into a given syndrome + * buffer. * The decoding is a two step process. The first step calculates * the syndrome over the received (data + syndrome) and calls the * second stage, which does the decoding / error correction itself. @@ -44,27 +44,27 @@ #include <linux/module.h> #include <linux/rslib.h> #include <linux/slab.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> /* This list holds all currently allocated rs control structures */ static LIST_HEAD (rslist); /* Protection for the list */ -static DECLARE_MUTEX(rslistlock); +static DEFINE_MUTEX(rslistlock); -/** +/** * rs_init - Initialize a Reed-Solomon codec - * * @symsize: symbol size, bits (1-8) * @gfpoly: Field generator polynomial coefficients + * @gffunc: Field generator function * @fcr: first root of RS code generator polynomial, index form * @prim: primitive element to generate polynomial roots * @nroots: RS code generator polynomial degree (number of roots) * * Allocate a control structure and the polynom arrays for faster - * en/decoding. Fill the arrays according to the given parameters + * en/decoding. Fill the arrays according to the given parameters. */ -static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, - int prim, int nroots) +static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int), + int fcr, int prim, int nroots) { struct rs_control *rs; int i, j, sr, root, iprim; @@ -82,6 +82,7 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, rs->prim = prim; rs->nroots = nroots; rs->gfpoly = gfpoly; + rs->gffunc = gffunc; /* Allocate the arrays */ rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL); @@ -99,17 +100,26 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, /* Generate Galois field lookup tables */ rs->index_of[0] = rs->nn; /* log(zero) = -inf */ rs->alpha_to[rs->nn] = 0; /* alpha**-inf = 0 */ - sr = 1; - for (i = 0; i < rs->nn; i++) { - rs->index_of[sr] = i; - rs->alpha_to[i] = sr; - sr <<= 1; - if (sr & (1 << symsize)) - sr ^= gfpoly; - sr &= rs->nn; + if (gfpoly) { + sr = 1; + for (i = 0; i < rs->nn; i++) { + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr <<= 1; + if (sr & (1 << symsize)) + sr ^= gfpoly; + sr &= rs->nn; + } + } else { + sr = gffunc(0); + for (i = 0; i < rs->nn; i++) { + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr = gffunc(sr); + } } /* If it's not primitive, exit */ - if(sr != 1) + if(sr != rs->alpha_to[0]) goto errpol; /* Find prim-th root of 1, used in decoding */ @@ -124,15 +134,15 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, /* Multiply rs->genpoly[] by @**(root + x) */ for (j = i; j > 0; j--) { if (rs->genpoly[j] != 0) { - rs->genpoly[j] = rs->genpoly[j -1] ^ - rs->alpha_to[rs_modnn(rs, + rs->genpoly[j] = rs->genpoly[j -1] ^ + rs->alpha_to[rs_modnn(rs, rs->index_of[rs->genpoly[j]] + root)]; } else rs->genpoly[j] = rs->genpoly[j - 1]; } /* rs->genpoly[0] can never be zero */ - rs->genpoly[0] = - rs->alpha_to[rs_modnn(rs, + rs->genpoly[0] = + rs->alpha_to[rs_modnn(rs, rs->index_of[rs->genpoly[0]] + root)]; } /* convert rs->genpoly[] to index form for quicker encoding */ @@ -153,15 +163,14 @@ errrs: } -/** - * free_rs - Free the rs control structure, if its not longer used - * +/** + * free_rs - Free the rs control structure, if it is no longer used * @rs: the control structure which is not longer used by the * caller */ void free_rs(struct rs_control *rs) { - down(&rslistlock); + mutex_lock(&rslistlock); rs->users--; if(!rs->users) { list_del(&rs->list); @@ -170,23 +179,26 @@ void free_rs(struct rs_control *rs) kfree(rs->genpoly); kfree(rs); } - up(&rslistlock); + mutex_unlock(&rslistlock); } -/** - * init_rs - Find a matching or allocate a new rs control structure - * +/** + * init_rs_internal - Find a matching or allocate a new rs control structure * @symsize: the symbol size (number of bits) * @gfpoly: the extended Galois field generator polynomial coefficients, * with the 0th coefficient in the low order bit. The polynomial * must be primitive; - * @fcr: the first consecutive root of the rs code generator polynomial + * @gffunc: pointer to function to generate the next field element, + * or the multiplicative identity element if given 0. Used + * instead of gfpoly if gfpoly is 0 + * @fcr: the first consecutive root of the rs code generator polynomial * in index form * @prim: primitive element to generate polynomial roots * @nroots: RS code generator polynomial degree (number of roots) */ -struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, - int nroots) +static struct rs_control *init_rs_internal(int symsize, int gfpoly, + int (*gffunc)(int), int fcr, + int prim, int nroots) { struct list_head *tmp; struct rs_control *rs; @@ -198,10 +210,10 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, return NULL; if (prim <= 0 || prim >= (1<<symsize)) return NULL; - if (nroots < 0 || nroots >= (1<<symsize) || nroots > 8) + if (nroots < 0 || nroots >= (1<<symsize)) return NULL; - - down(&rslistlock); + + mutex_lock(&rslistlock); /* Walk through the list and look for a matching entry */ list_for_each(tmp, &rslist) { @@ -210,10 +222,12 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, continue; if (gfpoly != rs->gfpoly) continue; + if (gffunc != rs->gffunc) + continue; if (fcr != rs->fcr) - continue; + continue; if (prim != rs->prim) - continue; + continue; if (nroots != rs->nroots) continue; /* We have a matching one already */ @@ -222,23 +236,58 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, } /* Create a new one */ - rs = rs_init(symsize, gfpoly, fcr, prim, nroots); + rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots); if (rs) { rs->users = 1; list_add(&rs->list, &rslist); } -out: - up(&rslistlock); +out: + mutex_unlock(&rslistlock); return rs; } +/** + * init_rs - Find a matching or allocate a new rs control structure + * @symsize: the symbol size (number of bits) + * @gfpoly: the extended Galois field generator polynomial coefficients, + * with the 0th coefficient in the low order bit. The polynomial + * must be primitive; + * @fcr: the first consecutive root of the rs code generator polynomial + * in index form + * @prim: primitive element to generate polynomial roots + * @nroots: RS code generator polynomial degree (number of roots) + */ +struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, + int nroots) +{ + return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots); +} + +/** + * init_rs_non_canonical - Find a matching or allocate a new rs control + * structure, for fields with non-canonical + * representation + * @symsize: the symbol size (number of bits) + * @gffunc: pointer to function to generate the next field element, + * or the multiplicative identity element if given 0. Used + * instead of gfpoly if gfpoly is 0 + * @fcr: the first consecutive root of the rs code generator polynomial + * in index form + * @prim: primitive element to generate polynomial roots + * @nroots: RS code generator polynomial degree (number of roots) + */ +struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int), + int fcr, int prim, int nroots) +{ + return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots); +} + #ifdef CONFIG_REED_SOLOMON_ENC8 -/** +/** * encode_rs8 - Calculate the parity for data values (8bit data width) - * * @rs: the rs control structure * @data: data field of a given type - * @len: data length + * @len: data length * @par: parity data, must be initialized by caller (usually all 0) * @invmsk: invert data mask (will be xored on data) * @@ -246,7 +295,7 @@ out: * symbol size > 8. The calling code must take care of encoding of the * syndrome result for storage itself. */ -int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, +int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, uint16_t invmsk) { #include "encode_rs.c" @@ -255,9 +304,8 @@ EXPORT_SYMBOL_GPL(encode_rs8); #endif #ifdef CONFIG_REED_SOLOMON_DEC8 -/** +/** * decode_rs8 - Decode codeword (8bit data width) - * * @rs: the rs control structure * @data: data field of a given type * @par: received parity data field @@ -271,9 +319,10 @@ EXPORT_SYMBOL_GPL(encode_rs8); * The syndrome and parity uses a uint16_t data type to enable * symbol size > 8. The calling code must take care of decoding of the * syndrome result and the received parity before calling this code. + * Returns the number of corrected bits or -EBADMSG for uncorrectable errors. */ int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, - uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, + uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, uint16_t *corr) { #include "decode_rs.c" @@ -284,16 +333,15 @@ EXPORT_SYMBOL_GPL(decode_rs8); #ifdef CONFIG_REED_SOLOMON_ENC16 /** * encode_rs16 - Calculate the parity for data values (16bit data width) - * * @rs: the rs control structure * @data: data field of a given type - * @len: data length + * @len: data length * @par: parity data, must be initialized by caller (usually all 0) * @invmsk: invert data mask (will be xored on data, not on parity!) * * Each field in the data array contains up to symbol size bits of valid data. */ -int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, +int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, uint16_t invmsk) { #include "encode_rs.c" @@ -302,9 +350,8 @@ EXPORT_SYMBOL_GPL(encode_rs16); #endif #ifdef CONFIG_REED_SOLOMON_DEC16 -/** +/** * decode_rs16 - Decode codeword (16bit data width) - * * @rs: the rs control structure * @data: data field of a given type * @par: received parity data field @@ -312,13 +359,14 @@ EXPORT_SYMBOL_GPL(encode_rs16); * @s: syndrome data field (if NULL, syndrome is calculated) * @no_eras: number of erasures * @eras_pos: position of erasures, can be NULL - * @invmsk: invert data mask (will be xored on data, not on parity!) + * @invmsk: invert data mask (will be xored on data, not on parity!) * @corr: buffer to store correction bitmask on eras_pos * * Each field in the data array contains up to symbol size bits of valid data. + * Returns the number of corrected bits or -EBADMSG for uncorrectable errors. */ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len, - uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, + uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, uint16_t *corr) { #include "decode_rs.c" @@ -327,6 +375,7 @@ EXPORT_SYMBOL_GPL(decode_rs16); #endif EXPORT_SYMBOL_GPL(init_rs); +EXPORT_SYMBOL_GPL(init_rs_non_canonical); EXPORT_SYMBOL_GPL(free_rs); MODULE_LICENSE("GPL"); |
