GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / shared / bcmutils.c
blobca8c950437d442b22f7abf99ac9ccc6066818b1b
1 /*
2 * Driver O/S-independent utility routines
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $Id: bcmutils.c 371895 2012-11-29 20:15:08Z $
20 #include <bcm_cfg.h>
21 #include <typedefs.h>
22 #include <bcmdefs.h>
23 #if defined(__FreeBSD__) || defined(__NetBSD__)
24 #include <sys/param.h>
25 #if __NetBSD_Version__ >= 500000003
26 #include <sys/stdarg.h>
27 #else
28 #include <machine/stdarg.h>
29 #endif
30 #else
31 #include <stdarg.h>
32 #endif /* NetBSD */
33 #ifdef BCMDRIVER
35 #include <osl.h>
36 #include <bcmutils.h>
37 #include <siutils.h>
38 #include <bcmnvram.h>
40 #else /* !BCMDRIVER */
42 #include <stdio.h>
43 #include <string.h>
44 #include <bcmutils.h>
46 #if defined(BCMEXTSUP)
47 #include <bcm_osl.h>
48 #endif
51 #endif /* !BCMDRIVER */
53 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_)
54 #include <bcmstdlib.h>
55 #endif
56 #include <bcmendian.h>
57 #include <bcmdevs.h>
58 #include <proto/ethernet.h>
59 #include <proto/vlan.h>
60 #include <proto/bcmip.h>
61 #include <proto/802.1d.h>
62 #include <proto/802.11.h>
63 #ifdef BCMPERFSTATS
64 #include <bcmperf.h>
65 #endif
66 #include <proto/bcmipv6.h>
67 void *_bcmutils_dummy_fn = NULL;
69 #ifdef BCMDRIVER
71 #ifdef WLC_LOW
72 /* nvram vars cache */
73 static char *nvram_vars = NULL;
74 static int vars_len = -1;
75 #endif /* WLC_LOW */
77 int
78 pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx)
80 int i, err = BCME_OK;
81 void *p;
82 int pktplen;
84 ASSERT(pktp != NULL);
85 ASSERT(osh != NULL);
86 ASSERT(pplen != NULL);
88 pktplen = *pplen;
90 bzero(pktp, sizeof(pktpool_t));
91 pktp->inited = TRUE;
92 pktp->istx = istx ? TRUE : FALSE;
93 pktp->plen = (uint16)plen;
94 *pplen = 0;
96 pktp->maxlen = PKTPOOL_LEN_MAX;
97 if (pktplen > pktp->maxlen)
98 pktplen = pktp->maxlen;
100 for (i = 0; i < pktplen; i++) {
101 p = PKTGET(osh, plen, pktp->istx);
102 if (p == NULL) {
103 /* Not able to allocate all requested pkts
104 * so just return what was actually allocated
105 * We can add to the pool later
107 if (pktp->w == 0)
108 err = BCME_NOMEM;
110 goto exit;
113 PKTSETPOOL(osh, p, TRUE, pktp);
114 pktp->q[i] = p;
115 pktp->w++;
116 pktp->len++;
117 #ifdef BCMDBG_POOL
118 pktp->dbg_q[pktp->dbg_qlen++].p = p;
119 #endif
122 exit:
123 *pplen = pktp->w;
124 pktp->len++; /* Add one for end */
125 return err;
129 pktpool_deinit(osl_t *osh, pktpool_t *pktp)
131 int i;
132 int cnt;
134 ASSERT(osh != NULL);
135 ASSERT(pktp != NULL);
137 cnt = pktp->len;
138 for (i = 0; i < cnt; i++) {
139 if (pktp->q[i] != NULL) {
140 PKTSETPOOL(osh, pktp->q[i], FALSE, NULL);
141 PKTFREE(osh, pktp->q[i], pktp->istx);
142 pktp->q[i] = NULL;
143 pktp->len--;
145 #ifdef BCMDBG_POOL
146 if (pktp->dbg_q[i].p != NULL)
147 pktp->dbg_q[i].p = NULL;
148 #endif
150 pktp->inited = FALSE;
152 /* Are there still pending pkts? */
153 ASSERT(pktpool_len(pktp) == 0);
155 return 0;
159 pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal)
161 void *p;
162 int err = 0;
163 int len, psize, maxlen;
165 ASSERT(pktpool_plen(pktp) != 0);
167 maxlen = pktpool_maxlen(pktp);
168 psize = minimal ? (maxlen >> 2) : maxlen;
169 len = pktpool_len(pktp);
170 for (; len < psize; len++) {
171 p = PKTGET(osh, pktpool_plen(pktp), FALSE);
172 if (p == NULL) {
173 err = BCME_NOMEM;
174 break;
177 if (pktpool_add(pktp, p) != BCME_OK) {
178 PKTFREE(osh, p, FALSE);
179 err = BCME_ERROR;
180 break;
184 return err;
187 uint16
188 pktpool_avail(pktpool_t *pktp)
190 if (pktp->w == pktp->r)
191 return 0;
193 return (pktp->w > pktp->r) ? (pktp->w - pktp->r) : ((pktp->len) - (pktp->r - pktp->w));
196 static void *
197 pktpool_deq(pktpool_t *pktp)
199 void *p;
201 if (pktp->r == pktp->w)
202 return NULL;
204 p = pktp->q[pktp->r];
205 ASSERT(p != NULL);
207 pktp->q[pktp->r++] = NULL;
208 pktp->r %= (pktp->len);
210 return p;
213 static void
214 pktpool_enq(pktpool_t *pktp, void *p)
216 uint16 next;
218 ASSERT(p != NULL);
220 next = (pktp->w + 1) % (pktp->len);
221 if (next == pktp->r) {
222 /* Should not happen; otherwise pkt leak */
223 ASSERT(0);
224 return;
227 ASSERT(pktp->q[pktp->w] == NULL);
229 pktp->q[pktp->w] = p;
230 pktp->w = next;
234 pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
236 int i;
238 ASSERT(cb != NULL);
240 i = pktp->cbcnt;
241 if (i == PKTPOOL_CB_MAX)
242 return BCME_ERROR;
244 ASSERT(pktp->cbs[i].cb == NULL);
245 pktp->cbs[i].cb = cb;
246 pktp->cbs[i].arg = arg;
247 pktp->cbcnt++;
249 return 0;
253 pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
255 int i;
257 ASSERT(cb != NULL);
259 i = pktp->ecbcnt;
260 if (i == PKTPOOL_CB_MAX)
261 return BCME_ERROR;
263 ASSERT(pktp->ecbs[i].cb == NULL);
264 pktp->ecbs[i].cb = cb;
265 pktp->ecbs[i].arg = arg;
266 pktp->ecbcnt++;
268 return 0;
271 static int
272 pktpool_empty_notify(pktpool_t *pktp)
274 int i;
276 pktp->empty = TRUE;
277 for (i = 0; i < pktp->ecbcnt; i++) {
278 ASSERT(pktp->ecbs[i].cb != NULL);
279 pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg);
281 pktp->empty = FALSE;
283 return 0;
286 #ifdef BCMDBG_POOL
288 pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
290 int i;
292 ASSERT(cb);
294 i = pktp->dbg_cbcnt;
295 if (i == PKTPOOL_CB_MAX)
296 return BCME_ERROR;
298 ASSERT(pktp->dbg_cbs[i].cb == NULL);
299 pktp->dbg_cbs[i].cb = cb;
300 pktp->dbg_cbs[i].arg = arg;
301 pktp->dbg_cbcnt++;
303 return 0;
306 int pktpool_dbg_notify(pktpool_t *pktp);
309 pktpool_dbg_notify(pktpool_t *pktp)
311 int i;
313 for (i = 0; i < pktp->dbg_cbcnt; i++) {
314 ASSERT(pktp->dbg_cbs[i].cb);
315 pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg);
318 return 0;
322 pktpool_dbg_dump(pktpool_t *pktp)
324 int i;
326 printf("pool len=%d maxlen=%d\n", pktp->dbg_qlen, pktp->maxlen);
327 for (i = 0; i < pktp->dbg_qlen; i++) {
328 ASSERT(pktp->dbg_q[i].p);
329 printf("%d, p: 0x%x dur:%lu us state:%d\n", i,
330 pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p));
333 return 0;
337 pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats)
339 int i;
340 int state;
342 bzero(stats, sizeof(pktpool_stats_t));
343 for (i = 0; i < pktp->dbg_qlen; i++) {
344 ASSERT(pktp->dbg_q[i].p != NULL);
346 state = PKTPOOLSTATE(pktp->dbg_q[i].p);
347 switch (state) {
348 case POOL_TXENQ:
349 stats->enq++; break;
350 case POOL_TXDH:
351 stats->txdh++; break;
352 case POOL_TXD11:
353 stats->txd11++; break;
354 case POOL_RXDH:
355 stats->rxdh++; break;
356 case POOL_RXD11:
357 stats->rxd11++; break;
358 case POOL_RXFILL:
359 stats->rxfill++; break;
360 case POOL_IDLE:
361 stats->idle++; break;
365 return 0;
369 pktpool_start_trigger(pktpool_t *pktp, void *p)
371 uint32 cycles, i;
373 if (!PKTPOOL(NULL, p))
374 return 0;
376 OSL_GETCYCLES(cycles);
378 for (i = 0; i < pktp->dbg_qlen; i++) {
379 ASSERT(pktp->dbg_q[i].p != NULL);
381 if (pktp->dbg_q[i].p == p) {
382 pktp->dbg_q[i].cycles = cycles;
383 break;
387 return 0;
390 int pktpool_stop_trigger(pktpool_t *pktp, void *p);
392 pktpool_stop_trigger(pktpool_t *pktp, void *p)
394 uint32 cycles, i;
396 if (!PKTPOOL(NULL, p))
397 return 0;
399 OSL_GETCYCLES(cycles);
401 for (i = 0; i < pktp->dbg_qlen; i++) {
402 ASSERT(pktp->dbg_q[i].p != NULL);
404 if (pktp->dbg_q[i].p == p) {
405 if (pktp->dbg_q[i].cycles == 0)
406 break;
408 if (cycles >= pktp->dbg_q[i].cycles)
409 pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles;
410 else
411 pktp->dbg_q[i].dur =
412 (((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1;
414 pktp->dbg_q[i].cycles = 0;
415 break;
419 return 0;
421 #endif /* BCMDBG_POOL */
424 pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp)
426 ASSERT(pktp);
427 pktp->availcb_excl = NULL;
428 return 0;
432 pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb)
434 int i;
436 ASSERT(pktp);
437 ASSERT(pktp->availcb_excl == NULL);
438 for (i = 0; i < pktp->cbcnt; i++) {
439 if (cb == pktp->cbs[i].cb) {
440 pktp->availcb_excl = &pktp->cbs[i];
441 break;
445 if (pktp->availcb_excl == NULL)
446 return BCME_ERROR;
447 else
448 return 0;
451 static int
452 pktpool_avail_notify(pktpool_t *pktp)
454 int i, k, idx;
455 int avail;
457 ASSERT(pktp);
458 if (pktp->availcb_excl != NULL) {
459 pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg);
460 return 0;
463 k = pktp->cbcnt - 1;
464 for (i = 0; i < pktp->cbcnt; i++) {
465 avail = pktpool_avail(pktp);
467 if (avail) {
468 if (pktp->cbtoggle)
469 idx = i;
470 else
471 idx = k--;
473 ASSERT(pktp->cbs[idx].cb != NULL);
474 pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg);
478 /* Alternate between filling from head or tail
480 pktp->cbtoggle ^= 1;
482 return 0;
485 void *
486 pktpool_get(pktpool_t *pktp)
488 void *p;
490 p = pktpool_deq(pktp);
492 if (p == NULL) {
493 /* Notify and try to reclaim tx pkts */
494 if (pktp->ecbcnt)
495 pktpool_empty_notify(pktp);
497 p = pktpool_deq(pktp);
500 return p;
503 void
504 pktpool_free(pktpool_t *pktp, void *p)
506 ASSERT(p != NULL);
508 #ifdef BCMDBG_POOL
509 /* pktpool_stop_trigger(pktp, p); */
510 #endif
512 pktpool_enq(pktp, p);
514 if (pktp->emptycb_disable)
515 return;
517 if (pktp->cbcnt) {
518 if (pktp->empty == FALSE)
519 pktpool_avail_notify(pktp);
524 pktpool_add(pktpool_t *pktp, void *p)
526 ASSERT(p != NULL);
528 if (pktpool_len(pktp) == pktp->maxlen)
529 return BCME_RANGE;
531 ASSERT(pktpool_plen(pktp) == PKTLEN(NULL, p)); /* pkts in pool have same length */
532 PKTSETPOOL(NULL, p, TRUE, pktp);
534 pktp->len++;
535 if (pktp->r > pktp->w) {
536 /* Add to tail */
537 ASSERT(pktp->q[pktp->len - 1] == NULL);
538 pktp->q[pktp->len - 1] = p;
539 } else
540 pktpool_enq(pktp, p);
542 #ifdef BCMDBG_POOL
543 pktp->dbg_q[pktp->dbg_qlen++].p = p;
544 #endif
546 return 0;
550 pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen)
552 if (maxlen > PKTPOOL_LEN_MAX)
553 maxlen = PKTPOOL_LEN_MAX;
555 /* if pool is already beyond maxlen, then just cap it
556 * since we currently do not reduce the pool len
557 * already allocated
559 pktp->maxlen = (pktpool_len(pktp) > maxlen) ? pktpool_len(pktp) : maxlen;
561 return pktp->maxlen;
564 void
565 pktpool_emptycb_disable(pktpool_t *pktp, bool disable)
567 ASSERT(pktp);
569 pktp->emptycb_disable = disable;
572 bool
573 pktpool_emptycb_disabled(pktpool_t *pktp)
575 ASSERT(pktp);
576 return pktp->emptycb_disable;
579 /* copy a pkt buffer chain into a buffer */
580 uint
581 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
583 uint n, ret = 0;
585 if (len < 0)
586 len = 4096; /* "infinite" */
588 /* skip 'offset' bytes */
589 for (; p && offset; p = PKTNEXT(osh, p)) {
590 if (offset < (uint)PKTLEN(osh, p))
591 break;
592 offset -= PKTLEN(osh, p);
595 if (!p)
596 return 0;
598 /* copy the data */
599 for (; p && len; p = PKTNEXT(osh, p)) {
600 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
601 bcopy(PKTDATA(osh, p) + offset, buf, n);
602 buf += n;
603 len -= n;
604 ret += n;
605 offset = 0;
608 return ret;
611 /* copy a buffer into a pkt buffer chain */
612 uint
613 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
615 uint n, ret = 0;
617 /* skip 'offset' bytes */
618 for (; p && offset; p = PKTNEXT(osh, p)) {
619 if (offset < (uint)PKTLEN(osh, p))
620 break;
621 offset -= PKTLEN(osh, p);
624 if (!p)
625 return 0;
627 /* copy the data */
628 for (; p && len; p = PKTNEXT(osh, p)) {
629 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
630 bcopy(buf, PKTDATA(osh, p) + offset, n);
631 buf += n;
632 len -= n;
633 ret += n;
634 offset = 0;
637 return ret;
640 #ifdef NOTYET
641 /* copy data from one pkt buffer (chain) to another */
642 uint
643 pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, int maxlen)
645 uint8 *dp1, *dp2;
646 uint len1, len2, copylen, totallen;
648 for (; p1 && offs; p1 = PKTNEXT(osh, p1)) {
649 if (offs1 < (uint)PKTLEN(osh, p1))
650 break;
651 offs1 -= PKTLEN(osh, p1);
653 for (; p2 && offs; p2 = PKTNEXT(osh, p2)) {
654 if (offs2 < (uint)PKTLEN(osh, p2))
655 break;
656 offs2 -= PKTLEN(osh, p2);
659 /* Heck w/it, only need the above for now */
661 #endif /* NOTYET */
664 /* return total length of buffer chain */
665 uint BCMFASTPATH
666 pkttotlen(osl_t *osh, void *p)
668 uint total;
669 int len;
671 total = 0;
672 for (; p; p = PKTNEXT(osh, p)) {
673 len = PKTLEN(osh, p);
674 #ifdef MACOSX
675 if (len < 0) {
676 /* Bad packet length, just drop and exit */
677 printf("wl: pkttotlen bad (%p,%d)\n", p, len);
678 break;
680 #endif /* MACOSX */
681 total += len;
684 return (total);
687 /* return the last buffer of chained pkt */
688 void *
689 pktlast(osl_t *osh, void *p)
691 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
694 return (p);
697 /* count segments of a chained packet */
698 uint BCMFASTPATH
699 pktsegcnt(osl_t *osh, void *p)
701 uint cnt;
703 for (cnt = 0; p; p = PKTNEXT(osh, p))
704 cnt++;
706 return cnt;
710 /* count segments of a chained packet */
711 uint BCMFASTPATH
712 pktsegcnt_war(osl_t *osh, void *p)
714 uint cnt;
715 uint8 *pktdata;
716 uint len, remain, align64;
718 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
719 cnt++;
720 len = PKTLEN(osh, p);
721 if (len > 128) {
722 pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
723 /* Check for page boundary straddle (2048B) */
724 if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
725 cnt++;
727 align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
728 align64 = (64 - align64) & 0x3f;
729 len -= align64; /* bytes from aligned 64B to end */
730 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
731 remain = len % 128;
732 if (remain > 0 && remain <= 4)
733 cnt++; /* add extra seg */
737 return cnt;
740 uint8 * BCMFASTPATH
741 pktdataoffset(osl_t *osh, void *p, uint offset)
743 uint total = pkttotlen(osh, p);
744 uint pkt_off = 0, len = 0;
745 uint8 *pdata = (uint8 *) PKTDATA(osh, p);
747 if (offset > total)
748 return NULL;
750 for (; p; p = PKTNEXT(osh, p)) {
751 pdata = (uint8 *) PKTDATA(osh, p);
752 pkt_off = offset - len;
753 len += PKTLEN(osh, p);
754 if (len > offset)
755 break;
757 return (uint8*) (pdata+pkt_off);
761 /* given a offset in pdata, find the pkt seg hdr */
762 void *
763 pktoffset(osl_t *osh, void *p, uint offset)
765 uint total = pkttotlen(osh, p);
766 uint len = 0;
768 if (offset > total)
769 return NULL;
771 for (; p; p = PKTNEXT(osh, p)) {
772 len += PKTLEN(osh, p);
773 if (len > offset)
774 break;
776 return p;
780 * osl multiple-precedence packet queue
781 * hi_prec is always >= the number of the highest non-empty precedence
783 void * BCMFASTPATH
784 pktq_penq(struct pktq *pq, int prec, void *p)
786 struct pktq_prec *q;
788 ASSERT(prec >= 0 && prec < pq->num_prec);
789 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
791 ASSERT(!pktq_full(pq));
792 ASSERT(!pktq_pfull(pq, prec));
794 q = &pq->q[prec];
796 if (q->head)
797 PKTSETLINK(q->tail, p);
798 else
799 q->head = p;
801 q->tail = p;
802 q->len++;
804 pq->len++;
806 if (pq->hi_prec < prec)
807 pq->hi_prec = (uint8)prec;
809 return p;
812 void * BCMFASTPATH
813 pktq_penq_head(struct pktq *pq, int prec, void *p)
815 struct pktq_prec *q;
817 ASSERT(prec >= 0 && prec < pq->num_prec);
818 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
820 ASSERT(!pktq_full(pq));
821 ASSERT(!pktq_pfull(pq, prec));
823 q = &pq->q[prec];
825 if (q->head == NULL)
826 q->tail = p;
828 PKTSETLINK(p, q->head);
829 q->head = p;
830 q->len++;
832 pq->len++;
834 if (pq->hi_prec < prec)
835 pq->hi_prec = (uint8)prec;
837 return p;
840 void * BCMFASTPATH
841 pktq_pdeq(struct pktq *pq, int prec)
843 struct pktq_prec *q;
844 void *p;
846 ASSERT(prec >= 0 && prec < pq->num_prec);
848 q = &pq->q[prec];
850 if ((p = q->head) == NULL)
851 return NULL;
853 if ((q->head = PKTLINK(p)) == NULL)
854 q->tail = NULL;
856 q->len--;
858 pq->len--;
860 PKTSETLINK(p, NULL);
862 return p;
865 void * BCMFASTPATH
866 pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p)
868 struct pktq_prec *q;
869 void *p;
871 ASSERT(prec >= 0 && prec < pq->num_prec);
873 q = &pq->q[prec];
875 if (prev_p == NULL)
876 return NULL;
878 if ((p = PKTLINK(prev_p)) == NULL)
879 return NULL;
881 if (q->tail == p)
882 q->tail = prev_p;
884 q->len--;
886 pq->len--;
888 PKTSETLINK(prev_p, PKTLINK(p));
889 PKTSETLINK(p, NULL);
891 return p;
894 void * BCMFASTPATH
895 pktq_pdeq_tail(struct pktq *pq, int prec)
897 struct pktq_prec *q;
898 void *p, *prev;
900 ASSERT(prec >= 0 && prec < pq->num_prec);
902 q = &pq->q[prec];
904 if ((p = q->head) == NULL)
905 return NULL;
907 for (prev = NULL; p != q->tail; p = PKTLINK(p))
908 prev = p;
910 if (prev)
911 PKTSETLINK(prev, NULL);
912 else
913 q->head = NULL;
915 q->tail = prev;
916 q->len--;
918 pq->len--;
920 return p;
923 void
924 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
926 struct pktq_prec *q;
927 void *p, *prev = NULL;
929 q = &pq->q[prec];
930 p = q->head;
931 while (p) {
932 if (fn == NULL || (*fn)(p, arg)) {
933 bool head = (p == q->head);
934 if (head)
935 q->head = PKTLINK(p);
936 else
937 PKTSETLINK(prev, PKTLINK(p));
938 PKTSETLINK(p, NULL);
939 PKTFREE(osh, p, dir);
940 q->len--;
941 pq->len--;
942 p = (head ? q->head : PKTLINK(prev));
943 } else {
944 prev = p;
945 p = PKTLINK(p);
949 if (q->head == NULL) {
950 ASSERT(q->len == 0);
951 q->tail = NULL;
955 bool BCMFASTPATH
956 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
958 struct pktq_prec *q;
959 void *p;
961 ASSERT(prec >= 0 && prec < pq->num_prec);
963 if (!pktbuf)
964 return FALSE;
966 q = &pq->q[prec];
968 if (q->head == pktbuf) {
969 if ((q->head = PKTLINK(pktbuf)) == NULL)
970 q->tail = NULL;
971 } else {
972 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
974 if (p == NULL)
975 return FALSE;
977 PKTSETLINK(p, PKTLINK(pktbuf));
978 if (q->tail == pktbuf)
979 q->tail = p;
982 q->len--;
983 pq->len--;
984 PKTSETLINK(pktbuf, NULL);
985 return TRUE;
988 void
989 pktq_init(struct pktq *pq, int num_prec, int max_len)
991 int prec;
993 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
995 /* pq is variable size; only zero out what's requested */
996 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
998 pq->num_prec = (uint16)num_prec;
1000 pq->max = (uint16)max_len;
1002 for (prec = 0; prec < num_prec; prec++)
1003 pq->q[prec].max = pq->max;
1006 void
1007 pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
1009 ASSERT(prec >= 0 && prec < pq->num_prec);
1011 if (prec < pq->num_prec)
1012 pq->q[prec].max = (uint16)max_len;
1015 void * BCMFASTPATH
1016 pktq_deq(struct pktq *pq, int *prec_out)
1018 struct pktq_prec *q;
1019 void *p;
1020 int prec;
1022 if (pq->len == 0)
1023 return NULL;
1025 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1026 pq->hi_prec--;
1028 q = &pq->q[prec];
1030 if ((p = q->head) == NULL)
1031 return NULL;
1033 if ((q->head = PKTLINK(p)) == NULL)
1034 q->tail = NULL;
1036 q->len--;
1038 pq->len--;
1040 if (prec_out)
1041 *prec_out = prec;
1043 PKTSETLINK(p, NULL);
1045 return p;
1048 void * BCMFASTPATH
1049 pktq_deq_tail(struct pktq *pq, int *prec_out)
1051 struct pktq_prec *q;
1052 void *p, *prev;
1053 int prec;
1055 if (pq->len == 0)
1056 return NULL;
1058 for (prec = 0; prec < pq->hi_prec; prec++)
1059 if (pq->q[prec].head)
1060 break;
1062 q = &pq->q[prec];
1064 if ((p = q->head) == NULL)
1065 return NULL;
1067 for (prev = NULL; p != q->tail; p = PKTLINK(p))
1068 prev = p;
1070 if (prev)
1071 PKTSETLINK(prev, NULL);
1072 else
1073 q->head = NULL;
1075 q->tail = prev;
1076 q->len--;
1078 pq->len--;
1080 if (prec_out)
1081 *prec_out = prec;
1083 PKTSETLINK(p, NULL);
1085 return p;
1088 void *
1089 pktq_peek(struct pktq *pq, int *prec_out)
1091 int prec;
1093 if (pq->len == 0)
1094 return NULL;
1096 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1097 pq->hi_prec--;
1099 if (prec_out)
1100 *prec_out = prec;
1102 return (pq->q[prec].head);
1105 void *
1106 pktq_peek_tail(struct pktq *pq, int *prec_out)
1108 int prec;
1110 if (pq->len == 0)
1111 return NULL;
1113 for (prec = 0; prec < pq->hi_prec; prec++)
1114 if (pq->q[prec].head)
1115 break;
1117 if (prec_out)
1118 *prec_out = prec;
1120 return (pq->q[prec].tail);
1123 void
1124 pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
1126 int prec;
1128 /* Optimize flush, if pktq len = 0, just return.
1129 * pktq len of 0 means pktq's prec q's are all empty.
1131 if (pq->len == 0) {
1132 return;
1135 for (prec = 0; prec < pq->num_prec; prec++)
1136 pktq_pflush(osh, pq, prec, dir, fn, arg);
1137 if (fn == NULL)
1138 ASSERT(pq->len == 0);
1141 /* Return sum of lengths of a specific set of precedences */
1143 pktq_mlen(struct pktq *pq, uint prec_bmp)
1145 int prec, len;
1147 len = 0;
1149 for (prec = 0; prec <= pq->hi_prec; prec++)
1150 if (prec_bmp & (1 << prec))
1151 len += pq->q[prec].len;
1153 return len;
1156 /* Priority peek from a specific set of precedences */
1157 void * BCMFASTPATH
1158 pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out)
1160 struct pktq_prec *q;
1161 void *p;
1162 int prec;
1164 if (pq->len == 0)
1166 return NULL;
1168 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1169 pq->hi_prec--;
1171 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
1172 if (prec-- == 0)
1173 return NULL;
1175 q = &pq->q[prec];
1177 if ((p = q->head) == NULL)
1178 return NULL;
1180 if (prec_out)
1181 *prec_out = prec;
1183 return p;
1185 /* Priority dequeue from a specific set of precedences */
1186 void * BCMFASTPATH
1187 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
1189 struct pktq_prec *q;
1190 void *p;
1191 int prec;
1193 if (pq->len == 0)
1194 return NULL;
1196 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1197 pq->hi_prec--;
1199 while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0))
1200 if (prec-- == 0)
1201 return NULL;
1203 q = &pq->q[prec];
1205 if ((p = q->head) == NULL)
1206 return NULL;
1208 if ((q->head = PKTLINK(p)) == NULL)
1209 q->tail = NULL;
1211 q->len--;
1213 if (prec_out)
1214 *prec_out = prec;
1216 pq->len--;
1218 PKTSETLINK(p, NULL);
1220 return p;
1223 #endif /* BCMDRIVER */
1225 #if defined(BCMROMBUILD)
1226 const unsigned char BCMROMDATA(bcm_ctype)[] = {
1227 #else
1228 const unsigned char bcm_ctype[] = {
1229 #endif
1231 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
1232 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
1233 _BCM_C, /* 8-15 */
1234 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
1235 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
1236 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
1237 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
1238 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
1239 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
1240 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
1241 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
1242 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
1243 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
1244 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
1245 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
1246 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
1247 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
1248 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
1249 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
1250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
1251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
1252 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1253 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
1254 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1255 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
1256 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
1257 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
1258 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
1259 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
1260 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
1261 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
1262 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
1263 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
1266 ulong
1267 BCMROMFN(bcm_strtoul)(const char *cp, char **endp, uint base)
1269 ulong result, last_result = 0, value;
1270 bool minus;
1272 minus = FALSE;
1274 while (bcm_isspace(*cp))
1275 cp++;
1277 if (cp[0] == '+')
1278 cp++;
1279 else if (cp[0] == '-') {
1280 minus = TRUE;
1281 cp++;
1284 if (base == 0) {
1285 if (cp[0] == '0') {
1286 if ((cp[1] == 'x') || (cp[1] == 'X')) {
1287 base = 16;
1288 cp = &cp[2];
1289 } else {
1290 base = 8;
1291 cp = &cp[1];
1293 } else
1294 base = 10;
1295 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
1296 cp = &cp[2];
1299 result = 0;
1301 while (bcm_isxdigit(*cp) &&
1302 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
1303 result = result*base + value;
1304 /* Detected overflow */
1305 if (result < last_result && !minus)
1306 return (ulong)-1;
1307 last_result = result;
1308 cp++;
1311 if (minus)
1312 result = (ulong)(-(long)result);
1314 if (endp)
1315 *endp = DISCARD_QUAL(cp, char);
1317 return (result);
1321 BCMROMFN(bcm_atoi)(const char *s)
1323 return (int)bcm_strtoul(s, NULL, 10);
1326 /* return pointer to location of substring 'needle' in 'haystack' */
1327 char *
1328 BCMROMFN(bcmstrstr)(const char *haystack, const char *needle)
1330 int len, nlen;
1331 int i;
1333 if ((haystack == NULL) || (needle == NULL))
1334 return DISCARD_QUAL(haystack, char);
1336 nlen = strlen(needle);
1337 len = strlen(haystack) - nlen + 1;
1339 for (i = 0; i < len; i++)
1340 if (memcmp(needle, &haystack[i], nlen) == 0)
1341 return DISCARD_QUAL(&haystack[i], char);
1342 return (NULL);
1345 char *
1346 BCMROMFN(bcmstrcat)(char *dest, const char *src)
1348 char *p;
1350 p = dest + strlen(dest);
1352 while ((*p++ = *src++) != '\0')
1355 return (dest);
1358 char *
1359 BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size)
1361 char *endp;
1362 char *p;
1364 p = dest + strlen(dest);
1365 endp = p + size;
1367 while (p != endp && (*p++ = *src++) != '\0')
1370 return (dest);
1374 /****************************************************************************
1375 * Function: bcmstrtok
1377 * Purpose:
1378 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
1379 * but allows strToken() to be used by different strings or callers at the same
1380 * time. Each call modifies '*string' by substituting a NULL character for the
1381 * first delimiter that is encountered, and updates 'string' to point to the char
1382 * after the delimiter. Leading delimiters are skipped.
1384 * Parameters:
1385 * string (mod) Ptr to string ptr, updated by token.
1386 * delimiters (in) Set of delimiter characters.
1387 * tokdelim (out) Character that delimits the returned token. (May
1388 * be set to NULL if token delimiter is not required).
1390 * Returns: Pointer to the next token found. NULL when no more tokens are found.
1391 *****************************************************************************
1393 char *
1394 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
1396 unsigned char *str;
1397 unsigned long map[8];
1398 int count;
1399 char *nextoken;
1401 if (tokdelim != NULL) {
1402 /* Prime the token delimiter */
1403 *tokdelim = '\0';
1406 /* Clear control map */
1407 for (count = 0; count < 8; count++) {
1408 map[count] = 0;
1411 /* Set bits in delimiter table */
1412 do {
1413 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
1415 while (*delimiters++);
1417 str = (unsigned char*)*string;
1419 /* Find beginning of token (skip over leading delimiters). Note that
1420 * there is no token iff this loop sets str to point to the terminal
1421 * null (*str == '\0')
1423 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
1424 str++;
1427 nextoken = (char*)str;
1429 /* Find the end of the token. If it is not the end of the string,
1430 * put a null there.
1432 for (; *str; str++) {
1433 if (map[*str >> 5] & (1 << (*str & 31))) {
1434 if (tokdelim != NULL) {
1435 *tokdelim = *str;
1438 *str++ = '\0';
1439 break;
1443 *string = (char*)str;
1445 /* Determine if a token has been found. */
1446 if (nextoken == (char *) str) {
1447 return NULL;
1449 else {
1450 return nextoken;
1455 #define xToLower(C) \
1456 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
1459 /****************************************************************************
1460 * Function: bcmstricmp
1462 * Purpose: Compare to strings case insensitively.
1464 * Parameters: s1 (in) First string to compare.
1465 * s2 (in) Second string to compare.
1467 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1468 * t1 > t2, when ignoring case sensitivity.
1469 *****************************************************************************
1472 bcmstricmp(const char *s1, const char *s2)
1474 char dc, sc;
1476 while (*s2 && *s1) {
1477 dc = xToLower(*s1);
1478 sc = xToLower(*s2);
1479 if (dc < sc) return -1;
1480 if (dc > sc) return 1;
1481 s1++;
1482 s2++;
1485 if (*s1 && !*s2) return 1;
1486 if (!*s1 && *s2) return -1;
1487 return 0;
1491 /****************************************************************************
1492 * Function: bcmstrnicmp
1494 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
1495 * characters.
1497 * Parameters: s1 (in) First string to compare.
1498 * s2 (in) Second string to compare.
1499 * cnt (in) Max characters to compare.
1501 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1502 * t1 > t2, when ignoring case sensitivity.
1503 *****************************************************************************
1506 bcmstrnicmp(const char* s1, const char* s2, int cnt)
1508 char dc, sc;
1510 while (*s2 && *s1 && cnt) {
1511 dc = xToLower(*s1);
1512 sc = xToLower(*s2);
1513 if (dc < sc) return -1;
1514 if (dc > sc) return 1;
1515 s1++;
1516 s2++;
1517 cnt--;
1520 if (!cnt) return 0;
1521 if (*s1 && !*s2) return 1;
1522 if (!*s1 && *s2) return -1;
1523 return 0;
1526 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
1528 BCMROMFN(bcm_ether_atoe)(const char *p, struct ether_addr *ea)
1530 int i = 0;
1531 char *ep;
1533 for (;;) {
1534 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
1535 p = ep;
1536 if (!*p++ || i == 6)
1537 break;
1540 return (i == 6);
1544 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
1545 /* registry routine buffer preparation utility functions:
1546 * parameter order is like strncpy, but returns count
1547 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
1549 ulong
1550 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
1552 ulong copyct = 1;
1553 ushort i;
1555 if (abuflen == 0)
1556 return 0;
1558 /* wbuflen is in bytes */
1559 wbuflen /= sizeof(ushort);
1561 for (i = 0; i < wbuflen; ++i) {
1562 if (--abuflen == 0)
1563 break;
1564 *abuf++ = (char) *wbuf++;
1565 ++copyct;
1567 *abuf = '\0';
1569 return copyct;
1571 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
1573 char *
1574 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
1576 static const char hex[] =
1578 '0', '1', '2', '3', '4', '5', '6', '7',
1579 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1581 const uint8 *octet = ea->octet;
1582 char *p = buf;
1583 int i;
1585 for (i = 0; i < 6; i++, octet++) {
1586 *p++ = hex[(*octet >> 4) & 0xf];
1587 *p++ = hex[*octet & 0xf];
1588 *p++ = ':';
1591 *(p-1) = '\0';
1593 return (buf);
1596 char *
1597 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
1599 snprintf(buf, 16, "%d.%d.%d.%d",
1600 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
1601 return (buf);
1604 #ifdef BCMDRIVER
1606 void
1607 bcm_mdelay(uint ms)
1609 uint i;
1611 for (i = 0; i < ms; i++) {
1612 OSL_DELAY(1000);
1617 * Search the name=value vars for a specific one and return its value.
1618 * Returns NULL if not found.
1620 char *
1621 getvar(char *vars, const char *name)
1623 #ifdef _MINOSL_
1624 return NULL;
1625 #else
1626 char *s;
1627 int len;
1629 if (!name)
1630 return NULL;
1632 len = strlen(name);
1633 if (len == 0)
1634 return NULL;
1636 /* first look in vars[] */
1637 for (s = vars; s && *s;) {
1638 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
1639 return (&s[len+1]);
1641 while (*s++)
1645 /* then query nvram */
1646 return (nvram_get(name));
1647 #endif /* defined(_MINOSL_) */
1651 * Search the vars for a specific one and return its value as
1652 * an integer. Returns 0 if not found.
1655 getintvar(char *vars, const char *name)
1657 #ifdef _MINOSL_
1658 return 0;
1659 #else
1660 char *val;
1662 if ((val = getvar(vars, name)) == NULL)
1663 return (0);
1665 return (bcm_strtoul(val, NULL, 0));
1666 #endif /* _MINOSL_ */
1670 getintvararray(char *vars, const char *name, int index)
1672 #ifdef _MINOSL_
1673 return 0;
1674 #else
1675 char *buf, *endp;
1676 int i = 0;
1677 int val = 0;
1679 if ((buf = getvar(vars, name)) == NULL) {
1680 return (0);
1683 /* table values are always separated by "," or " " */
1684 while (*buf != '\0') {
1685 val = bcm_strtoul(buf, &endp, 0);
1686 if (i == index) {
1687 return val;
1689 buf = endp;
1690 /* delimiter is ',' */
1691 if (*buf == ',')
1692 buf++;
1693 i++;
1695 return 0;
1696 #endif /* _MINOSL_ */
1700 getintvararraysize(char *vars, const char *name)
1702 #ifdef _MINOSL_
1703 return 0;
1704 #else
1705 char *buf, *endp;
1706 int count = 0;
1707 int val = 0;
1709 if ((buf = getvar(vars, name)) == NULL) {
1710 return (0);
1713 /* table values are always separated by "," or " " */
1714 while (*buf != '\0') {
1715 val = bcm_strtoul(buf, &endp, 0);
1716 buf = endp;
1717 /* delimiter is ',' */
1718 if (*buf == ',')
1719 buf++;
1720 count++;
1722 BCM_REFERENCE(val);
1723 return count;
1724 #endif /* _MINOSL_ */
1727 /* Search for token in comma separated token-string */
1728 static int
1729 findmatch(const char *string, const char *name)
1731 uint len;
1732 char *c;
1734 len = strlen(name);
1735 while ((c = strchr(string, ',')) != NULL) {
1736 if (len == (uint)(c - string) && !strncmp(string, name, len))
1737 return 1;
1738 string = c + 1;
1741 return (!strcmp(string, name));
1744 /* Return gpio pin number assigned to the named pin
1746 * Variable should be in format:
1748 * gpio<N>=pin_name,pin_name
1750 * This format allows multiple features to share the gpio with mutual
1751 * understanding.
1753 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
1754 * and if def_pin is not used by others.
1756 uint
1757 getgpiopin(char *vars, char *pin_name, uint def_pin)
1759 char name[] = "gpioXXXX";
1760 char *val;
1761 uint pin;
1763 /* Go thru all possibilities till a match in pin name */
1764 for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
1765 snprintf(name, sizeof(name), "gpio%d", pin);
1766 val = getvar(vars, name);
1767 if (val && findmatch(val, pin_name))
1768 return pin;
1771 if (def_pin != GPIO_PIN_NOTDEFINED) {
1772 /* make sure the default pin is not used by someone else */
1773 snprintf(name, sizeof(name), "gpio%d", def_pin);
1774 if (getvar(vars, name)) {
1775 def_pin = GPIO_PIN_NOTDEFINED;
1778 return def_pin;
1781 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
1783 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
1784 static struct {
1785 uint cycles;
1786 char *fmt;
1787 uint a1;
1788 uint a2;
1789 } logtab[LOGSIZE];
1791 /* last entry logged */
1792 static uint logi = 0;
1793 /* next entry to read */
1794 static uint readi = 0;
1795 #endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
1797 #ifdef BCMPERFSTATS
1798 void
1799 bcm_perf_enable()
1801 BCMPERF_ENABLE_INSTRCOUNT();
1802 BCMPERF_ENABLE_ICACHE_MISS();
1803 BCMPERF_ENABLE_ICACHE_HIT();
1806 /* WARNING: This routine uses OSL_GETCYCLES(), which can give unexpected results on
1807 * modern speed stepping CPUs. Use bcmtslog() instead in combination with TSF counter.
1809 void
1810 bcmlog(char *fmt, uint a1, uint a2)
1812 static uint last = 0;
1813 uint cycles, i;
1814 OSL_GETCYCLES(cycles);
1816 i = logi;
1818 logtab[i].cycles = cycles - last;
1819 logtab[i].fmt = fmt;
1820 logtab[i].a1 = a1;
1821 logtab[i].a2 = a2;
1823 logi = (i + 1) % LOGSIZE;
1824 last = cycles;
1828 void
1829 bcmstats(char *fmt)
1831 static uint last = 0;
1832 static uint32 ic_miss = 0;
1833 static uint32 instr_count = 0;
1834 uint32 ic_miss_cur;
1835 uint32 instr_count_cur;
1836 uint cycles, i;
1838 OSL_GETCYCLES(cycles);
1839 BCMPERF_GETICACHE_MISS(ic_miss_cur);
1840 BCMPERF_GETINSTRCOUNT(instr_count_cur);
1842 i = logi;
1844 logtab[i].cycles = cycles - last;
1845 logtab[i].a1 = ic_miss_cur - ic_miss;
1846 logtab[i].a2 = instr_count_cur - instr_count;
1847 logtab[i].fmt = fmt;
1849 logi = (i + 1) % LOGSIZE;
1851 last = cycles;
1852 instr_count = instr_count_cur;
1853 ic_miss = ic_miss_cur;
1857 void
1858 bcmdumplog(char *buf, int size)
1860 char *limit;
1861 int j = 0;
1862 int num;
1864 limit = buf + size - 80;
1865 *buf = '\0';
1867 num = logi - readi;
1869 if (num < 0)
1870 num += LOGSIZE;
1872 /* print in chronological order */
1874 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
1875 if (logtab[readi].fmt == NULL)
1876 continue;
1877 buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles);
1878 buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
1879 logtab[readi].a2);
1880 buf += snprintf(buf, (limit - buf), "\n");
1887 * Dump one log entry at a time.
1888 * Return index of next entry or -1 when no more .
1891 bcmdumplogent(char *buf, uint i)
1893 bool hit;
1896 * If buf is NULL, return the starting index,
1897 * interpreting i as the indicator of last 'i' entries to dump.
1899 if (buf == NULL) {
1900 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
1901 return ((logi - i) % LOGSIZE);
1904 *buf = '\0';
1906 ASSERT(i < LOGSIZE);
1908 if (i == logi)
1909 return (-1);
1911 hit = FALSE;
1912 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
1913 if (logtab[i].fmt == NULL)
1914 continue;
1915 buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles);
1916 buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
1917 buf += sprintf(buf, "\n");
1918 hit = TRUE;
1921 return (i);
1924 #endif /* BCMPERFSTATS */
1926 #if defined(BCMTSTAMPEDLOGS)
1927 /* Store a TSF timestamp and a log line in the log buffer */
1928 void
1929 bcmtslog(uint32 tstamp, char *fmt, uint a1, uint a2)
1931 uint i = logi;
1932 bool use_delta = FALSE;
1933 static uint32 last = 0; /* used only when use_delta is true */
1935 logtab[i].cycles = tstamp;
1936 if (use_delta)
1937 logtab[i].cycles -= last;
1939 logtab[i].fmt = fmt;
1940 logtab[i].a1 = a1;
1941 logtab[i].a2 = a2;
1943 if (use_delta)
1944 last = tstamp;
1945 logi = (i + 1) % LOGSIZE;
1948 /* Print out a microsecond timestamp as "sec.ms.us " */
1949 void
1950 bcmprinttstamp(uint32 ticks)
1952 uint us, ms, sec;
1954 us = (ticks % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
1955 ms = ticks / TSF_TICKS_PER_MS;
1956 sec = ms / 1000;
1957 ms -= sec * 1000;
1958 printf("%04u.%03u.%03u ", sec, ms, us);
1961 /* Print out the log buffer with timestamps */
1962 void
1963 bcmprinttslogs(void)
1965 int j = 0;
1966 int num;
1968 num = logi - readi;
1969 if (num < 0)
1970 num += LOGSIZE;
1972 /* Format and print the log entries directly in chronological order */
1973 for (j = 0; j < num; readi = (readi + 1) % LOGSIZE, j++) {
1974 if (logtab[readi].fmt == NULL)
1975 continue;
1976 bcmprinttstamp(logtab[readi].cycles);
1977 printf(logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
1978 printf("\n");
1982 void
1983 bcmdumptslog(char *buf, int size)
1985 char *limit;
1986 int j = 0;
1987 int num;
1988 uint us, ms, sec;
1990 limit = buf + size - 80;
1991 *buf = '\0';
1993 num = logi - readi;
1995 if (num < 0)
1996 num += LOGSIZE;
1998 /* print in chronological order */
1999 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
2000 if (logtab[readi].fmt == NULL)
2001 continue;
2002 us = (logtab[readi].cycles % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
2003 ms = logtab[readi].cycles / TSF_TICKS_PER_MS;
2004 sec = ms / 1000;
2005 ms -= sec * 1000;
2007 buf += snprintf(buf, (limit - buf), "%04u.%03u.%03u ", sec, ms, us);
2008 /* buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); */
2009 buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
2010 logtab[readi].a2);
2011 buf += snprintf(buf, (limit - buf), "\n");
2015 #endif /* BCMTSTAMPEDLOGS */
2017 #if defined(BCMDBG) || defined(DHD_DEBUG)
2018 /* pretty hex print a pkt buffer chain */
2019 void
2020 prpkt(const char *msg, osl_t *osh, void *p0)
2022 void *p;
2024 if (msg && (msg[0] != '\0'))
2025 printf("%s:\n", msg);
2027 for (p = p0; p; p = PKTNEXT(osh, p))
2028 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
2030 #endif /* BCMDBG || DHD_DEBUG */
2032 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
2033 * Also updates the inplace vlan tag if requested.
2034 * For debugging, it returns an indication of what it did.
2036 uint BCMFASTPATH
2037 pktsetprio(void *pkt, bool update_vtag)
2039 struct ether_header *eh;
2040 struct ethervlan_header *evh;
2041 uint8 *pktdata;
2042 int priority = 0;
2043 int rc = 0;
2045 pktdata = (uint8 *)PKTDATA(NULL, pkt);
2046 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
2048 eh = (struct ether_header *) pktdata;
2050 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
2051 uint16 vlan_tag;
2052 int vlan_prio, dscp_prio = 0;
2054 evh = (struct ethervlan_header *)eh;
2056 vlan_tag = ntoh16(evh->vlan_tag);
2057 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
2059 if (evh->ether_type == hton16(ETHER_TYPE_IP)) {
2060 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
2061 uint8 tos_tc = IP_TOS46(ip_body);
2062 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
2065 /* DSCP priority gets precedence over 802.1P (vlan tag) */
2066 if (dscp_prio != 0) {
2067 priority = dscp_prio;
2068 rc |= PKTPRIO_VDSCP;
2069 } else {
2070 priority = vlan_prio;
2071 rc |= PKTPRIO_VLAN;
2074 * If the DSCP priority is not the same as the VLAN priority,
2075 * then overwrite the priority field in the vlan tag, with the
2076 * DSCP priority value. This is required for Linux APs because
2077 * the VLAN driver on Linux, overwrites the skb->priority field
2078 * with the priority value in the vlan tag
2080 if (update_vtag && (priority != vlan_prio)) {
2081 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
2082 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
2083 evh->vlan_tag = hton16(vlan_tag);
2084 rc |= PKTPRIO_UPD;
2086 } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) {
2087 uint8 *ip_body = pktdata + sizeof(struct ether_header);
2088 uint8 tos_tc = IP_TOS46(ip_body);
2089 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
2090 rc |= PKTPRIO_DSCP;
2093 ASSERT(priority >= 0 && priority <= MAXPRIO);
2094 PKTSETPRIO(pkt, priority);
2095 return (rc | priority);
2098 #ifndef BCM_BOOTLOADER
2100 static char bcm_undeferrstr[32];
2101 static const char *const bcmerrorstrtable[] = BCMERRSTRINGTABLE;
2103 /* Convert the error codes into related error strings */
2104 const char *
2105 bcmerrorstr(int bcmerror)
2107 /* check if someone added a bcmerror code but forgot to add errorstring */
2108 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
2110 if (bcmerror > 0 || bcmerror < BCME_LAST) {
2111 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
2112 return bcm_undeferrstr;
2115 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
2117 return bcmerrorstrtable[-bcmerror];
2120 #endif /* !BCM_BOOTLOADER */
2122 #ifdef WLC_LOW
2123 static void
2124 BCMINITFN(bcm_nvram_refresh)(char *flash)
2126 int i;
2127 int ret = 0;
2129 ASSERT(flash != NULL);
2131 /* default "empty" vars cache */
2132 bzero(flash, 2);
2134 if ((ret = nvram_getall(flash, MAX_NVRAM_SPACE)))
2135 return;
2137 /* determine nvram length */
2138 for (i = 0; i < MAX_NVRAM_SPACE; i++) {
2139 if (flash[i] == '\0' && flash[i+1] == '\0')
2140 break;
2143 if (i > 1)
2144 vars_len = i + 2;
2145 else
2146 vars_len = 0;
2149 char *
2150 bcm_nvram_vars(uint *length)
2152 #ifndef BCMNVRAMR
2153 /* cache may be stale if nvram is read/write */
2154 if (nvram_vars) {
2155 ASSERT(!bcmreclaimed);
2156 bcm_nvram_refresh(nvram_vars);
2158 #endif
2159 if (length)
2160 *length = vars_len;
2161 return nvram_vars;
2164 /* copy nvram vars into locally-allocated multi-string array */
2166 BCMINITFN(bcm_nvram_cache)(void *sih)
2168 int ret = 0;
2169 void *osh;
2170 char *flash = NULL;
2172 if (vars_len >= 0) {
2173 #ifndef BCMNVRAMR
2174 bcm_nvram_refresh(nvram_vars);
2175 #endif
2176 return 0;
2179 osh = si_osh((si_t *)sih);
2181 /* allocate memory and read in flash */
2182 if (!(flash = MALLOC(osh, MAX_NVRAM_SPACE))) {
2183 ret = BCME_NOMEM;
2184 goto exit;
2187 bcm_nvram_refresh(flash);
2189 #ifdef BCMNVRAMR
2190 if (vars_len > 3) {
2191 /* copy into a properly-sized buffer */
2192 if (!(nvram_vars = MALLOC(osh, vars_len))) {
2193 ret = BCME_NOMEM;
2194 } else
2195 bcopy(flash, nvram_vars, vars_len);
2197 MFREE(osh, flash, MAX_NVRAM_SPACE);
2198 #else
2199 /* cache must be full size of nvram if read/write */
2200 nvram_vars = flash;
2201 #endif /* BCMNVRAMR */
2203 exit:
2204 return ret;
2206 #endif /* WLC_LOW */
2209 /* iovar table lookup */
2210 const bcm_iovar_t*
2211 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
2213 const bcm_iovar_t *vi;
2214 const char *lookup_name;
2216 /* skip any ':' delimited option prefixes */
2217 lookup_name = strrchr(name, ':');
2218 if (lookup_name != NULL)
2219 lookup_name++;
2220 else
2221 lookup_name = name;
2223 ASSERT(table != NULL);
2225 for (vi = table; vi->name; vi++) {
2226 if (!strcmp(vi->name, lookup_name))
2227 return vi;
2229 /* ran to end of table */
2231 return NULL; /* var name not found */
2235 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
2237 int bcmerror = 0;
2239 /* length check on io buf */
2240 switch (vi->type) {
2241 case IOVT_BOOL:
2242 case IOVT_INT8:
2243 case IOVT_INT16:
2244 case IOVT_INT32:
2245 case IOVT_UINT8:
2246 case IOVT_UINT16:
2247 case IOVT_UINT32:
2248 /* all integers are int32 sized args at the ioctl interface */
2249 if (len < (int)sizeof(int)) {
2250 bcmerror = BCME_BUFTOOSHORT;
2252 break;
2254 case IOVT_BUFFER:
2255 /* buffer must meet minimum length requirement */
2256 if (len < vi->minlen) {
2257 bcmerror = BCME_BUFTOOSHORT;
2259 break;
2261 case IOVT_VOID:
2262 if (!set) {
2263 /* Cannot return nil... */
2264 bcmerror = BCME_UNSUPPORTED;
2265 } else if (len) {
2266 /* Set is an action w/o parameters */
2267 bcmerror = BCME_BUFTOOLONG;
2269 break;
2271 default:
2272 /* unknown type for length check in iovar info */
2273 ASSERT(0);
2274 bcmerror = BCME_UNSUPPORTED;
2277 return bcmerror;
2280 #endif /* BCMDRIVER */
2283 /*******************************************************************************
2284 * crc8
2286 * Computes a crc8 over the input data using the polynomial:
2288 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
2290 * The caller provides the initial value (either CRC8_INIT_VALUE
2291 * or the previous returned value) to allow for processing of
2292 * discontiguous blocks of data. When generating the CRC the
2293 * caller is responsible for complementing the final return value
2294 * and inserting it into the byte stream. When checking, a final
2295 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2297 * Reference: Dallas Semiconductor Application Note 27
2298 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2299 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2300 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2302 * ****************************************************************************
2305 static const uint8 crc8_table[256] = {
2306 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
2307 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
2308 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2309 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
2310 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
2311 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2312 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
2313 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
2314 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2315 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
2316 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
2317 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2318 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
2319 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
2320 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2321 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
2322 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
2323 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2324 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
2325 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
2326 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2327 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
2328 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
2329 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2330 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
2331 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
2332 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2333 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
2334 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
2335 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2336 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
2337 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
2340 #define CRC_INNER_LOOP(n, c, x) \
2341 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2343 uint8
2344 BCMROMFN(hndcrc8)(
2345 uint8 *pdata, /* pointer to array of data to process */
2346 uint nbytes, /* number of input data bytes to process */
2347 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
2350 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
2351 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2353 while (nbytes-- > 0)
2354 crc = crc8_table[(crc ^ *pdata++) & 0xff];
2356 return crc;
2359 /*******************************************************************************
2360 * crc16
2362 * Computes a crc16 over the input data using the polynomial:
2364 * x^16 + x^12 +x^5 + 1
2366 * The caller provides the initial value (either CRC16_INIT_VALUE
2367 * or the previous returned value) to allow for processing of
2368 * discontiguous blocks of data. When generating the CRC the
2369 * caller is responsible for complementing the final return value
2370 * and inserting it into the byte stream. When checking, a final
2371 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2373 * Reference: Dallas Semiconductor Application Note 27
2374 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2375 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2376 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2378 * ****************************************************************************
2381 static const uint16 crc16_table[256] = {
2382 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
2383 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
2384 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
2385 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
2386 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
2387 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
2388 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
2389 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
2390 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2391 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
2392 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
2393 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
2394 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
2395 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
2396 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
2397 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
2398 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
2399 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2400 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
2401 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
2402 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
2403 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
2404 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
2405 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
2406 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
2407 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
2408 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2409 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
2410 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
2411 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
2412 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
2413 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
2416 uint16
2417 BCMROMFN(hndcrc16)(
2418 uint8 *pdata, /* pointer to array of data to process */
2419 uint nbytes, /* number of input data bytes to process */
2420 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
2423 while (nbytes-- > 0)
2424 CRC_INNER_LOOP(16, crc, *pdata++);
2425 return crc;
2428 static const uint32 crc32_table[256] = {
2429 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
2430 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
2431 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2432 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
2433 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
2434 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2435 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
2436 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
2437 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2438 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
2439 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
2440 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2441 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
2442 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
2443 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2444 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
2445 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
2446 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2447 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
2448 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
2449 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2450 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
2451 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
2452 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2453 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
2454 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
2455 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2456 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
2457 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
2458 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
2459 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
2460 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
2461 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
2462 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
2463 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
2464 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
2465 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
2466 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
2467 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
2468 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
2469 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
2470 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
2471 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
2472 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
2473 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
2474 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
2475 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
2476 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
2477 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
2478 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
2479 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
2480 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
2481 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
2482 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
2483 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
2484 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
2485 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
2486 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
2487 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
2488 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
2489 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
2490 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
2491 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
2492 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
2496 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
2497 * accumulating over multiple pieces.
2499 uint32
2500 BCMROMFN(hndcrc32)(uint8 *pdata, uint nbytes, uint32 crc)
2502 uint8 *pend;
2503 #ifdef __mips__
2504 uint8 tmp[4];
2505 ulong *tptr = (ulong *)tmp;
2507 if (nbytes > 3) {
2508 /* in case the beginning of the buffer isn't aligned */
2509 pend = (uint8 *)((uint)(pdata + 3) & ~0x3);
2510 nbytes -= (pend - pdata);
2511 while (pdata < pend)
2512 CRC_INNER_LOOP(32, crc, *pdata++);
2515 if (nbytes > 3) {
2516 /* handle bulk of data as 32-bit words */
2517 pend = pdata + (nbytes & ~0x3);
2518 while (pdata < pend) {
2519 *tptr = *(ulong *)pdata;
2520 pdata += sizeof(ulong *);
2521 CRC_INNER_LOOP(32, crc, tmp[0]);
2522 CRC_INNER_LOOP(32, crc, tmp[1]);
2523 CRC_INNER_LOOP(32, crc, tmp[2]);
2524 CRC_INNER_LOOP(32, crc, tmp[3]);
2528 /* 1-3 bytes at end of buffer */
2529 pend = pdata + (nbytes & 0x03);
2530 while (pdata < pend)
2531 CRC_INNER_LOOP(32, crc, *pdata++);
2532 #else
2533 pend = pdata + nbytes;
2534 while (pdata < pend)
2535 CRC_INNER_LOOP(32, crc, *pdata++);
2536 #endif /* __mips__ */
2538 return crc;
2541 #ifdef notdef
2542 #define CLEN 1499 /* CRC Length */
2543 #define CBUFSIZ (CLEN+4)
2544 #define CNBUFS 5 /* # of bufs */
2546 void
2547 testcrc32(void)
2549 uint j, k, l;
2550 uint8 *buf;
2551 uint len[CNBUFS];
2552 uint32 crcr;
2553 uint32 crc32tv[CNBUFS] =
2554 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
2556 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
2558 /* step through all possible alignments */
2559 for (l = 0; l <= 4; l++) {
2560 for (j = 0; j < CNBUFS; j++) {
2561 len[j] = CLEN;
2562 for (k = 0; k < len[j]; k++)
2563 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
2566 for (j = 0; j < CNBUFS; j++) {
2567 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
2568 ASSERT(crcr == crc32tv[j]);
2572 MFREE(buf, CBUFSIZ*CNBUFS);
2573 return;
2575 #endif /* notdef */
2578 * Advance from the current 1-byte tag/1-byte length/variable-length value
2579 * triple, to the next, returning a pointer to the next.
2580 * If the current or next TLV is invalid (does not fit in given buffer length),
2581 * NULL is returned.
2582 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
2583 * by the TLV parameter's length if it is valid.
2585 bcm_tlv_t *
2586 BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen)
2588 int len;
2590 /* validate current elt */
2591 if (!bcm_valid_tlv(elt, *buflen))
2592 return NULL;
2594 /* advance to next elt */
2595 len = elt->len;
2596 elt = (bcm_tlv_t*)(elt->data + len);
2597 *buflen -= (TLV_HDR_LEN + len);
2599 /* validate next elt */
2600 if (!bcm_valid_tlv(elt, *buflen))
2601 return NULL;
2603 return elt;
2607 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2608 * triples, returning a pointer to the substring whose first element
2609 * matches tag
2611 bcm_tlv_t *
2612 BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key)
2614 bcm_tlv_t *elt;
2615 int totlen;
2617 elt = (bcm_tlv_t*)buf;
2618 totlen = buflen;
2620 /* find tagged parameter */
2621 while (totlen >= TLV_HDR_LEN) {
2622 int len = elt->len;
2624 /* validate remaining totlen */
2625 if ((elt->id == key) &&
2626 (totlen >= (len + TLV_HDR_LEN)))
2627 return (elt);
2629 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2630 totlen -= (len + TLV_HDR_LEN);
2633 return NULL;
2637 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2638 * triples, returning a pointer to the substring whose first element
2639 * matches tag. Stop parsing when we see an element whose ID is greater
2640 * than the target key.
2642 bcm_tlv_t *
2643 BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key)
2645 bcm_tlv_t *elt;
2646 int totlen;
2648 elt = (bcm_tlv_t*)buf;
2649 totlen = buflen;
2651 /* find tagged parameter */
2652 while (totlen >= TLV_HDR_LEN) {
2653 uint id = elt->id;
2654 int len = elt->len;
2656 /* Punt if we start seeing IDs > than target key */
2657 if (id > key)
2658 return (NULL);
2660 /* validate remaining totlen */
2661 if ((id == key) &&
2662 (totlen >= (len + TLV_HDR_LEN)))
2663 return (elt);
2665 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2666 totlen -= (len + TLV_HDR_LEN);
2668 return NULL;
2671 #if defined(BCMDBG) || defined(BCMDBG_ERR) || defined(WLMSG_PRHDRS) || \
2672 defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || defined(DHD_DEBUG)
2674 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
2676 int i, slen = 0;
2677 uint32 bit, mask;
2678 const char *name;
2679 mask = bd->mask;
2680 if (len < 2 || !buf)
2681 return 0;
2683 buf[0] = '\0';
2685 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
2686 bit = bd->bitfield[i].bit;
2687 if ((flags & mask) == bit) {
2688 if (len > (int)strlen(name)) {
2689 slen = strlen(name);
2690 strncpy(buf, name, slen+1);
2692 break;
2695 return slen;
2699 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
2701 int i;
2702 char* p = buf;
2703 char hexstr[16];
2704 int slen = 0, nlen = 0;
2705 uint32 bit;
2706 const char* name;
2708 if (len < 2 || !buf)
2709 return 0;
2711 buf[0] = '\0';
2713 for (i = 0; flags != 0; i++) {
2714 bit = bd[i].bit;
2715 name = bd[i].name;
2716 if (bit == 0 && flags != 0) {
2717 /* print any unnamed bits */
2718 snprintf(hexstr, 16, "0x%X", flags);
2719 name = hexstr;
2720 flags = 0; /* exit loop */
2721 } else if ((flags & bit) == 0)
2722 continue;
2723 flags &= ~bit;
2724 nlen = strlen(name);
2725 slen += nlen;
2726 /* count btwn flag space */
2727 if (flags != 0)
2728 slen += 1;
2729 /* need NULL char as well */
2730 if (len <= slen)
2731 break;
2732 /* copy NULL char but don't count it */
2733 strncpy(p, name, nlen + 1);
2734 p += nlen;
2735 /* copy btwn flag space and NULL char */
2736 if (flags != 0)
2737 p += snprintf(p, 2, " ");
2740 /* indicate the str was too short */
2741 if (flags != 0) {
2742 if (len < 2)
2743 p -= 2 - len; /* overwrite last char */
2744 p += snprintf(p, 2, ">");
2747 return (int)(p - buf);
2750 /* print bytes formatted as hex to a string. return the resulting string length */
2752 bcm_format_hex(char *str, const void *bytes, int len)
2754 int i;
2755 char *p = str;
2756 const uint8 *src = (const uint8*)bytes;
2758 for (i = 0; i < len; i++) {
2759 p += snprintf(p, 3, "%02X", *src);
2760 src++;
2762 return (int)(p - str);
2764 #endif
2766 /* pretty hex print a contiguous buffer */
2767 void
2768 prhex(const char *msg, uchar *buf, uint nbytes)
2770 char line[128], *p;
2771 int len = sizeof(line);
2772 int nchar;
2773 uint i;
2775 if (msg && (msg[0] != '\0'))
2776 printf("%s:\n", msg);
2778 p = line;
2779 for (i = 0; i < nbytes; i++) {
2780 if (i % 16 == 0) {
2781 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
2782 p += nchar;
2783 len -= nchar;
2785 if (len > 0) {
2786 nchar = snprintf(p, len, "%02x ", buf[i]);
2787 p += nchar;
2788 len -= nchar;
2791 if (i % 16 == 15) {
2792 printf("%s\n", line); /* flush line */
2793 p = line;
2794 len = sizeof(line);
2798 /* flush last partial line */
2799 if (p != line)
2800 printf("%s\n", line);
2803 static const char *crypto_algo_names[] = {
2804 "NONE",
2805 "WEP1",
2806 "TKIP",
2807 "WEP128",
2808 "AES_CCM",
2809 "AES_OCB_MSDU",
2810 "AES_OCB_MPDU",
2811 "NALG"
2812 "UNDEF",
2813 "UNDEF",
2814 "UNDEF",
2815 "UNDEF"
2818 const char *
2819 bcm_crypto_algo_name(uint algo)
2821 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
2824 #ifdef BCMDBG
2825 void
2826 deadbeef(void *p, uint len)
2828 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
2830 while (len-- > 0) {
2831 *(uint8*)p = meat[((uintptr)p) & 3];
2832 p = (uint8*)p + 1;
2835 #endif /* BCMDBG */
2837 char *
2838 bcm_chipname(uint chipid, char *buf, uint len)
2840 const char *fmt;
2842 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
2843 snprintf(buf, len, fmt, chipid);
2844 return buf;
2847 /* Produce a human-readable string for boardrev */
2848 char *
2849 bcm_brev_str(uint32 brev, char *buf)
2851 if (brev < 0x100)
2852 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
2853 else
2854 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
2856 return (buf);
2859 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2861 /* dump large strings to console */
2862 void
2863 printbig(char *buf)
2865 uint len, max_len;
2866 char c;
2868 len = strlen(buf);
2870 max_len = BUFSIZE_TODUMP_ATONCE;
2872 while (len > max_len) {
2873 c = buf[max_len];
2874 buf[max_len] = '\0';
2875 printf("%s", buf);
2876 buf[max_len] = c;
2878 buf += max_len;
2879 len -= max_len;
2881 /* print the remaining string */
2882 printf("%s\n", buf);
2883 return;
2886 /* routine to dump fields in a fileddesc structure */
2887 uint
2888 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
2889 char *buf, uint32 bufsize)
2891 uint filled_len;
2892 int len;
2893 struct fielddesc *cur_ptr;
2895 filled_len = 0;
2896 cur_ptr = fielddesc_array;
2898 while (bufsize > 1) {
2899 if (cur_ptr->nameandfmt == NULL)
2900 break;
2901 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
2902 read_rtn(arg0, arg1, cur_ptr->offset));
2903 /* check for snprintf overflow or error */
2904 if (len < 0 || (uint32)len >= bufsize)
2905 len = bufsize - 1;
2906 buf += len;
2907 bufsize -= len;
2908 filled_len += len;
2909 cur_ptr++;
2911 return filled_len;
2914 uint
2915 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
2917 uint len;
2919 len = strlen(name) + 1;
2921 if ((len + datalen) > buflen)
2922 return 0;
2924 strncpy(buf, name, buflen);
2926 /* append data onto the end of the name string */
2927 memcpy(&buf[len], data, datalen);
2928 len += datalen;
2930 return len;
2933 /* Quarter dBm units to mW
2934 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2935 * Table is offset so the last entry is largest mW value that fits in
2936 * a uint16.
2939 #define QDBM_OFFSET 153 /* Offset for first entry */
2940 #define QDBM_TABLE_LEN 40 /* Table size */
2942 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2943 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2945 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2947 /* Largest mW value that will round down to the last table entry,
2948 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2949 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2951 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2953 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
2954 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
2955 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
2956 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
2957 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
2958 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
2959 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
2962 uint16
2963 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm)
2965 uint factor = 1;
2966 int idx = qdbm - QDBM_OFFSET;
2968 if (idx >= QDBM_TABLE_LEN) {
2969 /* clamp to max uint16 mW value */
2970 return 0xFFFF;
2973 /* scale the qdBm index up to the range of the table 0-40
2974 * where an offset of 40 qdBm equals a factor of 10 mW.
2976 while (idx < 0) {
2977 idx += 40;
2978 factor *= 10;
2981 /* return the mW value scaled down to the correct factor of 10,
2982 * adding in factor/2 to get proper rounding.
2984 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
2987 uint8
2988 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw)
2990 uint8 qdbm;
2991 int offset;
2992 uint mw_uint = mw;
2993 uint boundary;
2995 /* handle boundary case */
2996 if (mw_uint <= 1)
2997 return 0;
2999 offset = QDBM_OFFSET;
3001 /* move mw into the range of the table */
3002 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
3003 mw_uint *= 10;
3004 offset -= 40;
3007 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
3008 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
3009 nqdBm_to_mW_map[qdbm])/2;
3010 if (mw_uint < boundary) break;
3013 qdbm += (uint8)offset;
3015 return (qdbm);
3019 uint
3020 BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length)
3022 uint bitcount = 0, i;
3023 uint8 tmp;
3024 for (i = 0; i < length; i++) {
3025 tmp = bitmap[i];
3026 while (tmp) {
3027 bitcount++;
3028 tmp &= (tmp - 1);
3031 return bitcount;
3034 #ifdef BCMDRIVER
3036 /* Initialization of bcmstrbuf structure */
3037 void
3038 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
3040 b->origsize = b->size = size;
3041 b->origbuf = b->buf = buf;
3044 /* Buffer sprintf wrapper to guard against buffer overflow */
3046 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
3048 va_list ap;
3049 int r;
3051 va_start(ap, fmt);
3053 r = vsnprintf(b->buf, b->size, fmt, ap);
3055 /* Non Ansi C99 compliant returns -1,
3056 * Ansi compliant return r >= b->size,
3057 * bcmstdlib returns 0, handle all
3059 /* r == 0 is also the case when strlen(fmt) is zero.
3060 * typically the case when "" is passed as argument.
3062 if ((r == -1) || (r >= (int)b->size)) {
3063 b->size = 0;
3064 } else {
3065 b->size -= r;
3066 b->buf += r;
3069 va_end(ap);
3071 return r;
3074 void
3075 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len)
3077 int i;
3079 if (msg != NULL && msg[0] != '\0')
3080 bcm_bprintf(b, "%s", msg);
3081 for (i = 0; i < len; i ++)
3082 bcm_bprintf(b, "%02X", buf[i]);
3083 if (newline)
3084 bcm_bprintf(b, "\n");
3087 void
3088 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
3090 int i;
3092 for (i = 0; i < num_bytes; i++) {
3093 num[i] += amount;
3094 if (num[i] >= amount)
3095 break;
3096 amount = 1;
3101 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
3103 int i;
3105 for (i = nbytes - 1; i >= 0; i--) {
3106 if (arg1[i] != arg2[i])
3107 return (arg1[i] - arg2[i]);
3109 return 0;
3112 void
3113 bcm_print_bytes(const char *name, const uchar *data, int len)
3115 int i;
3116 int per_line = 0;
3118 printf("%s: %d \n", name ? name : "", len);
3119 for (i = 0; i < len; i++) {
3120 printf("%02x ", *data++);
3121 per_line++;
3122 if (per_line == 16) {
3123 per_line = 0;
3124 printf("\n");
3127 printf("\n");
3129 #if defined(WLTINYDUMP) || defined(BCMDBG) || defined(WLMSG_INFORM) || \
3130 defined(WLMSG_ASSOC) || defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
3131 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
3134 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
3136 uint i, c;
3137 char *p = buf;
3138 char *endp = buf + SSID_FMT_BUF_LEN;
3140 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
3142 for (i = 0; i < ssid_len; i++) {
3143 c = (uint)ssid[i];
3144 if (c == '\\') {
3145 *p++ = '\\';
3146 *p++ = '\\';
3147 } else if (bcm_isprint((uchar)c)) {
3148 *p++ = (char)c;
3149 } else {
3150 p += snprintf(p, (endp - p), "\\x%02X", c);
3153 *p = '\0';
3154 ASSERT(p < endp);
3156 return (int)(p - buf);
3158 #endif /* WLTINYDUMP || BCMDBG || WLMSG_INFORM || WLMSG_ASSOC || WLMSG_PRPKT */
3160 #endif /* BCMDRIVER */
3163 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
3164 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
3165 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
3166 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
3169 unsigned int
3170 process_nvram_vars(char *varbuf, unsigned int len)
3172 char *dp;
3173 bool findNewline;
3174 int column;
3175 unsigned int buf_len, n;
3176 unsigned int pad = 0;
3178 dp = varbuf;
3180 findNewline = FALSE;
3181 column = 0;
3183 for (n = 0; n < len; n++) {
3184 if (varbuf[n] == '\r')
3185 continue;
3186 if (findNewline && varbuf[n] != '\n')
3187 continue;
3188 findNewline = FALSE;
3189 if (varbuf[n] == '#') {
3190 findNewline = TRUE;
3191 continue;
3193 if (varbuf[n] == '\n') {
3194 if (column == 0)
3195 continue;
3196 *dp++ = 0;
3197 column = 0;
3198 continue;
3200 *dp++ = varbuf[n];
3201 column++;
3203 buf_len = (unsigned int)(dp - varbuf);
3204 if (buf_len % 4) {
3205 pad = 4 - buf_len % 4;
3206 if (pad && (buf_len + pad <= len)) {
3207 buf_len += pad;
3211 while (dp < varbuf + n)
3212 *dp++ = 0;
3214 return buf_len;
3217 /* calculate a * b + c */
3218 void
3219 bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
3221 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
3222 uint32 r1, r0;
3223 uint32 a1, a0, b1, b0, t, cc = 0;
3225 a1 = a >> 16;
3226 a0 = a & 0xffff;
3227 b1 = b >> 16;
3228 b0 = b & 0xffff;
3230 r0 = a0 * b0;
3231 FORMALIZE(r0);
3233 t = (a1 * b0) << 16;
3234 FORMALIZE(t);
3236 r0 += t;
3237 FORMALIZE(r0);
3239 t = (a0 * b1) << 16;
3240 FORMALIZE(t);
3242 r0 += t;
3243 FORMALIZE(r0);
3245 FORMALIZE(c);
3247 r0 += c;
3248 FORMALIZE(r0);
3250 r0 |= (cc % 2) ? 0x80000000 : 0;
3251 r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
3253 *r_high = r1;
3254 *r_low = r0;
3257 /* calculate a / b */
3258 void
3259 bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
3261 uint32 a1 = a_high, a0 = a_low, r0 = 0;
3263 if (b < 2)
3264 return;
3266 while (a1 != 0) {
3267 r0 += (0xffffffff / b) * a1;
3268 bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
3271 r0 += a0 / b;
3272 *r = r0;