Annotation of sys/dev/pci/if_wi_pci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_wi_pci.c,v 1.43 2006/11/26 19:46:28 deraadt Exp $ */
2:
3: /*
4: * Copyright (c) 2001-2003 Todd C. Miller <Todd.Miller@courtesan.com>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: *
18: * Sponsored in part by the Defense Advanced Research Projects
19: * Agency (DARPA) and Air Force Research Laboratory, Air Force
20: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
21: */
22:
23: /*
24: * PCI attachment for the Wavelan driver. There are two basic types
25: * of PCI card supported:
26: *
27: * 1) Cards based on the Prism2.5 Mini-PCI chipset
28: * 2) Cards that use a dumb PCMCIA->PCI bridge
29: *
30: * Only the first type are "true" PCI cards.
31: *
32: * The latter are simply PCMCIA cards (or the guts of same) with some
33: * type of dumb PCMCIA->PCI bridge. They are "dumb" in that they
34: * are not true PCMCIA bridges and really just serve to deal with
35: * the different interrupt types and timings of the ISA vs. PCI bus.
36: *
37: * The following bridge types are supported:
38: * o PLX 9052 (the most common)
39: * o TMD 7160 (found in some NDC/Sohoware NCP130 cards)
40: * o ACEX EP1K30 (really a PLD, found in Symbol cards and their OEMs)
41: */
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/device.h>
46: #include <sys/timeout.h>
47: #include <sys/socket.h>
48: #include <sys/tree.h>
49:
50: #include <net/if.h>
51: #include <net/if_dl.h>
52: #include <net/if_media.h>
53:
54: #ifdef INET
55: #include <netinet/in.h>
56: #include <netinet/if_ether.h>
57: #endif
58:
59: #include <net80211/ieee80211_var.h>
60: #include <net80211/ieee80211_ioctl.h>
61:
62: #include <machine/bus.h>
63:
64: #include <dev/pci/pcireg.h>
65: #include <dev/pci/pcivar.h>
66: #include <dev/pci/pcidevs.h>
67:
68: #include <dev/ic/if_wireg.h>
69: #include <dev/ic/if_wi_ieee.h>
70: #include <dev/ic/if_wivar.h>
71:
72: /* For printing CIS of the actual PCMCIA card */
73: #define CIS_MFG_NAME_OFFSET 0x16
74: #define CIS_INFO_SIZE 256
75:
76: const struct wi_pci_product *wi_pci_lookup(struct pci_attach_args *pa);
77: int wi_pci_match(struct device *, void *, void *);
78: void wi_pci_attach(struct device *, struct device *, void *);
79: int wi_pci_acex_attach(struct pci_attach_args *pa, struct wi_softc *sc);
80: int wi_pci_plx_attach(struct pci_attach_args *pa, struct wi_softc *sc);
81: int wi_pci_tmd_attach(struct pci_attach_args *pa, struct wi_softc *sc);
82: int wi_pci_native_attach(struct pci_attach_args *pa, struct wi_softc *sc);
83: int wi_pci_common_attach(struct pci_attach_args *pa, struct wi_softc *sc);
84: void wi_pci_plx_print_cis(struct wi_softc *);
85: void wi_pci_power(int, void *);
86:
87: struct wi_pci_softc {
88: struct wi_softc sc_wi; /* real softc */
89: void *sc_powerhook;
90: };
91:
92: struct cfattach wi_pci_ca = {
93: sizeof (struct wi_pci_softc), wi_pci_match, wi_pci_attach
94: };
95:
96: static const struct wi_pci_product {
97: pci_vendor_id_t pp_vendor;
98: pci_product_id_t pp_product;
99: int (*pp_attach)(struct pci_attach_args *pa, struct wi_softc *sc);
100: } wi_pci_products[] = {
101: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_GL24110P, wi_pci_plx_attach },
102: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_GL24110P02, wi_pci_plx_attach },
103: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_GL24110P03, wi_pci_plx_attach },
104: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_8031, wi_pci_plx_attach },
105: { PCI_VENDOR_EUMITCOM, PCI_PRODUCT_EUMITCOM_WL11000P, wi_pci_plx_attach },
106: { PCI_VENDOR_USR2, PCI_PRODUCT_USR2_WL11000P, wi_pci_plx_attach },
107: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRWE777A, wi_pci_plx_attach },
108: { PCI_VENDOR_NETGEAR, PCI_PRODUCT_NETGEAR_MA301, wi_pci_plx_attach },
109: { PCI_VENDOR_EFFICIENTNETS, PCI_PRODUCT_EFFICIENTNETS_SS1023, wi_pci_plx_attach },
110: { PCI_VENDOR_ADDTRON, PCI_PRODUCT_ADDTRON_AWA100, wi_pci_plx_attach },
111: { PCI_VENDOR_BELKIN, PCI_PRODUCT_BELKIN_F5D6000, wi_pci_plx_attach },
112: { PCI_VENDOR_NDC, PCI_PRODUCT_NDC_NCP130, wi_pci_plx_attach },
113: { PCI_VENDOR_NDC, PCI_PRODUCT_NDC_NCP130A2, wi_pci_tmd_attach },
114: { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_MINI_PCI_WLAN, wi_pci_native_attach },
115: { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_ISL3872, wi_pci_native_attach },
116: { PCI_VENDOR_SAMSUNG, PCI_PRODUCT_SAMSUNG_SWL2210P, wi_pci_native_attach },
117: { PCI_VENDOR_NORTEL, PCI_PRODUCT_NORTEL_211818A, wi_pci_acex_attach },
118: { PCI_VENDOR_SYMBOL, PCI_PRODUCT_SYMBOL_LA41X3, wi_pci_acex_attach },
119: { 0, 0, 0 }
120: };
121:
122: const struct wi_pci_product *
123: wi_pci_lookup(struct pci_attach_args *pa)
124: {
125: const struct wi_pci_product *pp;
126:
127: for (pp = wi_pci_products; pp->pp_product != 0; pp++) {
128: if (PCI_VENDOR(pa->pa_id) == pp->pp_vendor &&
129: PCI_PRODUCT(pa->pa_id) == pp->pp_product)
130: return (pp);
131: }
132:
133: return (NULL);
134: }
135:
136: int
137: wi_pci_match(struct device *parent, void *match, void *aux)
138: {
139: return (wi_pci_lookup(aux) != NULL);
140: }
141:
142: void
143: wi_pci_attach(struct device *parent, struct device *self, void *aux)
144: {
145: struct wi_pci_softc *psc = (struct wi_pci_softc *)self;
146: struct wi_softc *sc = (struct wi_softc *)self;
147: struct pci_attach_args *pa = aux;
148: const struct wi_pci_product *pp;
149:
150: pp = wi_pci_lookup(pa);
151: if (pp->pp_attach(pa, sc) != 0)
152: return;
153: printf("\n");
154: wi_attach(sc, &wi_func_io);
155:
156: psc->sc_powerhook = powerhook_establish(wi_pci_power, sc);
157: }
158:
159: void
160: wi_pci_power(int why, void *arg)
161: {
162: struct wi_softc *sc = (struct wi_softc *)arg;
163:
164: if (why == PWR_RESUME) {
165: if (sc->sc_ic.ic_if.if_flags & IFF_UP)
166: wi_init(sc);
167: }
168: }
169:
170: /*
171: * ACEX EP1K30-based PCMCIA->PCI bridge attachment.
172: *
173: * The ACEX EP1K30 is a programmable logic device (PLD) used as a
174: * PCMCIA->PCI bridge on the Symbol LA4123 and its OEM equivalents
175: * (such as the Nortel E-mobility 211818-A). There are 3 I/O ports:
176: * BAR0 at 0x10 appears to be a command port.
177: * BAR1 at 0x14 contains COR at offset 0xe0.
178: * BAR2 at 0x18 maps the actual PCMCIA card.
179: *
180: * The datasheet for the ACEX EP1K30 is available from Altera but that
181: * doesn't really help much since we don't know how it is programmed.
182: * Details for this attachment were gleaned from a version of the
183: * Linux orinoco driver modified by Tobias Hoffmann based on
184: * what he discoverd from the Windows driver.
185: */
186: int
187: wi_pci_acex_attach(struct pci_attach_args *pa, struct wi_softc *sc)
188: {
189: bus_space_handle_t commandh, localh, ioh;
190: bus_space_tag_t commandt, localt;
191: bus_space_tag_t iot = pa->pa_iot;
192: bus_size_t commandsize, localsize, iosize;
193: int i;
194:
195: if (pci_mapreg_map(pa, WI_ACEX_CMDRES, PCI_MAPREG_TYPE_IO,
196: 0, &commandt, &commandh, NULL, &commandsize, 0) != 0) {
197: printf(": can't map command I/O space\n");
198: return (ENXIO);
199: }
200:
201: if (pci_mapreg_map(pa, WI_ACEX_LOCALRES, PCI_MAPREG_TYPE_IO,
202: 0, &localt, &localh, NULL, &localsize, 0) != 0) {
203: printf(": can't map local I/O space\n");
204: bus_space_unmap(commandt, commandh, commandsize);
205: return (ENXIO);
206: }
207: sc->wi_ltag = localt;
208: sc->wi_lhandle = localh;
209:
210: if (pci_mapreg_map(pa, WI_TMD_IORES, PCI_MAPREG_TYPE_IO,
211: 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
212: printf(": can't map I/O space\n");
213: bus_space_unmap(localt, localh, localsize);
214: bus_space_unmap(commandt, commandh, commandsize);
215: return (ENXIO);
216: }
217: sc->wi_btag = iot;
218: sc->wi_bhandle = ioh;
219:
220: /*
221: * Setup bridge chip.
222: */
223: if (bus_space_read_4(commandt, commandh, 0) & 1) {
224: printf(": bridge not ready\n");
225: bus_space_unmap(iot, ioh, iosize);
226: bus_space_unmap(localt, localh, localsize);
227: bus_space_unmap(commandt, commandh, commandsize);
228: return (ENXIO);
229: }
230: bus_space_write_4(commandt, commandh, 2, 0x118);
231: bus_space_write_4(commandt, commandh, 2, 0x108);
232: DELAY(30 * 1000);
233: bus_space_write_4(commandt, commandh, 2, 0x8);
234: for (i = 0; i < 30; i++) {
235: DELAY(30 * 1000);
236: if (bus_space_read_4(commandt, commandh, 0) & 0x10)
237: break;
238: }
239: if (i == 30) {
240: printf(": bridge timeout\n");
241: bus_space_unmap(iot, ioh, iosize);
242: bus_space_unmap(localt, localh, localsize);
243: bus_space_unmap(commandt, commandh, commandsize);
244: return (ENXIO);
245: }
246: if ((bus_space_read_4(localt, localh, 0xe0) & 1) ||
247: (bus_space_read_4(localt, localh, 0xe2) & 1) ||
248: (bus_space_read_4(localt, localh, 0xe4) & 1)) {
249: printf(": failed bridge setup\n");
250: bus_space_unmap(iot, ioh, iosize);
251: bus_space_unmap(localt, localh, localsize);
252: bus_space_unmap(commandt, commandh, commandsize);
253: return (ENXIO);
254: }
255:
256: if (wi_pci_common_attach(pa, sc) != 0) {
257: bus_space_unmap(iot, ioh, iosize);
258: bus_space_unmap(localt, localh, localsize);
259: bus_space_unmap(commandt, commandh, commandsize);
260: return (ENXIO);
261: }
262:
263: /*
264: * Enable I/O mode and level interrupts on the embedded PCMCIA
265: * card.
266: */
267: bus_space_write_1(localt, localh, WI_ACEX_COR_OFFSET, WI_COR_IOMODE);
268: sc->wi_cor_offset = WI_ACEX_COR_OFFSET;
269:
270: /* Unmap registers we no longer need access to. */
271: bus_space_unmap(commandt, commandh, commandsize);
272:
273: return (0);
274: }
275:
276: /*
277: * PLX 9052-based PCMCIA->PCI bridge attachment.
278: *
279: * These are often sold as "PCI wireless card adapters" and are
280: * sold by several vendors. Most are simply rebadged versions of the
281: * Eumitcom WL11000P or Global Sun Technology GL24110P02.
282: * These cards use the PLX 9052 dumb bridge chip to connect a PCMCIA
283: * wireless card to the PCI bus. Because it is a dumb bridge and
284: * not a true PCMCIA bridge, the PCMCIA subsystem is not involved
285: * (or even required). The PLX 9052 provides multiple PCI address
286: * space mappings. The primary mappings at PCI registers 0x10 (mem)
287: * and 0x14 (I/O) are for the PLX chip itself, *NOT* the PCMCIA card.
288: * The mem and I/O spaces for the PCMCIA card are mapped to 0x18 and
289: * 0x1C respectively.
290: * The PLX 9050/9052 datasheet may be downloaded from PLX at
291: * http://www.plxtech.com/products/toolbox/9050.htm
292: */
293: int
294: wi_pci_plx_attach(struct pci_attach_args *pa, struct wi_softc *sc)
295: {
296: bus_space_handle_t localh, ioh, memh;
297: bus_space_tag_t localt;
298: bus_space_tag_t iot = pa->pa_iot;
299: bus_space_tag_t memt = pa->pa_memt;
300: bus_size_t localsize, memsize, iosize;
301: u_int32_t intcsr;
302:
303: if (pci_mapreg_map(pa, WI_PLX_MEMRES, PCI_MAPREG_TYPE_MEM, 0,
304: &memt, &memh, NULL, &memsize, 0) != 0) {
305: printf(": can't map mem space\n");
306: return (ENXIO);
307: }
308: sc->wi_ltag = memt;
309: sc->wi_lhandle = memh;
310:
311: if (pci_mapreg_map(pa, WI_PLX_IORES,
312: PCI_MAPREG_TYPE_IO, 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
313: printf(": can't map I/O space\n");
314: bus_space_unmap(memt, memh, memsize);
315: return (ENXIO);
316: }
317: sc->wi_btag = iot;
318: sc->wi_bhandle = ioh;
319:
320: /*
321: * Some cards, such as the PLX version of the NDC NCP130,
322: * don't have the PLX local registers mapped. In general
323: * this is OK since on those cards the serial EEPROM has
324: * already set things up for us.
325: * As such, we don't consider an error here to be fatal.
326: */
327: localsize = 0;
328: if (pci_mapreg_type(pa->pa_pc, pa->pa_tag, WI_PLX_LOCALRES)
329: == PCI_MAPREG_TYPE_IO) {
330: if (pci_mapreg_map(pa, WI_PLX_LOCALRES, PCI_MAPREG_TYPE_IO,
331: 0, &localt, &localh, NULL, &localsize, 0) != 0)
332: printf(": can't map PLX I/O space\n");
333: }
334:
335: if (wi_pci_common_attach(pa, sc) != 0) {
336: if (localsize)
337: bus_space_unmap(localt, localh, localsize);
338: bus_space_unmap(iot, ioh, iosize);
339: bus_space_unmap(memt, memh, memsize);
340: return (ENXIO);
341: }
342:
343: if (localsize != 0) {
344: intcsr = bus_space_read_4(localt, localh,
345: WI_PLX_INTCSR);
346:
347: /*
348: * The Netgear MA301 has local interrupt 1 active
349: * when there is no card in the adapter. We bail
350: * early in this case since our attempt to check
351: * for the presence of a card later will hang the
352: * MA301.
353: */
354: if (intcsr & WI_PLX_LINT1STAT) {
355: printf("\n%s: no PCMCIA card detected in bridge card\n",
356: WI_PRT_ARG(sc));
357: pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
358: if (localsize)
359: bus_space_unmap(localt, localh, localsize);
360: bus_space_unmap(iot, ioh, iosize);
361: bus_space_unmap(memt, memh, memsize);
362: return (ENXIO);
363: }
364:
365: /*
366: * Enable PCI interrupts on the PLX chip if they are
367: * not already enabled. On most adapters the serial
368: * EEPROM has done this for us but some (such as
369: * the Netgear MA301) do not.
370: */
371: if (!(intcsr & WI_PLX_INTEN)) {
372: intcsr |= WI_PLX_INTEN;
373: bus_space_write_4(localt, localh, WI_PLX_INTCSR,
374: intcsr);
375: }
376: }
377:
378: /*
379: * Enable I/O mode and level interrupts on the PCMCIA card.
380: * The PCMCIA card's COR is the first byte after the CIS.
381: */
382: bus_space_write_1(memt, memh, WI_PLX_COR_OFFSET, WI_COR_IOMODE);
383: sc->wi_cor_offset = WI_PLX_COR_OFFSET;
384:
385: if (localsize != 0) {
386: /*
387: * Test the presence of a wi(4) card by writing
388: * a magic number to the first software support
389: * register and then reading it back.
390: */
391: CSR_WRITE_2(sc, WI_SW0, WI_DRVR_MAGIC);
392: DELAY(1000);
393: if (CSR_READ_2(sc, WI_SW0) != WI_DRVR_MAGIC) {
394: printf("\n%s: no PCMCIA card detected in bridge card\n",
395: WI_PRT_ARG(sc));
396: pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
397: if (localsize)
398: bus_space_unmap(localt, localh, localsize);
399: bus_space_unmap(iot, ioh, iosize);
400: bus_space_unmap(memt, memh, memsize);
401: return (ENXIO);
402: }
403:
404: /* Unmap registers we no longer need access to. */
405: bus_space_unmap(localt, localh, localsize);
406:
407: /* Print PCMCIA card's CIS strings. */
408: wi_pci_plx_print_cis(sc);
409: }
410:
411: return (0);
412: }
413:
414: /*
415: * TMD 7160-based PCMCIA->PCI bridge attachment.
416: *
417: * The TMD7160 dumb bridge chip is used on some versions of the
418: * NDC/Sohoware NCP130. The TMD7160 provides two PCI I/O registers.
419: * The first, at 0x14, maps to the Prism2 COR.
420: * The second, at 0x18, is for the Prism2 chip itself.
421: *
422: * The datasheet for the TMD7160 does not seem to be publicly available.
423: * Details for this attachment were gleaned from a version of the
424: * Linux WLAN driver modified by NDC.
425: */
426: int
427: wi_pci_tmd_attach(struct pci_attach_args *pa, struct wi_softc *sc)
428: {
429: bus_space_handle_t localh, ioh;
430: bus_space_tag_t localt;
431: bus_space_tag_t iot = pa->pa_iot;
432: bus_size_t localsize, iosize;
433:
434: if (pci_mapreg_map(pa, WI_TMD_LOCALRES, PCI_MAPREG_TYPE_IO,
435: 0, &localt, &localh, NULL, &localsize, 0) != 0) {
436: printf(": can't map TMD I/O space\n");
437: return (ENXIO);
438: }
439: sc->wi_ltag = localt;
440: sc->wi_lhandle = localh;
441:
442: if (pci_mapreg_map(pa, WI_TMD_IORES, PCI_MAPREG_TYPE_IO,
443: 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
444: printf(": can't map I/O space\n");
445: bus_space_unmap(localt, localh, localsize);
446: return (ENXIO);
447: }
448: sc->wi_btag = iot;
449: sc->wi_bhandle = ioh;
450:
451: if (wi_pci_common_attach(pa, sc) != 0) {
452: bus_space_unmap(iot, ioh, iosize);
453: bus_space_unmap(localt, localh, localsize);
454: return (ENXIO);
455: }
456:
457: /*
458: * Enable I/O mode and level interrupts on the embedded PCMCIA
459: * card. The PCMCIA card's COR is the first byte of BAR 0.
460: */
461: bus_space_write_1(localt, localh, 0, WI_COR_IOMODE);
462: sc->wi_cor_offset = 0;
463:
464: return (0);
465: }
466:
467: int
468: wi_pci_native_attach(struct pci_attach_args *pa, struct wi_softc *sc)
469: {
470: bus_space_handle_t ioh;
471: bus_space_tag_t iot = pa->pa_iot;
472: bus_size_t iosize;
473:
474: if (pci_mapreg_map(pa, WI_PCI_CBMA, PCI_MAPREG_TYPE_MEM,
475: 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
476: printf(": can't map mem space\n");
477: return (ENXIO);
478: }
479: sc->wi_ltag = iot;
480: sc->wi_lhandle = ioh;
481: sc->wi_btag = iot;
482: sc->wi_bhandle = ioh;
483: sc->sc_pci = 1;
484:
485: if (wi_pci_common_attach(pa, sc) != 0) {
486: bus_space_unmap(iot, ioh, iosize);
487: return (ENXIO);
488: }
489:
490: /* Do a soft reset of the HFA3842 MAC core */
491: bus_space_write_2(iot, ioh, WI_PCI_COR_OFFSET, WI_COR_SOFT_RESET);
492: DELAY(100*1000); /* 100 m sec */
493: bus_space_write_2(iot, ioh, WI_PCI_COR_OFFSET, WI_COR_CLEAR);
494: DELAY(100*1000); /* 100 m sec */
495: sc->wi_cor_offset = WI_PCI_COR_OFFSET;
496:
497: return (0);
498: }
499:
500: int
501: wi_pci_common_attach(struct pci_attach_args *pa, struct wi_softc *sc)
502: {
503: pci_intr_handle_t ih;
504: pci_chipset_tag_t pc = pa->pa_pc;
505: const char *intrstr;
506:
507: /* Make sure interrupts are disabled. */
508: CSR_WRITE_2(sc, WI_INT_EN, 0);
509: CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
510:
511: /* Map and establish the interrupt. */
512: if (pci_intr_map(pa, &ih)) {
513: printf(": couldn't map interrupt\n");
514: return (ENXIO);
515: }
516: intrstr = pci_intr_string(pc, ih);
517: sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, wi_intr, sc,
518: sc->sc_dev.dv_xname);
519: if (sc->sc_ih == NULL) {
520: printf(": couldn't establish interrupt");
521: if (intrstr != NULL)
522: printf(" at %s", intrstr);
523: printf("\n");
524: return (ENXIO);
525: }
526: printf(": %s", intrstr);
527:
528: return (0);
529: }
530:
531: void
532: wi_pci_plx_print_cis(struct wi_softc *sc)
533: {
534: int i, stringno;
535: char cisbuf[CIS_INFO_SIZE];
536: char *cis_strings[3];
537: u_int8_t value;
538: const u_int8_t cis_magic[] = {
539: 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
540: };
541:
542: /* Make sure the CIS data is valid. */
543: for (i = 0; i < 8; i++) {
544: value = bus_space_read_1(sc->wi_ltag, sc->wi_lhandle, i * 2);
545: if (value != cis_magic[i])
546: return;
547: }
548:
549: cis_strings[0] = cisbuf;
550: stringno = 0;
551: for (i = 0; i < CIS_INFO_SIZE && stringno < 3; i++) {
552: cisbuf[i] = bus_space_read_1(sc->wi_ltag,
553: sc->wi_lhandle, (CIS_MFG_NAME_OFFSET + i) * 2);
554: if (cisbuf[i] == '\0' && ++stringno < 3)
555: cis_strings[stringno] = &cisbuf[i + 1];
556: }
557: cisbuf[CIS_INFO_SIZE - 1] = '\0';
558: printf("\n%s: \"%s, %s, %s\"", WI_PRT_ARG(sc),
559: cis_strings[0], cis_strings[1], cis_strings[2]);
560: }
CVSweb