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