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

Cache object: 89f62db8ecef2909a347aa5b47b813a8


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