diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 416ff9d55465..38551d54d779 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -4,7 +4,7 @@ # # This kernel is NOT MEANT to be runnable! # -# $Id: LINT,v 1.90 1994/10/01 05:43:09 davidg Exp $ +# $Id: LINT,v 1.91 1994/10/01 16:44:07 phk Exp $ # machine "i386" @@ -212,6 +212,9 @@ device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr device snd7 at isa? port 0x300 device snd1 at isa? port 0x388 +# Cortex-I Frame Grabber driver +device ctx0 at isa? port 0x230 iomem 0xd0000 + # The digital speaker driver (/dev/pcaudio). device pca0 at isa? tty diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index c08c57795ea3..01cc7f686d79 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.50 1994/10/01 02:36:24 swallace Exp $ +# $Id: files.i386,v 1.51 1994/10/01 02:55:57 davidg Exp $ # i386/apm/apm.c optional apm device-driver i386/apm/apm_setup.s optional apm @@ -48,6 +48,7 @@ i386/isa/aic6360.c optional aic device-driver i386/isa/b004.c optional bqu device-driver i386/isa/bt742a.c optional bt device-driver i386/isa/clock.c standard +i386/isa/ctx.c optional ctx device-driver i386/isa/fd.c optional fd device-driver i386/isa/ft.c optional ft device-driver i386/isa/elink.c optional ie device-driver diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 416ff9d55465..38551d54d779 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -4,7 +4,7 @@ # # This kernel is NOT MEANT to be runnable! # -# $Id: LINT,v 1.90 1994/10/01 05:43:09 davidg Exp $ +# $Id: LINT,v 1.91 1994/10/01 16:44:07 phk Exp $ # machine "i386" @@ -212,6 +212,9 @@ device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr device snd7 at isa? port 0x300 device snd1 at isa? port 0x388 +# Cortex-I Frame Grabber driver +device ctx0 at isa? port 0x230 iomem 0xd0000 + # The digital speaker driver (/dev/pcaudio). device pca0 at isa? tty diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 416ff9d55465..38551d54d779 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -4,7 +4,7 @@ # # This kernel is NOT MEANT to be runnable! # -# $Id: LINT,v 1.90 1994/10/01 05:43:09 davidg Exp $ +# $Id: LINT,v 1.91 1994/10/01 16:44:07 phk Exp $ # machine "i386" @@ -212,6 +212,9 @@ device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr device snd7 at isa? port 0x300 device snd1 at isa? port 0x388 +# Cortex-I Frame Grabber driver +device ctx0 at isa? port 0x230 iomem 0xd0000 + # The digital speaker driver (/dev/pcaudio). device pca0 at isa? tty diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index c08c57795ea3..01cc7f686d79 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.50 1994/10/01 02:36:24 swallace Exp $ +# $Id: files.i386,v 1.51 1994/10/01 02:55:57 davidg Exp $ # i386/apm/apm.c optional apm device-driver i386/apm/apm_setup.s optional apm @@ -48,6 +48,7 @@ i386/isa/aic6360.c optional aic device-driver i386/isa/b004.c optional bqu device-driver i386/isa/bt742a.c optional bt device-driver i386/isa/clock.c standard +i386/isa/ctx.c optional ctx device-driver i386/isa/fd.c optional fd device-driver i386/isa/ft.c optional ft device-driver i386/isa/elink.c optional ie device-driver diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c index 181c976e4cb9..d31861e1dae0 100644 --- a/sys/i386/i386/conf.c +++ b/sys/i386/i386/conf.c @@ -41,7 +41,7 @@ * SUCH DAMAGE. * * from: @(#)conf.c 5.8 (Berkeley) 5/12/91 - * $Id: conf.c,v 1.35 1994/09/29 08:59:33 sos Exp $ + * $Id: conf.c,v 1.36 1994/10/01 02:55:59 davidg Exp $ */ #include @@ -544,6 +544,21 @@ d_ioctl_t apmioctl; #define apmioctl (d_ioctl_t *)enxio #endif +#include "ctx.h" +#if NCTX > 0 +d_open_t ctxopen; +d_close_t ctxclose; +d_rdwr_t ctxread; +d_rdwr_t ctxwrite; +d_ioctl_t ctxioctl; +#else +#define ctxopen (d_open_t *)enxio +#define ctxclose (d_close_t *)enxio +#define ctxread (d_rdwr_t *)enxio +#define ctxwrite (d_rdwr_t *)enxio +#define ctxioctl (d_ioctl_t *)enxio +#endif + #define noopen (d_open_t *)enodev #define noclose (d_close_t *)enodev #define noread (d_rdwr_t *)enodev @@ -685,8 +700,11 @@ struct cdevsw cdevsw[] = { apmopen, apmclose, noread, nowrite, /*39*/ apmioctl, nostop, nullreset, NULL, /* laptop APM */ seltrue, nommap, NULL }, - /* character device 40 is reserved for local use */ - { (d_open_t *)enxio, (d_close_t *)enxio, (d_rdwr_t *)enxio, /*40*/ + { ctxopen, ctxclose, ctxread, ctxwrite, /*40*/ + ctxioctl, nostop, nullreset, NULL, /* cortex framegrabber */ + seltrue, nommap, NULL }, + /* character device 41 is reserved for local use */ + { (d_open_t *)enxio, (d_close_t *)enxio, (d_rdwr_t *)enxio, /*41*/ (d_rdwr_t *)enxio, (d_ioctl_t *)enxio, (d_stop_t *)enxio, (d_reset_t *)enxio, NULL, (d_select_t *)enxio, (d_mmap_t *)enxio, NULL } diff --git a/sys/i386/include/ioctl_ctx.h b/sys/i386/include/ioctl_ctx.h new file mode 100644 index 000000000000..a7de049f7114 --- /dev/null +++ b/sys/i386/include/ioctl_ctx.h @@ -0,0 +1,30 @@ +/* + * + * Copyright (C) 1994, Paul S. LaFollette, Jr. This software may be used, + * modified, copied, distributed, and sold, in both source and binary form + * provided that the above copyright and these terms are retained. Under + * no circumstances is the author responsible for the proper functioning + * of this software, nor does the author assume any responsibility + * for damages incurred with its use + * + * $Id$ + */ + +/* + * ioctl constants for Cortex-I frame grabber + */ + +#ifndef _MACHINE_IOCTL_CTX_H_ +#define _MACHINE_IOCTL_CTX_H_ + +#include +typedef char _CTX_LUTBUF[256]; /* look up table buffer */ + +#define CTX_LIVE _IO('x', 1) /* live video */ +#define CTX_GRAB _IO('x', 2) /* frame grab */ +#define CTX_H_ORGANIZE _IO('x', 3) /* file goes across screen (horiz. read) */ +#define CTX_V_ORGANIZE _IO('x', 4) /* file goes down screen (vert. read) */ +#define CTX_SET_LUT _IOW('x', 5, _CTX_LUTBUF) /* set lookup table */ +#define CTX_GET_LUT _IOR('x', 6, _CTX_LUTBUF) /* get lookup table */ + +#endif /* ifndef _MACHINE_IOCTL_CTX_H */ diff --git a/sys/i386/isa/ctx.c b/sys/i386/isa/ctx.c new file mode 100644 index 000000000000..8ba2cc65d347 --- /dev/null +++ b/sys/i386/isa/ctx.c @@ -0,0 +1,415 @@ +/* + * CORTEX-I Frame Grabber driver V1.0 + * + * Copyright (C) 1994, Paul S. LaFollette, Jr. This software may be used, + * modified, copied, distributed, and sold, in both source and binary form + * provided that the above copyright and these terms are retained. Under + * no circumstances is the author responsible for the proper functioning + * of this software, nor does the author assume any responsibility + * for damages incurred with its use. + * + * $Id$ + */ + +/* + * + * + * + * Device Driver for CORTEX-I Frame Grabber + * Made by ImageNation Corporation + * 1200 N.E. Keyues Road + * Vancouver, WA 98684 (206) 944-9131 + * (I have no ties to this company, just thought you might want + * to know how to get in touch with them.) + * + * In order to understand this device, you really need to consult the + * manual which ImageNation provides when you buy the board. (And + * what a pleasure it is to buy something for a PC and actually get + * programming information along with it.) I will limit myself here to + * a few comments which are specific to this driver. See also the file + * ctxreg.h for definitions of registers and control bits. + * + * 1. Although the hardware supports low resolution (256 x 256) + * acqusition and display, I have not implemented access to + * these modes in this driver. There are some fairly quirky + * aspects to the way this board works in low resolution mode, + * and I don't want to deal with them. Maybe later. + * + * 2. Choosing the base address for the video memory: This is set + * using a combination of hardware and software, using the left + * most dip switch on the board, and the AB_SELECT bit of control + * port 1, according to the chart below: + * + * Left DIP switch || DOWN | UP | + * ================================================= + * AB_SELECT = 0 || 0xA0000 | 0xB0000 | + * ------------------------------------------------- + * AB_SELECT = 1 || 0xD0000 | 0xE0000 | + * ------------------------------------------------ + * + * When the RAM_ENABLE bit of control port 1 is clear (0), the + * video ram is disconnected from the computer bus. This makes + * it possible, in principle, to share memory space with other + * devices (such as VGA) which can also disconnect themselves + * from the bus. It also means that multiple CORTEX-I boards + * can share the same video memory space. Disconnecting from the + * bus does not affect the video display of the video ram contents, + * so that one needs only set the RAM_ENABLE bit when actually + * reading or writing to memory. The cost of this is low, + * the benefits to me are great (I need more than one board + * in my machine, and 0xE0000 is the only address choice that + * doesn't conflict with anything) so I adopt this strategy here. + * + * XXX-Note... this driver has only been tested for the + * XXX base = 0xE0000 case! + * + * 3) There is a deficiency in the documentation from ImageNation, I + * think. In order to successfully load the lookup table, it is + * necessary to clear SEE_STORED_VIDEO in control port 0 as well as + * setting LUT_LOAD_ENABLE in control port 1. + * + * 4) This driver accesses video memory through read or write operations. + * Other functionality is provided through ioctl's, manifest + * constants for which are defined in ioctl_ctx.h. The ioctl's + * include: + * CTX_LIVE Display live video + * CTX_GRAB Grab a frame of video data + * CTX_H_ORGANIZE Set things up so that sequential read + * operations access horizontal lines of + * pixels. + * CTX_V_ORGANIZE Set things up so that sequential read + * operations access vertical lines of + * pixels. + * CTX_SET_LUT Set the lookup table from an array + * of 256 unsigned chars passed as the + * third parameter to ioctl. + * CTX_GET_LUT Return the current lookup table to + * the application as an array of 256 + * unsigned chars. Again the third + * parameter to the ioctl call. + * + * Thus, + * ioctl(fi, CTX_H_ORGANIZE, 0); + * lseek(fi, y*512, SEEK_SET); + * read(fi, buffer, 512); + * + * will fill buffer with 512 pixels (unsigned chars) which represent + * the y-th horizontal line of the image. + * Similarly, + * ioctl(fi, CTX_V_ORGANIZE, 0: + * lseek(fi, x*512+y, SEEK_SET); + * read(fi, buffer, 10); + * + * will read 10 a vertical line of 10 pixels starting at (x,y). + * + * Obviously, this sort of ugliness needs to be hidden away from + * the casual user, with an appropriate set of higher level + * functions. + * + */ + +#include "ctx.h" +#if NCTX > 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "isa.h" +#include "isa_device.h" +#include "ctxreg.h" +#include + +int waitvb(short); + +/* state flags */ +#define OPEN (0x01) /* device is open */ + +#define UNIT(x) ((x) & 0x07) + +int ctxprobe(), ctxattach(); +struct isa_driver ctxdriver = {ctxprobe, ctxattach, "ctx"}; + +#define LUTSIZE 256 /* buffer size for Look Up Table (LUT) */ +#define PAGESIZE 65536 /* size of one video page, 1/4 of the screen */ + +/* + * Per unit shadow registers (because the dumb hardware is RO) +*/ + +struct ctx_soft_registers { + u_char *lutp; + u_char cp0; + u_char cp1; + u_char flag; + short iobase; + caddr_t maddr; + int msize; +} ctx_sr[NCTX]; + + + +int +ctxprobe(struct isa_device * devp) +{ + int status; + + if (inb(devp->id_iobase) == 0xff) /* 0xff only if board absent */ + status = 0; + else + status = 1; + return (status); +} + +int +ctxattach(struct isa_device * devp) +{ + struct ctx_soft_registers *sr; + + sr = &(ctx_sr[devp->id_unit]); + sr->cp0 = 0; /* zero out the shadow registers */ + sr->cp1 = 0; /* and the open flag. wait for */ + sr->flag = 0; /* open to malloc the LUT space */ + sr->iobase = devp->id_iobase; + sr->maddr = devp->id_maddr; + sr->msize = devp->id_msize; + return (1); +} + +int +ctxopen(dev_t dev, int flag) +{ + struct ctx_soft_registers *sr; + u_char unit; + int i; + + unit = UNIT(minor(dev)); + + /* minor number out of range? */ + + if (unit >= NCTX) + return (ENXIO); + sr = &(ctx_sr[unit]); + + if (sr->flag != 0) /* someone has already opened us */ + return (EBUSY); + + /* get space for the LUT buffer */ + + sr->lutp = malloc(LUTSIZE, M_DEVBUF, M_WAITOK); + if (sr->lutp == NULL) + return (ENOMEM); + + sr->flag = OPEN; + +/* + Set up the shadow registers. We don't actually write these + values to the control ports until after we finish loading the + lookup table. +*/ + sr->cp0 |= SEE_STORED_VIDEO; + if ((kvtop(sr->maddr) == 0xB0000) || (kvtop(sr->maddr) == 0xE0000)) + sr->cp1 |= AB_SELECT; /* map to B or E if necessary */ + /* but don't enable RAM */ +/* + Set up the lookup table initially so that it is transparent. +*/ + + outb(sr->iobase + ctx_cp0, (u_char) 0); + outb(sr->iobase + ctx_cp1, (u_char) (LUT_LOAD_ENABLE | BLANK_DISPLAY)); + for (i = 0; i < LUTSIZE; i++) { + outb(sr->iobase + ctx_lutaddr, (u_char) i); + sr->lutp[i] = (u_char) i; + outb(sr->iobase + ctx_lutdata, (u_char) sr->lutp[i]); + } +/* + Disable LUT loading, and push the data in the shadow + registers into the control ports. +*/ + outb(sr->iobase + ctx_cp0, sr->cp0); + outb(sr->iobase + ctx_cp1, sr->cp1); + return (0); /* successful open. All ready to go. */ +} + +int +ctxclose(dev_t dev, int flag) +{ + int unit; + + unit = UNIT(minor(dev)); + ctx_sr[unit].flag = 0; + free(ctx_sr[unit].lutp, M_DEVBUF); + ctx_sr[unit].lutp = NULL; + return (0); +} + +int +ctxwrite(dev_t dev, struct uio * uio) +{ + int unit, status = 0; + int page, count, offset; + struct ctx_soft_registers *sr; + + unit = UNIT(minor(dev)); + sr = &(ctx_sr[unit]); + + page = uio->uio_offset / PAGESIZE; + offset = uio->uio_offset % PAGESIZE; + count = min(uio->uio_resid, PAGESIZE - offset); + while ((page >= 0) && (page <= 3) && (count > 0)) { + sr->cp0 &= ~3; + sr->cp0 |= page; + outb(sr->iobase + ctx_cp0, sr->cp0); + +/* + Before doing the uiomove, we need to "connect" the frame buffer + ram to the machine bus. This is done here so that we can have + several different boards installed, all sharing the same memory + space... each board is only "connected" to the bus when its memory + is actually being read or written. All my instincts tell me that + I should disable interrupts here, so I have done so. +*/ + + disable_intr(); + sr->cp1 |= RAM_ENABLE; + outb(sr->iobase + ctx_cp1, sr->cp1); + status = uiomove(sr->maddr + offset, count, uio); + sr->cp1 &= ~RAM_ENABLE; + outb(sr->iobase + ctx_cp1, sr->cp1); + enable_intr(); + + page = uio->uio_offset / PAGESIZE; + offset = uio->uio_offset % PAGESIZE; + count = min(uio->uio_resid, PAGESIZE - offset); + } + if (uio->uio_resid > 0) + return (ENOSPC); + else + return (status); +} + +int +ctxread(dev_t dev, struct uio * uio) +{ + int unit, status = 0; + int page, count, offset; + struct ctx_soft_registers *sr; + + unit = UNIT(minor(dev)); + sr = &(ctx_sr[unit]); + + page = uio->uio_offset / PAGESIZE; + offset = uio->uio_offset % PAGESIZE; + count = min(uio->uio_resid, PAGESIZE - offset); + while ((page >= 0) && (page <= 3) && (count > 0)) { + sr->cp0 &= ~3; + sr->cp0 |= page; + outb(sr->iobase + ctx_cp0, sr->cp0); +/* + Before doing the uiomove, we need to "connect" the frame buffer + ram to the machine bus. This is done here so that we can have + several different boards installed, all sharing the same memory + space... each board is only "connected" to the bus when its memory + is actually being read or written. All my instincts tell me that + I should disable interrupts here, so I have done so. +*/ + disable_intr(); + sr->cp1 |= RAM_ENABLE; + outb(sr->iobase + ctx_cp1, sr->cp1); + status = uiomove(sr->maddr + offset, count, uio); + sr->cp1 &= ~RAM_ENABLE; + outb(sr->iobase + ctx_cp1, sr->cp1); + enable_intr(); + + page = uio->uio_offset / PAGESIZE; + offset = uio->uio_offset % PAGESIZE; + count = min(uio->uio_resid, PAGESIZE - offset); + } + if (uio->uio_resid > 0) + return (ENOSPC); + else + return (status); +} + +int +ctxioctl(dev_t dev, int cmd, caddr_t data, int flag) +{ + int error; + int unit, i; + struct ctx_soft_registers *sr; + + error = 0; + unit = UNIT(minor(dev)); + sr = &(ctx_sr[unit]); + + switch (cmd) { + case CTX_LIVE: + sr->cp0 &= ~SEE_STORED_VIDEO; + outb(sr->iobase + ctx_cp0, sr->cp0); + break; + case CTX_GRAB: + sr->cp0 &= ~SEE_STORED_VIDEO; + outb(sr->iobase + ctx_cp0, sr->cp0); + sr->cp0 |= ACQUIRE; + if (waitvb(sr->iobase)) /* wait for vert blank to start + * acquire */ + error = ENODEV; + outb(sr->iobase + ctx_cp0, sr->cp0); + if (waitvb(sr->iobase)) /* wait for two more to finish acquire */ + error = ENODEV; + if (waitvb(sr->iobase)) + error = ENODEV; + sr->cp0 &= ~ACQUIRE; /* turn off acquire and turn on + * display */ + sr->cp0 |= SEE_STORED_VIDEO; + outb(sr->iobase + ctx_cp0, sr->cp0); + break; + case CTX_H_ORGANIZE: + sr->cp0 &= ~PAGE_ROTATE; + outb(sr->iobase + ctx_cp0, sr->cp0); + break; + case CTX_V_ORGANIZE: + sr->cp0 |= PAGE_ROTATE; + outb(sr->iobase + ctx_cp0, sr->cp0); + break; + case CTX_SET_LUT: + bcopy((u_char *) data, sr->lutp, LUTSIZE); + outb(sr->iobase + ctx_cp0, (u_char) 0); + outb(sr->iobase + ctx_cp1, (u_char) (LUT_LOAD_ENABLE | BLANK_DISPLAY)); + for (i = 0; i < LUTSIZE; i++) { + outb(sr->iobase + ctx_lutaddr, i); + outb(sr->iobase + ctx_lutdata, sr->lutp[i]); + } + outb(sr->iobase + ctx_cp0, sr->cp0); /* restore control + * registers */ + outb(sr->iobase + ctx_cp1, sr->cp1); + break; + case CTX_GET_LUT: + bcopy(sr->lutp, (u_char *) data, LUTSIZE); + break; + default: + error = ENODEV; + } + + return (error); +} + +int +waitvb(short port) +{ /* wait for a vertical blank, */ + if (inb(port) == 0xff) /* 0xff means no board present */ + return (1); + + while ((inb(port) & VERTICAL_BLANK) != 0) { + } + while ((inb(port) & VERTICAL_BLANK) == 0) { + } + + return (0); +} +#endif /* NCTX > 0 */ diff --git a/sys/i386/isa/ctxreg.h b/sys/i386/isa/ctxreg.h new file mode 100644 index 000000000000..28b644ad4db9 --- /dev/null +++ b/sys/i386/isa/ctxreg.h @@ -0,0 +1,59 @@ +/* + * + * Copyright (C) 1994, Paul S. LaFollette, Jr. This software may be used, + * modified, copied, distributed, and sold, in both source and binary form + * provided that the above copyright and these terms are retained. Under + * no circumstances is the author responsible for the proper functioning + * of this software, nor does the author assume any responsibility + * for damages incurred with its use + * + * $Id$ + */ + +/* + * Register and bit definitions for CORTEX-I frame grabber + */ + +#ifndef _I386_ISA_CTXREG_H_ +#define _I386_ISA_CTXREG_H_ + + /* Control Ports (all are write-only) */ + +#define ctx_cp0 0 /* offset to control port 0 */ +#define ctx_cp1 1 /* offset to control port 1 */ +#define ctx_lutaddr 2 /* offset to lut address port */ +#define ctx_lutdata 3 /* offset to lut data port */ + + /* Status port (read-only but same address as control port 0) */ + +#define ctx_status 0 /* offset to status port */ + + /* Bit assignments for control port 0 */ + +#define PAGE_SELECT0 1 /* These two bits choose which 1/4 of the */ +#define PAGE_SELECT1 2 /* video memory is accessible to us. */ +#define PAGE_ROTATE 4 /* 0 => horizontal access. 1 => vertical */ +#define ACQUIRE 8 /* set to start frame grab */ +#define SEE_STORED_VIDEO 16 /* set to allow stored frame to be seen */ +#define LOW_RESOLUTION 32 /* set to enable 256 x 256 mode */ + + /* Bit assignments for control port 1 */ + +#define INTERRUPT_ENABLE 1 /* Allow interrupts (we avoid this bit) */ +#define TRIGGER_ENABLE 2 /* Enable external trigger for frame grab */ +#define LUT_LOAD_ENABLE 4 /* Allow loading of lookup table */ +#define BLANK_DISPLAY 8 /* Turn off display */ +#define AB_SELECT 16 /* Along with HW switch, choose base memory */ +#define RAM_ENABLE 32 /* Connect video RAM to computer bus */ + + /* Bit assignments for status port */ + +#define INTERRUPT_STATUS 1 /* Ignored by us */ +#define ADC_OVERFLOW 2 /* Set if any pixes from camera "too bright"*/ +#define FIELD 4 /* 0 or 1 shows which interlace field are in*/ +#define VERTICAL_BLANK 8 /* 1 if in vertical blanking interval */ +#define TRIGGERED 16 /* 1 if HW trigger contacts closed */ +#define ACQUIRING_ACK 32 /* 1 if currently grabbing a frame */ + + +#endif /* ifndef _I386_ISA_CTXREG_H_ */