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 
  113 #include <sys/param.h>
  114 #include <sys/systm.h>
  115 #include <sys/conf.h>
  116 #include <sys/uio.h>
  117 #include <sys/kernel.h>
  118 #include <sys/malloc.h>
  119 #include <i386/isa/isa_device.h>
  120 #include <i386/isa/ctxreg.h>
  121 #include <machine/ioctl_ctx.h>
  122 #include <machine/md_var.h>
  123 
  124 static int     waitvb(int port);
  125 
  126 /* state flags */
  127 #define   OPEN        (0x01)    /* device is open */
  128 
  129 #define   UNIT(x) ((x) & 0x07)
  130 
  131 static int      ctxprobe __P((struct isa_device *devp));
  132 static int      ctxattach __P((struct isa_device *devp));
  133 struct isa_driver ctxdriver = {ctxprobe, ctxattach, "ctx"};
  134 
  135 static  d_open_t        ctxopen;
  136 static  d_close_t       ctxclose;
  137 static  d_read_t        ctxread;
  138 static  d_write_t       ctxwrite;
  139 static  d_ioctl_t       ctxioctl;
  140 #define CDEV_MAJOR 40
  141 
  142 static struct cdevsw ctx_cdevsw = {
  143         /* open */      ctxopen,
  144         /* close */     ctxclose,
  145         /* read */      ctxread,
  146         /* write */     ctxwrite,
  147         /* ioctl */     ctxioctl,
  148         /* poll */      nopoll,
  149         /* mmap */      nommap,
  150         /* strategy */  nostrategy,
  151         /* name */      "ctx",
  152         /* maj */       CDEV_MAJOR,
  153         /* dump */      nodump,
  154         /* psize */     nopsize,
  155         /* flags */     0,
  156         /* bmaj */      -1
  157 };
  158 
  159 
  160 #define   LUTSIZE     256       /* buffer size for Look Up Table (LUT) */
  161 #define   PAGESIZE    65536     /* size of one video page, 1/4 of the screen */
  162 
  163 /*
  164  *  Per unit shadow registers (because the dumb hardware is RO)
  165 */
  166 
  167 static struct ctx_soft_registers {
  168         u_char *lutp;
  169         u_char  cp0;
  170         u_char  cp1;
  171         u_char  flag;
  172         int     iobase;
  173         caddr_t maddr;
  174         int     msize;
  175 }       ctx_sr[NCTX];
  176 
  177 
  178 static int
  179 ctxprobe(struct isa_device * devp)
  180 {
  181         int     status;
  182         static int once;
  183 
  184         if (!once++)
  185                 cdevsw_add(&ctx_cdevsw);
  186         if (inb(devp->id_iobase) == 0xff)       /* 0xff only if board absent */
  187                 status = 0;
  188         else {
  189                 status = 1; /*XXX uses only one port? */
  190         }
  191         return (status);
  192 }
  193 
  194 static int
  195 ctxattach(struct isa_device * devp)
  196 {
  197         struct ctx_soft_registers *sr;
  198 
  199         sr = &(ctx_sr[devp->id_unit]);
  200         sr->cp0 = 0;    /* zero out the shadow registers */
  201         sr->cp1 = 0;    /* and the open flag.  wait for  */
  202         sr->flag = 0;   /* open to malloc the LUT space  */
  203         sr->iobase = devp->id_iobase;
  204         sr->maddr = devp->id_maddr;
  205         sr->msize = devp->id_msize;
  206         make_dev(&ctx_cdevsw, 0, 0, 0, 0600, "ctx%d", devp->id_unit);
  207         return (1);
  208 }
  209 
  210 static int
  211 ctxopen(dev_t dev, int flags, int fmt, struct proc *p)
  212 {
  213         struct ctx_soft_registers *sr;
  214         u_char  unit;
  215         int     i;
  216 
  217         unit = UNIT(minor(dev));
  218 
  219         /* minor number out of range? */
  220 
  221         if (unit >= NCTX)
  222                 return (ENXIO);
  223         sr = &(ctx_sr[unit]);
  224 
  225         if (sr->flag != 0)      /* someone has already opened us */
  226                 return (EBUSY);
  227 
  228         /* get space for the LUT buffer */
  229 
  230         sr->lutp = malloc(LUTSIZE, M_DEVBUF, M_WAITOK);
  231         if (sr->lutp == NULL)
  232                 return (ENOMEM);
  233 
  234         sr->flag = OPEN;
  235 
  236 /*
  237         Set up the shadow registers.  We don't actually write these
  238         values to the control ports until after we finish loading the
  239         lookup table.
  240 */
  241         sr->cp0 |= SEE_STORED_VIDEO;
  242         if ((kvtop(sr->maddr) == 0xB0000) || (kvtop(sr->maddr) == 0xE0000))
  243                 sr->cp1 |= AB_SELECT;   /* map to B or E if necessary */
  244         /* but don't enable RAM   */
  245 /*
  246         Set up the lookup table initially so that it is transparent.
  247 */
  248 
  249         outb(sr->iobase + ctx_cp0, (u_char) 0);
  250         outb(sr->iobase + ctx_cp1, (u_char) (LUT_LOAD_ENABLE | BLANK_DISPLAY));
  251         for (i = 0; i < LUTSIZE; i++) {
  252                 outb(sr->iobase + ctx_lutaddr, (u_char) i);
  253                 sr->lutp[i] = (u_char) i;
  254                 outb(sr->iobase + ctx_lutdata, (u_char) sr->lutp[i]);
  255         }
  256 /*
  257         Disable LUT loading, and push the data in the shadow
  258         registers into the control ports.
  259 */
  260         outb(sr->iobase + ctx_cp0, sr->cp0);
  261         outb(sr->iobase + ctx_cp1, sr->cp1);
  262         return (0);     /* successful open.  All ready to go. */
  263 }
  264 
  265 static int
  266 ctxclose(dev_t dev, int flags, int fmt, struct proc *p)
  267 {
  268         int     unit;
  269 
  270         unit = UNIT(minor(dev));
  271         ctx_sr[unit].flag = 0;
  272         free(ctx_sr[unit].lutp, M_DEVBUF);
  273         ctx_sr[unit].lutp = NULL;
  274         return (0);
  275 }
  276 
  277 static int
  278 ctxwrite(dev_t dev, struct uio * uio, int ioflag)
  279 {
  280         int     unit, status = 0;
  281         int     page, count, offset;
  282         struct ctx_soft_registers *sr;
  283 
  284         unit = UNIT(minor(dev));
  285         sr = &(ctx_sr[unit]);
  286 
  287         if (uio->uio_offset < 0)
  288                 return (EINVAL);
  289         if (uio->uio_offset >= 4 * PAGESIZE)
  290                 page = 4;       /* EOF */
  291         else
  292                 page = (u_int)uio->uio_offset / PAGESIZE;
  293         offset = (u_int)uio->uio_offset % PAGESIZE;
  294         count = min(uio->uio_resid, PAGESIZE - offset);
  295         while ((page >= 0) && (page <= 3) && (count > 0)) {
  296                 sr->cp0 &= ~3;
  297                 sr->cp0 |= page;
  298                 outb(sr->iobase + ctx_cp0, sr->cp0);
  299 
  300 /*
  301         Before doing the uiomove, we need to "connect" the frame buffer
  302         ram to the machine bus.  This is done here so that we can have
  303         several different boards installed, all sharing the same memory
  304         space... each board is only "connected" to the bus when its memory
  305         is actually being read or written.  All my instincts tell me that
  306         I should disable interrupts here, so I have done so.
  307 */
  308 
  309                 disable_intr();
  310                 sr->cp1 |= RAM_ENABLE;
  311                 outb(sr->iobase + ctx_cp1, sr->cp1);
  312                 status = uiomove(sr->maddr + offset, count, uio);
  313                 sr->cp1 &= ~RAM_ENABLE;
  314                 outb(sr->iobase + ctx_cp1, sr->cp1);
  315                 enable_intr();
  316 
  317                 page = (u_int)uio->uio_offset / PAGESIZE;
  318                 offset = (u_int)uio->uio_offset % PAGESIZE;
  319                 count = min(uio->uio_resid, PAGESIZE - offset);
  320         }
  321         if (uio->uio_resid > 0)
  322                 return (ENOSPC);
  323         else
  324                 return (status);
  325 }
  326 
  327 static int
  328 ctxread(dev_t dev, struct uio * uio, int ioflag)
  329 {
  330         int     unit, status = 0;
  331         int     page, count, offset;
  332         struct ctx_soft_registers *sr;
  333 
  334         unit = UNIT(minor(dev));
  335         sr = &(ctx_sr[unit]);
  336 
  337         if (uio->uio_offset < 0)
  338                 return (EINVAL);
  339         if (uio->uio_offset >= 4 * PAGESIZE)
  340                 page = 4;       /* EOF */
  341         else
  342                 page = (u_int)uio->uio_offset / PAGESIZE;
  343         offset = (u_int)uio->uio_offset % PAGESIZE;
  344         count = min(uio->uio_resid, PAGESIZE - offset);
  345         while ((page >= 0) && (page <= 3) && (count > 0)) {
  346                 sr->cp0 &= ~3;
  347                 sr->cp0 |= page;
  348                 outb(sr->iobase + ctx_cp0, sr->cp0);
  349 /*
  350         Before doing the uiomove, we need to "connect" the frame buffer
  351         ram to the machine bus.  This is done here so that we can have
  352         several different boards installed, all sharing the same memory
  353         space... each board is only "connected" to the bus when its memory
  354         is actually being read or written.  All my instincts tell me that
  355         I should disable interrupts here, so I have done so.
  356 */
  357                 disable_intr();
  358                 sr->cp1 |= RAM_ENABLE;
  359                 outb(sr->iobase + ctx_cp1, sr->cp1);
  360                 status = uiomove(sr->maddr + offset, count, uio);
  361                 sr->cp1 &= ~RAM_ENABLE;
  362                 outb(sr->iobase + ctx_cp1, sr->cp1);
  363                 enable_intr();
  364 
  365                 page = (u_int)uio->uio_offset / PAGESIZE;
  366                 offset = (u_int)uio->uio_offset % PAGESIZE;
  367                 count = min(uio->uio_resid, PAGESIZE - offset);
  368         }
  369         if (uio->uio_resid > 0)
  370                 return (ENOSPC);
  371         else
  372                 return (status);
  373 }
  374 
  375 static int
  376 ctxioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  377 {
  378         int     error;
  379         int     unit, i;
  380         struct ctx_soft_registers *sr;
  381 
  382         error = 0;
  383         unit = UNIT(minor(dev));
  384         sr = &(ctx_sr[unit]);
  385 
  386         switch (cmd) {
  387         case CTX_LIVE:
  388                 sr->cp0 &= ~SEE_STORED_VIDEO;
  389                 outb(sr->iobase + ctx_cp0, sr->cp0);
  390                 break;
  391         case CTX_GRAB:
  392                 sr->cp0 &= ~SEE_STORED_VIDEO;
  393                 outb(sr->iobase + ctx_cp0, sr->cp0);
  394                 sr->cp0 |= ACQUIRE;
  395                 if (waitvb(sr->iobase)) /* wait for vert blank to start
  396                                          * acquire */
  397                         error = ENODEV;
  398                 outb(sr->iobase + ctx_cp0, sr->cp0);
  399                 if (waitvb(sr->iobase)) /* wait for two more to finish acquire */
  400                         error = ENODEV;
  401                 if (waitvb(sr->iobase))
  402                         error = ENODEV;
  403                 sr->cp0 &= ~ACQUIRE;    /* turn off acquire and turn on
  404                                          * display */
  405                 sr->cp0 |= SEE_STORED_VIDEO;
  406                 outb(sr->iobase + ctx_cp0, sr->cp0);
  407                 break;
  408         case CTX_H_ORGANIZE:
  409                 sr->cp0 &= ~PAGE_ROTATE;
  410                 outb(sr->iobase + ctx_cp0, sr->cp0);
  411                 break;
  412         case CTX_V_ORGANIZE:
  413                 sr->cp0 |= PAGE_ROTATE;
  414                 outb(sr->iobase + ctx_cp0, sr->cp0);
  415                 break;
  416         case CTX_SET_LUT:
  417                 bcopy((u_char *) data, sr->lutp, LUTSIZE);
  418                 outb(sr->iobase + ctx_cp0, (u_char) 0);
  419                 outb(sr->iobase + ctx_cp1, (u_char) (LUT_LOAD_ENABLE | BLANK_DISPLAY));
  420                 for (i = 0; i < LUTSIZE; i++) {
  421                         outb(sr->iobase + ctx_lutaddr, i);
  422                         outb(sr->iobase + ctx_lutdata, sr->lutp[i]);
  423                 }
  424                 outb(sr->iobase + ctx_cp0, sr->cp0);    /* restore control
  425                                                          * registers */
  426                 outb(sr->iobase + ctx_cp1, sr->cp1);
  427                 break;
  428         case CTX_GET_LUT:
  429                 bcopy(sr->lutp, (u_char *) data, LUTSIZE);
  430                 break;
  431         default:
  432                 error = ENODEV;
  433         }
  434 
  435         return (error);
  436 }
  437 
  438 static int
  439 waitvb(int port)
  440 {                               /* wait for a vertical blank,  */
  441         if (inb(port) == 0xff)  /* 0xff means no board present */
  442                 return (1);
  443 
  444         while ((inb(port) & VERTICAL_BLANK) != 0) {
  445         }
  446         while ((inb(port) & VERTICAL_BLANK) == 0) {
  447         }
  448 
  449         return (0);
  450 }

Cache object: 29bb3d4b71d78539308658e10f62c519


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