Home | History | Annotate | Line # | Download | only in pcmcia
if_sm_pcmcia.c revision 1.23.2.1
      1  1.23.2.1   nathanw /*	$NetBSD: if_sm_pcmcia.c,v 1.23.2.1 2001/08/24 00:10:28 nathanw Exp $	*/
      2       1.2   thorpej 
      3       1.2   thorpej /*-
      4      1.20       cgd  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
      5       1.2   thorpej  * All rights reserved.
      6       1.2   thorpej  *
      7       1.2   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8       1.2   thorpej  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9       1.2   thorpej  * NASA Ames Research Center.
     10       1.2   thorpej  *
     11       1.2   thorpej  * Redistribution and use in source and binary forms, with or without
     12       1.2   thorpej  * modification, are permitted provided that the following conditions
     13       1.2   thorpej  * are met:
     14       1.2   thorpej  * 1. Redistributions of source code must retain the above copyright
     15       1.2   thorpej  *    notice, this list of conditions and the following disclaimer.
     16       1.2   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     17       1.2   thorpej  *    notice, this list of conditions and the following disclaimer in the
     18       1.2   thorpej  *    documentation and/or other materials provided with the distribution.
     19       1.2   thorpej  * 3. All advertising materials mentioning features or use of this software
     20       1.2   thorpej  *    must display the following acknowledgement:
     21       1.2   thorpej  *	This product includes software developed by the NetBSD
     22       1.2   thorpej  *	Foundation, Inc. and its contributors.
     23       1.2   thorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24       1.2   thorpej  *    contributors may be used to endorse or promote products derived
     25       1.2   thorpej  *    from this software without specific prior written permission.
     26       1.2   thorpej  *
     27       1.2   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28       1.2   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29       1.2   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30       1.2   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31       1.2   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32       1.2   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33       1.2   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34       1.2   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35       1.2   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36       1.2   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37       1.2   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     38       1.2   thorpej  */
     39       1.2   thorpej 
     40       1.2   thorpej #include <sys/param.h>
     41       1.2   thorpej #include <sys/systm.h>
     42       1.2   thorpej #include <sys/mbuf.h>
     43       1.2   thorpej #include <sys/socket.h>
     44       1.2   thorpej #include <sys/ioctl.h>
     45       1.2   thorpej #include <sys/errno.h>
     46       1.2   thorpej #include <sys/syslog.h>
     47       1.2   thorpej #include <sys/select.h>
     48       1.2   thorpej #include <sys/device.h>
     49       1.2   thorpej 
     50       1.2   thorpej #include <net/if.h>
     51       1.2   thorpej #include <net/if_dl.h>
     52       1.2   thorpej #include <net/if_ether.h>
     53       1.2   thorpej #include <net/if_media.h>
     54       1.2   thorpej 
     55       1.2   thorpej #include <machine/intr.h>
     56       1.2   thorpej #include <machine/bus.h>
     57      1.23    briggs 
     58      1.23    briggs #include <dev/mii/mii.h>
     59      1.23    briggs #include <dev/mii/miivar.h>
     60       1.2   thorpej 
     61       1.2   thorpej #include <dev/ic/smc91cxxreg.h>
     62       1.2   thorpej #include <dev/ic/smc91cxxvar.h>
     63       1.2   thorpej 
     64       1.2   thorpej #include <dev/pcmcia/pcmciareg.h>
     65       1.2   thorpej #include <dev/pcmcia/pcmciavar.h>
     66       1.6  christos #include <dev/pcmcia/pcmciadevs.h>
     67       1.2   thorpej 
     68       1.2   thorpej int	sm_pcmcia_match __P((struct device *, struct cfdata *, void *));
     69       1.2   thorpej void	sm_pcmcia_attach __P((struct device *, struct device *, void *));
     70      1.13   thorpej int	sm_pcmcia_detach __P((struct device *, int));
     71       1.2   thorpej 
     72       1.2   thorpej struct sm_pcmcia_softc {
     73       1.2   thorpej 	struct	smc91cxx_softc sc_smc;		/* real "smc" softc */
     74       1.2   thorpej 
     75       1.2   thorpej 	/* PCMCIA-specific goo. */
     76       1.2   thorpej 	struct	pcmcia_io_handle sc_pcioh;	/* PCMCIA i/o space info */
     77       1.2   thorpej 	int	sc_io_window;			/* our i/o window */
     78       1.2   thorpej 	void	*sc_ih;				/* interrupt cookie */
     79       1.2   thorpej 	struct	pcmcia_function *sc_pf;		/* our PCMCIA function */
     80       1.2   thorpej };
     81       1.2   thorpej 
     82       1.2   thorpej struct cfattach sm_pcmcia_ca = {
     83      1.13   thorpej 	sizeof(struct sm_pcmcia_softc), sm_pcmcia_match, sm_pcmcia_attach,
     84      1.15   thorpej 	    sm_pcmcia_detach, smc91cxx_activate
     85       1.2   thorpej };
     86       1.2   thorpej 
     87       1.2   thorpej int	sm_pcmcia_enable __P((struct smc91cxx_softc *));
     88       1.2   thorpej void	sm_pcmcia_disable __P((struct smc91cxx_softc *));
     89       1.2   thorpej 
     90      1.10   thorpej int	sm_pcmcia_ascii_enaddr __P((const char *, u_int8_t *));
     91      1.10   thorpej int	sm_pcmcia_funce_enaddr __P((struct device *, u_int8_t *));
     92       1.7   thorpej 
     93      1.10   thorpej int	sm_pcmcia_lannid_ciscallback __P((struct pcmcia_tuple *, void *));
     94       1.7   thorpej 
     95      1.20       cgd const struct pcmcia_product sm_pcmcia_products[] = {
     96      1.20       cgd 	{ PCMCIA_STR_MEGAHERTZ2_XJACK,		PCMCIA_VENDOR_MEGAHERTZ2,
     97      1.20       cgd 	  PCMCIA_PRODUCT_MEGAHERTZ2_XJACK,	 0, },
     98      1.16       abs 
     99      1.20       cgd 	{ PCMCIA_STR_NEWMEDIA_BASICS,		PCMCIA_VENDOR_NEWMEDIA,
    100      1.20       cgd 	  PCMCIA_PRODUCT_NEWMEDIA_BASICS,	0, },
    101      1.10   thorpej 
    102      1.11   thorpej #if 0
    103      1.20       cgd 	{ PCMCIA_STR_SMC_8020BT,		PCMCIA_VENDOR_SMC,
    104      1.20       cgd 	  PCMCIA_PRODUCT_SMC_8020BT,		0, },
    105      1.11   thorpej #endif
    106       1.7   thorpej 
    107      1.20       cgd 	{ NULL }
    108       1.7   thorpej };
    109       1.7   thorpej 
    110       1.2   thorpej int
    111       1.2   thorpej sm_pcmcia_match(parent, match, aux)
    112       1.2   thorpej 	struct device *parent;
    113       1.2   thorpej 	struct cfdata *match;
    114       1.2   thorpej 	void *aux;
    115       1.2   thorpej {
    116       1.2   thorpej 	struct pcmcia_attach_args *pa = aux;
    117       1.2   thorpej 
    118      1.20       cgd 	if (pcmcia_product_lookup(pa, sm_pcmcia_products,
    119      1.20       cgd 	    sizeof sm_pcmcia_products[0], NULL) != NULL)
    120       1.7   thorpej 		return (1);
    121       1.2   thorpej 	return (0);
    122       1.2   thorpej }
    123       1.2   thorpej 
    124       1.2   thorpej void
    125       1.2   thorpej sm_pcmcia_attach(parent, self, aux)
    126       1.2   thorpej 	struct device *parent, *self;
    127       1.2   thorpej 	void *aux;
    128       1.2   thorpej {
    129       1.2   thorpej 	struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)self;
    130       1.2   thorpej 	struct smc91cxx_softc *sc = &psc->sc_smc;
    131       1.2   thorpej 	struct pcmcia_attach_args *pa = aux;
    132       1.2   thorpej 	struct pcmcia_config_entry *cfe;
    133       1.2   thorpej 	u_int8_t myla[ETHER_ADDR_LEN], *enaddr = NULL;
    134      1.20       cgd 	const struct pcmcia_product *pp;
    135       1.2   thorpej 
    136       1.2   thorpej 	psc->sc_pf = pa->pf;
    137       1.2   thorpej 	cfe = pa->pf->cfe_head.sqh_first;
    138       1.2   thorpej 
    139       1.2   thorpej 	/* Enable the card. */
    140       1.2   thorpej 	pcmcia_function_init(pa->pf, cfe);
    141       1.2   thorpej 	if (pcmcia_function_enable(pa->pf)) {
    142       1.2   thorpej 		printf(": function enable failed\n");
    143      1.21     enami 		goto enable_failed;
    144       1.2   thorpej 	}
    145       1.2   thorpej 
    146       1.2   thorpej 	/* XXX sanity check number of mem and i/o spaces */
    147       1.2   thorpej 
    148       1.2   thorpej 	/* Allocate and map i/o space for the card. */
    149       1.2   thorpej 	if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
    150       1.2   thorpej 	    cfe->iospace[0].length, &psc->sc_pcioh)) {
    151       1.2   thorpej 		printf(": can't allocate i/o space\n");
    152      1.21     enami 		goto ioalloc_failed;
    153       1.2   thorpej 	}
    154       1.2   thorpej 
    155       1.2   thorpej 	sc->sc_bst = psc->sc_pcioh.iot;
    156       1.2   thorpej 	sc->sc_bsh = psc->sc_pcioh.ioh;
    157       1.2   thorpej 
    158       1.2   thorpej 	sc->sc_enable = sm_pcmcia_enable;
    159       1.2   thorpej 	sc->sc_disable = sm_pcmcia_disable;
    160       1.2   thorpej 
    161       1.2   thorpej 	if (pcmcia_io_map(pa->pf, (cfe->flags & PCMCIA_CFE_IO16) ?
    162       1.2   thorpej 	    PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8, 0, cfe->iospace[0].length,
    163       1.2   thorpej 	    &psc->sc_pcioh, &psc->sc_io_window)) {
    164       1.2   thorpej 		printf(": can't map i/o space\n");
    165      1.21     enami 		goto iomap_failed;
    166       1.2   thorpej 	}
    167       1.2   thorpej 
    168      1.20       cgd 	pp = pcmcia_product_lookup(pa, sm_pcmcia_products,
    169      1.20       cgd 	    sizeof sm_pcmcia_products[0], NULL);
    170      1.20       cgd 	if (pp == NULL)
    171       1.7   thorpej 		panic("sm_pcmcia_attach: impossible");
    172       1.7   thorpej 
    173      1.20       cgd 	printf(": %s\n", pp->pp_name);
    174       1.7   thorpej 
    175      1.10   thorpej 	/*
    176      1.10   thorpej 	 * First try to get the Ethernet address from FUNCE/LANNID tuple.
    177      1.10   thorpej 	 */
    178      1.10   thorpej 	if (sm_pcmcia_funce_enaddr(parent, myla))
    179      1.10   thorpej 		enaddr = myla;
    180      1.10   thorpej 
    181      1.10   thorpej 	/*
    182      1.10   thorpej 	 * If that failed, try one of the CIS info strings.
    183      1.10   thorpej 	 */
    184      1.10   thorpej 	if (enaddr == NULL) {
    185      1.10   thorpej 		char *cisstr = NULL;
    186      1.10   thorpej 
    187      1.10   thorpej 		switch (pa->manufacturer) {
    188      1.16       abs 		case PCMCIA_VENDOR_MEGAHERTZ:
    189      1.10   thorpej 		case PCMCIA_VENDOR_MEGAHERTZ2:
    190      1.10   thorpej 			cisstr = pa->pf->sc->card.cis1_info[3];
    191      1.10   thorpej 			break;
    192      1.10   thorpej 
    193      1.10   thorpej 		case PCMCIA_VENDOR_SMC:
    194      1.10   thorpej 			cisstr = pa->pf->sc->card.cis1_info[2];
    195      1.10   thorpej 			break;
    196      1.10   thorpej 		}
    197      1.10   thorpej 
    198      1.10   thorpej 		if (cisstr != NULL && sm_pcmcia_ascii_enaddr(cisstr, myla))
    199      1.10   thorpej 			enaddr = myla;
    200      1.10   thorpej 	}
    201      1.10   thorpej 
    202      1.10   thorpej 	if (enaddr == NULL)
    203       1.7   thorpej 		printf("%s: unable to get Ethernet address\n",
    204       1.7   thorpej 		    sc->sc_dev.dv_xname);
    205       1.7   thorpej 
    206       1.7   thorpej 	/* Perform generic intialization. */
    207       1.7   thorpej 	smc91cxx_attach(sc, enaddr);
    208       1.7   thorpej 
    209       1.7   thorpej 	pcmcia_function_disable(pa->pf);
    210      1.21     enami 	return;
    211      1.21     enami 
    212      1.21     enami  iomap_failed:
    213      1.22     enami 	/* Free our i/o space. */
    214      1.22     enami 	pcmcia_io_free(pa->pf, &psc->sc_pcioh);
    215      1.22     enami 
    216      1.22     enami  ioalloc_failed:
    217      1.21     enami 	/* Disable the device */
    218      1.21     enami 	pcmcia_function_disable(pa->pf);
    219      1.21     enami 
    220      1.21     enami  enable_failed:
    221      1.21     enami 	psc->sc_io_window = -1;
    222      1.13   thorpej }
    223      1.13   thorpej 
    224      1.13   thorpej int
    225      1.13   thorpej sm_pcmcia_detach(self, flags)
    226      1.13   thorpej 	struct device *self;
    227      1.13   thorpej 	int flags;
    228      1.13   thorpej {
    229      1.14   thorpej 	struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)self;
    230      1.19    itojun 	int rv;
    231      1.14   thorpej 
    232      1.21     enami 	if (psc->sc_io_window == -1)
    233      1.21     enami 		/* Nothing to detach. */
    234      1.21     enami 		return (0);
    235      1.14   thorpej 
    236      1.19    itojun 	rv = smc91cxx_detach((struct device *)&psc->sc_smc, flags);
    237      1.21     enami 	if (rv != 0)
    238      1.21     enami 		return (rv);
    239      1.21     enami 
    240      1.21     enami 	/* Unmap our i/o window. */
    241      1.21     enami 	pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
    242      1.14   thorpej 
    243      1.21     enami 	/* Free our i/o space. */
    244      1.21     enami 	pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
    245      1.21     enami 	return (0);
    246       1.7   thorpej }
    247       1.7   thorpej 
    248       1.7   thorpej int
    249      1.10   thorpej sm_pcmcia_ascii_enaddr(cisstr, myla)
    250      1.10   thorpej 	const char *cisstr;
    251       1.7   thorpej 	u_int8_t *myla;
    252       1.7   thorpej {
    253      1.18   thorpej 	u_int8_t digit;
    254      1.18   thorpej 	int i;
    255       1.7   thorpej 
    256      1.18   thorpej 	memset(myla, 0, ETHER_ADDR_LEN);
    257      1.18   thorpej 
    258      1.18   thorpej 	for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) {
    259      1.18   thorpej 		if (cisstr[i] >= '0' && cisstr[i] <= '9')
    260      1.18   thorpej 			digit |= cisstr[i] - '0';
    261      1.18   thorpej 		else if (cisstr[i] >= 'a' && cisstr[i] <= 'f')
    262      1.18   thorpej 			digit |= (cisstr[i] - 'a') + 10;
    263      1.18   thorpej 		else if (cisstr[i] >= 'A' && cisstr[i] <= 'F')
    264      1.18   thorpej 			digit |= (cisstr[i] - 'A') + 10;
    265      1.18   thorpej 		else {
    266      1.18   thorpej 			/* Bogus digit!! */
    267      1.18   thorpej 			return (0);
    268       1.2   thorpej 		}
    269      1.18   thorpej 
    270      1.18   thorpej 		/* Compensate for ordering of digits. */
    271      1.18   thorpej 		if (i & 1) {
    272      1.18   thorpej 			myla[i >> 1] = digit;
    273      1.18   thorpej 			digit = 0;
    274      1.18   thorpej 		} else
    275      1.18   thorpej 			digit <<= 4;
    276       1.2   thorpej 	}
    277       1.2   thorpej 
    278       1.7   thorpej 	return (1);
    279       1.7   thorpej }
    280       1.7   thorpej 
    281       1.7   thorpej int
    282      1.10   thorpej sm_pcmcia_funce_enaddr(parent, myla)
    283       1.7   thorpej 	struct device *parent;
    284       1.7   thorpej 	u_int8_t *myla;
    285       1.7   thorpej {
    286       1.7   thorpej 
    287      1.10   thorpej 	return (pcmcia_scan_cis(parent, sm_pcmcia_lannid_ciscallback, myla));
    288       1.7   thorpej }
    289       1.7   thorpej 
    290       1.7   thorpej int
    291      1.10   thorpej sm_pcmcia_lannid_ciscallback(tuple, arg)
    292       1.7   thorpej 	struct pcmcia_tuple *tuple;
    293       1.7   thorpej 	void *arg;
    294       1.7   thorpej {
    295       1.7   thorpej 	u_int8_t *myla = arg;
    296       1.7   thorpej 	int i;
    297       1.2   thorpej 
    298       1.8   thorpej 	if (tuple->code == PCMCIA_CISTPL_FUNCE) {
    299       1.9   thorpej 		/* subcode, length */
    300       1.9   thorpej 		if (tuple->length < 2)
    301       1.7   thorpej 			return (0);
    302       1.9   thorpej 
    303      1.12   thorpej 		if ((pcmcia_tuple_read_1(tuple, 0) !=
    304      1.12   thorpej 		     PCMCIA_TPLFE_TYPE_LAN_NID) ||
    305      1.12   thorpej 		    (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN))
    306      1.12   thorpej 			return (0);
    307       1.9   thorpej 
    308       1.7   thorpej 		for (i = 0; i < ETHER_ADDR_LEN; i++)
    309       1.7   thorpej 			myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
    310       1.7   thorpej 		return (1);
    311       1.7   thorpej 	}
    312       1.7   thorpej 	return (0);
    313       1.2   thorpej }
    314       1.2   thorpej 
    315       1.2   thorpej int
    316       1.2   thorpej sm_pcmcia_enable(sc)
    317       1.2   thorpej 	struct smc91cxx_softc *sc;
    318       1.2   thorpej {
    319       1.2   thorpej 	struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
    320      1.19    itojun 	int rv;
    321      1.19    itojun 
    322       1.2   thorpej 	/* Establish the interrupt handler. */
    323       1.2   thorpej 	psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, smc91cxx_intr,
    324       1.2   thorpej 	    sc);
    325       1.2   thorpej 	if (psc->sc_ih == NULL) {
    326       1.2   thorpej 		printf("%s: couldn't establish interrupt handler\n",
    327       1.2   thorpej 		    sc->sc_dev.dv_xname);
    328       1.2   thorpej 		return (1);
    329       1.2   thorpej 	}
    330       1.2   thorpej 
    331      1.19    itojun 	rv = pcmcia_function_enable(psc->sc_pf);
    332      1.21     enami 	if (rv != 0)
    333      1.21     enami 		pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
    334      1.19    itojun 	return (rv);
    335       1.2   thorpej }
    336       1.2   thorpej 
    337       1.2   thorpej void
    338       1.2   thorpej sm_pcmcia_disable(sc)
    339       1.2   thorpej 	struct smc91cxx_softc *sc;
    340       1.2   thorpej {
    341       1.2   thorpej 	struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
    342       1.2   thorpej 
    343       1.2   thorpej 	pcmcia_function_disable(psc->sc_pf);
    344       1.2   thorpej 	pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
    345       1.2   thorpej }
    346