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