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

Cache object: 61091a0a9b79965d9ea7cd175d6c5493


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