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/ppc/ppc_isa.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) 1997-2000 Nicolas Souchu
    3  * Copyright (c) 2001 Alcove - Nicolas Souchu
    4  * Copyright (c) 2006 Marcel Moolenaar
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/8.3/sys/dev/ppc/ppc_isa.c 187576 2009-01-21 23:10:06Z jhb $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/lock.h>
   36 #include <sys/module.h>
   37 #include <sys/mutex.h>
   38 #include <sys/bus.h>
   39 #include <machine/bus.h>
   40 #include <sys/malloc.h>
   41 #include <sys/rman.h>
   42 
   43 #include <isa/isavar.h>
   44 
   45 #include <dev/ppbus/ppbconf.h>
   46 #include <dev/ppbus/ppb_msq.h>
   47 #include <dev/ppc/ppcvar.h>
   48 #include <dev/ppc/ppcreg.h>
   49 
   50 #include "ppbus_if.h"
   51 
   52 static int ppc_isa_probe(device_t dev);
   53 
   54 int ppc_isa_attach(device_t dev);
   55 int ppc_isa_write(device_t, char *, int, int);
   56 
   57 static device_method_t ppc_isa_methods[] = {
   58         /* device interface */
   59         DEVMETHOD(device_probe,         ppc_isa_probe),
   60         DEVMETHOD(device_attach,        ppc_isa_attach),
   61         DEVMETHOD(device_detach,        ppc_detach),
   62 
   63         /* bus interface */
   64         DEVMETHOD(bus_read_ivar,        ppc_read_ivar),
   65         DEVMETHOD(bus_write_ivar,       ppc_write_ivar),
   66         DEVMETHOD(bus_alloc_resource,   ppc_alloc_resource),
   67         DEVMETHOD(bus_release_resource, ppc_release_resource),
   68 
   69         /* ppbus interface */
   70         DEVMETHOD(ppbus_io,             ppc_io),
   71         DEVMETHOD(ppbus_exec_microseq,  ppc_exec_microseq),
   72         DEVMETHOD(ppbus_reset_epp,      ppc_reset_epp),
   73         DEVMETHOD(ppbus_setmode,        ppc_setmode),
   74         DEVMETHOD(ppbus_ecp_sync,       ppc_ecp_sync),
   75         DEVMETHOD(ppbus_read,           ppc_read),
   76         DEVMETHOD(ppbus_write,          ppc_isa_write),
   77 
   78         { 0, 0 }
   79 };
   80 
   81 static driver_t ppc_isa_driver = {
   82         ppc_driver_name,
   83         ppc_isa_methods,
   84         sizeof(struct ppc_data),
   85 };
   86 
   87 static struct isa_pnp_id lpc_ids[] = {
   88         { 0x0004d041, "Standard parallel printer port" },       /* PNP0400 */
   89         { 0x0104d041, "ECP parallel printer port" },            /* PNP0401 */
   90         { 0 }
   91 };
   92 
   93 static void
   94 ppc_isa_dmadone(struct ppc_data *ppc)
   95 {
   96         isa_dmadone(ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt,
   97             ppc->ppc_dmachan);
   98 }
   99 
  100 int
  101 ppc_isa_attach(device_t dev)
  102 {
  103         struct ppc_data *ppc = device_get_softc(dev);
  104 
  105         if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) {
  106                 /* acquire the DMA channel forever */   /* XXX */
  107                 isa_dma_acquire(ppc->ppc_dmachan);
  108                 isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */
  109                 ppc->ppc_dmadone = ppc_isa_dmadone;
  110         }
  111 
  112         return (ppc_attach(dev));
  113 }
  114 
  115 static int
  116 ppc_isa_probe(device_t dev)
  117 {
  118         device_t parent;
  119         int error;
  120 
  121         parent = device_get_parent(dev);
  122 
  123         error = ISA_PNP_PROBE(parent, dev, lpc_ids);
  124         if (error == ENXIO)
  125                 return (ENXIO);
  126         if (error != 0)         /* XXX shall be set after detection */
  127                 device_set_desc(dev, "Parallel port");
  128 
  129         return (ppc_probe(dev, 0));
  130 }
  131 
  132 /*
  133  * Call this function if you want to send data in any advanced mode
  134  * of your parallel port: FIFO, DMA
  135  *
  136  * If what you want is not possible (no ECP, no DMA...),
  137  * EINVAL is returned
  138  */
  139 int
  140 ppc_isa_write(device_t dev, char *buf, int len, int how)
  141 {
  142         struct ppc_data *ppc = device_get_softc(dev);
  143         char ecr, ecr_sav, ctr, ctr_sav;
  144         int s, error = 0;
  145         int spin;
  146 
  147         PPC_ASSERT_LOCKED(ppc);
  148         if (!(ppc->ppc_avm & PPB_ECP))
  149                 return (EINVAL);
  150         if (ppc->ppc_dmachan == 0)
  151                 return (EINVAL);
  152 
  153 #ifdef PPC_DEBUG
  154         printf("w");
  155 #endif
  156 
  157         ecr_sav = r_ecr(ppc);
  158         ctr_sav = r_ctr(ppc);
  159 
  160         /*
  161          * Send buffer with DMA, FIFO and interrupts
  162          */
  163 
  164         /* byte mode, no intr, no DMA, dir=0, flush fifo */
  165         ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
  166         w_ecr(ppc, ecr);
  167 
  168         /* disable nAck interrupts */
  169         ctr = r_ctr(ppc);
  170         ctr &= ~IRQENABLE;
  171         w_ctr(ppc, ctr);
  172 
  173         ppc->ppc_dmaflags = 0;
  174         ppc->ppc_dmaddr = (caddr_t)buf;
  175         ppc->ppc_dmacnt = (u_int)len;
  176 
  177         switch (ppc->ppc_mode) {
  178         case PPB_COMPATIBLE:
  179                 /* compatible mode with FIFO, no intr, DMA, dir=0 */
  180                 ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
  181                 break;
  182         case PPB_ECP:
  183                 ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
  184                 break;
  185         default:
  186                 error = EINVAL;
  187                 goto error;
  188         }
  189 
  190         w_ecr(ppc, ecr);
  191         ecr = r_ecr(ppc);
  192 
  193         /* enter splhigh() not to be preempted
  194          * by the dma interrupt, we may miss
  195          * the wakeup otherwise
  196          */
  197         s = splhigh();
  198 
  199         ppc->ppc_dmastat = PPC_DMA_INIT;
  200 
  201         /* enable interrupts */
  202         ecr &= ~PPC_SERVICE_INTR;
  203         ppc->ppc_irqstat = PPC_IRQ_DMA;
  204         w_ecr(ppc, ecr);
  205 
  206         isa_dmastart(ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt,
  207                      ppc->ppc_dmachan);
  208         ppc->ppc_dmastat = PPC_DMA_STARTED;
  209 
  210 #ifdef PPC_DEBUG
  211         printf("s%d", ppc->ppc_dmacnt);
  212 #endif
  213 
  214         /* Wait for the DMA completed interrupt. We hope we won't
  215          * miss it, otherwise a signal will be necessary to unlock the
  216          * process.
  217          */
  218         do {
  219                 /* release CPU */
  220                 error = mtx_sleep(ppc, &ppc->ppc_lock, PPBPRI | PCATCH,
  221                     "ppcdma", 0);
  222         } while (error == EWOULDBLOCK);
  223 
  224         splx(s);
  225 
  226         if (error) {
  227 #ifdef PPC_DEBUG
  228                 printf("i");
  229 #endif
  230                 /* stop DMA */
  231                 isa_dmadone(ppc->ppc_dmaflags, ppc->ppc_dmaddr,
  232                             ppc->ppc_dmacnt, ppc->ppc_dmachan);
  233 
  234                 /* no dma, no interrupt, flush the fifo */
  235                 w_ecr(ppc, PPC_ECR_RESET);
  236 
  237                 ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
  238                 goto error;
  239         }
  240 
  241         /* wait for an empty fifo */
  242         while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
  243 
  244                 for (spin=100; spin; spin--)
  245                         if (r_ecr(ppc) & PPC_FIFO_EMPTY)
  246                                 goto fifo_empty;
  247 #ifdef PPC_DEBUG
  248                 printf("Z");
  249 #endif
  250                 error = mtx_sleep(ppc, &ppc->ppc_lock, PPBPRI | PCATCH,
  251                     "ppcfifo", hz / 100);
  252                 if (error != EWOULDBLOCK) {
  253 #ifdef PPC_DEBUG
  254                         printf("I");
  255 #endif
  256                         /* no dma, no interrupt, flush the fifo */
  257                         w_ecr(ppc, PPC_ECR_RESET);
  258 
  259                         ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
  260                         error = EINTR;
  261                         goto error;
  262                 }
  263         }
  264 
  265 fifo_empty:
  266         /* no dma, no interrupt, flush the fifo */
  267         w_ecr(ppc, PPC_ECR_RESET);
  268 
  269 error:
  270         /* PDRQ must be kept unasserted until nPDACK is
  271          * deasserted for a minimum of 350ns (SMC datasheet)
  272          *
  273          * Consequence may be a FIFO that never empty
  274          */
  275         DELAY(1);
  276 
  277         w_ecr(ppc, ecr_sav);
  278         w_ctr(ppc, ctr_sav);
  279         return (error);
  280 }
  281 
  282 DRIVER_MODULE(ppc, isa, ppc_isa_driver, ppc_devclass, 0, 0);

Cache object: b4ec316187aa53cc6fbf9d1e43f7cff2


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