1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18    Copyright 2001, ASUSTeK Inc.
19    All Rights Reserved.
20
21    This is UNPUBLISHED PROPRIETARY SOURCE CODE of ASUSTeK Inc.;
22    the contents of this file may not be disclosed to third parties, copied or
23    duplicated in any form, in whole or in part, without the prior written
24    permission of ASUSTeK Inc.
25*/
26/*
27 * Misc useful OS-independent routines.
28 *
29 * Copyright(c) 2001 ASUSTeK Inc.
30 */
31
32#include <osl.h>
33#include <nvram/bcmutils.h>
34
35#define _U	0x01	/* upper */
36#define _L	0x02	/* lower */
37#define _D	0x04	/* digit */
38#define _C	0x08	/* cntrl */
39#define _P	0x10	/* punct */
40#define _S	0x20	/* white space (space/lf/tab) */
41#define _X	0x40	/* hex digit */
42#define _SP	0x80	/* hard space (0x20) */
43
44static unsigned char _ctype[] = {
45	_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
46	_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
47	_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
48	_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
49	_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
50	_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
51	_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
52	_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
53	_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
54	_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
55	_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
56	_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
57	_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
58	_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
59	_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
60	_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
61	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
62	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
63	_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
64	_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
65	_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
66	_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
67	_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
68	_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L	/* 240-255 */
69};
70
71#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
72
73#define isalnum(c)	((__ismask(c)&(_U|_L|_D)) != 0)
74#define isalpha(c)	((__ismask(c)&(_U|_L)) != 0)
75#define iscntrl(c)	((__ismask(c)&(_C)) != 0)
76#define isdigit(c)	((__ismask(c)&(_D)) != 0)
77#define isgraph(c)	((__ismask(c)&(_P|_U|_L|_D)) != 0)
78#define islower(c)	((__ismask(c)&(_L)) != 0)
79#define isprint(c)	((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
80#define ispunct(c)	((__ismask(c)&(_P)) != 0)
81#define isspace(c)	((__ismask(c)&(_S)) != 0)
82#define isupper(c)	((__ismask(c)&(_U)) != 0)
83#define isxdigit(c)	((__ismask(c)&(_D|_X)) != 0)
84
85static uchar
86bcm_toupper(uchar c)
87{
88	if (islower(c))
89		c -= 'a'-'A';
90	return (c);
91}
92
93ulong
94bcm_strtoul(char *cp, char **endp, uint base)
95{
96	ulong result, value;
97
98	/* The real strtoul supports a base of 0, but we don't */
99	ASSERT(base);
100
101	result = 0;
102
103	while (isxdigit(*cp) &&
104	       (value = isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
105		result = result*base + value;
106		cp++;
107	}
108	if (endp)
109		*endp = (char *)cp;
110
111	return (result);
112}
113
114uint
115bcm_atoi(char *s)
116{
117	uint n;
118
119	n = 0;
120
121	while (isdigit(*s))
122		n = (n * 10) + *s++ - '0';
123	return (n);
124}
125
126void
127deadbeef(char *p, uint len)
128{
129	static uchar meat[] = { 0xde, 0xad, 0xbe, 0xef };
130
131	while (len-- > 0) {
132		*p = meat[((uint)p) & 3];
133		p++;
134	}
135}
136
137uchar*
138bcm_ether_ntoa(char *ea, char *buf)
139{
140	sprintf(buf,"%x:%x:%x:%x:%x:%x",
141		ea[0]&0xff, ea[1]&0xff, ea[2]&0xff, ea[3]&0xff, ea[4]&0xff, ea[5]&0xff);
142	return (buf);
143}
144
145/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
146void
147bcm_ether_atoe(char *p, char *ea)
148{
149	int i;
150
151	for (i = 0; i < 6; i++) {
152		ea[i] = (char) bcm_strtoul(p, &p, 16);
153		if (*p == '\0')	/* just bail on error */
154			break;
155		p++;
156	}
157}
158
159int
160bcm_isprint(uchar c)
161{
162	return (isprint(c));
163}
164
165/*
166 * Traverse a string of 1-byte tag/1-byte length/variable-length value
167 * triples, returning a pointer to the substring whose first element
168 * matches tag
169 */
170uint8 *
171bcm_parse_tlvs(uint8 *buf, int buflen, uint key)
172{
173	uint8 *cp;
174	int totlen;
175
176	cp = buf;
177	totlen = buflen;
178
179	/* find tagged parameter */
180	while (totlen > 0) {
181		uint tag, len;
182
183		tag = *cp;
184
185		if (tag == key)
186			return (cp);
187
188		len = *(cp + 1);
189		cp += (len + 2);
190		totlen -= (len + 2);
191	}
192
193	return NULL;
194}
195
196#define	pktq_next(i)	((i+1) & (MAXQLEN-1))
197#define	pktq_prev(i)	((i-1) & (MAXQLEN-1))
198
199void
200pktqinit(struct pktq *q)
201{
202	q->head = q->tail = 0;
203	bzero((char*)q->p, sizeof (q->p));
204}
205
206void
207pktenq(struct pktq *q, void *p)
208{
209	ASSERT(p);
210	ASSERT(!pktq_full(q));
211
212	ASSERT(q->p[q->tail] == NULL);
213	q->p[q->tail] = p;
214	q->tail = pktq_next(q->tail);
215}
216
217void*
218pktdeq(struct pktq *q)
219{
220	void *p;
221
222	if (q->head == q->tail)
223		return (NULL);
224
225	p = q->p[q->head];
226	ASSERT(p);
227
228	q->p[q->head] = NULL;
229	q->head = pktq_next(q->head);
230
231	return (p);
232}
233
234/*******************************************************************************
235 * crc8
236 *
237 * Computes a crc8 over the input data using the polynomial:
238 *
239 *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
240 *
241 * The caller provides the initial value (either CRC8_INIT_VALUE
242 * or the previous returned value) to allow for processing of
243 * discontiguous blocks of data.  When generating the CRC the
244 * caller is responsible for complementing the final return value
245 * and inserting it into the byte stream.  When checking, a final
246 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
247 *
248 * Reference: Dallas Semiconductor Application Note 27
249 *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
250 *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
251 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
252 *
253 ******************************************************************************/
254
255static uint8 crc8_table[256] = {
256    0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
257    0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
258    0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
259    0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
260    0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
261    0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
262    0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
263    0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
264    0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
265    0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
266    0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
267    0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
268    0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
269    0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
270    0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
271    0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
272    0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
273    0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
274    0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
275    0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
276    0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
277    0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
278    0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
279    0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
280    0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
281    0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
282    0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
283    0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
284    0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
285    0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
286    0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
287    0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
288};
289
290#define CRC_INNER_LOOP(n, c, x) \
291    (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
292
293uint8
294crc8(
295	uint8 *pdata,	/* pointer to array of data to process */
296	uint  nbytes,	/* number of input data bytes to process */
297	uint8 crc	/* either CRC8_INIT_VALUE or previous return value */
298)
299{
300	/* hard code the crc loop instead of using CRC_INNER_LOOP macro
301	 * to avoid the undefined and unnecessary (uint8 >> 8) operation. */
302	while (nbytes-- > 0)
303		crc = crc8_table[(crc ^ *pdata++) & 0xff];
304
305	return crc;
306}
307
308/*******************************************************************************
309 * crc16
310 *
311 * Computes a crc16 over the input data using the polynomial:
312 *
313 *       x^16 + x^12 +x^5 + 1
314 *
315 * The caller provides the initial value (either CRC16_INIT_VALUE
316 * or the previous returned value) to allow for processing of
317 * discontiguous blocks of data.  When generating the CRC the
318 * caller is responsible for complementing the final return value
319 * and inserting it into the byte stream.  When checking, a final
320 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
321 *
322 * Reference: Dallas Semiconductor Application Note 27
323 *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
324 *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
325 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
326 *
327 ******************************************************************************/
328
329static uint16 crc16_table[256] = {
330    0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
331    0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
332    0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
333    0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
334    0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
335    0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
336    0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
337    0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
338    0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
339    0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
340    0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
341    0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
342    0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
343    0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
344    0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
345    0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
346    0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
347    0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
348    0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
349    0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
350    0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
351    0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
352    0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
353    0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
354    0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
355    0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
356    0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
357    0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
358    0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
359    0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
360    0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
361    0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
362};
363
364uint16
365crc16(
366    uint8 *pdata,  /* pointer to array of data to process */
367    uint nbytes, /* number of input data bytes to process */
368    uint16 crc     /* either CRC16_INIT_VALUE or previous return value */
369)
370{
371    while (nbytes-- > 0)
372	CRC_INNER_LOOP(16, crc, *pdata++);
373    return crc;
374}
375
376static uint32 crc32_table[256] = {
377    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
378    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
379    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
380    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
381    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
382    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
383    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
384    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
385    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
386    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
387    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
388    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
389    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
390    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
391    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
392    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
393    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
394    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
395    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
396    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
397    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
398    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
399    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
400    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
401    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
402    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
403    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
404    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
405    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
406    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
407    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
408    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
409    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
410    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
411    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
412    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
413    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
414    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
415    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
416    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
417    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
418    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
419    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
420    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
421    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
422    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
423    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
424    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
425    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
426    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
427    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
428    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
429    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
430    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
431    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
432    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
433    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
434    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
435    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
436    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
437    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
438    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
439    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
440    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
441};
442
443uint32
444crc32(
445    uint8 *pdata,  /* pointer to array of data to process */
446    uint   nbytes, /* number of input data bytes to process */
447    uint32 crc     /* either CRC32_INIT_VALUE or previous return value */
448)
449{
450    uint8 *pend;
451#ifdef __mips__
452    uint8 tmp[4];
453    ulong *tptr = (ulong *)tmp;
454
455	/* in case the beginning of the buffer isn't aligned */
456	pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
457	nbytes -= (pend - pdata);
458	while (pdata < pend)
459		CRC_INNER_LOOP(32, crc, *pdata++);
460
461    /* handle bulk of data as 32-bit words */
462    pend = pdata + (nbytes & 0xfffffffc);
463    while (pdata < pend) {
464	*tptr = *((ulong *)pdata)++;
465	CRC_INNER_LOOP(32, crc, tmp[0]);
466	CRC_INNER_LOOP(32, crc, tmp[1]);
467	CRC_INNER_LOOP(32, crc, tmp[2]);
468	CRC_INNER_LOOP(32, crc, tmp[3]);
469    }
470
471    /* 1-3 bytes at end of buffer */
472    pend = pdata + (nbytes & 0x03);
473    while (pdata < pend)
474	CRC_INNER_LOOP(32, crc, *pdata++);
475#else
476    pend = pdata + nbytes;
477    while (pdata < pend)
478	CRC_INNER_LOOP(32, crc, *pdata++);
479#endif
480
481    return crc;
482}
483
484
485#ifdef BCMDBG
486#define CLEN 	1499
487#define CBUFSIZ 	(CLEN+4)
488#define CNBUFS		5
489
490void testcrc32(void)
491{
492	uint j,k,l;
493	uint8 *buf;
494	uint len[CNBUFS];
495	uint32 crcr;
496	uint32 crc32tv[CNBUFS] =
497		{0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
498
499	ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
500
501	/* step through all possible alignments */
502	for (l=0;l<=4;l++) {
503		for (j=0; j<CNBUFS; j++) {
504			len[j] = CLEN;
505			for (k=0; k<len[j]; k++)
506				*(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
507		}
508
509		for (j=0; j<CNBUFS; j++) {
510			crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
511			ASSERT(crcr == crc32tv[j]);
512		}
513	}
514
515	MFREE(buf, CBUFSIZ*CNBUFS);
516	return;
517}
518#endif
519