Annotation of sys/dev/pcmcia/if_rln_pcmcia.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_rln_pcmcia.c,v 1.15 2005/01/27 17:04:56 millert Exp $ */
! 2: /*
! 3: * David Leonard <d@openbsd.org>, 1999. Public domain.
! 4: *
! 5: * Proxim RangeLAN2 PC-Card and compatibles
! 6: */
! 7:
! 8: #include <sys/param.h>
! 9: #include <sys/systm.h>
! 10: #include <sys/socket.h>
! 11: #include <sys/device.h>
! 12: #include <sys/queue.h>
! 13:
! 14: #include <net/if.h>
! 15:
! 16: #ifdef INET
! 17: #include <netinet/in.h>
! 18: #include <netinet/if_ether.h>
! 19: #endif
! 20:
! 21: #include <machine/bus.h>
! 22: #include <machine/intr.h>
! 23:
! 24: #include <dev/ic/rln.h>
! 25: #include <dev/ic/rlnvar.h>
! 26: #include <dev/ic/rlnreg.h>
! 27:
! 28: #include <dev/pcmcia/pcmciareg.h>
! 29: #include <dev/pcmcia/pcmciavar.h>
! 30: #include <dev/pcmcia/pcmciadevs.h>
! 31:
! 32: struct rln_pcmcia_softc {
! 33: struct rln_softc psc_rln; /* real "rln" softc */
! 34:
! 35: struct pcmcia_io_handle psc_pcioh; /* PCMCIA i/o information */
! 36: int sc_io_window; /* i/o window for the card */
! 37: struct pcmcia_function *psc_pf; /* our PCMCIA function */
! 38: void *psc_ih; /* our interrupt handle */
! 39: };
! 40:
! 41: static int rln_pcmcia_match(struct device *, void *, void *);
! 42: static struct rln_pcmcia_product * rln_pcmcia_product_lookup(struct pcmcia_attach_args *);
! 43: static void rln_pcmcia_attach(struct device *, struct device *, void *);
! 44: static int rln_pcmcia_detach(struct device *, int);
! 45: static int rln_pcmcia_activate(struct device *, enum devact);
! 46: static int rlnintr_pcmcia(void *arg);
! 47:
! 48: struct cfattach rln_pcmcia_ca = {
! 49: sizeof(struct rln_pcmcia_softc), rln_pcmcia_match, rln_pcmcia_attach,
! 50: rln_pcmcia_detach, rln_pcmcia_activate
! 51: };
! 52:
! 53: static struct rln_pcmcia_product {
! 54: u_int16_t manufacturer;
! 55: u_int16_t product;
! 56: const char *cis[4];
! 57: u_int8_t flags;
! 58: } rln_pcmcia_products[] = {
! 59: /* Digital RoamAbout 2400 FH, from d@openbsd.org */
! 60: { PCMCIA_VENDOR_PROXIM,
! 61: PCMCIA_PRODUCT_PROXIM_ROAMABOUT_2400FH,
! 62: PCMCIA_CIS_PROXIM_ROAMABOUT_2400FH,
! 63: 0 },
! 64: /* AMP Wireless, from jimduchek@ou.edu */
! 65: { PCMCIA_VENDOR_COMPEX,
! 66: PCMCIA_PRODUCT_COMPEX_AMP_WIRELESS,
! 67: PCMCIA_CIS_COMPEX_AMP_WIRELESS,
! 68: 0 },
! 69: /* Proxim RangeLAN2 7401, from louis@bertrandtech.on.ca */
! 70: { PCMCIA_VENDOR_PROXIM,
! 71: PCMCIA_PRODUCT_PROXIM_RANGELAN2_7401,
! 72: PCMCIA_CIS_PROXIM_RANGELAN2_7401,
! 73: 0 },
! 74: /* Generic and clone cards matched by CIS alone */
! 75: { PCMCIA_VENDOR_INVALID,
! 76: PCMCIA_PRODUCT_INVALID,
! 77: PCMCIA_CIS_PROXIM_RL2_7200,
! 78: 0 },
! 79: { PCMCIA_VENDOR_INVALID,
! 80: PCMCIA_PRODUCT_INVALID,
! 81: PCMCIA_CIS_PROXIM_RL2_7400,
! 82: 0 },
! 83: { PCMCIA_VENDOR_INVALID,
! 84: PCMCIA_PRODUCT_INVALID,
! 85: PCMCIA_CIS_PROXIM_SYMPHONY,
! 86: 0 }
! 87: };
! 88: #define NPRODUCTS (sizeof rln_pcmcia_products / sizeof rln_pcmcia_products[0])
! 89:
! 90: /* Match the card information with known card types */
! 91: static struct rln_pcmcia_product *
! 92: rln_pcmcia_product_lookup(pa)
! 93: struct pcmcia_attach_args *pa;
! 94: {
! 95: int i, j;
! 96: struct rln_pcmcia_product *rpp;
! 97:
! 98: for (i = 0; i < NPRODUCTS; i++) {
! 99: rpp = &rln_pcmcia_products[i];
! 100: if (rpp->manufacturer != PCMCIA_VENDOR_INVALID &&
! 101: rpp->manufacturer != pa->manufacturer)
! 102: continue;
! 103: if (rpp->product != PCMCIA_PRODUCT_INVALID &&
! 104: rpp->product != pa->product)
! 105: continue;
! 106: for (j = 0; j < 4; j++) {
! 107: if (rpp->cis[j] == NULL)
! 108: return rpp;
! 109: if (pa->card->cis1_info[j] &&
! 110: strcmp(pa->card->cis1_info[j], rpp->cis[j]) != 0)
! 111: break;
! 112: }
! 113: if (j == 4)
! 114: return rpp;
! 115: }
! 116: return NULL;
! 117: }
! 118:
! 119: /* Do we know this card? */
! 120: static int
! 121: rln_pcmcia_match(parent, match, aux)
! 122: struct device *parent;
! 123: void *match, *aux;
! 124: {
! 125: struct pcmcia_attach_args *pa = aux;
! 126:
! 127: return (rln_pcmcia_product_lookup(pa) != NULL);
! 128: }
! 129:
! 130: /* Attach and configure */
! 131: void
! 132: rln_pcmcia_attach(parent, self, aux)
! 133: struct device *parent, *self;
! 134: void *aux;
! 135: {
! 136: struct rln_pcmcia_softc *psc = (void *) self;
! 137: struct rln_softc *sc = &psc->psc_rln;
! 138: struct pcmcia_attach_args *pa = aux;
! 139: struct pcmcia_config_entry *cfe;
! 140: struct rln_pcmcia_product *rpp;
! 141: const char *intrstr;
! 142:
! 143: psc->psc_pf = pa->pf;
! 144: cfe = SIMPLEQ_FIRST(&psc->psc_pf->cfe_head);
! 145:
! 146: /* Guess the transfer width we will be using */
! 147: if (cfe->flags & PCMCIA_CFE_IO16)
! 148: sc->sc_width = 16;
! 149: else if (cfe->flags & PCMCIA_CFE_IO8)
! 150: sc->sc_width = 8;
! 151: else
! 152: sc->sc_width = 0;
! 153:
! 154: #ifdef DIAGNOSTIC
! 155: /* We only expect one i/o region and no memory region */
! 156: if (cfe->num_memspace != 0)
! 157: printf(": unexpected number of memory spaces (%d)\n",
! 158: cfe->num_memspace);
! 159: if (cfe->num_iospace != 1)
! 160: printf(": unexpected number of i/o spaces (%d)\n",
! 161: cfe->num_iospace);
! 162: else if (cfe->iospace[0].length != RLN_NPORTS)
! 163: printf(": unexpected size of i/o space (0x%x)\n",
! 164: cfe->iospace[0].length);
! 165: if (sc->sc_width == 0)
! 166: printf(": unknown bus width\n");
! 167: #endif /* DIAGNOSTIC */
! 168:
! 169: pcmcia_function_init(psc->psc_pf, cfe);
! 170:
! 171: /* Allocate i/o space */
! 172: if (pcmcia_io_alloc(psc->psc_pf, 0, RLN_NPORTS,
! 173: RLN_NPORTS, &psc->psc_pcioh)) {
! 174: printf(": can't allocate i/o space\n");
! 175: return;
! 176: }
! 177:
! 178: sc->sc_iot = psc->psc_pcioh.iot;
! 179: sc->sc_ioh = psc->psc_pcioh.ioh;
! 180:
! 181: /* Map i/o space */
! 182: if (pcmcia_io_map(psc->psc_pf, ((sc->sc_width == 8) ? PCMCIA_WIDTH_IO8 :
! 183: (sc->sc_width == 16) ? PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO),
! 184: 0, RLN_NPORTS, &psc->psc_pcioh, &psc->sc_io_window)) {
! 185: printf(": can't map i/o space\n");
! 186: return;
! 187: }
! 188: printf(" port 0x%lx/%d", psc->psc_pcioh.addr, RLN_NPORTS);
! 189:
! 190: /* Enable the card */
! 191: if (pcmcia_function_enable(psc->psc_pf)) {
! 192: printf(": function enable failed\n");
! 193: return;
! 194: }
! 195:
! 196: #ifdef notyet
! 197: sc->enable = rln_pcmcia_enable;
! 198: sc->disable = rln_pcmcia_disable;
! 199: #endif
! 200:
! 201: rpp = rln_pcmcia_product_lookup(pa);
! 202:
! 203: /* Check if the device has a separate antenna module */
! 204: sc->sc_cardtype = 0;
! 205: switch (psc->psc_pf->ccr_base) {
! 206: case 0x0100:
! 207: sc->sc_cardtype |= RLN_CTYPE_ONE_PIECE;
! 208: break;
! 209: case 0x0800:
! 210: sc->sc_cardtype &= ~RLN_CTYPE_ONE_PIECE;
! 211: break;
! 212: #ifdef DIAGNOSTIC
! 213: default:
! 214: printf(": cannot tell if one or two piece (ccr addr %x)\n",
! 215: sc->sc_dev.dv_xname, psc->psc_pf->ccr_base);
! 216: #endif
! 217: }
! 218:
! 219: /* The PC-card needs to be told to use 'irq' 15 */
! 220: sc->sc_irq = 15;
! 221:
! 222: /*
! 223: * We need to get an interrupt before configuring, since
! 224: * polling registers (the alternative) to reading card
! 225: * responses, causes hard lock-ups.
! 226: */
! 227: psc->psc_ih = pcmcia_intr_establish(psc->psc_pf, IPL_NET,
! 228: rlnintr_pcmcia, sc, sc->sc_dev.dv_xname);
! 229: intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
! 230: if (*intrstr)
! 231: printf(", %s", intrstr);
! 232: sc->sc_ih = NULL;
! 233:
! 234: #ifdef DIAGNOSTIC
! 235: if (rpp->manufacturer == PCMCIA_VENDOR_INVALID)
! 236: printf(" manf %04x prod %04x", pa->manufacturer, pa->product);
! 237: #endif
! 238:
! 239: rln_reset(sc);
! 240: rlnconfig(sc);
! 241: printf("\n");
! 242: }
! 243:
! 244: static int
! 245: rln_pcmcia_detach(dev, flags)
! 246: struct device *dev;
! 247: int flags;
! 248: {
! 249: struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *)dev;
! 250: struct rln_softc *sc = (struct rln_softc *)dev;
! 251: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 252: int rv = 0;
! 253:
! 254: pcmcia_io_unmap(psc->psc_pf, psc->sc_io_window);
! 255: pcmcia_io_free(psc->psc_pf, &psc->psc_pcioh);
! 256:
! 257: ether_ifdetach(ifp);
! 258: if_detach(ifp);
! 259:
! 260: return (rv);
! 261: }
! 262:
! 263: static int
! 264: rln_pcmcia_activate(dev, act)
! 265: struct device *dev;
! 266: enum devact act;
! 267: {
! 268: struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *)dev;
! 269: struct rln_softc *sc = (struct rln_softc *)dev;
! 270: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 271: int s;
! 272:
! 273: s = splnet();
! 274: switch (act) {
! 275: case DVACT_ACTIVATE:
! 276: pcmcia_function_enable(psc->psc_pf);
! 277: psc->psc_ih = pcmcia_intr_establish(psc->psc_pf, IPL_NET,
! 278: rlnintr_pcmcia, psc, sc->sc_dev.dv_xname);
! 279: rlninit(sc);
! 280: break;
! 281:
! 282: case DVACT_DEACTIVATE:
! 283: ifp->if_timer = 0;
! 284: if (ifp->if_flags & IFF_RUNNING)
! 285: rlnstop(sc);
! 286: pcmcia_intr_disestablish(psc->psc_pf, psc->psc_ih);
! 287: pcmcia_function_disable(psc->psc_pf);
! 288: break;
! 289: }
! 290: splx(s);
! 291: return (0);
! 292: }
! 293:
! 294: /* Interrupt handler */
! 295: static int
! 296: rlnintr_pcmcia(arg)
! 297: void *arg;
! 298: {
! 299: struct rln_softc *sc = (struct rln_softc *)arg;
! 300: struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *)sc;
! 301: int opt;
! 302: int ret;
! 303:
! 304: /* Need to immediately read/write the option register for PC-card */
! 305: opt = pcmcia_ccr_read(psc->psc_pf, PCMCIA_CCR_OPTION);
! 306: pcmcia_ccr_write(psc->psc_pf, PCMCIA_CCR_OPTION, opt);
! 307:
! 308: /* Call actual interrupt handler */
! 309: ret = rlnintr(sc);
! 310:
! 311: return (ret);
! 312: }
CVSweb