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