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/misc/ppi/ppi.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, 1998, 1999 Nicolas Souchu, Michael Smith
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: src/sys/dev/ppbus/ppi.c,v 1.21.2.3 2000/08/07 18:24:43 peter Exp $
   27  *
   28  */
   29 #include "opt_ppb_1284.h"
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/module.h>
   34 #include <sys/bus.h>
   35 #include <sys/conf.h>
   36 #include <sys/device.h>
   37 #include <sys/kernel.h>
   38 #include <sys/uio.h>
   39 #include <sys/fcntl.h>
   40 #include <sys/rman.h>
   41 
   42 #include <machine/clock.h>
   43 
   44 #include <bus/ppbus/ppbconf.h>
   45 #include <bus/ppbus/ppb_msq.h>
   46 
   47 #ifdef PERIPH_1284
   48 #include <bus/ppbus/ppb_1284.h>
   49 #endif
   50 
   51 #include "ppi.h"
   52 
   53 #include "ppbus_if.h"
   54 
   55 #include <bus/ppbus/ppbio.h>
   56 
   57 #define BUFSIZE         512
   58 
   59 struct ppi_data {
   60 
   61     int         ppi_unit;
   62     int         ppi_flags;
   63 #define HAVE_PPBUS      (1<<0)
   64 #define HAD_PPBUS       (1<<1)
   65 
   66     int         ppi_count;
   67     int         ppi_mode;                       /* IEEE1284 mode */
   68     char        ppi_buffer[BUFSIZE];
   69 
   70 #ifdef PERIPH_1284
   71     struct resource *intr_resource;     /* interrupt resource */
   72     void *intr_cookie;                  /* interrupt registration cookie */
   73 #endif /* PERIPH_1284 */
   74 };
   75 
   76 #define DEVTOSOFTC(dev) \
   77         ((struct ppi_data *)device_get_softc(dev))
   78 #define UNITOSOFTC(unit) \
   79         ((struct ppi_data *)devclass_get_softc(ppi_devclass, (unit)))
   80 #define UNITODEVICE(unit) \
   81         (devclass_get_device(ppi_devclass, (unit)))
   82 
   83 static devclass_t ppi_devclass;
   84 
   85 static  d_open_t        ppiopen;
   86 static  d_close_t       ppiclose;
   87 static  d_ioctl_t       ppiioctl;
   88 static  d_write_t       ppiwrite;
   89 static  d_read_t        ppiread;
   90 
   91 static struct dev_ops ppi_ops = {
   92         { "ppi", 0, 0 },
   93         .d_open =       ppiopen,
   94         .d_close =      ppiclose,
   95         .d_read =       ppiread,
   96         .d_write =      ppiwrite,
   97         .d_ioctl =      ppiioctl,
   98 };
   99 
  100 #ifdef PERIPH_1284
  101 
  102 static void
  103 ppi_enable_intr(device_t ppidev)
  104 {
  105         char r;
  106         device_t ppbus = device_get_parent(ppidev);
  107 
  108         r = ppb_rctr(ppbus);
  109         ppb_wctr(ppbus, r | IRQENABLE);
  110 
  111         return;
  112 }
  113 
  114 static void
  115 ppi_disable_intr(device_t ppidev)
  116 {
  117         char r;
  118         device_t ppbus = device_get_parent(ppidev);
  119 
  120         r = ppb_rctr(ppbus);
  121         ppb_wctr(ppbus, r & ~IRQENABLE);
  122 
  123         return;
  124 }
  125 
  126 #endif /* PERIPH_1284 */
  127 
  128 /*
  129  * ppi_probe()
  130  */
  131 static int
  132 ppi_probe(device_t dev)
  133 {
  134         struct ppi_data *ppi;
  135 
  136         /* probe is always ok */
  137         device_set_desc(dev, "Parallel I/O");
  138 
  139         ppi = DEVTOSOFTC(dev);
  140         bzero(ppi, sizeof(struct ppi_data));
  141 
  142         return (0);
  143 }
  144 
  145 /*
  146  * ppi_attach()
  147  */
  148 static int
  149 ppi_attach(device_t dev)
  150 {
  151 #ifdef PERIPH_1284
  152         uintptr_t irq;
  153         int zero = 0;
  154         struct ppi_data *ppi = DEVTOSOFTC(dev);
  155 
  156         /* retrive the irq */
  157         BUS_READ_IVAR(device_get_parent(dev), dev, PPBUS_IVAR_IRQ, &irq);
  158 
  159         /* declare our interrupt handler */
  160         ppi->intr_resource = bus_alloc_legacy_irq_resource(dev, &zero, irq,
  161             RF_ACTIVE);
  162 #endif /* PERIPH_1284 */
  163 
  164         make_dev(&ppi_ops, device_get_unit(dev),        /* XXX cleanup */
  165                  UID_ROOT, GID_WHEEL,
  166                  0600, "ppi%d", device_get_unit(dev));
  167 
  168         return (0);
  169 }
  170 
  171 #ifdef PERIPH_1284
  172 /*
  173  * Cable
  174  * -----
  175  *
  176  * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
  177  *
  178  * nStrobe   <-> nAck           1  <-> 10
  179  * nAutofd   <-> Busy           11 <-> 14
  180  * nSelectin <-> Select         17 <-> 13
  181  * nInit     <-> nFault         15 <-> 16
  182  *
  183  */
  184 static void
  185 ppiintr(void *arg)
  186 {
  187         device_t ppidev = (device_t)arg;
  188         device_t ppbus = device_get_parent(ppidev);
  189         struct ppi_data *ppi = DEVTOSOFTC(ppidev);
  190 
  191         ppi_disable_intr(ppidev);
  192 
  193         switch (ppb_1284_get_state(ppbus)) {
  194 
  195         /* accept IEEE1284 negociation then wakeup an waiting process to
  196          * continue negociation at process level */
  197         case PPB_FORWARD_IDLE:
  198                 /* Event 1 */
  199                 if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) ==
  200                                                         (SELECT | nBUSY)) {
  201                         /* IEEE1284 negociation */
  202 #ifdef DEBUG_1284
  203                         kprintf("N");
  204 #endif
  205 
  206                         /* Event 2 - prepare for reading the ext. value */
  207                         ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN);
  208 
  209                         ppb_1284_set_state(ppbus, PPB_NEGOCIATION);
  210 
  211                 } else {
  212 #ifdef DEBUG_1284
  213                         kprintf("0x%x", ppb_rstr(ppbus));
  214 #endif
  215                         ppb_peripheral_terminate(ppbus, PPB_DONTWAIT);
  216                         break;
  217                 }
  218 
  219                 /* wake up any process waiting for negociation from
  220                  * remote master host */
  221 
  222                 /* XXX should set a variable to warn the process about
  223                  * the interrupt */
  224 
  225                 wakeup(ppi);
  226                 break;
  227         default:
  228 #ifdef DEBUG_1284
  229                 kprintf("?%d", ppb_1284_get_state(ppbus));
  230 #endif
  231                 ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE);
  232                 ppb_set_mode(ppbus, PPB_COMPATIBLE);
  233                 break;
  234         }
  235 
  236         ppi_enable_intr(ppidev);
  237 
  238         return;
  239 }
  240 #endif /* PERIPH_1284 */
  241 
  242 static int
  243 ppiopen(struct dev_open_args *ap)
  244 {
  245         cdev_t dev = ap->a_head.a_dev;
  246         u_int unit = minor(dev);
  247         struct ppi_data *ppi = UNITOSOFTC(unit);
  248         device_t ppidev = UNITODEVICE(unit);
  249         device_t ppbus = device_get_parent(ppidev);
  250         int res;
  251 
  252         if (!ppi)
  253                 return (ENXIO);
  254 
  255         if (!(ppi->ppi_flags & HAVE_PPBUS)) {
  256                 if ((res = ppb_request_bus(ppbus, ppidev,
  257                         (ap->a_oflags & O_NONBLOCK) ? PPB_DONTWAIT :
  258                                                 (PPB_WAIT | PPB_INTR))))
  259                         return (res);
  260 
  261                 ppi->ppi_flags |= HAVE_PPBUS;
  262 
  263 #ifdef PERIPH_1284
  264                 if (ppi->intr_resource) {
  265                         /* register our interrupt handler */
  266                         BUS_SETUP_INTR(device_get_parent(ppidev), ppidev,
  267                                        ppi->intr_resource, 0,
  268                                        ppiintr, dev, 
  269                                        &ppi->intr_cookie, NULL, NULL);
  270                 }
  271 #endif /* PERIPH_1284 */
  272         }
  273         ppi->ppi_count += 1;
  274 
  275         return (0);
  276 }
  277 
  278 static int
  279 ppiclose(struct dev_close_args *ap)
  280 {
  281         cdev_t dev = ap->a_head.a_dev;
  282         u_int unit = minor(dev);
  283         struct ppi_data *ppi = UNITOSOFTC(unit);
  284         device_t ppidev = UNITODEVICE(unit);
  285         device_t ppbus = device_get_parent(ppidev);
  286 
  287         ppi->ppi_count --;
  288         if (!ppi->ppi_count) {
  289 
  290 #ifdef PERIPH_1284
  291                 switch (ppb_1284_get_state(ppbus)) {
  292                 case PPB_PERIPHERAL_IDLE:
  293                         ppb_peripheral_terminate(ppbus, 0);
  294                         break;
  295                 case PPB_REVERSE_IDLE:
  296                 case PPB_EPP_IDLE:
  297                 case PPB_ECP_FORWARD_IDLE:
  298                 default:
  299                         ppb_1284_terminate(ppbus);
  300                         break;
  301                 }
  302 #endif /* PERIPH_1284 */
  303 
  304                 /* unregistration of interrupt forced by release */
  305                 ppb_release_bus(ppbus, ppidev);
  306 
  307                 ppi->ppi_flags &= ~HAVE_PPBUS;
  308         }
  309 
  310         return (0);
  311 }
  312 
  313 /*
  314  * ppiread()
  315  *
  316  * IEEE1284 compliant read.
  317  *
  318  * First, try negociation to BYTE then NIBBLE mode
  319  * If no data is available, wait for it otherwise transfer as much as possible
  320  */
  321 static int
  322 ppiread(struct dev_read_args *ap)
  323 {
  324 #ifdef PERIPH_1284
  325         cdev_t dev = ap->a_head.a_dev;
  326         struct uio *uio = ap->a_uio;
  327         u_int unit = minor(dev);
  328         struct ppi_data *ppi = UNITOSOFTC(unit);
  329         device_t ppidev = UNITODEVICE(unit);
  330         device_t ppbus = device_get_parent(ppidev);
  331         int len, error = 0;
  332 
  333         switch (ppb_1284_get_state(ppbus)) {
  334         case PPB_PERIPHERAL_IDLE:
  335                 ppb_peripheral_terminate(ppbus, 0);
  336                 /* fall throught */
  337 
  338         case PPB_FORWARD_IDLE:
  339                 /* if can't negociate NIBBLE mode then try BYTE mode,
  340                  * the peripheral may be a computer
  341                  */
  342                 if ((ppb_1284_negociate(ppbus,
  343                         ppi->ppi_mode = PPB_NIBBLE, 0))) {
  344 
  345                         /* XXX Wait 2 seconds to let the remote host some
  346                          * time to terminate its interrupt
  347                          */
  348                         tsleep(ppi, 0, "ppiread", 2*hz);
  349                         
  350                         if ((error = ppb_1284_negociate(ppbus,
  351                                 ppi->ppi_mode = PPB_BYTE, 0)))
  352                                 return (error);
  353                 }
  354                 break;
  355 
  356         case PPB_REVERSE_IDLE:
  357         case PPB_EPP_IDLE:
  358         case PPB_ECP_FORWARD_IDLE:
  359         default:
  360                 break;
  361         }
  362 
  363 #ifdef DEBUG_1284
  364         kprintf("N");
  365 #endif
  366         /* read data */
  367         len = 0;
  368         while (uio->uio_resid) {
  369                 error = ppb_1284_read(ppbus, ppi->ppi_mode, ppi->ppi_buffer,
  370                                      (int)szmin(BUFSIZE, uio->uio_resid),
  371                                      &len);
  372                 if (error)
  373                         goto error;
  374 
  375                 if (!len)
  376                         goto error;             /* no more data */
  377 
  378 #ifdef DEBUG_1284
  379                 kprintf("d");
  380 #endif
  381                 if ((error = uiomove(ppi->ppi_buffer, (size_t)len, uio)))
  382                         goto error;
  383         }
  384 
  385 error:
  386 
  387 #else /* PERIPH_1284 */
  388         int error = ENODEV;
  389 #endif
  390 
  391         return (error);
  392 }
  393 
  394 /*
  395  * ppiwrite()
  396  *
  397  * IEEE1284 compliant write
  398  *
  399  * Actually, this is the peripheral side of a remote IEEE1284 read
  400  *
  401  * The first part of the negociation (IEEE1284 device detection) is
  402  * done at interrupt level, then the remaining is done by the writing
  403  * process
  404  *
  405  * Once negociation done, transfer data
  406  */
  407 static int
  408 ppiwrite(struct dev_write_args *ap)
  409 {
  410 #ifdef PERIPH_1284
  411         cdev_t dev = ap->a_head.a_dev;
  412         struct uio *uio = ap->a_uio;
  413         u_int unit = minor(dev);
  414         struct ppi_data *ppi = UNITOSOFTC(unit);
  415         device_t ppidev = UNITODEVICE(unit);
  416         device_t ppbus = device_get_parent(ppidev);
  417         int len, error = 0, sent;
  418 
  419 #if 0
  420         int ret;
  421 
  422         #define ADDRESS         MS_PARAM(0, 0, MS_TYP_PTR)
  423         #define LENGTH          MS_PARAM(0, 1, MS_TYP_INT)
  424 
  425         struct ppb_microseq msq[] = {
  426                   { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
  427                   MS_RET(0)
  428         };
  429 
  430         /* negociate ECP mode */
  431         if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) {
  432                 kprintf("ppiwrite: ECP negotiation failed\n");
  433         }
  434 
  435         while (!error && (len = (int)szmin(uio->uio_resid, BUFSIZE))) {
  436                 uiomove(ppi->ppi_buffer, (size_t)len, uio);
  437 
  438                 ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
  439 
  440                 error = ppb_MS_microseq(ppbus, msq, &ret);
  441         }
  442 #endif
  443 
  444         /* we have to be peripheral to be able to send data, so
  445          * wait for the appropriate state
  446          */
  447         if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION)
  448                 ppb_1284_terminate(ppbus);
  449 
  450         while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) {
  451                 /* XXX should check a variable before sleeping */
  452 #ifdef DEBUG_1284
  453                 kprintf("s");
  454 #endif
  455 
  456                 ppi_enable_intr(ppidev);
  457 
  458                 /* sleep until IEEE1284 negociation starts */
  459                 error = tsleep(ppi, PCATCH, "ppiwrite", 0);
  460 
  461                 switch (error) {
  462                 case 0:
  463                         /* negociate peripheral side with BYTE mode */
  464                         ppb_peripheral_negociate(ppbus, PPB_BYTE, 0);
  465                         break;
  466                 case EWOULDBLOCK:
  467                         break;
  468                 default:
  469                         goto error;
  470                 }
  471         }
  472 #ifdef DEBUG_1284
  473         kprintf("N");
  474 #endif
  475 
  476         /* negociation done, write bytes to master host */
  477         while ((len = (int)szmin(uio->uio_resid, BUFSIZE)) != 0) {
  478                 uiomove(ppi->ppi_buffer, (size_t)len, uio);
  479                 if ((error = byte_peripheral_write(ppbus,
  480                                                 ppi->ppi_buffer, len, &sent)))
  481                         goto error;
  482 #ifdef DEBUG_1284
  483                 kprintf("d");
  484 #endif
  485         }
  486 
  487 error:
  488 
  489 #else /* PERIPH_1284 */
  490         int error = ENODEV;
  491 #endif
  492 
  493         return (error);
  494 }
  495 
  496 static int
  497 ppiioctl(struct dev_ioctl_args *ap)
  498 {
  499         cdev_t dev = ap->a_head.a_dev;
  500         u_int unit = minor(dev);
  501         device_t ppidev = UNITODEVICE(unit);
  502         device_t ppbus = device_get_parent(ppidev);
  503         int error = 0;
  504         u_int8_t *val = (u_int8_t *)ap->a_data;
  505 
  506         switch (ap->a_cmd) {
  507         case PPIGDATA:                  /* get data register */
  508                 *val = ppb_rdtr(ppbus);
  509                 break;
  510         case PPIGSTATUS:                /* get status bits */
  511                 *val = ppb_rstr(ppbus);
  512                 break;
  513         case PPIGCTRL:                  /* get control bits */
  514                 *val = ppb_rctr(ppbus);
  515                 break;
  516         case PPIGEPPD:                  /* get EPP data bits */
  517                 *val = ppb_repp_D(ppbus);
  518                 break;
  519         case PPIGECR:                   /* get ECP bits */
  520                 *val = ppb_recr(ppbus);
  521                 break;
  522         case PPIGFIFO:                  /* read FIFO */
  523                 *val = ppb_rfifo(ppbus);
  524                 break;
  525         case PPISDATA:                  /* set data register */
  526                 ppb_wdtr(ppbus, *val);
  527                 break;
  528         case PPISSTATUS:                /* set status bits */
  529                 ppb_wstr(ppbus, *val);
  530                 break;
  531         case PPISCTRL:                  /* set control bits */
  532                 ppb_wctr(ppbus, *val);
  533                 break;
  534         case PPISEPPD:                  /* set EPP data bits */
  535                 ppb_wepp_D(ppbus, *val);
  536                 break;
  537         case PPISECR:                   /* set ECP bits */
  538                 ppb_wecr(ppbus, *val);
  539                 break;
  540         case PPISFIFO:                  /* write FIFO */
  541                 ppb_wfifo(ppbus, *val);
  542                 break;
  543         case PPIGEPPA:                  /* get EPP address bits */
  544                 *val = ppb_repp_A(ppbus);
  545                 break;
  546         case PPISEPPA:                  /* set EPP address bits */
  547                 ppb_wepp_A(ppbus, *val);
  548                 break;
  549         default:
  550                 error = ENOTTY;
  551                 break;
  552         }
  553     
  554         return (error);
  555 }
  556 
  557 /*
  558  * Because ppi is a static device under any attached ppbuf, and not
  559  * scanned by the ppbuf, we need an identify function to create the
  560  * device.
  561  */
  562 static device_method_t ppi_methods[] = {
  563         /* device interface */
  564         DEVMETHOD(device_identify,      bus_generic_identify),
  565         DEVMETHOD(device_probe,         ppi_probe),
  566         DEVMETHOD(device_attach,        ppi_attach),
  567 
  568         DEVMETHOD_END
  569 };
  570 
  571 static driver_t ppi_driver = {
  572         "ppi",
  573         ppi_methods,
  574         sizeof(struct ppi_data),
  575 };
  576 DRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, NULL, NULL);

Cache object: 53c75c8849c877fc294bbb6a7afec45a


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