2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <linux/ctype.h>
22 #include <linux/kernel.h>
26 #include <bcmendian.h>
28 #include <proto/ethernet.h>
29 #include <proto/802.1d.h>
30 #include <proto/802.11.h>
33 /* nvram vars cache */
34 static char *nvram_vars
;
35 static int vars_len
= -1;
38 /* copy a pkt buffer chain into a buffer */
39 uint
pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
44 len
= 4096; /* "infinite" */
46 /* skip 'offset' bytes */
47 for (; p
&& offset
; p
= PKTNEXT(p
)) {
48 if (offset
< (uint
) PKTLEN(p
))
57 for (; p
&& len
; p
= PKTNEXT(p
)) {
58 n
= MIN((uint
) PKTLEN(p
) - offset
, (uint
) len
);
59 bcopy(PKTDATA(p
) + offset
, buf
, n
);
69 /* copy a buffer into a pkt buffer chain */
70 uint
pktfrombuf(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
74 /* skip 'offset' bytes */
75 for (; p
&& offset
; p
= PKTNEXT(p
)) {
76 if (offset
< (uint
) PKTLEN(p
))
85 for (; p
&& len
; p
= PKTNEXT(p
)) {
86 n
= MIN((uint
) PKTLEN(p
) - offset
, (uint
) len
);
87 bcopy(buf
, PKTDATA(p
) + offset
, n
);
97 /* return total length of buffer chain */
98 uint BCMFASTPATH
pkttotlen(osl_t
*osh
, void *p
)
103 for (; p
; p
= PKTNEXT(p
))
108 /* return the last buffer of chained pkt */
109 void *pktlast(osl_t
*osh
, void *p
)
111 for (; PKTNEXT(p
); p
= PKTNEXT(p
))
117 /* count segments of a chained packet */
118 uint BCMFASTPATH
pktsegcnt(osl_t
*osh
, void *p
)
122 for (cnt
= 0; p
; p
= PKTNEXT(p
))
129 * osl multiple-precedence packet queue
130 * hi_prec is always >= the number of the highest non-empty precedence
132 void *BCMFASTPATH
pktq_penq(struct pktq
*pq
, int prec
, void *p
)
136 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
137 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
139 ASSERT(!pktq_full(pq
));
140 ASSERT(!pktq_pfull(pq
, prec
));
145 PKTSETLINK(q
->tail
, p
);
154 if (pq
->hi_prec
< prec
)
155 pq
->hi_prec
= (uint8
) prec
;
160 void *BCMFASTPATH
pktq_penq_head(struct pktq
*pq
, int prec
, void *p
)
164 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
165 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
167 ASSERT(!pktq_full(pq
));
168 ASSERT(!pktq_pfull(pq
, prec
));
175 PKTSETLINK(p
, q
->head
);
181 if (pq
->hi_prec
< prec
)
182 pq
->hi_prec
= (uint8
) prec
;
187 void *BCMFASTPATH
pktq_pdeq(struct pktq
*pq
, int prec
)
192 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
200 q
->head
= PKTLINK(p
);
213 void *BCMFASTPATH
pktq_pdeq_tail(struct pktq
*pq
, int prec
)
218 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
226 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
230 PKTSETLINK(prev
, NULL
);
243 pktq_pflush(osl_t
*osh
, struct pktq
*pq
, int prec
, bool dir
, ifpkt_cb_t fn
,
247 void *p
, *prev
= NULL
;
252 if (fn
== NULL
|| (*fn
) (p
, arg
)) {
253 bool head
= (p
== q
->head
);
255 q
->head
= PKTLINK(p
);
257 PKTSETLINK(prev
, PKTLINK(p
));
259 PKTFREE(osh
, p
, dir
);
262 p
= (head
? q
->head
: PKTLINK(prev
));
269 if (q
->head
== NULL
) {
275 bool BCMFASTPATH
pktq_pdel(struct pktq
*pq
, void *pktbuf
, int prec
)
280 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
287 if (q
->head
== pktbuf
) {
288 q
->head
= PKTLINK(pktbuf
);
292 for (p
= q
->head
; p
&& PKTLINK(p
) != pktbuf
; p
= PKTLINK(p
))
297 PKTSETLINK(p
, PKTLINK(pktbuf
));
298 if (q
->tail
== pktbuf
)
304 PKTSETLINK(pktbuf
, NULL
);
308 void pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
312 ASSERT(num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
314 /* pq is variable size; only zero out what's requested */
316 OFFSETOF(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
318 pq
->num_prec
= (uint16
) num_prec
;
320 pq
->max
= (uint16
) max_len
;
322 for (prec
= 0; prec
< num_prec
; prec
++)
323 pq
->q
[prec
].max
= pq
->max
;
326 void *BCMFASTPATH
pktq_deq(struct pktq
*pq
, int *prec_out
)
335 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
344 q
->head
= PKTLINK(p
);
360 void *BCMFASTPATH
pktq_deq_tail(struct pktq
*pq
, int *prec_out
)
369 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
370 if (pq
->q
[prec
].head
)
379 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
383 PKTSETLINK(prev
, NULL
);
400 void *pktq_peek(struct pktq
*pq
, int *prec_out
)
407 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
413 return pq
->q
[prec
].head
;
416 void *pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
423 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
424 if (pq
->q
[prec
].head
)
430 return pq
->q
[prec
].tail
;
433 void pktq_flush(osl_t
*osh
, struct pktq
*pq
, bool dir
, ifpkt_cb_t fn
, int arg
)
436 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
437 pktq_pflush(osh
, pq
, prec
, dir
, fn
, arg
);
439 ASSERT(pq
->len
== 0);
442 /* Return sum of lengths of a specific set of precedences */
443 int pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
449 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
450 if (prec_bmp
& (1 << prec
))
451 len
+= pq
->q
[prec
].len
;
456 /* Priority dequeue from a specific set of precedences */
457 void *BCMFASTPATH
pktq_mdeq(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
466 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
469 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
479 q
->head
= PKTLINK(p
);
495 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
496 int BCMROMFN(bcm_ether_atoe
) (char *p
, struct ether_addr
*ea
)
501 ea
->octet
[i
++] = (char)simple_strtoul(p
, &p
, 16);
509 char *bcm_ether_ntoa(const struct ether_addr
*ea
, char *buf
)
511 snprintf(buf
, 18, "%pM", ea
->octet
);
515 void bcm_mdelay(uint ms
)
519 for (i
= 0; i
< ms
; i
++) {
525 * Search the name=value vars for a specific one and return its value.
526 * Returns NULL if not found.
528 char *getvar(char *vars
, const char *name
)
540 /* first look in vars[] */
541 for (s
= vars
; s
&& *s
;) {
542 if ((bcmp(s
, name
, len
) == 0) && (s
[len
] == '='))
549 /* then query nvram */
550 return nvram_get(name
);
554 * Search the vars for a specific one and return its value as
555 * an integer. Returns 0 if not found.
557 int getintvar(char *vars
, const char *name
)
561 val
= getvar(vars
, name
);
565 return simple_strtoul(val
, NULL
, 0);
568 int getintvararray(char *vars
, const char *name
, uint8 index
)
574 buf
= getvar(vars
, name
);
579 /* table values are always separated by "," or " " */
580 while (*buf
!= '\0') {
581 val
= simple_strtoul(buf
, &endp
, 0);
586 /* delimiter is ',' */
594 /* Search for token in comma separated token-string */
595 static int findmatch(char *string
, char *name
)
601 while ((c
= strchr(string
, ',')) != NULL
) {
602 if (len
== (uint
) (c
- string
) && !strncmp(string
, name
, len
))
607 return !strcmp(string
, name
);
610 /* Return gpio pin number assigned to the named pin
612 * Variable should be in format:
614 * gpio<N>=pin_name,pin_name
616 * This format allows multiple features to share the gpio with mutual
619 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
620 * and if def_pin is not used by others.
622 uint
getgpiopin(char *vars
, char *pin_name
, uint def_pin
)
624 char name
[] = "gpioXXXX";
628 /* Go thru all possibilities till a match in pin name */
629 for (pin
= 0; pin
< GPIO_NUMPINS
; pin
++) {
630 snprintf(name
, sizeof(name
), "gpio%d", pin
);
631 val
= getvar(vars
, name
);
632 if (val
&& findmatch(val
, pin_name
))
636 if (def_pin
!= GPIO_PIN_NOTDEFINED
) {
637 /* make sure the default pin is not used by someone else */
638 snprintf(name
, sizeof(name
), "gpio%d", def_pin
);
639 if (getvar(vars
, name
)) {
640 def_pin
= GPIO_PIN_NOTDEFINED
;
647 /* pretty hex print a pkt buffer chain */
648 void prpkt(const char *msg
, osl_t
*osh
, void *p0
)
652 if (msg
&& (msg
[0] != '\0'))
653 printf("%s:\n", msg
);
655 for (p
= p0
; p
; p
= PKTNEXT(p
))
656 prhex(NULL
, PKTDATA(p
), PKTLEN(p
));
658 #endif /* defined(BCMDBG) */
660 static char bcm_undeferrstr
[32];
661 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
663 /* Convert the error codes into related error strings */
664 const char *bcmerrorstr(int bcmerror
)
666 /* check if someone added a bcmerror code but forgot to add errorstring */
667 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
669 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
670 snprintf(bcm_undeferrstr
, sizeof(bcm_undeferrstr
),
671 "Undefined error %d", bcmerror
);
672 return bcm_undeferrstr
;
675 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
677 return bcmerrorstrtable
[-bcmerror
];
681 static void BCMINITFN(bcm_nvram_refresh
) (char *flash
)
686 ASSERT(flash
!= NULL
);
688 /* default "empty" vars cache */
691 ret
= nvram_getall(flash
, NVRAM_SPACE
);
695 /* determine nvram length */
696 for (i
= 0; i
< NVRAM_SPACE
; i
++) {
697 if (flash
[i
] == '\0' && flash
[i
+ 1] == '\0')
707 char *bcm_nvram_vars(uint
*length
)
710 /* cache may be stale if nvram is read/write */
712 ASSERT(!bcmreclaimed
);
713 bcm_nvram_refresh(nvram_vars
);
721 /* copy nvram vars into locally-allocated multi-string array */
722 int BCMINITFN(bcm_nvram_cache
) (void *sih
)
730 bcm_nvram_refresh(nvram_vars
);
735 osh
= si_osh((si_t
*) sih
);
737 /* allocate memory and read in flash */
738 flash
= MALLOC(osh
, NVRAM_SPACE
);
744 bcm_nvram_refresh(flash
);
747 /* copy into a properly-sized buffer */
748 nvram_vars
= MALLOC(osh
, vars_len
);
752 bcopy(flash
, nvram_vars
, vars_len
);
754 MFREE(osh
, flash
, NVRAM_SPACE
);
756 /* cache must be full size of nvram if read/write */
758 #endif /* BCMNVRAMR */
765 /* iovar table lookup */
766 const bcm_iovar_t
*bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
768 const bcm_iovar_t
*vi
;
769 const char *lookup_name
;
771 /* skip any ':' delimited option prefixes */
772 lookup_name
= strrchr(name
, ':');
773 if (lookup_name
!= NULL
)
778 ASSERT(table
!= NULL
);
780 for (vi
= table
; vi
->name
; vi
++) {
781 if (!strcmp(vi
->name
, lookup_name
))
784 /* ran to end of table */
786 return NULL
; /* var name not found */
789 int bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
793 /* length check on io buf */
802 /* all integers are int32 sized args at the ioctl interface */
803 if (len
< (int)sizeof(int)) {
804 bcmerror
= BCME_BUFTOOSHORT
;
809 /* buffer must meet minimum length requirement */
810 if (len
< vi
->minlen
) {
811 bcmerror
= BCME_BUFTOOSHORT
;
817 /* Cannot return nil... */
818 bcmerror
= BCME_UNSUPPORTED
;
820 /* Set is an action w/o parameters */
821 bcmerror
= BCME_BUFTOOLONG
;
826 /* unknown type for length check in iovar info */
828 bcmerror
= BCME_UNSUPPORTED
;
834 /*******************************************************************************
837 * Computes a crc8 over the input data using the polynomial:
839 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
841 * The caller provides the initial value (either CRC8_INIT_VALUE
842 * or the previous returned value) to allow for processing of
843 * discontiguous blocks of data. When generating the CRC the
844 * caller is responsible for complementing the final return value
845 * and inserting it into the byte stream. When checking, a final
846 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
848 * Reference: Dallas Semiconductor Application Note 27
849 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
850 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
851 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
853 * ****************************************************************************
856 static const uint8 crc8_table
[256] = {
857 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
858 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
859 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
860 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
861 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
862 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
863 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
864 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
865 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
866 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
867 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
868 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
869 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
870 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
871 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
872 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
873 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
874 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
875 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
876 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
877 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
878 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
879 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
880 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
881 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
882 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
883 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
884 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
885 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
886 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
887 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
888 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
891 #define CRC_INNER_LOOP(n, c, x) \
892 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
894 uint8
BCMROMFN(hndcrc8
) (uint8
*pdata
, /* pointer to array of data to process */
895 uint nbytes
, /* number of input data bytes to process */
896 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
898 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
899 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
902 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
907 /*******************************************************************************
910 * Computes a crc16 over the input data using the polynomial:
912 * x^16 + x^12 +x^5 + 1
914 * The caller provides the initial value (either CRC16_INIT_VALUE
915 * or the previous returned value) to allow for processing of
916 * discontiguous blocks of data. When generating the CRC the
917 * caller is responsible for complementing the final return value
918 * and inserting it into the byte stream. When checking, a final
919 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
921 * Reference: Dallas Semiconductor Application Note 27
922 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
923 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
924 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
926 * ****************************************************************************
929 static const uint16 crc16_table
[256] = {
930 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
931 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
932 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
933 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
934 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
935 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
936 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
937 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
938 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
939 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
940 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
941 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
942 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
943 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
944 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
945 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
946 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
947 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
948 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
949 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
950 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
951 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
952 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
953 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
954 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
955 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
956 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
957 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
958 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
959 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
960 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
961 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
964 uint16
BCMROMFN(hndcrc16
) (uint8
*pdata
, /* pointer to array of data to process */
965 uint nbytes
, /* number of input data bytes to process */
966 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
969 CRC_INNER_LOOP(16, crc
, *pdata
++);
974 * Advance from the current 1-byte tag/1-byte length/variable-length value
975 * triple, to the next, returning a pointer to the next.
976 * If the current or next TLV is invalid (does not fit in given buffer length),
978 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
979 * by the TLV parameter's length if it is valid.
981 bcm_tlv_t
*BCMROMFN(bcm_next_tlv
) (bcm_tlv_t
*elt
, int *buflen
)
985 /* validate current elt */
986 if (!bcm_valid_tlv(elt
, *buflen
))
989 /* advance to next elt */
991 elt
= (bcm_tlv_t
*) (elt
->data
+ len
);
992 *buflen
-= (2 + len
);
994 /* validate next elt */
995 if (!bcm_valid_tlv(elt
, *buflen
))
1002 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1003 * triples, returning a pointer to the substring whose first element
1006 bcm_tlv_t
*BCMROMFN(bcm_parse_tlvs
) (void *buf
, int buflen
, uint key
)
1011 elt
= (bcm_tlv_t
*) buf
;
1014 /* find tagged parameter */
1015 while (totlen
>= 2) {
1018 /* validate remaining totlen */
1019 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
1022 elt
= (bcm_tlv_t
*) ((uint8
*) elt
+ (len
+ 2));
1023 totlen
-= (len
+ 2);
1030 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1031 * triples, returning a pointer to the substring whose first element
1032 * matches tag. Stop parsing when we see an element whose ID is greater
1033 * than the target key.
1035 bcm_tlv_t
*BCMROMFN(bcm_parse_ordered_tlvs
) (void *buf
, int buflen
, uint key
)
1040 elt
= (bcm_tlv_t
*) buf
;
1043 /* find tagged parameter */
1044 while (totlen
>= 2) {
1048 /* Punt if we start seeing IDs > than target key */
1052 /* validate remaining totlen */
1053 if ((id
== key
) && (totlen
>= (len
+ 2)))
1056 elt
= (bcm_tlv_t
*) ((uint8
*) elt
+ (len
+ 2));
1057 totlen
-= (len
+ 2);
1064 bcm_format_flags(const bcm_bit_desc_t
*bd
, uint32 flags
, char *buf
, int len
)
1069 int slen
= 0, nlen
= 0;
1073 if (len
< 2 || !buf
)
1078 for (i
= 0; flags
!= 0; i
++) {
1081 if (bit
== 0 && flags
!= 0) {
1082 /* print any unnamed bits */
1083 snprintf(hexstr
, 16, "0x%X", flags
);
1085 flags
= 0; /* exit loop */
1086 } else if ((flags
& bit
) == 0)
1089 nlen
= strlen(name
);
1091 /* count btwn flag space */
1094 /* need NULL char as well */
1097 /* copy NULL char but don't count it */
1098 strncpy(p
, name
, nlen
+ 1);
1100 /* copy btwn flag space and NULL char */
1102 p
+= snprintf(p
, 2, " ");
1106 /* indicate the str was too short */
1109 p
-= 2 - len
; /* overwrite last char */
1110 p
+= snprintf(p
, 2, ">");
1113 return (int)(p
- buf
);
1116 /* print bytes formatted as hex to a string. return the resulting string length */
1117 int bcm_format_hex(char *str
, const void *bytes
, int len
)
1121 const uint8
*src
= (const uint8
*)bytes
;
1123 for (i
= 0; i
< len
; i
++) {
1124 p
+= snprintf(p
, 3, "%02X", *src
);
1127 return (int)(p
- str
);
1129 #endif /* defined(BCMDBG) */
1131 /* pretty hex print a contiguous buffer */
1132 void prhex(const char *msg
, uchar
*buf
, uint nbytes
)
1135 int len
= sizeof(line
);
1139 if (msg
&& (msg
[0] != '\0'))
1140 printf("%s:\n", msg
);
1143 for (i
= 0; i
< nbytes
; i
++) {
1145 nchar
= snprintf(p
, len
, " %04d: ", i
); /* line prefix */
1150 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
1156 printf("%s\n", line
); /* flush line */
1162 /* flush last partial line */
1164 printf("%s\n", line
);
1167 static const char *crypto_algo_names
[] = {
1179 const char *bcm_crypto_algo_name(uint algo
)
1182 ARRAYSIZE(crypto_algo_names
)) ? crypto_algo_names
[algo
] : "ERR";
1186 void deadbeef(void *p
, uint len
)
1188 static uint8 meat
[] = { 0xde, 0xad, 0xbe, 0xef };
1191 *(uint8
*) p
= meat
[((uintptr
) p
) & 3];
1192 p
= (uint8
*) p
+ 1;
1197 char *bcm_chipname(uint chipid
, char *buf
, uint len
)
1201 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
1202 snprintf(buf
, len
, fmt
, chipid
);
1206 /* Produce a human-readable string for boardrev */
1207 char *bcm_brev_str(uint32 brev
, char *buf
)
1210 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
1212 snprintf(buf
, 8, "%c%03x",
1213 ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
1218 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1220 /* dump large strings to console */
1221 void printbig(char *buf
)
1228 max_len
= BUFSIZE_TODUMP_ATONCE
;
1230 while (len
> max_len
) {
1232 buf
[max_len
] = '\0';
1239 /* print the remaining string */
1240 printf("%s\n", buf
);
1244 /* routine to dump fields in a fileddesc structure */
1246 bcmdumpfields(bcmutl_rdreg_rtn read_rtn
, void *arg0
, uint arg1
,
1247 struct fielddesc
*fielddesc_array
, char *buf
, uint32 bufsize
)
1251 struct fielddesc
*cur_ptr
;
1254 cur_ptr
= fielddesc_array
;
1256 while (bufsize
> 1) {
1257 if (cur_ptr
->nameandfmt
== NULL
)
1259 len
= snprintf(buf
, bufsize
, cur_ptr
->nameandfmt
,
1260 read_rtn(arg0
, arg1
, cur_ptr
->offset
));
1261 /* check for snprintf overflow or error */
1262 if (len
< 0 || (uint32
) len
>= bufsize
)
1272 uint
bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
1276 len
= strlen(name
) + 1;
1278 if ((len
+ datalen
) > buflen
)
1281 strncpy(buf
, name
, buflen
);
1283 /* append data onto the end of the name string */
1284 memcpy(&buf
[len
], data
, datalen
);
1290 /* Quarter dBm units to mW
1291 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1292 * Table is offset so the last entry is largest mW value that fits in
1296 #define QDBM_OFFSET 153 /* Offset for first entry */
1297 #define QDBM_TABLE_LEN 40 /* Table size */
1299 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1300 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1302 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1304 /* Largest mW value that will round down to the last table entry,
1305 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1306 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1308 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1310 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
1311 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1312 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1313 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1314 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1315 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1316 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1319 uint16
BCMROMFN(bcm_qdbm_to_mw
) (uint8 qdbm
)
1322 int idx
= qdbm
- QDBM_OFFSET
;
1324 if (idx
>= QDBM_TABLE_LEN
) {
1325 /* clamp to max uint16 mW value */
1329 /* scale the qdBm index up to the range of the table 0-40
1330 * where an offset of 40 qdBm equals a factor of 10 mW.
1337 /* return the mW value scaled down to the correct factor of 10,
1338 * adding in factor/2 to get proper rounding.
1340 return (nqdBm_to_mW_map
[idx
] + factor
/ 2) / factor
;
1343 uint8
BCMROMFN(bcm_mw_to_qdbm
) (uint16 mw
)
1350 /* handle boundary case */
1354 offset
= QDBM_OFFSET
;
1356 /* move mw into the range of the table */
1357 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
1362 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
- 1; qdbm
++) {
1363 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+ 1] -
1364 nqdBm_to_mW_map
[qdbm
]) / 2;
1365 if (mw_uint
< boundary
)
1369 qdbm
+= (uint8
) offset
;
1374 uint
BCMROMFN(bcm_bitcount
) (uint8
*bitmap
, uint length
)
1376 uint bitcount
= 0, i
;
1378 for (i
= 0; i
< length
; i
++) {
1388 /* Initialization of bcmstrbuf structure */
1389 void bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
1391 b
->origsize
= b
->size
= size
;
1392 b
->origbuf
= b
->buf
= buf
;
1395 /* Buffer sprintf wrapper to guard against buffer overflow */
1396 int bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
1402 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
1404 /* Non Ansi C99 compliant returns -1,
1405 * Ansi compliant return r >= b->size,
1406 * bcmstdlib returns 0, handle all
1408 if ((r
== -1) || (r
>= (int)b
->size
) || (r
== 0)) {
1420 void bcm_inc_bytes(uchar
*num
, int num_bytes
, uint8 amount
)
1424 for (i
= 0; i
< num_bytes
; i
++) {
1426 if (num
[i
] >= amount
)
1432 int bcm_cmp_bytes(uchar
*arg1
, uchar
*arg2
, uint8 nbytes
)
1436 for (i
= nbytes
- 1; i
>= 0; i
--) {
1437 if (arg1
[i
] != arg2
[i
])
1438 return arg1
[i
] - arg2
[i
];
1443 void bcm_print_bytes(char *name
, const uchar
*data
, int len
)
1448 printf("%s: %d\n", name
? name
: "", len
);
1449 for (i
= 0; i
< len
; i
++) {
1450 printf("%02x ", *data
++);
1452 if (per_line
== 16) {
1461 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1462 int bcm_format_ssid(char *buf
, const uchar ssid
[], uint ssid_len
)
1466 char *endp
= buf
+ SSID_FMT_BUF_LEN
;
1468 if (ssid_len
> DOT11_MAX_SSID_LEN
)
1469 ssid_len
= DOT11_MAX_SSID_LEN
;
1471 for (i
= 0; i
< ssid_len
; i
++) {
1476 } else if (isprint((uchar
) c
)) {
1479 p
+= snprintf(p
, (endp
- p
), "\\x%02X", c
);
1485 return (int)(p
- buf
);
1487 #endif /* defined(BCMDBG) */