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/ic/upc.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 /* $NetBSD: upc.c,v 1.9 2005/02/27 00:27:03 perry Exp $ */
    2 /*-
    3  * Copyright (c) 2000, 2003 Ben Harris
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 /*
   29  * upc - driver for C&T Universal Peripheral Controllers
   30  *
   31  * Supports:
   32  * 82C710 Universal Peripheral Controller
   33  * 82C711 Universal Peripheral Controller II
   34  * 82C721 Universal Peripheral Controller III (untested)
   35  *
   36  * The 82C710 is substantially different from its successors.
   37  * Functions that just handle the 82C710 are named upc1_*, which those
   38  * that handle the 82C711 and 82C721 are named upc2_*.
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __KERNEL_RCSID(0, "$NetBSD: upc.c,v 1.9 2005/02/27 00:27:03 perry Exp $");
   43 
   44 #include <sys/param.h>
   45 #include <sys/device.h>
   46 #include <sys/systm.h>
   47 
   48 #include <machine/bus.h>
   49 
   50 #include <dev/ata/atavar.h> /* XXX needed by wdcvar.h */
   51 #include <dev/ic/comreg.h>
   52 #include <dev/ic/lptreg.h>
   53 #include <dev/ic/lptvar.h>
   54 #include <dev/ic/wdcreg.h>
   55 #include <dev/ic/wdcvar.h>
   56 #include <dev/ic/upcreg.h>
   57 #include <dev/ic/upcvar.h>
   58 
   59 #include "locators.h"
   60 
   61 /* Conventional port to use for 82C710 configuration */
   62 #define UPC1_PORT_CRI   0x390
   63 #define UPC1_PORT_CAP   (UPC1_PORT_CRI + 1)
   64 
   65 static int upc1_probe(struct upc_softc *);
   66 static void upc1_attach(struct upc_softc *);
   67 static void upc2_attach(struct upc_softc *);
   68 static void upc_found(struct upc_softc *, char const *, int, int,
   69                       struct upc_irqhandle *);
   70 static void upc_found2(struct upc_softc *, char const *, int, int, int, int,
   71                        struct upc_irqhandle *);
   72 static int upc_print(void *, char const *);
   73 static int upc_submatch(struct device *, struct cfdata *,
   74                         const locdesc_t *, void *);
   75 static int upc2_com3_addr(int);
   76 static int upc2_com4_addr(int);
   77 
   78 void
   79 upc_attach(struct upc_softc *sc)
   80 {
   81 
   82         if (upc1_probe(sc))
   83                 upc1_attach(sc);
   84         else
   85                 upc2_attach(sc);
   86 }
   87 
   88 static int
   89 upc1_probe(struct upc_softc *sc)
   90 {
   91 
   92         return upc1_read_config(sc, UPC1_CFGADDR_CONFBASE) ==
   93             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT;
   94 }
   95 
   96 static void
   97 upc1_attach(struct upc_softc *sc)
   98 {
   99         u_int8_t cr[16];
  100         int i;
  101 
  102         aprint_normal(": 82C710\n");
  103         /* Dump configuration */
  104         for (i = 0; i < 16; i++)
  105                 cr[i] = upc1_read_config(sc, i);
  106 
  107         aprint_verbose("%s: config state", sc->sc_dev.dv_xname);
  108         for (i = 0; i < 16; i++)
  109                 aprint_verbose(" %02x", cr[i]);
  110         aprint_verbose("\n");
  111 
  112         /* FDC */
  113         if (cr[UPC1_CFGADDR_CRC] & UPC1_CRC_FDCEN)
  114                 upc_found(sc, "fdc", UPC_PORT_FDCBASE, 2, &sc->sc_fintr);
  115         /* IDE */
  116         if (cr[UPC1_CFGADDR_CRC] & UPC1_CRC_IDEEN)
  117                 upc_found2(sc, "wdc", UPC_PORT_IDECMDBASE, 8,
  118                            UPC_PORT_IDECTLBASE, 2, &sc->sc_wintr);
  119         /* Parallel */
  120         if (cr[UPC1_CFGADDR_CR0] & UPC1_CR0_PEN)
  121                 upc_found(sc, "lpt",
  122                     cr[UPC1_CFGADDR_PARBASE] << UPC1_PARBASE_SHIFT,
  123                     LPT_NPORTS, &sc->sc_pintr);
  124         /* UART */
  125         if (cr[UPC1_CFGADDR_CR0] & UPC1_CR0_SEN)
  126                 upc_found(sc, "com",
  127                     cr[UPC1_CFGADDR_UARTBASE] << UPC1_UARTBASE_SHIFT,
  128                     COM_NPORTS, &sc->sc_irq4);
  129         /* Mouse */
  130         /* XXX not yet supported */
  131 }
  132 
  133 static void
  134 upc2_attach(struct upc_softc *sc)
  135 {
  136         u_int8_t cr[5];
  137         int i;
  138 
  139         aprint_normal(": 82C711/82C721");
  140         /* Dump configuration */
  141         for (i = 0; i < 5; i++)
  142                 cr[i] = upc2_read_config(sc, i);
  143 
  144         aprint_verbose(", config state %02x %02x %02x %02x %02x",
  145                cr[0], cr[1], cr[2], cr[3], cr[4]);
  146         aprint_normal("\n");
  147 
  148         /* "Find" the attached devices */
  149         /* FDC */
  150         if (cr[0] & UPC2_CR0_FDC_ENABLE)
  151                 upc_found(sc, "fdc", UPC_PORT_FDCBASE, 2, &sc->sc_fintr);
  152         /* IDE */
  153         if (cr[0] & UPC2_CR0_IDE_ENABLE)
  154                 upc_found2(sc, "wdc", UPC_PORT_IDECMDBASE, 8,
  155                            UPC_PORT_IDECTLBASE, 2, &sc->sc_wintr);
  156         /* Parallel */
  157         switch (cr[1] & UPC2_CR1_LPT_MASK) {
  158         case UPC2_CR1_LPT_3BC:
  159                 upc_found(sc, "lpt", 0x3bc, LPT_NPORTS, &sc->sc_pintr);
  160                 break;
  161         case UPC2_CR1_LPT_378:
  162                 upc_found(sc, "lpt", 0x378, LPT_NPORTS, &sc->sc_pintr);
  163                 break;
  164         case UPC2_CR1_LPT_278:
  165                 upc_found(sc, "lpt", 0x278, LPT_NPORTS, &sc->sc_pintr);
  166                 break;
  167         }
  168         /* UART1 */
  169         if (cr[2] & UPC2_CR2_UART1_ENABLE) {
  170                 switch (cr[2] & UPC2_CR2_UART1_MASK) {
  171                 case UPC2_CR2_UART1_3F8:
  172                         upc_found(sc, "com", 0x3f8, COM_NPORTS, &sc->sc_irq4);
  173                         break;
  174                 case UPC2_CR2_UART1_2F8:
  175                         upc_found(sc, "com", 0x2f8, COM_NPORTS, &sc->sc_irq3);
  176                         break;
  177                 case UPC2_CR2_UART1_COM3:
  178                         upc_found(sc, "com", upc2_com3_addr(cr[1]), COM_NPORTS,
  179                                   &sc->sc_irq4);
  180                         break;
  181                 case UPC2_CR2_UART1_COM4:
  182                         upc_found(sc, "com", upc2_com4_addr(cr[1]), COM_NPORTS,
  183                                   &sc->sc_irq3);
  184                         break;
  185                 }
  186         }
  187         /* UART2 */
  188         if (cr[2] & UPC2_CR2_UART2_ENABLE) {
  189                 switch (cr[2] & UPC2_CR2_UART2_MASK) {
  190                 case UPC2_CR2_UART2_3F8:
  191                         upc_found(sc, "com", 0x3f8, COM_NPORTS, &sc->sc_irq4);
  192                         break;
  193                 case UPC2_CR2_UART2_2F8:
  194                         upc_found(sc, "com", 0x2f8, COM_NPORTS, &sc->sc_irq3);
  195                         break;
  196                 case UPC2_CR2_UART2_COM3:
  197                         upc_found(sc, "com", upc2_com3_addr(cr[1]), COM_NPORTS,
  198                                   &sc->sc_irq4);
  199                         break;
  200                 case UPC2_CR2_UART2_COM4:
  201                         upc_found(sc, "com", upc2_com4_addr(cr[1]), COM_NPORTS,
  202                                   &sc->sc_irq3);
  203                         break;
  204                 }
  205         }
  206 
  207 }
  208 
  209 static void
  210 upc_found(struct upc_softc *sc, char const *devtype, int offset, int size,
  211           struct upc_irqhandle *uih)
  212 {
  213         struct upc_attach_args ua;
  214         int help[2];
  215         locdesc_t *ldesc = (void *)help;
  216 
  217         ua.ua_devtype = devtype;
  218         ua.ua_offset = offset;
  219         ua.ua_iot = sc->sc_iot;
  220         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset, size, &ua.ua_ioh);
  221         ua.ua_irqhandle = uih;
  222 
  223         ldesc->len = 1;
  224         ldesc->locs[UPCCF_OFFSET] = offset;
  225 
  226         config_found_sm_loc(&sc->sc_dev, "upc", ldesc, &ua,
  227                             upc_print, upc_submatch);
  228 }
  229 
  230 static void
  231 upc_found2(struct upc_softc *sc, char const *devtype, int offset, int size,
  232            int offset2, int size2, struct upc_irqhandle *uih)
  233 {
  234         struct upc_attach_args ua;
  235         int help[2];
  236         locdesc_t *ldesc = (void *)help;
  237 
  238         ua.ua_devtype = devtype;
  239         ua.ua_offset = offset;
  240         ua.ua_iot = sc->sc_iot;
  241         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset, size, &ua.ua_ioh);
  242         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset2, size2,
  243                             &ua.ua_ioh2);
  244         ua.ua_irqhandle = uih;
  245 
  246         ldesc->len = 1;
  247         ldesc->locs[UPCCF_OFFSET] = offset;
  248 
  249         config_found_sm_loc(&sc->sc_dev, "upc", ldesc, &ua,
  250                             upc_print, upc_submatch);
  251 }
  252 
  253 void
  254 upc_intr_establish(struct upc_irqhandle *uih, int level, int (*func)(void *),
  255                    void *arg) {
  256 
  257         uih->uih_level = level;
  258         uih->uih_func = func;
  259         uih->uih_arg = arg;
  260         /* Actual MD establishment will be handled later by bus attachment. */
  261 }
  262 
  263 static int
  264 upc2_com3_addr(int cr1)
  265 {
  266 
  267         switch (cr1 & UPC2_CR1_COM34_MASK) {
  268         case UPC2_CR1_COM34_338_238:
  269                 return 0x338;
  270         case UPC2_CR1_COM34_3E8_2E8:
  271                 return 0x3e8;
  272         case UPC2_CR1_COM34_2E8_2E0:
  273                 return 0x2e8;
  274         case UPC2_CR1_COM34_220_228:
  275                 return 0x220;
  276         }
  277         return -1;
  278 }
  279 
  280 static int
  281 upc2_com4_addr(int cr1)
  282 {
  283 
  284         switch (cr1 & UPC2_CR1_COM34_MASK) {
  285         case UPC2_CR1_COM34_338_238:
  286                 return 0x238;
  287         case UPC2_CR1_COM34_3E8_2E8:
  288                 return 0x2e8;
  289         case UPC2_CR1_COM34_2E8_2E0:
  290                 return 0x2e0;
  291         case UPC2_CR1_COM34_220_228:
  292                 return 0x228;
  293         }
  294         return -1;
  295 }
  296 
  297 static int
  298 upc_print(void *aux, char const *pnp)
  299 {
  300         struct upc_attach_args *ua = aux;
  301 
  302         if (pnp)
  303                 aprint_normal("%s at %s", ua->ua_devtype, pnp);
  304         aprint_normal(" offset 0x%x", ua->ua_offset);
  305         return UNCONF;
  306 }
  307 
  308 static int
  309 upc_submatch(struct device *parent, struct cfdata *cf,
  310              const locdesc_t *ldesc, void *aux)
  311 {
  312         struct upc_attach_args *ua = aux;
  313 
  314         if (strcmp(cf->cf_name, ua->ua_devtype) == 0 &&
  315             (cf->cf_loc[UPCCF_OFFSET] == UPCCF_OFFSET_DEFAULT ||
  316              cf->cf_loc[UPCCF_OFFSET] == ldesc->locs[UPCCF_OFFSET]))
  317                 return config_match(parent, cf, aux);
  318         return 0;
  319 }
  320 
  321 int
  322 upc1_read_config(struct upc_softc *sc, int reg)
  323 {
  324         bus_space_tag_t iot = sc->sc_iot;
  325         bus_space_handle_t ioh = sc->sc_ioh;
  326         int retval;
  327 
  328         /* Switch into configuration mode. */
  329         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1, UPC1_CFGMAGIC_1);
  330         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_2);
  331         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_3);
  332         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2,
  333             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT);
  334         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1,
  335             (UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT) ^ 0xff);
  336 
  337         /* Read register. */
  338         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, reg);
  339         retval = bus_space_read_1(iot, ioh, UPC1_PORT_CAP);
  340 
  341         /* Leave configuration mode. */
  342         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, UPC1_CFGADDR_EXIT);
  343         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, 0);
  344         return retval;
  345 }
  346 
  347 void
  348 upc1_write_config(struct upc_softc *sc, int reg, int val)
  349 {
  350         bus_space_tag_t iot = sc->sc_iot;
  351         bus_space_handle_t ioh = sc->sc_ioh;
  352 
  353         /* Switch into configuration mode. */
  354         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1, UPC1_CFGMAGIC_1);
  355         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_2);
  356         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_3);
  357         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2,
  358             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT);
  359         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1,
  360             (UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT) ^ 0xff);
  361 
  362         /* Read register. */
  363         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, reg);
  364         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, val);
  365 
  366         /* Leave configuration mode. */
  367         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, UPC1_CFGADDR_EXIT);
  368         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, 0);
  369 }
  370 
  371 int
  372 upc2_read_config(struct upc_softc *sc, int reg)
  373 {
  374         bus_space_tag_t iot = sc->sc_iot;
  375         bus_space_handle_t ioh = sc->sc_ioh;
  376         int retval;
  377 
  378         /* Switch into configuration mode. */
  379         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  380         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  381 
  382         /* Read register. */
  383         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, reg);
  384         retval = bus_space_read_1(iot, ioh, UPC2_PORT_CFGDATA);
  385 
  386         /* Leave configuration mode. */
  387         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_EXIT);
  388         return retval;
  389 }
  390 
  391 void
  392 upc2_write_config(struct upc_softc *sc, int reg, int val)
  393 {
  394         bus_space_tag_t iot = sc->sc_iot;
  395         bus_space_handle_t ioh = sc->sc_ioh;
  396 
  397         /* Switch into configuration mode. */
  398         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  399         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  400 
  401         /* Write register. */
  402         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, reg);
  403         bus_space_write_1(iot, ioh, UPC2_PORT_CFGDATA, val);
  404 
  405         /* Leave configuration mode. */
  406         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_EXIT);
  407 }

Cache object: 1401808bc6bc3007902b6adbce150673


[ 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.