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