get rid of $Id$ - it has never helped us and it has broken too many patches ;)
[openwrt/staging/yousong.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