d259e265352fff26b84b87045345b92bede2786d
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.
17 #include <linux/ctype.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <linux/netdevice.h>
23 #include <linux/sched.h>
24 #include <linux/printk.h>
27 #include <brcmu_utils.h>
30 MODULE_AUTHOR("Broadcom Corporation");
31 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
32 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
33 MODULE_LICENSE("Dual BSD/GPL");
35 struct sk_buff
*brcmu_pkt_buf_get_skb(uint len
)
39 skb
= dev_alloc_skb(len
);
47 EXPORT_SYMBOL(brcmu_pkt_buf_get_skb
);
49 /* Free the driver packet. Free the tag if present */
50 void brcmu_pkt_buf_free_skb(struct sk_buff
*skb
)
55 /* perversion: we use skb->next to chain multi-skb packets */
61 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
64 dev_kfree_skb_any(skb
);
66 /* can free immediately (even in_irq()) if destructor
75 EXPORT_SYMBOL(brcmu_pkt_buf_free_skb
);
78 /* copy a buffer into a pkt buffer chain */
79 uint
brcmu_pktfrombuf(struct sk_buff
*p
, uint offset
, int len
,
84 /* skip 'offset' bytes */
85 for (; p
&& offset
; p
= p
->next
) {
86 if (offset
< (uint
) (p
->len
))
95 for (; p
&& len
; p
= p
->next
) {
96 n
= min((uint
) (p
->len
) - offset
, (uint
) len
);
97 memcpy(p
->data
+ offset
, buf
, n
);
106 EXPORT_SYMBOL(brcmu_pktfrombuf
);
108 /* return total length of buffer chain */
109 uint
brcmu_pkttotlen(struct sk_buff
*p
)
114 for (; p
; p
= p
->next
)
118 EXPORT_SYMBOL(brcmu_pkttotlen
);
121 * osl multiple-precedence packet queue
122 * hi_prec is always >= the number of the highest non-empty precedence
124 struct sk_buff
*brcmu_pktq_penq(struct pktq
*pq
, int prec
,
129 if (pktq_full(pq
) || pktq_pfull(pq
, prec
))
144 if (pq
->hi_prec
< prec
)
145 pq
->hi_prec
= (u8
) prec
;
149 EXPORT_SYMBOL(brcmu_pktq_penq
);
151 struct sk_buff
*brcmu_pktq_penq_head(struct pktq
*pq
, int prec
,
156 if (pktq_full(pq
) || pktq_pfull(pq
, prec
))
170 if (pq
->hi_prec
< prec
)
171 pq
->hi_prec
= (u8
) prec
;
175 EXPORT_SYMBOL(brcmu_pktq_penq_head
);
177 struct sk_buff
*brcmu_pktq_pdeq(struct pktq
*pq
, int prec
)
200 EXPORT_SYMBOL(brcmu_pktq_pdeq
);
202 struct sk_buff
*brcmu_pktq_pdeq_tail(struct pktq
*pq
, int prec
)
205 struct sk_buff
*p
, *prev
;
213 for (prev
= NULL
; p
!= q
->tail
; p
= p
->prev
)
228 EXPORT_SYMBOL(brcmu_pktq_pdeq_tail
);
231 brcmu_pktq_pflush(struct pktq
*pq
, int prec
, bool dir
,
232 ifpkt_cb_t fn
, void *arg
)
235 struct sk_buff
*p
, *prev
= NULL
;
240 if (fn
== NULL
|| (*fn
) (p
, arg
)) {
241 bool head
= (p
== q
->head
);
245 prev
->prev
= p
->prev
;
247 brcmu_pkt_buf_free_skb(p
);
250 p
= (head
? q
->head
: prev
->prev
);
257 if (q
->head
== NULL
) {
261 EXPORT_SYMBOL(brcmu_pktq_pflush
);
263 void brcmu_pktq_flush(struct pktq
*pq
, bool dir
,
264 ifpkt_cb_t fn
, void *arg
)
267 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
268 brcmu_pktq_pflush(pq
, prec
, dir
, fn
, arg
);
270 EXPORT_SYMBOL(brcmu_pktq_flush
);
272 void brcmu_pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
276 /* pq is variable size; only zero out what's requested */
278 offsetof(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
280 pq
->num_prec
= (u16
) num_prec
;
282 pq
->max
= (u16
) max_len
;
284 for (prec
= 0; prec
< num_prec
; prec
++)
285 pq
->q
[prec
].max
= pq
->max
;
287 EXPORT_SYMBOL(brcmu_pktq_init
);
289 struct sk_buff
*brcmu_pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
296 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
297 if (pq
->q
[prec
].head
)
303 return pq
->q
[prec
].tail
;
305 EXPORT_SYMBOL(brcmu_pktq_peek_tail
);
307 /* Return sum of lengths of a specific set of precedences */
308 int brcmu_pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
314 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
315 if (prec_bmp
& (1 << prec
))
316 len
+= pq
->q
[prec
].len
;
320 EXPORT_SYMBOL(brcmu_pktq_mlen
);
322 /* Priority dequeue from a specific set of precedences */
323 struct sk_buff
*brcmu_pktq_mdeq(struct pktq
*pq
, uint prec_bmp
,
333 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
336 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
361 EXPORT_SYMBOL(brcmu_pktq_mdeq
);
363 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
364 int brcmu_ether_atoe(char *p
, u8
*ea
)
369 ea
[i
++] = (char)simple_strtoul(p
, &p
, 16);
376 EXPORT_SYMBOL(brcmu_ether_atoe
);
379 /* pretty hex print a pkt buffer chain */
380 void brcmu_prpkt(const char *msg
, struct sk_buff
*p0
)
384 if (msg
&& (msg
[0] != '\0'))
385 printk(KERN_DEBUG
"%s:\n", msg
);
387 for (p
= p0
; p
; p
= p
->next
)
388 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
, p
->data
, p
->len
);
390 EXPORT_SYMBOL(brcmu_prpkt
);
391 #endif /* defined(BCMDBG) */
393 /* iovar table lookup */
394 const struct brcmu_iovar
*brcmu_iovar_lookup(const struct brcmu_iovar
*table
,
397 const struct brcmu_iovar
*vi
;
398 const char *lookup_name
;
400 /* skip any ':' delimited option prefixes */
401 lookup_name
= strrchr(name
, ':');
402 if (lookup_name
!= NULL
)
407 for (vi
= table
; vi
->name
; vi
++) {
408 if (!strcmp(vi
->name
, lookup_name
))
411 /* ran to end of table */
413 return NULL
; /* var name not found */
415 EXPORT_SYMBOL(brcmu_iovar_lookup
);
417 int brcmu_iovar_lencheck(const struct brcmu_iovar
*vi
, void *arg
, int len
,
422 /* length check on io buf */
431 /* all integers are s32 sized args at the ioctl interface */
432 if (len
< (int)sizeof(int)) {
433 bcmerror
= -EOVERFLOW
;
438 /* buffer must meet minimum length requirement */
439 if (len
< vi
->minlen
) {
440 bcmerror
= -EOVERFLOW
;
446 /* Cannot return nil... */
447 bcmerror
= -ENOTSUPP
;
449 /* Set is an action w/o parameters */
455 /* unknown type for length check in iovar info */
456 bcmerror
= -ENOTSUPP
;
461 EXPORT_SYMBOL(brcmu_iovar_lencheck
);
463 /*******************************************************************************
466 * Computes a crc8 over the input data using the polynomial:
468 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
470 * The caller provides the initial value (either CRC8_INIT_VALUE
471 * or the previous returned value) to allow for processing of
472 * discontiguous blocks of data. When generating the CRC the
473 * caller is responsible for complementing the final return value
474 * and inserting it into the byte stream. When checking, a final
475 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
477 * Reference: Dallas Semiconductor Application Note 27
478 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
479 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
480 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
482 * ****************************************************************************
485 static const u8 crc8_table
[256] = {
486 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
487 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
488 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
489 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
490 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
491 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
492 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
493 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
494 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
495 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
496 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
497 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
498 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
499 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
500 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
501 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
502 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
503 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
504 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
505 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
506 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
507 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
508 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
509 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
510 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
511 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
512 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
513 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
514 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
515 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
516 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
517 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
520 u8
brcmu_crc8(u8
*pdata
, /* pointer to array of data to process */
521 uint nbytes
, /* number of input data bytes to process */
522 u8 crc
/* either CRC8_INIT_VALUE or previous return value */
524 /* loop over the buffer data */
526 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
530 EXPORT_SYMBOL(brcmu_crc8
);
533 * Traverse a string of 1-byte tag/1-byte length/variable-length value
534 * triples, returning a pointer to the substring whose first element
537 struct brcmu_tlv
*brcmu_parse_tlvs(void *buf
, int buflen
, uint key
)
539 struct brcmu_tlv
*elt
;
542 elt
= (struct brcmu_tlv
*) buf
;
545 /* find tagged parameter */
546 while (totlen
>= 2) {
549 /* validate remaining totlen */
550 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
553 elt
= (struct brcmu_tlv
*) ((u8
*) elt
+ (len
+ 2));
559 EXPORT_SYMBOL(brcmu_parse_tlvs
);
564 brcmu_format_flags(const struct brcmu_bit_desc
*bd
, u32 flags
, char *buf
,
570 int slen
= 0, nlen
= 0;
579 for (i
= 0; flags
!= 0; i
++) {
582 if (bit
== 0 && flags
!= 0) {
583 /* print any unnamed bits */
584 snprintf(hexstr
, 16, "0x%X", flags
);
586 flags
= 0; /* exit loop */
587 } else if ((flags
& bit
) == 0)
592 /* count btwn flag space */
595 /* need NULL char as well */
598 /* copy NULL char but don't count it */
599 strncpy(p
, name
, nlen
+ 1);
601 /* copy btwn flag space and NULL char */
603 p
+= snprintf(p
, 2, " ");
607 /* indicate the str was too short */
610 p
-= 2 - len
; /* overwrite last char */
611 p
+= snprintf(p
, 2, ">");
614 return (int)(p
- buf
);
616 EXPORT_SYMBOL(brcmu_format_flags
);
618 /* print bytes formatted as hex to a string. return the resulting string length */
619 int brcmu_format_hex(char *str
, const void *bytes
, int len
)
623 const u8
*src
= (const u8
*)bytes
;
625 for (i
= 0; i
< len
; i
++) {
626 p
+= snprintf(p
, 3, "%02X", *src
);
629 return (int)(p
- str
);
631 EXPORT_SYMBOL(brcmu_format_hex
);
632 #endif /* defined(BCMDBG) */
634 char *brcmu_chipname(uint chipid
, char *buf
, uint len
)
638 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
639 snprintf(buf
, len
, fmt
, chipid
);
642 EXPORT_SYMBOL(brcmu_chipname
);
644 uint
brcmu_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
648 len
= strlen(name
) + 1;
650 if ((len
+ datalen
) > buflen
)
653 strncpy(buf
, name
, buflen
);
655 /* append data onto the end of the name string */
656 memcpy(&buf
[len
], data
, datalen
);
661 EXPORT_SYMBOL(brcmu_mkiovar
);
663 /* Quarter dBm units to mW
664 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
665 * Table is offset so the last entry is largest mW value that fits in
669 #define QDBM_OFFSET 153 /* Offset for first entry */
670 #define QDBM_TABLE_LEN 40 /* Table size */
672 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
673 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
675 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
677 /* Largest mW value that will round down to the last table entry,
678 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
679 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
680 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
682 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
684 static const u16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
685 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
686 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
687 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
688 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
689 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
690 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
693 u16
brcmu_qdbm_to_mw(u8 qdbm
)
696 int idx
= qdbm
- QDBM_OFFSET
;
698 if (idx
>= QDBM_TABLE_LEN
) {
699 /* clamp to max u16 mW value */
703 /* scale the qdBm index up to the range of the table 0-40
704 * where an offset of 40 qdBm equals a factor of 10 mW.
711 /* return the mW value scaled down to the correct factor of 10,
712 * adding in factor/2 to get proper rounding.
714 return (nqdBm_to_mW_map
[idx
] + factor
/ 2) / factor
;
716 EXPORT_SYMBOL(brcmu_qdbm_to_mw
);
718 u8
brcmu_mw_to_qdbm(u16 mw
)
725 /* handle boundary case */
729 offset
= QDBM_OFFSET
;
731 /* move mw into the range of the table */
732 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
737 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
- 1; qdbm
++) {
738 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+ 1] -
739 nqdBm_to_mW_map
[qdbm
]) / 2;
740 if (mw_uint
< boundary
)
748 EXPORT_SYMBOL(brcmu_mw_to_qdbm
);
750 uint
brcmu_bitcount(u8
*bitmap
, uint length
)
752 uint bitcount
= 0, i
;
754 for (i
= 0; i
< length
; i
++) {
763 EXPORT_SYMBOL(brcmu_bitcount
);
765 /* Initialization of brcmu_strbuf structure */
766 void brcmu_binit(struct brcmu_strbuf
*b
, char *buf
, uint size
)
768 b
->origsize
= b
->size
= size
;
769 b
->origbuf
= b
->buf
= buf
;
771 EXPORT_SYMBOL(brcmu_binit
);
773 /* Buffer sprintf wrapper to guard against buffer overflow */
774 int brcmu_bprintf(struct brcmu_strbuf
*b
, const char *fmt
, ...)
780 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
782 /* Non Ansi C99 compliant returns -1,
783 * Ansi compliant return r >= b->size,
784 * stdlib returns 0, handle all
786 if ((r
== -1) || (r
>= (int)b
->size
) || (r
== 0)) {
797 EXPORT_SYMBOL(brcmu_bprintf
);
This page took 0.057734 seconds and 4 git commands to generate.