grfabs_fal.c revision 1.4 1 /* $NetBSD: grfabs_fal.c,v 1.4 1996/05/15 07:29:05 leo Exp $ */
2
3 /*
4 * Copyright (c) 1995 Thomas Gerner.
5 * Copyright (c) 1995 Leo Weppelman.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Leo Weppelman.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #ifdef FALCON_VIDEO
35 /*
36 * atari abstract graphics driver: Falcon-interface
37 */
38 #include <sys/param.h>
39 #include <sys/queue.h>
40 #include <sys/malloc.h>
41 #include <sys/device.h>
42 #include <sys/systm.h>
43
44 #include <machine/iomap.h>
45 #include <machine/video.h>
46 #include <machine/mfp.h>
47 #include <atari/atari/device.h>
48 #include <atari/atari/stalloc.h>
49 #include <atari/dev/grfabs_reg.h>
50
51 /*
52 * Function decls
53 */
54 static void init_view __P((view_t *, bmap_t *, dmode_t *, box_t *));
55 static bmap_t *alloc_bitmap __P((u_long, u_long, u_char));
56 static colormap_t *alloc_colormap __P((dmode_t *));
57 static void free_bitmap __P((bmap_t *));
58 static void falcon_display_view __P((view_t *));
59 static view_t *falcon_alloc_view __P((dmode_t *, dimen_t *, u_char));
60 static void falcon_free_view __P((view_t *));
61 static void falcon_remove_view __P((view_t *));
62 static int falcon_use_colormap __P((view_t *, colormap_t *));
63 static void falcon_detect __P((dmode_t *));
64 static struct videl *falcon_getreg __P((u_short));
65
66 /*
67 * Our function switch table
68 */
69 struct grfabs_sw fal_vid_sw = {
70 falcon_display_view,
71 falcon_alloc_view,
72 falcon_free_view,
73 falcon_remove_view,
74 falcon_use_colormap
75 };
76
77 static dmode_t vid_modes[] = {
78 { {NULL,NULL}, "falauto", { 0, 0 }, 0, {RES_FALAUTO }, &fal_vid_sw},
79 { {NULL,NULL}, "sthigh", { 640,400 }, 1, {RES_FAL_STHIGH}, &fal_vid_sw},
80 { {NULL,NULL}, "stmid", { 640,200 }, 2, {RES_FAL_STMID }, &fal_vid_sw},
81 { {NULL,NULL}, "stlow", { 320,200 }, 4, {RES_FAL_STLOW }, &fal_vid_sw},
82 { {NULL,NULL}, "ttlow", { 320,480 }, 8, {RES_FAL_TTLOW }, &fal_vid_sw},
83 { {NULL,NULL}, "vga2", { 640,480 }, 1, {RES_VGA2 }, &fal_vid_sw},
84 { {NULL,NULL}, "vga4", { 640,480 }, 2, {RES_VGA4 }, &fal_vid_sw},
85 { {NULL,NULL}, "vga16", { 640,480 }, 4, {RES_VGA16 }, &fal_vid_sw},
86 { {NULL,NULL}, "vga256", { 640,480 }, 8, {RES_VGA256 }, &fal_vid_sw},
87 { {NULL,NULL}, "highcol", { 320,200 }, 16, {RES_DIRECT }, &fal_vid_sw},
88 { {NULL,NULL}, NULL, }
89 };
90
91 /*
92 * The following table contains timing values for the various video modes.
93 * I have only a multisync display, therefore I can not say if this values
94 * are useful at other displays.
95 * Use other video modes at YOUR OWN RISK.
96 * THERE IS NO WARRENTY ABOUT THIS VALUES TO WORK WITH A PARTICULAR
97 * DISPLAY. -- Thomas
98 */
99 static struct videl videlinit[] = {
100 { RES_FALAUTO, /* autodedect */
101 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
102 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
103
104 { FAL_VGA | RES_FAL_STHIGH, /* sthigh, 640x400, 2 colors */
105 0x2, 0x0, 0x28, 0x0, 0x400, 0xc6, 0x8d, 0x15, 0x273, 0x50, 0x96, 0x0,
106 0x0, 0x419, 0x3af, 0x8f, 0x8f, 0x3af, 0x415, 0x186, 0x8 },
107
108 #if 0 /* not yet */
109 { FAL_SM | RES_FAL_STHIGH, /* sthigh, 640x400, 2 colors */
110 0x0, 0x0, 0x28, 0x2, 0x0, 0x1a, 0x0, 0x0, 0x20f, 0xc, 0x14, 0x0,
111 0x0, 0x3e9, 0x0, 0x0, 0x43, 0x363, 0x3e7, 0x80, 0x8 },
112 #endif
113
114 { FAL_VGA | RES_FAL_STMID, /* stmid, 640x200, 4 colors */
115 0x2, 0x0, 0x50, 0x1, 0x0, 0x17, 0x12, 0x1, 0x20e, 0xd, 0x11, 0x0,
116 0x0, 0x419, 0x3af, 0x8f, 0x8f, 0x3af, 0x415, 0x186, 0x9 },
117
118 { FAL_VGA | RES_FAL_STLOW, /* stlow, 320x200, 16 colors */
119 0x2, 0x0, 0x50, 0x0, 0x0, 0x17, 0x12, 0x1, 0x20e, 0xd, 0x11, 0x0,
120 0x0, 0x419, 0x3af, 0x8f, 0x8f, 0x3af, 0x415, 0x186, 0x5 },
121
122 { FAL_VGA | RES_FAL_TTLOW, /* ttlow, 320x480, 256 colors */
123 0x2, 0x0, 0xa0, 0x0, 0x10, 0xc6, 0x8d, 0x15, 0x29a, 0x7b, 0x96, 0x0,
124 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x4 },
125
126 { FAL_VGA | RES_VGA2, /* vga, 640x480, 2 colors */
127 0x2, 0x0, 0x28, 0x0, 0x400, 0xc6, 0x8d, 0x15, 0x273, 0x50, 0x96, 0x0,
128 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
129
130 { FAL_VGA | RES_VGA4, /* vga, 640x480, 4 colors */
131 0x2, 0x0, 0x50, 0x1, 0x0, 0x17, 0x12, 0x1, 0x20e, 0xd, 0x11, 0x0,
132 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
133
134 { FAL_VGA | RES_VGA16, /* vga, 640x480, 16 colors */
135 0x2, 0x0, 0xa0, 0x1, 0x0, 0xc6, 0x8d, 0x15, 0x2a3, 0x7c, 0x96, 0x0,
136 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
137
138 { FAL_VGA | RES_VGA256, /* vga, 640x480, 256 colors */
139 0x2, 0x0, 0x140, 0x1, 0x10, 0xc6, 0x8d, 0x15, 0x2ab, 0x84, 0x96, 0x0,
140 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
141
142 { FAL_VGA | RES_DIRECT, /* direct video, 320x200, 65536 colors */
143 0x2, 0x0, 0x140, 0x0, 0x100, 0xc6, 0x8d, 0x15, 0x2ac, 0x91, 0x96, 0x0,
144 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x4 },
145
146 { 0xffff } /* end of list */
147 };
148
149 static u_short mon_type;
150 /*
151 * XXX: called from ite console init routine.
152 * Initialize list of posible video modes.
153 */
154 void
155 falcon_probe_video(modelp)
156 MODES *modelp;
157 {
158 dmode_t *dm;
159 struct videl *vregs;
160 int i;
161
162 /* XXX: The address definition should moved to a header file */
163 mon_type = *(volatile unsigned char *)(0xff8006L);
164 mon_type = (mon_type & 0xc0) << 2;
165
166 /*
167 * get all posible modes
168 */
169
170 for (i = 0; (dm = &vid_modes[i])->name != NULL; i++) {
171 if (dm->vm_mode == RES_FALAUTO) {
172 dm->vm_regs = falcon_getreg(RES_FALAUTO);
173 falcon_detect(dm);
174 LIST_INSERT_HEAD(modelp, dm, link);
175 } else {
176 vregs = falcon_getreg(dm->vm_mode | mon_type);
177 if (vregs) {
178 dm->vm_regs = vregs;
179 LIST_INSERT_HEAD(modelp, dm, link);
180 }
181 }
182 }
183
184 /*
185 * This seems to prevent bordered screens.
186 */
187 for (i=0; i < 16; i++)
188 VIDEO->vd_fal_rgb[i] = CM_L2FAL(gra_def_color16[i]);
189 }
190
191 static struct videl *
192 falcon_getreg(mode)
193 u_short mode;
194 {
195 int i;
196 struct videl *vregs;
197
198 for (i = 0; (vregs = &videlinit[i])->video_mode != 0xffff; i++)
199 if ((vregs->video_mode) == mode)
200 return vregs;
201
202 return NULL; /* mode not found */
203 }
204
205 static void
206 falcon_detect(dm)
207 dmode_t *dm;
208 {
209 u_short falshift, stshift;
210 struct videl *vregs = dm->vm_regs;
211
212 /*
213 * First get the the videl register values
214 */
215
216 vregs->vd_syncmode = VIDEO->vd_sync;
217 vregs->vd_line_wide = VIDEO->vd_line_wide;
218 vregs->vd_vert_wrap = VIDEO->vd_vert_wrap;
219 vregs->vd_st_res = VIDEO->vd_st_res;
220 vregs->vd_fal_res = VIDEO->vd_fal_res;
221 vregs->vd_h_hold_tim = VIDEO->vd_h_hold_tim;
222 vregs->vd_h_bord_beg = VIDEO->vd_h_bord_beg;
223 vregs->vd_h_bord_end = VIDEO->vd_h_bord_end;
224 vregs->vd_h_dis_beg = VIDEO->vd_h_dis_beg;
225 vregs->vd_h_dis_end = VIDEO->vd_h_dis_end;
226 vregs->vd_h_ss = VIDEO->vd_h_ss;
227 vregs->vd_h_fs = VIDEO->vd_h_fs;
228 vregs->vd_h_hh = VIDEO->vd_h_hh;
229 vregs->vd_v_freq_tim = VIDEO->vd_v_freq_tim;
230 vregs->vd_v_bord_beg = VIDEO->vd_v_bord_beg;
231 vregs->vd_v_bord_end = VIDEO->vd_v_bord_end;
232 vregs->vd_v_dis_beg = VIDEO->vd_v_dis_beg;
233 vregs->vd_v_dis_end = VIDEO->vd_v_dis_end;
234 vregs->vd_v_ss = VIDEO->vd_v_ss;
235 vregs->vd_fal_ctrl = VIDEO->vd_fal_ctrl;
236 vregs->vd_fal_mode = VIDEO->vd_fal_mode;
237
238
239 /*
240 * Calculate the depth of the screen
241 */
242
243 falshift = vregs->vd_fal_res;
244 stshift = vregs->vd_st_res;
245
246 if (falshift & 0x400) /* 2 color */
247 dm->depth = 1;
248 else if (falshift & 0x100) /* high color, direct */
249 dm->depth = 16;
250 else if (falshift & 0x10) /* 256 color */
251 dm->depth = 8;
252 else if (stshift == 0) /* 16 color */
253 dm->depth = 4;
254 else if (stshift == 1) /* 4 color */
255 dm->depth = 2;
256 else dm->depth = 1; /* 2 color */
257
258 /*
259 * Now calculate the screen hight
260 */
261
262 dm->size.height = vregs->vd_v_dis_end - vregs->vd_v_dis_beg;
263 if (!((vregs->vd_fal_mode & 0x2) >> 1)) /* if not interlaced */
264 dm->size.height >>=1;
265 if (vregs->vd_fal_mode & 0x1) /* if doublescan */
266 dm->size.height >>=1;
267
268 /*
269 * And the width
270 */
271
272 dm->size.width = vregs->vd_vert_wrap * 16 / dm->depth;
273
274 }
275
276 static void
277 falcon_display_view(v)
278 view_t *v;
279 {
280 dmode_t *dm = v->mode;
281 bmap_t *bm = v->bitmap;
282 struct videl *vregs = v->mode->vm_regs;
283
284 if (dm->current_view) {
285 /*
286 * Mark current view for this mode as no longer displayed
287 */
288 dm->current_view->flags &= ~VF_DISPLAY;
289 }
290 dm->current_view = v;
291 v->flags |= VF_DISPLAY;
292
293 falcon_use_colormap(v, v->colormap);
294
295 /* XXX: should use vbl for this */
296
297 VIDEO->vd_raml = (u_long)bm->hw_address & 0xff;
298 VIDEO->vd_ramm = ((u_long)bm->hw_address >> 8) & 0xff;
299 VIDEO->vd_ramh = ((u_long)bm->hw_address >> 16) & 0xff;
300
301 /*
302 * Write to videl registers only on VGA displays
303 * This is only a hack. Must be fixed soon. XXX -- Thomas
304 */
305 if(mon_type != FAL_VGA) return;
306
307 VIDEO->vd_v_freq_tim = vregs->vd_v_freq_tim;
308 VIDEO->vd_v_ss = vregs->vd_v_ss;
309 VIDEO->vd_v_bord_beg = vregs->vd_v_bord_beg;
310 VIDEO->vd_v_bord_end = vregs->vd_v_bord_end;
311 VIDEO->vd_v_dis_beg = vregs->vd_v_dis_beg;
312 VIDEO->vd_v_dis_end = vregs->vd_v_dis_end;
313 VIDEO->vd_h_hold_tim = vregs->vd_h_hold_tim;
314 VIDEO->vd_h_ss = vregs->vd_h_ss;
315 VIDEO->vd_h_bord_beg = vregs->vd_h_bord_beg;
316 VIDEO->vd_h_bord_end = vregs->vd_h_bord_end;
317 VIDEO->vd_h_dis_beg = vregs->vd_h_dis_beg;
318 VIDEO->vd_h_dis_end = vregs->vd_h_dis_end;
319 #if 0 /* This seems not to be necessary -- Thomas */
320 VIDEO->vd_h_fs = vregs->vd_h_fs;
321 VIDEO->vd_h_hh = vregs->vd_h_hh;
322 #endif
323 VIDEO->vd_sync = vregs->vd_syncmode;
324 VIDEO->vd_fal_res = 0;
325 if (dm->depth == 2)
326 VIDEO->vd_st_res = vregs->vd_st_res;
327 else {
328 VIDEO->vd_st_res = 0;
329 VIDEO->vd_fal_res = vregs->vd_fal_res;
330 }
331 VIDEO->vd_vert_wrap = vregs->vd_vert_wrap;
332 VIDEO->vd_line_wide = vregs->vd_line_wide;
333 VIDEO->vd_fal_ctrl = vregs->vd_fal_ctrl;
334 VIDEO->vd_fal_mode = vregs->vd_fal_mode;
335 }
336
337 static void
338 falcon_remove_view(v)
339 view_t *v;
340 {
341 dmode_t *mode = v->mode;
342
343 if (mode->current_view == v) {
344 #if 0
345 if (v->flags & VF_DISPLAY)
346 panic("Cannot shutdown display\n"); /* XXX */
347 #endif
348 mode->current_view = NULL;
349 }
350 v->flags &= ~VF_DISPLAY;
351 }
352
353 static void
354 falcon_free_view(v)
355 view_t *v;
356 {
357 if (v) {
358 falcon_remove_view(v);
359 if (v->colormap != &gra_con_cmap)
360 free(v->colormap, M_DEVBUF);
361 free_bitmap(v->bitmap);
362 if (v != &gra_con_view)
363 free(v, M_DEVBUF);
364 }
365 }
366
367 static int
368 falcon_use_colormap(v, cm)
369 view_t *v;
370 colormap_t *cm;
371 {
372 dmode_t *dm;
373 volatile u_short *creg;
374 volatile u_long *fcreg;
375 u_long *src;
376 colormap_t *vcm;
377 u_long *vcreg;
378 u_short ncreg;
379 int i;
380
381 dm = v->mode;
382 vcm = v->colormap;
383
384 /*
385 * I guess it seems reasonable to require the maps to be
386 * of the same type...
387 */
388 if (cm->type != vcm->type)
389 return (EINVAL);
390
391 /*
392 * First get the colormap addresses an calculate
393 * howmany colors are in it.
394 */
395 if (dm->depth == 16) /* direct color, no colormap;
396 but also not (yet) supported */
397 return(0);
398 fcreg = &VIDEO->vd_fal_rgb[0];
399 creg = &VIDEO->vd_st_rgb[0];
400 ncreg = 1 << dm->depth;
401
402 /* If first entry specified beyond capabilities -> error */
403 if (cm->first >= ncreg)
404 return (EINVAL);
405
406 /*
407 * A little tricky, the actual colormap pointer will be NULL
408 * when view is not displaying, valid otherwise.
409 */
410 if (v->flags & VF_DISPLAY)
411 creg = &creg[cm->first];
412 else creg = NULL;
413
414 vcreg = &vcm->entry[cm->first];
415 ncreg -= cm->first;
416 if (cm->size > ncreg)
417 return (EINVAL);
418 ncreg = cm->size;
419
420 for (i = 0, src = cm->entry; i < ncreg; i++, vcreg++) {
421 *vcreg = *src++;
422
423 /*
424 * If displaying, also update actual color register.
425 */
426 if (creg != NULL) {
427 *fcreg++ = CM_L2FAL(*vcreg);
428 if (i < 16 )
429 *creg++ = CM_L2ST(*vcreg);
430 }
431 }
432 return (0);
433 }
434
435 static view_t *
436 falcon_alloc_view(mode, dim, depth)
437 dmode_t *mode;
438 dimen_t *dim;
439 u_char depth;
440 {
441 view_t *v;
442 bmap_t *bm;
443
444 if (!atari_realconfig)
445 v = &gra_con_view;
446 else v = malloc(sizeof(*v), M_DEVBUF, M_NOWAIT);
447 if (v == NULL)
448 return(NULL);
449
450 bm = alloc_bitmap(mode->size.width, mode->size.height, mode->depth);
451 if (bm) {
452 box_t box;
453
454 v->colormap = alloc_colormap(mode);
455 if (v->colormap) {
456 INIT_BOX(&box,0,0,mode->size.width,mode->size.height);
457 init_view(v, bm, mode, &box);
458 return(v);
459 }
460 free_bitmap(bm);
461 }
462 if (v != &gra_con_view)
463 free(v, M_DEVBUF);
464 return (NULL);
465 }
466
467 static void
468 init_view(v, bm, mode, dbox)
469 view_t *v;
470 bmap_t *bm;
471 dmode_t *mode;
472 box_t *dbox;
473 {
474 v->bitmap = bm;
475 v->mode = mode;
476 v->flags = 0;
477 bcopy(dbox, &v->display, sizeof(box_t));
478 }
479
480 /* bitmap functions */
481
482 static bmap_t *
483 alloc_bitmap(width, height, depth)
484 u_long width, height;
485 u_char depth;
486 {
487 u_long total_size, bm_size;
488 void *hw_address;
489 bmap_t *bm;
490
491 /*
492 * Sigh, it seems for mapping to work we need the bitplane data to
493 * 1: be aligned on a page boundry.
494 * 2: be n pages large.
495 *
496 * why? because the user gets a page aligned address, if this is before
497 * your allocation, too bad. Also it seems that the mapping routines
498 * do not watch to closely to the allowable length. so if you go over
499 * n pages by less than another page, the user gets to write all over
500 * the entire page. Since you did not allocate up to a page boundry
501 * (or more) the user writes into someone elses memory. -ch
502 */
503 bm_size = atari_round_page((width * height * depth) / NBBY);
504 total_size = bm_size + sizeof(bmap_t) + NBPG;
505
506 if ((bm = (bmap_t*)alloc_stmem(total_size, &hw_address)) == NULL)
507 return(NULL);
508
509 bm->plane = (u_char*)bm + sizeof(bmap_t);
510 bm->plane = (u_char*)atari_round_page(bm->plane);
511 bm->hw_address = (u_char*)hw_address + sizeof(bmap_t);
512 bm->hw_address = (u_char*)atari_round_page(bm->hw_address);
513 bm->bytes_per_row = (width * depth) / NBBY;
514 bm->rows = height;
515 bm->depth = depth;
516
517 bzero(bm->plane, bm_size);
518 return (bm);
519 }
520
521 static void
522 free_bitmap(bm)
523 bmap_t *bm;
524 {
525 if (bm)
526 free_stmem(bm);
527 }
528
529 static colormap_t *
530 alloc_colormap(dm)
531 dmode_t *dm;
532 {
533 int nentries, i;
534 colormap_t *cm;
535 u_char type = CM_COLOR;
536
537 if (dm->depth == 16) /* direct color, no colormap;
538 not (yet) supported */
539 nentries = 0;
540 else
541 nentries = 1 << dm->depth;
542
543 if (!atari_realconfig) {
544 cm = &gra_con_cmap;
545 cm->entry = gra_con_colors;
546 }
547 else {
548 int size;
549
550 size = sizeof(*cm) + (nentries * sizeof(cm->entry[0]));
551 cm = malloc(size, M_DEVBUF, M_NOWAIT);
552 if (cm == NULL)
553 return(NULL);
554 cm->entry = (long *)&cm[1];
555
556 }
557
558 if ((cm->type = type) == CM_COLOR)
559 cm->red_mask = cm->green_mask = cm->blue_mask = 0x3f;
560
561 cm->first = 0;
562 cm->size = nentries;
563
564 for (i = 0; i < nentries; i++)
565 cm->entry[i] = gra_def_color16[i % 16];
566 return (cm);
567 }
568 #endif /* FALCON_VIDEO */
569