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

Cache object: 841af56fd54dc9b9fa387293ad7e5905


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