grfabs.c revision 1.2
1/* $NetBSD: grfabs.c,v 1.2 1995/03/28 06:35:40 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 */ 48static dmode_t *get_best_display_mode __P((int, int, int)); 49static view_t *alloc_view __P((dmode_t *, dimen_t *, u_char)); 50static void init_view __P((view_t *, bmap_t *, dmode_t *, box_t *)); 51static bmap_t *alloc_bitmap __P((u_long, u_long, u_char, int)); 52static void free_bitmap __P((bmap_t *)); 53static 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 */ 59extern int atari_realconfig; /* 0 -> no malloc */ 60static view_t con_view; 61static colormap_t con_cmap; 62static long con_colors[MAX_CENTRIES]; 63 64/* 65 * List of available graphic modes 66 */ 67static LIST_HEAD(modelist, display_mode) modes; 68 69static dmode_t vid_modes[] = { 70 { { NULL, NULL }, "stlow", { 320, 200 }, 4, 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 */ 88static 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 */ 111int 112grfabs_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 140 /* 141 * This seems to prevent bordered screens. 142 */ 143 for(i=0; i < 16; i++) 144 VIDEO->vd_tt_rgb[i] = def_color16[i]; 145 146 return(1); 147} 148 149view_t * 150grf_alloc_view(d, dim, depth) 151dmode_t *d; 152dimen_t *dim; 153u_char depth; 154{ 155 if(!d) 156 d = get_best_display_mode(dim->width, dim->height, depth); 157 if(d) 158 return(alloc_view(d, dim, depth)); 159 return(NULL); 160} 161 162void grf_display_view(v) 163view_t *v; 164{ 165 dmode_t *dm = v->mode; 166 bmap_t *bm = v->bitmap; 167 168 if(dm->current_view) { 169 /* 170 * Mark current view for this mode as no longer displayed 171 */ 172 dm->current_view->flags &= ~VF_DISPLAY; 173 } 174 dm->current_view = v; 175 v->flags |= VF_DISPLAY; 176 177 grf_use_colormap(v, v->colormap); 178 179 /* XXX: should use vbl for this */ 180 VIDEO->vd_tt_res = dm->vm_reg; 181 VIDEO->vd_raml = (u_long)bm->hw_address & 0xff; 182 VIDEO->vd_ramm = ((u_long)bm->hw_address >> 8) & 0xff; 183 VIDEO->vd_ramh = ((u_long)bm->hw_address >> 16) & 0xff; 184} 185 186void grf_remove_view(v) 187view_t *v; 188{ 189 dmode_t *mode = v->mode; 190 191 if(mode->current_view == v) { 192#if 0 193 if(v->flags & VF_DISPLAY) 194 panic("Cannot shutdown display\n"); /* XXX */ 195#endif 196 mode->current_view = NULL; 197 } 198 v->flags &= ~VF_DISPLAY; 199} 200 201void grf_free_view(v) 202view_t *v; 203{ 204 if(v) { 205 dmode_t *md = v->mode; 206 207 grf_remove_view(v); 208 if(v->colormap != &con_cmap) 209 free(v->colormap, M_DEVBUF); 210 free_bitmap(v->bitmap); 211 if(v != &con_view) 212 free(v, M_DEVBUF); 213 } 214} 215 216int 217grf_get_colormap(v, cm) 218view_t *v; 219colormap_t *cm; 220{ 221 colormap_t *gcm; 222 int i, n; 223 224 bzero(cm->entry, cm->size * sizeof(long)); 225 226 gcm = v->colormap; 227 n = cm->size < gcm->size ? cm->size : gcm->size; 228 for(i = 0; i < n; i++) 229 cm->entry[i] = gcm->entry[i]; 230 return(0); 231} 232 233int 234grf_use_colormap(v, cm) 235view_t *v; 236colormap_t *cm; 237{ 238 dmode_t *dm; 239 volatile u_short *creg; 240 long *src; 241 u_short ncreg; 242 int i; 243 244 dm = v->mode; 245 246 switch(dm->vm_reg) { 247 case RES_STLOW: 248 creg = &VIDEO->vd_tt_rgb[0]; 249 ncreg = 16; 250 break; 251 case RES_STMID: 252 creg = &VIDEO->vd_tt_rgb[0]; 253 ncreg = 4; 254 break; 255 case RES_STHIGH: 256 creg = &VIDEO->vd_tt_rgb[254]; 257 ncreg = 2; 258 break; 259 case RES_TTLOW: 260 creg = &VIDEO->vd_tt_rgb[0]; 261 ncreg = 256; 262 break; 263 case RES_TTMID: 264 creg = &VIDEO->vd_tt_rgb[0]; 265 ncreg = 16; 266 break; 267 case RES_TTHIGH: 268 return(0); /* No colors */ 269 default: 270 panic("grf_get_colormap: wrong mode!?"); 271 } 272 273 if(cm->first >= ncreg) 274 return(EINVAL); 275 creg = &creg[cm->first]; 276 ncreg -= cm->first; 277 278 if(cm->size > ncreg) 279 return(EINVAL); 280 ncreg = cm->size; 281 282 for(i = 0, src = cm->entry; i < ncreg; i++) { 283 register long val = *src++; 284 *creg++ = CM_LTOW(val); 285 } 286 return(0); 287} 288 289static dmode_t * 290get_best_display_mode(width, height, depth) 291int width, height, depth; 292{ 293 dmode_t *save; 294 dmode_t *dm; 295 long dt, dx, dy, ct; 296 297 save = NULL; 298 dm = modes.lh_first; 299 while(dm != NULL) { 300 if(depth > dm->depth) { 301 dm = dm->link.le_next; 302 continue; 303 } 304 else if(width > dm->size.width || height > dm->size.height) { 305 dm = dm->link.le_next; 306 continue; 307 } 308 else if (width < dm->size.width || height < dm->size.height) { 309 dm = dm->link.le_next; 310 continue; 311 } 312 dx = abs(dm->size.width - width); 313 dy = abs(dm->size.height - height); 314 ct = dx + dy; 315 316 if (ct < dt || save == NULL) { 317 save = dm; 318 dt = ct; 319 } 320 dm = dm->link.le_next; 321 } 322 return (save); 323} 324 325static view_t * 326alloc_view(mode, dim, depth) 327dmode_t *mode; 328dimen_t *dim; 329u_char depth; 330{ 331 view_t *v; 332 bmap_t *bm; 333 334 if(!atari_realconfig) 335 v = &con_view; 336 else v = malloc(sizeof(*v), M_DEVBUF, M_NOWAIT); 337 338 bm = alloc_bitmap(mode->size.width, mode->size.height, mode->depth, 1); 339 if(bm) { 340 int i; 341 box_t box; 342 343 v->colormap = alloc_colormap(mode); 344 if(v->colormap) { 345 INIT_BOX(&box,0,0,mode->size.width,mode->size.height); 346 init_view(v, bm, mode, &box); 347 return(v); 348 } 349 free_bitmap(bm); 350 } 351 if(v != &con_view) 352 free(v, M_DEVBUF); 353 return (NULL); 354} 355 356static void 357init_view(v, bm, mode, dbox) 358view_t *v; 359bmap_t *bm; 360dmode_t *mode; 361box_t *dbox; 362{ 363 v->bitmap = bm; 364 v->mode = mode; 365 bcopy(dbox, &v->display, sizeof(box_t)); 366} 367 368/* bitmap functions */ 369 370static bmap_t * 371alloc_bitmap(width, height, depth, clear) 372u_long width, height; 373u_char depth; 374int clear; 375{ 376 int i; 377 u_long total_size, bm_size; 378 void *hw_address; 379 bmap_t *bm; 380 381 /* 382 * Sigh, it seems for mapping to work we need the bitplane data to 383 * 1: be aligned on a page boundry. 384 * 2: be n pages large. 385 * 386 * why? because the user gets a page aligned address, if this is before 387 * your allocation, too bad. Also it seems that the mapping routines 388 * do not watch to closely to the allowable length. so if you go over 389 * n pages by less than another page, the user gets to write all over 390 * the entire page. Since you did not allocate up to a page boundry 391 * (or more) the user writes into someone elses memory. -ch 392 */ 393 bm_size = atari_round_page((width * height * depth) / NBBY); 394 total_size = bm_size + sizeof(bmap_t) + NBPG; 395 396 if((bm = (bmap_t*)alloc_stmem(total_size, &hw_address)) == NULL) 397 return(NULL); 398 399 bm->plane = (u_char*)bm + sizeof(bmap_t); 400 bm->plane = (u_char*)atari_round_page(bm->plane); 401 bm->hw_address = (u_char*)hw_address + sizeof(bmap_t); 402 bm->hw_address = (u_char*)atari_round_page(bm->hw_address); 403 bm->bytes_per_row = (width * depth) / NBBY; 404 bm->rows = height; 405 bm->depth = depth; 406 407 if(clear) 408 bzero(bm->plane, bm_size); 409 return(bm); 410} 411 412static void 413free_bitmap(bm) 414bmap_t *bm; 415{ 416 if(bm) 417 free_stmem(bm); 418} 419 420static colormap_t * 421alloc_colormap(dm) 422dmode_t *dm; 423{ 424 int nentries, i; 425 colormap_t *cm; 426 u_char type = CM_COLOR; 427 428 switch(dm->vm_reg) { 429 case RES_STLOW: 430 case RES_TTMID: 431 nentries = 16; 432 break; 433 case RES_STMID: 434 nentries = 4; 435 break; 436 case RES_STHIGH: 437 nentries = 2; 438 break; 439 case RES_TTLOW: 440 nentries = 256; 441 break; 442 case RES_TTHIGH: 443 type = CM_MONO; 444 nentries = 0; 445 default: 446 panic("grf:alloc_colormap: wrong mode!?"); 447 } 448 if(!atari_realconfig) { 449 cm = &con_cmap; 450 cm->entry = con_colors; 451 } 452 else { 453 int size; 454 455 size = sizeof(*cm) + (nentries * sizeof(cm->entry[0])); 456 cm = malloc(size, M_DEVBUF, M_NOWAIT); 457 if(cm == NULL) 458 return(NULL); 459 cm->entry = (long *)&cm[1]; 460 461 } 462 if((cm->type = type) == CM_COLOR) 463 cm->red_mask = cm->green_mask = cm->blue_mask = 0xf; 464 cm->first = 0; 465 cm->size = nentries; 466 467 for(i = 0; i < nentries; i++) { 468 register short val = def_color16[i % 16]; 469 cm->entry[i] = CM_WTOL(val); 470 } 471 return(cm); 472} 473