grfabs.c revision 1.1 1 /* $NetBSD: grfabs.c,v 1.1 1995/03/26 07:12:15 leo Exp $ */
2
3 /*
4 * Copyright (c) 1995 Leo Weppelman.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Leo Weppelman.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * atari abstract graphics driver.
35 */
36 #include <sys/param.h>
37 #include <sys/queue.h>
38 #include <sys/malloc.h>
39
40 #include <machine/iomap.h>
41 #include <machine/video.h>
42 #include <machine/mfp.h>
43 #include <atari/dev/grfabs_reg.h>
44
45 /*
46 * Function decls
47 */
48 static dmode_t *get_best_display_mode __P((int, int, int));
49 static view_t *alloc_view __P((dmode_t *, dimen_t *, u_char));
50 static void init_view __P((view_t *, bmap_t *, dmode_t *, box_t *));
51 static bmap_t *alloc_bitmap __P((u_long, u_long, u_char, int));
52 static void free_bitmap __P((bmap_t *));
53 static colormap_t *alloc_colormap __P((dmode_t *));
54
55 /*
56 * Ugh.. Stuff needed to allocate console structures before the VM-system
57 * is running. There is no malloc() available at that time.
58 */
59 extern int atari_realconfig; /* 0 -> no malloc */
60 static view_t con_view;
61 static colormap_t con_cmap;
62 static u_short con_colors[MAX_CENTRIES];
63
64 /*
65 * List of available graphic modes
66 */
67 static LIST_HEAD(modelist, display_mode) modes;
68
69 static dmode_t vid_modes[] = {
70 { { NULL, NULL }, "stlow", { 320, 200 }, 1, RES_STLOW },
71 { { NULL, NULL }, "stmid", { 640, 200 }, 2, RES_STMID },
72 { { NULL, NULL }, "sthigh", { 640, 400 }, 1, RES_STHIGH },
73 { { NULL, NULL }, "ttlow", { 320, 480 }, 8, RES_TTLOW },
74 { { NULL, NULL }, "ttmid", { 640, 480 }, 4, RES_TTMID },
75 { { NULL, NULL }, "tthigh", { 1280, 960 }, 1, RES_TTHIGH },
76 { { NULL, NULL }, NULL, }
77 };
78
79 /*
80 * Default colors.....
81 * Currently the TT-low (256 colors) just uses 16 time the 16-color default.
82 * If you have a sensible 256 scale, feel free to add.....
83 * The first 2 colors in all maps are {black,white}, so ite (text) displays
84 * are initially readable. Also, this enables me to supply only 1 map. The
85 * 4 color mode uses the first four entries of the 16 color mode thus giving
86 * a gray scale display. (Maybe we can add an intensity bit to the ite...)
87 */
88 static u_short def_color16[16] = {
89 0x000, /* black */
90 0xfff, /* white */
91 0xccc, /* light gray */
92 0x888, /* gray */
93 0x00c, /* blue */
94 0x0c0, /* green */
95 0x0cc, /* cyan */
96 0xc00, /* red */
97 0xc0c, /* magenta */
98 0xcc0, /* brown */
99 0x00f, /* light blue */
100 0x0f0, /* light green */
101 0x0ff, /* light cyan */
102 0xf00, /* light red */
103 0xf0f, /* light magenta */
104 0xff0 /* light brown */
105 };
106
107 /*
108 * XXX: called from ite console init routine.
109 * Initialize list of posible video modes.
110 */
111 int
112 grfabs_probe()
113 {
114 dmode_t *dm;
115 int i;
116 int has_mono;
117 static int inited = 0;
118
119 if(inited)
120 return; /* Has to be done only once */
121 inited++;
122
123 /*
124 * First find out what kind of monitor is attached. Dma-sound
125 * should be off because the 'sound-done' and 'monochrome-detect'
126 * are xor-ed together. I think that shutting it down here is the
127 * wrong place.
128 */
129 has_mono = (MFP->mf_gpip & IA_MONO) == 0;
130
131 LIST_INIT(&modes);
132 for(i = 0; (dm = &vid_modes[i])->name != NULL; i++) {
133 if(has_mono && (dm->vm_reg != RES_TTHIGH))
134 continue;
135 if(!has_mono && (dm->vm_reg == RES_TTHIGH))
136 continue;
137 LIST_INSERT_HEAD(&modes, dm, link);
138 }
139 return(1);
140 }
141
142 view_t *
143 grf_alloc_view(d, dim, depth)
144 dmode_t *d;
145 dimen_t *dim;
146 u_char depth;
147 {
148 if(!d)
149 d = get_best_display_mode(dim->width, dim->height, depth);
150 if(d)
151 return(alloc_view(d, dim, depth));
152 return(NULL);
153 }
154
155 void grf_display_view(v)
156 view_t *v;
157 {
158 dmode_t *dm = v->mode;
159 bmap_t *bm = v->bitmap;
160
161 if(dm->current_view) {
162 /*
163 * Mark current view for this mode as no longer displayed
164 */
165 dm->current_view->flags &= ~VF_DISPLAY;
166 }
167 dm->current_view = v;
168 v->flags |= VF_DISPLAY;
169
170 grf_use_colormap(v, v->colormap);
171
172 /* XXX: should use vbl for this */
173 VIDEO->vd_tt_res = dm->vm_reg;
174 VIDEO->vd_raml = (u_long)bm->hw_address & 0xff;
175 VIDEO->vd_ramm = ((u_long)bm->hw_address >> 8) & 0xff;
176 VIDEO->vd_ramh = ((u_long)bm->hw_address >> 16) & 0xff;
177 }
178
179 void grf_remove_view(v)
180 view_t *v;
181 {
182 dmode_t *mode = v->mode;
183
184 if(mode->current_view == v) {
185 #if 0
186 if(v->flags & VF_DISPLAY)
187 panic("Cannot shutdown display\n"); /* XXX */
188 #endif
189 mode->current_view = NULL;
190 }
191 v->flags &= ~VF_DISPLAY;
192 }
193
194 void grf_free_view(v)
195 view_t *v;
196 {
197 if(v) {
198 dmode_t *md = v->mode;
199
200 grf_remove_view(v);
201 if(v->colormap != &con_cmap)
202 free(v->colormap, M_DEVBUF);
203 free_bitmap(v->bitmap);
204 if(v != &con_view)
205 free(v, M_DEVBUF);
206 }
207 }
208
209 int
210 grf_get_colormap(v, cm)
211 view_t *v;
212 colormap_t *cm;
213 {
214 colormap_t *gcm;
215 int i, n;
216
217 bzero(cm->centry, cm->nentries * sizeof(u_short));
218
219 gcm = v->colormap;
220 n = cm->nentries < gcm->nentries ? cm->nentries : gcm->nentries;
221 for(i = 0; i < n; i++)
222 cm->centry[i] = gcm->centry[i];
223 return(0);
224 }
225
226 int
227 grf_use_colormap(v, cm)
228 view_t *v;
229 colormap_t *cm;
230 {
231 dmode_t *dm;
232 volatile u_short *creg;
233 u_short *src;
234 u_short ncreg;
235 int i;
236
237 dm = v->mode;
238
239 switch(dm->vm_reg) {
240 case RES_STLOW:
241 creg = &VIDEO->vd_tt_rgb[0];
242 ncreg = 16;
243 break;
244 case RES_STMID:
245 creg = &VIDEO->vd_tt_rgb[0];
246 ncreg = 4;
247 break;
248 case RES_STHIGH:
249 creg = &VIDEO->vd_tt_rgb[254];
250 ncreg = 2;
251 break;
252 case RES_TTLOW:
253 creg = &VIDEO->vd_tt_rgb[0];
254 ncreg = 256;
255 break;
256 case RES_TTMID:
257 creg = &VIDEO->vd_tt_rgb[0];
258 ncreg = 16;
259 break;
260 case RES_TTHIGH:
261 return(0); /* No colors */
262 default:
263 panic("grf_get_colormap: wrong mode!?");
264 }
265 if(cm->nentries < ncreg)
266 ncreg = cm->nentries;
267
268 for(i = 0, src = cm->centry; i < ncreg; i++)
269 *creg++ = *src++;
270 return(0);
271 }
272
273 static dmode_t *
274 get_best_display_mode(width, height, depth)
275 int width, height, depth;
276 {
277 dmode_t *save;
278 dmode_t *dm;
279 long dt, dx, dy, ct;
280
281 save = NULL;
282 dm = modes.lh_first;
283 while(dm != NULL) {
284 if(depth > dm->depth) {
285 dm = dm->link.le_next;
286 continue;
287 }
288 else if(width > dm->size.width || height > dm->size.height) {
289 dm = dm->link.le_next;
290 continue;
291 }
292 else if (width < dm->size.width || height < dm->size.height) {
293 dm = dm->link.le_next;
294 continue;
295 }
296 dx = abs(dm->size.width - width);
297 dy = abs(dm->size.height - height);
298 ct = dx + dy;
299
300 if (ct < dt || save == NULL) {
301 save = dm;
302 dt = ct;
303 }
304 dm = dm->link.le_next;
305 }
306 return (save);
307 }
308
309 static view_t *
310 alloc_view(mode, dim, depth)
311 dmode_t *mode;
312 dimen_t *dim;
313 u_char depth;
314 {
315 view_t *v;
316 bmap_t *bm;
317
318 if(!atari_realconfig)
319 v = &con_view;
320 else v = malloc(sizeof(*v), M_DEVBUF, M_WAITOK);
321
322 bm = alloc_bitmap(mode->size.width, mode->size.height, mode->depth, 1);
323 if(bm) {
324 int i;
325 box_t box;
326
327 v->colormap = alloc_colormap(mode);
328 if(v->colormap) {
329 INIT_BOX(&box,0,0,mode->size.width,mode->size.height);
330 init_view(v, bm, mode, &box);
331 return(v);
332 }
333 free_bitmap(bm);
334 }
335 if(v != &con_view)
336 free(v, M_DEVBUF);
337 return (NULL);
338 }
339
340 static void
341 init_view(v, bm, mode, dbox)
342 view_t *v;
343 bmap_t *bm;
344 dmode_t *mode;
345 box_t *dbox;
346 {
347 v->bitmap = bm;
348 v->mode = mode;
349 bcopy(dbox, &v->display, sizeof(box_t));
350 }
351
352 /* bitmap functions */
353
354 static bmap_t *
355 alloc_bitmap(width, height, depth, clear)
356 u_long width, height;
357 u_char depth;
358 int clear;
359 {
360 int i;
361 u_long total_size, bm_size;
362 void *hw_address;
363 bmap_t *bm;
364
365 /*
366 * Sigh, it seems for mapping to work we need the bitplane data to
367 * 1: be aligned on a page boundry.
368 * 2: be n pages large.
369 *
370 * why? because the user gets a page aligned address, if this is before
371 * your allocation, too bad. Also it seems that the mapping routines
372 * do not watch to closely to the allowable length. so if you go over
373 * n pages by less than another page, the user gets to write all over
374 * the entire page. Since you did not allocate up to a page boundry
375 * (or more) the user writes into someone elses memory. -ch
376 */
377 bm_size = atari_round_page((width * height * depth) / NBBY);
378 total_size = bm_size + sizeof(bmap_t) + NBPG;
379
380 if((bm = (bmap_t*)alloc_stmem(total_size, &hw_address)) == NULL)
381 return(NULL);
382
383 bm->plane = (u_char*)bm + sizeof(bmap_t);
384 bm->plane = (u_char*)atari_round_page(bm->plane);
385 bm->hw_address = (u_char*)hw_address + sizeof(bmap_t);
386 bm->hw_address = (u_char*)atari_round_page(bm->hw_address);
387 bm->bytes_per_row = (width * depth) / NBBY;
388 bm->rows = height;
389 bm->depth = depth;
390
391 if(clear)
392 bzero(bm->plane, bm_size);
393 return(bm);
394 }
395
396 static void
397 free_bitmap(bm)
398 bmap_t *bm;
399 {
400 if(bm)
401 free_stmem(bm);
402 }
403
404 static colormap_t *
405 alloc_colormap(dm)
406 dmode_t *dm;
407 {
408 int nentries, i;
409 colormap_t *cm;
410
411 switch(dm->vm_reg) {
412 case RES_STLOW:
413 case RES_TTMID:
414 nentries = 16;
415 break;
416 case RES_STMID:
417 nentries = 4;
418 break;
419 case RES_STHIGH:
420 nentries = 2;
421 break;
422 case RES_TTLOW:
423 nentries = 256;
424 break;
425 case RES_TTHIGH:
426 nentries = 0;
427 default:
428 panic("grf:alloc_colormap: wrong mode!?");
429 }
430 if(!atari_realconfig) {
431 cm = &con_cmap;
432 cm->centry = con_colors;
433 }
434 else {
435 int size;
436
437 size = sizeof(*cm) + (nentries * sizeof(u_short));
438 cm = malloc(size, M_DEVBUF, M_WAITOK);
439 if(cm == NULL)
440 return(NULL);
441 cm->centry = (u_short *)&cm[1];
442
443 }
444 cm->nentries = nentries;
445
446 for(i = 0; i < nentries; i++)
447 cm->centry[i] = def_color16[i % 16];
448 return(cm);
449 }
450