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/ieee488/pcii.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 /*-
    2  * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
    3  * Copyright (c) 2010 Joerg Wunsch <joerg@FreeBSD.org>
    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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * Driver for GPIB cards based on NEC µPD7210 and compatibles.
   28  *
   29  * This driver just hooks up to the hardware and leaves all the interesting
   30  * stuff to upd7210.c.
   31  *
   32  * Supported hardware:
   33  *    PCIIA compatible cards.
   34  *
   35  *    Tested and known working:
   36  *      "B&C Microsystems PC488A-0"
   37  *      "National Instruments GPIB-PCII/PCIIA" (in PCIIa mode)
   38  *      "Axiom AX5488"
   39  *
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __FBSDID("$FreeBSD: releng/8.4/sys/dev/ieee488/pcii.c 204491 2010-02-28 22:25:39Z joerg $");
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/lock.h>
   48 #include <sys/mutex.h>
   49 #include <sys/kernel.h>
   50 #include <sys/module.h>
   51 #include <sys/bus.h>
   52 #include <machine/bus.h>
   53 #include <machine/resource.h>
   54 #include <sys/rman.h>
   55 #include <isa/isavar.h>
   56 
   57 #define UPD7210_HW_DRIVER
   58 #include <dev/ieee488/upd7210.h>
   59 
   60 struct pcii_softc {
   61         int foo;
   62         struct resource *res[11];
   63         void *intr_handler;
   64         struct upd7210  upd7210;
   65 };
   66 
   67 static devclass_t pcii_devclass;
   68 
   69 static int      pcii_probe(device_t dev);
   70 static int      pcii_attach(device_t dev);
   71 
   72 static device_method_t pcii_methods[] = {
   73         DEVMETHOD(device_probe,         pcii_probe),
   74         DEVMETHOD(device_attach,        pcii_attach),
   75         DEVMETHOD(device_suspend,       bus_generic_suspend),
   76         DEVMETHOD(device_resume,        bus_generic_resume),
   77 
   78         { 0, 0 }
   79 };
   80 
   81 static struct resource_spec pcii_res_spec[] = {
   82         { SYS_RES_IRQ,          0, RF_ACTIVE | RF_SHAREABLE},
   83         { SYS_RES_DRQ,          0, RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL},
   84         { SYS_RES_IOPORT,       0, RF_ACTIVE},
   85         { SYS_RES_IOPORT,       1, RF_ACTIVE},
   86         { SYS_RES_IOPORT,       2, RF_ACTIVE},
   87         { SYS_RES_IOPORT,       3, RF_ACTIVE},
   88         { SYS_RES_IOPORT,       4, RF_ACTIVE},
   89         { SYS_RES_IOPORT,       5, RF_ACTIVE},
   90         { SYS_RES_IOPORT,       6, RF_ACTIVE},
   91         { SYS_RES_IOPORT,       7, RF_ACTIVE},
   92         { SYS_RES_IOPORT,       8, RF_ACTIVE | RF_SHAREABLE},
   93         { -1, 0, 0 }
   94 };
   95 
   96 static driver_t pcii_driver = {
   97         "pcii",
   98         pcii_methods,
   99         sizeof(struct pcii_softc),
  100 };
  101 
  102 static int
  103 pcii_probe(device_t dev)
  104 {
  105         int rid, i, j;
  106         u_long start, count, addr;
  107         int error = 0;
  108         struct pcii_softc *sc;
  109 
  110         device_set_desc(dev, "PCII IEEE-4888 controller");
  111         sc = device_get_softc(dev);
  112 
  113         rid = 0;
  114         if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
  115                 return ENXIO;
  116         /*
  117          * The PCIIA decodes a fixed pattern of 0x2e1 for the lower 10
  118          * address bits A0 ... A9.  Bits A10 through A12 are used by
  119          * the µPD7210 register select lines.  This makes the
  120          * individual 7210 register being 0x400 bytes apart in the ISA
  121          * bus address space.  Address bits A13 and A14 are compared
  122          * to a DIP switch setting on the card, allowing for up to 4
  123          * different cards being installed (at base addresses 0x2e1,
  124          * 0x22e1, 0x42e1, and 0x62e1, respectively).  A15 has been
  125          * used to select an optional on-board time-of-day clock chip
  126          * (MM58167A) on the original PCIIA rather than the µPD7210
  127          * (which is not implemented on later boards).  The
  128          * documentation states the respective addresses for that chip
  129          * should be handled as reserved addresses, which we don't do
  130          * (right now).  Finally, the IO addresses 0x2f0 ... 0x2f7 for
  131          * a "special interrupt handling feature" (re-enable
  132          * interrupts so the IRQ can be shared).
  133          *
  134          * Usually, the user will only set the base address in the
  135          * device hints, so we handle the rest here.
  136          *
  137          * (Source: GPIB-PCIIA Technical Reference Manual, September
  138          * 1989 Edition, National Instruments.)
  139          */
  140         if ((start & 0x3ff) != 0x2e1) {
  141                 if (bootverbose)
  142                         printf("pcii_probe: PCIIA base address 0x%lx not "
  143                                "0x2e1/0x22e1/0x42e1/0x62e1\n",
  144                                start);
  145                 return (ENXIO);
  146         }
  147 
  148         for (rid = 0, addr = start; rid < 8; rid++, addr += 0x400) {
  149                 if (bus_set_resource(dev, SYS_RES_IOPORT, rid, addr, 1) != 0) {
  150                         printf("pcii_probe: could not set IO port 0x%lx\n",
  151                                addr);
  152                         return (ENXIO);
  153                 }
  154         }
  155         if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) {
  156                 printf("pcii_probe: cannot obtain IRQ level\n");
  157                 return ENXIO;
  158         }
  159         if (start > 7) {
  160                 printf("pcii_probe: IRQ level %lu too high\n", start);
  161                 return ENXIO;
  162         }
  163 
  164         if (bus_set_resource(dev, SYS_RES_IOPORT, 8, 0x2f0 + start, 1) != 0) {
  165                 printf("pcii_probe: could not set IO port 0x%3lx\n",
  166                        0x2f0 + start);
  167                 return (ENXIO);
  168         }
  169 
  170         error = bus_alloc_resources(dev, pcii_res_spec, sc->res);
  171         if (error) {
  172                 printf("pcii_probe: Could not allocate resources\n");
  173                 return (error);
  174         }
  175         error = ENXIO;
  176         /*
  177          * Perform some basic tests on the µPD7210 registers.  At
  178          * least *some* register must read different from 0x00 or
  179          * 0xff.
  180          */
  181         for (i = 0; i < 8; i++) {
  182                 j = bus_read_1(sc->res[2 + i], 0);
  183                 if (j != 0x00 && j != 0xff)
  184                         error = 0;
  185         }
  186         /* SPSR/SPMR read/write test */
  187         if (!error) {
  188                 bus_write_1(sc->res[2 + 3], 0, 0x55);
  189                 if (bus_read_1(sc->res[2 + 3], 0) != 0x55)
  190                         error = ENXIO;
  191         }
  192         if (!error) {
  193                 bus_write_1(sc->res[2 + 3], 0, 0xaa);
  194                 if (bus_read_1(sc->res[2 + 3], 0) != 0xaa)
  195                         error = ENXIO;
  196         }
  197         if (error)
  198                 printf("pcii_probe: probe failure\n");
  199 
  200         bus_release_resources(dev, pcii_res_spec, sc->res);
  201         return (error);
  202 }
  203 
  204 static int
  205 pcii_attach(device_t dev)
  206 {
  207         struct pcii_softc *sc;
  208         u_long          start, count;
  209         int             unit;
  210         int             rid;
  211         int             error = 0;
  212 
  213         unit = device_get_unit(dev);
  214         sc = device_get_softc(dev);
  215         memset(sc, 0, sizeof *sc);
  216 
  217         device_set_desc(dev, "PCII IEEE-4888 controller");
  218 
  219         if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) {
  220                 printf("pcii_attach: cannot obtain IRQ number\n");
  221                 return ENXIO;
  222         }
  223 
  224         error = bus_alloc_resources(dev, pcii_res_spec, sc->res);
  225         if (error)
  226                 return (error);
  227 
  228         error = bus_setup_intr(dev, sc->res[0],
  229             INTR_TYPE_MISC | INTR_MPSAFE, NULL,
  230             upd7210intr, &sc->upd7210, &sc->intr_handler);
  231         if (error) {
  232                 bus_release_resources(dev, pcii_res_spec, sc->res);
  233                 return (error);
  234         }
  235 
  236         for (rid = 0; rid < 8; rid++) {
  237                 sc->upd7210.reg_res[rid] = sc->res[2 + rid];
  238                 sc->upd7210.reg_offset[rid] = 0;
  239         }
  240         sc->upd7210.irq_clear_res = sc->res[10];
  241         sc->upd7210.use_fifo = 0;
  242 
  243         if (sc->res[1] == NULL)
  244                 sc->upd7210.dmachan = -1;
  245         else
  246                 sc->upd7210.dmachan = rman_get_start(sc->res[1]);
  247 
  248         upd7210attach(&sc->upd7210);
  249         device_printf(dev, "attached gpib%d\n", sc->upd7210.unit);
  250 
  251         return (0);
  252 }
  253 
  254 DRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0);
  255 DRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0);

Cache object: 33f4ebb4a4d34b5688b79c2bfe177ee9


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