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/pbio/pbio.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) 2000-2004
    5  *          Diomidis D. Spinellis, Athens, Greece
    6  *      All rights reserved.
    7  *
    8  *  Redistribution and use in source and binary forms, with or without
    9  *  modification, are permitted provided that the following conditions
   10  *  are met:
   11  *  1. Redistributions of source code must retain the above copyright
   12  *     notice, this list of conditions and the following disclaimer as
   13  *     the first lines of this file unmodified.
   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 Diomidis D. Spinellis ``AS IS'' AND ANY
   19  *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   21  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL Diomidis D. Spinellis BE
   22  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   23  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   24  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   25  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   26  *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   27  *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   28  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  * $Id: pbio.c,v 1.12 2003/10/11 13:05:08 dds Exp dds $
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>         /* SYSINIT stuff */
   39 #include <sys/bus.h>
   40 #include <sys/resource.h>
   41 #include <sys/syslog.h>
   42 #include <sys/sysctl.h>
   43 #include <sys/conf.h>           /* cdevsw stuff */
   44 #include <sys/malloc.h>         /* malloc region definitions */
   45 #include <sys/module.h>
   46 #include <machine/bus.h>
   47 #include <machine/resource.h>
   48 #include <sys/rman.h>
   49 #include <dev/pbio/pbioio.h>            /* pbio IOCTL definitions */
   50 #include <sys/uio.h>
   51 #include <sys/fcntl.h>
   52 #include <sys/sx.h>
   53 #include <isa/isavar.h>
   54 
   55 /* Function prototypes (these should all be static) */
   56 static  d_open_t        pbioopen;
   57 static  d_read_t        pbioread;
   58 static  d_write_t       pbiowrite;
   59 static  d_ioctl_t       pbioioctl;
   60 static  d_poll_t        pbiopoll;
   61 static  int             pbioprobe(device_t);
   62 static  int             pbioattach(device_t);
   63 
   64 /* Device registers */
   65 #define PBIO_PORTA      0
   66 #define PBIO_PORTB      1
   67 #define PBIO_PORTC      2
   68 #define PBIO_CFG        3
   69 #define PBIO_IOSIZE     4
   70 
   71 /* Per-port buffer size */
   72 #define PBIO_BUFSIZ 64
   73 
   74 /* Number of /dev entries */
   75 #define PBIO_NPORTS 4
   76 
   77 /* I/O port range */
   78 #define IO_PBIOSIZE 4
   79 
   80 static char *port_names[] = {"a", "b", "ch", "cl"};
   81 
   82 #define PBIO_PNAME(n)           (port_names[(n)])
   83 
   84 #define PORT(dev)               (dev2unit(dev))
   85 
   86 #define pbio_addr(dev)          ((dev)->si_drv1)
   87 
   88 static struct cdevsw pbio_cdevsw = {
   89         .d_version = D_VERSION,
   90         .d_open = pbioopen,
   91         .d_read = pbioread,
   92         .d_write = pbiowrite,
   93         .d_ioctl = pbioioctl,
   94         .d_poll = pbiopoll,
   95         .d_name = "pbio"
   96 };
   97 
   98 /*
   99  * Data specific to each I/O port
  100  */
  101 struct portdata {
  102         struct cdev *port;
  103         int     diff;                   /* When true read only differences */
  104         int     ipace;                  /* Input pace */
  105         int     opace;                  /* Output pace */
  106         char    oldval;                 /* Last value read */
  107         char    buff[PBIO_BUFSIZ];      /* Per-port data buffer */
  108 };
  109 
  110 /*
  111  * One of these per allocated device
  112  */
  113 struct pbio_softc {
  114         struct portdata pd[PBIO_NPORTS];/* Per port data */
  115         int     iomode;                 /* Virtualized I/O mode port value */
  116                                         /* The real port is write-only */
  117         struct resource *res;
  118         struct sx lock;
  119 };
  120 
  121 typedef struct pbio_softc *sc_p;
  122 
  123 static device_method_t pbio_methods[] = {
  124         /* Device interface */
  125         DEVMETHOD(device_probe,         pbioprobe),
  126         DEVMETHOD(device_attach,        pbioattach),
  127         { 0, 0 }
  128 };
  129 
  130 static char driver_name[] = "pbio";
  131 
  132 static driver_t pbio_driver = {
  133         driver_name,
  134         pbio_methods,
  135         sizeof(struct pbio_softc),
  136 };
  137 
  138 DRIVER_MODULE(pbio, isa, pbio_driver, 0, 0);
  139 
  140 static __inline uint8_t
  141 pbinb(struct pbio_softc *scp, int off)
  142 {
  143 
  144         return (bus_read_1(scp->res, off));
  145 }
  146 
  147 static __inline void
  148 pboutb(struct pbio_softc *scp, int off, uint8_t val)
  149 {
  150 
  151         bus_write_1(scp->res, off, val);
  152 }
  153 
  154 static int
  155 pbioprobe(device_t dev)
  156 {
  157         int             rid;
  158         struct pbio_softc *scp = device_get_softc(dev);
  159 #ifdef GENERIC_PBIO_PROBE
  160         unsigned char val;
  161 #endif
  162 
  163         if (isa_get_logicalid(dev))             /* skip PnP probes */
  164                 return (ENXIO);
  165         rid = 0;
  166         scp->res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
  167             IO_PBIOSIZE, RF_ACTIVE);
  168         if (scp->res == NULL)
  169                 return (ENXIO);
  170 
  171 #ifdef GENERIC_PBIO_PROBE
  172         /*
  173          * try see if the device is there.
  174          * This probe works only if the device has no I/O attached to it
  175          * XXX Better allow flags to abort testing
  176          */
  177         /* Set all ports to output */
  178         pboutb(scp, PBIO_CFG, 0x80);
  179         printf("pbio val(CFG: 0x%03x)=0x%02x (should be 0x80)\n",
  180                 rman_get_start(scp->res), pbinb(scp, PBIO_CFG));
  181         pboutb(scp, PBIO_PORTA, 0xa5);
  182         val = pbinb(scp, PBIO_PORTA);
  183         printf("pbio val=0x%02x (should be 0xa5)\n", val);
  184         if (val != 0xa5) {
  185                 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->res);
  186                 return (ENXIO);
  187         }
  188         pboutb(scp, PBIO_PORTA, 0x5a);
  189         val = pbinb(scp, PBIO_PORTA);
  190         printf("pbio val=0x%02x (should be 0x5a)\n", val);
  191         if (val != 0x5a) {
  192                 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->res);
  193                 return (ENXIO);
  194         }
  195 #endif
  196         device_set_desc(dev, "Intel 8255 PPI (basic mode)");
  197         /* Set all ports to input */
  198         /* pboutb(scp, PBIO_CFG, 0x9b); */
  199         bus_release_resource(dev, SYS_RES_IOPORT, rid, scp->res);
  200         return (BUS_PROBE_DEFAULT);
  201 }
  202 
  203 /*
  204  * Called if the probe succeeded.
  205  * We can be destructive here as we know we have the device.
  206  * we can also trust the unit number.
  207  */
  208 static int
  209 pbioattach (device_t dev)
  210 {
  211         struct make_dev_args args;
  212         int unit;
  213         int i;
  214         int             rid;
  215         struct pbio_softc *sc;
  216 
  217         sc = device_get_softc(dev);
  218         unit = device_get_unit(dev);
  219         rid = 0;
  220         sc->res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
  221             IO_PBIOSIZE, RF_ACTIVE);
  222         if (sc->res == NULL)
  223                 return (ENXIO);
  224 
  225         /*
  226          * Store whatever seems wise.
  227          */
  228         sc->iomode = 0x9b;              /* All ports to input */
  229 
  230         sx_init(&sc->lock, "pbio");
  231         for (i = 0; i < PBIO_NPORTS; i++) {
  232                 make_dev_args_init(&args);
  233                 args.mda_devsw = &pbio_cdevsw;
  234                 args.mda_uid = 0;
  235                 args.mda_gid = 0;
  236                 args.mda_mode = 0600;
  237                 args.mda_unit = i;
  238                 args.mda_si_drv1 = sc;
  239                 (void)make_dev_s(&args, &sc->pd[i].port, "pbio%d%s", unit,
  240                     PBIO_PNAME(i));
  241         }
  242         return (0);
  243 }
  244 
  245 static int
  246 pbioioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag,
  247     struct thread *td)
  248 {
  249         struct pbio_softc *scp;
  250         int error, port;
  251 
  252         error = 0;
  253         port = PORT(dev);
  254         scp = pbio_addr(dev);
  255         sx_xlock(&scp->lock);
  256         switch (cmd) {
  257         case PBIO_SETDIFF:
  258                 scp->pd[port].diff = *(int *)data;
  259                 break;
  260         case PBIO_SETIPACE:
  261                 scp->pd[port].ipace = *(int *)data;
  262                 break;
  263         case PBIO_SETOPACE:
  264                 scp->pd[port].opace = *(int *)data;
  265                 break;
  266         case PBIO_GETDIFF:
  267                 *(int *)data = scp->pd[port].diff;
  268                 break;
  269         case PBIO_GETIPACE:
  270                 *(int *)data = scp->pd[port].ipace;
  271                 break;
  272         case PBIO_GETOPACE:
  273                 *(int *)data = scp->pd[port].opace;
  274                 break;
  275         default:
  276                 error = ENXIO;
  277         }
  278         sx_xunlock(&scp->lock);
  279         return (error);
  280 }
  281 
  282 static  int
  283 pbioopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
  284 {
  285         struct pbio_softc *scp;
  286         int error, ocfg, port;
  287         int portbit;                    /* Port configuration bit */
  288 
  289         port = PORT(dev);
  290         scp = pbio_addr(dev);
  291 
  292         switch (port) {
  293         case 0: portbit = 0x10; break;  /* Port A */
  294         case 1: portbit = 0x02; break;  /* Port B */
  295         case 2: portbit = 0x08; break;  /* Port CH */
  296         case 3: portbit = 0x01; break;  /* Port CL */
  297         default: return (ENODEV);
  298         }
  299         ocfg = scp->iomode;
  300 
  301         error = 0;
  302         sx_xlock(&scp->lock);
  303         if (oflags & FWRITE)
  304                 /* Writing == output; zero the bit */
  305                 pboutb(scp, PBIO_CFG, scp->iomode = (ocfg & (~portbit)));
  306         else if (oflags & FREAD)
  307                 /* Reading == input; set the bit */
  308                 pboutb(scp, PBIO_CFG, scp->iomode = (ocfg | portbit));
  309         else
  310                 error = EACCES;
  311         sx_xunlock(&scp->lock);
  312 
  313         return (error);
  314 }
  315 
  316 /*
  317  * Return the value of a given port on a given I/O base address
  318  * Handles the split C port nibbles and blocking
  319  */
  320 static int
  321 portval(int port, struct pbio_softc *scp, char *val)
  322 {
  323         int err;
  324 
  325         for (;;) {
  326                 switch (port) {
  327                 case 0:
  328                         *val = pbinb(scp, PBIO_PORTA);
  329                         break;
  330                 case 1:
  331                         *val = pbinb(scp, PBIO_PORTB);
  332                         break;
  333                 case 2:
  334                         *val = (pbinb(scp, PBIO_PORTC) >> 4) & 0xf;
  335                         break;
  336                 case 3:
  337                         *val = pbinb(scp, PBIO_PORTC) & 0xf;
  338                         break;
  339                 default:
  340                         *val = 0;
  341                         break;
  342                 }
  343                 if (scp->pd[port].diff) {
  344                         if (*val != scp->pd[port].oldval) {
  345                                 scp->pd[port].oldval = *val;
  346                                 return (0);
  347                         }
  348                         err = pause_sig("pbiopl", max(1, scp->pd[port].ipace));
  349                         if (err == EINTR)
  350                                 return (EINTR);
  351                 } else
  352                         return (0);
  353         }
  354 }
  355 
  356 static  int
  357 pbioread(struct cdev *dev, struct uio *uio, int ioflag)
  358 {
  359         struct pbio_softc *scp;
  360         int err, i, port, toread;
  361         char val;
  362 
  363         port = PORT(dev);
  364         scp = pbio_addr(dev);
  365 
  366         err = 0;
  367         sx_xlock(&scp->lock);
  368         while (uio->uio_resid > 0) {
  369                 toread = min(uio->uio_resid, PBIO_BUFSIZ);
  370                 if ((err = uiomove(scp->pd[port].buff, toread, uio)) != 0)
  371                         break;
  372                 for (i = 0; i < toread; i++) {
  373                         if ((err = portval(port, scp, &val)) != 0)
  374                                 break;
  375                         scp->pd[port].buff[i] = val;
  376                         if (!scp->pd[port].diff && scp->pd[port].ipace)
  377                                 pause_sig("pbioip", scp->pd[port].ipace);
  378                 }
  379         }
  380         sx_xunlock(&scp->lock);
  381         return (err);
  382 }
  383 
  384 static int
  385 pbiowrite(struct cdev *dev, struct uio *uio, int ioflag)
  386 {
  387         struct pbio_softc *scp;
  388         int i, port, ret, towrite;
  389         char val, oval;
  390 
  391         port = PORT(dev);
  392         scp = pbio_addr(dev);
  393 
  394         ret = 0;
  395         sx_xlock(&scp->lock);
  396         while (uio->uio_resid > 0) {
  397                 towrite = min(uio->uio_resid, PBIO_BUFSIZ);
  398                 if ((ret = uiomove(scp->pd[port].buff, towrite, uio)) != 0)
  399                         break;
  400                 for (i = 0; i < towrite; i++) {
  401                         val = scp->pd[port].buff[i];
  402                         switch (port) {
  403                         case 0:
  404                                 pboutb(scp, PBIO_PORTA, val);
  405                                 break;
  406                         case 1:
  407                                 pboutb(scp, PBIO_PORTB, val);
  408                                 break;
  409                         case 2:
  410                                 oval = pbinb(scp, PBIO_PORTC);
  411                                 oval &= 0xf;
  412                                 val <<= 4;
  413                                 pboutb(scp, PBIO_PORTC, val | oval);
  414                                 break;
  415                         case 3:
  416                                 oval = pbinb(scp, PBIO_PORTC);
  417                                 oval &= 0xf0;
  418                                 val &= 0xf;
  419                                 pboutb(scp, PBIO_PORTC, oval | val);
  420                                 break;
  421                         }
  422                         if (scp->pd[port].opace)
  423                                 pause_sig("pbioop", scp->pd[port].opace);
  424                 }
  425         }
  426         sx_xunlock(&scp->lock);
  427         return (ret);
  428 }
  429 
  430 static  int
  431 pbiopoll(struct cdev *dev, int which, struct thread *td)
  432 {
  433         /*
  434          * Do processing
  435          */
  436         return (0); /* this is the wrong value I'm sure */
  437 }

Cache object: 5a2c1bdbafe6efaa7e68c86688537bac


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