root/dev/cardbus/com_cardbus.c

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

DEFINITIONS

This source file includes following definitions.
  1. com_cardbus_find_csdev
  2. com_cardbus_match
  3. com_cardbus_gofigure
  4. com_cardbus_attach
  5. com_cardbus_setup
  6. com_cardbus_enable
  7. com_cardbus_disable
  8. com_cardbus_detach

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

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