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