Broadcom SDK and wireless driver: another attempt to update to ver. 5.10.147.0
[tomato.git] / release / src-rt / shared / bcmutils.c
blob1fa85180dee5217ffed5f3bc968c4055987abe7f
1 /*
2 * Driver O/S-independent utility routines
4 * Copyright (C) 2009, 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.
12 * $Id: bcmutils.c,v 1.218.2.19 2009/11/11 18:22:21 Exp $
15 #include <typedefs.h>
16 #include <bcmdefs.h>
17 #include <stdarg.h>
18 #include <bcmutils.h>
19 #ifdef BCMDRIVER
20 #include <osl.h>
21 #include <siutils.h>
22 #include <bcmnvram.h>
23 #else
24 #include <stdio.h>
25 #include <string.h>
26 #endif /* BCMDRIVER */
27 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_) || \
28 defined(EFI)
29 /* debatable */
30 #include <bcmstdlib.h>
31 #endif
32 #include <bcmendian.h>
33 #include <bcmdevs.h>
34 #include <proto/ethernet.h>
35 #include <proto/vlan.h>
36 #include <proto/bcmip.h>
37 #include <proto/802.1d.h>
39 #ifdef BCMPERFSTATS
40 #include <bcmperf.h>
41 #endif
43 #ifdef BCMDRIVER
44 #ifdef WLC_LOW
45 /* nvram vars cache */
46 static char *nvram_vars = NULL;
47 static int vars_len = -1;
48 #endif /* WLC_LOW */
50 /* copy a pkt buffer chain into a buffer */
51 uint
52 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
54 uint n, ret = 0;
56 if (len < 0)
57 len = 4096; /* "infinite" */
59 /* skip 'offset' bytes */
60 for (; p && offset; p = PKTNEXT(osh, p)) {
61 if (offset < (uint)PKTLEN(osh, p))
62 break;
63 offset -= PKTLEN(osh, p);
66 if (!p)
67 return 0;
69 /* copy the data */
70 for (; p && len; p = PKTNEXT(osh, p)) {
71 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
72 bcopy(PKTDATA(osh, p) + offset, buf, n);
73 buf += n;
74 len -= n;
75 ret += n;
76 offset = 0;
79 return ret;
82 /* copy a buffer into a pkt buffer chain */
83 uint
84 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
86 uint n, ret = 0;
88 /* skip 'offset' bytes */
89 for (; p && offset; p = PKTNEXT(osh, p)) {
90 if (offset < (uint)PKTLEN(osh, p))
91 break;
92 offset -= PKTLEN(osh, p);
95 if (!p)
96 return 0;
98 /* copy the data */
99 for (; p && len; p = PKTNEXT(osh, p)) {
100 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
101 bcopy(buf, PKTDATA(osh, p) + offset, n);
102 buf += n;
103 len -= n;
104 ret += n;
105 offset = 0;
108 return ret;
111 #ifdef NOTYET
112 /* copy data from one pkt buffer (chain) to another */
113 uint
114 pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, int maxlen)
116 uint8 *dp1, *dp2;
117 uint len1, len2, copylen, totallen;
119 for (; p1 && offs; p1 = PKTNEXT(osh, p1)) {
120 if (offs1 < (uint)PKTLEN(osh, p1))
121 break;
122 offs1 -= PKTLEN(osh, p1);
124 for (; p2 && offs; p2 = PKTNEXT(osh, p2)) {
125 if (offs2 < (uint)PKTLEN(osh, p2))
126 break;
127 offs2 -= PKTLEN(osh, p2);
130 /* Heck w/it, only need the above for now */
132 #endif /* NOTYET */
135 /* return total length of buffer chain */
136 uint BCMFASTPATH
137 pkttotlen(osl_t *osh, void *p)
139 uint total;
141 total = 0;
142 for (; p; p = PKTNEXT(osh, p))
143 total += PKTLEN(osh, p);
144 return (total);
147 /* return the last buffer of chained pkt */
148 void *
149 pktlast(osl_t *osh, void *p)
151 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
154 return (p);
157 /* count segments of a chained packet */
158 uint BCMFASTPATH
159 pktsegcnt(osl_t *osh, void *p)
161 uint cnt;
163 for (cnt = 0; p; p = PKTNEXT(osh, p))
164 cnt++;
166 return cnt;
171 * osl multiple-precedence packet queue
172 * hi_prec is always >= the number of the highest non-empty precedence
174 void * BCMFASTPATH
175 pktq_penq(struct pktq *pq, int prec, void *p)
177 struct pktq_prec *q;
179 ASSERT(prec >= 0 && prec < pq->num_prec);
180 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
182 ASSERT(!pktq_full(pq));
183 ASSERT(!pktq_pfull(pq, prec));
185 q = &pq->q[prec];
187 if (q->head)
188 PKTSETLINK(q->tail, p);
189 else
190 q->head = p;
192 q->tail = p;
193 q->len++;
195 pq->len++;
197 if (pq->hi_prec < prec)
198 pq->hi_prec = (uint8)prec;
200 return p;
203 void * BCMFASTPATH
204 pktq_penq_head(struct pktq *pq, int prec, void *p)
206 struct pktq_prec *q;
208 ASSERT(prec >= 0 && prec < pq->num_prec);
209 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
211 ASSERT(!pktq_full(pq));
212 ASSERT(!pktq_pfull(pq, prec));
214 q = &pq->q[prec];
216 if (q->head == NULL)
217 q->tail = p;
219 PKTSETLINK(p, q->head);
220 q->head = p;
221 q->len++;
223 pq->len++;
225 if (pq->hi_prec < prec)
226 pq->hi_prec = (uint8)prec;
228 return p;
231 void * BCMFASTPATH
232 pktq_pdeq(struct pktq *pq, int prec)
234 struct pktq_prec *q;
235 void *p;
237 ASSERT(prec >= 0 && prec < pq->num_prec);
239 q = &pq->q[prec];
241 if ((p = q->head) == NULL)
242 return NULL;
244 if ((q->head = PKTLINK(p)) == NULL)
245 q->tail = NULL;
247 q->len--;
249 pq->len--;
251 PKTSETLINK(p, NULL);
253 return p;
256 void * BCMFASTPATH
257 pktq_pdeq_tail(struct pktq *pq, int prec)
259 struct pktq_prec *q;
260 void *p, *prev;
262 ASSERT(prec >= 0 && prec < pq->num_prec);
264 q = &pq->q[prec];
266 if ((p = q->head) == NULL)
267 return NULL;
269 for (prev = NULL; p != q->tail; p = PKTLINK(p))
270 prev = p;
272 if (prev)
273 PKTSETLINK(prev, NULL);
274 else
275 q->head = NULL;
277 q->tail = prev;
278 q->len--;
280 pq->len--;
282 return p;
285 void
286 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
288 struct pktq_prec *q;
289 void *p;
291 q = &pq->q[prec];
292 p = q->head;
293 while (p) {
294 q->head = PKTLINK(p);
295 PKTSETLINK(p, NULL);
296 PKTFREE(osh, p, dir);
297 q->len--;
298 pq->len--;
299 p = q->head;
301 ASSERT(q->len == 0);
302 q->tail = NULL;
305 bool BCMFASTPATH
306 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
308 struct pktq_prec *q;
309 void *p;
311 ASSERT(prec >= 0 && prec < pq->num_prec);
313 if (!pktbuf)
314 return FALSE;
316 q = &pq->q[prec];
318 if (q->head == pktbuf) {
319 if ((q->head = PKTLINK(pktbuf)) == NULL)
320 q->tail = NULL;
321 } else {
322 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
324 if (p == NULL)
325 return FALSE;
327 PKTSETLINK(p, PKTLINK(pktbuf));
328 if (q->tail == pktbuf)
329 q->tail = p;
332 q->len--;
333 pq->len--;
334 PKTSETLINK(pktbuf, NULL);
335 return TRUE;
338 void
339 pktq_init(struct pktq *pq, int num_prec, int max_len)
341 int prec;
343 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
345 /* pq is variable size; only zero out what's requested */
346 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
348 pq->num_prec = (uint16)num_prec;
350 pq->max = (uint16)max_len;
352 for (prec = 0; prec < num_prec; prec++)
353 pq->q[prec].max = pq->max;
356 void * BCMFASTPATH
357 pktq_deq(struct pktq *pq, int *prec_out)
359 struct pktq_prec *q;
360 void *p;
361 int prec;
363 if (pq->len == 0)
364 return NULL;
366 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
367 pq->hi_prec--;
369 q = &pq->q[prec];
371 if ((p = q->head) == NULL)
372 return NULL;
374 if ((q->head = PKTLINK(p)) == NULL)
375 q->tail = NULL;
377 q->len--;
379 pq->len--;
381 if (prec_out)
382 *prec_out = prec;
384 PKTSETLINK(p, NULL);
386 return p;
389 void * BCMFASTPATH
390 pktq_deq_tail(struct pktq *pq, int *prec_out)
392 struct pktq_prec *q;
393 void *p, *prev;
394 int prec;
396 if (pq->len == 0)
397 return NULL;
399 for (prec = 0; prec < pq->hi_prec; prec++)
400 if (pq->q[prec].head)
401 break;
403 q = &pq->q[prec];
405 if ((p = q->head) == NULL)
406 return NULL;
408 for (prev = NULL; p != q->tail; p = PKTLINK(p))
409 prev = p;
411 if (prev)
412 PKTSETLINK(prev, NULL);
413 else
414 q->head = NULL;
416 q->tail = prev;
417 q->len--;
419 pq->len--;
421 if (prec_out)
422 *prec_out = prec;
424 PKTSETLINK(p, NULL);
426 return p;
429 void *
430 pktq_peek(struct pktq *pq, int *prec_out)
432 int prec;
434 if (pq->len == 0)
435 return NULL;
437 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
438 pq->hi_prec--;
440 if (prec_out)
441 *prec_out = prec;
443 return (pq->q[prec].head);
446 void *
447 pktq_peek_tail(struct pktq *pq, int *prec_out)
449 int prec;
451 if (pq->len == 0)
452 return NULL;
454 for (prec = 0; prec < pq->hi_prec; prec++)
455 if (pq->q[prec].head)
456 break;
458 if (prec_out)
459 *prec_out = prec;
461 return (pq->q[prec].tail);
464 void
465 pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
467 int prec;
468 for (prec = 0; prec < pq->num_prec; prec++)
469 pktq_pflush(osh, pq, prec, dir);
470 ASSERT(pq->len == 0);
473 /* Return sum of lengths of a specific set of precedences */
475 pktq_mlen(struct pktq *pq, uint prec_bmp)
477 int prec, len;
479 len = 0;
481 for (prec = 0; prec <= pq->hi_prec; prec++)
482 if (prec_bmp & (1 << prec))
483 len += pq->q[prec].len;
485 return len;
488 /* Priority dequeue from a specific set of precedences */
489 void * BCMFASTPATH
490 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
492 struct pktq_prec *q;
493 void *p;
494 int prec;
496 if (pq->len == 0)
497 return NULL;
499 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
500 pq->hi_prec--;
502 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
503 if (prec-- == 0)
504 return NULL;
506 q = &pq->q[prec];
508 if ((p = q->head) == NULL)
509 return NULL;
511 if ((q->head = PKTLINK(p)) == NULL)
512 q->tail = NULL;
514 q->len--;
516 if (prec_out)
517 *prec_out = prec;
519 pq->len--;
521 PKTSETLINK(p, NULL);
523 return p;
525 #endif /* BCMDRIVER */
528 const unsigned char bcm_ctype[] = {
529 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
530 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
531 _BCM_C, /* 8-15 */
532 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
533 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
534 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
535 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
536 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
537 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
538 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
539 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
540 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
541 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
542 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
543 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
544 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
545 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
546 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
547 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
549 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
550 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
551 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
552 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
553 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
554 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
555 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
556 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
557 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
558 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
559 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
560 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
561 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
564 ulong
565 BCMROMFN(bcm_strtoul)(char *cp, char **endp, uint base)
567 ulong result, last_result = 0, value;
568 bool minus;
570 minus = FALSE;
572 while (bcm_isspace(*cp))
573 cp++;
575 if (cp[0] == '+')
576 cp++;
577 else if (cp[0] == '-') {
578 minus = TRUE;
579 cp++;
582 if (base == 0) {
583 if (cp[0] == '0') {
584 if ((cp[1] == 'x') || (cp[1] == 'X')) {
585 base = 16;
586 cp = &cp[2];
587 } else {
588 base = 8;
589 cp = &cp[1];
591 } else
592 base = 10;
593 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
594 cp = &cp[2];
597 result = 0;
599 while (bcm_isxdigit(*cp) &&
600 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
601 result = result*base + value;
602 /* Detected overflow */
603 if (result < last_result && !minus)
604 return ((unsigned long) -1);
605 last_result = result;
606 cp++;
609 if (minus)
610 result = (ulong)(result * -1);
612 if (endp)
613 *endp = (char *)cp;
615 return (result);
619 BCMROMFN(bcm_atoi)(char *s)
621 return (int)bcm_strtoul(s, NULL, 10);
624 /* return pointer to location of substring 'needle' in 'haystack' */
625 char*
626 BCMROMFN(bcmstrstr)(char *haystack, char *needle)
628 int len, nlen;
629 int i;
631 if ((haystack == NULL) || (needle == NULL))
632 return (haystack);
634 nlen = strlen(needle);
635 len = strlen(haystack) - nlen + 1;
637 for (i = 0; i < len; i++)
638 if (memcmp(needle, &haystack[i], nlen) == 0)
639 return (&haystack[i]);
640 return (NULL);
643 char*
644 BCMROMFN(bcmstrcat)(char *dest, const char *src)
646 char *p;
648 p = dest + strlen(dest);
650 while ((*p++ = *src++) != '\0')
653 return (dest);
656 char*
657 BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size)
659 char *endp;
660 char *p;
662 p = dest + strlen(dest);
663 endp = p + size;
665 while (p != endp && (*p++ = *src++) != '\0')
668 return (dest);
671 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
673 BCMROMFN(bcm_ether_atoe)(char *p, struct ether_addr *ea)
675 int i = 0;
677 for (;;) {
678 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
679 if (!*p++ || i == 6)
680 break;
683 return (i == 6);
686 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
687 /* registry routine buffer preparation utility functions:
688 * parameter order is like strncpy, but returns count
689 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
691 ulong
692 wchar2ascii(
693 char *abuf,
694 ushort *wbuf,
695 ushort wbuflen,
696 ulong abuflen
699 ulong copyct = 1;
700 ushort i;
702 if (abuflen == 0)
703 return 0;
705 /* wbuflen is in bytes */
706 wbuflen /= sizeof(ushort);
708 for (i = 0; i < wbuflen; ++i) {
709 if (--abuflen == 0)
710 break;
711 *abuf++ = (char) *wbuf++;
712 ++copyct;
714 *abuf = '\0';
716 return copyct;
718 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
720 char *
721 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
723 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
724 snprintf(buf, 18, template,
725 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
726 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
727 return (buf);
730 char *
731 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
733 snprintf(buf, 16, "%d.%d.%d.%d",
734 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
735 return (buf);
738 #ifdef BCMDRIVER
740 void
741 bcm_mdelay(uint ms)
743 uint i;
745 for (i = 0; i < ms; i++) {
746 OSL_DELAY(1000);
751 * Search the name=value vars for a specific one and return its value.
752 * Returns NULL if not found.
754 char *
755 getvar(char *vars, const char *name)
757 #ifdef _MINOSL_
758 return NULL;
759 #else
760 char *s;
761 int len;
763 if (!name)
764 return NULL;
766 len = strlen(name);
767 if (len == 0)
768 return NULL;
770 /* first look in vars[] */
771 for (s = vars; s && *s;) {
772 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
773 return (&s[len+1]);
775 while (*s++)
779 /* then query nvram */
780 return (nvram_get(name));
781 #endif /* defined(_MINOSL_) */
785 * Search the vars for a specific one and return its value as
786 * an integer. Returns 0 if not found.
789 getintvar(char *vars, const char *name)
791 #ifdef _MINOSL_
792 return 0;
793 #else
794 char *val;
796 if ((val = getvar(vars, name)) == NULL)
797 return (0);
799 return (bcm_strtoul(val, NULL, 0));
800 #endif /* _MINOSL_ */
804 /* Search for token in comma separated token-string */
805 static int
806 findmatch(char *string, char *name)
808 uint len;
809 char *c;
811 len = strlen(name);
812 while ((c = strchr(string, ',')) != NULL) {
813 if (len == (uint)(c - string) && !strncmp(string, name, len))
814 return 1;
815 string = c + 1;
818 return (!strcmp(string, name));
821 /* Return gpio pin number assigned to the named pin
823 * Variable should be in format:
825 * gpio<N>=pin_name,pin_name
827 * This format allows multiple features to share the gpio with mutual
828 * understanding.
830 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
831 * and if def_pin is not used by others.
833 uint
834 getgpiopin(char *vars, char *pin_name, uint def_pin)
836 char name[] = "gpioXXXX";
837 char *val;
838 uint pin;
840 /* Go thru all possibilities till a match in pin name */
841 for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
842 snprintf(name, sizeof(name), "gpio%d", pin);
843 val = getvar(vars, name);
844 if (val && findmatch(val, pin_name))
845 return pin;
848 if (def_pin != GPIO_PIN_NOTDEFINED) {
849 /* make sure the default pin is not used by someone else */
850 snprintf(name, sizeof(name), "gpio%d", def_pin);
851 if (getvar(vars, name)) {
852 def_pin = GPIO_PIN_NOTDEFINED;
855 return def_pin;
859 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
861 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
862 static struct {
863 uint cycles;
864 char *fmt;
865 uint a1;
866 uint a2;
867 } logtab[LOGSIZE];
869 /* last entry logged */
870 static uint logi = 0;
871 /* next entry to read */
872 static uint readi = 0;
873 #endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
875 #ifdef BCMPERFSTATS
876 void
877 bcm_perf_enable()
879 BCMPERF_ENABLE_INSTRCOUNT();
880 BCMPERF_ENABLE_ICACHE_MISS();
881 BCMPERF_ENABLE_ICACHE_HIT();
884 void
885 bcmlog(char *fmt, uint a1, uint a2)
887 static uint last = 0;
888 uint cycles, i;
889 OSL_GETCYCLES(cycles);
891 i = logi;
893 logtab[i].cycles = cycles - last;
894 logtab[i].fmt = fmt;
895 logtab[i].a1 = a1;
896 logtab[i].a2 = a2;
898 logi = (i + 1) % LOGSIZE;
899 last = cycles;
903 void
904 bcmstats(char *fmt)
906 static uint last = 0;
907 static uint32 ic_miss = 0;
908 static uint32 instr_count = 0;
909 uint32 ic_miss_cur;
910 uint32 instr_count_cur;
911 uint cycles, i;
913 OSL_GETCYCLES(cycles);
914 BCMPERF_GETICACHE_MISS(ic_miss_cur);
915 BCMPERF_GETINSTRCOUNT(instr_count_cur);
917 i = logi;
919 logtab[i].cycles = cycles - last;
920 logtab[i].a1 = ic_miss_cur - ic_miss;
921 logtab[i].a2 = instr_count_cur - instr_count;
922 logtab[i].fmt = fmt;
924 logi = (i + 1) % LOGSIZE;
926 last = cycles;
927 instr_count = instr_count_cur;
928 ic_miss = ic_miss_cur;
932 void
933 bcmdumplog(char *buf, int size)
935 char *limit, *line;
936 int j = 0;
937 int num;
939 limit = buf + size - 80;
940 *buf = '\0';
942 num = logi - readi;
944 if (num < 0)
945 num += LOGSIZE;
947 /* print in chronological order */
949 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
950 if (logtab[readi].fmt == NULL)
951 continue;
952 line = buf;
953 buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles);
954 buf += snprintf(buf, (limit - buf), logtab[readi].fmt,
955 logtab[readi].a1, logtab[readi].a2);
956 buf += snprintf(buf, (limit - buf), "\n");
963 * Dump one log entry at a time.
964 * Return index of next entry or -1 when no more .
967 bcmdumplogent(char *buf, uint i)
969 bool hit;
972 * If buf is NULL, return the starting index,
973 * interpreting i as the indicator of last 'i' entries to dump.
975 if (buf == NULL) {
976 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
977 return ((logi - i) % LOGSIZE);
980 *buf = '\0';
982 ASSERT(i < LOGSIZE);
984 if (i == logi)
985 return (-1);
987 hit = FALSE;
988 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
989 if (logtab[i].fmt == NULL)
990 continue;
991 buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles);
992 buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
993 buf += sprintf(buf, "\n");
994 hit = TRUE;
997 return (i);
1000 #endif /* BCMPERFSTATS */
1002 #if defined(BCMTSTAMPEDLOGS)
1003 /* Store a TSF timestamp and a log line in the log buffer */
1004 void
1005 bcmtslog(uint32 tstamp, char *fmt, uint a1, uint a2)
1007 uint i = logi;
1009 logtab[i].cycles = tstamp;
1010 logtab[i].fmt = fmt;
1011 logtab[i].a1 = a1;
1012 logtab[i].a2 = a2;
1014 logi = (i + 1) % LOGSIZE;
1017 /* Print out a microsecond timestamp as "sec.ms.us " */
1018 void
1019 bcmprinttstamp(uint32 ticks)
1021 uint us, ms, sec;
1023 us = (ticks % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
1024 ms = ticks / TSF_TICKS_PER_MS;
1025 sec = ms / 1000;
1026 ms -= sec * 1000;
1027 printf("%04u.%03u.%03u ", sec, ms, us);
1030 /* Print out the log buffer with timestamps */
1031 void
1032 bcmprinttslogs(void)
1034 int j = 0;
1035 int num;
1037 num = logi - readi;
1038 if (num < 0)
1039 num += LOGSIZE;
1041 /* Format and print the log entries directly in chronological order */
1042 for (j = 0; j < num; readi = (readi + 1) % LOGSIZE, j++) {
1043 if (logtab[readi].fmt == NULL)
1044 continue;
1045 bcmprinttstamp(logtab[readi].cycles);
1046 printf(logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
1047 printf("\n");
1050 #endif /* BCMTSTAMPEDLOGS */
1053 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
1054 * Also updates the inplace vlan tag if requested.
1055 * For debugging, it returns an indication of what it did.
1057 uint BCMFASTPATH
1058 pktsetprio(void *pkt, bool update_vtag)
1060 struct ether_header *eh;
1061 struct ethervlan_header *evh;
1062 uint8 *pktdata;
1063 int priority = 0;
1064 int rc = 0;
1066 pktdata = (uint8 *) PKTDATA(NULL, pkt);
1067 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
1069 eh = (struct ether_header *) pktdata;
1071 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
1072 uint16 vlan_tag;
1073 int vlan_prio, dscp_prio = 0;
1075 evh = (struct ethervlan_header *)eh;
1077 vlan_tag = ntoh16(evh->vlan_tag);
1078 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
1080 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
1081 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
1082 uint8 tos_tc = IP_TOS46(ip_body);
1083 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1086 /* DSCP priority gets precedence over 802.1P (vlan tag) */
1087 if (dscp_prio != 0) {
1088 priority = dscp_prio;
1089 rc |= PKTPRIO_VDSCP;
1090 } else {
1091 priority = vlan_prio;
1092 rc |= PKTPRIO_VLAN;
1095 * If the DSCP priority is not the same as the VLAN priority,
1096 * then overwrite the priority field in the vlan tag, with the
1097 * DSCP priority value. This is required for Linux APs because
1098 * the VLAN driver on Linux, overwrites the skb->priority field
1099 * with the priority value in the vlan tag
1101 if (update_vtag && (priority != vlan_prio)) {
1102 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
1103 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
1104 evh->vlan_tag = hton16(vlan_tag);
1105 rc |= PKTPRIO_UPD;
1107 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
1108 uint8 *ip_body = pktdata + sizeof(struct ether_header);
1109 uint8 tos_tc = IP_TOS46(ip_body);
1110 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1111 rc |= PKTPRIO_DSCP;
1114 ASSERT(priority >= 0 && priority <= MAXPRIO);
1115 PKTSETPRIO(pkt, priority);
1116 return (rc | priority);
1119 static char bcm_undeferrstr[BCME_STRLEN];
1121 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1123 /* Convert the error codes into related error strings */
1124 const char *
1125 bcmerrorstr(int bcmerror)
1127 /* check if someone added a bcmerror code but forgot to add errorstring */
1128 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1130 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1131 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror);
1132 return bcm_undeferrstr;
1135 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1137 return bcmerrorstrtable[-bcmerror];
1140 #ifdef WLC_LOW
1141 static void
1142 BCMINITFN(bcm_nvram_refresh)(char *flash)
1144 int i;
1145 int ret = 0;
1147 ASSERT(flash != NULL);
1149 /* default "empty" vars cache */
1150 bzero(flash, 2);
1152 if ((ret = nvram_getall(flash, NVRAM_SPACE)))
1153 return;
1155 /* determine nvram length */
1156 for (i = 0; i < NVRAM_SPACE; i++) {
1157 if (flash[i] == '\0' && flash[i+1] == '\0')
1158 break;
1161 if (i > 1)
1162 vars_len = i + 2;
1163 else
1164 vars_len = 0;
1167 char *
1168 bcm_nvram_vars(uint *length)
1170 #ifndef BCMNVRAMR
1171 /* cache may be stale if nvram is read/write */
1172 if (nvram_vars) {
1173 ASSERT(!bcmreclaimed);
1174 bcm_nvram_refresh(nvram_vars);
1176 #endif
1177 if (length)
1178 *length = vars_len;
1179 return nvram_vars;
1182 /* copy nvram vars into locally-allocated multi-string array */
1184 BCMINITFN(bcm_nvram_cache)(void *sih)
1186 int ret = 0;
1187 void *osh;
1188 char *flash = NULL;
1190 if (vars_len >= 0) {
1191 #ifndef BCMNVRAMR
1192 bcm_nvram_refresh(nvram_vars);
1193 #endif
1194 return 0;
1197 osh = si_osh((si_t *)sih);
1199 /* allocate memory and read in flash */
1200 if (!(flash = MALLOC(osh, NVRAM_SPACE))) {
1201 ret = BCME_NOMEM;
1202 goto exit;
1205 bcm_nvram_refresh(flash);
1207 #ifdef BCMNVRAMR
1208 if (vars_len > 3) {
1209 /* copy into a properly-sized buffer */
1210 if (!(nvram_vars = MALLOC(osh, vars_len))) {
1211 ret = BCME_NOMEM;
1212 } else
1213 bcopy(flash, nvram_vars, vars_len);
1215 MFREE(osh, flash, NVRAM_SPACE);
1216 #else
1217 /* cache must be full size of nvram if read/write */
1218 nvram_vars = flash;
1219 #endif /* BCMNVRAMR */
1221 exit:
1222 return ret;
1224 #endif /* WLC_LOW */
1226 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1227 /* Add a packet to the pktlist */
1228 void
1229 pktlist_add(pktlist_info_t *pktlist, void *pkt)
1231 uint i;
1232 ASSERT(pktlist->count < PKTLIST_SIZE);
1234 /* Verify the packet is not already part of the list */
1235 for (i = 0; i < pktlist->count; i++) {
1236 if (pktlist->list[i] == pkt)
1237 ASSERT(0);
1239 pktlist->list[pktlist->count] = pkt;
1240 pktlist->count++;
1241 return;
1244 /* Remove a packet from the pktlist */
1245 void
1246 pktlist_remove(pktlist_info_t *pktlist, void *pkt)
1248 uint i;
1249 uint num = pktlist->count;
1251 /* find the index where pkt exists */
1252 for (i = 0; i < num; i++)
1254 /* check for the existence of pkt in the list */
1255 if (pktlist->list[i] == pkt)
1257 /* replace with the last element */
1258 pktlist->list[i] = pktlist->list[num-1];
1259 pktlist->count--;
1260 return;
1264 printf("%s: pktlist %p count %d pkt %p\n", __FUNCTION__,
1265 pktlist, pktlist->count, pkt);
1266 ASSERT(0);
1269 /* Dump the pktlist (and the contents of each packet if 'data'
1270 * is set). 'buf' should be large enough
1273 char *
1274 pktlist_dump(pktlist_info_t *pktlist, char *buf)
1276 char *obuf;
1277 uint i;
1279 obuf = buf;
1281 buf += sprintf(buf, "Packet list dump:\n");
1283 for (i = 0; i < (pktlist->count); i++) {
1284 buf += sprintf(buf, "0x%p\t", pktlist->list[i]);
1286 #ifdef NOTDEF /* Remove this ifdef to print pkttag and pktdata */
1287 if (PKTTAG(pktlist->list[i])) {
1288 /* Print pkttag */
1289 buf += sprintf(buf, "Pkttag(in hex): ");
1290 buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i]), OSL_PKTTAG_SZ);
1292 buf += sprintf(buf, "Pktdata(in hex): ");
1293 buf += bcm_format_hex(buf, PKTDATA(NULL, pktlist->list[i]),
1294 PKTLEN(NULL, pktlist->list[i]));
1295 #endif /* NOTDEF */
1297 buf += sprintf(buf, "\n");
1299 return obuf;
1301 #endif /* BCMDBG_PKT */
1303 /* iovar table lookup */
1304 const bcm_iovar_t*
1305 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1307 const bcm_iovar_t *vi;
1308 const char *lookup_name;
1310 /* skip any ':' delimited option prefixes */
1311 lookup_name = strrchr(name, ':');
1312 if (lookup_name != NULL)
1313 lookup_name++;
1314 else
1315 lookup_name = name;
1317 ASSERT(table != NULL);
1319 for (vi = table; vi->name; vi++) {
1320 if (!strcmp(vi->name, lookup_name))
1321 return vi;
1323 /* ran to end of table */
1325 return NULL; /* var name not found */
1329 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1331 int bcmerror = 0;
1333 /* length check on io buf */
1334 switch (vi->type) {
1335 case IOVT_BOOL:
1336 case IOVT_INT8:
1337 case IOVT_INT16:
1338 case IOVT_INT32:
1339 case IOVT_UINT8:
1340 case IOVT_UINT16:
1341 case IOVT_UINT32:
1342 /* all integers are int32 sized args at the ioctl interface */
1343 if (len < (int)sizeof(int)) {
1344 bcmerror = BCME_BUFTOOSHORT;
1346 break;
1348 case IOVT_BUFFER:
1349 /* buffer must meet minimum length requirement */
1350 if (len < vi->minlen) {
1351 bcmerror = BCME_BUFTOOSHORT;
1353 break;
1355 case IOVT_VOID:
1356 if (!set) {
1357 /* Cannot return nil... */
1358 bcmerror = BCME_UNSUPPORTED;
1359 } else if (len) {
1360 /* Set is an action w/o parameters */
1361 bcmerror = BCME_BUFTOOLONG;
1363 break;
1365 default:
1366 /* unknown type for length check in iovar info */
1367 ASSERT(0);
1368 bcmerror = BCME_UNSUPPORTED;
1371 return bcmerror;
1374 #endif /* BCMDRIVER */
1377 /*******************************************************************************
1378 * crc8
1380 * Computes a crc8 over the input data using the polynomial:
1382 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1384 * The caller provides the initial value (either CRC8_INIT_VALUE
1385 * or the previous returned value) to allow for processing of
1386 * discontiguous blocks of data. When generating the CRC the
1387 * caller is responsible for complementing the final return value
1388 * and inserting it into the byte stream. When checking, a final
1389 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1391 * Reference: Dallas Semiconductor Application Note 27
1392 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1393 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1394 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1396 * ****************************************************************************
1399 static const uint8 crc8_table[256] = {
1400 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1401 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1402 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1403 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1404 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1405 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1406 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1407 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1408 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1409 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1410 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1411 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1412 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1413 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1414 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1415 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1416 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1417 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1418 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1419 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1420 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1421 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1422 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1423 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1424 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1425 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1426 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1427 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1428 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1429 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1430 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1431 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1434 #define CRC_INNER_LOOP(n, c, x) \
1435 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1437 uint8
1438 BCMROMFN(hndcrc8)(
1439 uint8 *pdata, /* pointer to array of data to process */
1440 uint nbytes, /* number of input data bytes to process */
1441 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1444 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1445 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1447 while (nbytes-- > 0)
1448 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1450 return crc;
1453 /*******************************************************************************
1454 * crc16
1456 * Computes a crc16 over the input data using the polynomial:
1458 * x^16 + x^12 +x^5 + 1
1460 * The caller provides the initial value (either CRC16_INIT_VALUE
1461 * or the previous returned value) to allow for processing of
1462 * discontiguous blocks of data. When generating the CRC the
1463 * caller is responsible for complementing the final return value
1464 * and inserting it into the byte stream. When checking, a final
1465 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1467 * Reference: Dallas Semiconductor Application Note 27
1468 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1469 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1470 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1472 * ****************************************************************************
1475 static const uint16 crc16_table[256] = {
1476 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1477 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1478 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1479 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1480 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1481 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1482 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1483 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1484 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1485 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1486 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1487 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1488 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1489 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1490 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1491 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1492 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1493 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1494 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1495 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1496 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1497 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1498 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1499 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1500 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1501 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1502 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1503 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1504 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1505 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1506 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1507 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1510 uint16
1511 BCMROMFN(hndcrc16)(
1512 uint8 *pdata, /* pointer to array of data to process */
1513 uint nbytes, /* number of input data bytes to process */
1514 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1517 while (nbytes-- > 0)
1518 CRC_INNER_LOOP(16, crc, *pdata++);
1519 return crc;
1522 static const uint32 crc32_table[256] = {
1523 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1524 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1525 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1526 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1527 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1528 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1529 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1530 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1531 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1532 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1533 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1534 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1535 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1536 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1537 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1538 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1539 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1540 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1541 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1542 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1543 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1544 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1545 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1546 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1547 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1548 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1549 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1550 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1551 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1552 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1553 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1554 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1555 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1556 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1557 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1558 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1559 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1560 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1561 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1562 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1563 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1564 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1565 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1566 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1567 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1568 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1569 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1570 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1571 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1572 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1573 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1574 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1575 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1576 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1577 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1578 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1579 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1580 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1581 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1582 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1583 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1584 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1585 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1586 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1589 uint32
1590 BCMROMFN(hndcrc32)(
1591 uint8 *pdata, /* pointer to array of data to process */
1592 uint nbytes, /* number of input data bytes to process */
1593 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
1596 uint8 *pend;
1597 #ifdef __mips__
1598 uint8 tmp[4];
1599 ulong *tptr = (ulong *)tmp;
1601 /* in case the beginning of the buffer isn't aligned */
1602 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1603 nbytes -= (pend - pdata);
1604 while (pdata < pend)
1605 CRC_INNER_LOOP(32, crc, *pdata++);
1607 /* handle bulk of data as 32-bit words */
1608 pend = pdata + (nbytes & 0xfffffffc);
1609 while (pdata < pend) {
1610 *tptr = *(ulong *)pdata;
1611 pdata += sizeof(ulong *);
1612 CRC_INNER_LOOP(32, crc, tmp[0]);
1613 CRC_INNER_LOOP(32, crc, tmp[1]);
1614 CRC_INNER_LOOP(32, crc, tmp[2]);
1615 CRC_INNER_LOOP(32, crc, tmp[3]);
1618 /* 1-3 bytes at end of buffer */
1619 pend = pdata + (nbytes & 0x03);
1620 while (pdata < pend)
1621 CRC_INNER_LOOP(32, crc, *pdata++);
1622 #else
1623 pend = pdata + nbytes;
1624 while (pdata < pend)
1625 CRC_INNER_LOOP(32, crc, *pdata++);
1626 #endif /* __mips__ */
1628 return crc;
1631 #ifdef notdef
1632 #define CLEN 1499 /* CRC Length */
1633 #define CBUFSIZ (CLEN+4)
1634 #define CNBUFS 5 /* # of bufs */
1636 void
1637 testcrc32(void)
1639 uint j, k, l;
1640 uint8 *buf;
1641 uint len[CNBUFS];
1642 uint32 crcr;
1643 uint32 crc32tv[CNBUFS] =
1644 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1646 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1648 /* step through all possible alignments */
1649 for (l = 0; l <= 4; l++) {
1650 for (j = 0; j < CNBUFS; j++) {
1651 len[j] = CLEN;
1652 for (k = 0; k < len[j]; k++)
1653 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1656 for (j = 0; j < CNBUFS; j++) {
1657 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1658 ASSERT(crcr == crc32tv[j]);
1662 MFREE(buf, CBUFSIZ*CNBUFS);
1663 return;
1665 #endif /* notdef */
1668 * Advance from the current 1-byte tag/1-byte length/variable-length value
1669 * triple, to the next, returning a pointer to the next.
1670 * If the current or next TLV is invalid (does not fit in given buffer length),
1671 * NULL is returned.
1672 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1673 * by the TLV parameter's length if it is valid.
1675 bcm_tlv_t *
1676 BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen)
1678 int len;
1680 /* validate current elt */
1681 if (!bcm_valid_tlv(elt, *buflen))
1682 return NULL;
1684 /* advance to next elt */
1685 len = elt->len;
1686 elt = (bcm_tlv_t*)(elt->data + len);
1687 *buflen -= (2 + len);
1689 /* validate next elt */
1690 if (!bcm_valid_tlv(elt, *buflen))
1691 return NULL;
1693 return elt;
1697 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1698 * triples, returning a pointer to the substring whose first element
1699 * matches tag
1701 bcm_tlv_t *
1702 BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key)
1704 bcm_tlv_t *elt;
1705 int totlen;
1707 elt = (bcm_tlv_t*)buf;
1708 totlen = buflen;
1710 /* find tagged parameter */
1711 while (totlen >= 2) {
1712 int len = elt->len;
1714 /* validate remaining totlen */
1715 if ((elt->id == key) && (totlen >= (len + 2)))
1716 return (elt);
1718 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1719 totlen -= (len + 2);
1722 return NULL;
1726 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1727 * triples, returning a pointer to the substring whose first element
1728 * matches tag. Stop parsing when we see an element whose ID is greater
1729 * than the target key.
1731 bcm_tlv_t *
1732 BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key)
1734 bcm_tlv_t *elt;
1735 int totlen;
1737 elt = (bcm_tlv_t*)buf;
1738 totlen = buflen;
1740 /* find tagged parameter */
1741 while (totlen >= 2) {
1742 uint id = elt->id;
1743 int len = elt->len;
1745 /* Punt if we start seeing IDs > than target key */
1746 if (id > key)
1747 return (NULL);
1749 /* validate remaining totlen */
1750 if ((id == key) && (totlen >= (len + 2)))
1751 return (elt);
1753 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1754 totlen -= (len + 2);
1756 return NULL;
1759 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1760 defined(BCMDBG_DUMP)
1762 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1764 int i;
1765 char* p = buf;
1766 char hexstr[16];
1767 int slen = 0, nlen = 0;
1768 uint32 bit;
1769 const char* name;
1771 if (len < 2 || !buf)
1772 return 0;
1774 buf[0] = '\0';
1775 len -= 1;
1777 for (i = 0; flags != 0; i++) {
1778 bit = bd[i].bit;
1779 name = bd[i].name;
1780 if (bit == 0 && flags) {
1781 /* print any unnamed bits */
1782 snprintf(hexstr, 16, "0x%X", flags);
1783 name = hexstr;
1784 flags = 0; /* exit loop */
1785 } else if ((flags & bit) == 0)
1786 continue;
1787 nlen = strlen(name);
1788 slen += nlen;
1789 if (len < slen)
1790 break;
1791 if (p != buf) p += snprintf(p, 2, " "); /* btwn flag space */
1792 strncpy(p, name, nlen + 1);
1793 p += (nlen + 1);
1794 flags &= ~bit;
1795 len -= slen;
1796 slen = 1; /* account for btwn flag space */
1799 /* indicate the str was too short */
1800 if (flags != 0) {
1801 if (len == 0)
1802 p--; /* overwrite last char */
1803 p += snprintf(p, 2, ">");
1806 return (int)(p - buf);
1809 /* print bytes formatted as hex to a string. return the resulting string length */
1811 bcm_format_hex(char *str, const void *bytes, int len)
1813 int i;
1814 char *p = str;
1815 const uint8 *src = (const uint8*)bytes;
1817 for (i = 0; i < len; i++) {
1818 p += snprintf(p, 3, "%02X", *src);
1819 src++;
1821 return (int)(p - str);
1824 /* pretty hex print a contiguous buffer */
1825 void
1826 prhex(const char *msg, uchar *buf, uint nbytes)
1828 char line[128], *p;
1829 int len = sizeof(line);
1830 int nchar;
1831 uint i;
1833 if (msg && (msg[0] != '\0'))
1834 printf("%s:\n", msg);
1836 p = line;
1837 for (i = 0; i < nbytes; i++) {
1838 if (i % 16 == 0) {
1839 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1840 p += nchar;
1841 len -= nchar;
1843 if (len > 0) {
1844 nchar = snprintf(p, len, "%02x ", buf[i]);
1845 p += nchar;
1846 len -= nchar;
1849 if (i % 16 == 15) {
1850 printf("%s\n", line); /* flush line */
1851 p = line;
1852 len = sizeof(line);
1856 /* flush last partial line */
1857 if (p != line)
1858 printf("%s\n", line);
1860 #endif
1863 char *
1864 bcm_chipname(uint chipid, char *buf, uint len)
1866 const char *fmt;
1868 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1869 snprintf(buf, len, fmt, chipid);
1870 return buf;
1873 /* Produce a human-readable string for boardrev */
1874 char *
1875 bcm_brev_str(uint32 brev, char *buf)
1877 if (brev < 0x100)
1878 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1879 else
1880 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1882 return (buf);
1885 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1887 /* dump large strings to console */
1888 void
1889 printbig(char *buf)
1891 uint len, max_len;
1892 char c;
1894 len = strlen(buf);
1896 max_len = BUFSIZE_TODUMP_ATONCE;
1898 while (len > max_len) {
1899 c = buf[max_len];
1900 buf[max_len] = '\0';
1901 printf("%s", buf);
1902 buf[max_len] = c;
1904 buf += max_len;
1905 len -= max_len;
1907 /* print the remaining string */
1908 printf("%s\n", buf);
1909 return;
1912 /* routine to dump fields in a fileddesc structure */
1913 uint
1914 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
1915 char *buf, uint32 bufsize)
1917 uint filled_len;
1918 int len;
1919 struct fielddesc *cur_ptr;
1921 filled_len = 0;
1922 cur_ptr = fielddesc_array;
1924 while (bufsize > 1) {
1925 if (cur_ptr->nameandfmt == NULL)
1926 break;
1927 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1928 read_rtn(arg0, arg1, cur_ptr->offset));
1929 /* check for snprintf overflow or error */
1930 if (len < 0 || (uint32)len >= bufsize)
1931 len = bufsize - 1;
1932 buf += len;
1933 bufsize -= len;
1934 filled_len += len;
1935 cur_ptr++;
1937 return filled_len;
1940 uint
1941 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1943 uint len;
1945 len = strlen(name) + 1;
1947 if ((len + datalen) > buflen)
1948 return 0;
1950 strncpy(buf, name, buflen);
1952 /* append data onto the end of the name string */
1953 memcpy(&buf[len], data, datalen);
1954 len += datalen;
1956 return len;
1960 /* Quarter dBm units to mW
1961 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1962 * Table is offset so the last entry is largest mW value that fits in
1963 * a uint16.
1966 #define QDBM_OFFSET 153 /* Offset for first entry */
1967 #define QDBM_TABLE_LEN 40 /* Table size */
1969 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1970 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1972 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1974 /* Largest mW value that will round down to the last table entry,
1975 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1976 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1978 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1980 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1981 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1982 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1983 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1984 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1985 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1986 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1989 uint16
1990 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm)
1992 uint factor = 1;
1993 int idx = qdbm - QDBM_OFFSET;
1995 if (idx >= QDBM_TABLE_LEN) {
1996 /* clamp to max uint16 mW value */
1997 return 0xFFFF;
2000 /* scale the qdBm index up to the range of the table 0-40
2001 * where an offset of 40 qdBm equals a factor of 10 mW.
2003 while (idx < 0) {
2004 idx += 40;
2005 factor *= 10;
2008 /* return the mW value scaled down to the correct factor of 10,
2009 * adding in factor/2 to get proper rounding.
2011 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
2014 uint8
2015 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw)
2017 uint8 qdbm;
2018 int offset;
2019 uint mw_uint = mw;
2020 uint boundary;
2022 /* handle boundary case */
2023 if (mw_uint <= 1)
2024 return 0;
2026 offset = QDBM_OFFSET;
2028 /* move mw into the range of the table */
2029 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
2030 mw_uint *= 10;
2031 offset -= 40;
2034 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
2035 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
2036 nqdBm_to_mW_map[qdbm])/2;
2037 if (mw_uint < boundary) break;
2040 qdbm += (uint8)offset;
2042 return (qdbm);
2046 uint
2047 BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length)
2049 uint bitcount = 0, i;
2050 uint8 tmp;
2051 for (i = 0; i < length; i++) {
2052 tmp = bitmap[i];
2053 while (tmp) {
2054 bitcount++;
2055 tmp &= (tmp - 1);
2058 return bitcount;
2062 #ifdef BCMDRIVER
2064 /* Initialization of bcmstrbuf structure */
2065 void
2066 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
2068 b->origsize = b->size = size;
2069 b->origbuf = b->buf = buf;
2072 /* Buffer sprintf wrapper to guard against buffer overflow */
2074 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
2076 va_list ap;
2077 int r;
2079 va_start(ap, fmt);
2080 r = vsnprintf(b->buf, b->size, fmt, ap);
2082 /* Non Ansi C99 compliant returns -1,
2083 * Ansi compliant return r >= b->size,
2084 * bcmstdlib returns 0, handle all
2086 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
2087 b->size = 0;
2088 } else {
2089 b->size -= r;
2090 b->buf += r;
2093 va_end(ap);
2095 return r;
2098 void
2099 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
2101 int i;
2103 for (i = 0; i < num_bytes; i++) {
2104 num[i] += amount;
2105 if (num[i] >= amount)
2106 break;
2107 amount = 1;
2112 bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
2114 int i;
2116 for (i = nbytes - 1; i >= 0; i--) {
2117 if (arg1[i] != arg2[i])
2118 return (arg1[i] - arg2[i]);
2120 return 0;
2123 void
2124 bcm_print_bytes(char *name, const uchar *data, int len)
2126 int i;
2127 int per_line = 0;
2129 printf("%s: %d \n", name ? name : "", len);
2130 for (i = 0; i < len; i++) {
2131 printf("%02x ", *data++);
2132 per_line++;
2133 if (per_line == 16) {
2134 per_line = 0;
2135 printf("\n");
2138 printf("\n");
2141 #endif /* BCMDRIVER */