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/ctx.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  * CORTEX-I Frame Grabber driver V1.0
    3  *
    4  *      Copyright (C) 1994, Paul S. LaFollette, Jr. This software may be used,
    5  *      modified, copied, distributed, and sold, in both source and binary form
    6  *      provided that the above copyright and these terms are retained. Under
    7  *      no circumstances is the author responsible for the proper functioning
    8  *      of this software, nor does the author assume any responsibility
    9  *      for damages incurred with its use.
   10  *
   11  * $FreeBSD$
   12  */
   13 
   14 /*
   15  *
   16  *
   17  *
   18  *      Device Driver for CORTEX-I Frame Grabber
   19  *      Made by ImageNation Corporation
   20  *      1200 N.E. Keyues Road
   21  *      Vancouver, WA 98684  (206) 944-9131
   22  *      (I have no ties to this company, just thought you might want
   23  *       to know how to get in touch with them.)
   24  *
   25  *      In order to understand this device, you really need to consult the
   26  *      manual which ImageNation provides when you buy the board. (And
   27  *      what a pleasure it is to buy something for a PC and actually get
   28  *      programming information along with it.)  I will limit myself here to
   29  *      a few comments which are specific to this driver.  See also the file
   30  *      ctxreg.h for definitions of registers and control bits.
   31  *
   32  *      1.  Although the hardware supports low resolution (256 x 256)
   33  *          acqusition and display, I have not implemented access to
   34  *          these modes in this driver.  There are some fairly quirky
   35  *          aspects to the way this board works in low resolution mode,
   36  *          and I don't want to deal with them.  Maybe later.
   37  *
   38  *      2.  Choosing the base address for the video memory:  This is set
   39  *          using a combination of hardware and software, using the left
   40  *          most dip switch on the board, and the AB_SELECT bit of control
   41  *          port 1, according to the chart below:
   42  *
   43  *              Left DIP switch ||      DOWN    |       UP      |
   44  *              =================================================
   45  *               AB_SELECT =  0 ||    0xA0000   |    0xB0000    |
   46  *              -------------------------------------------------
   47  *               AB_SELECT = 1  ||    0xD0000   |    0xE0000    |
   48  *              ------------------------------------------------
   49  *
   50  *          When the RAM_ENABLE bit of control port 1 is clear (0), the
   51  *          video ram is disconnected from the computer bus.  This makes
   52  *          it possible, in principle, to share memory space with other
   53  *          devices (such as VGA) which can also disconnect themselves
   54  *          from the bus.  It also means that multiple CORTEX-I boards
   55  *          can share the same video memory space.  Disconnecting from the
   56  *          bus does not affect the video display of the video ram contents,
   57  *          so that one needs only set the RAM_ENABLE bit when actually
   58  *          reading or writing to memory.  The cost of this is low,
   59  *          the benefits to me are great (I need more than one board
   60  *          in my machine, and 0xE0000 is the only address choice that
   61  *          doesn't conflict with anything) so I adopt this strategy here.
   62  *
   63  *          XXX-Note... this driver has only been tested for the
   64  *          XXX base = 0xE0000 case!
   65  *
   66  *      3)  There is a deficiency in the documentation from ImageNation, I
   67  *          think.  In order to successfully load the lookup table, it is
   68  *          necessary to clear SEE_STORED_VIDEO in control port 0 as well as
   69  *          setting LUT_LOAD_ENABLE in control port 1.
   70  *
   71  *      4)  This driver accesses video memory through read or write operations.
   72  *          Other functionality is provided through ioctl's, manifest
   73  *          constants for which are defined in ioctl_ctx.h. The ioctl's
   74  *          include:
   75  *                      CTX_LIVE        Display live video
   76  *                      CTX_GRAB        Grab a frame of video data
   77  *                      CTX_H_ORGANIZE  Set things up so that sequential read
   78  *                                      operations access horizontal lines of
   79  *                                      pixels.
   80  *                      CTX_V_ORGANIZE  Set things up so that sequential read
   81  *                                      operations access vertical lines of
   82  *                                      pixels.
   83  *                      CTX_SET_LUT     Set the lookup table from an array
   84  *                                      of 256 unsigned chars passed as the
   85  *                                      third parameter to ioctl.
   86  *                      CTX_GET_LUT     Return the current lookup table to
   87  *                                      the application as an array of 256
   88  *                                      unsigned chars.  Again the third
   89  *                                      parameter to the ioctl call.
   90  *
   91  *          Thus,
   92  *              ioctl(fi, CTX_H_ORGANIZE, 0);
   93  *              lseek(fi, y*512, SEEK_SET);
   94  *              read(fi, buffer, 512);
   95  *
   96  *          will fill buffer with 512 pixels (unsigned chars) which represent
   97  *          the y-th horizontal line of the image.
   98  *          Similarly,
   99  *              ioctl(fi, CTX_V_ORGANIZE, 0:
  100  *              lseek(fi, x*512+y, SEEK_SET);
  101  *              read(fi, buffer, 10);
  102  *
  103  *          will read 10 a vertical line of 10 pixels starting at (x,y).
  104  *
  105  *          Obviously, this sort of ugliness needs to be hidden away from
  106  *          the casual user, with an appropriate set of higher level
  107  *          functions.
  108  *
  109  */
  110 
  111 #include "ctx.h"
  112 #if NCTX > 0
  113 
  114 #include "opt_devfs.h"
  115 
  116 #include <sys/param.h>
  117 #include <sys/systm.h>
  118 #include <sys/conf.h>
  119 #include <sys/uio.h>
  120 #include <sys/kernel.h>
  121 #include <sys/malloc.h>
  122 #ifdef DEVFS
  123 #include <sys/devfsext.h>
  124 #endif /*DEVFS*/
  125 
  126 #include <i386/isa/isa_device.h>
  127 #include <i386/isa/ctxreg.h>
  128 #include <machine/ioctl_ctx.h>
  129 #include <machine/md_var.h>
  130 
  131 static int     waitvb(int port);
  132 
  133 /* state flags */
  134 #define   OPEN        (0x01)    /* device is open */
  135 
  136 #define   UNIT(x) ((x) & 0x07)
  137 
  138 static int      ctxprobe __P((struct isa_device *devp));
  139 static int      ctxattach __P((struct isa_device *devp));
  140 struct isa_driver ctxdriver = {ctxprobe, ctxattach, "ctx"};
  141 
  142 static  d_open_t        ctxopen;
  143 static  d_close_t       ctxclose;
  144 static  d_read_t        ctxread;
  145 static  d_write_t       ctxwrite;
  146 static  d_ioctl_t       ctxioctl;
  147 #define CDEV_MAJOR 40
  148 
  149 static struct cdevsw ctx_cdevsw = 
  150         { ctxopen,      ctxclose,       ctxread,        ctxwrite,       /*40*/
  151           ctxioctl,     nostop,         nullreset,      nodevtotty,/* cortex */
  152           seltrue,      nommap,         NULL,   "ctx",  NULL,   -1 };
  153 
  154 
  155 #define   LUTSIZE     256       /* buffer size for Look Up Table (LUT) */
  156 #define   PAGESIZE    65536     /* size of one video page, 1/4 of the screen */
  157 
  158 /*
  159  *  Per unit shadow registers (because the dumb hardware is RO)
  160 */
  161 
  162 static struct ctx_soft_registers {
  163         u_char *lutp;
  164         u_char  cp0;
  165         u_char  cp1;
  166         u_char  flag;
  167         int     iobase;
  168         caddr_t maddr;
  169         int     msize;
  170         void    *devfs_token;
  171 }       ctx_sr[NCTX];
  172 
  173 
  174 static int
  175 ctxprobe(struct isa_device * devp)
  176 {
  177         int     status;
  178 
  179         if (inb(devp->id_iobase) == 0xff)       /* 0xff only if board absent */
  180                 status = 0;
  181         else {
  182                 status = 1; /*XXX uses only one port? */
  183         }
  184         return (status);
  185 }
  186 
  187 static int
  188 ctxattach(struct isa_device * devp)
  189 {
  190         struct ctx_soft_registers *sr;
  191 
  192         sr = &(ctx_sr[devp->id_unit]);
  193         sr->cp0 = 0;    /* zero out the shadow registers */
  194         sr->cp1 = 0;    /* and the open flag.  wait for  */
  195         sr->flag = 0;   /* open to malloc the LUT space  */
  196         sr->iobase = devp->id_iobase;
  197         sr->maddr = devp->id_maddr;
  198         sr->msize = devp->id_msize;
  199 #ifdef DEVFS
  200         sr->devfs_token = 
  201                 devfs_add_devswf(&ctx_cdevsw, 0, DV_CHR, 0, 0, 0600,
  202                                  "ctx%d", devp->id_unit);
  203 #endif /* DEVFS */
  204         return (1);
  205 }
  206 
  207 static int
  208 ctxopen(dev_t dev, int flags, int fmt, struct proc *p)
  209 {
  210         struct ctx_soft_registers *sr;
  211         u_char  unit;
  212         int     i;
  213 
  214         unit = UNIT(minor(dev));
  215 
  216         /* minor number out of range? */
  217 
  218         if (unit >= NCTX)
  219                 return (ENXIO);
  220         sr = &(ctx_sr[unit]);
  221 
  222         if (sr->flag != 0)      /* someone has already opened us */
  223                 return (EBUSY);
  224 
  225         /* get space for the LUT buffer */
  226 
  227         sr->lutp = malloc(LUTSIZE, M_DEVBUF, M_WAITOK);
  228         if (sr->lutp == NULL)
  229                 return (ENOMEM);
  230 
  231         sr->flag = OPEN;
  232 
  233 /*
  234         Set up the shadow registers.  We don't actually write these
  235         values to the control ports until after we finish loading the
  236         lookup table.
  237 */
  238         sr->cp0 |= SEE_STORED_VIDEO;
  239         if ((kvtop(sr->maddr) == 0xB0000) || (kvtop(sr->maddr) == 0xE0000))
  240                 sr->cp1 |= AB_SELECT;   /* map to B or E if necessary */
  241         /* but don't enable RAM   */
  242 /*
  243         Set up the lookup table initially so that it is transparent.
  244 */
  245 
  246         outb(sr->iobase + ctx_cp0, (u_char) 0);
  247         outb(sr->iobase + ctx_cp1, (u_char) (LUT_LOAD_ENABLE | BLANK_DISPLAY));
  248         for (i = 0; i < LUTSIZE; i++) {
  249                 outb(sr->iobase + ctx_lutaddr, (u_char) i);
  250                 sr->lutp[i] = (u_char) i;
  251                 outb(sr->iobase + ctx_lutdata, (u_char) sr->lutp[i]);
  252         }
  253 /*
  254         Disable LUT loading, and push the data in the shadow
  255         registers into the control ports.
  256 */
  257         outb(sr->iobase + ctx_cp0, sr->cp0);
  258         outb(sr->iobase + ctx_cp1, sr->cp1);
  259         return (0);     /* successful open.  All ready to go. */
  260 }
  261 
  262 static int
  263 ctxclose(dev_t dev, int flags, int fmt, struct proc *p)
  264 {
  265         int     unit;
  266 
  267         unit = UNIT(minor(dev));
  268         ctx_sr[unit].flag = 0;
  269         free(ctx_sr[unit].lutp, M_DEVBUF);
  270         ctx_sr[unit].lutp = NULL;
  271         return (0);
  272 }
  273 
  274 static int
  275 ctxwrite(dev_t dev, struct uio * uio, int ioflag)
  276 {
  277         int     unit, status = 0;
  278         int     page, count, offset;
  279         struct ctx_soft_registers *sr;
  280 
  281         unit = UNIT(minor(dev));
  282         sr = &(ctx_sr[unit]);
  283 
  284         if (uio->uio_offset < 0)
  285                 return (EINVAL);
  286         if (uio->uio_offset >= 4 * PAGESIZE)
  287                 page = 4;       /* EOF */
  288         else
  289                 page = (u_int)uio->uio_offset / PAGESIZE;
  290         offset = (u_int)uio->uio_offset % PAGESIZE;
  291         count = min(uio->uio_resid, PAGESIZE - offset);
  292         while ((page >= 0) && (page <= 3) && (count > 0)) {
  293                 sr->cp0 &= ~3;
  294                 sr->cp0 |= page;
  295                 outb(sr->iobase + ctx_cp0, sr->cp0);
  296 
  297 /*
  298         Before doing the uiomove, we need to "connect" the frame buffer
  299         ram to the machine bus.  This is done here so that we can have
  300         several different boards installed, all sharing the same memory
  301         space... each board is only "connected" to the bus when its memory
  302         is actually being read or written.  All my instincts tell me that
  303         I should disable interrupts here, so I have done so.
  304 */
  305 
  306                 disable_intr();
  307                 sr->cp1 |= RAM_ENABLE;
  308                 outb(sr->iobase + ctx_cp1, sr->cp1);
  309                 status = uiomove(sr->maddr + offset, count, uio);
  310                 sr->cp1 &= ~RAM_ENABLE;
  311                 outb(sr->iobase + ctx_cp1, sr->cp1);
  312                 enable_intr();
  313 
  314                 page = (u_int)uio->uio_offset / PAGESIZE;
  315                 offset = (u_int)uio->uio_offset % PAGESIZE;
  316                 count = min(uio->uio_resid, PAGESIZE - offset);
  317         }
  318         if (uio->uio_resid > 0)
  319                 return (ENOSPC);
  320         else
  321                 return (status);
  322 }
  323 
  324 static int
  325 ctxread(dev_t dev, struct uio * uio, int ioflag)
  326 {
  327         int     unit, status = 0;
  328         int     page, count, offset;
  329         struct ctx_soft_registers *sr;
  330 
  331         unit = UNIT(minor(dev));
  332         sr = &(ctx_sr[unit]);
  333 
  334         if (uio->uio_offset < 0)
  335                 return (EINVAL);
  336         if (uio->uio_offset >= 4 * PAGESIZE)
  337                 page = 4;       /* EOF */
  338         else
  339                 page = (u_int)uio->uio_offset / PAGESIZE;
  340         offset = (u_int)uio->uio_offset % PAGESIZE;
  341         count = min(uio->uio_resid, PAGESIZE - offset);
  342         while ((page >= 0) && (page <= 3) && (count > 0)) {
  343                 sr->cp0 &= ~3;
  344                 sr->cp0 |= page;
  345                 outb(sr->iobase + ctx_cp0, sr->cp0);
  346 /*
  347         Before doing the uiomove, we need to "connect" the frame buffer
  348         ram to the machine bus.  This is done here so that we can have
  349         several different boards installed, all sharing the same memory
  350         space... each board is only "connected" to the bus when its memory
  351         is actually being read or written.  All my instincts tell me that
  352         I should disable interrupts here, so I have done so.
  353 */
  354                 disable_intr();
  355                 sr->cp1 |= RAM_ENABLE;
  356                 outb(sr->iobase + ctx_cp1, sr->cp1);
  357                 status = uiomove(sr->maddr + offset, count, uio);
  358                 sr->cp1 &= ~RAM_ENABLE;
  359                 outb(sr->iobase + ctx_cp1, sr->cp1);
  360                 enable_intr();
  361 
  362                 page = (u_int)uio->uio_offset / PAGESIZE;
  363                 offset = (u_int)uio->uio_offset % PAGESIZE;
  364                 count = min(uio->uio_resid, PAGESIZE - offset);
  365         }
  366         if (uio->uio_resid > 0)
  367                 return (ENOSPC);
  368         else
  369                 return (status);
  370 }
  371 
  372 static int
  373 ctxioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  374 {
  375         int     error;
  376         int     unit, i;
  377         struct ctx_soft_registers *sr;
  378 
  379         error = 0;
  380         unit = UNIT(minor(dev));
  381         sr = &(ctx_sr[unit]);
  382 
  383         switch (cmd) {
  384         case CTX_LIVE:
  385                 sr->cp0 &= ~SEE_STORED_VIDEO;
  386                 outb(sr->iobase + ctx_cp0, sr->cp0);
  387                 break;
  388         case CTX_GRAB:
  389                 sr->cp0 &= ~SEE_STORED_VIDEO;
  390                 outb(sr->iobase + ctx_cp0, sr->cp0);
  391                 sr->cp0 |= ACQUIRE;
  392                 if (waitvb(sr->iobase)) /* wait for vert blank to start
  393                                          * acquire */
  394                         error = ENODEV;
  395                 outb(sr->iobase + ctx_cp0, sr->cp0);
  396                 if (waitvb(sr->iobase)) /* wait for two more to finish acquire */
  397                         error = ENODEV;
  398                 if (waitvb(sr->iobase))
  399                         error = ENODEV;
  400                 sr->cp0 &= ~ACQUIRE;    /* turn off acquire and turn on
  401                                          * display */
  402                 sr->cp0 |= SEE_STORED_VIDEO;
  403                 outb(sr->iobase + ctx_cp0, sr->cp0);
  404                 break;
  405         case CTX_H_ORGANIZE:
  406                 sr->cp0 &= ~PAGE_ROTATE;
  407                 outb(sr->iobase + ctx_cp0, sr->cp0);
  408                 break;
  409         case CTX_V_ORGANIZE:
  410                 sr->cp0 |= PAGE_ROTATE;
  411                 outb(sr->iobase + ctx_cp0, sr->cp0);
  412                 break;
  413         case CTX_SET_LUT:
  414                 bcopy((u_char *) data, sr->lutp, LUTSIZE);
  415                 outb(sr->iobase + ctx_cp0, (u_char) 0);
  416                 outb(sr->iobase + ctx_cp1, (u_char) (LUT_LOAD_ENABLE | BLANK_DISPLAY));
  417                 for (i = 0; i < LUTSIZE; i++) {
  418                         outb(sr->iobase + ctx_lutaddr, i);
  419                         outb(sr->iobase + ctx_lutdata, sr->lutp[i]);
  420                 }
  421                 outb(sr->iobase + ctx_cp0, sr->cp0);    /* restore control
  422                                                          * registers */
  423                 outb(sr->iobase + ctx_cp1, sr->cp1);
  424                 break;
  425         case CTX_GET_LUT:
  426                 bcopy(sr->lutp, (u_char *) data, LUTSIZE);
  427                 break;
  428         default:
  429                 error = ENODEV;
  430         }
  431 
  432         return (error);
  433 }
  434 
  435 static int
  436 waitvb(int port)
  437 {                               /* wait for a vertical blank,  */
  438         if (inb(port) == 0xff)  /* 0xff means no board present */
  439                 return (1);
  440 
  441         while ((inb(port) & VERTICAL_BLANK) != 0) {
  442         }
  443         while ((inb(port) & VERTICAL_BLANK) == 0) {
  444         }
  445 
  446         return (0);
  447 }
  448 
  449 
  450 
  451 static ctx_devsw_installed = 0;
  452 
  453 static void
  454 ctx_drvinit(void *unused)
  455 {
  456         dev_t dev;
  457 
  458         if( ! ctx_devsw_installed ) {
  459                 dev = makedev(CDEV_MAJOR,0);
  460                 cdevsw_add(&dev,&ctx_cdevsw,NULL);
  461                 ctx_devsw_installed = 1;
  462         }
  463 }
  464 
  465 SYSINIT(ctxdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctx_drvinit,NULL)
  466 
  467 
  468 #endif                          /* NCTX > 0 */

Cache object: 825d6ebdc05660c673ecf4f85bff142f


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