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/ppbus/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 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$
   27  *
   28  */
   29 #include "ppi.h"
   30 
   31 #if NPPI > 0
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/conf.h>
   36 #include <sys/kernel.h>
   37 #include <sys/uio.h>
   38 #include <sys/malloc.h>
   39 #include <sys/fcntl.h>
   40 
   41 #include <machine/clock.h>
   42 
   43 #include <dev/ppbus/ppbconf.h>
   44 #include <dev/ppbus/ppb_msq.h>
   45 
   46 #include "opt_ppb_1284.h"
   47 
   48 #ifdef PERIPH_1284
   49 #include <dev/ppbus/ppb_1284.h>
   50 #endif
   51 
   52 #include <dev/ppbus/ppi.h>
   53 
   54 #define BUFSIZE         512
   55 
   56 struct ppi_data {
   57 
   58     int         ppi_unit;
   59     int         ppi_flags;
   60 #define HAVE_PPBUS      (1<<0)
   61 #define HAD_PPBUS       (1<<1)
   62 
   63     int         ppi_count;
   64     int         ppi_mode;                       /* IEEE1284 mode */
   65     char        ppi_buffer[BUFSIZE];
   66 
   67     struct ppb_device ppi_dev;
   68 };
   69 
   70 #define MAXPPI          8                       /* XXX not much better! */
   71 static int              nppi = 0;
   72 static struct ppi_data  *ppidata[MAXPPI];
   73 
   74 /*
   75  * Make ourselves visible as a ppbus driver
   76  */
   77 
   78 static struct ppb_device        *ppiprobe(struct ppb_data *ppb);
   79 static int                      ppiattach(struct ppb_device *dev);
   80 static void                     ppiintr(int unit);
   81 
   82 static struct ppb_driver ppidriver = {
   83     ppiprobe, ppiattach, "ppi"
   84 };
   85 DATA_SET(ppbdriver_set, ppidriver);
   86 
   87 static  d_open_t        ppiopen;
   88 static  d_close_t       ppiclose;
   89 static  d_ioctl_t       ppiioctl;
   90 static  d_write_t       ppiwrite;
   91 static  d_read_t        ppiread;
   92 
   93 #define CDEV_MAJOR 82
   94 static struct cdevsw ppi_cdevsw = 
   95         { ppiopen,      ppiclose,       ppiread,        ppiwrite,       /* 82 */
   96           ppiioctl,     nullstop,       nullreset,      nodevtotty,
   97           seltrue,      nommap,         nostrat,        "ppi",  NULL,   -1 };
   98 
   99 #ifdef PERIPH_1284
  100 
  101 static void
  102 ppi_enable_intr(struct ppi_data *ppi)
  103 {
  104         char r;
  105 
  106         r = ppb_rctr(&ppi->ppi_dev);
  107         ppb_wctr(&ppi->ppi_dev, r | IRQENABLE);
  108 
  109         return;
  110 }
  111 
  112 static void
  113 ppi_disable_intr(struct ppi_data *ppi)
  114 {
  115         char r;
  116 
  117         r = ppb_rctr(&ppi->ppi_dev);
  118         ppb_wctr(&ppi->ppi_dev, r & ~IRQENABLE);
  119 
  120         return;
  121 }
  122 
  123 #endif /* PERIPH_1284 */
  124 
  125 /*
  126  * ppiprobe()
  127  */
  128 static struct ppb_device *
  129 ppiprobe(struct ppb_data *ppb)
  130 {
  131         struct ppi_data *ppi;
  132 
  133         ppi = (struct ppi_data *) malloc(sizeof(struct ppi_data),
  134                                                         M_TEMP, M_NOWAIT);
  135         if (!ppi) {
  136                 printf("ppi: cannot malloc!\n");
  137                 return 0;
  138         }
  139         bzero(ppi, sizeof(struct ppi_data));
  140 
  141         ppidata[nppi] = ppi;
  142 
  143         /*
  144          * ppi dependent initialisation.
  145          */
  146         ppi->ppi_unit = nppi;
  147 
  148         /*
  149          * ppbus dependent initialisation.
  150          */
  151         ppi->ppi_dev.id_unit = ppi->ppi_unit;
  152         ppi->ppi_dev.ppb = ppb;
  153         ppi->ppi_dev.intr = ppiintr;
  154 
  155         /* Ok, go to next device on next probe */
  156         nppi ++;
  157 
  158         return &ppi->ppi_dev;
  159 }
  160 
  161 static int
  162 ppiattach(struct ppb_device *dev)
  163 {
  164         /*
  165          * Report ourselves
  166          */
  167         printf("ppi%d: <generic parallel i/o> on ppbus %d\n",
  168                dev->id_unit, dev->ppb->ppb_link->adapter_unit);
  169 
  170         return (1);
  171 }
  172 
  173 /*
  174  * Cable
  175  * -----
  176  *
  177  * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
  178  *
  179  * nStrobe   <-> nAck           1  <-> 10
  180  * nAutofd   <-> Busy           11 <-> 14
  181  * nSelectin <-> Select         17 <-> 13
  182  * nInit     <-> nFault         15 <-> 16
  183  *
  184  */
  185 static void
  186 ppiintr(int unit)
  187 {
  188 #ifdef PERIPH_1284
  189         struct ppi_data *ppi = ppidata[unit];
  190 
  191         ppi_disable_intr(ppi);
  192 
  193         switch (ppi->ppi_dev.ppb->state) {
  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(&ppi->ppi_dev) & (SELECT | nBUSY)) ==
  200                                                         (SELECT | nBUSY)) {
  201                         /* IEEE1284 negociation */
  202 #ifdef DEBUG_1284
  203                         printf("N");
  204 #endif
  205 
  206                         /* Event 2 - prepare for reading the ext. value */
  207                         ppb_wctr(&ppi->ppi_dev, (PCD | STROBE | nINIT) & ~SELECTIN);
  208 
  209                         ppi->ppi_dev.ppb->state = PPB_NEGOCIATION;
  210 
  211                 } else {
  212 #ifdef DEBUG_1284
  213                         printf("0x%x", ppb_rstr(&ppi->ppi_dev));
  214 #endif
  215                         ppb_peripheral_terminate(&ppi->ppi_dev, 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                 printf("?%d", ppi->ppi_dev.ppb->state);
  230 #endif
  231                 ppi->ppi_dev.ppb->state = PPB_FORWARD_IDLE;
  232                 ppb_set_mode(&ppi->ppi_dev, PPB_COMPATIBLE);
  233                 break;
  234         }
  235 
  236         ppi_enable_intr(ppi);
  237 #endif /* PERIPH_1284 */
  238 
  239         return;
  240 }
  241 
  242 static int
  243 ppiopen(dev_t dev, int flags, int fmt, struct proc *p)
  244 {
  245         u_int unit = minor(dev);
  246         struct ppi_data *ppi = ppidata[unit];
  247         int res;
  248 
  249         if (unit >= nppi)
  250                 return (ENXIO);
  251 
  252         if (!(ppi->ppi_flags & HAVE_PPBUS)) {
  253                 if ((res = ppb_request_bus(&ppi->ppi_dev,
  254                         (flags & O_NONBLOCK) ? PPB_DONTWAIT :
  255                                                 (PPB_WAIT | PPB_INTR))))
  256                         return (res);
  257 
  258                 ppi->ppi_flags |= HAVE_PPBUS;
  259         }
  260         ppi->ppi_count += 1;
  261 
  262         return (0);
  263 }
  264 
  265 static int
  266 ppiclose(dev_t dev, int flags, int fmt, struct proc *p)
  267 {
  268         u_int unit = minor(dev);
  269         struct ppi_data *ppi = ppidata[unit];
  270 
  271         ppi->ppi_count --;
  272         if (!ppi->ppi_count) {
  273 
  274 #ifdef PERIPH_1284
  275                 switch (ppi->ppi_dev.ppb->state) {
  276                 case PPB_PERIPHERAL_IDLE:
  277                         ppb_peripheral_terminate(&ppi->ppi_dev, 0);
  278                         break;
  279                 case PPB_REVERSE_IDLE:
  280                 case PPB_EPP_IDLE:
  281                 case PPB_ECP_FORWARD_IDLE:
  282                 default:
  283                         ppb_1284_terminate(&ppi->ppi_dev);
  284                         break;
  285                 }
  286 #endif /* PERIPH_1284 */
  287 
  288                 ppb_release_bus(&ppi->ppi_dev);
  289                 ppi->ppi_flags &= ~HAVE_PPBUS;
  290         }
  291 
  292         return (0);
  293 }
  294 
  295 /*
  296  * ppiread()
  297  *
  298  * IEEE1284 compliant read.
  299  *
  300  * First, try negociation to BYTE then NIBBLE mode
  301  * If no data is available, wait for it otherwise transfer as much as possible
  302  */
  303 static int
  304 ppiread(dev_t dev, struct uio *uio, int ioflag)
  305 {
  306 #ifdef PERIPH_1284
  307         u_int unit = minor(dev);
  308         struct ppi_data *ppi = ppidata[unit];
  309         int len, error = 0;
  310 
  311         switch (ppi->ppi_dev.ppb->state) {
  312         case PPB_PERIPHERAL_IDLE:
  313                 ppb_peripheral_terminate(&ppi->ppi_dev, 0);
  314                 /* fall throught */
  315 
  316         case PPB_FORWARD_IDLE:
  317                 /* if can't negociate NIBBLE mode then try BYTE mode,
  318                  * the peripheral may be a computer
  319                  */
  320                 if ((ppb_1284_negociate(&ppi->ppi_dev,
  321                         ppi->ppi_mode = PPB_NIBBLE, 0))) {
  322 
  323                         /* XXX Wait 2 seconds to let the remote host some
  324                          * time to terminate its interrupt
  325                          */
  326                         tsleep(ppi, PPBPRI, "ppiread", 2*hz);
  327                         
  328                         if ((error = ppb_1284_negociate(&ppi->ppi_dev,
  329                                 ppi->ppi_mode = PPB_BYTE, 0)))
  330                                 return (error);
  331                 }
  332                 break;
  333 
  334         case PPB_REVERSE_IDLE:
  335         case PPB_EPP_IDLE:
  336         case PPB_ECP_FORWARD_IDLE:
  337         default:
  338                 break;
  339         }
  340 
  341 #ifdef DEBUG_1284
  342         printf("N");
  343 #endif
  344         /* read data */
  345         len = 0;
  346         while (uio->uio_resid) {
  347                 if ((error = ppb_1284_read(&ppi->ppi_dev, ppi->ppi_mode,
  348                         ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
  349                         &len))) {
  350                         goto error;
  351                 }
  352 
  353                 if (!len)
  354                         goto error;             /* no more data */
  355 
  356 #ifdef DEBUG_1284
  357                 printf("d");
  358 #endif
  359                 if ((error = uiomove(ppi->ppi_buffer, len, uio)))
  360                         goto error;
  361         }
  362 
  363 error:
  364 
  365 #else /* PERIPH_1284 */
  366         int error = ENODEV;
  367 #endif
  368 
  369         return (error);
  370 }
  371 
  372 /*
  373  * ppiwrite()
  374  *
  375  * IEEE1284 compliant write
  376  *
  377  * Actually, this is the peripheral side of a remote IEEE1284 read
  378  *
  379  * The first part of the negociation (IEEE1284 device detection) is
  380  * done at interrupt level, then the remaining is done by the writing
  381  * process
  382  *
  383  * Once negociation done, transfer data
  384  */
  385 static int
  386 ppiwrite(dev_t dev, struct uio *uio, int ioflag)
  387 {
  388 #ifdef PERIPH_1284
  389         u_int unit = minor(dev);
  390         struct ppi_data *ppi = ppidata[unit];
  391         struct ppb_data *ppb = ppi->ppi_dev.ppb;
  392         int len, error = 0, sent;
  393 
  394 #if 0
  395         int ret;
  396 
  397         #define ADDRESS         MS_PARAM(0, 0, MS_TYP_PTR)
  398         #define LENGTH          MS_PARAM(0, 1, MS_TYP_INT)
  399 
  400         struct ppb_microseq msq[] = {
  401                   { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
  402                   MS_RET(0)
  403         };
  404 
  405         /* negociate ECP mode */
  406         if (ppb_1284_negociate(&ppi->ppi_dev, PPB_ECP, 0)) {
  407                 printf("ppiwrite: ECP negociation failed\n");
  408         }
  409 
  410         while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
  411                 uiomove(ppi->ppi_buffer, len, uio);
  412 
  413                 ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
  414 
  415                 error = ppb_MS_microseq(&ppi->ppi_dev, msq, &ret);
  416         }
  417 #endif
  418 
  419         /* we have to be peripheral to be able to send data, so
  420          * wait for the appropriate state
  421          */
  422         if (ppb->state < PPB_PERIPHERAL_NEGOCIATION)
  423                 ppb_1284_terminate(&ppi->ppi_dev);
  424 
  425         while (ppb->state != PPB_PERIPHERAL_IDLE) {
  426                 /* XXX should check a variable before sleeping */
  427 #ifdef DEBUG_1284
  428                 printf("s");
  429 #endif
  430 
  431                 ppi_enable_intr(ppi);
  432 
  433                 /* sleep until IEEE1284 negociation starts */
  434                 error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0);
  435 
  436                 switch (error) {
  437                 case 0:
  438                         /* negociate peripheral side with BYTE mode */
  439                         ppb_peripheral_negociate(&ppi->ppi_dev, PPB_BYTE, 0);
  440                         break;
  441                 case EWOULDBLOCK:
  442                         break;
  443                 default:
  444                         goto error;
  445                 }
  446         }
  447 #ifdef DEBUG_1284
  448         printf("N");
  449 #endif
  450 
  451         /* negociation done, write bytes to master host */
  452         while (len = min(uio->uio_resid, BUFSIZE)) {
  453                 uiomove(ppi->ppi_buffer, len, uio);
  454                 if ((error = byte_peripheral_write(&ppi->ppi_dev,
  455                                                 ppi->ppi_buffer, len, &sent)))
  456                         goto error;
  457 #ifdef DEBUG_1284
  458                 printf("d");
  459 #endif
  460         }
  461 
  462 error:
  463 
  464 #else /* PERIPH_1284 */
  465         int error = ENODEV;
  466 #endif
  467 
  468         return (error);
  469 }
  470 
  471 static int
  472 ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  473 {
  474         u_int unit = minor(dev);
  475         struct ppi_data *ppi = ppidata[unit];
  476         int error = 0;
  477         u_int8_t *val = (u_int8_t *)data;
  478 
  479         switch (cmd) {
  480 
  481         case PPIGDATA:                  /* get data register */
  482                 *val = ppb_rdtr(&ppi->ppi_dev);
  483                 break;
  484         case PPIGSTATUS:                /* get status bits */
  485                 *val = ppb_rstr(&ppi->ppi_dev);
  486                 break;
  487         case PPIGCTRL:                  /* get control bits */
  488                 *val = ppb_rctr(&ppi->ppi_dev);
  489                 break;
  490         case PPIGEPP:                   /* get EPP bits */
  491                 *val = ppb_repp(&ppi->ppi_dev);
  492                 break;
  493         case PPIGECR:                   /* get ECP bits */
  494                 *val = ppb_recr(&ppi->ppi_dev);
  495                 break;
  496         case PPIGFIFO:                  /* read FIFO */
  497                 *val = ppb_rfifo(&ppi->ppi_dev);
  498                 break;
  499 
  500         case PPISDATA:                  /* set data register */
  501                 ppb_wdtr(&ppi->ppi_dev, *val);
  502                 break;
  503         case PPISSTATUS:                /* set status bits */
  504                 ppb_wstr(&ppi->ppi_dev, *val);
  505                 break;
  506         case PPISCTRL:                  /* set control bits */
  507                 ppb_wctr(&ppi->ppi_dev, *val);
  508                 break;
  509         case PPISEPP:                   /* set EPP bits */
  510                 ppb_wepp(&ppi->ppi_dev, *val);
  511                 break;
  512         case PPISECR:                   /* set ECP bits */
  513                 ppb_wecr(&ppi->ppi_dev, *val);
  514                 break;
  515         case PPISFIFO:                  /* write FIFO */
  516                 ppb_wfifo(&ppi->ppi_dev, *val);
  517                 break;
  518         default:
  519                 error = ENOTTY;
  520                 break;
  521         }
  522     
  523         return (error);
  524 }
  525 
  526 #ifdef PPI_MODULE
  527 
  528 MOD_DEV(ppi, LM_DT_CHAR, CDEV_MAJOR, &ppi_cdevsw);
  529 
  530 static int
  531 ppi_load(struct lkm_table *lkmtp, int cmd)
  532 {
  533         struct ppb_data *ppb;
  534         struct ppb_device *dev;
  535         int i;
  536 
  537         for (ppb = ppb_next_bus(NULL); ppb; ppb = ppb_next_bus(ppb)) {
  538 
  539                 dev = ppiprobe(ppb);
  540                 ppiattach(dev);
  541 
  542                 ppb_attach_device(dev);
  543         }
  544 
  545         return (0);
  546 }
  547 
  548 static int
  549 ppi_unload(struct lkm_table *lkmtp, int cmd)
  550 {
  551         int i;
  552 
  553         for (i = nppi-1; i > 0; i--) {
  554                 ppb_remove_device(&ppidata[i]->ppi_dev);
  555                 free(ppidata[i], M_TEMP);
  556         }
  557 
  558         return (0);
  559 }
  560 
  561 int
  562 ppi_mod(struct lkm_table *lkmtp, int cmd, int ver)
  563 {
  564         DISPATCH(lkmtp, cmd, ver, ppi_load, ppi_unload, lkm_nullcmd);
  565 }
  566 
  567 #endif /* PPI_MODULE */
  568 
  569 static ppi_devsw_installed = 0;
  570 
  571 static void ppi_drvinit(void *unused)
  572 {
  573         dev_t dev;
  574 
  575         if (!ppi_devsw_installed ) {
  576                 dev = makedev(CDEV_MAJOR, 0);
  577                 cdevsw_add(&dev, &ppi_cdevsw, NULL);
  578                 ppi_devsw_installed = 1;
  579         }
  580 }
  581 
  582 SYSINIT(ppidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ppi_drvinit,NULL)
  583 
  584 #endif /* NPPI */

Cache object: 5f3f4b8c3fbef3119bec0fd27c3fc66d


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