sysfs: Remove support for tagged directories with untagged members (again)
[linux-btrfs-devel.git] / drivers / staging / brcm80211 / brcmutil / utils.c
blob37b6b7797793a0d0c3965b0fc0244b2247adea38
1 /*
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/netdevice.h>
18 #include <brcmu_utils.h>
20 MODULE_AUTHOR("Broadcom Corporation");
21 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
22 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
23 MODULE_LICENSE("Dual BSD/GPL");
25 struct sk_buff *brcmu_pkt_buf_get_skb(uint len)
27 struct sk_buff *skb;
29 skb = dev_alloc_skb(len);
30 if (skb) {
31 skb_put(skb, len);
32 skb->priority = 0;
35 return skb;
37 EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
39 /* Free the driver packet. Free the tag if present */
40 void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
42 struct sk_buff *nskb;
43 int nest = 0;
45 /* perversion: we use skb->next to chain multi-skb packets */
46 while (skb) {
47 nskb = skb->next;
48 skb->next = NULL;
50 if (skb->destructor)
51 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
52 * destructor exists
54 dev_kfree_skb_any(skb);
55 else
56 /* can free immediately (even in_irq()) if destructor
57 * does not exist
59 dev_kfree_skb(skb);
61 nest++;
62 skb = nskb;
65 EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
68 /* copy a buffer into a pkt buffer chain */
69 uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len,
70 unsigned char *buf)
72 uint n, ret = 0;
74 /* skip 'offset' bytes */
75 for (; p && offset; p = p->next) {
76 if (offset < (uint) (p->len))
77 break;
78 offset -= p->len;
81 if (!p)
82 return 0;
84 /* copy the data */
85 for (; p && len; p = p->next) {
86 n = min((uint) (p->len) - offset, (uint) len);
87 memcpy(p->data + offset, buf, n);
88 buf += n;
89 len -= n;
90 ret += n;
91 offset = 0;
94 return ret;
96 EXPORT_SYMBOL(brcmu_pktfrombuf);
98 /* return total length of buffer chain */
99 uint brcmu_pkttotlen(struct sk_buff *p)
101 uint total;
103 total = 0;
104 for (; p; p = p->next)
105 total += p->len;
106 return total;
108 EXPORT_SYMBOL(brcmu_pkttotlen);
111 * osl multiple-precedence packet queue
112 * hi_prec is always >= the number of the highest non-empty precedence
114 struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
115 struct sk_buff *p)
117 struct pktq_prec *q;
119 if (pktq_full(pq) || pktq_pfull(pq, prec))
120 return NULL;
122 q = &pq->q[prec];
124 if (q->head)
125 q->tail->prev = p;
126 else
127 q->head = p;
129 q->tail = p;
130 q->len++;
132 pq->len++;
134 if (pq->hi_prec < prec)
135 pq->hi_prec = (u8) prec;
137 return p;
139 EXPORT_SYMBOL(brcmu_pktq_penq);
141 struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
142 struct sk_buff *p)
144 struct pktq_prec *q;
146 if (pktq_full(pq) || pktq_pfull(pq, prec))
147 return NULL;
149 q = &pq->q[prec];
151 if (q->head == NULL)
152 q->tail = p;
154 p->prev = q->head;
155 q->head = p;
156 q->len++;
158 pq->len++;
160 if (pq->hi_prec < prec)
161 pq->hi_prec = (u8) prec;
163 return p;
165 EXPORT_SYMBOL(brcmu_pktq_penq_head);
167 struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
169 struct pktq_prec *q;
170 struct sk_buff *p;
172 q = &pq->q[prec];
174 p = q->head;
175 if (p == NULL)
176 return NULL;
178 q->head = p->prev;
179 if (q->head == NULL)
180 q->tail = NULL;
182 q->len--;
184 pq->len--;
186 p->prev = NULL;
188 return p;
190 EXPORT_SYMBOL(brcmu_pktq_pdeq);
192 struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
194 struct pktq_prec *q;
195 struct sk_buff *p, *prev;
197 q = &pq->q[prec];
199 p = q->head;
200 if (p == NULL)
201 return NULL;
203 for (prev = NULL; p != q->tail; p = p->prev)
204 prev = p;
206 if (prev)
207 prev->prev = NULL;
208 else
209 q->head = NULL;
211 q->tail = prev;
212 q->len--;
214 pq->len--;
216 return p;
218 EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
220 void
221 brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
222 ifpkt_cb_t fn, void *arg)
224 struct pktq_prec *q;
225 struct sk_buff *p, *prev = NULL;
227 q = &pq->q[prec];
228 p = q->head;
229 while (p) {
230 if (fn == NULL || (*fn) (p, arg)) {
231 bool head = (p == q->head);
232 if (head)
233 q->head = p->prev;
234 else
235 prev->prev = p->prev;
236 p->prev = NULL;
237 brcmu_pkt_buf_free_skb(p);
238 q->len--;
239 pq->len--;
240 p = (head ? q->head : prev->prev);
241 } else {
242 prev = p;
243 p = p->prev;
247 if (q->head == NULL) {
248 q->tail = NULL;
251 EXPORT_SYMBOL(brcmu_pktq_pflush);
253 void brcmu_pktq_flush(struct pktq *pq, bool dir,
254 ifpkt_cb_t fn, void *arg)
256 int prec;
257 for (prec = 0; prec < pq->num_prec; prec++)
258 brcmu_pktq_pflush(pq, prec, dir, fn, arg);
260 EXPORT_SYMBOL(brcmu_pktq_flush);
262 void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
264 int prec;
266 /* pq is variable size; only zero out what's requested */
267 memset(pq, 0,
268 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
270 pq->num_prec = (u16) num_prec;
272 pq->max = (u16) max_len;
274 for (prec = 0; prec < num_prec; prec++)
275 pq->q[prec].max = pq->max;
277 EXPORT_SYMBOL(brcmu_pktq_init);
279 struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
281 int prec;
283 if (pq->len == 0)
284 return NULL;
286 for (prec = 0; prec < pq->hi_prec; prec++)
287 if (pq->q[prec].head)
288 break;
290 if (prec_out)
291 *prec_out = prec;
293 return pq->q[prec].tail;
295 EXPORT_SYMBOL(brcmu_pktq_peek_tail);
297 /* Return sum of lengths of a specific set of precedences */
298 int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
300 int prec, len;
302 len = 0;
304 for (prec = 0; prec <= pq->hi_prec; prec++)
305 if (prec_bmp & (1 << prec))
306 len += pq->q[prec].len;
308 return len;
310 EXPORT_SYMBOL(brcmu_pktq_mlen);
312 /* Priority dequeue from a specific set of precedences */
313 struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
314 int *prec_out)
316 struct pktq_prec *q;
317 struct sk_buff *p;
318 int prec;
320 if (pq->len == 0)
321 return NULL;
323 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
324 pq->hi_prec--;
326 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
327 if (prec-- == 0)
328 return NULL;
330 q = &pq->q[prec];
332 p = q->head;
333 if (p == NULL)
334 return NULL;
336 q->head = p->prev;
337 if (q->head == NULL)
338 q->tail = NULL;
340 q->len--;
342 if (prec_out)
343 *prec_out = prec;
345 pq->len--;
347 p->prev = NULL;
349 return p;
351 EXPORT_SYMBOL(brcmu_pktq_mdeq);
353 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
354 int brcmu_ether_atoe(char *p, u8 *ea)
356 int i = 0;
358 for (;;) {
359 ea[i++] = (char)simple_strtoul(p, &p, 16);
360 if (!*p++ || i == 6)
361 break;
364 return i == 6;
366 EXPORT_SYMBOL(brcmu_ether_atoe);
368 #if defined(BCMDBG)
369 /* pretty hex print a pkt buffer chain */
370 void brcmu_prpkt(const char *msg, struct sk_buff *p0)
372 struct sk_buff *p;
374 if (msg && (msg[0] != '\0'))
375 printk(KERN_DEBUG "%s:\n", msg);
377 for (p = p0; p; p = p->next)
378 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len);
380 EXPORT_SYMBOL(brcmu_prpkt);
381 #endif /* defined(BCMDBG) */
383 /* iovar table lookup */
384 const struct brcmu_iovar *brcmu_iovar_lookup(const struct brcmu_iovar *table,
385 const char *name)
387 const struct brcmu_iovar *vi;
388 const char *lookup_name;
390 /* skip any ':' delimited option prefixes */
391 lookup_name = strrchr(name, ':');
392 if (lookup_name != NULL)
393 lookup_name++;
394 else
395 lookup_name = name;
397 for (vi = table; vi->name; vi++) {
398 if (!strcmp(vi->name, lookup_name))
399 return vi;
401 /* ran to end of table */
403 return NULL; /* var name not found */
405 EXPORT_SYMBOL(brcmu_iovar_lookup);
407 int brcmu_iovar_lencheck(const struct brcmu_iovar *vi, void *arg, int len,
408 bool set)
410 int bcmerror = 0;
412 /* length check on io buf */
413 switch (vi->type) {
414 case IOVT_BOOL:
415 case IOVT_INT8:
416 case IOVT_INT16:
417 case IOVT_INT32:
418 case IOVT_UINT8:
419 case IOVT_UINT16:
420 case IOVT_UINT32:
421 /* all integers are s32 sized args at the ioctl interface */
422 if (len < (int)sizeof(int)) {
423 bcmerror = -EOVERFLOW;
425 break;
427 case IOVT_BUFFER:
428 /* buffer must meet minimum length requirement */
429 if (len < vi->minlen) {
430 bcmerror = -EOVERFLOW;
432 break;
434 case IOVT_VOID:
435 if (!set) {
436 /* Cannot return nil... */
437 bcmerror = -ENOTSUPP;
438 } else if (len) {
439 /* Set is an action w/o parameters */
440 bcmerror = -ENOBUFS;
442 break;
444 default:
445 /* unknown type for length check in iovar info */
446 bcmerror = -ENOTSUPP;
449 return bcmerror;
451 EXPORT_SYMBOL(brcmu_iovar_lencheck);
453 /*******************************************************************************
454 * crc8
456 * Computes a crc8 over the input data using the polynomial:
458 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
460 * The caller provides the initial value (either CRC8_INIT_VALUE
461 * or the previous returned value) to allow for processing of
462 * discontiguous blocks of data. When generating the CRC the
463 * caller is responsible for complementing the final return value
464 * and inserting it into the byte stream. When checking, a final
465 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
467 * Reference: Dallas Semiconductor Application Note 27
468 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
469 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
470 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
472 * ****************************************************************************
475 static const u8 crc8_table[256] = {
476 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
477 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
478 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
479 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
480 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
481 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
482 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
483 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
484 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
485 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
486 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
487 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
488 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
489 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
490 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
491 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
492 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
493 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
494 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
495 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
496 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
497 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
498 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
499 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
500 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
501 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
502 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
503 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
504 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
505 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
506 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
507 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
510 u8 brcmu_crc8(u8 *pdata, /* pointer to array of data to process */
511 uint nbytes, /* number of input data bytes to process */
512 u8 crc /* either CRC8_INIT_VALUE or previous return value */
514 /* loop over the buffer data */
515 while (nbytes-- > 0)
516 crc = crc8_table[(crc ^ *pdata++) & 0xff];
518 return crc;
520 EXPORT_SYMBOL(brcmu_crc8);
523 * Traverse a string of 1-byte tag/1-byte length/variable-length value
524 * triples, returning a pointer to the substring whose first element
525 * matches tag
527 struct brcmu_tlv *brcmu_parse_tlvs(void *buf, int buflen, uint key)
529 struct brcmu_tlv *elt;
530 int totlen;
532 elt = (struct brcmu_tlv *) buf;
533 totlen = buflen;
535 /* find tagged parameter */
536 while (totlen >= 2) {
537 int len = elt->len;
539 /* validate remaining totlen */
540 if ((elt->id == key) && (totlen >= (len + 2)))
541 return elt;
543 elt = (struct brcmu_tlv *) ((u8 *) elt + (len + 2));
544 totlen -= (len + 2);
547 return NULL;
549 EXPORT_SYMBOL(brcmu_parse_tlvs);
552 #if defined(BCMDBG)
554 brcmu_format_flags(const struct brcmu_bit_desc *bd, u32 flags, char *buf,
555 int len)
557 int i;
558 char *p = buf;
559 char hexstr[16];
560 int slen = 0, nlen = 0;
561 u32 bit;
562 const char *name;
564 if (len < 2 || !buf)
565 return 0;
567 buf[0] = '\0';
569 for (i = 0; flags != 0; i++) {
570 bit = bd[i].bit;
571 name = bd[i].name;
572 if (bit == 0 && flags != 0) {
573 /* print any unnamed bits */
574 snprintf(hexstr, 16, "0x%X", flags);
575 name = hexstr;
576 flags = 0; /* exit loop */
577 } else if ((flags & bit) == 0)
578 continue;
579 flags &= ~bit;
580 nlen = strlen(name);
581 slen += nlen;
582 /* count btwn flag space */
583 if (flags != 0)
584 slen += 1;
585 /* need NULL char as well */
586 if (len <= slen)
587 break;
588 /* copy NULL char but don't count it */
589 strncpy(p, name, nlen + 1);
590 p += nlen;
591 /* copy btwn flag space and NULL char */
592 if (flags != 0)
593 p += snprintf(p, 2, " ");
594 len -= slen;
597 /* indicate the str was too short */
598 if (flags != 0) {
599 if (len < 2)
600 p -= 2 - len; /* overwrite last char */
601 p += snprintf(p, 2, ">");
604 return (int)(p - buf);
606 EXPORT_SYMBOL(brcmu_format_flags);
608 /* print bytes formatted as hex to a string. return the resulting string length */
609 int brcmu_format_hex(char *str, const void *bytes, int len)
611 int i;
612 char *p = str;
613 const u8 *src = (const u8 *)bytes;
615 for (i = 0; i < len; i++) {
616 p += snprintf(p, 3, "%02X", *src);
617 src++;
619 return (int)(p - str);
621 EXPORT_SYMBOL(brcmu_format_hex);
622 #endif /* defined(BCMDBG) */
624 char *brcmu_chipname(uint chipid, char *buf, uint len)
626 const char *fmt;
628 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
629 snprintf(buf, len, fmt, chipid);
630 return buf;
632 EXPORT_SYMBOL(brcmu_chipname);
634 uint brcmu_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
636 uint len;
638 len = strlen(name) + 1;
640 if ((len + datalen) > buflen)
641 return 0;
643 strncpy(buf, name, buflen);
645 /* append data onto the end of the name string */
646 memcpy(&buf[len], data, datalen);
647 len += datalen;
649 return len;
651 EXPORT_SYMBOL(brcmu_mkiovar);
653 /* Quarter dBm units to mW
654 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
655 * Table is offset so the last entry is largest mW value that fits in
656 * a u16.
659 #define QDBM_OFFSET 153 /* Offset for first entry */
660 #define QDBM_TABLE_LEN 40 /* Table size */
662 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
663 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
665 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
667 /* Largest mW value that will round down to the last table entry,
668 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
669 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
670 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
672 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
674 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
675 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
676 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
677 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
678 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
679 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
680 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
683 u16 brcmu_qdbm_to_mw(u8 qdbm)
685 uint factor = 1;
686 int idx = qdbm - QDBM_OFFSET;
688 if (idx >= QDBM_TABLE_LEN) {
689 /* clamp to max u16 mW value */
690 return 0xFFFF;
693 /* scale the qdBm index up to the range of the table 0-40
694 * where an offset of 40 qdBm equals a factor of 10 mW.
696 while (idx < 0) {
697 idx += 40;
698 factor *= 10;
701 /* return the mW value scaled down to the correct factor of 10,
702 * adding in factor/2 to get proper rounding.
704 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
706 EXPORT_SYMBOL(brcmu_qdbm_to_mw);
708 u8 brcmu_mw_to_qdbm(u16 mw)
710 u8 qdbm;
711 int offset;
712 uint mw_uint = mw;
713 uint boundary;
715 /* handle boundary case */
716 if (mw_uint <= 1)
717 return 0;
719 offset = QDBM_OFFSET;
721 /* move mw into the range of the table */
722 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
723 mw_uint *= 10;
724 offset -= 40;
727 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
728 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
729 nqdBm_to_mW_map[qdbm]) / 2;
730 if (mw_uint < boundary)
731 break;
734 qdbm += (u8) offset;
736 return qdbm;
738 EXPORT_SYMBOL(brcmu_mw_to_qdbm);
740 uint brcmu_bitcount(u8 *bitmap, uint length)
742 uint bitcount = 0, i;
743 u8 tmp;
744 for (i = 0; i < length; i++) {
745 tmp = bitmap[i];
746 while (tmp) {
747 bitcount++;
748 tmp &= (tmp - 1);
751 return bitcount;
753 EXPORT_SYMBOL(brcmu_bitcount);
755 /* Initialization of brcmu_strbuf structure */
756 void brcmu_binit(struct brcmu_strbuf *b, char *buf, uint size)
758 b->origsize = b->size = size;
759 b->origbuf = b->buf = buf;
761 EXPORT_SYMBOL(brcmu_binit);
763 /* Buffer sprintf wrapper to guard against buffer overflow */
764 int brcmu_bprintf(struct brcmu_strbuf *b, const char *fmt, ...)
766 va_list ap;
767 int r;
769 va_start(ap, fmt);
770 r = vsnprintf(b->buf, b->size, fmt, ap);
772 /* Non Ansi C99 compliant returns -1,
773 * Ansi compliant return r >= b->size,
774 * stdlib returns 0, handle all
776 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
777 b->size = 0;
778 } else {
779 b->size -= r;
780 b->buf += r;
783 va_end(ap);
785 return r;
787 EXPORT_SYMBOL(brcmu_bprintf);