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

Cache object: 67e057ed995a4df31674300b2ad9e8d3


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