if_bwi_cardbus.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* $OpenBSD: if_bwi_cardbus.c,v 1.15 2013/12/06 21:03:02 deraadt Exp $ */
  2. /*
  3. * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
  4. * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
  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. /*
  19. * Cardbus front-end for the Broadcom AirForce
  20. */
  21. #include "bpfilter.h"
  22. #include <sys/param.h>
  23. #include <sys/mbuf.h>
  24. #include <sys/socket.h>
  25. #include <sys/systm.h>
  26. #include <sys/timeout.h>
  27. #include <net/if.h>
  28. #include <net/if_media.h>
  29. #include <netinet/in.h>
  30. #include <netinet/if_ether.h>
  31. #include <net80211/ieee80211_var.h>
  32. #include <net80211/ieee80211_amrr.h>
  33. #include <net80211/ieee80211_radiotap.h>
  34. #include <dev/pci/pcireg.h>
  35. #include <dev/pci/pcivar.h>
  36. #include <dev/pci/pcidevs.h>
  37. #include <dev/cardbus/cardbusvar.h>
  38. #include <dev/ic/bwivar.h>
  39. struct bwi_cardbus_softc {
  40. struct bwi_softc csc_bwi;
  41. /* cardbus specific goo */
  42. cardbus_devfunc_t csc_ct;
  43. pcitag_t csc_tag;
  44. void *csc_ih;
  45. bus_size_t csc_mapsize;
  46. pcireg_t csc_bar_val;
  47. int csc_intrline;
  48. pci_chipset_tag_t csc_pc;
  49. };
  50. int bwi_cardbus_match(struct device *, void *, void*);
  51. void bwi_cardbus_attach(struct device *, struct device *, void *);
  52. int bwi_cardbus_detach(struct device *, int);
  53. void bwi_cardbus_setup(struct bwi_cardbus_softc *);
  54. int bwi_cardbus_enable(struct bwi_softc *);
  55. void bwi_cardbus_disable(struct bwi_softc *);
  56. void bwi_cardbus_conf_write(void *, uint32_t, uint32_t);
  57. uint32_t bwi_cardbus_conf_read(void *, uint32_t);
  58. struct cfattach bwi_cardbus_ca = {
  59. sizeof (struct bwi_cardbus_softc), bwi_cardbus_match,
  60. bwi_cardbus_attach, bwi_cardbus_detach
  61. };
  62. static const struct pci_matchid bwi_cardbus_devices[] = {
  63. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4303 },
  64. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306 },
  65. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306_2 },
  66. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4307 },
  67. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4309 },
  68. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 },
  69. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 },
  70. { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG }
  71. };
  72. int
  73. bwi_cardbus_match(struct device *parent, void *match, void *aux)
  74. {
  75. return (cardbus_matchbyid(aux, bwi_cardbus_devices,
  76. sizeof (bwi_cardbus_devices) / sizeof (bwi_cardbus_devices[0])));
  77. }
  78. void
  79. bwi_cardbus_attach(struct device *parent, struct device *self, void *aux)
  80. {
  81. struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
  82. struct cardbus_attach_args *ca = aux;
  83. struct bwi_softc *sc = &csc->csc_bwi;
  84. cardbus_devfunc_t ct = ca->ca_ct;
  85. pcireg_t reg;
  86. bus_addr_t base;
  87. int error;
  88. sc->sc_dmat = ca->ca_dmat;
  89. csc->csc_ct = ct;
  90. csc->csc_tag = ca->ca_tag;
  91. csc->csc_intrline = ca->ca_intrline;
  92. csc->csc_pc = ca->ca_pc;
  93. /* power management hooks */
  94. sc->sc_enable = bwi_cardbus_enable;
  95. sc->sc_disable = bwi_cardbus_disable;
  96. //sc->sc_power = bwi_cardbus_power;
  97. /* map control/status registers */
  98. error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
  99. PCI_MAPREG_TYPE_MEM, 0, &sc->sc_mem_bt,
  100. &sc->sc_mem_bh, &base, &csc->csc_mapsize);
  101. if (error != 0) {
  102. printf(": can't map mem space\n");
  103. return;
  104. }
  105. csc->csc_bar_val = base | PCI_MAPREG_TYPE_MEM;
  106. /* set up the PCI configuration registers */
  107. bwi_cardbus_setup(csc);
  108. printf(": irq %d", csc->csc_intrline);
  109. /* we need to access Cardbus config space from the driver */
  110. sc->sc_conf_read = bwi_cardbus_conf_read;
  111. sc->sc_conf_write = bwi_cardbus_conf_write;
  112. reg = (sc->sc_conf_read)(sc, PCI_SUBSYS_ID_REG);
  113. sc->sc_pci_revid = PCI_REVISION(ca->ca_class);
  114. sc->sc_pci_did = PCI_PRODUCT(ca->ca_id);
  115. sc->sc_pci_subvid = PCI_VENDOR(reg);
  116. sc->sc_pci_subdid = PCI_PRODUCT(reg);
  117. error = bwi_attach(sc);
  118. if (error != 0)
  119. bwi_cardbus_detach(&sc->sc_dev, 0);
  120. Cardbus_function_disable(ct);
  121. }
  122. int
  123. bwi_cardbus_detach(struct device *self, int flags)
  124. {
  125. struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
  126. struct bwi_softc *sc = &csc->csc_bwi;
  127. cardbus_devfunc_t ct = csc->csc_ct;
  128. cardbus_chipset_tag_t cc = ct->ct_cc;
  129. cardbus_function_tag_t cf = ct->ct_cf;
  130. int error;
  131. error = bwi_detach(sc);
  132. if (error != 0)
  133. return (error);
  134. /* unhook the interrupt handler */
  135. if (csc->csc_ih != NULL) {
  136. cardbus_intr_disestablish(cc, cf, csc->csc_ih);
  137. csc->csc_ih = NULL;
  138. }
  139. /* release bus space and close window */
  140. Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_mem_bt,
  141. sc->sc_mem_bh, csc->csc_mapsize);
  142. return (0);
  143. }
  144. void
  145. bwi_cardbus_setup(struct bwi_cardbus_softc *csc)
  146. {
  147. cardbus_devfunc_t ct = csc->csc_ct;
  148. cardbus_chipset_tag_t cc = ct->ct_cc;
  149. pci_chipset_tag_t pc = csc->csc_pc;
  150. cardbus_function_tag_t cf = ct->ct_cf;
  151. pcireg_t reg;
  152. /* program the BAR */
  153. pci_conf_write(pc, csc->csc_tag, CARDBUS_BASE0_REG,
  154. csc->csc_bar_val);
  155. /* make sure the right access type is on the cardbus bridge */
  156. (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
  157. (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
  158. /* enable the appropriate bits in the PCI CSR */
  159. reg = pci_conf_read(pc, csc->csc_tag,
  160. PCI_COMMAND_STATUS_REG);
  161. reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
  162. pci_conf_write(pc, csc->csc_tag, PCI_COMMAND_STATUS_REG,
  163. reg);
  164. }
  165. int
  166. bwi_cardbus_enable(struct bwi_softc *sc)
  167. {
  168. struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc;
  169. cardbus_devfunc_t ct = csc->csc_ct;
  170. cardbus_chipset_tag_t cc = ct->ct_cc;
  171. cardbus_function_tag_t cf = ct->ct_cf;
  172. /* power on the socket */
  173. Cardbus_function_enable(ct);
  174. /* setup the PCI configuration registers */
  175. bwi_cardbus_setup(csc);
  176. /* map and establish the interrupt handler */
  177. csc->csc_ih = cardbus_intr_establish(cc, cf, csc->csc_intrline, IPL_NET,
  178. bwi_intr, sc, sc->sc_dev.dv_xname);
  179. if (csc->csc_ih == NULL) {
  180. printf("%s: could not establish interrupt at %d\n",
  181. sc->sc_dev.dv_xname, csc->csc_intrline);
  182. Cardbus_function_disable(ct);
  183. return (1);
  184. }
  185. return (0);
  186. }
  187. void
  188. bwi_cardbus_disable(struct bwi_softc *sc)
  189. {
  190. struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc;
  191. cardbus_devfunc_t ct = csc->csc_ct;
  192. cardbus_chipset_tag_t cc = ct->ct_cc;
  193. cardbus_function_tag_t cf = ct->ct_cf;
  194. /* unhook the interrupt handler */
  195. cardbus_intr_disestablish(cc, cf, csc->csc_ih);
  196. csc->csc_ih = NULL;
  197. /* power down the socket */
  198. Cardbus_function_disable(ct);
  199. }
  200. void
  201. bwi_cardbus_conf_write(void *self, uint32_t reg, uint32_t val)
  202. {
  203. struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
  204. pci_chipset_tag_t pc = csc->csc_pc;
  205. pci_conf_write(pc, csc->csc_tag, reg, val);
  206. }
  207. uint32_t
  208. bwi_cardbus_conf_read(void *self, uint32_t reg)
  209. {
  210. struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
  211. pci_chipset_tag_t pc = csc->csc_pc;
  212. return (pci_conf_read(pc, csc->csc_tag, reg));
  213. }