88337d60c70880908b0e4af709477cf545f87705
[openwrt.git] / package / broadcom-wl / src / driver / bcmutils.c
1 /*
2  * Driver O/S-independent utility routines
3  *
4  * Copyright 2007, Broadcom Corporation
5  * All Rights Reserved.
6  * 
7  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8  * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9  * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10  * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11  * $Id$
12  */
13
14 #include <typedefs.h>
15 #include <bcmdefs.h>
16 #include <stdarg.h>
17 #include "bcmutils.h"
18 #include <osl.h>
19 #include <sbutils.h>
20 #include <bcmnvram.h>
21 #include <bcmendian.h>
22 #include <bcmdevs.h>
23 #include "proto/ethernet.h"
24 #include "proto/vlan.h"
25 #include "proto/bcmip.h"
26 #include "proto/bcmtcp.h"
27 #include "proto/802.1d.h"
28
29 #ifdef BCMPERFSTATS
30 #include <bcmperf.h>
31 #endif
32
33 #if 0
34 /* nvram vars cache */
35 static char *nvram_vars = NULL;
36 static int vars_len = -1;
37 #endif
38
39 /* copy a pkt buffer chain into a buffer */
40 uint
41 pktcopy (osl_t * osh, void *p, uint offset, int len, uchar * buf)
42 {
43   uint n, ret = 0;
44
45   if (len < 0)
46     len = 4096;                 /* "infinite" */
47
48   /* skip 'offset' bytes */
49   for (; p && offset; p = PKTNEXT (osh, p))
50     {
51       if (offset < (uint) PKTLEN (osh, p))
52         break;
53       offset -= PKTLEN (osh, p);
54     }
55
56   if (!p)
57     return 0;
58
59   /* copy the data */
60   for (; p && len; p = PKTNEXT (osh, p))
61     {
62       n = MIN ((uint) PKTLEN (osh, p) - offset, (uint) len);
63       bcopy (PKTDATA (osh, p) + offset, buf, n);
64       buf += n;
65       len -= n;
66       ret += n;
67       offset = 0;
68     }
69
70   return ret;
71 }
72
73 /* return total length of buffer chain */
74 uint
75 pkttotlen (osl_t * osh, void *p)
76 {
77   uint total;
78
79   total = 0;
80   for (; p; p = PKTNEXT (osh, p))
81     total += PKTLEN (osh, p);
82   return (total);
83 }
84
85 /* return the last buffer of chained pkt */
86 void *
87 pktlast (osl_t * osh, void *p)
88 {
89   for (; PKTNEXT (osh, p); p = PKTNEXT (osh, p))
90     ;
91
92   return (p);
93 }
94
95
96 /*
97  * osl multiple-precedence packet queue
98  * hi_prec is always >= the number of the highest non-empty precedence
99  */
100 void *
101 pktq_penq (struct pktq *pq, int prec, void *p)
102 {
103   struct pktq_prec *q;
104
105   ASSERT (prec >= 0 && prec < pq->num_prec);
106   ASSERT (PKTLINK (p) == NULL); /* queueing chains not allowed */
107
108   ASSERT (!pktq_full (pq));
109   ASSERT (!pktq_pfull (pq, prec));
110
111   q = &pq->q[prec];
112
113   if (q->head)
114     PKTSETLINK (q->tail, p);
115   else
116     q->head = p;
117
118   q->tail = p;
119   q->len++;
120
121   pq->len++;
122
123   if (pq->hi_prec < prec)
124     pq->hi_prec = (uint8) prec;
125
126   return p;
127 }
128
129 void *
130 pktq_penq_head (struct pktq *pq, int prec, void *p)
131 {
132   struct pktq_prec *q;
133
134   ASSERT (prec >= 0 && prec < pq->num_prec);
135   ASSERT (PKTLINK (p) == NULL); /* queueing chains not allowed */
136
137   ASSERT (!pktq_full (pq));
138   ASSERT (!pktq_pfull (pq, prec));
139
140   q = &pq->q[prec];
141
142   if (q->head == NULL)
143     q->tail = p;
144
145   PKTSETLINK (p, q->head);
146   q->head = p;
147   q->len++;
148
149   pq->len++;
150
151   if (pq->hi_prec < prec)
152     pq->hi_prec = (uint8) prec;
153
154   return p;
155 }
156
157 void *
158 pktq_pdeq (struct pktq *pq, int prec)
159 {
160   struct pktq_prec *q;
161   void *p;
162
163   ASSERT (prec >= 0 && prec < pq->num_prec);
164
165   q = &pq->q[prec];
166
167   if ((p = q->head) == NULL)
168     return NULL;
169
170   if ((q->head = PKTLINK (p)) == NULL)
171     q->tail = NULL;
172
173   q->len--;
174
175   pq->len--;
176
177   PKTSETLINK (p, NULL);
178
179   return p;
180 }
181
182 void *
183 pktq_pdeq_tail (struct pktq *pq, int prec)
184 {
185   struct pktq_prec *q;
186   void *p, *prev;
187
188   ASSERT (prec >= 0 && prec < pq->num_prec);
189
190   q = &pq->q[prec];
191
192   if ((p = q->head) == NULL)
193     return NULL;
194
195   for (prev = NULL; p != q->tail; p = PKTLINK (p))
196     prev = p;
197
198   if (prev)
199     PKTSETLINK (prev, NULL);
200   else
201     q->head = NULL;
202
203   q->tail = prev;
204   q->len--;
205
206   pq->len--;
207
208   return p;
209 }
210
211 void
212 pktq_pflush (osl_t * osh, struct pktq *pq, int prec, bool dir)
213 {
214   struct pktq_prec *q;
215   void *p;
216
217   q = &pq->q[prec];
218   p = q->head;
219   while (p)
220     {
221       q->head = PKTLINK (p);
222       PKTSETLINK (p, NULL);
223       PKTFREE (osh, p, dir);
224       q->len--;
225       pq->len--;
226       p = q->head;
227     }
228   ASSERT (q->len == 0);
229   q->tail = NULL;
230 }
231
232 #if 0
233 bool
234 pktq_pdel (struct pktq *pq, void *pktbuf, int prec)
235 {
236   struct pktq_prec *q;
237   void *p;
238
239   ASSERT (prec >= 0 && prec < pq->num_prec);
240
241   if (!pktbuf)
242     return FALSE;
243
244   q = &pq->q[prec];
245
246   if (q->head == pktbuf)
247     {
248       if ((q->head = PKTLINK (pktbuf)) == NULL)
249         q->tail = NULL;
250     }
251   else
252     {
253       for (p = q->head; p && PKTLINK (p) != pktbuf; p = PKTLINK (p))
254         ;
255       if (p == NULL)
256         return FALSE;
257
258       PKTSETLINK (p, PKTLINK (pktbuf));
259       if (q->tail == pktbuf)
260         q->tail = p;
261     }
262
263   q->len--;
264   pq->len--;
265   PKTSETLINK (pktbuf, NULL);
266   return TRUE;
267 }
268 #endif
269
270 void
271 pktq_init (struct pktq *pq, int num_prec, int max_len)
272 {
273   int prec;
274
275   ASSERT (num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
276
277   /* pq is variable size; only zero out what's requested */
278   bzero (pq,
279          OFFSETOF (struct pktq, q) + (sizeof (struct pktq_prec) * num_prec));
280
281   pq->num_prec = (uint16) num_prec;
282
283   pq->max = (uint16) max_len;
284
285   for (prec = 0; prec < num_prec; prec++)
286     pq->q[prec].max = pq->max;
287 }
288
289 int
290 pktq_setmax (struct pktq *pq, int max_len)
291 {
292   int prec;
293
294   if (!max_len)
295     return pq->max;
296
297   pq->max = (uint16) max_len;
298   for (prec = 0; prec < pq->num_prec; prec++)
299     pq->q[prec].max = pq->max;
300
301   return pq->max;
302 }
303
304 void *
305 pktq_deq (struct pktq *pq, int *prec_out)
306 {
307   struct pktq_prec *q;
308   void *p;
309   int prec;
310
311   if (pq->len == 0)
312     return NULL;
313
314   while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
315     pq->hi_prec--;
316
317   q = &pq->q[prec];
318
319   if ((p = q->head) == NULL)
320     return NULL;
321
322   if ((q->head = PKTLINK (p)) == NULL)
323     q->tail = NULL;
324
325   q->len--;
326
327   pq->len--;
328
329   if (prec_out)
330     *prec_out = prec;
331
332   PKTSETLINK (p, NULL);
333
334   return p;
335 }
336
337 void *
338 pktq_deq_tail (struct pktq *pq, int *prec_out)
339 {
340   struct pktq_prec *q;
341   void *p, *prev;
342   int prec;
343
344   if (pq->len == 0)
345     return NULL;
346
347   for (prec = 0; prec < pq->hi_prec; prec++)
348     if (pq->q[prec].head)
349       break;
350
351   q = &pq->q[prec];
352
353   if ((p = q->head) == NULL)
354     return NULL;
355
356   for (prev = NULL; p != q->tail; p = PKTLINK (p))
357     prev = p;
358
359   if (prev)
360     PKTSETLINK (prev, NULL);
361   else
362     q->head = NULL;
363
364   q->tail = prev;
365   q->len--;
366
367   pq->len--;
368
369   if (prec_out)
370     *prec_out = prec;
371
372   PKTSETLINK (p, NULL);
373
374   return p;
375 }
376
377 #if 0
378 void *
379 pktq_peek (struct pktq *pq, int *prec_out)
380 {
381   int prec;
382
383   if (pq->len == 0)
384     return NULL;
385
386   while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
387     pq->hi_prec--;
388
389   if (prec_out)
390     *prec_out = prec;
391
392   return (pq->q[prec].head);
393 }
394 #endif
395
396 void *
397 pktq_peek_tail (struct pktq *pq, int *prec_out)
398 {
399   int prec;
400
401   if (pq->len == 0)
402     return NULL;
403
404   for (prec = 0; prec < pq->hi_prec; prec++)
405     if (pq->q[prec].head)
406       break;
407
408   if (prec_out)
409     *prec_out = prec;
410
411   return (pq->q[prec].tail);
412 }
413
414 void
415 pktq_flush (osl_t * osh, struct pktq *pq, bool dir)
416 {
417   int prec;
418   for (prec = 0; prec < pq->num_prec; prec++)
419     pktq_pflush (osh, pq, prec, dir);
420   ASSERT (pq->len == 0);
421 }
422
423 /* Return sum of lengths of a specific set of precedences */
424 int
425 pktq_mlen (struct pktq *pq, uint prec_bmp)
426 {
427   int prec, len;
428
429   len = 0;
430
431   for (prec = 0; prec <= pq->hi_prec; prec++)
432     if (prec_bmp & (1 << prec))
433       len += pq->q[prec].len;
434
435   return len;
436 }
437
438 /* Priority dequeue from a specific set of precedences */
439 void *
440 pktq_mdeq (struct pktq *pq, uint prec_bmp, int *prec_out)
441 {
442   struct pktq_prec *q;
443   void *p;
444   int prec;
445
446   if (pq->len == 0)
447     return NULL;
448
449   while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
450     pq->hi_prec--;
451
452   while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
453     if (prec-- == 0)
454       return NULL;
455
456   q = &pq->q[prec];
457
458   if ((p = q->head) == NULL)
459     return NULL;
460
461   if ((q->head = PKTLINK (p)) == NULL)
462     q->tail = NULL;
463
464   q->len--;
465
466   if (prec_out)
467     *prec_out = prec;
468
469   pq->len--;
470
471   PKTSETLINK (p, NULL);
472
473   return p;
474 }
475
476 const unsigned char bcm_ctype[] = {
477   _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,       /* 0-7 */
478   _BCM_C, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S,
479     _BCM_C | _BCM_S, _BCM_C,
480   _BCM_C,                       /* 8-15 */
481   _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,       /* 16-23 */
482   _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,       /* 24-31 */
483   _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,     /* 32-39 */
484   _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,       /* 40-47 */
485   _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D,       /* 48-55 */
486   _BCM_D, _BCM_D, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,       /* 56-63 */
487   _BCM_P, _BCM_U | _BCM_X, _BCM_U | _BCM_X, _BCM_U | _BCM_X, _BCM_U | _BCM_X,
488     _BCM_U | _BCM_X,
489   _BCM_U | _BCM_X, _BCM_U,      /* 64-71 */
490   _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,       /* 72-79 */
491   _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,       /* 80-87 */
492   _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,       /* 88-95 */
493   _BCM_P, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X,
494     _BCM_L | _BCM_X,
495   _BCM_L | _BCM_X, _BCM_L,      /* 96-103 */
496   _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,       /* 104-111 */
497   _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,       /* 112-119 */
498   _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_C,       /* 120-127 */
499   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* 128-143 */
500   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* 144-159 */
501   _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
502     _BCM_P, _BCM_P,
503   _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,       /* 160-175 */
504   _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
505     _BCM_P, _BCM_P,
506   _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,       /* 176-191 */
507   _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
508     _BCM_U, _BCM_U,
509   _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,       /* 192-207 */
510   _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U,
511     _BCM_U, _BCM_U,
512   _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L,       /* 208-223 */
513   _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
514     _BCM_L, _BCM_L,
515   _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,       /* 224-239 */
516   _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L,
517     _BCM_L, _BCM_L,
518   _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L        /* 240-255 */
519 };
520
521 ulong BCMROMFN (bcm_strtoul) (char *cp, char **endp, uint base)
522 {
523   ulong result, value;
524   bool minus;
525
526   minus = FALSE;
527
528   while (bcm_isspace (*cp))
529     cp++;
530
531   if (cp[0] == '+')
532     cp++;
533   else if (cp[0] == '-')
534     {
535       minus = TRUE;
536       cp++;
537     }
538
539   if (base == 0)
540     {
541       if (cp[0] == '0')
542         {
543           if ((cp[1] == 'x') || (cp[1] == 'X'))
544             {
545               base = 16;
546               cp = &cp[2];
547             }
548           else
549             {
550               base = 8;
551               cp = &cp[1];
552             }
553         }
554       else
555         base = 10;
556     }
557   else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X')))
558     {
559       cp = &cp[2];
560     }
561
562   result = 0;
563
564   while (bcm_isxdigit (*cp) &&
565          (value =
566           bcm_isdigit (*cp) ? *cp - '0' : bcm_toupper (*cp) - 'A' + 10) <
567          base)
568     {
569       result = result * base + value;
570       cp++;
571     }
572
573   if (minus)
574     result = (ulong) (result * -1);
575
576   if (endp)
577     *endp = (char *) cp;
578
579   return (result);
580 }
581
582 #if 0
583 int BCMROMFN (bcm_atoi) (char *s)
584 {
585   return (int) bcm_strtoul (s, NULL, 10);
586 }
587
588 /* return pointer to location of substring 'needle' in 'haystack' */
589 char *BCMROMFN (bcmstrstr) (char *haystack, char *needle)
590 {
591   int len, nlen;
592   int i;
593
594   if ((haystack == NULL) || (needle == NULL))
595     return (haystack);
596
597   nlen = strlen (needle);
598   len = strlen (haystack) - nlen + 1;
599
600   for (i = 0; i < len; i++)
601     if (memcmp (needle, &haystack[i], nlen) == 0)
602       return (&haystack[i]);
603   return (NULL);
604 }
605
606 char *BCMROMFN (bcmstrcat) (char *dest, const char *src)
607 {
608   strcpy (&dest[strlen (dest)], src);
609   return (dest);
610 }
611
612 char *BCMROMFN (bcmstrncat) (char *dest, const char *src, uint size)
613 {
614   char *endp;
615   char *p;
616
617   p = dest + strlen (dest);
618   endp = p + size;
619
620   while (p != endp && (*p++ = *src++) != '\0')
621     ;
622
623   return (dest);
624 }
625 #endif
626
627 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
628 int BCMROMFN (bcm_ether_atoe) (char *p, struct ether_addr * ea)
629 {
630   int i = 0;
631
632   for (;;)
633     {
634       ea->octet[i++] = (char) bcm_strtoul (p, &p, 16);
635       if (!*p++ || i == 6)
636         break;
637     }
638
639   return (i == 6);
640 }
641
642 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
643 /* registry routine buffer preparation utility functions:
644  * parameter order is like strncpy, but returns count
645  * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
646  */
647 ulong
648 wchar2ascii (char *abuf, ushort * wbuf, ushort wbuflen, ulong abuflen)
649 {
650   ulong copyct = 1;
651   ushort i;
652
653   if (abuflen == 0)
654     return 0;
655
656   /* wbuflen is in bytes */
657   wbuflen /= sizeof (ushort);
658
659   for (i = 0; i < wbuflen; ++i)
660     {
661       if (--abuflen == 0)
662         break;
663       *abuf++ = (char) *wbuf++;
664       ++copyct;
665     }
666   *abuf = '\0';
667
668   return copyct;
669 }
670 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
671
672 #if 0
673 char *
674 bcm_ether_ntoa (struct ether_addr *ea, char *buf)
675 {
676   snprintf (buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
677             ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
678             ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
679   return (buf);
680 }
681
682 char *
683 bcm_ip_ntoa (struct ipv4_addr *ia, char *buf)
684 {
685   snprintf (buf, 16, "%d.%d.%d.%d",
686             ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
687   return (buf);
688 }
689 void
690 bcm_mdelay (uint ms)
691 {
692   uint i;
693
694   for (i = 0; i < ms; i++)
695     {
696       OSL_DELAY (1000);
697     }
698 }
699 #endif
700
701 #if 0
702
703 /*
704  * Search the name=value vars for a specific one and return its value.
705  * Returns NULL if not found.
706  */
707 char *
708 getvar (char *vars, const char *name)
709 {
710 #ifdef  _MINOSL_
711   return NULL;
712 #else
713   char *s;
714   int len;
715
716   if (!name)
717     return NULL;
718
719   len = strlen (name);
720   if (len == 0)
721     return NULL;
722
723   /* first look in vars[] */
724   for (s = vars; s && *s;)
725     {
726       /* CSTYLED */
727       if ((bcmp (s, name, len) == 0) && (s[len] == '='))
728         return (&s[len + 1]);
729
730       while (*s++)
731         ;
732     }
733
734   /* then query nvram */
735   return (nvram_get (name));
736 #endif /* _MINOSL_ */
737 }
738
739 /*
740  * Search the vars for a specific one and return its value as
741  * an integer. Returns 0 if not found.
742  */
743 int
744 getintvar (char *vars, const char *name)
745 {
746 #ifdef  _MINOSL_
747   return 0;
748 #else
749   char *val;
750
751   if ((val = getvar (vars, name)) == NULL)
752     return (0);
753
754   return (bcm_strtoul (val, NULL, 0));
755 #endif /* _MINOSL_ */
756 }
757
758
759 /* Search for token in comma separated token-string */
760 static int
761 findmatch (char *string, char *name)
762 {
763   uint len;
764   char *c;
765
766   len = strlen (name);
767   /* CSTYLED */
768   while ((c = strchr (string, ',')) != NULL)
769     {
770       if (len == (uint) (c - string) && !strncmp (string, name, len))
771         return 1;
772       string = c + 1;
773     }
774
775   return (!strcmp (string, name));
776 }
777
778 /* Return gpio pin number assigned to the named pin
779  *
780  * Variable should be in format:
781  *
782  *      gpio<N>=pin_name,pin_name
783  *
784  * This format allows multiple features to share the gpio with mutual
785  * understanding.
786  *
787  * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
788  * and if def_pin is not used by others.
789  */
790 uint
791 getgpiopin (char *vars, char *pin_name, uint def_pin)
792 {
793   char name[] = "gpioXXXX";
794   char *val;
795   uint pin;
796
797   /* Go thru all possibilities till a match in pin name */
798   for (pin = 0; pin < GPIO_NUMPINS; pin++)
799     {
800       snprintf (name, sizeof (name), "gpio%d", pin);
801       val = getvar (vars, name);
802       if (val && findmatch (val, pin_name))
803         return pin;
804     }
805
806   if (def_pin != GPIO_PIN_NOTDEFINED)
807     {
808       /* make sure the default pin is not used by someone else */
809       snprintf (name, sizeof (name), "gpio%d", def_pin);
810       if (getvar (vars, name))
811         {
812           def_pin = GPIO_PIN_NOTDEFINED;
813         }
814     }
815
816   return def_pin;
817 }
818 #endif
819
820 #ifdef BCMPERFSTATS
821
822 #define LOGSIZE 256             /* should be power of 2 to avoid div below */
823 static struct
824 {
825   uint cycles;
826   char *fmt;
827   uint a1;
828   uint a2;
829 } logtab[LOGSIZE];
830
831 /* last entry logged  */
832 static uint logi = 0;
833 /* next entry to read */
834 static uint readi = 0;
835
836 void
837 bcm_perf_enable ()
838 {
839   BCMPERF_ENABLE_INSTRCOUNT ();
840   BCMPERF_ENABLE_ICACHE_MISS ();
841   BCMPERF_ENABLE_ICACHE_HIT ();
842 }
843
844 void
845 bcmlog (char *fmt, uint a1, uint a2)
846 {
847   static uint last = 0;
848   uint cycles, i;
849   OSL_GETCYCLES (cycles);
850
851   i = logi;
852
853   logtab[i].cycles = cycles - last;
854   logtab[i].fmt = fmt;
855   logtab[i].a1 = a1;
856   logtab[i].a2 = a2;
857
858   logi = (i + 1) % LOGSIZE;
859   last = cycles;
860 }
861
862
863 void
864 bcmstats (char *fmt)
865 {
866   static uint last = 0;
867   static uint32 ic_miss = 0;
868   static uint32 instr_count = 0;
869   uint32 ic_miss_cur;
870   uint32 instr_count_cur;
871   uint cycles, i;
872
873   OSL_GETCYCLES (cycles);
874   BCMPERF_GETICACHE_MISS (ic_miss_cur);
875   BCMPERF_GETINSTRCOUNT (instr_count_cur);
876
877   i = logi;
878
879   logtab[i].cycles = cycles - last;
880   logtab[i].a1 = ic_miss_cur - ic_miss;
881   logtab[i].a2 = instr_count_cur - instr_count;
882   logtab[i].fmt = fmt;
883
884   logi = (i + 1) % LOGSIZE;
885
886   last = cycles;
887   instr_count = instr_count_cur;
888   ic_miss = ic_miss_cur;
889 }
890
891
892 void
893 bcmdumplog (char *buf, int size)
894 {
895   char *limit, *line;
896   int j = 0;
897   int num;
898
899   limit = buf + size - 80;
900   *buf = '\0';
901
902   num = logi - readi;
903
904   if (num < 0)
905     num += LOGSIZE;
906
907   /* print in chronological order */
908
909   for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++)
910     {
911       if (logtab[readi].fmt == NULL)
912         continue;
913       line = buf;
914       buf += sprintf (buf, "%d\t", logtab[readi].cycles);
915       buf +=
916         sprintf (buf, logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
917       buf += sprintf (buf, "\n");
918     }
919
920 }
921
922
923 /*
924  * Dump one log entry at a time.
925  * Return index of next entry or -1 when no more .
926  */
927 int
928 bcmdumplogent (char *buf, uint i)
929 {
930   bool hit;
931
932   /*
933    * If buf is NULL, return the starting index,
934    * interpreting i as the indicator of last 'i' entries to dump.
935    */
936   if (buf == NULL)
937     {
938       i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
939       return ((logi - i) % LOGSIZE);
940     }
941
942   *buf = '\0';
943
944   ASSERT (i < LOGSIZE);
945
946   if (i == logi)
947     return (-1);
948
949   hit = FALSE;
950   for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE)
951     {
952       if (logtab[i].fmt == NULL)
953         continue;
954       buf += sprintf (buf, "%d: %d\t", i, logtab[i].cycles);
955       buf += sprintf (buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
956       buf += sprintf (buf, "\n");
957       hit = TRUE;
958     }
959
960   return (i);
961 }
962
963 #endif /* BCMPERFSTATS */
964
965 #ifdef BCMDBG
966 /* pretty hex print a pkt buffer chain */
967 void
968 prpkt (const char *msg, osl_t * osh, void *p0)
969 {
970   void *p;
971
972   if (msg && (msg[0] != '\0'))
973     printf ("%s:\n", msg);
974
975   for (p = p0; p; p = PKTNEXT (osh, p))
976     prhex (NULL, PKTDATA (osh, p), PKTLEN (osh, p));
977 }
978 #endif /* BCMDBG */
979
980 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
981  * Also updates the inplace vlan tag if requested.
982  * For debugging, it returns an indication of what it did.
983  */
984 uint
985 pktsetprio (void *pkt, bool update_vtag)
986 {
987   struct ether_header *eh;
988   struct ethervlan_header *evh;
989   uint8 *pktdata;
990   int priority = 0;
991   int rc = 0;
992
993   pktdata = (uint8 *) PKTDATA (NULL, pkt);
994   ASSERT (ISALIGNED ((uintptr) pktdata, sizeof (uint16)));
995
996   eh = (struct ether_header *) pktdata;
997
998   if (ntoh16 (eh->ether_type) == ETHER_TYPE_8021Q)
999     {
1000       uint16 vlan_tag;
1001       int vlan_prio, dscp_prio = 0;
1002
1003       evh = (struct ethervlan_header *) eh;
1004
1005       vlan_tag = ntoh16 (evh->vlan_tag);
1006       vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
1007
1008       if (ntoh16 (evh->ether_type) == ETHER_TYPE_IP)
1009         {
1010           uint8 *ip_body = pktdata + sizeof (struct ethervlan_header);
1011           uint8 tos_tc = IP_TOS (ip_body);
1012           dscp_prio = (int) (tos_tc >> IPV4_TOS_PREC_SHIFT);
1013           if ((IP_VER (ip_body) == IP_VER_4)
1014               && (IPV4_PROT (ip_body) == IP_PROT_TCP))
1015             {
1016               int ip_len;
1017               int src_port;
1018               bool src_port_exc;
1019               uint8 *tcp_hdr;
1020
1021               ip_len = IPV4_PAYLOAD_LEN (ip_body);
1022               tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD (ip_body);
1023               src_port = TCP_SRC_PORT (tcp_hdr);
1024               src_port_exc = (src_port == 10110) || (src_port == 10120) ||
1025                 (src_port == 10130) || (src_port == 10140);
1026
1027               if ((ip_len == 40) && src_port_exc && TCP_IS_ACK (tcp_hdr))
1028                 {
1029                   dscp_prio = 7;
1030                 }
1031             }
1032         }
1033
1034       /* DSCP priority gets precedence over 802.1P (vlan tag) */
1035       if (dscp_prio != 0)
1036         {
1037           priority = dscp_prio;
1038           rc |= PKTPRIO_VDSCP;
1039         }
1040       else
1041         {
1042           priority = vlan_prio;
1043           rc |= PKTPRIO_VLAN;
1044         }
1045       /* 
1046        * If the DSCP priority is not the same as the VLAN priority,
1047        * then overwrite the priority field in the vlan tag, with the
1048        * DSCP priority value. This is required for Linux APs because
1049        * the VLAN driver on Linux, overwrites the skb->priority field
1050        * with the priority value in the vlan tag
1051        */
1052       if (update_vtag && (priority != vlan_prio))
1053         {
1054           vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
1055           vlan_tag |= (uint16) priority << VLAN_PRI_SHIFT;
1056           evh->vlan_tag = hton16 (vlan_tag);
1057           rc |= PKTPRIO_UPD;
1058         }
1059     }
1060   else if (ntoh16 (eh->ether_type) == ETHER_TYPE_IP)
1061     {
1062       uint8 *ip_body = pktdata + sizeof (struct ether_header);
1063       uint8 tos_tc = IP_TOS (ip_body);
1064       priority = (int) (tos_tc >> IPV4_TOS_PREC_SHIFT);
1065       rc |= PKTPRIO_DSCP;
1066       if ((IP_VER (ip_body) == IP_VER_4)
1067           && (IPV4_PROT (ip_body) == IP_PROT_TCP))
1068         {
1069           int ip_len;
1070           int src_port;
1071           bool src_port_exc;
1072           uint8 *tcp_hdr;
1073
1074           ip_len = IPV4_PAYLOAD_LEN (ip_body);
1075           tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD (ip_body);
1076           src_port = TCP_SRC_PORT (tcp_hdr);
1077           src_port_exc = (src_port == 10110) || (src_port == 10120) ||
1078             (src_port == 10130) || (src_port == 10140);
1079
1080           if ((ip_len == 40) && src_port_exc && TCP_IS_ACK (tcp_hdr))
1081             {
1082               priority = 7;
1083             }
1084         }
1085     }
1086
1087   ASSERT (priority >= 0 && priority <= MAXPRIO);
1088   PKTSETPRIO (pkt, priority);
1089   return (rc | priority);
1090 }
1091
1092 static char bcm_undeferrstr[BCME_STRLEN];
1093
1094 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1095
1096 /* Convert the error codes into related error strings  */
1097 const char *
1098 bcmerrorstr (int bcmerror)
1099 {
1100   /* check if someone added a bcmerror code but forgot to add errorstring */
1101   ASSERT (ABS (BCME_LAST) == (ARRAYSIZE (bcmerrorstrtable) - 1));
1102
1103   if (bcmerror > 0 || bcmerror < BCME_LAST)
1104     {
1105       snprintf (bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror);
1106       return bcm_undeferrstr;
1107     }
1108
1109   ASSERT (strlen (bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1110
1111   return bcmerrorstrtable[-bcmerror];
1112 }
1113
1114 #if 0
1115 static void BCMINITFN (bcm_nvram_refresh) (char *flash)
1116 {
1117   int i;
1118   int ret = 0;
1119
1120   ASSERT (flash);
1121
1122   /* default "empty" vars cache */
1123   bzero (flash, 2);
1124
1125   if ((ret = nvram_getall (flash, NVRAM_SPACE)))
1126     return;
1127
1128   /* determine nvram length */
1129   for (i = 0; i < NVRAM_SPACE; i++)
1130     {
1131       if (flash[i] == '\0' && flash[i + 1] == '\0')
1132         break;
1133     }
1134
1135   if (i > 1)
1136     vars_len = i + 2;
1137   else
1138     vars_len = 0;
1139 }
1140 #endif
1141
1142 #ifdef BCMDBG_PKT               /* pkt logging for debugging */
1143 /* Add a packet to the pktlist */
1144 void
1145 pktlist_add (pktlist_info_t * pktlist, void *pkt)
1146 {
1147   uint i;
1148   ASSERT (pktlist->count < PKTLIST_SIZE);
1149
1150   /* Verify the packet is not already part of the list */
1151   for (i = 0; i < pktlist->count; i++)
1152     {
1153       if (pktlist->list[i] == pkt)
1154         ASSERT (0);
1155     }
1156   pktlist->list[pktlist->count] = pkt;
1157   pktlist->count++;
1158   return;
1159 }
1160
1161 /* Remove a packet from the pktlist */
1162 void
1163 pktlist_remove (pktlist_info_t * pktlist, void *pkt)
1164 {
1165   uint i;
1166   uint num = pktlist->count;
1167
1168   /* find the index where pkt exists */
1169   for (i = 0; i < num; i++)
1170     {
1171       /* check for the existence of pkt in the list */
1172       if (pktlist->list[i] == pkt)
1173         {
1174           /* replace with the last element */
1175           pktlist->list[i] = pktlist->list[num - 1];
1176           pktlist->count--;
1177           return;
1178         }
1179     }
1180   ASSERT (0);
1181 }
1182
1183 /* Dump the pktlist (and the contents of each packet if 'data'
1184  * is set). 'buf' should be large enough
1185  */
1186
1187 char *
1188 pktlist_dump (pktlist_info_t * pktlist, char *buf)
1189 {
1190   char *obuf;
1191   uint i;
1192
1193   obuf = buf;
1194
1195   buf += sprintf (buf, "Packet list dump:\n");
1196
1197   for (i = 0; i < (pktlist->count); i++)
1198     {
1199       buf += sprintf (buf, "0x%p\t", pktlist->list[i]);
1200
1201 #ifdef NOTDEF                   /* Remove this ifdef to print pkttag and pktdata */
1202       if (PKTTAG (pktlist->list[i]))
1203         {
1204           /* Print pkttag */
1205           buf += sprintf (buf, "Pkttag(in hex): ");
1206           buf +=
1207             bcm_format_hex (buf, PKTTAG (pktlist->list[i]), OSL_PKTTAG_SZ);
1208         }
1209       buf += sprintf (buf, "Pktdata(in hex): ");
1210       buf += bcm_format_hex (buf, PKTDATA (NULL, pktlist->list[i]),
1211                              PKTLEN (NULL, pktlist->list[i]));
1212 #endif /* NOTDEF */
1213
1214       buf += sprintf (buf, "\n");
1215     }
1216   return obuf;
1217 }
1218 #endif /* BCMDBG_PKT */
1219
1220 #if 0
1221 /* iovar table lookup */
1222 const bcm_iovar_t *
1223 bcm_iovar_lookup (const bcm_iovar_t * table, const char *name)
1224 {
1225   const bcm_iovar_t *vi;
1226   const char *lookup_name;
1227
1228   /* skip any ':' delimited option prefixes */
1229   lookup_name = strrchr (name, ':');
1230   if (lookup_name != NULL)
1231     lookup_name++;
1232   else
1233     lookup_name = name;
1234
1235   ASSERT (table);
1236
1237   for (vi = table; vi->name; vi++)
1238     {
1239       if (!strcmp (vi->name, lookup_name))
1240         return vi;
1241     }
1242   /* ran to end of table */
1243
1244   return NULL;                  /* var name not found */
1245 }
1246 #endif
1247
1248 int
1249 bcm_iovar_lencheck (const bcm_iovar_t * vi, void *arg, int len, bool set)
1250 {
1251   int bcmerror = 0;
1252
1253   /* length check on io buf */
1254   switch (vi->type)
1255     {
1256     case IOVT_BOOL:
1257     case IOVT_INT8:
1258     case IOVT_INT16:
1259     case IOVT_INT32:
1260     case IOVT_UINT8:
1261     case IOVT_UINT16:
1262     case IOVT_UINT32:
1263       /* all integers are int32 sized args at the ioctl interface */
1264       if (len < (int) sizeof (int))
1265         {
1266           bcmerror = BCME_BUFTOOSHORT;
1267         }
1268       break;
1269
1270     case IOVT_BUFFER:
1271       /* buffer must meet minimum length requirement */
1272       if (len < vi->minlen)
1273         {
1274           bcmerror = BCME_BUFTOOSHORT;
1275         }
1276       break;
1277
1278     case IOVT_VOID:
1279       if (!set)
1280         {
1281           /* Cannot return nil... */
1282           bcmerror = BCME_UNSUPPORTED;
1283         }
1284       else if (len)
1285         {
1286           /* Set is an action w/o parameters */
1287           bcmerror = BCME_BUFTOOLONG;
1288         }
1289       break;
1290
1291     default:
1292       /* unknown type for length check in iovar info */
1293       ASSERT (0);
1294       bcmerror = BCME_UNSUPPORTED;
1295     }
1296
1297   return bcmerror;
1298 }
1299
1300 #define CRC_INNER_LOOP(n, c, x) \
1301         (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1302
1303 #if 0
1304 /*******************************************************************************
1305  * crc8
1306  *
1307  * Computes a crc8 over the input data using the polynomial:
1308  *
1309  *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
1310  *
1311  * The caller provides the initial value (either CRC8_INIT_VALUE
1312  * or the previous returned value) to allow for processing of
1313  * discontiguous blocks of data.  When generating the CRC the
1314  * caller is responsible for complementing the final return value
1315  * and inserting it into the byte stream.  When checking, a final
1316  * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1317  *
1318  * Reference: Dallas Semiconductor Application Note 27
1319  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1320  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1321  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1322  *
1323  * ****************************************************************************
1324  */
1325
1326 static const uint8 crc8_table[256] = {
1327   0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1328   0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1329   0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1330   0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1331   0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1332   0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1333   0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1334   0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1335   0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1336   0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1337   0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1338   0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1339   0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1340   0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1341   0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1342   0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1343   0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1344   0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1345   0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1346   0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1347   0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1348   0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1349   0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1350   0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1351   0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1352   0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1353   0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1354   0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1355   0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1356   0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1357   0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1358   0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1359 };
1360
1361 uint8 BCMROMFN (hndcrc8) (uint8 * pdata,        /* pointer to array of data to process */
1362                           uint nbytes,  /* number of input data bytes to process */
1363                           uint8 crc     /* either CRC8_INIT_VALUE or previous return value */
1364   )
1365 {
1366   /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1367    * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1368    */
1369   while (nbytes-- > 0)
1370     crc = crc8_table[(crc ^ *pdata++) & 0xff];
1371
1372   return crc;
1373 }
1374
1375 /*******************************************************************************
1376  * crc16
1377  *
1378  * Computes a crc16 over the input data using the polynomial:
1379  *
1380  *       x^16 + x^12 +x^5 + 1
1381  *
1382  * The caller provides the initial value (either CRC16_INIT_VALUE
1383  * or the previous returned value) to allow for processing of
1384  * discontiguous blocks of data.  When generating the CRC the
1385  * caller is responsible for complementing the final return value
1386  * and inserting it into the byte stream.  When checking, a final
1387  * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1388  *
1389  * Reference: Dallas Semiconductor Application Note 27
1390  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1391  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1392  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1393  *
1394  * ****************************************************************************
1395  */
1396 static const uint16 crc16_table[256] = {
1397   0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1398   0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1399   0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1400   0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1401   0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1402   0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1403   0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1404   0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1405   0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1406   0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1407   0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1408   0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1409   0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1410   0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1411   0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1412   0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1413   0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1414   0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1415   0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1416   0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1417   0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1418   0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1419   0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1420   0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1421   0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1422   0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1423   0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1424   0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1425   0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1426   0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1427   0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1428   0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1429 };
1430
1431 uint16 BCMROMFN (hndcrc16) (uint8 * pdata,      /* pointer to array of data to process */
1432                             uint nbytes,        /* number of input data bytes to process */
1433                             uint16 crc  /* either CRC16_INIT_VALUE or previous return value */
1434   )
1435 {
1436   while (nbytes-- > 0)
1437     CRC_INNER_LOOP (16, crc, *pdata++);
1438   return crc;
1439 }
1440 #endif
1441
1442 static const uint32 crc32_table[256] = {
1443   0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1444   0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1445   0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1446   0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1447   0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1448   0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1449   0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1450   0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1451   0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1452   0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1453   0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1454   0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1455   0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1456   0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1457   0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1458   0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1459   0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1460   0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1461   0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1462   0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1463   0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1464   0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1465   0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1466   0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1467   0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1468   0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1469   0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1470   0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1471   0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1472   0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1473   0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1474   0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1475   0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1476   0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1477   0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1478   0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1479   0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1480   0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1481   0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1482   0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1483   0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1484   0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1485   0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1486   0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1487   0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1488   0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1489   0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1490   0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1491   0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1492   0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1493   0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1494   0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1495   0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1496   0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1497   0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1498   0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1499   0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1500   0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1501   0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1502   0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1503   0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1504   0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1505   0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1506   0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1507 };
1508
1509 uint32 BCMROMFN (hndcrc32) (uint8 * pdata,      /* pointer to array of data to process */
1510                             uint nbytes,        /* number of input data bytes to process */
1511                             uint32 crc  /* either CRC32_INIT_VALUE or previous return value */
1512   )
1513 {
1514   uint8 *pend;
1515 #ifdef __mips__
1516   uint8 tmp[4];
1517   ulong *tptr = (ulong *) tmp;
1518
1519   /* in case the beginning of the buffer isn't aligned */
1520   pend = (uint8 *) ((uint) (pdata + 3) & 0xfffffffc);
1521   nbytes -= (pend - pdata);
1522   while (pdata < pend)
1523     CRC_INNER_LOOP (32, crc, *pdata++);
1524
1525   /* handle bulk of data as 32-bit words */
1526   pend = pdata + (nbytes & 0xfffffffc);
1527   while (pdata < pend)
1528     {
1529       *tptr = *(ulong *) pdata;
1530       pdata += sizeof (ulong *);
1531       CRC_INNER_LOOP (32, crc, tmp[0]);
1532       CRC_INNER_LOOP (32, crc, tmp[1]);
1533       CRC_INNER_LOOP (32, crc, tmp[2]);
1534       CRC_INNER_LOOP (32, crc, tmp[3]);
1535     }
1536
1537   /* 1-3 bytes at end of buffer */
1538   pend = pdata + (nbytes & 0x03);
1539   while (pdata < pend)
1540     CRC_INNER_LOOP (32, crc, *pdata++);
1541 #else
1542   pend = pdata + nbytes;
1543   while (pdata < pend)
1544     CRC_INNER_LOOP (32, crc, *pdata++);
1545 #endif /* __mips__ */
1546
1547   return crc;
1548 }
1549
1550 #ifdef notdef
1551 #define CLEN    1499            /*  CRC Length */
1552 #define CBUFSIZ         (CLEN+4)
1553 #define CNBUFS          5       /* # of bufs */
1554
1555 void
1556 testcrc32 (void)
1557 {
1558   uint j, k, l;
1559   uint8 *buf;
1560   uint len[CNBUFS];
1561   uint32 crcr;
1562   uint32 crc32tv[CNBUFS] =
1563     { 0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110 };
1564
1565   ASSERT ((buf = MALLOC (CBUFSIZ * CNBUFS)) != NULL);
1566
1567   /* step through all possible alignments */
1568   for (l = 0; l <= 4; l++)
1569     {
1570       for (j = 0; j < CNBUFS; j++)
1571         {
1572           len[j] = CLEN;
1573           for (k = 0; k < len[j]; k++)
1574             *(buf + j * CBUFSIZ + (k + l)) = (j + k) & 0xff;
1575         }
1576
1577       for (j = 0; j < CNBUFS; j++)
1578         {
1579           crcr = crc32 (buf + j * CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1580           ASSERT (crcr == crc32tv[j]);
1581         }
1582     }
1583
1584   MFREE (buf, CBUFSIZ * CNBUFS);
1585   return;
1586 }
1587 #endif /* notdef */
1588
1589 /*
1590  * Advance from the current 1-byte tag/1-byte length/variable-length value
1591  * triple, to the next, returning a pointer to the next.
1592  * If the current or next TLV is invalid (does not fit in given buffer length),
1593  * NULL is returned.
1594  * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1595  * by the TLV parameter's length if it is valid.
1596  */
1597 bcm_tlv_t *BCMROMFN (bcm_next_tlv) (bcm_tlv_t * elt, int *buflen)
1598 {
1599   int len;
1600
1601   /* validate current elt */
1602   if (!bcm_valid_tlv (elt, *buflen))
1603     return NULL;
1604
1605   /* advance to next elt */
1606   len = elt->len;
1607   elt = (bcm_tlv_t *) (elt->data + len);
1608   *buflen -= (2 + len);
1609
1610   /* validate next elt */
1611   if (!bcm_valid_tlv (elt, *buflen))
1612     return NULL;
1613
1614   return elt;
1615 }
1616
1617 /*
1618  * Traverse a string of 1-byte tag/1-byte length/variable-length value
1619  * triples, returning a pointer to the substring whose first element
1620  * matches tag
1621  */
1622 bcm_tlv_t *BCMROMFN (bcm_parse_tlvs) (void *buf, int buflen, uint key)
1623 {
1624   bcm_tlv_t *elt;
1625   int totlen;
1626
1627   elt = (bcm_tlv_t *) buf;
1628   totlen = buflen;
1629
1630   /* find tagged parameter */
1631   while (totlen >= 2)
1632     {
1633       int len = elt->len;
1634
1635       /* validate remaining totlen */
1636       if ((elt->id == key) && (totlen >= (len + 2)))
1637         return (elt);
1638
1639       elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1640       totlen -= (len + 2);
1641     }
1642
1643   return NULL;
1644 }
1645
1646 #if 0
1647 /*
1648  * Traverse a string of 1-byte tag/1-byte length/variable-length value
1649  * triples, returning a pointer to the substring whose first element
1650  * matches tag.  Stop parsing when we see an element whose ID is greater
1651  * than the target key.
1652  */
1653 bcm_tlv_t *BCMROMFN (bcm_parse_ordered_tlvs) (void *buf, int buflen, uint key)
1654 {
1655   bcm_tlv_t *elt;
1656   int totlen;
1657
1658   elt = (bcm_tlv_t *) buf;
1659   totlen = buflen;
1660
1661   /* find tagged parameter */
1662   while (totlen >= 2)
1663     {
1664       uint id = elt->id;
1665       int len = elt->len;
1666
1667       /* Punt if we start seeing IDs > than target key */
1668       if (id > key)
1669         return (NULL);
1670
1671       /* validate remaining totlen */
1672       if ((id == key) && (totlen >= (len + 2)))
1673         return (elt);
1674
1675       elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1676       totlen -= (len + 2);
1677     }
1678   return NULL;
1679 }
1680
1681 #ifdef BCMDBG
1682 int
1683 bcm_format_flags (const bcm_bit_desc_t * bd, uint32 flags, char *buf, int len)
1684 {
1685   int i;
1686   char *p = buf;
1687   char hexstr[16];
1688   int slen = 0;
1689   uint32 bit;
1690   const char *name;
1691
1692   if (len < 2 || !buf)
1693     return 0;
1694
1695   buf[0] = '\0';
1696   len -= 1;
1697
1698   for (i = 0; flags != 0; i++)
1699     {
1700       bit = bd[i].bit;
1701       name = bd[i].name;
1702       if (bit == 0 && flags)
1703         {
1704           /* print any unnamed bits */
1705           sprintf (hexstr, "0x%X", flags);
1706           name = hexstr;
1707           flags = 0;            /* exit loop */
1708         }
1709       else if ((flags & bit) == 0)
1710         continue;
1711       slen += strlen (name);
1712       if (len < slen)
1713         break;
1714       if (p != buf)
1715         p += sprintf (p, " ");  /* btwn flag space */
1716       strcat (p, name);
1717       p += strlen (name);
1718       flags &= ~bit;
1719       len -= slen;
1720       slen = 1;                 /* account for btwn flag space */
1721     }
1722
1723   /* indicate the str was too short */
1724   if (flags != 0)
1725     {
1726       if (len == 0)
1727         p--;                    /* overwrite last char */
1728       p += sprintf (p, ">");
1729     }
1730
1731   return (int) (p - buf);
1732 }
1733
1734 void
1735 deadbeef (void *p, uint len)
1736 {
1737   static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1738
1739   while (len-- > 0)
1740     {
1741       *(uint8 *) p = meat[((uintptr) p) & 3];
1742       p = (uint8 *) p + 1;
1743     }
1744 }
1745
1746 /* pretty hex print a contiguous buffer */
1747 void
1748 prhex (const char *msg, uchar * buf, uint nbytes)
1749 {
1750   char line[128], *p;
1751   uint i;
1752
1753   if (msg && (msg[0] != '\0'))
1754     printf ("%s:\n", msg);
1755
1756   p = line;
1757   for (i = 0; i < nbytes; i++)
1758     {
1759       if (i % 16 == 0)
1760         {
1761           p += sprintf (p, "  %04d: ", i);      /* line prefix */
1762         }
1763       p += sprintf (p, "%02x ", buf[i]);
1764       if (i % 16 == 15)
1765         {
1766           printf ("%s\n", line);        /* flush line */
1767           p = line;
1768         }
1769     }
1770
1771   /* flush last partial line */
1772   if (p != line)
1773     printf ("%s\n", line);
1774 }
1775
1776 /* print bytes formatted as hex to a string. return the resulting string length */
1777 int
1778 bcm_format_hex (char *str, const void *bytes, int len)
1779 {
1780   int i;
1781   char *p = str;
1782   const uint8 *src = (const uint8 *) bytes;
1783
1784   for (i = 0; i < len; i++)
1785     {
1786       p += sprintf (p, "%02X", *src);
1787       src++;
1788     }
1789   return (int) (p - str);
1790 }
1791
1792 #endif /* BCMDBG */
1793
1794 /* Produce a human-readable string for boardrev */
1795 char *
1796 bcm_brev_str (uint16 brev, char *buf)
1797 {
1798   if (brev < 0x100)
1799     snprintf (buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1800   else
1801     snprintf (buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A',
1802               brev & 0xfff);
1803
1804   return (buf);
1805 }
1806
1807 #define BUFSIZE_TODUMP_ATONCE 512       /* Buffer size */
1808
1809 /* dump large strings to console */
1810 void
1811 printfbig (char *buf)
1812 {
1813   uint len, max_len;
1814   char c;
1815
1816   len = strlen (buf);
1817
1818   max_len = BUFSIZE_TODUMP_ATONCE;
1819
1820   while (len > max_len)
1821     {
1822       c = buf[max_len];
1823       buf[max_len] = '\0';
1824       printf ("%s", buf);
1825       buf[max_len] = c;
1826
1827       buf += max_len;
1828       len -= max_len;
1829     }
1830   /* print the remaining string */
1831   printf ("%s\n", buf);
1832   return;
1833 }
1834
1835 /* routine to dump fields in a fileddesc structure */
1836 uint
1837 bcmdumpfields (readreg_rtn read_rtn, void *arg0, void *arg1,
1838                struct fielddesc * fielddesc_array, char *buf, uint32 bufsize)
1839 {
1840   uint filled_len;
1841   int len;
1842   struct fielddesc *cur_ptr;
1843
1844   filled_len = 0;
1845   cur_ptr = fielddesc_array;
1846
1847   while (bufsize > 1)
1848     {
1849       if (cur_ptr->nameandfmt == NULL)
1850         break;
1851       len = snprintf (buf, bufsize, cur_ptr->nameandfmt,
1852                       read_rtn (arg0, arg1, cur_ptr->offset));
1853       /* check for snprintf overflow or error */
1854       if (len < 0 || (uint32) len >= bufsize)
1855         len = bufsize - 1;
1856       buf += len;
1857       bufsize -= len;
1858       filled_len += len;
1859       cur_ptr++;
1860     }
1861   return filled_len;
1862 }
1863 #endif
1864
1865 uint
1866 bcm_mkiovar (char *name, char *data, uint datalen, char *buf, uint buflen)
1867 {
1868   uint len;
1869
1870   len = strlen (name) + 1;
1871
1872   if ((len + datalen) > buflen)
1873     return 0;
1874
1875   strncpy (buf, name, buflen);
1876
1877   /* append data onto the end of the name string */
1878   memcpy (&buf[len], data, datalen);
1879   len += datalen;
1880
1881   return len;
1882 }
1883
1884 /* Quarter dBm units to mW
1885  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1886  * Table is offset so the last entry is largest mW value that fits in
1887  * a uint16.
1888  */
1889
1890 #define QDBM_OFFSET 153         /* Offset for first entry */
1891 #define QDBM_TABLE_LEN 40       /* Table size */
1892
1893 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1894  * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1895  */
1896 #define QDBM_TABLE_LOW_BOUND 6493       /* Low bound */
1897
1898 /* Largest mW value that will round down to the last table entry,
1899  * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1900  * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1901  */
1902 #define QDBM_TABLE_HIGH_BOUND 64938     /* High bound */
1903
1904 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1905 /* qdBm:        +0      +1      +2      +3      +4      +5      +6      +7 */
1906 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1907 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1908 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1909 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1910 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1911 };
1912
1913 uint16 BCMROMFN (bcm_qdbm_to_mw) (uint8 qdbm)
1914 {
1915   uint factor = 1;
1916   int idx = qdbm - QDBM_OFFSET;
1917
1918   if (idx > QDBM_TABLE_LEN)
1919     {
1920       /* clamp to max uint16 mW value */
1921       return 0xFFFF;
1922     }
1923
1924   /* scale the qdBm index up to the range of the table 0-40
1925    * where an offset of 40 qdBm equals a factor of 10 mW.
1926    */
1927   while (idx < 0)
1928     {
1929       idx += 40;
1930       factor *= 10;
1931     }
1932
1933   /* return the mW value scaled down to the correct factor of 10,
1934    * adding in factor/2 to get proper rounding.
1935    */
1936   return ((nqdBm_to_mW_map[idx] + factor / 2) / factor);
1937 }
1938
1939 uint8 BCMROMFN (bcm_mw_to_qdbm) (uint16 mw)
1940 {
1941   uint8 qdbm;
1942   int offset;
1943   uint mw_uint = mw;
1944   uint boundary;
1945
1946   /* handle boundary case */
1947   if (mw_uint <= 1)
1948     return 0;
1949
1950   offset = QDBM_OFFSET;
1951
1952   /* move mw into the range of the table */
1953   while (mw_uint < QDBM_TABLE_LOW_BOUND)
1954     {
1955       mw_uint *= 10;
1956       offset -= 40;
1957     }
1958
1959   for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++)
1960     {
1961       boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1962                                           nqdBm_to_mW_map[qdbm]) / 2;
1963       if (mw_uint < boundary)
1964         break;
1965     }
1966
1967   qdbm += (uint8) offset;
1968
1969   return (qdbm);
1970 }
1971
1972
1973 uint BCMROMFN (bcm_bitcount) (uint8 * bitmap, uint length)
1974 {
1975   uint bitcount = 0, i;
1976   uint8 tmp;
1977   for (i = 0; i < length; i++)
1978     {
1979       tmp = bitmap[i];
1980       while (tmp)
1981         {
1982           bitcount++;
1983           tmp &= (tmp - 1);
1984         }
1985     }
1986   return bitcount;
1987 }
1988
1989
1990 /* Initialization of bcmstrbuf structure */
1991 void
1992 bcm_binit (struct bcmstrbuf *b, char *buf, uint size)
1993 {
1994   b->origsize = b->size = size;
1995   b->origbuf = b->buf = buf;
1996 }
1997
1998 /* Buffer sprintf wrapper to guard against buffer overflow */
1999 int
2000 bcm_bprintf (struct bcmstrbuf *b, const char *fmt, ...)
2001 {
2002   va_list ap;
2003   int r;
2004
2005   va_start (ap, fmt);
2006   r = vsnprintf (b->buf, b->size, fmt, ap);
2007
2008   /* Non Ansi C99 compliant returns -1,
2009    * Ansi compliant return r >= b->size,
2010    * bcmstdlib returns 0, handle all
2011    */
2012   if ((r == -1) || (r >= (int) b->size) || (r == 0))
2013     {
2014       b->size = 0;
2015     }
2016   else
2017     {
2018       b->size -= r;
2019       b->buf += r;
2020     }
2021
2022   va_end (ap);
2023
2024   return r;
2025 }
2026
2027 char *
2028 bcm_ether_ntoa (struct ether_addr *ea, char *buf)
2029 {
2030         snprintf (buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
2031                 ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
2032                 ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
2033         return (buf);
2034 }
2035