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

Cache object: 5133d1adbd59d1a7e8c6a289c280f78c


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