Home | History | Annotate | Line # | Download | only in cardbus
com_cardbus.c revision 1.28.2.1
      1  1.28.2.1    rmind /* $NetBSD: com_cardbus.c,v 1.28.2.1 2010/05/30 05:17:19 rmind Exp $ */
      2       1.1     joda 
      3       1.1     joda /*
      4       1.1     joda  * Copyright (c) 2000 Johan Danielsson
      5       1.1     joda  * All rights reserved.
      6       1.1     joda  *
      7      1.14    perry  * Redistribution and use in source and binary forms, with or without
      8      1.14    perry  * modification, are permitted provided that the following conditions
      9      1.14    perry  * are met:
     10       1.1     joda  *
     11      1.14    perry  * 1. Redistributions of source code must retain the above copyright
     12      1.14    perry  *    notice, this list of conditions and the following disclaimer.
     13       1.1     joda  *
     14      1.14    perry  * 2. Redistributions in binary form must reproduce the above copyright
     15      1.14    perry  *    notice, this list of conditions and the following disclaimer in the
     16      1.14    perry  *    documentation and/or other materials provided with the distribution.
     17       1.1     joda  *
     18       1.1     joda  * 3. Neither the name of author nor the names of any contributors may
     19       1.1     joda  *    be used to endorse or promote products derived from this
     20       1.1     joda  *    software without specific prior written permission.
     21       1.1     joda  *
     22       1.1     joda  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     23       1.1     joda  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24       1.1     joda  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     25       1.1     joda  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
     26       1.1     joda  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     27       1.1     joda  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     28       1.1     joda  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     29       1.1     joda  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     30       1.1     joda  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     31       1.1     joda  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     32       1.1     joda  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33       1.1     joda  */
     34       1.1     joda 
     35      1.14    perry /* A driver for CardBus based serial devices.
     36       1.1     joda 
     37       1.1     joda    If the CardBus device only has one BAR (that is not also the CIS
     38       1.1     joda    BAR) listed in the CIS, it is assumed to be the one to use. For
     39       1.5     joda    devices with more than one BAR, the list of known devices has to be
     40       1.1     joda    updated below.  */
     41       1.6    lukem 
     42       1.6    lukem #include <sys/cdefs.h>
     43  1.28.2.1    rmind __KERNEL_RCSID(0, "$NetBSD: com_cardbus.c,v 1.28.2.1 2010/05/30 05:17:19 rmind Exp $");
     44       1.1     joda 
     45       1.1     joda #include <sys/param.h>
     46       1.1     joda #include <sys/systm.h>
     47       1.1     joda #include <sys/tty.h>
     48       1.1     joda #include <sys/device.h>
     49       1.1     joda 
     50       1.1     joda #include <dev/cardbus/cardbusvar.h>
     51      1.13  mycroft #include <dev/pci/pcidevs.h>
     52       1.1     joda 
     53       1.4     joda #include <dev/pcmcia/pcmciareg.h>
     54       1.4     joda 
     55       1.1     joda #include <dev/ic/comreg.h>
     56       1.1     joda #include <dev/ic/comvar.h>
     57       1.1     joda 
     58       1.1     joda struct com_cardbus_softc {
     59       1.1     joda 	struct com_softc	cc_com;
     60      1.26   dyoung 	cardbus_intr_line_t	cc_intrline;
     61       1.1     joda 	void			*cc_ih;
     62       1.1     joda 	cardbus_devfunc_t	cc_ct;
     63       1.1     joda 	bus_addr_t		cc_addr;
     64      1.24   dyoung 	pcireg_t		cc_base;
     65       1.1     joda 	bus_size_t		cc_size;
     66      1.24   dyoung 	pcireg_t		cc_csr;
     67      1.24   dyoung 	pcitag_t		cc_tag;
     68      1.24   dyoung 	pcireg_t		cc_reg;
     69       1.1     joda 	int			cc_type;
     70       1.1     joda };
     71       1.1     joda 
     72      1.21     cube #define DEVICET(CSC) ((CSC)->cc_com.sc_dev)
     73       1.1     joda 
     74      1.21     cube static int com_cardbus_match (device_t, cfdata_t, void*);
     75      1.21     cube static void com_cardbus_attach (device_t, device_t, void*);
     76      1.21     cube static int com_cardbus_detach (device_t, int);
     77       1.1     joda 
     78       1.1     joda static void com_cardbus_setup(struct com_cardbus_softc*);
     79       1.1     joda static int com_cardbus_enable (struct com_softc*);
     80      1.11   itojun static void com_cardbus_disable(struct com_softc*);
     81       1.1     joda 
     82      1.21     cube CFATTACH_DECL_NEW(com_cardbus, sizeof(struct com_cardbus_softc),
     83      1.23   dyoung     com_cardbus_match, com_cardbus_attach, com_cardbus_detach, NULL);
     84       1.1     joda 
     85       1.1     joda static struct csdev {
     86       1.1     joda 	int		vendor;
     87       1.1     joda 	int		product;
     88      1.24   dyoung 	pcireg_t	reg;
     89       1.1     joda 	int		type;
     90       1.1     joda } csdevs[] = {
     91      1.13  mycroft 	{ PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
     92      1.28   dyoung 	  PCI_BAR0, PCI_MAPREG_TYPE_IO },
     93      1.13  mycroft 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
     94      1.28   dyoung 	  PCI_BAR0, PCI_MAPREG_TYPE_IO },
     95      1.13  mycroft 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656_M,
     96      1.28   dyoung 	  PCI_BAR0, PCI_MAPREG_TYPE_IO },
     97      1.13  mycroft 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656B_M,
     98      1.28   dyoung 	  PCI_BAR0, PCI_MAPREG_TYPE_IO },
     99      1.13  mycroft 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656C_M,
    100      1.28   dyoung 	  PCI_BAR0, PCI_MAPREG_TYPE_IO },
    101       1.1     joda };
    102       1.1     joda 
    103       1.1     joda static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
    104       1.1     joda 
    105       1.1     joda static struct csdev*
    106       1.1     joda find_csdev(struct cardbus_attach_args *ca)
    107       1.1     joda {
    108       1.1     joda 	struct csdev *cp;
    109       1.1     joda 
    110       1.1     joda 	for(cp = csdevs; cp < csdevs + ncsdevs; cp++)
    111      1.28   dyoung 		if(cp->vendor == PCI_VENDOR(ca->ca_id) &&
    112      1.28   dyoung 		   cp->product == PCI_PRODUCT(ca->ca_id))
    113       1.1     joda 			return cp;
    114       1.1     joda 	return NULL;
    115       1.1     joda }
    116       1.1     joda 
    117       1.1     joda static int
    118      1.21     cube com_cardbus_match(device_t parent, cfdata_t match, void *aux)
    119       1.1     joda {
    120       1.1     joda 	struct cardbus_attach_args *ca = aux;
    121       1.1     joda 
    122       1.4     joda 	/* known devices are ok */
    123       1.4     joda 	if(find_csdev(ca) != NULL)
    124       1.4     joda 	    return 10;
    125       1.4     joda 
    126       1.4     joda 	/* as are serial devices with a known UART */
    127       1.4     joda 	if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
    128       1.4     joda 	   ca->ca_cis.funce.serial.uart_present != 0 &&
    129       1.4     joda 	   (ca->ca_cis.funce.serial.uart_type == 0 ||	/* 8250 */
    130       1.4     joda 	    ca->ca_cis.funce.serial.uart_type == 1 ||	/* 16450 */
    131       1.4     joda 	    ca->ca_cis.funce.serial.uart_type == 2))	/* 16550 */
    132       1.4     joda 	    return 1;
    133       1.4     joda 
    134       1.1     joda 	return 0;
    135       1.1     joda }
    136       1.1     joda 
    137       1.1     joda static int
    138       1.1     joda gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc)
    139       1.1     joda {
    140       1.1     joda 	int i, index = -1;
    141      1.24   dyoung 	pcireg_t cis_ptr;
    142       1.1     joda 	struct csdev *cp;
    143       1.1     joda 
    144       1.1     joda 	/* If this device is listed above, use the known values, */
    145       1.1     joda 	cp = find_csdev(ca);
    146       1.1     joda 	if(cp != NULL) {
    147       1.1     joda 		csc->cc_reg = cp->reg;
    148       1.1     joda 		csc->cc_type = cp->type;
    149       1.1     joda 		return 0;
    150       1.1     joda 	}
    151       1.1     joda 
    152       1.1     joda 	cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
    153       1.1     joda 
    154       1.1     joda 	/* otherwise try to deduce which BAR and type to use from CIS.  If
    155       1.1     joda 	   there is only one BAR, it must be the one we should use, if
    156       1.1     joda 	   there are more, we're out of luck.  */
    157       1.1     joda 	for(i = 0; i < 7; i++) {
    158       1.1     joda 		/* ignore zero sized BARs */
    159       1.1     joda 		if(ca->ca_cis.bar[i].size == 0)
    160       1.1     joda 			continue;
    161       1.1     joda 		/* ignore the CIS BAR */
    162      1.14    perry 		if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
    163       1.1     joda 		   CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
    164       1.1     joda 			continue;
    165       1.1     joda 		if(index != -1)
    166       1.1     joda 			goto multi_bar;
    167       1.1     joda 		index = i;
    168       1.1     joda 	}
    169       1.1     joda 	if(index == -1) {
    170      1.21     cube 		aprint_error(": couldn't find any base address tuple\n");
    171       1.1     joda 		return 1;
    172       1.1     joda 	}
    173       1.1     joda 	csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
    174       1.1     joda 	if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
    175      1.28   dyoung 		csc->cc_type = PCI_MAPREG_TYPE_MEM;
    176       1.1     joda 	else
    177      1.28   dyoung 		csc->cc_type = PCI_MAPREG_TYPE_IO;
    178       1.1     joda 	return 0;
    179       1.1     joda 
    180       1.1     joda   multi_bar:
    181      1.21     cube 	aprint_error(": there are more than one possible base\n");
    182      1.14    perry 
    183      1.21     cube 	aprint_error_dev(DEVICET(csc), "address for this device, "
    184      1.21     cube 	       "please report the following information\n");
    185      1.21     cube 	aprint_error_dev(DEVICET(csc), "vendor 0x%x product 0x%x\n",
    186      1.28   dyoung 	       PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
    187       1.1     joda 	for(i = 0; i < 7; i++) {
    188       1.1     joda 		/* ignore zero sized BARs */
    189       1.1     joda 		if(ca->ca_cis.bar[i].size == 0)
    190       1.1     joda 			continue;
    191       1.1     joda 		/* ignore the CIS BAR */
    192      1.14    perry 		if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
    193       1.1     joda 		   CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
    194       1.1     joda 			continue;
    195      1.21     cube 		aprint_error_dev(DEVICET(csc),
    196      1.21     cube 		       "base address %x type %s size %x\n",
    197      1.14    perry 		       CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
    198       1.1     joda 		       (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
    199       1.1     joda 		       ca->ca_cis.bar[i].size);
    200       1.1     joda 	}
    201       1.1     joda 	return 1;
    202       1.1     joda }
    203       1.1     joda 
    204       1.1     joda static void
    205      1.21     cube com_cardbus_attach (device_t parent, device_t self, void *aux)
    206       1.1     joda {
    207      1.17  thorpej 	struct com_softc *sc = device_private(self);
    208      1.17  thorpej 	struct com_cardbus_softc *csc = device_private(self);
    209       1.1     joda 	struct cardbus_attach_args *ca = aux;
    210      1.18  gdamore 	bus_space_handle_t	ioh;
    211      1.18  gdamore 	bus_space_tag_t		iot;
    212       1.1     joda 
    213      1.21     cube 	sc->sc_dev = self;
    214      1.26   dyoung 	csc->cc_intrline = ca->ca_intrline;
    215       1.1     joda 	csc->cc_ct = ca->ca_ct;
    216      1.25   dyoung 	csc->cc_tag = ca->ca_tag;
    217       1.1     joda 
    218       1.1     joda 	if(gofigure(ca, csc) != 0)
    219       1.1     joda 		return;
    220      1.14    perry 
    221      1.14    perry 	if(Cardbus_mapreg_map(ca->ca_ct,
    222       1.1     joda 			      csc->cc_reg,
    223      1.14    perry 			      csc->cc_type,
    224      1.14    perry 			      0,
    225      1.18  gdamore 			      &iot,
    226      1.18  gdamore 			      &ioh,
    227      1.14    perry 			      &csc->cc_addr,
    228       1.1     joda 			      &csc->cc_size) != 0) {
    229      1.21     cube 		aprint_error("failed to map memory");
    230       1.1     joda 		return;
    231       1.1     joda 	}
    232       1.1     joda 
    233      1.18  gdamore 	COM_INIT_REGS(sc->sc_regs, iot, ioh, csc->cc_addr);
    234      1.18  gdamore 
    235       1.1     joda 	csc->cc_base = csc->cc_addr;
    236      1.28   dyoung 	csc->cc_csr = PCI_COMMAND_MASTER_ENABLE;
    237      1.28   dyoung 	if(csc->cc_type == PCI_MAPREG_TYPE_IO) {
    238      1.28   dyoung 		csc->cc_base |= PCI_MAPREG_TYPE_IO;
    239      1.28   dyoung 		csc->cc_csr |= PCI_COMMAND_IO_ENABLE;
    240       1.1     joda 	} else {
    241      1.28   dyoung 		csc->cc_csr |= PCI_COMMAND_MEM_ENABLE;
    242       1.1     joda 	}
    243       1.1     joda 
    244       1.1     joda 	sc->sc_frequency = COM_FREQ;
    245       1.1     joda 
    246       1.1     joda 	sc->enable = com_cardbus_enable;
    247       1.1     joda 	sc->disable = com_cardbus_disable;
    248       1.1     joda 	sc->enabled = 0;
    249       1.1     joda 
    250       1.1     joda 	if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
    251      1.21     cube 		aprint_normal(": %s %s\n", ca->ca_cis.cis1_info[0],
    252       1.1     joda 		    ca->ca_cis.cis1_info[1]);
    253      1.21     cube 		aprint_normal("%s", device_xname(DEVICET(csc)));
    254       1.1     joda 	}
    255       1.1     joda 
    256       1.1     joda 	com_cardbus_setup(csc);
    257      1.14    perry 
    258       1.1     joda 	com_attach_subr(sc);
    259       1.2     joda 
    260       1.2     joda 	Cardbus_function_disable(csc->cc_ct);
    261       1.1     joda }
    262       1.1     joda 
    263       1.1     joda static void
    264       1.1     joda com_cardbus_setup(struct com_cardbus_softc *csc)
    265       1.1     joda {
    266       1.1     joda         cardbus_devfunc_t ct = csc->cc_ct;
    267      1.24   dyoung 	pcireg_t reg;
    268       1.1     joda 
    269       1.1     joda 	Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base);
    270       1.1     joda 
    271       1.1     joda 	/* and the card itself */
    272      1.28   dyoung 	reg = Cardbus_conf_read(ct, csc->cc_tag, PCI_COMMAND_STATUS_REG);
    273      1.28   dyoung 	reg &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
    274       1.1     joda 	reg |= csc->cc_csr;
    275      1.28   dyoung 	Cardbus_conf_write(ct, csc->cc_tag, PCI_COMMAND_STATUS_REG, reg);
    276       1.1     joda 
    277       1.1     joda         /*
    278       1.1     joda          * Make sure the latency timer is set to some reasonable
    279       1.1     joda          * value.
    280       1.1     joda          */
    281      1.28   dyoung         reg = Cardbus_conf_read(ct, csc->cc_tag, PCI_BHLC_REG);
    282      1.28   dyoung         if (PCI_LATTIMER(reg) < 0x20) {
    283      1.28   dyoung                 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
    284      1.28   dyoung                 reg |= (0x20 << PCI_LATTIMER_SHIFT);
    285      1.28   dyoung                 Cardbus_conf_write(ct, csc->cc_tag, PCI_BHLC_REG, reg);
    286       1.1     joda         }
    287       1.1     joda }
    288       1.1     joda 
    289       1.1     joda static int
    290       1.1     joda com_cardbus_enable(struct com_softc *sc)
    291       1.1     joda {
    292       1.1     joda 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
    293      1.26   dyoung 	cardbus_devfunc_t ct = csc->cc_ct;
    294       1.1     joda 
    295      1.26   dyoung 	Cardbus_function_enable(ct);
    296       1.1     joda 
    297       1.1     joda 	com_cardbus_setup(csc);
    298       1.1     joda 
    299       1.1     joda 	/* establish the interrupt. */
    300  1.28.2.1    rmind 	csc->cc_ih = Cardbus_intr_establish(ct, csc->cc_intrline,
    301       1.1     joda 					    IPL_SERIAL, comintr, sc);
    302       1.1     joda 	if (csc->cc_ih == NULL) {
    303      1.21     cube 		aprint_error_dev(DEVICET(csc),
    304      1.21     cube 		    "couldn't establish interrupt\n");
    305       1.1     joda 		return 1;
    306       1.1     joda 	}
    307       1.1     joda 
    308       1.1     joda 	return 0;
    309       1.1     joda }
    310       1.1     joda 
    311       1.1     joda static void
    312       1.1     joda com_cardbus_disable(struct com_softc *sc)
    313      1.14    perry {
    314       1.1     joda 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
    315      1.26   dyoung 	cardbus_devfunc_t ct = csc->cc_ct;
    316       1.1     joda 
    317  1.28.2.1    rmind 	Cardbus_intr_disestablish(ct, csc->cc_ih);
    318      1.10  kanaoka 	csc->cc_ih = NULL;
    319      1.10  kanaoka 
    320      1.26   dyoung 	Cardbus_function_disable(ct);
    321       1.1     joda }
    322       1.1     joda 
    323       1.1     joda static int
    324      1.21     cube com_cardbus_detach(device_t self, int flags)
    325       1.1     joda {
    326      1.17  thorpej 	struct com_cardbus_softc *csc = device_private(self);
    327      1.17  thorpej 	struct com_softc *sc = device_private(self);
    328      1.26   dyoung 	cardbus_devfunc_t ct = csc->cc_ct;
    329       1.1     joda 	int error;
    330       1.1     joda 
    331       1.1     joda 	if ((error = com_detach(self, flags)) != 0)
    332       1.1     joda 		return error;
    333       1.1     joda 
    334      1.10  kanaoka 	if (csc->cc_ih != NULL)
    335  1.28.2.1    rmind 		Cardbus_intr_disestablish(ct, csc->cc_ih);
    336      1.14    perry 
    337      1.18  gdamore 	Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_regs.cr_iot,
    338      1.18  gdamore 	    sc->sc_regs.cr_ioh, csc->cc_size);
    339       1.1     joda 
    340       1.1     joda 	return 0;
    341       1.1     joda }
    342