LCOV - code coverage report
Current view: top level - dev/cardbus - com_cardbus.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 143 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $OpenBSD: com_cardbus.c,v 1.43 2015/11/14 14:47:56 miod 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             : 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           0 : com_cardbus_find_csdev(struct cardbus_attach_args *ca)
     139             : {
     140             :         struct csdev *cp;
     141             : 
     142           0 :         for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
     143           0 :                 if (cp->vendor == PCI_VENDOR(ca->ca_id) &&
     144           0 :                     cp->product == PCI_PRODUCT(ca->ca_id))
     145           0 :                         return (cp);
     146           0 :         return (NULL);
     147           0 : }
     148             : 
     149             : int
     150           0 : com_cardbus_match(struct device *parent, void *match, void *aux)
     151             : {
     152           0 :         struct cardbus_attach_args *ca = aux;
     153             : 
     154             :         /* known devices are ok */
     155           0 :         if (com_cardbus_find_csdev(ca) != NULL)
     156           0 :             return (10);
     157             : 
     158             :         /* as are serial devices with a known UART */
     159           0 :         if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
     160           0 :             ca->ca_cis.funce.serial.uart_present != 0 &&
     161           0 :             (ca->ca_cis.funce.serial.uart_type == 0 ||       /* 8250 */
     162           0 :             ca->ca_cis.funce.serial.uart_type == 1 ||        /* 16450 */
     163           0 :             ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
     164           0 :                 return (1);
     165             : 
     166           0 :         return (0);
     167           0 : }
     168             : 
     169             : int
     170           0 : 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           0 :         cp = com_cardbus_find_csdev(ca);
     179           0 :         if (cp != NULL) {
     180           0 :                 csc->cc_reg = cp->reg;
     181           0 :                 csc->cc_type = cp->type;
     182           0 :                 csc->cc_bug = cp->bug;
     183           0 :                 return (0);
     184             :         }
     185             : 
     186           0 :         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           0 :         for (i = 0; i < 7; i++) {
     192             :                 /* ignore zero sized BARs */
     193           0 :                 if (ca->ca_cis.bar[i].size == 0)
     194             :                         continue;
     195             :                 /* ignore the CIS BAR */
     196           0 :                 if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
     197           0 :                     CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
     198             :                         continue;
     199           0 :                 if (index != -1)
     200             :                         goto multi_bar;
     201             :                 index = i;
     202           0 :         }
     203           0 :         if (index == -1) {
     204           0 :                 printf(": couldn't find any base address tuple\n");
     205           0 :                 return (1);
     206             :         }
     207           0 :         csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
     208           0 :         if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
     209           0 :                 csc->cc_type = PCI_MAPREG_TYPE_MEM;
     210             :         else
     211           0 :                 csc->cc_type = PCI_MAPREG_TYPE_IO;
     212           0 :         return (0);
     213             : 
     214             :   multi_bar:
     215           0 :         printf(": there are more than one possible base\n");
     216             : 
     217           0 :         printf("%s: address for this device, "
     218             :             "please report the following information\n",
     219           0 :             DEVNAME(csc));
     220           0 :         printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
     221           0 :             PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
     222           0 :         for (i = 0; i < 7; i++) {
     223             :                 /* ignore zero sized BARs */
     224           0 :                 if (ca->ca_cis.bar[i].size == 0)
     225             :                         continue;
     226             :                 /* ignore the CIS BAR */
     227           0 :                 if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
     228           0 :                     CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
     229             :                         continue;
     230           0 :                 printf("%s: base address %x type %s size %x\n",
     231             :                     DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
     232           0 :                     (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
     233             :                     ca->ca_cis.bar[i].size);
     234           0 :         }
     235           0 :         return (1);
     236           0 : }
     237             : 
     238             : void
     239           0 : com_cardbus_attach(struct device *parent, struct device *self, void *aux)
     240             : {
     241           0 :         struct com_softc *sc = (struct com_softc*)self;
     242           0 :         struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
     243           0 :         struct cardbus_attach_args *ca = aux;
     244             :         cardbus_devfunc_t ct;
     245             : 
     246           0 :         csc->cc_ct = ct = ca->ca_ct;
     247           0 :         csc->cc_tag = pci_make_tag(ca->ca_pc, ct->ct_bus, ct->ct_dev, ct->ct_func);
     248           0 :         csc->cc_pc = ca->ca_pc;
     249             : 
     250           0 :         if (com_cardbus_gofigure(ca, csc) != 0)
     251           0 :                 return;
     252             : 
     253           0 :         if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
     254           0 :             &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
     255           0 :                 printf(": can't map memory\n");
     256           0 :                 return;
     257             :         }
     258             : 
     259           0 :         csc->cc_base = csc->cc_addr;
     260           0 :         csc->cc_csr = PCI_COMMAND_MASTER_ENABLE;
     261           0 :         if (csc->cc_type == PCI_MAPREG_TYPE_IO) {
     262           0 :                 csc->cc_base |= PCI_MAPREG_TYPE_IO;
     263           0 :                 csc->cc_csr |= PCI_COMMAND_IO_ENABLE;
     264           0 :                 csc->cc_cben = CARDBUS_IO_ENABLE;
     265           0 :         } else {
     266           0 :                 csc->cc_csr |= PCI_COMMAND_MEM_ENABLE;
     267           0 :                 csc->cc_cben = CARDBUS_MEM_ENABLE;
     268             :         }
     269             : 
     270           0 :         sc->sc_iobase = csc->cc_addr;
     271           0 :         sc->sc_frequency = COM_FREQ;
     272             : 
     273           0 :         sc->enable = com_cardbus_enable;
     274           0 :         sc->disable = com_cardbus_disable;
     275           0 :         sc->enabled = 0;
     276             : 
     277           0 :         if (com_cardbus_enable(sc))
     278           0 :                 return;
     279           0 :         sc->enabled = 1;
     280             : 
     281           0 :         sc->sc_hwflags = 0;
     282           0 :         sc->sc_swflags = 0;
     283             : 
     284           0 :         if (csc->cc_bug & BUG_BROADCOM)
     285           0 :                 sc->sc_fifolen = 15;
     286             : 
     287           0 :         com_attach_subr(sc);
     288           0 : }
     289             : 
     290             : void
     291           0 : com_cardbus_setup(struct com_cardbus_softc *csc)
     292             : {
     293           0 :         cardbus_devfunc_t ct = csc->cc_ct;
     294           0 :         cardbus_chipset_tag_t cc = ct->ct_cc;
     295           0 :         pci_chipset_tag_t pc = csc->cc_pc;
     296           0 :         cardbus_function_tag_t cf = ct->ct_cf;
     297             :         pcireg_t reg;
     298             : 
     299           0 :         pci_conf_write(pc, csc->cc_tag, csc->cc_reg, csc->cc_base);
     300             : 
     301             :         /* enable accesses on cardbus bridge */
     302           0 :         cf->cardbus_ctrl(cc, csc->cc_cben);
     303           0 :         cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);
     304             : 
     305             :         /* and the card itself */
     306           0 :         reg = pci_conf_read(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG);
     307           0 :         reg &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
     308           0 :         reg |= csc->cc_csr;
     309           0 :         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           0 :         reg = pci_conf_read(pc, csc->cc_tag, PCI_BHLC_REG);
     316           0 :         if (PCI_LATTIMER(reg) < 0x20) {
     317           0 :                         reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
     318           0 :                         reg |= (0x20 << PCI_LATTIMER_SHIFT);
     319           0 :                         pci_conf_write(pc, csc->cc_tag, PCI_BHLC_REG, reg);
     320           0 :         }
     321           0 : }
     322             : 
     323             : int
     324           0 : com_cardbus_enable(struct com_softc *sc)
     325             : {
     326           0 :         struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
     327             :         struct cardbus_softc *psc =
     328           0 :             (struct cardbus_softc *)sc->sc_dev.dv_parent;
     329           0 :         cardbus_chipset_tag_t cc = psc->sc_cc;
     330           0 :         cardbus_function_tag_t cf = psc->sc_cf;
     331             : 
     332           0 :         Cardbus_function_enable(csc->cc_ct);
     333             : 
     334           0 :         com_cardbus_setup(csc);
     335             : 
     336             :         /* establish the interrupt. */
     337           0 :         csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
     338           0 :             IPL_TTY, comintr, sc, DEVNAME(csc));
     339           0 :         if (csc->cc_ih == NULL) {
     340           0 :                 printf(": couldn't establish interrupt\n");
     341           0 :                 return (1);
     342             :         }
     343             : 
     344           0 :         printf(": irq %d", psc->sc_intrline);
     345             : 
     346           0 :         return (0);
     347           0 : }
     348             : 
     349             : void
     350           0 : com_cardbus_disable(struct com_softc *sc)
     351             : {
     352           0 :         struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
     353             :         struct cardbus_softc *psc =
     354           0 :             (struct cardbus_softc *)sc->sc_dev.dv_parent;
     355           0 :         cardbus_chipset_tag_t cc = psc->sc_cc;
     356           0 :         cardbus_function_tag_t cf = psc->sc_cf;
     357             : 
     358           0 :         cardbus_intr_disestablish(cc, cf, csc->cc_ih);
     359           0 :         Cardbus_function_disable(csc->cc_ct);
     360           0 : }
     361             : 
     362             : int
     363           0 : com_cardbus_detach(struct device *self, int flags)
     364             : {
     365           0 :         struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
     366           0 :         struct com_softc *sc = (struct com_softc *) self;
     367           0 :         struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
     368             :         int error;
     369             : 
     370           0 :         if ((error = com_detach(self, flags)) != 0)
     371           0 :                 return (error);
     372             : 
     373           0 :         cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
     374             : 
     375           0 :         Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
     376             :             csc->cc_size);
     377             : 
     378           0 :         return (0);
     379           0 : }

Generated by: LCOV version 1.13