if_sm_pcmcia.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /* $OpenBSD: if_sm_pcmcia.c,v 1.36 2015/03/14 03:38:49 jsg Exp $ */
  2. /* $NetBSD: if_sm_pcmcia.c,v 1.11 1998/08/15 20:47:32 thorpej Exp $ */
  3. /*-
  4. * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
  5. * All rights reserved.
  6. *
  7. * This code is derived from software contributed to The NetBSD Foundation
  8. * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
  9. * NASA Ames Research Center.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  22. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  24. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include "bpfilter.h"
  33. #include <sys/param.h>
  34. #include <sys/systm.h>
  35. #include <sys/mbuf.h>
  36. #include <sys/socket.h>
  37. #include <sys/ioctl.h>
  38. #include <sys/errno.h>
  39. #include <sys/syslog.h>
  40. #include <sys/selinfo.h>
  41. #include <sys/timeout.h>
  42. #include <sys/device.h>
  43. #include <net/if.h>
  44. #include <net/if_dl.h>
  45. #include <net/if_media.h>
  46. #include <netinet/in.h>
  47. #include <netinet/if_ether.h>
  48. #if NBPFILTER > 0
  49. #include <net/bpf.h>
  50. #endif
  51. #include <machine/intr.h>
  52. #include <machine/bus.h>
  53. #include <dev/mii/mii.h>
  54. #include <dev/mii/miivar.h>
  55. #include <dev/ic/smc91cxxvar.h>
  56. #include <dev/pcmcia/pcmciareg.h>
  57. #include <dev/pcmcia/pcmciavar.h>
  58. #include <dev/pcmcia/pcmciadevs.h>
  59. int sm_pcmcia_match(struct device *, void *, void *);
  60. void sm_pcmcia_attach(struct device *, struct device *, void *);
  61. int sm_pcmcia_detach(struct device *, int);
  62. int sm_pcmcia_activate(struct device *, int);
  63. struct sm_pcmcia_softc {
  64. struct smc91cxx_softc sc_smc; /* real "smc" softc */
  65. /* PCMCIA-specific goo. */
  66. struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
  67. int sc_io_window; /* our i/o window */
  68. void *sc_ih; /* interrupt cookie */
  69. struct pcmcia_function *sc_pf; /* our PCMCIA function */
  70. };
  71. struct cfattach sm_pcmcia_ca = {
  72. sizeof(struct sm_pcmcia_softc), sm_pcmcia_match, sm_pcmcia_attach,
  73. sm_pcmcia_detach, sm_pcmcia_activate
  74. };
  75. int sm_pcmcia_enable(struct smc91cxx_softc *);
  76. void sm_pcmcia_disable(struct smc91cxx_softc *);
  77. int sm_pcmcia_ascii_enaddr(const char *, u_int8_t *);
  78. int sm_pcmcia_funce_enaddr(struct device *, u_int8_t *);
  79. int sm_pcmcia_lannid_ciscallback(struct pcmcia_tuple *, void *);
  80. struct sm_pcmcia_product {
  81. u_int16_t spp_vendor; /* vendor ID */
  82. u_int16_t spp_product; /* product ID */
  83. int spp_expfunc; /* expected function */
  84. } sm_pcmcia_prod[] = {
  85. { PCMCIA_VENDOR_MEGAHERTZ2, PCMCIA_PRODUCT_MEGAHERTZ2_XJACK,
  86. 0 },
  87. { PCMCIA_VENDOR_MEGAHERTZ2, PCMCIA_PRODUCT_MEGAHERTZ2_XJEM1144,
  88. 0 },
  89. { PCMCIA_VENDOR_NEWMEDIA, PCMCIA_PRODUCT_NEWMEDIA_BASICS,
  90. 0 },
  91. { PCMCIA_VENDOR_SMC, PCMCIA_PRODUCT_SMC_8020,
  92. 0 },
  93. { PCMCIA_VENDOR_PSION, PCMCIA_PRODUCT_PSION_GOLDCARD,
  94. 0 }
  95. };
  96. int
  97. sm_pcmcia_match(parent, match, aux)
  98. struct device *parent;
  99. void *match, *aux;
  100. {
  101. struct pcmcia_attach_args *pa = aux;
  102. int i;
  103. for (i = 0; i < nitems(sm_pcmcia_prod); i++)
  104. if (pa->manufacturer == sm_pcmcia_prod[i].spp_vendor &&
  105. pa->product == sm_pcmcia_prod[i].spp_product &&
  106. pa->pf->number == sm_pcmcia_prod[i].spp_expfunc)
  107. return (1);
  108. return (0);
  109. }
  110. void
  111. sm_pcmcia_attach(parent, self, aux)
  112. struct device *parent, *self;
  113. void *aux;
  114. {
  115. struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)self;
  116. struct smc91cxx_softc *sc = &psc->sc_smc;
  117. struct pcmcia_attach_args *pa = aux;
  118. struct pcmcia_config_entry *cfe;
  119. u_int8_t myla[ETHER_ADDR_LEN], *enaddr = NULL;
  120. const char *intrstr;
  121. psc->sc_pf = pa->pf;
  122. cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
  123. /* Enable the card. */
  124. pcmcia_function_init(pa->pf, cfe);
  125. if (pcmcia_function_enable(pa->pf)) {
  126. printf(": function enable failed\n");
  127. return;
  128. }
  129. /* XXX sanity check number of mem and i/o spaces */
  130. /* Allocate and map i/o space for the card. */
  131. if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
  132. cfe->iospace[0].length, &psc->sc_pcioh)) {
  133. printf(": can't allocate i/o space\n");
  134. return;
  135. }
  136. sc->sc_bst = psc->sc_pcioh.iot;
  137. sc->sc_bsh = psc->sc_pcioh.ioh;
  138. #ifdef notyet
  139. sc->sc_enable = sm_pcmcia_enable;
  140. sc->sc_disable = sm_pcmcia_disable;
  141. #endif
  142. sc->sc_enabled = 1;
  143. if (pcmcia_io_map(pa->pf, (cfe->flags & PCMCIA_CFE_IO16) ?
  144. PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8, 0, cfe->iospace[0].length,
  145. &psc->sc_pcioh, &psc->sc_io_window)) {
  146. printf(": can't map i/o space\n");
  147. return;
  148. }
  149. printf(" port 0x%lx/%lu", psc->sc_pcioh.addr,
  150. (u_long)psc->sc_pcioh.size);
  151. /*
  152. * First try to get the Ethernet address from FUNCE/LANNID tuple.
  153. */
  154. if (sm_pcmcia_funce_enaddr(parent, myla))
  155. enaddr = myla;
  156. /*
  157. * If that failed, try one of the CIS info strings.
  158. */
  159. if (enaddr == NULL) {
  160. char *cisstr = NULL;
  161. switch (pa->manufacturer) {
  162. case PCMCIA_VENDOR_MEGAHERTZ2:
  163. cisstr = pa->pf->sc->card.cis1_info[3];
  164. break;
  165. case PCMCIA_VENDOR_SMC:
  166. cisstr = pa->pf->sc->card.cis1_info[2];
  167. break;
  168. }
  169. if (cisstr != NULL && sm_pcmcia_ascii_enaddr(cisstr, myla))
  170. enaddr = myla;
  171. }
  172. if (enaddr == NULL)
  173. printf(", unable to get Ethernet address\n");
  174. psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
  175. smc91cxx_intr, sc, sc->sc_dev.dv_xname);
  176. intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
  177. if (*intrstr)
  178. printf(", %s", intrstr);
  179. /* Perform generic initialization. */
  180. smc91cxx_attach(sc, enaddr);
  181. #ifdef notyet
  182. pcmcia_function_disable(pa->pf);
  183. #endif
  184. }
  185. int
  186. sm_pcmcia_detach(dev, flags)
  187. struct device *dev;
  188. int flags;
  189. {
  190. struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)dev;
  191. struct ifnet *ifp = &psc->sc_smc.sc_arpcom.ac_if;
  192. int rv = 0;
  193. pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  194. pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  195. ether_ifdetach(ifp);
  196. if_detach(ifp);
  197. return (rv);
  198. }
  199. int
  200. sm_pcmcia_activate(dev, act)
  201. struct device *dev;
  202. int act;
  203. {
  204. struct sm_pcmcia_softc *sc = (struct sm_pcmcia_softc *)dev;
  205. struct ifnet *ifp = &sc->sc_smc.sc_arpcom.ac_if;
  206. switch (act) {
  207. case DVACT_DEACTIVATE:
  208. ifp->if_timer = 0;
  209. if (ifp->if_flags & IFF_RUNNING)
  210. smc91cxx_stop(&sc->sc_smc);
  211. if (sc->sc_ih)
  212. pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  213. sc->sc_ih = NULL;
  214. pcmcia_function_disable(sc->sc_pf);
  215. break;
  216. }
  217. return (0);
  218. }
  219. int
  220. sm_pcmcia_ascii_enaddr(cisstr, myla)
  221. const char *cisstr;
  222. u_int8_t *myla;
  223. {
  224. char enaddr_str[12];
  225. int i, j;
  226. if (strlen(cisstr) != 12) {
  227. /* Bogus address! */
  228. return (0);
  229. }
  230. bcopy(cisstr, enaddr_str, sizeof enaddr_str);
  231. for (i = 0; i < 6; i++) {
  232. for (j = 0; j < 2; j++) {
  233. /* Convert to upper case. */
  234. if (enaddr_str[(i * 2) + j] >= 'a' &&
  235. enaddr_str[(i * 2) + j] <= 'z')
  236. enaddr_str[(i * 2) + j] -= 'a' - 'A';
  237. /* Parse the digit. */
  238. if (enaddr_str[(i * 2) + j] >= '0' &&
  239. enaddr_str[(i * 2) + j] <= '9')
  240. myla[i] |= enaddr_str[(i * 2) + j]
  241. - '0';
  242. else if (enaddr_str[(i * 2) + j] >= 'A' &&
  243. enaddr_str[(i * 2) + j] <= 'F')
  244. myla[i] |= enaddr_str[(i * 2) + j]
  245. - 'A' + 10;
  246. else {
  247. /* Bogus digit!! */
  248. return (0);
  249. }
  250. /* Compensate for ordering of digits. */
  251. if (j == 0)
  252. myla[i] <<= 4;
  253. }
  254. }
  255. return (1);
  256. }
  257. int
  258. sm_pcmcia_funce_enaddr(parent, myla)
  259. struct device *parent;
  260. u_int8_t *myla;
  261. {
  262. return (pcmcia_scan_cis(parent, sm_pcmcia_lannid_ciscallback, myla));
  263. }
  264. int
  265. sm_pcmcia_lannid_ciscallback(tuple, arg)
  266. struct pcmcia_tuple *tuple;
  267. void *arg;
  268. {
  269. u_int8_t *myla = arg;
  270. int i;
  271. if (tuple->code == PCMCIA_CISTPL_FUNCE || tuple->code ==
  272. PCMCIA_CISTPL_SPCL) {
  273. /* subcode, length */
  274. if (tuple->length < 2)
  275. return (0);
  276. if ((pcmcia_tuple_read_1(tuple, 0) !=
  277. PCMCIA_TPLFE_TYPE_LAN_NID) ||
  278. (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN))
  279. return (0);
  280. for (i = 0; i < ETHER_ADDR_LEN; i++)
  281. myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
  282. return (1);
  283. }
  284. return (0);
  285. }
  286. int
  287. sm_pcmcia_enable(sc)
  288. struct smc91cxx_softc *sc;
  289. {
  290. struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
  291. /* Establish the interrupt handler. */
  292. psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, smc91cxx_intr,
  293. sc, sc->sc_dev.dv_xname);
  294. if (psc->sc_ih == NULL) {
  295. printf("%s: couldn't establish interrupt handler\n",
  296. sc->sc_dev.dv_xname);
  297. return (1);
  298. }
  299. return (pcmcia_function_enable(psc->sc_pf));
  300. }
  301. void
  302. sm_pcmcia_disable(sc)
  303. struct smc91cxx_softc *sc;
  304. {
  305. struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
  306. pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
  307. pcmcia_function_disable(psc->sc_pf);
  308. }