The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/cardbus/com_cardbus.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $OpenBSD: com_cardbus.c,v 1.44 2022/04/06 18:59:27 naddy 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 
   61 #include <dev/ic/comreg.h>
   62 #include <dev/ic/comvar.h>
   63 #include <dev/ic/ns16550reg.h>
   64 
   65 #define com_lcr         com_cfcr
   66 
   67 struct com_cardbus_softc {
   68         struct com_softc        cc_com;
   69         void                    *cc_ih;
   70         cardbus_devfunc_t       cc_ct;
   71         bus_addr_t              cc_addr;
   72         pcireg_t                cc_base;
   73         bus_size_t              cc_size;
   74         pcireg_t                cc_csr;
   75         int                     cc_cben;
   76         pcitag_t                cc_tag;
   77         pcireg_t                cc_reg;
   78         int                     cc_type;
   79         u_char                  cc_bug;
   80         pci_chipset_tag_t       cc_pc;
   81 };
   82 
   83 #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
   84 
   85 int     com_cardbus_match(struct device *, void *, void *);
   86 void    com_cardbus_attach(struct device *, struct device *, void *);
   87 int     com_cardbus_detach(struct device *, int);
   88 
   89 void    com_cardbus_setup(struct com_cardbus_softc *);
   90 int     com_cardbus_enable(struct com_softc *);
   91 void    com_cardbus_disable(struct com_softc *);
   92 struct csdev *com_cardbus_find_csdev(struct cardbus_attach_args *);
   93 int     com_cardbus_gofigure(struct cardbus_attach_args *,
   94     struct com_cardbus_softc *);
   95 
   96 const struct cfattach com_cardbus_ca = {
   97         sizeof(struct com_cardbus_softc), com_cardbus_match,
   98         com_cardbus_attach, com_cardbus_detach, com_activate
   99 };
  100 
  101 #define BUG_BROADCOM    0x01
  102 
  103 /* XXX Keep this list synchronized with the corresponding one in pucdata.c */
  104 static struct csdev {
  105         u_short         vendor;
  106         u_short         product;
  107         pcireg_t        reg;
  108         u_char          type;
  109         u_char          bug;
  110 } csdevs[] = {
  111         { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_GLOBALMODEM56,
  112           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  113         { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_MODEM56,
  114           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  115         { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL,
  116           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
  117         { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_2,
  118           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
  119         { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_GC,
  120           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  121         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
  122           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  123         { PCI_VENDOR_OXFORD2, PCI_PRODUCT_OXFORD2_OXCB950,
  124           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  125         { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_CBEM56G,
  126           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  127         { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
  128           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  129         { PCI_VENDOR_WCH, PCI_PRODUCT_WCH_CH352,
  130           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
  131         { PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9820,
  132           CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO }
  133 };
  134 
  135 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
  136 
  137 struct csdev*
  138 com_cardbus_find_csdev(struct cardbus_attach_args *ca)
  139 {
  140         struct csdev *cp;
  141 
  142         for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
  143                 if (cp->vendor == PCI_VENDOR(ca->ca_id) &&
  144                     cp->product == PCI_PRODUCT(ca->ca_id))
  145                         return (cp);
  146         return (NULL);
  147 }
  148 
  149 int
  150 com_cardbus_match(struct device *parent, void *match, void *aux)
  151 {
  152         struct cardbus_attach_args *ca = aux;
  153 
  154         /* known devices are ok */
  155         if (com_cardbus_find_csdev(ca) != NULL)
  156             return (10);
  157 
  158         /* as are serial devices with a known UART */
  159         if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
  160             ca->ca_cis.funce.serial.uart_present != 0 &&
  161             (ca->ca_cis.funce.serial.uart_type == 0 ||  /* 8250 */
  162             ca->ca_cis.funce.serial.uart_type == 1 ||   /* 16450 */
  163             ca->ca_cis.funce.serial.uart_type == 2))    /* 16550 */
  164                 return (1);
  165 
  166         return (0);
  167 }
  168 
  169 int
  170 com_cardbus_gofigure(struct cardbus_attach_args *ca,
  171     struct com_cardbus_softc *csc)
  172 {
  173         int i, index = -1;
  174         pcireg_t cis_ptr;
  175         struct csdev *cp;
  176 
  177         /* If this device is listed above, use the known values, */
  178         cp = com_cardbus_find_csdev(ca);
  179         if (cp != NULL) {
  180                 csc->cc_reg = cp->reg;
  181                 csc->cc_type = cp->type;
  182                 csc->cc_bug = cp->bug;
  183                 return (0);
  184         }
  185 
  186         cis_ptr = pci_conf_read(ca->ca_pc, csc->cc_tag, CARDBUS_CIS_REG);
  187 
  188         /* otherwise try to deduce which BAR and type to use from CIS.  If
  189            there is only one BAR, it must be the one we should use, if
  190            there are more, we're out of luck.  */
  191         for (i = 0; i < 7; i++) {
  192                 /* ignore zero sized BARs */
  193                 if (ca->ca_cis.bar[i].size == 0)
  194                         continue;
  195                 /* ignore the CIS BAR */
  196                 if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
  197                     CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
  198                         continue;
  199                 if (index != -1)
  200                         goto multi_bar;
  201                 index = i;
  202         }
  203         if (index == -1) {
  204                 printf(": couldn't find any base address tuple\n");
  205                 return (1);
  206         }
  207         csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
  208         if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
  209                 csc->cc_type = PCI_MAPREG_TYPE_MEM;
  210         else
  211                 csc->cc_type = PCI_MAPREG_TYPE_IO;
  212         return (0);
  213 
  214   multi_bar:
  215         printf(": there are more than one possible base\n");
  216 
  217         printf("%s: address for this device, "
  218             "please report the following information\n",
  219             DEVNAME(csc));
  220         printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
  221             PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
  222         for (i = 0; i < 7; i++) {
  223                 /* ignore zero sized BARs */
  224                 if (ca->ca_cis.bar[i].size == 0)
  225                         continue;
  226                 /* ignore the CIS BAR */
  227                 if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
  228                     CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
  229                         continue;
  230                 printf("%s: base address %x type %s size %x\n",
  231                     DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
  232                     (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
  233                     ca->ca_cis.bar[i].size);
  234         }
  235         return (1);
  236 }
  237 
  238 void
  239 com_cardbus_attach(struct device *parent, struct device *self, void *aux)
  240 {
  241         struct com_softc *sc = (struct com_softc*)self;
  242         struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
  243         struct cardbus_attach_args *ca = aux;
  244         cardbus_devfunc_t ct;
  245 
  246         csc->cc_ct = ct = ca->ca_ct;
  247         csc->cc_tag = pci_make_tag(ca->ca_pc, ct->ct_bus, ct->ct_dev, ct->ct_func);
  248         csc->cc_pc = ca->ca_pc;
  249 
  250         if (com_cardbus_gofigure(ca, csc) != 0)
  251                 return;
  252 
  253         if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
  254             &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
  255                 printf(": can't map memory\n");
  256                 return;
  257         }
  258 
  259         csc->cc_base = csc->cc_addr;
  260         csc->cc_csr = PCI_COMMAND_MASTER_ENABLE;
  261         if (csc->cc_type == PCI_MAPREG_TYPE_IO) {
  262                 csc->cc_base |= PCI_MAPREG_TYPE_IO;
  263                 csc->cc_csr |= PCI_COMMAND_IO_ENABLE;
  264                 csc->cc_cben = CARDBUS_IO_ENABLE;
  265         } else {
  266                 csc->cc_csr |= PCI_COMMAND_MEM_ENABLE;
  267                 csc->cc_cben = CARDBUS_MEM_ENABLE;
  268         }
  269 
  270         sc->sc_iobase = csc->cc_addr;
  271         sc->sc_frequency = COM_FREQ;
  272 
  273         sc->enable = com_cardbus_enable;
  274         sc->disable = com_cardbus_disable;
  275         sc->enabled = 0;
  276 
  277         if (com_cardbus_enable(sc))
  278                 return;
  279         sc->enabled = 1;
  280 
  281         sc->sc_hwflags = 0;
  282         sc->sc_swflags = 0;
  283 
  284         if (csc->cc_bug & BUG_BROADCOM)
  285                 sc->sc_fifolen = 15;
  286 
  287         com_attach_subr(sc);
  288 }
  289 
  290 void
  291 com_cardbus_setup(struct com_cardbus_softc *csc)
  292 {
  293         cardbus_devfunc_t ct = csc->cc_ct;
  294         cardbus_chipset_tag_t cc = ct->ct_cc;
  295         pci_chipset_tag_t pc = csc->cc_pc;
  296         cardbus_function_tag_t cf = ct->ct_cf;
  297         pcireg_t reg;
  298 
  299         pci_conf_write(pc, csc->cc_tag, csc->cc_reg, csc->cc_base);
  300 
  301         /* enable accesses on cardbus bridge */
  302         cf->cardbus_ctrl(cc, csc->cc_cben);
  303         cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);
  304 
  305         /* and the card itself */
  306         reg = pci_conf_read(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG);
  307         reg &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
  308         reg |= csc->cc_csr;
  309         pci_conf_write(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG, reg);
  310 
  311         /*
  312          * Make sure the latency timer is set to some reasonable
  313          * value.
  314          */
  315         reg = pci_conf_read(pc, csc->cc_tag, PCI_BHLC_REG);
  316         if (PCI_LATTIMER(reg) < 0x20) {
  317                         reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
  318                         reg |= (0x20 << PCI_LATTIMER_SHIFT);
  319                         pci_conf_write(pc, csc->cc_tag, PCI_BHLC_REG, reg);
  320         }
  321 }
  322 
  323 int
  324 com_cardbus_enable(struct com_softc *sc)
  325 {
  326         struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
  327         struct cardbus_softc *psc =
  328             (struct cardbus_softc *)sc->sc_dev.dv_parent;
  329         cardbus_chipset_tag_t cc = psc->sc_cc;
  330         cardbus_function_tag_t cf = psc->sc_cf;
  331 
  332         Cardbus_function_enable(csc->cc_ct);
  333 
  334         com_cardbus_setup(csc);
  335 
  336         /* establish the interrupt. */
  337         csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
  338             IPL_TTY, comintr, sc, DEVNAME(csc));
  339         if (csc->cc_ih == NULL) {
  340                 printf(": couldn't establish interrupt\n");
  341                 return (1);
  342         }
  343 
  344         printf(": irq %d", psc->sc_intrline);
  345 
  346         return (0);
  347 }
  348 
  349 void
  350 com_cardbus_disable(struct com_softc *sc)
  351 {
  352         struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
  353         struct cardbus_softc *psc =
  354             (struct cardbus_softc *)sc->sc_dev.dv_parent;
  355         cardbus_chipset_tag_t cc = psc->sc_cc;
  356         cardbus_function_tag_t cf = psc->sc_cf;
  357 
  358         cardbus_intr_disestablish(cc, cf, csc->cc_ih);
  359         Cardbus_function_disable(csc->cc_ct);
  360 }
  361 
  362 int
  363 com_cardbus_detach(struct device *self, int flags)
  364 {
  365         struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
  366         struct com_softc *sc = (struct com_softc *) self;
  367         struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
  368         int error;
  369 
  370         if ((error = com_detach(self, flags)) != 0)
  371                 return (error);
  372 
  373         cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
  374 
  375         Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
  376             csc->cc_size);
  377 
  378         return (0);
  379 }

Cache object: e85a7e29002ac6dec6596be877bc255c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.