Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.git] / drivers / staging / brcm80211 / util / bcmutils.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/ctype.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <bcmdefs.h>
21 #include <stdarg.h>
22 #include <osl.h>
23 #include <linuxver.h>
24 #include <bcmutils.h>
25 #include <siutils.h>
26 #include <bcmnvram.h>
27 #include <bcmendian.h>
28 #include <bcmdevs.h>
29 #include <proto/ethernet.h>
30 #include <proto/802.1d.h>
31 #include <proto/802.11.h>
32
33
34 /* copy a buffer into a pkt buffer chain */
35 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
36 {
37         uint n, ret = 0;
38
39         /* skip 'offset' bytes */
40         for (; p && offset; p = PKTNEXT(p)) {
41                 if (offset < (uint) PKTLEN(p))
42                         break;
43                 offset -= PKTLEN(p);
44         }
45
46         if (!p)
47                 return 0;
48
49         /* copy the data */
50         for (; p && len; p = PKTNEXT(p)) {
51                 n = min((uint) PKTLEN(p) - offset, (uint) len);
52                 bcopy(buf, PKTDATA(p) + offset, n);
53                 buf += n;
54                 len -= n;
55                 ret += n;
56                 offset = 0;
57         }
58
59         return ret;
60 }
61 /* return total length of buffer chain */
62 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
63 {
64         uint total;
65
66         total = 0;
67         for (; p; p = PKTNEXT(p))
68                 total += PKTLEN(p);
69         return total;
70 }
71
72 /*
73  * osl multiple-precedence packet queue
74  * hi_prec is always >= the number of the highest non-empty precedence
75  */
76 void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
77 {
78         struct pktq_prec *q;
79
80         ASSERT(prec >= 0 && prec < pq->num_prec);
81         ASSERT(PKTLINK(p) == NULL);     /* queueing chains not allowed */
82
83         ASSERT(!pktq_full(pq));
84         ASSERT(!pktq_pfull(pq, prec));
85
86         q = &pq->q[prec];
87
88         if (q->head)
89                 PKTSETLINK(q->tail, p);
90         else
91                 q->head = p;
92
93         q->tail = p;
94         q->len++;
95
96         pq->len++;
97
98         if (pq->hi_prec < prec)
99                 pq->hi_prec = (u8) prec;
100
101         return p;
102 }
103
104 void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
105 {
106         struct pktq_prec *q;
107
108         ASSERT(prec >= 0 && prec < pq->num_prec);
109         ASSERT(PKTLINK(p) == NULL);     /* queueing chains not allowed */
110
111         ASSERT(!pktq_full(pq));
112         ASSERT(!pktq_pfull(pq, prec));
113
114         q = &pq->q[prec];
115
116         if (q->head == NULL)
117                 q->tail = p;
118
119         PKTSETLINK(p, q->head);
120         q->head = p;
121         q->len++;
122
123         pq->len++;
124
125         if (pq->hi_prec < prec)
126                 pq->hi_prec = (u8) prec;
127
128         return p;
129 }
130
131 void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
132 {
133         struct pktq_prec *q;
134         void *p;
135
136         ASSERT(prec >= 0 && prec < pq->num_prec);
137
138         q = &pq->q[prec];
139
140         p = q->head;
141         if (p == NULL)
142                 return NULL;
143
144         q->head = PKTLINK(p);
145         if (q->head == NULL)
146                 q->tail = NULL;
147
148         q->len--;
149
150         pq->len--;
151
152         PKTSETLINK(p, NULL);
153
154         return p;
155 }
156
157 void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
158 {
159         struct pktq_prec *q;
160         void *p, *prev;
161
162         ASSERT(prec >= 0 && prec < pq->num_prec);
163
164         q = &pq->q[prec];
165
166         p = q->head;
167         if (p == NULL)
168                 return NULL;
169
170         for (prev = NULL; p != q->tail; p = PKTLINK(p))
171                 prev = p;
172
173         if (prev)
174                 PKTSETLINK(prev, NULL);
175         else
176                 q->head = NULL;
177
178         q->tail = prev;
179         q->len--;
180
181         pq->len--;
182
183         return p;
184 }
185
186 #ifdef BRCM_FULLMAC
187 void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
188 {
189         struct pktq_prec *q;
190         void *p;
191
192         q = &pq->q[prec];
193         p = q->head;
194         while (p) {
195                 q->head = PKTLINK(p);
196                 PKTSETLINK(p, NULL);
197                 PKTFREE(osh, p, dir);
198                 q->len--;
199                 pq->len--;
200                 p = q->head;
201         }
202         ASSERT(q->len == 0);
203         q->tail = NULL;
204 }
205
206 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
207 {
208         int prec;
209         for (prec = 0; prec < pq->num_prec; prec++)
210                 pktq_pflush(osh, pq, prec, dir);
211         ASSERT(pq->len == 0);
212 }
213 #else /* !BRCM_FULLMAC */
214 void
215 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
216             int arg)
217 {
218         struct pktq_prec *q;
219         void *p, *prev = NULL;
220
221         q = &pq->q[prec];
222         p = q->head;
223         while (p) {
224                 if (fn == NULL || (*fn) (p, arg)) {
225                         bool head = (p == q->head);
226                         if (head)
227                                 q->head = PKTLINK(p);
228                         else
229                                 PKTSETLINK(prev, PKTLINK(p));
230                         PKTSETLINK(p, NULL);
231                         PKTFREE(osh, p, dir);
232                         q->len--;
233                         pq->len--;
234                         p = (head ? q->head : PKTLINK(prev));
235                 } else {
236                         prev = p;
237                         p = PKTLINK(p);
238                 }
239         }
240
241         if (q->head == NULL) {
242                 ASSERT(q->len == 0);
243                 q->tail = NULL;
244         }
245 }
246
247 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
248 {
249         int prec;
250         for (prec = 0; prec < pq->num_prec; prec++)
251                 pktq_pflush(osh, pq, prec, dir, fn, arg);
252         if (fn == NULL)
253                 ASSERT(pq->len == 0);
254 }
255 #endif /* BRCM_FULLMAC */
256
257 void pktq_init(struct pktq *pq, int num_prec, int max_len)
258 {
259         int prec;
260
261         ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
262
263         /* pq is variable size; only zero out what's requested */
264         bzero(pq,
265               offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
266
267         pq->num_prec = (u16) num_prec;
268
269         pq->max = (u16) max_len;
270
271         for (prec = 0; prec < num_prec; prec++)
272                 pq->q[prec].max = pq->max;
273 }
274
275 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
276 {
277         int prec;
278
279         if (pq->len == 0)
280                 return NULL;
281
282         for (prec = 0; prec < pq->hi_prec; prec++)
283                 if (pq->q[prec].head)
284                         break;
285
286         if (prec_out)
287                 *prec_out = prec;
288
289         return pq->q[prec].tail;
290 }
291
292 /* Return sum of lengths of a specific set of precedences */
293 int pktq_mlen(struct pktq *pq, uint prec_bmp)
294 {
295         int prec, len;
296
297         len = 0;
298
299         for (prec = 0; prec <= pq->hi_prec; prec++)
300                 if (prec_bmp & (1 << prec))
301                         len += pq->q[prec].len;
302
303         return len;
304 }
305 /* Priority dequeue from a specific set of precedences */
306 void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
307 {
308         struct pktq_prec *q;
309         void *p;
310         int prec;
311
312         if (pq->len == 0)
313                 return NULL;
314
315         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
316                 pq->hi_prec--;
317
318         while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
319                 if (prec-- == 0)
320                         return NULL;
321
322         q = &pq->q[prec];
323
324         p = q->head;
325         if (p == NULL)
326                 return NULL;
327
328         q->head = PKTLINK(p);
329         if (q->head == NULL)
330                 q->tail = NULL;
331
332         q->len--;
333
334         if (prec_out)
335                 *prec_out = prec;
336
337         pq->len--;
338
339         PKTSETLINK(p, NULL);
340
341         return p;
342 }
343
344 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
345 int bcm_ether_atoe(char *p, struct ether_addr *ea)
346 {
347         int i = 0;
348
349         for (;;) {
350                 ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
351                 if (!*p++ || i == 6)
352                         break;
353         }
354
355         return i == 6;
356 }
357
358 /*
359  * Search the name=value vars for a specific one and return its value.
360  * Returns NULL if not found.
361  */
362 char *getvar(char *vars, const char *name)
363 {
364         char *s;
365         int len;
366
367         if (!name)
368                 return NULL;
369
370         len = strlen(name);
371         if (len == 0)
372                 return NULL;
373
374         /* first look in vars[] */
375         for (s = vars; s && *s;) {
376                 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
377                         return &s[len + 1];
378
379                 while (*s++)
380                         ;
381         }
382 #ifdef BRCM_FULLMAC
383         return NULL;
384 #else
385         /* then query nvram */
386         return nvram_get(name);
387 #endif
388 }
389
390 /*
391  * Search the vars for a specific one and return its value as
392  * an integer. Returns 0 if not found.
393  */
394 int getintvar(char *vars, const char *name)
395 {
396         char *val;
397
398         val = getvar(vars, name);
399         if (val == NULL)
400                 return 0;
401
402         return simple_strtoul(val, NULL, 0);
403 }
404
405 #if defined(BCMDBG)
406 /* pretty hex print a pkt buffer chain */
407 void prpkt(const char *msg, osl_t *osh, void *p0)
408 {
409         void *p;
410
411         if (msg && (msg[0] != '\0'))
412                 printf("%s:\n", msg);
413
414         for (p = p0; p; p = PKTNEXT(p))
415                 prhex(NULL, PKTDATA(p), PKTLEN(p));
416 }
417 #endif                          /* defined(BCMDBG) */
418
419 static char bcm_undeferrstr[BCME_STRLEN];
420
421 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
422
423 /* Convert the error codes into related error strings  */
424 const char *bcmerrorstr(int bcmerror)
425 {
426         /* check if someone added a bcmerror code but
427                  forgot to add errorstring */
428         ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
429
430         if (bcmerror > 0 || bcmerror < BCME_LAST) {
431                 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
432                          bcmerror);
433                 return bcm_undeferrstr;
434         }
435
436         ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
437
438         return bcmerrorstrtable[-bcmerror];
439 }
440
441 /* iovar table lookup */
442 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
443 {
444         const bcm_iovar_t *vi;
445         const char *lookup_name;
446
447         /* skip any ':' delimited option prefixes */
448         lookup_name = strrchr(name, ':');
449         if (lookup_name != NULL)
450                 lookup_name++;
451         else
452                 lookup_name = name;
453
454         ASSERT(table != NULL);
455
456         for (vi = table; vi->name; vi++) {
457                 if (!strcmp(vi->name, lookup_name))
458                         return vi;
459         }
460         /* ran to end of table */
461
462         return NULL;            /* var name not found */
463 }
464
465 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
466 {
467         int bcmerror = 0;
468
469         /* length check on io buf */
470         switch (vi->type) {
471         case IOVT_BOOL:
472         case IOVT_INT8:
473         case IOVT_INT16:
474         case IOVT_INT32:
475         case IOVT_UINT8:
476         case IOVT_UINT16:
477         case IOVT_UINT32:
478                 /* all integers are s32 sized args at the ioctl interface */
479                 if (len < (int)sizeof(int)) {
480                         bcmerror = BCME_BUFTOOSHORT;
481                 }
482                 break;
483
484         case IOVT_BUFFER:
485                 /* buffer must meet minimum length requirement */
486                 if (len < vi->minlen) {
487                         bcmerror = BCME_BUFTOOSHORT;
488                 }
489                 break;
490
491         case IOVT_VOID:
492                 if (!set) {
493                         /* Cannot return nil... */
494                         bcmerror = BCME_UNSUPPORTED;
495                 } else if (len) {
496                         /* Set is an action w/o parameters */
497                         bcmerror = BCME_BUFTOOLONG;
498                 }
499                 break;
500
501         default:
502                 /* unknown type for length check in iovar info */
503                 ASSERT(0);
504                 bcmerror = BCME_UNSUPPORTED;
505         }
506
507         return bcmerror;
508 }
509
510 /*******************************************************************************
511  * crc8
512  *
513  * Computes a crc8 over the input data using the polynomial:
514  *
515  *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
516  *
517  * The caller provides the initial value (either CRC8_INIT_VALUE
518  * or the previous returned value) to allow for processing of
519  * discontiguous blocks of data.  When generating the CRC the
520  * caller is responsible for complementing the final return value
521  * and inserting it into the byte stream.  When checking, a final
522  * return value of CRC8_GOOD_VALUE indicates a valid CRC.
523  *
524  * Reference: Dallas Semiconductor Application Note 27
525  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
526  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
527  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
528  *
529  * ****************************************************************************
530  */
531
532 static const u8 crc8_table[256] = {
533         0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
534         0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
535         0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
536         0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
537         0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
538         0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
539         0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
540         0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
541         0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
542         0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
543         0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
544         0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
545         0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
546         0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
547         0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
548         0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
549         0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
550         0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
551         0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
552         0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
553         0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
554         0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
555         0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
556         0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
557         0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
558         0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
559         0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
560         0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
561         0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
562         0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
563         0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
564         0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
565 };
566
567 #define CRC_INNER_LOOP(n, c, x) \
568         ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
569
570 u8 hndcrc8(u8 *pdata,   /* pointer to array of data to process */
571                          uint nbytes,   /* number of input data bytes to process */
572                          u8 crc /* either CRC8_INIT_VALUE or previous return value */
573     ) {
574         /* hard code the crc loop instead of using CRC_INNER_LOOP macro
575          * to avoid the undefined and unnecessary (u8 >> 8) operation.
576          */
577         while (nbytes-- > 0)
578                 crc = crc8_table[(crc ^ *pdata++) & 0xff];
579
580         return crc;
581 }
582
583 /*******************************************************************************
584  * crc16
585  *
586  * Computes a crc16 over the input data using the polynomial:
587  *
588  *       x^16 + x^12 +x^5 + 1
589  *
590  * The caller provides the initial value (either CRC16_INIT_VALUE
591  * or the previous returned value) to allow for processing of
592  * discontiguous blocks of data.  When generating the CRC the
593  * caller is responsible for complementing the final return value
594  * and inserting it into the byte stream.  When checking, a final
595  * return value of CRC16_GOOD_VALUE indicates a valid CRC.
596  *
597  * Reference: Dallas Semiconductor Application Note 27
598  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
599  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
600  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
601  *
602  * ****************************************************************************
603  */
604
605 static const u16 crc16_table[256] = {
606         0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
607         0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
608         0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
609         0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
610         0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
611         0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
612         0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
613         0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
614         0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
615         0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
616         0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
617         0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
618         0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
619         0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
620         0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
621         0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
622         0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
623         0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
624         0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
625         0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
626         0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
627         0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
628         0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
629         0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
630         0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
631         0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
632         0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
633         0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
634         0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
635         0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
636         0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
637         0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
638 };
639
640 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
641         uint nbytes,    /* number of input data bytes to process */
642         u16 crc /* either CRC16_INIT_VALUE or previous return value */
643     ) {
644         while (nbytes-- > 0)
645                 CRC_INNER_LOOP(16, crc, *pdata++);
646         return crc;
647 }
648
649 static const u32 crc32_table[256] = {
650         0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
651         0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
652         0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
653         0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
654         0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
655         0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
656         0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
657         0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
658         0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
659         0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
660         0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
661         0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
662         0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
663         0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
664         0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
665         0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
666         0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
667         0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
668         0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
669         0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
670         0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
671         0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
672         0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
673         0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
674         0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
675         0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
676         0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
677         0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
678         0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
679         0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
680         0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
681         0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
682         0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
683         0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
684         0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
685         0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
686         0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
687         0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
688         0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
689         0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
690         0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
691         0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
692         0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
693         0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
694         0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
695         0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
696         0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
697         0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
698         0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
699         0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
700         0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
701         0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
702         0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
703         0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
704         0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
705         0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
706         0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
707         0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
708         0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
709         0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
710         0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
711         0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
712         0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
713         0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
714 };
715
716 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
717                 uint nbytes,    /* number of input data bytes to process */
718                 u32 crc /* either CRC32_INIT_VALUE or previous
719                                          return value */
720 )
721 {
722         u8 *pend;
723 #ifdef __mips__
724         u8 tmp[4];
725         unsigned long *tptr = (unsigned long *) tmp;
726
727         /* in case the beginning of the buffer isn't aligned */
728         pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
729         nbytes -= (pend - pdata);
730         while (pdata < pend)
731                 CRC_INNER_LOOP(32, crc, *pdata++);
732
733         /* handle bulk of data as 32-bit words */
734         pend = pdata + (nbytes & 0xfffffffc);
735         while (pdata < pend) {
736                 *tptr = *(unsigned long *) pdata;
737                 pdata += sizeof(unsigned long *);
738                 CRC_INNER_LOOP(32, crc, tmp[0]);
739                 CRC_INNER_LOOP(32, crc, tmp[1]);
740                 CRC_INNER_LOOP(32, crc, tmp[2]);
741                 CRC_INNER_LOOP(32, crc, tmp[3]);
742         }
743
744         /* 1-3 bytes at end of buffer */
745         pend = pdata + (nbytes & 0x03);
746         while (pdata < pend)
747                 CRC_INNER_LOOP(32, crc, *pdata++);
748 #else
749         pend = pdata + nbytes;
750         while (pdata < pend)
751                 CRC_INNER_LOOP(32, crc, *pdata++);
752 #endif                          /* __mips__ */
753
754         return crc;
755 }
756 /*
757  * Traverse a string of 1-byte tag/1-byte length/variable-length value
758  * triples, returning a pointer to the substring whose first element
759  * matches tag
760  */
761 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
762 {
763         bcm_tlv_t *elt;
764         int totlen;
765
766         elt = (bcm_tlv_t *) buf;
767         totlen = buflen;
768
769         /* find tagged parameter */
770         while (totlen >= 2) {
771                 int len = elt->len;
772
773                 /* validate remaining totlen */
774                 if ((elt->id == key) && (totlen >= (len + 2)))
775                         return elt;
776
777                 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
778                 totlen -= (len + 2);
779         }
780
781         return NULL;
782 }
783
784
785 #if defined(BCMDBG)
786 int
787 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
788 {
789         int i;
790         char *p = buf;
791         char hexstr[16];
792         int slen = 0, nlen = 0;
793         u32 bit;
794         const char *name;
795
796         if (len < 2 || !buf)
797                 return 0;
798
799         buf[0] = '\0';
800
801         for (i = 0; flags != 0; i++) {
802                 bit = bd[i].bit;
803                 name = bd[i].name;
804                 if (bit == 0 && flags != 0) {
805                         /* print any unnamed bits */
806                         snprintf(hexstr, 16, "0x%X", flags);
807                         name = hexstr;
808                         flags = 0;      /* exit loop */
809                 } else if ((flags & bit) == 0)
810                         continue;
811                 flags &= ~bit;
812                 nlen = strlen(name);
813                 slen += nlen;
814                 /* count btwn flag space */
815                 if (flags != 0)
816                         slen += 1;
817                 /* need NULL char as well */
818                 if (len <= slen)
819                         break;
820                 /* copy NULL char but don't count it */
821                 strncpy(p, name, nlen + 1);
822                 p += nlen;
823                 /* copy btwn flag space and NULL char */
824                 if (flags != 0)
825                         p += snprintf(p, 2, " ");
826                 len -= slen;
827         }
828
829         /* indicate the str was too short */
830         if (flags != 0) {
831                 if (len < 2)
832                         p -= 2 - len;   /* overwrite last char */
833                 p += snprintf(p, 2, ">");
834         }
835
836         return (int)(p - buf);
837 }
838
839 /* print bytes formatted as hex to a string. return the resulting string length */
840 int bcm_format_hex(char *str, const void *bytes, int len)
841 {
842         int i;
843         char *p = str;
844         const u8 *src = (const u8 *)bytes;
845
846         for (i = 0; i < len; i++) {
847                 p += snprintf(p, 3, "%02X", *src);
848                 src++;
849         }
850         return (int)(p - str);
851 }
852 #endif                          /* defined(BCMDBG) */
853
854 /* pretty hex print a contiguous buffer */
855 void prhex(const char *msg, unsigned char *buf, uint nbytes)
856 {
857         char line[128], *p;
858         int len = sizeof(line);
859         int nchar;
860         uint i;
861
862         if (msg && (msg[0] != '\0'))
863                 printf("%s:\n", msg);
864
865         p = line;
866         for (i = 0; i < nbytes; i++) {
867                 if (i % 16 == 0) {
868                         nchar = snprintf(p, len, "  %04d: ", i);        /* line prefix */
869                         p += nchar;
870                         len -= nchar;
871                 }
872                 if (len > 0) {
873                         nchar = snprintf(p, len, "%02x ", buf[i]);
874                         p += nchar;
875                         len -= nchar;
876                 }
877
878                 if (i % 16 == 15) {
879                         printf("%s\n", line);   /* flush line */
880                         p = line;
881                         len = sizeof(line);
882                 }
883         }
884
885         /* flush last partial line */
886         if (p != line)
887                 printf("%s\n", line);
888 }
889
890 char *bcm_chipname(uint chipid, char *buf, uint len)
891 {
892         const char *fmt;
893
894         fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
895         snprintf(buf, len, fmt, chipid);
896         return buf;
897 }
898
899 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
900 {
901         uint len;
902
903         len = strlen(name) + 1;
904
905         if ((len + datalen) > buflen)
906                 return 0;
907
908         strncpy(buf, name, buflen);
909
910         /* append data onto the end of the name string */
911         memcpy(&buf[len], data, datalen);
912         len += datalen;
913
914         return len;
915 }
916
917 /* Quarter dBm units to mW
918  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
919  * Table is offset so the last entry is largest mW value that fits in
920  * a u16.
921  */
922
923 #define QDBM_OFFSET 153         /* Offset for first entry */
924 #define QDBM_TABLE_LEN 40       /* Table size */
925
926 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
927  * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
928  */
929 #define QDBM_TABLE_LOW_BOUND 6493       /* Low bound */
930
931 /* Largest mW value that will round down to the last table entry,
932  * QDBM_OFFSET + QDBM_TABLE_LEN-1.
933  * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
934  * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
935  */
936 #define QDBM_TABLE_HIGH_BOUND 64938     /* High bound */
937
938 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
939 /* qdBm:        +0      +1      +2      +3      +4      +5      +6      +7 */
940 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
941 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
942 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
943 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
944 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
945 };
946
947 u16 bcm_qdbm_to_mw(u8 qdbm)
948 {
949         uint factor = 1;
950         int idx = qdbm - QDBM_OFFSET;
951
952         if (idx >= QDBM_TABLE_LEN) {
953                 /* clamp to max u16 mW value */
954                 return 0xFFFF;
955         }
956
957         /* scale the qdBm index up to the range of the table 0-40
958          * where an offset of 40 qdBm equals a factor of 10 mW.
959          */
960         while (idx < 0) {
961                 idx += 40;
962                 factor *= 10;
963         }
964
965         /* return the mW value scaled down to the correct factor of 10,
966          * adding in factor/2 to get proper rounding.
967          */
968         return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
969 }
970 u8 bcm_mw_to_qdbm(u16 mw)
971 {
972         u8 qdbm;
973         int offset;
974         uint mw_uint = mw;
975         uint boundary;
976
977         /* handle boundary case */
978         if (mw_uint <= 1)
979                 return 0;
980
981         offset = QDBM_OFFSET;
982
983         /* move mw into the range of the table */
984         while (mw_uint < QDBM_TABLE_LOW_BOUND) {
985                 mw_uint *= 10;
986                 offset -= 40;
987         }
988
989         for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
990                 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
991                                                     nqdBm_to_mW_map[qdbm]) / 2;
992                 if (mw_uint < boundary)
993                         break;
994         }
995
996         qdbm += (u8) offset;
997
998         return qdbm;
999 }
1000 uint bcm_bitcount(u8 *bitmap, uint length)
1001 {
1002         uint bitcount = 0, i;
1003         u8 tmp;
1004         for (i = 0; i < length; i++) {
1005                 tmp = bitmap[i];
1006                 while (tmp) {
1007                         bitcount++;
1008                         tmp &= (tmp - 1);
1009                 }
1010         }
1011         return bitcount;
1012 }
1013 /* Initialization of bcmstrbuf structure */
1014 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1015 {
1016         b->origsize = b->size = size;
1017         b->origbuf = b->buf = buf;
1018 }
1019
1020 /* Buffer sprintf wrapper to guard against buffer overflow */
1021 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1022 {
1023         va_list ap;
1024         int r;
1025
1026         va_start(ap, fmt);
1027         r = vsnprintf(b->buf, b->size, fmt, ap);
1028
1029         /* Non Ansi C99 compliant returns -1,
1030          * Ansi compliant return r >= b->size,
1031          * bcmstdlib returns 0, handle all
1032          */
1033         if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1034                 b->size = 0;
1035         } else {
1036                 b->size -= r;
1037                 b->buf += r;
1038         }
1039
1040         va_end(ap);
1041
1042         return r;
1043 }
1044