root/dev/pcmcia/if_rln_pcmcia.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rln_pcmcia_product_lookup
  2. rln_pcmcia_match
  3. rln_pcmcia_attach
  4. rln_pcmcia_detach
  5. rln_pcmcia_activate
  6. rlnintr_pcmcia

    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 }

/* [<][>][^][v][top][bottom][index][help] */