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