pci fixup
[openwrt.git] / package / linux / kernel-source / drivers / net / hnd / bcmutils.c
1 /*
2 * Misc useful OS-independent routines.
3 *
4 * Copyright 2004, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 * $Id$
12 */
13
14 #include <typedefs.h>
15 #include <osl.h>
16 #include <bcmutils.h>
17 #include <bcmendian.h>
18 #include <bcmnvram.h>
19
20 unsigned char bcm_ctype[] = {
21 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
22 _BCM_C,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C,_BCM_C, /* 8-15 */
23 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
24 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
25 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
26 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
27 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
28 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
29 _BCM_P,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U, /* 64-71 */
30 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
31 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
32 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
33 _BCM_P,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L, /* 96-103 */
34 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
35 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
36 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
37 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
38 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
39 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 160-175 */
40 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 176-191 */
41 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 192-207 */
42 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_L, /* 208-223 */
43 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 224-239 */
44 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L /* 240-255 */
45 };
46
47 uchar
48 bcm_toupper(uchar c)
49 {
50 if (bcm_islower(c))
51 c -= 'a'-'A';
52 return (c);
53 }
54
55 ulong
56 bcm_strtoul(char *cp, char **endp, uint base)
57 {
58 ulong result, value;
59 bool minus;
60
61 minus = FALSE;
62
63 while (bcm_isspace(*cp))
64 cp++;
65
66 if (cp[0] == '+')
67 cp++;
68 else if (cp[0] == '-') {
69 minus = TRUE;
70 cp++;
71 }
72
73 if (base == 0) {
74 if (cp[0] == '0') {
75 if ((cp[1] == 'x') || (cp[1] == 'X')) {
76 base = 16;
77 cp = &cp[2];
78 } else {
79 base = 8;
80 cp = &cp[1];
81 }
82 } else
83 base = 10;
84 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
85 cp = &cp[2];
86 }
87
88 result = 0;
89
90 while (bcm_isxdigit(*cp) &&
91 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
92 result = result*base + value;
93 cp++;
94 }
95
96 if (minus)
97 result = (ulong)(result * -1);
98
99 if (endp)
100 *endp = (char *)cp;
101
102 return (result);
103 }
104
105 uint
106 bcm_atoi(char *s)
107 {
108 uint n;
109
110 n = 0;
111
112 while (bcm_isdigit(*s))
113 n = (n * 10) + *s++ - '0';
114 return (n);
115 }
116
117 void
118 deadbeef(char *p, uint len)
119 {
120 static uchar meat[] = { 0xde, 0xad, 0xbe, 0xef };
121
122 while (len-- > 0) {
123 *p = meat[((uint)p) & 3];
124 p++;
125 }
126 }
127
128 /* pretty hex print a contiguous buffer */
129 void
130 prhex(char *msg, uchar *buf, uint nbytes)
131 {
132 char line[256];
133 char* p;
134 uint i;
135
136 if (msg && (msg[0] != '\0'))
137 printf("%s: ", msg);
138
139 p = line;
140 for (i = 0; i < nbytes; i++) {
141 if (i % 16 == 0) {
142 p += sprintf(p, "%04d: ", i); /* line prefix */
143 }
144 p += sprintf(p, "%02x ", buf[i]);
145 if (i % 16 == 15) {
146 printf("%s\n", line); /* flush line */
147 p = line;
148 }
149 }
150
151 /* flush last partial line */
152 if (p != line)
153 printf("%s\n", line);
154 }
155
156 /* pretty hex print a pkt buffer chain */
157 void
158 prpkt(char *msg, void *drv, void *p0)
159 {
160 void *p;
161
162 if (msg && (msg[0] != '\0'))
163 printf("%s: ", msg);
164
165 for (p = p0; p; p = PKTNEXT(drv, p))
166 prhex(NULL, PKTDATA(drv, p), PKTLEN(drv, p));
167 }
168
169 /* copy a pkt buffer chain into a buffer */
170 uint
171 pktcopy(void *drv, void *p, uint offset, int len, uchar *buf)
172 {
173 uint n, ret = 0;
174
175 if (len < 0)
176 len = 4096; /* "infinite" */
177
178 /* skip 'offset' bytes */
179 for (; p && offset; p = PKTNEXT(drv, p)) {
180 if (offset < (uint)PKTLEN(drv, p))
181 break;
182 offset -= PKTLEN(drv, p);
183 }
184
185 if (!p)
186 return 0;
187
188 /* copy the data */
189 for (; p && len; p = PKTNEXT(drv, p)) {
190 n = MIN((uint)PKTLEN(drv, p) - offset, (uint)len);
191 bcopy(PKTDATA(drv, p) + offset, buf, n);
192 buf += n;
193 len -= n;
194 ret += n;
195 offset = 0;
196 }
197
198 return ret;
199 }
200
201 /* return total length of buffer chain */
202 uint
203 pkttotlen(void *drv, void *p)
204 {
205 uint total;
206
207 total = 0;
208 for (; p; p = PKTNEXT(drv, p))
209 total += PKTLEN(drv, p);
210 return (total);
211 }
212
213
214 uchar*
215 bcm_ether_ntoa(char *ea, char *buf)
216 {
217 sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",
218 (uchar)ea[0]&0xff, (uchar)ea[1]&0xff, (uchar)ea[2]&0xff,
219 (uchar)ea[3]&0xff, (uchar)ea[4]&0xff, (uchar)ea[5]&0xff);
220 return (buf);
221 }
222
223 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
224 int
225 bcm_ether_atoe(char *p, char *ea)
226 {
227 int i = 0;
228
229 for (;;) {
230 ea[i++] = (char) bcm_strtoul(p, &p, 16);
231 if (!*p++ || i == 6)
232 break;
233 }
234
235 return (i == 6);
236 }
237
238 /*
239 * Advance from the current 1-byte tag/1-byte length/variable-length value
240 * triple, to the next, returning a pointer to the next.
241 */
242 bcm_tlv_t *
243 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
244 {
245 int len;
246
247 /* validate current elt */
248 if (*buflen < 2) {
249 return NULL;
250 }
251
252 len = elt->len;
253
254 /* validate remaining buflen */
255 if (*buflen >= (2 + len + 2)) {
256 elt = (bcm_tlv_t*)(elt->data + len);
257 *buflen -= (2 + len);
258 } else {
259 elt = NULL;
260 }
261
262 return elt;
263 }
264
265 /*
266 * Traverse a string of 1-byte tag/1-byte length/variable-length value
267 * triples, returning a pointer to the substring whose first element
268 * matches tag. Stop parsing when we see an element whose ID is greater
269 * than the target key.
270 */
271 bcm_tlv_t *
272 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
273 {
274 bcm_tlv_t *elt;
275 int totlen;
276
277 elt = (bcm_tlv_t*)buf;
278 totlen = buflen;
279
280 /* find tagged parameter */
281 while (totlen >= 2) {
282 uint id = elt->id;
283 int len = elt->len;
284
285 /* Punt if we start seeing IDs > than target key */
286 if (id > key)
287 return(NULL);
288
289 /* validate remaining totlen */
290 if ((id == key) && (totlen >= (len + 2)))
291 return (elt);
292
293 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
294 totlen -= (len + 2);
295 }
296 return NULL;
297 }
298
299
300 /*
301 * Traverse a string of 1-byte tag/1-byte length/variable-length value
302 * triples, returning a pointer to the substring whose first element
303 * matches tag
304 */
305 bcm_tlv_t *
306 bcm_parse_tlvs(void *buf, int buflen, uint key)
307 {
308 bcm_tlv_t *elt;
309 int totlen;
310
311 elt = (bcm_tlv_t*)buf;
312 totlen = buflen;
313
314 /* find tagged parameter */
315 while (totlen >= 2) {
316 int len = elt->len;
317
318 /* validate remaining totlen */
319 if ((elt->id == key) && (totlen >= (len + 2)))
320 return (elt);
321
322 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
323 totlen -= (len + 2);
324 }
325
326 return NULL;
327 }
328
329 void
330 pktq_init(struct pktq *q, uint maxlen, bool priority)
331 {
332 q->head = q->tail = NULL;
333 q->priority = priority;
334 q->maxlen = maxlen;
335 q->len = 0;
336 }
337
338 bool
339 pktenq(struct pktq *q, void *p, bool lifo)
340 {
341 void *next, *prev;
342
343 /* Queue is full */
344 if (q->len >= q->maxlen)
345 return FALSE;
346
347 /* Queueing chains not allowed */
348 ASSERT(PKTLINK(p) == NULL);
349
350 /* Queue is empty */
351 if (q->tail == NULL) {
352 ASSERT(q->head == NULL);
353 q->head = q->tail = p;
354 }
355
356 /* Insert at head or tail */
357 else if (q->priority == FALSE) {
358 /* Insert at head (LIFO) */
359 if (lifo) {
360 PKTSETLINK(p, q->head);
361 q->head = p;
362 }
363 /* Insert at tail (FIFO) */
364 else {
365 ASSERT(PKTLINK(q->tail) == NULL);
366 PKTSETLINK(q->tail, p);
367 PKTSETLINK(p, NULL);
368 q->tail = p;
369 }
370 }
371
372 /* Insert by priority */
373 else {
374 ASSERT(q->head);
375 ASSERT(q->tail);
376 /* Shortcut to insertion at tail */
377 if (PKTPRIO(p) < PKTPRIO(q->tail) ||
378 (!lifo && PKTPRIO(p) <= PKTPRIO(q->tail))) {
379 prev = q->tail;
380 next = NULL;
381 }
382 /* Insert at head or in the middle */
383 else {
384 prev = NULL;
385 next = q->head;
386 }
387 /* Walk the queue */
388 for (; next; prev = next, next = PKTLINK(next)) {
389 /* Priority queue invariant */
390 ASSERT(!prev || PKTPRIO(prev) >= PKTPRIO(next));
391 /* Insert at head of string of packets of same priority (LIFO) */
392 if (lifo) {
393 if (PKTPRIO(p) >= PKTPRIO(next))
394 break;
395 }
396 /* Insert at tail of string of packets of same priority (FIFO) */
397 else {
398 if (PKTPRIO(p) > PKTPRIO(next))
399 break;
400 }
401 }
402 /* Insert at tail */
403 if (next == NULL) {
404 ASSERT(PKTLINK(q->tail) == NULL);
405 PKTSETLINK(q->tail, p);
406 PKTSETLINK(p, NULL);
407 q->tail = p;
408 }
409 /* Insert in the middle */
410 else if (prev) {
411 PKTSETLINK(prev, p);
412 PKTSETLINK(p, next);
413 }
414 /* Insert at head */
415 else {
416 PKTSETLINK(p, q->head);
417 q->head = p;
418 }
419 }
420
421 /* List invariants after insertion */
422 ASSERT(q->head);
423 ASSERT(PKTLINK(q->tail) == NULL);
424
425 q->len++;
426 return TRUE;
427 }
428
429 void*
430 pktdeq(struct pktq *q)
431 {
432 void *p;
433
434 if ((p = q->head)) {
435 ASSERT(q->tail);
436 q->head = PKTLINK(p);
437 PKTSETLINK(p, NULL);
438 q->len--;
439 if (q->head == NULL)
440 q->tail = NULL;
441 }
442 else {
443 ASSERT(q->tail == NULL);
444 }
445
446 return (p);
447 }
448
449 /*******************************************************************************
450 * crc8
451 *
452 * Computes a crc8 over the input data using the polynomial:
453 *
454 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
455 *
456 * The caller provides the initial value (either CRC8_INIT_VALUE
457 * or the previous returned value) to allow for processing of
458 * discontiguous blocks of data. When generating the CRC the
459 * caller is responsible for complementing the final return value
460 * and inserting it into the byte stream. When checking, a final
461 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
462 *
463 * Reference: Dallas Semiconductor Application Note 27
464 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
465 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
466 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
467 *
468 ******************************************************************************/
469
470 static uint8 crc8_table[256] = {
471 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
472 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
473 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
474 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
475 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
476 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
477 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
478 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
479 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
480 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
481 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
482 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
483 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
484 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
485 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
486 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
487 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
488 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
489 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
490 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
491 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
492 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
493 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
494 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
495 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
496 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
497 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
498 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
499 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
500 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
501 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
502 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
503 };
504
505 /*
506 * Search the name=value vars for a specific one and return its value.
507 * Returns NULL if not found.
508 */
509 char*
510 getvar(char *vars, char *name)
511 {
512 char *s;
513 int len;
514
515 len = strlen(name);
516
517 /* first look in vars[] */
518 for (s = vars; s && *s; ) {
519 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
520 return (&s[len+1]);
521
522 while (*s++)
523 ;
524 }
525
526 /* then query nvram */
527 return (nvram_get(name));
528 }
529
530 /*
531 * Search the vars for a specific one and return its value as
532 * an integer. Returns 0 if not found.
533 */
534 int
535 getintvar(char *vars, char *name)
536 {
537 char *val;
538
539 if ((val = getvar(vars, name)) == NULL)
540 return (0);
541
542 return (bcm_strtoul(val, NULL, 0));
543 }
544
545 /* return pointer to location of substring 'needle' in 'haystack' */
546 char*
547 bcmstrstr(char *haystack, char *needle)
548 {
549 int len, nlen;
550 int i;
551
552 if ((haystack == NULL) || (needle == NULL))
553 return (haystack);
554
555 nlen = strlen(needle);
556 len = strlen(haystack) - nlen + 1;
557
558 for (i = 0; i < len; i++)
559 if (bcmp(needle, &haystack[i], nlen) == 0)
560 return (&haystack[i]);
561 return (NULL);
562 }
563
564 void
565 bcm_mdelay(uint ms)
566 {
567 uint i;
568
569 for (i = 0; i < ms; i++) {
570 OSL_DELAY(1000);
571 }
572 }
573
574 #define CRC_INNER_LOOP(n, c, x) \
575 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
576
577 uint8
578 crc8(
579 uint8 *pdata, /* pointer to array of data to process */
580 uint nbytes, /* number of input data bytes to process */
581 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
582 )
583 {
584 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
585 * to avoid the undefined and unnecessary (uint8 >> 8) operation. */
586 while (nbytes-- > 0)
587 crc = crc8_table[(crc ^ *pdata++) & 0xff];
588
589 return crc;
590 }
591
592 /*******************************************************************************
593 * crc16
594 *
595 * Computes a crc16 over the input data using the polynomial:
596 *
597 * x^16 + x^12 +x^5 + 1
598 *
599 * The caller provides the initial value (either CRC16_INIT_VALUE
600 * or the previous returned value) to allow for processing of
601 * discontiguous blocks of data. When generating the CRC the
602 * caller is responsible for complementing the final return value
603 * and inserting it into the byte stream. When checking, a final
604 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
605 *
606 * Reference: Dallas Semiconductor Application Note 27
607 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
608 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
609 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
610 *
611 ******************************************************************************/
612
613 static uint16 crc16_table[256] = {
614 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
615 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
616 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
617 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
618 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
619 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
620 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
621 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
622 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
623 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
624 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
625 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
626 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
627 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
628 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
629 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
630 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
631 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
632 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
633 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
634 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
635 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
636 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
637 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
638 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
639 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
640 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
641 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
642 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
643 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
644 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
645 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
646 };
647
648 uint16
649 crc16(
650 uint8 *pdata, /* pointer to array of data to process */
651 uint nbytes, /* number of input data bytes to process */
652 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
653 )
654 {
655 while (nbytes-- > 0)
656 CRC_INNER_LOOP(16, crc, *pdata++);
657 return crc;
658 }
659
660 static uint32 crc32_table[256] = {
661 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
662 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
663 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
664 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
665 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
666 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
667 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
668 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
669 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
670 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
671 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
672 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
673 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
674 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
675 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
676 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
677 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
678 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
679 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
680 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
681 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
682 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
683 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
684 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
685 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
686 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
687 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
688 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
689 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
690 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
691 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
692 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
693 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
694 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
695 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
696 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
697 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
698 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
699 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
700 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
701 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
702 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
703 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
704 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
705 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
706 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
707 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
708 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
709 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
710 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
711 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
712 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
713 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
714 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
715 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
716 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
717 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
718 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
719 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
720 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
721 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
722 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
723 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
724 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
725 };
726
727 uint32
728 crc32(
729 uint8 *pdata, /* pointer to array of data to process */
730 uint nbytes, /* number of input data bytes to process */
731 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
732 )
733 {
734 uint8 *pend;
735 #ifdef __mips__
736 uint8 tmp[4];
737 ulong *tptr = (ulong *)tmp;
738
739 /* in case the beginning of the buffer isn't aligned */
740 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
741 nbytes -= (pend - pdata);
742 while (pdata < pend)
743 CRC_INNER_LOOP(32, crc, *pdata++);
744
745 /* handle bulk of data as 32-bit words */
746 pend = pdata + (nbytes & 0xfffffffc);
747 while (pdata < pend) {
748 *tptr = (*((ulong *)pdata))++;
749 CRC_INNER_LOOP(32, crc, tmp[0]);
750 CRC_INNER_LOOP(32, crc, tmp[1]);
751 CRC_INNER_LOOP(32, crc, tmp[2]);
752 CRC_INNER_LOOP(32, crc, tmp[3]);
753 }
754
755 /* 1-3 bytes at end of buffer */
756 pend = pdata + (nbytes & 0x03);
757 while (pdata < pend)
758 CRC_INNER_LOOP(32, crc, *pdata++);
759 #else
760 pend = pdata + nbytes;
761 while (pdata < pend)
762 CRC_INNER_LOOP(32, crc, *pdata++);
763 #endif
764
765 return crc;
766 }
767
768 #ifdef notdef
769 #define CLEN 1499
770 #define CBUFSIZ (CLEN+4)
771 #define CNBUFS 5
772
773 void testcrc32(void)
774 {
775 uint j,k,l;
776 uint8 *buf;
777 uint len[CNBUFS];
778 uint32 crcr;
779 uint32 crc32tv[CNBUFS] =
780 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
781
782 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
783
784 /* step through all possible alignments */
785 for (l=0;l<=4;l++) {
786 for (j=0; j<CNBUFS; j++) {
787 len[j] = CLEN;
788 for (k=0; k<len[j]; k++)
789 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
790 }
791
792 for (j=0; j<CNBUFS; j++) {
793 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
794 ASSERT(crcr == crc32tv[j]);
795 }
796 }
797
798 MFREE(buf, CBUFSIZ*CNBUFS);
799 return;
800 }
801 #endif
802
803
This page took 0.086623 seconds and 5 git commands to generate.