upgrade wireless-tools and iproute2
[openwrt.git] / package / linux / kernel-source / drivers / net / hnd / bcmsrom.c
1 /*
2  *  Misc useful routines to access NIC SROM
3  *
4  * Copyright 2004, 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 <osl.h>
16 #include <bcmutils.h>
17 #include <bcmsrom.h>
18 #include <bcmdevs.h>
19 #include <bcmendian.h>
20 #include <sbpcmcia.h>
21 #include <pcicfg.h>
22 #include <sbutils.h>
23
24 #include <proto/ethernet.h>     /* for sprom content groking */
25
26 #define VARS_MAX        4096    /* should be reduced */
27
28 static int initvars_srom_pci(void *curmap, char **vars, int *count);
29 static int initvars_cis_pcmcia(void *sbh, void *curmap, void *osh, char **vars, int *count);
30 static int sprom_cmd_pcmcia(void *osh, uint8 cmd);
31 static int sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data);
32 static int sprom_write_pcmcia(void *osh, uint16 addr, uint16 data);
33 static int sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc);
34
35 /*
36  * Initialize the vars from the right source for this platform.
37  * Return 0 on success, nonzero on error.
38  */
39 int
40 srom_var_init(void *sbh, uint bus, void *curmap, void *osh, char **vars, int *count)
41 {
42         if (vars == NULL)
43                 return (0);
44
45         switch (bus) {
46         case SB_BUS:
47                 /* These two could be asserts ... */
48                 *vars = NULL;
49                 *count = 0;
50                 return(0);
51
52         case PCI_BUS:
53                 ASSERT(curmap); /* can not be NULL */
54                 return(initvars_srom_pci(curmap, vars, count));
55
56         case PCMCIA_BUS:
57                 return(initvars_cis_pcmcia(sbh, curmap, osh, vars, count));
58
59
60         default:
61                 ASSERT(0);
62         }
63         return (-1);
64 }
65
66
67 /* support only 16-bit word read from srom */
68 int
69 srom_read(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
70 {
71         void *srom;
72         uint i, off, nw;
73
74         /* check input - 16-bit access only */
75         if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
76                 return 1;
77
78         if (bus == PCI_BUS) {
79                 if (!curmap)
80                         return 1;
81                 srom = (void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
82                 if (sprom_read_pci(srom, byteoff, buf, nbytes, FALSE))
83                         return 1;
84         } else if (bus == PCMCIA_BUS) {
85                 off = byteoff / 2;
86                 nw = nbytes / 2;
87                 for (i = 0; i < nw; i++) {
88                         if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i)))
89                                 return 1;
90                 }
91         } else {
92                 return 1;
93         }
94
95         return 0;
96 }
97
98 /* support only 16-bit word write into srom */
99 int
100 srom_write(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
101 {
102         uint16 *srom;
103         uint i, off, nw, crc_range;
104         uint16 image[SPROM_SIZE], *p;
105         uint8 crc;
106         volatile uint32 val32;
107
108         /* check input - 16-bit access only */
109         if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
110                 return 1;
111
112         crc_range = ((bus == PCMCIA_BUS) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2;
113
114         /* if changes made inside crc cover range */
115         if (byteoff < crc_range) {
116                 nw = (((byteoff + nbytes) > crc_range) ? byteoff + nbytes : crc_range) / 2;
117                 /* read data including entire first 64 words from srom */
118                 if (srom_read(bus, curmap, osh, 0, nw * 2, image))
119                         return 1;
120                 /* make changes */
121                 bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
122                 /* calculate crc */
123                 htol16_buf(image, crc_range);
124                 crc = ~crc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
125                 ltoh16_buf(image, crc_range);
126                 image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
127                 p = image;
128                 off = 0;
129         } else {
130                 p = buf;
131                 off = byteoff / 2;
132                 nw = nbytes / 2;
133         }
134
135         if (bus == PCI_BUS) {
136                 srom = (uint16*)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
137                 /* enable writes to the SPROM */
138                 val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
139                 val32 |= SPROM_WRITEEN;
140                 OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
141                 bcm_mdelay(500);
142                 /* write srom */
143                 for (i = 0; i < nw; i++) {
144                         W_REG(&srom[off + i], p[i]);
145                         bcm_mdelay(20);
146                 }
147                 /* disable writes to the SPROM */
148                 OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN);
149         } else if (bus == PCMCIA_BUS) {
150                 /* enable writes to the SPROM */
151                 if (sprom_cmd_pcmcia(osh, SROM_WEN))
152                         return 1;
153                 bcm_mdelay(500);
154                 /* write srom */
155                 for (i = 0; i < nw; i++) {
156                         sprom_write_pcmcia(osh, (uint16)(off + i), p[i]);
157                         bcm_mdelay(20);
158                 }
159                 /* disable writes to the SPROM */
160                 if (sprom_cmd_pcmcia(osh, SROM_WDS))
161                         return 1;
162         } else {
163                 return 1;
164         }
165
166         bcm_mdelay(500);
167         return 0;
168 }
169
170
171 int
172 srom_parsecis(uint8 *cis, char **vars, int *count)
173 {
174         char eabuf[32];
175         char *vp, *base;
176         uint8 tup, tlen, sromrev = 1;
177         int i, j;
178         uint varsize;
179         bool ag_init = FALSE;
180         uint16 w;
181
182         ASSERT(vars);
183         ASSERT(count);
184
185         base = vp = MALLOC(VARS_MAX);
186         ASSERT(vp);
187
188         i = 0;
189         do {
190                 tup = cis[i++];
191                 tlen = cis[i++];
192                 if ((i + tlen) >= CIS_SIZE)
193                         break;
194
195                 switch (tup) {
196                 case CISTPL_MANFID:
197                         vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]);
198                         vp++;
199                         vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]);
200                         vp++;
201                         break;
202
203                 case CISTPL_FUNCE:
204                         if (cis[i] == LAN_NID) {
205                                 ASSERT(cis[i + 1] == ETHER_ADDR_LEN);
206                                 bcm_ether_ntoa((uchar*)&cis[i + 2], eabuf);
207                                 vp += sprintf(vp, "il0macaddr=%s", eabuf);
208                                 vp++;
209                         }
210                         break;
211
212                 case CISTPL_CFTABLE:
213                         vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]);
214                         vp++;
215                         break;
216
217                 case CISTPL_BRCM_HNBU:
218                         switch (cis[i]) {
219                         case HNBU_CHIPID:
220                                 vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) + cis[i + 1]);
221                                 vp++;
222                                 vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) + cis[i + 3]);
223                                 vp++;
224                                 if (tlen == 7) {
225                                         vp += sprintf(vp, "chiprev=%d", (cis[i + 6] << 8) + cis[i + 5]);
226                                         vp++;
227                                 }
228                                 break;
229
230                         case HNBU_BOARDREV:
231                                 vp += sprintf(vp, "boardrev=%d", cis[i + 1]);
232                                 vp++;
233                                 break;
234
235                         case HNBU_AA:
236                                 vp += sprintf(vp, "aa0=%d", cis[i + 1]);
237                                 vp++;
238                                 break;
239
240                         case HNBU_AG:
241                                 vp += sprintf(vp, "ag0=%d", cis[i + 1]);
242                                 vp++;
243                                 ag_init = TRUE;
244                                 break;
245
246                         case HNBU_CC:
247                                 vp += sprintf(vp, "cc=%d", cis[i + 1]);
248                                 vp++;
249                                 break;
250
251                         case HNBU_PAPARMS:
252                                 vp += sprintf(vp, "pa0maxpwr=%d", cis[i + tlen - 1]);
253                                 vp++;
254                                 if (tlen == 9) {
255                                         /* New version */
256                                         for (j = 0; j < 3; j++) {
257                                                 vp += sprintf(vp, "pa0b%d=%d", j,
258                                                               (cis[i + (j * 2) + 2] << 8) + cis[i + (j * 2) + 1]);
259                                                 vp++;
260                                         }
261                                         vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]);
262                                         vp++;
263                                 }
264                                 break;
265
266                         case HNBU_OEM:
267                                 vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
268                                         cis[i + 1], cis[i + 2], cis[i + 3], cis[i + 4],
269                                         cis[i + 5], cis[i + 6], cis[i + 7], cis[i + 8]);
270                                 vp++;
271                                 break;
272                         case HNBU_BOARDFLAGS:
273                                 w = (cis[i + 2] << 8) + cis[i + 1];
274                                 if (w == 0xffff) w = 0;
275                                 vp += sprintf(vp, "boardflags=%d", w);
276                                 vp++;
277                                 break;
278                         case HNBU_LED:
279                                 if (cis[i + 1] != 0xff) {
280                                         vp += sprintf(vp, "wl0gpio0=%d", cis[i + 1]);
281                                         vp++;
282                                 }
283                                 if (cis[i + 2] != 0xff) {
284                                         vp += sprintf(vp, "wl0gpio1=%d", cis[i + 2]);
285                                         vp++;
286                                 }
287                                 if (cis[i + 3] != 0xff) {
288                                         vp += sprintf(vp, "wl0gpio2=%d", cis[i + 3]);
289                                         vp++;
290                                 }
291                                 if (cis[i + 4] != 0xff) {
292                                         vp += sprintf(vp, "wl0gpio3=%d", cis[i + 4]);
293                                         vp++;
294                                 }
295                                 break;
296                         }
297                         break;
298
299                 }
300                 i += tlen;
301         } while (tup != 0xff);
302
303         /* Set the srom version */
304         vp += sprintf(vp, "sromrev=%d", sromrev);
305         vp++;
306
307         /* For now just set boardflags2 to zero */
308         vp += sprintf(vp, "boardflags2=0");
309         vp++;
310
311         /* if there is no antenna gain field, set default */
312         if (ag_init == FALSE) {
313                 vp += sprintf(vp, "ag0=%d", 0xff);
314                 vp++;
315         }
316
317         /* final nullbyte terminator */
318         *vp++ = '\0';
319         varsize = (uint)vp - (uint)base;
320
321         ASSERT(varsize < VARS_MAX);
322
323         if (varsize == VARS_MAX) {
324                 *vars = base;
325         } else {
326                 vp = MALLOC(varsize);
327                 ASSERT(vp);
328                 bcopy(base, vp, varsize);
329                 MFREE(base, VARS_MAX);
330                 *vars = vp;
331         }
332         *count = varsize;
333
334         return (0);
335 }
336
337
338 /* set PCMCIA sprom command register */
339 static int
340 sprom_cmd_pcmcia(void *osh, uint8 cmd)
341 {
342         uint8 status;
343         uint wait_cnt = 1000;
344
345         /* write sprom command register */
346         OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1);
347
348         /* wait status */
349         while (wait_cnt--) {
350                 OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1);
351                 if (status & SROM_DONE)
352                         return 0;
353         }
354
355         return 1;
356 }
357
358 /* read a word from the PCMCIA srom */
359 static int
360 sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data)
361 {
362         uint8 addr_l, addr_h, data_l, data_h;
363
364         addr_l = (uint8)((addr * 2) & 0xff);
365         addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
366
367         /* set address */
368         OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
369         OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
370
371         /* do read */
372         if (sprom_cmd_pcmcia(osh, SROM_READ))
373                 return 1;
374
375         /* read data */
376         OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1);
377         OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1);
378
379         *data = (data_h << 8) | data_l;
380         return 0;
381 }
382
383 /* write a word to the PCMCIA srom */
384 static int
385 sprom_write_pcmcia(void *osh, uint16 addr, uint16 data)
386 {
387         uint8 addr_l, addr_h, data_l, data_h;
388
389         addr_l = (uint8)((addr * 2) & 0xff);
390         addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
391         data_l = (uint8)(data & 0xff);
392         data_h = (uint8)((data >> 8) & 0xff);
393
394         /* set address */
395         OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
396         OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
397
398         /* write data */
399         OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1);
400         OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1);
401
402         /* do write */
403         return sprom_cmd_pcmcia(osh, SROM_WRITE);
404 }
405
406 /*
407  * Read in and validate sprom.
408  * Return 0 on success, nonzero on error.
409  */
410 static int
411 sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc)
412 {
413         int off, nw;
414         uint8 chk8;
415         int i;
416
417         off = byteoff / 2;
418         nw = ROUNDUP(nbytes, 2) / 2;
419
420         /* read the sprom */
421         for (i = 0; i < nw; i++)
422                 buf[i] = R_REG(&sprom[off + i]);
423
424         if (check_crc) {
425                 /* fixup the endianness so crc8 will pass */
426                 htol16_buf(buf, nw * 2);
427                 if ((chk8 = crc8((uchar*)buf, nbytes, CRC8_INIT_VALUE)) != CRC8_GOOD_VALUE)
428                         return (1);
429                 /* now correct the endianness of the byte array */
430                 ltoh16_buf(buf, nw * 2);
431         }
432
433         return (0);
434 }
435
436 /*
437  * Initialize nonvolatile variable table from sprom.
438  * Return 0 on success, nonzero on error.
439  */
440
441 static int
442 initvars_srom_pci(void *curmap, char **vars, int *count)
443 {
444         uint16 w, b[64];
445         uint8 sromrev;
446         struct ether_addr ea;
447         char eabuf[32];              
448         uint32 bfl;
449         int c, woff, i;
450         char *vp, *base;
451
452         if (sprom_read_pci((void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, sizeof (b), TRUE))
453                 return (-1);
454
455         /* top word of sprom contains version and crc8 */
456         sromrev = b[63] & 0xff;
457         if ((sromrev != 1) && (sromrev != 2)) {
458                 return (-2);
459         }
460
461         ASSERT(vars);
462         ASSERT(count);
463
464         base = vp = MALLOC(VARS_MAX);
465         ASSERT(vp);
466
467         vp += sprintf(vp, "sromrev=%d", sromrev);
468         vp++;
469
470         if (sromrev >= 2) {
471                 /* New section takes over the 4th hardware function space */
472
473                 /* Word 29 is max power 11a high/low */
474                 w = b[29];
475                 vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff);
476                 vp++;
477                 vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff);
478                 vp++;
479
480                 /* Words 30-32 set the 11alow pa settings,
481                  * 33-35 are the 11ahigh ones.
482                  */
483                 for (i = 0; i < 3; i++) {
484                         vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]);
485                         vp++;
486                         vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]);
487                         vp++;
488                 }
489                 w = b[59];
490                 if (w == 0)
491                         vp += sprintf(vp, "ccode=");
492                 else
493                         vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
494                 vp++;
495
496         }
497
498         /* parameter section of sprom starts at byte offset 72 */
499         woff = 72/2;
500
501         /* first 6 bytes are il0macaddr */
502         ea.octet[0] = (b[woff] >> 8) & 0xff;
503         ea.octet[1] = b[woff] & 0xff;
504         ea.octet[2] = (b[woff+1] >> 8) & 0xff;
505         ea.octet[3] = b[woff+1] & 0xff;
506         ea.octet[4] = (b[woff+2] >> 8) & 0xff;
507         ea.octet[5] = b[woff+2] & 0xff;
508         woff += ETHER_ADDR_LEN/2 ;
509         bcm_ether_ntoa((uchar*)&ea, eabuf);
510         vp += sprintf(vp, "il0macaddr=%s", eabuf);
511         vp++;
512
513         /* next 6 bytes are et0macaddr */
514         ea.octet[0] = (b[woff] >> 8) & 0xff;
515         ea.octet[1] = b[woff] & 0xff;
516         ea.octet[2] = (b[woff+1] >> 8) & 0xff;
517         ea.octet[3] = b[woff+1] & 0xff;
518         ea.octet[4] = (b[woff+2] >> 8) & 0xff;
519         ea.octet[5] = b[woff+2] & 0xff;
520         woff += ETHER_ADDR_LEN/2 ;
521         bcm_ether_ntoa((uchar*)&ea, eabuf);
522         vp += sprintf(vp, "et0macaddr=%s", eabuf);
523         vp++;
524
525         /* next 6 bytes are et1macaddr */
526         ea.octet[0] = (b[woff] >> 8) & 0xff;
527         ea.octet[1] = b[woff] & 0xff;
528         ea.octet[2] = (b[woff+1] >> 8) & 0xff;
529         ea.octet[3] = b[woff+1] & 0xff;
530         ea.octet[4] = (b[woff+2] >> 8) & 0xff;
531         ea.octet[5] = b[woff+2] & 0xff;
532         woff += ETHER_ADDR_LEN/2 ;
533         bcm_ether_ntoa((uchar*)&ea, eabuf);
534         vp += sprintf(vp, "et1macaddr=%s", eabuf);
535         vp++;
536
537         /*
538          * Enet phy settings one or two singles or a dual
539          * Bits 4-0 : MII address for enet0 (0x1f for not there)
540          * Bits 9-5 : MII address for enet1 (0x1f for not there)
541          * Bit 14   : Mdio for enet0
542          * Bit 15   : Mdio for enet1
543          */
544         w = b[woff];
545         vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f));
546         vp++;
547         vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f));
548         vp++;
549         vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1));
550         vp++;
551         vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1));
552         vp++;
553
554         /* Word 46 has board rev, antennas 0/1 & Country code/control */
555         w = b[46];
556         vp += sprintf(vp, "boardrev=%d", w & 0xff);
557         vp++;
558
559         if (sromrev > 1)
560                 vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf);
561         else
562                 vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf);
563         vp++;
564
565         vp += sprintf(vp, "aa0=%d", (w >> 12) & 0x3);
566         vp++;
567
568         vp += sprintf(vp, "aa1=%d", (w >> 14) & 0x3);
569         vp++;
570
571         /* Words 47-49 set the (wl) pa settings */
572         woff = 47;
573
574         for (i = 0; i < 3; i++) {
575                 vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]);
576                 vp++;
577                 vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]);
578                 vp++;
579         }
580
581         /*
582          * Words 50-51 set the customer-configured wl led behavior.
583          * 8 bits/gpio pin.  High bit:  activehi=0, activelo=1;
584          * LED behavior values defined in wlioctl.h .
585          */
586         w = b[50];
587         if ((w != 0) && (w != 0xffff)) {
588                 /* gpio0 */
589                 vp += sprintf(vp, "wl0gpio0=%d", (w & 0xff));
590                 vp++;
591
592                 /* gpio1 */
593                 vp += sprintf(vp, "wl0gpio1=%d", (w >> 8) & 0xff);
594                 vp++;
595         }
596         w = b[51];
597         if ((w != 0) && (w != 0xffff)) {
598                 /* gpio2 */
599                 vp += sprintf(vp, "wl0gpio2=%d", w & 0xff);
600                 vp++;
601
602                 /* gpio3 */
603                 vp += sprintf(vp, "wl0gpio3=%d", (w >> 8) & 0xff);
604                 vp++;
605         }
606         
607         /* Word 52 is max power 0/1 */
608         w = b[52];
609         vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff);
610         vp++;
611         vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff);
612         vp++;
613
614         /* Word 56 is idle tssi target 0/1 */
615         w = b[56];
616         vp += sprintf(vp, "pa0itssit=%d", w & 0xff);
617         vp++;
618         vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff);
619         vp++;
620
621         /* Word 57 is boardflags, if not programmed make it zero */
622         bfl = (uint32)b[57];
623         if (bfl == 0xffff) bfl = 0;
624         if (sromrev > 1) {
625                 /* Word 28 is boardflags2 */
626                 bfl |= (uint32)b[28] << 16;
627         }
628         vp += sprintf(vp, "boardflags=%d", bfl);
629         vp++;
630
631         /* Word 58 is antenna gain 0/1 */
632         w = b[58];
633         vp += sprintf(vp, "ag0=%d", w & 0xff);
634         vp++;
635
636         vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
637         vp++;
638
639         if (sromrev == 1) {
640                 /* set the oem string */
641                 vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
642                               ((b[59] >> 8) & 0xff), (b[59] & 0xff),
643                               ((b[60] >> 8) & 0xff), (b[60] & 0xff),
644                               ((b[61] >> 8) & 0xff), (b[61] & 0xff),
645                               ((b[62] >> 8) & 0xff), (b[62] & 0xff));
646                 vp++;
647         } else {
648                 if (sromrev >= 1){
649                         /* Word 60 OFDM tx power offset from CCK level */
650                         /* OFDM Power Offset - opo */
651                         w = b[60] & 0xff;
652                         if (w == 0xff)
653                                 w = 16;
654                         vp += sprintf(vp, "opo=%d", w);
655                         vp++;
656                 }
657         }
658
659         /* final nullbyte terminator */
660         *vp++ = '\0';
661
662         c = vp - base;
663         ASSERT(c <= VARS_MAX);
664
665         if (c == VARS_MAX) {
666                 *vars = base;
667         } else {
668                 vp = MALLOC(c);
669                 ASSERT(vp);
670                 bcopy(base, vp, c);
671                 MFREE(base, VARS_MAX);
672                 *vars = vp;
673         }
674         *count = c;
675
676         return (0);
677 }
678
679 /*
680  * Read the cis and call parsecis to initialize the vars.
681  * Return 0 on success, nonzero on error.
682  */
683 static int
684 initvars_cis_pcmcia(void *sbh, void *curmap, void *osh, char **vars, int *count)
685 {
686         uint8 *cis = NULL;
687         int rc;
688         uint data_sz;
689
690         data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
691
692         if ((cis = MALLOC(data_sz)) == NULL)
693                 return (-1);
694
695         if (sb_pcmciarev(sbh) == 1) {
696                 if (srom_read(PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) {
697                         MFREE(cis, data_sz);
698                         return (-1);
699                 }
700                 /* fix up endianess for 16-bit data vs 8-bit parsing */
701                 ltoh16_buf((uint16 *)cis, data_sz);
702         } else
703                 OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz);
704
705         rc = srom_parsecis(cis, vars, count);
706
707         MFREE(cis, data_sz);
708
709         return (rc);
710 }
711