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

Cache object: fca88c5162c5b06fe97e81f3f6ab55e0


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