d259e265352fff26b84b87045345b92bede2786d
[deliverable/linux.git] / drivers / staging / brcm80211 / brcmutil / utils.c
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
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.
7 *
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.
15 */
16
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>
25 #include <bcmdefs.h>
26 #include <stdarg.h>
27 #include <brcmu_utils.h>
28 #include <bcmdevs.h>
29
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");
34
35 struct sk_buff *brcmu_pkt_buf_get_skb(uint len)
36 {
37 struct sk_buff *skb;
38
39 skb = dev_alloc_skb(len);
40 if (skb) {
41 skb_put(skb, len);
42 skb->priority = 0;
43 }
44
45 return skb;
46 }
47 EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
48
49 /* Free the driver packet. Free the tag if present */
50 void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
51 {
52 struct sk_buff *nskb;
53 int nest = 0;
54
55 /* perversion: we use skb->next to chain multi-skb packets */
56 while (skb) {
57 nskb = skb->next;
58 skb->next = NULL;
59
60 if (skb->destructor)
61 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
62 * destructor exists
63 */
64 dev_kfree_skb_any(skb);
65 else
66 /* can free immediately (even in_irq()) if destructor
67 * does not exist
68 */
69 dev_kfree_skb(skb);
70
71 nest++;
72 skb = nskb;
73 }
74 }
75 EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
76
77
78 /* copy a buffer into a pkt buffer chain */
79 uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len,
80 unsigned char *buf)
81 {
82 uint n, ret = 0;
83
84 /* skip 'offset' bytes */
85 for (; p && offset; p = p->next) {
86 if (offset < (uint) (p->len))
87 break;
88 offset -= p->len;
89 }
90
91 if (!p)
92 return 0;
93
94 /* copy the data */
95 for (; p && len; p = p->next) {
96 n = min((uint) (p->len) - offset, (uint) len);
97 memcpy(p->data + offset, buf, n);
98 buf += n;
99 len -= n;
100 ret += n;
101 offset = 0;
102 }
103
104 return ret;
105 }
106 EXPORT_SYMBOL(brcmu_pktfrombuf);
107
108 /* return total length of buffer chain */
109 uint brcmu_pkttotlen(struct sk_buff *p)
110 {
111 uint total;
112
113 total = 0;
114 for (; p; p = p->next)
115 total += p->len;
116 return total;
117 }
118 EXPORT_SYMBOL(brcmu_pkttotlen);
119
120 /*
121 * osl multiple-precedence packet queue
122 * hi_prec is always >= the number of the highest non-empty precedence
123 */
124 struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
125 struct sk_buff *p)
126 {
127 struct pktq_prec *q;
128
129 if (pktq_full(pq) || pktq_pfull(pq, prec))
130 return NULL;
131
132 q = &pq->q[prec];
133
134 if (q->head)
135 q->tail->prev = p;
136 else
137 q->head = p;
138
139 q->tail = p;
140 q->len++;
141
142 pq->len++;
143
144 if (pq->hi_prec < prec)
145 pq->hi_prec = (u8) prec;
146
147 return p;
148 }
149 EXPORT_SYMBOL(brcmu_pktq_penq);
150
151 struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
152 struct sk_buff *p)
153 {
154 struct pktq_prec *q;
155
156 if (pktq_full(pq) || pktq_pfull(pq, prec))
157 return NULL;
158
159 q = &pq->q[prec];
160
161 if (q->head == NULL)
162 q->tail = p;
163
164 p->prev = q->head;
165 q->head = p;
166 q->len++;
167
168 pq->len++;
169
170 if (pq->hi_prec < prec)
171 pq->hi_prec = (u8) prec;
172
173 return p;
174 }
175 EXPORT_SYMBOL(brcmu_pktq_penq_head);
176
177 struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
178 {
179 struct pktq_prec *q;
180 struct sk_buff *p;
181
182 q = &pq->q[prec];
183
184 p = q->head;
185 if (p == NULL)
186 return NULL;
187
188 q->head = p->prev;
189 if (q->head == NULL)
190 q->tail = NULL;
191
192 q->len--;
193
194 pq->len--;
195
196 p->prev = NULL;
197
198 return p;
199 }
200 EXPORT_SYMBOL(brcmu_pktq_pdeq);
201
202 struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
203 {
204 struct pktq_prec *q;
205 struct sk_buff *p, *prev;
206
207 q = &pq->q[prec];
208
209 p = q->head;
210 if (p == NULL)
211 return NULL;
212
213 for (prev = NULL; p != q->tail; p = p->prev)
214 prev = p;
215
216 if (prev)
217 prev->prev = NULL;
218 else
219 q->head = NULL;
220
221 q->tail = prev;
222 q->len--;
223
224 pq->len--;
225
226 return p;
227 }
228 EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
229
230 void
231 brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
232 ifpkt_cb_t fn, void *arg)
233 {
234 struct pktq_prec *q;
235 struct sk_buff *p, *prev = NULL;
236
237 q = &pq->q[prec];
238 p = q->head;
239 while (p) {
240 if (fn == NULL || (*fn) (p, arg)) {
241 bool head = (p == q->head);
242 if (head)
243 q->head = p->prev;
244 else
245 prev->prev = p->prev;
246 p->prev = NULL;
247 brcmu_pkt_buf_free_skb(p);
248 q->len--;
249 pq->len--;
250 p = (head ? q->head : prev->prev);
251 } else {
252 prev = p;
253 p = p->prev;
254 }
255 }
256
257 if (q->head == NULL) {
258 q->tail = NULL;
259 }
260 }
261 EXPORT_SYMBOL(brcmu_pktq_pflush);
262
263 void brcmu_pktq_flush(struct pktq *pq, bool dir,
264 ifpkt_cb_t fn, void *arg)
265 {
266 int prec;
267 for (prec = 0; prec < pq->num_prec; prec++)
268 brcmu_pktq_pflush(pq, prec, dir, fn, arg);
269 }
270 EXPORT_SYMBOL(brcmu_pktq_flush);
271
272 void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
273 {
274 int prec;
275
276 /* pq is variable size; only zero out what's requested */
277 memset(pq, 0,
278 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
279
280 pq->num_prec = (u16) num_prec;
281
282 pq->max = (u16) max_len;
283
284 for (prec = 0; prec < num_prec; prec++)
285 pq->q[prec].max = pq->max;
286 }
287 EXPORT_SYMBOL(brcmu_pktq_init);
288
289 struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
290 {
291 int prec;
292
293 if (pq->len == 0)
294 return NULL;
295
296 for (prec = 0; prec < pq->hi_prec; prec++)
297 if (pq->q[prec].head)
298 break;
299
300 if (prec_out)
301 *prec_out = prec;
302
303 return pq->q[prec].tail;
304 }
305 EXPORT_SYMBOL(brcmu_pktq_peek_tail);
306
307 /* Return sum of lengths of a specific set of precedences */
308 int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
309 {
310 int prec, len;
311
312 len = 0;
313
314 for (prec = 0; prec <= pq->hi_prec; prec++)
315 if (prec_bmp & (1 << prec))
316 len += pq->q[prec].len;
317
318 return len;
319 }
320 EXPORT_SYMBOL(brcmu_pktq_mlen);
321
322 /* Priority dequeue from a specific set of precedences */
323 struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
324 int *prec_out)
325 {
326 struct pktq_prec *q;
327 struct sk_buff *p;
328 int prec;
329
330 if (pq->len == 0)
331 return NULL;
332
333 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
334 pq->hi_prec--;
335
336 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
337 if (prec-- == 0)
338 return NULL;
339
340 q = &pq->q[prec];
341
342 p = q->head;
343 if (p == NULL)
344 return NULL;
345
346 q->head = p->prev;
347 if (q->head == NULL)
348 q->tail = NULL;
349
350 q->len--;
351
352 if (prec_out)
353 *prec_out = prec;
354
355 pq->len--;
356
357 p->prev = NULL;
358
359 return p;
360 }
361 EXPORT_SYMBOL(brcmu_pktq_mdeq);
362
363 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
364 int brcmu_ether_atoe(char *p, u8 *ea)
365 {
366 int i = 0;
367
368 for (;;) {
369 ea[i++] = (char)simple_strtoul(p, &p, 16);
370 if (!*p++ || i == 6)
371 break;
372 }
373
374 return i == 6;
375 }
376 EXPORT_SYMBOL(brcmu_ether_atoe);
377
378 #if defined(BCMDBG)
379 /* pretty hex print a pkt buffer chain */
380 void brcmu_prpkt(const char *msg, struct sk_buff *p0)
381 {
382 struct sk_buff *p;
383
384 if (msg && (msg[0] != '\0'))
385 printk(KERN_DEBUG "%s:\n", msg);
386
387 for (p = p0; p; p = p->next)
388 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len);
389 }
390 EXPORT_SYMBOL(brcmu_prpkt);
391 #endif /* defined(BCMDBG) */
392
393 /* iovar table lookup */
394 const struct brcmu_iovar *brcmu_iovar_lookup(const struct brcmu_iovar *table,
395 const char *name)
396 {
397 const struct brcmu_iovar *vi;
398 const char *lookup_name;
399
400 /* skip any ':' delimited option prefixes */
401 lookup_name = strrchr(name, ':');
402 if (lookup_name != NULL)
403 lookup_name++;
404 else
405 lookup_name = name;
406
407 for (vi = table; vi->name; vi++) {
408 if (!strcmp(vi->name, lookup_name))
409 return vi;
410 }
411 /* ran to end of table */
412
413 return NULL; /* var name not found */
414 }
415 EXPORT_SYMBOL(brcmu_iovar_lookup);
416
417 int brcmu_iovar_lencheck(const struct brcmu_iovar *vi, void *arg, int len,
418 bool set)
419 {
420 int bcmerror = 0;
421
422 /* length check on io buf */
423 switch (vi->type) {
424 case IOVT_BOOL:
425 case IOVT_INT8:
426 case IOVT_INT16:
427 case IOVT_INT32:
428 case IOVT_UINT8:
429 case IOVT_UINT16:
430 case IOVT_UINT32:
431 /* all integers are s32 sized args at the ioctl interface */
432 if (len < (int)sizeof(int)) {
433 bcmerror = -EOVERFLOW;
434 }
435 break;
436
437 case IOVT_BUFFER:
438 /* buffer must meet minimum length requirement */
439 if (len < vi->minlen) {
440 bcmerror = -EOVERFLOW;
441 }
442 break;
443
444 case IOVT_VOID:
445 if (!set) {
446 /* Cannot return nil... */
447 bcmerror = -ENOTSUPP;
448 } else if (len) {
449 /* Set is an action w/o parameters */
450 bcmerror = -ENOBUFS;
451 }
452 break;
453
454 default:
455 /* unknown type for length check in iovar info */
456 bcmerror = -ENOTSUPP;
457 }
458
459 return bcmerror;
460 }
461 EXPORT_SYMBOL(brcmu_iovar_lencheck);
462
463 /*******************************************************************************
464 * crc8
465 *
466 * Computes a crc8 over the input data using the polynomial:
467 *
468 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
469 *
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.
476 *
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
481 *
482 * ****************************************************************************
483 */
484
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
518 };
519
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 */
523 ) {
524 /* loop over the buffer data */
525 while (nbytes-- > 0)
526 crc = crc8_table[(crc ^ *pdata++) & 0xff];
527
528 return crc;
529 }
530 EXPORT_SYMBOL(brcmu_crc8);
531
532 /*
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
535 * matches tag
536 */
537 struct brcmu_tlv *brcmu_parse_tlvs(void *buf, int buflen, uint key)
538 {
539 struct brcmu_tlv *elt;
540 int totlen;
541
542 elt = (struct brcmu_tlv *) buf;
543 totlen = buflen;
544
545 /* find tagged parameter */
546 while (totlen >= 2) {
547 int len = elt->len;
548
549 /* validate remaining totlen */
550 if ((elt->id == key) && (totlen >= (len + 2)))
551 return elt;
552
553 elt = (struct brcmu_tlv *) ((u8 *) elt + (len + 2));
554 totlen -= (len + 2);
555 }
556
557 return NULL;
558 }
559 EXPORT_SYMBOL(brcmu_parse_tlvs);
560
561
562 #if defined(BCMDBG)
563 int
564 brcmu_format_flags(const struct brcmu_bit_desc *bd, u32 flags, char *buf,
565 int len)
566 {
567 int i;
568 char *p = buf;
569 char hexstr[16];
570 int slen = 0, nlen = 0;
571 u32 bit;
572 const char *name;
573
574 if (len < 2 || !buf)
575 return 0;
576
577 buf[0] = '\0';
578
579 for (i = 0; flags != 0; i++) {
580 bit = bd[i].bit;
581 name = bd[i].name;
582 if (bit == 0 && flags != 0) {
583 /* print any unnamed bits */
584 snprintf(hexstr, 16, "0x%X", flags);
585 name = hexstr;
586 flags = 0; /* exit loop */
587 } else if ((flags & bit) == 0)
588 continue;
589 flags &= ~bit;
590 nlen = strlen(name);
591 slen += nlen;
592 /* count btwn flag space */
593 if (flags != 0)
594 slen += 1;
595 /* need NULL char as well */
596 if (len <= slen)
597 break;
598 /* copy NULL char but don't count it */
599 strncpy(p, name, nlen + 1);
600 p += nlen;
601 /* copy btwn flag space and NULL char */
602 if (flags != 0)
603 p += snprintf(p, 2, " ");
604 len -= slen;
605 }
606
607 /* indicate the str was too short */
608 if (flags != 0) {
609 if (len < 2)
610 p -= 2 - len; /* overwrite last char */
611 p += snprintf(p, 2, ">");
612 }
613
614 return (int)(p - buf);
615 }
616 EXPORT_SYMBOL(brcmu_format_flags);
617
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)
620 {
621 int i;
622 char *p = str;
623 const u8 *src = (const u8 *)bytes;
624
625 for (i = 0; i < len; i++) {
626 p += snprintf(p, 3, "%02X", *src);
627 src++;
628 }
629 return (int)(p - str);
630 }
631 EXPORT_SYMBOL(brcmu_format_hex);
632 #endif /* defined(BCMDBG) */
633
634 char *brcmu_chipname(uint chipid, char *buf, uint len)
635 {
636 const char *fmt;
637
638 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
639 snprintf(buf, len, fmt, chipid);
640 return buf;
641 }
642 EXPORT_SYMBOL(brcmu_chipname);
643
644 uint brcmu_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
645 {
646 uint len;
647
648 len = strlen(name) + 1;
649
650 if ((len + datalen) > buflen)
651 return 0;
652
653 strncpy(buf, name, buflen);
654
655 /* append data onto the end of the name string */
656 memcpy(&buf[len], data, datalen);
657 len += datalen;
658
659 return len;
660 }
661 EXPORT_SYMBOL(brcmu_mkiovar);
662
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
666 * a u16.
667 */
668
669 #define QDBM_OFFSET 153 /* Offset for first entry */
670 #define QDBM_TABLE_LEN 40 /* Table size */
671
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
674 */
675 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
676
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.
681 */
682 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
683
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
691 };
692
693 u16 brcmu_qdbm_to_mw(u8 qdbm)
694 {
695 uint factor = 1;
696 int idx = qdbm - QDBM_OFFSET;
697
698 if (idx >= QDBM_TABLE_LEN) {
699 /* clamp to max u16 mW value */
700 return 0xFFFF;
701 }
702
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.
705 */
706 while (idx < 0) {
707 idx += 40;
708 factor *= 10;
709 }
710
711 /* return the mW value scaled down to the correct factor of 10,
712 * adding in factor/2 to get proper rounding.
713 */
714 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
715 }
716 EXPORT_SYMBOL(brcmu_qdbm_to_mw);
717
718 u8 brcmu_mw_to_qdbm(u16 mw)
719 {
720 u8 qdbm;
721 int offset;
722 uint mw_uint = mw;
723 uint boundary;
724
725 /* handle boundary case */
726 if (mw_uint <= 1)
727 return 0;
728
729 offset = QDBM_OFFSET;
730
731 /* move mw into the range of the table */
732 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
733 mw_uint *= 10;
734 offset -= 40;
735 }
736
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)
741 break;
742 }
743
744 qdbm += (u8) offset;
745
746 return qdbm;
747 }
748 EXPORT_SYMBOL(brcmu_mw_to_qdbm);
749
750 uint brcmu_bitcount(u8 *bitmap, uint length)
751 {
752 uint bitcount = 0, i;
753 u8 tmp;
754 for (i = 0; i < length; i++) {
755 tmp = bitmap[i];
756 while (tmp) {
757 bitcount++;
758 tmp &= (tmp - 1);
759 }
760 }
761 return bitcount;
762 }
763 EXPORT_SYMBOL(brcmu_bitcount);
764
765 /* Initialization of brcmu_strbuf structure */
766 void brcmu_binit(struct brcmu_strbuf *b, char *buf, uint size)
767 {
768 b->origsize = b->size = size;
769 b->origbuf = b->buf = buf;
770 }
771 EXPORT_SYMBOL(brcmu_binit);
772
773 /* Buffer sprintf wrapper to guard against buffer overflow */
774 int brcmu_bprintf(struct brcmu_strbuf *b, const char *fmt, ...)
775 {
776 va_list ap;
777 int r;
778
779 va_start(ap, fmt);
780 r = vsnprintf(b->buf, b->size, fmt, ap);
781
782 /* Non Ansi C99 compliant returns -1,
783 * Ansi compliant return r >= b->size,
784 * stdlib returns 0, handle all
785 */
786 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
787 b->size = 0;
788 } else {
789 b->size -= r;
790 b->buf += r;
791 }
792
793 va_end(ap);
794
795 return r;
796 }
797 EXPORT_SYMBOL(brcmu_bprintf);
This page took 0.057734 seconds and 4 git commands to generate.