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