1 /* $NetBSD: view.c,v 1.30 2009/03/18 17:06:43 cegger Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Christian E. Hopps 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 Christian E. Hopps. 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 /* The view major device is a placeholder device. It serves 34 * simply to map the semantics of a graphics dipslay to 35 * the semantics of a character block device. In other 36 * words the graphics system as currently built does not like to be 37 * refered to by open/close/ioctl. This device serves as 38 * a interface to graphics. */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: view.c,v 1.30 2009/03/18 17:06:43 cegger Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/proc.h> 46 #include <sys/ioctl.h> 47 #include <sys/file.h> 48 #include <sys/device.h> 49 #include <sys/malloc.h> 50 #include <sys/queue.h> 51 #include <sys/conf.h> 52 #include <machine/cpu.h> 53 #include <atari/dev/grfabs_reg.h> 54 #include <atari/dev/viewioctl.h> 55 #include <atari/dev/viewvar.h> 56 #include "view.h" 57 58 static void view_display(struct view_softc *); 59 static void view_remove(struct view_softc *); 60 static int view_setsize(struct view_softc *, struct view_size *); 61 static int view_get_colormap(struct view_softc *, colormap_t *); 62 static int view_set_colormap(struct view_softc *, colormap_t *); 63 64 struct view_softc views[NVIEW]; 65 static int view_inited; 66 67 int view_default_x; 68 int view_default_y; 69 int view_default_width = 640; 70 int view_default_height = 400; 71 int view_default_depth = 1; 72 73 dev_type_open(viewopen); 74 dev_type_close(viewclose); 75 dev_type_ioctl(viewioctl); 76 dev_type_mmap(viewmmap); 77 78 const struct cdevsw view_cdevsw = { 79 viewopen, viewclose, nullread, nullwrite, viewioctl, 80 nostop, notty, nopoll, viewmmap, nokqfilter, 81 }; 82 83 /* 84 * functions for probeing. 85 */ 86 void viewattach(int); 87 88 void 89 viewattach(int cnt) 90 { 91 viewprobe(); 92 printf("%d view%s configured\n", NVIEW, NVIEW > 1 ? "s" : ""); 93 } 94 95 /* this function is called early to set up a display. */ 96 int 97 viewprobe(void) 98 { 99 int i; 100 101 if(view_inited) 102 return(1); 103 104 view_inited = 1; 105 106 for(i=0; i<NVIEW; i++) { 107 views[i].view = NULL; 108 views[i].flags = 0; 109 } 110 return(1); 111 } 112 113 114 /* 115 * Internal functions. 116 */ 117 118 static void 119 view_display (struct view_softc *vu) 120 { 121 int s, i; 122 123 if (vu == NULL) 124 return; 125 126 s = spltty(); 127 128 /* 129 * mark views that share this monitor as not displaying 130 */ 131 for (i = 0; i < NVIEW; i++) { 132 if(views[i].flags & VUF_DISPLAY) { 133 if (vu->view && (vu->view == views[i].view)) { 134 splx(s); 135 return; 136 } 137 if (views[i].view) { 138 grf_save_view(views[i].view); 139 views[i].view->flags &= ~VF_DISPLAY; 140 } 141 views[i].flags &= ~VUF_DISPLAY; 142 } 143 } 144 145 vu->flags |= VUF_ADDED; 146 if (vu->view) { 147 vu->view->display.x = vu->size.x; 148 vu->view->display.y = vu->size.y; 149 150 grf_display_view(vu->view); 151 vu->view->flags |= VF_DISPLAY; 152 153 vu->size.x = vu->view->display.x; 154 vu->size.y = vu->view->display.y; 155 vu->flags |= VUF_DISPLAY; 156 } 157 splx(s); 158 } 159 160 /* 161 * remove a view from our added list if it is marked as displaying 162 * switch to a new display. 163 */ 164 static void 165 view_remove(struct view_softc *vu) 166 { 167 int i; 168 169 if ((vu->flags & VUF_ADDED) == 0) 170 return; 171 172 vu->flags &= ~VUF_ADDED; 173 if (vu->flags & VUF_DISPLAY) { 174 for (i = 0; i < NVIEW; i++) { 175 if((views[i].flags & VUF_ADDED) && &views[i] != vu) { 176 view_display(&views[i]); 177 break; 178 } 179 } 180 } 181 vu->flags &= ~VUF_DISPLAY; 182 grf_remove_view(vu->view); 183 } 184 185 static int 186 view_setsize(struct view_softc *vu, struct view_size *vs) 187 { 188 view_t *new, *old; 189 dmode_t *dmode; 190 dimen_t ns; 191 int co, cs; 192 193 co = 0; 194 cs = 0; 195 if (vs->x != vu->size.x || vs->y != vu->size.y) 196 co = 1; 197 198 if (vs->width != vu->size.width || vs->height != vu->size.height || 199 vs->depth != vu->size.depth) 200 cs = 1; 201 202 if (cs == 0 && co == 0) 203 return(0); 204 205 ns.width = vs->width; 206 ns.height = vs->height; 207 208 if((dmode = grf_get_best_mode(&ns, vs->depth)) != NULL) { 209 /* 210 * If we can't do better, leave it 211 */ 212 if(dmode == vu->view->mode) 213 return(0); 214 } 215 new = grf_alloc_view(dmode, &ns, vs->depth); 216 if (new == NULL) 217 return(ENOMEM); 218 219 old = vu->view; 220 vu->view = new; 221 vu->size.x = new->display.x; 222 vu->size.y = new->display.y; 223 vu->size.width = new->display.width; 224 vu->size.height = new->display.height; 225 vu->size.depth = new->bitmap->depth; 226 227 /* 228 * we need a custom remove here to avoid letting 229 * another view display mark as not added or displayed 230 */ 231 if (vu->flags & VUF_DISPLAY) { 232 vu->flags &= ~(VUF_ADDED|VUF_DISPLAY); 233 view_display(vu); 234 } 235 grf_free_view(old); 236 return(0); 237 } 238 239 static int 240 view_get_colormap (struct view_softc *vu, colormap_t *ucm) 241 { 242 int error; 243 long *cme; 244 long *uep; 245 246 if(ucm->size > MAX_CENTRIES) 247 return(EINVAL); 248 249 /* add one incase of zero, ick. */ 250 cme = malloc(sizeof(ucm->entry[0])*(ucm->size+1), M_TEMP,M_WAITOK); 251 if (cme == NULL) 252 return(ENOMEM); 253 254 error = 0; 255 uep = ucm->entry; 256 ucm->entry = cme; /* set entry to out alloc. */ 257 if(vu->view == NULL || grf_get_colormap(vu->view, ucm)) 258 error = EINVAL; 259 else error = copyout(cme, uep, sizeof(ucm->entry[0]) * ucm->size); 260 ucm->entry = uep; /* set entry back to users. */ 261 free(cme, M_TEMP); 262 return(error); 263 } 264 265 static int 266 view_set_colormap(struct view_softc *vu, colormap_t *ucm) 267 { 268 colormap_t *cm; 269 int error = 0; 270 271 if(ucm->size > MAX_CENTRIES) 272 return(EINVAL); 273 274 cm = malloc(sizeof(ucm->entry[0])*ucm->size + sizeof(*cm), M_TEMP, 275 M_WAITOK); 276 if(cm == NULL) 277 return(ENOMEM); 278 279 memcpy( cm, ucm, sizeof(colormap_t)); 280 cm->entry = (long *)&cm[1]; /* table directly after. */ 281 if (((error = 282 copyin(ucm->entry,cm->entry,sizeof(ucm->entry[0])*ucm->size)) == 0) 283 && (vu->view == NULL || grf_use_colormap(vu->view, cm))) 284 error = EINVAL; 285 free(cm, M_TEMP); 286 return(error); 287 } 288 289 /* 290 * functions made available by conf.c 291 */ 292 293 /*ARGSUSED*/ 294 int 295 viewopen(dev_t dev, int flags, int mode, struct lwp *l) 296 { 297 dimen_t size; 298 struct view_softc *vu; 299 300 vu = &views[minor(dev)]; 301 302 if(minor(dev) >= NVIEW) 303 return(EXDEV); 304 if(vu->flags & VUF_OPEN) 305 return(EBUSY); 306 307 vu->size.x = view_default_x; 308 vu->size.y = view_default_y; 309 size.width = vu->size.width = view_default_width; 310 size.height = vu->size.height = view_default_height; 311 vu->size.depth = view_default_depth; 312 vu->view = grf_alloc_view(NULL, &size, vu->size.depth); 313 if (vu->view == NULL) 314 return(ENOMEM); 315 316 vu->size.x = vu->view->display.x; 317 vu->size.y = vu->view->display.y; 318 vu->size.width = vu->view->display.width; 319 vu->size.height = vu->view->display.height; 320 vu->size.depth = vu->view->bitmap->depth; 321 vu->flags |= VUF_OPEN; 322 return(0); 323 } 324 325 /*ARGSUSED*/ 326 int 327 viewclose (dev_t dev, int flags, int mode, struct lwp *l) 328 { 329 struct view_softc *vu; 330 331 vu = &views[minor(dev)]; 332 333 if ((vu->flags & VUF_OPEN) == 0) 334 return (0); /* XXX not open? */ 335 view_remove (vu); 336 grf_free_view (vu->view); 337 vu->flags = 0; 338 vu->view = NULL; 339 return (0); 340 } 341 342 343 /*ARGSUSED*/ 344 int 345 viewioctl (dev_t dev, u_long cmd, void * data, int flag, struct lwp *l) 346 { 347 struct view_softc *vu; 348 bmap_t *bm; 349 int error; 350 351 vu = &views[minor(dev)]; 352 error = 0; 353 354 switch (cmd) { 355 case VIOCDISPLAY: 356 view_display(vu); 357 break; 358 case VIOCREMOVE: 359 view_remove(vu); 360 break; 361 case VIOCGSIZE: 362 memcpy( data, &vu->size, sizeof (struct view_size)); 363 break; 364 case VIOCSSIZE: 365 error = view_setsize(vu, (struct view_size *)data); 366 break; 367 case VIOCGBMAP: 368 bm = (bmap_t *)data; 369 memcpy( bm, vu->view->bitmap, sizeof(bmap_t)); 370 if (l != NOLWP) { 371 bm->plane = NULL; 372 bm->hw_address = NULL; 373 bm->regs = NULL; 374 bm->hw_regs = NULL; 375 } 376 break; 377 case VIOCGCMAP: 378 error = view_get_colormap(vu, (colormap_t *)data); 379 break; 380 case VIOCSCMAP: 381 error = view_set_colormap(vu, (colormap_t *)data); 382 break; 383 default: 384 error = EPASSTHROUGH; 385 break; 386 } 387 return(error); 388 } 389 390 /*ARGSUSED*/ 391 paddr_t 392 viewmmap(dev_t dev, off_t off, int prot) 393 { 394 struct view_softc *vu; 395 bmap_t *bm; 396 u_char *bmd_start; 397 u_long bmd_lin, bmd_vga; 398 399 vu = &views[minor(dev)]; 400 bm = vu->view->bitmap; 401 bmd_start = bm->hw_address; 402 bmd_lin = bm->lin_base; 403 bmd_vga = bm->vga_base; 404 405 /* 406 * control registers 407 */ 408 if (off >= 0 && off < bm->reg_size) 409 return(((paddr_t)bm->hw_regs + off) >> PGSHIFT); 410 411 /* 412 * VGA memory 413 */ 414 if (off >= bmd_vga && off < (bmd_vga + bm->vga_mappable)) 415 return(((paddr_t)bm->vga_address - bmd_vga + off) >> PGSHIFT); 416 417 /* 418 * frame buffer 419 */ 420 if (off >= bmd_lin && off < (bmd_lin + bm->phys_mappable)) 421 return(((paddr_t)bmd_start - bmd_lin + off) >> PGSHIFT); 422 423 return(-1); 424 } 425 426 view_t * 427 viewview(dev_t dev) 428 { 429 return(views[minor(dev)].view); 430 } 431