1 /* $NetBSD: if_bwi_pci.c,v 1.7 2009/04/26 10:26:54 cegger Exp $ */
2 /* $OpenBSD: if_bwi_pci.c,v 1.6 2008/02/14 22:10:02 brad Exp $ */
5 * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Broadcom AirForce BCM43xx IEEE 802.11b/g wireless network driver
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: if_bwi_pci.c,v 1.7 2009/04/26 10:26:54 cegger Exp $");
30 #include <sys/param.h>
31 #include <sys/callout.h>
32 #include <sys/device.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/systm.h>
40 #include <machine/bus.h>
43 #include <net/if_dl.h>
44 #include <net/if_ether.h>
45 #include <net/if_media.h>
47 #include <net80211/ieee80211_var.h>
48 #include <net80211/ieee80211_amrr.h>
49 #include <net80211/ieee80211_radiotap.h>
51 #include <dev/ic/bwivar.h>
53 #include <dev/pci/pcireg.h>
54 #include <dev/pci/pcivar.h>
55 #include <dev/pci/pcidevs.h>
57 /* Base Address Register */
58 #define BWI_PCI_BAR0 0x10
60 static int bwi_pci_match(device_t
, cfdata_t
, void *);
61 static void bwi_pci_attach(device_t
, device_t
, void *);
62 static int bwi_pci_detach(device_t
, int);
63 static void bwi_pci_conf_write(void *, uint32_t, uint32_t);
64 static uint32_t bwi_pci_conf_read(void *, uint32_t);
66 struct bwi_pci_softc
{
67 struct bwi_softc psc_bwi
;
69 pci_chipset_tag_t psc_pc
;
72 bus_size_t psc_mapsize
;
75 CFATTACH_DECL_NEW(bwi_pci
, sizeof(struct bwi_pci_softc
),
76 bwi_pci_match
, bwi_pci_attach
, bwi_pci_detach
, NULL
);
79 bwi_pci_match(device_t parent
, cfdata_t match
, void *aux
)
81 struct pci_attach_args
*pa
= aux
;
83 if (PCI_VENDOR(pa
->pa_id
) != PCI_VENDOR_BROADCOM
)
86 switch (PCI_PRODUCT(pa
->pa_id
)) {
87 case PCI_PRODUCT_BROADCOM_BCM4303
:
88 case PCI_PRODUCT_BROADCOM_BCM4306
:
89 case PCI_PRODUCT_BROADCOM_BCM4306_2
:
90 case PCI_PRODUCT_BROADCOM_BCM4307
:
91 case PCI_PRODUCT_BROADCOM_BCM4309
:
92 case PCI_PRODUCT_BROADCOM_BCM4311
:
93 case PCI_PRODUCT_BROADCOM_BCM4312
:
94 case PCI_PRODUCT_BROADCOM_BCM4318
:
95 case PCI_PRODUCT_BROADCOM_BCM4319
:
96 case PCI_PRODUCT_BROADCOM_BCM4322
:
97 case PCI_PRODUCT_BROADCOM_BCM43XG
:
98 case PCI_PRODUCT_BROADCOM_BCM4328
:
106 bwi_pci_attach(device_t parent
, device_t self
, void *aux
)
108 struct bwi_pci_softc
*psc
= device_private(self
);
109 struct pci_attach_args
*pa
= aux
;
110 struct bwi_softc
*sc
= &psc
->psc_bwi
;
111 const char *intrstr
= NULL
;
112 pci_intr_handle_t ih
;
113 pcireg_t memtype
, reg
;
117 aprint_normal(": Broadcom Wireless");
120 sc
->sc_dmat
= pa
->pa_dmat
;
121 psc
->psc_pc
= pa
->pa_pc
;
122 psc
->psc_pcitag
= pa
->pa_tag
;
124 /* map control / status registers */
125 memtype
= pci_mapreg_type(pa
->pa_pc
, pa
->pa_tag
, BWI_PCI_BAR0
);
127 case PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_32BIT
:
128 case PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_64BIT
:
131 aprint_error_dev(self
, "invalid base address register\n");
135 if (pci_mapreg_map(pa
, BWI_PCI_BAR0
,
136 memtype
, 0, &sc
->sc_mem_bt
, &sc
->sc_mem_bh
,
137 NULL
, &psc
->psc_mapsize
) != 0)
139 aprint_error_dev(self
, "could not map mem space\n");
144 if (pci_intr_map(pa
, &ih
) != 0) {
145 aprint_error_dev(self
, "could not map interrupt\n");
149 /* establish interrupt */
150 intrstr
= pci_intr_string(psc
->psc_pc
, ih
);
151 sc
->sc_ih
= pci_intr_establish(psc
->psc_pc
, ih
, IPL_NET
, bwi_intr
, sc
);
152 if (sc
->sc_ih
== NULL
) {
153 aprint_error_dev(self
, "could not establish interrupt");
155 aprint_error(" at %s", intrstr
);
159 aprint_normal_dev(self
, "interrupting at %s\n", intrstr
);
161 /* we need to access PCI config space from the driver */
162 sc
->sc_conf_write
= bwi_pci_conf_write
;
163 sc
->sc_conf_read
= bwi_pci_conf_read
;
165 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_SUBSYS_ID_REG
);
167 sc
->sc_pci_revid
= PCI_REVISION(pa
->pa_class
);
168 sc
->sc_pci_did
= PCI_PRODUCT(pa
->pa_id
);
169 sc
->sc_pci_subvid
= PCI_VENDOR(reg
);
170 sc
->sc_pci_subdid
= PCI_PRODUCT(reg
);
172 if (!pmf_device_register(self
, bwi_suspend
, bwi_resume
))
173 aprint_error_dev(self
, "couldn't establish power handler\n");
175 error
= bwi_attach(sc
);
182 pci_intr_disestablish(psc
->psc_pc
, sc
->sc_ih
);
185 if (psc
->psc_mapsize
) {
186 bus_space_unmap(sc
->sc_mem_bt
, sc
->sc_mem_bh
, psc
->psc_mapsize
);
187 psc
->psc_mapsize
= 0;
193 bwi_pci_detach(device_t self
, int flags
)
195 struct bwi_pci_softc
*psc
= device_private(self
);
196 struct bwi_softc
*sc
= &psc
->psc_bwi
;
198 pmf_device_deregister(self
);
202 if (sc
->sc_ih
!= NULL
) {
203 pci_intr_disestablish(psc
->psc_pc
, sc
->sc_ih
);
211 bwi_pci_conf_write(void *sc
, uint32_t reg
, uint32_t val
)
213 struct bwi_pci_softc
*psc
= (struct bwi_pci_softc
*)sc
;
215 pci_conf_write(psc
->psc_pc
, psc
->psc_pcitag
, reg
, val
);
219 bwi_pci_conf_read(void *sc
, uint32_t reg
)
221 struct bwi_pci_softc
*psc
= (struct bwi_pci_softc
*)sc
;
223 return (pci_conf_read(psc
->psc_pc
, psc
->psc_pcitag
, reg
));