1 1.40 andvar /* $NetBSD: view.c,v 1.40 2025/01/27 21:20:25 andvar Exp $ */ 2 1.1 leo 3 1.1 leo /* 4 1.1 leo * Copyright (c) 1994 Christian E. Hopps 5 1.1 leo * All rights reserved. 6 1.1 leo * 7 1.1 leo * Redistribution and use in source and binary forms, with or without 8 1.1 leo * modification, are permitted provided that the following conditions 9 1.1 leo * are met: 10 1.1 leo * 1. Redistributions of source code must retain the above copyright 11 1.1 leo * notice, this list of conditions and the following disclaimer. 12 1.1 leo * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 leo * notice, this list of conditions and the following disclaimer in the 14 1.1 leo * documentation and/or other materials provided with the distribution. 15 1.1 leo * 3. All advertising materials mentioning features or use of this software 16 1.1 leo * must display the following acknowledgement: 17 1.1 leo * This product includes software developed by Christian E. Hopps. 18 1.1 leo * 4. The name of the author may not be used to endorse or promote products 19 1.1 leo * derived from this software without specific prior written permission 20 1.1 leo * 21 1.1 leo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 leo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 leo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 leo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 leo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 1.1 leo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.1 leo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 leo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.1 leo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 1.1 leo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.1 leo */ 32 1.1 leo 33 1.1 leo /* The view major device is a placeholder device. It serves 34 1.39 andvar * simply to map the semantics of a graphics display to 35 1.1 leo * the semantics of a character block device. In other 36 1.1 leo * words the graphics system as currently built does not like to be 37 1.36 andvar * referred to by open/close/ioctl. This device serves as 38 1.1 leo * a interface to graphics. */ 39 1.22 lukem 40 1.22 lukem #include <sys/cdefs.h> 41 1.40 andvar __KERNEL_RCSID(0, "$NetBSD: view.c,v 1.40 2025/01/27 21:20:25 andvar Exp $"); 42 1.1 leo 43 1.1 leo #include <sys/param.h> 44 1.7 leo #include <sys/systm.h> 45 1.1 leo #include <sys/proc.h> 46 1.1 leo #include <sys/ioctl.h> 47 1.1 leo #include <sys/file.h> 48 1.1 leo #include <sys/device.h> 49 1.1 leo #include <sys/malloc.h> 50 1.1 leo #include <sys/queue.h> 51 1.8 leo #include <sys/conf.h> 52 1.1 leo #include <machine/cpu.h> 53 1.1 leo #include <atari/dev/grfabs_reg.h> 54 1.1 leo #include <atari/dev/viewioctl.h> 55 1.1 leo #include <atari/dev/viewvar.h> 56 1.35 christos 57 1.1 leo #include "view.h" 58 1.35 christos #include "ioconf.h" 59 1.1 leo 60 1.26 dsl static void view_display(struct view_softc *); 61 1.26 dsl static void view_remove(struct view_softc *); 62 1.26 dsl static int view_setsize(struct view_softc *, struct view_size *); 63 1.26 dsl static int view_get_colormap(struct view_softc *, colormap_t *); 64 1.26 dsl static int view_set_colormap(struct view_softc *, colormap_t *); 65 1.1 leo 66 1.1 leo struct view_softc views[NVIEW]; 67 1.1 leo static int view_inited; 68 1.1 leo 69 1.1 leo int view_default_x; 70 1.1 leo int view_default_y; 71 1.1 leo int view_default_width = 640; 72 1.1 leo int view_default_height = 400; 73 1.1 leo int view_default_depth = 1; 74 1.19 gehenna 75 1.37 tsutsui static dev_type_open(viewopen); 76 1.37 tsutsui static dev_type_close(viewclose); 77 1.37 tsutsui static dev_type_ioctl(viewioctl); 78 1.37 tsutsui static dev_type_mmap(viewmmap); 79 1.19 gehenna 80 1.19 gehenna const struct cdevsw view_cdevsw = { 81 1.33 dholland .d_open = viewopen, 82 1.33 dholland .d_close = viewclose, 83 1.33 dholland .d_read = nullread, 84 1.33 dholland .d_write = nullwrite, 85 1.33 dholland .d_ioctl = viewioctl, 86 1.33 dholland .d_stop = nostop, 87 1.33 dholland .d_tty = notty, 88 1.33 dholland .d_poll = nopoll, 89 1.33 dholland .d_mmap = viewmmap, 90 1.33 dholland .d_kqfilter = nokqfilter, 91 1.34 dholland .d_discard = nodiscard, 92 1.33 dholland .d_flag = 0 93 1.19 gehenna }; 94 1.1 leo 95 1.38 tsutsui /* 96 1.40 andvar * functions for probing. 97 1.1 leo */ 98 1.7 leo void 99 1.27 dsl viewattach(int cnt) 100 1.1 leo { 101 1.1 leo viewprobe(); 102 1.13 christos printf("%d view%s configured\n", NVIEW, NVIEW > 1 ? "s" : ""); 103 1.1 leo } 104 1.1 leo 105 1.1 leo /* this function is called early to set up a display. */ 106 1.7 leo int 107 1.29 cegger viewprobe(void) 108 1.1 leo { 109 1.38 tsutsui int i; 110 1.38 tsutsui 111 1.32 tsutsui if (view_inited) 112 1.32 tsutsui return 1; 113 1.1 leo 114 1.1 leo view_inited = 1; 115 1.1 leo 116 1.32 tsutsui for (i = 0; i < NVIEW; i++) { 117 1.1 leo views[i].view = NULL; 118 1.1 leo views[i].flags = 0; 119 1.1 leo } 120 1.32 tsutsui return 1; 121 1.1 leo } 122 1.1 leo 123 1.1 leo 124 1.1 leo /* 125 1.1 leo * Internal functions. 126 1.1 leo */ 127 1.1 leo 128 1.1 leo static void 129 1.28 dsl view_display (struct view_softc *vu) 130 1.1 leo { 131 1.1 leo int s, i; 132 1.1 leo 133 1.1 leo if (vu == NULL) 134 1.1 leo return; 135 1.38 tsutsui 136 1.9 leo s = spltty(); 137 1.1 leo 138 1.1 leo /* 139 1.38 tsutsui * mark views that share this monitor as not displaying 140 1.1 leo */ 141 1.9 leo for (i = 0; i < NVIEW; i++) { 142 1.32 tsutsui if (views[i].flags & VUF_DISPLAY) { 143 1.9 leo if (vu->view && (vu->view == views[i].view)) { 144 1.9 leo splx(s); 145 1.9 leo return; 146 1.9 leo } 147 1.11 leo if (views[i].view) { 148 1.11 leo grf_save_view(views[i].view); 149 1.11 leo views[i].view->flags &= ~VF_DISPLAY; 150 1.11 leo } 151 1.1 leo views[i].flags &= ~VUF_DISPLAY; 152 1.9 leo } 153 1.1 leo } 154 1.1 leo 155 1.1 leo vu->flags |= VUF_ADDED; 156 1.1 leo if (vu->view) { 157 1.1 leo vu->view->display.x = vu->size.x; 158 1.1 leo vu->view->display.y = vu->size.y; 159 1.1 leo 160 1.1 leo grf_display_view(vu->view); 161 1.11 leo vu->view->flags |= VF_DISPLAY; 162 1.1 leo 163 1.1 leo vu->size.x = vu->view->display.x; 164 1.1 leo vu->size.y = vu->view->display.y; 165 1.1 leo vu->flags |= VUF_DISPLAY; 166 1.1 leo } 167 1.1 leo splx(s); 168 1.1 leo } 169 1.1 leo 170 1.38 tsutsui /* 171 1.1 leo * remove a view from our added list if it is marked as displaying 172 1.1 leo * switch to a new display. 173 1.1 leo */ 174 1.1 leo static void 175 1.27 dsl view_remove(struct view_softc *vu) 176 1.1 leo { 177 1.1 leo int i; 178 1.1 leo 179 1.1 leo if ((vu->flags & VUF_ADDED) == 0) 180 1.1 leo return; 181 1.1 leo 182 1.1 leo vu->flags &= ~VUF_ADDED; 183 1.1 leo if (vu->flags & VUF_DISPLAY) { 184 1.1 leo for (i = 0; i < NVIEW; i++) { 185 1.32 tsutsui if ((views[i].flags & VUF_ADDED) && &views[i] != vu) { 186 1.1 leo view_display(&views[i]); 187 1.1 leo break; 188 1.1 leo } 189 1.1 leo } 190 1.1 leo } 191 1.1 leo vu->flags &= ~VUF_DISPLAY; 192 1.1 leo grf_remove_view(vu->view); 193 1.1 leo } 194 1.1 leo 195 1.1 leo static int 196 1.27 dsl view_setsize(struct view_softc *vu, struct view_size *vs) 197 1.1 leo { 198 1.4 leo view_t *new, *old; 199 1.4 leo dmode_t *dmode; 200 1.1 leo dimen_t ns; 201 1.4 leo int co, cs; 202 1.38 tsutsui 203 1.1 leo co = 0; 204 1.1 leo cs = 0; 205 1.1 leo if (vs->x != vu->size.x || vs->y != vu->size.y) 206 1.1 leo co = 1; 207 1.1 leo 208 1.1 leo if (vs->width != vu->size.width || vs->height != vu->size.height || 209 1.1 leo vs->depth != vu->size.depth) 210 1.1 leo cs = 1; 211 1.1 leo 212 1.1 leo if (cs == 0 && co == 0) 213 1.32 tsutsui return 0; 214 1.38 tsutsui 215 1.1 leo ns.width = vs->width; 216 1.1 leo ns.height = vs->height; 217 1.1 leo 218 1.32 tsutsui if ((dmode = grf_get_best_mode(&ns, vs->depth)) != NULL) { 219 1.4 leo /* 220 1.4 leo * If we can't do better, leave it 221 1.4 leo */ 222 1.32 tsutsui if (dmode == vu->view->mode) 223 1.32 tsutsui return 0; 224 1.4 leo } 225 1.4 leo new = grf_alloc_view(dmode, &ns, vs->depth); 226 1.1 leo if (new == NULL) 227 1.32 tsutsui return ENOMEM; 228 1.38 tsutsui 229 1.1 leo old = vu->view; 230 1.1 leo vu->view = new; 231 1.1 leo vu->size.x = new->display.x; 232 1.1 leo vu->size.y = new->display.y; 233 1.1 leo vu->size.width = new->display.width; 234 1.1 leo vu->size.height = new->display.height; 235 1.1 leo vu->size.depth = new->bitmap->depth; 236 1.1 leo 237 1.38 tsutsui /* 238 1.38 tsutsui * we need a custom remove here to avoid letting 239 1.38 tsutsui * another view display mark as not added or displayed 240 1.1 leo */ 241 1.1 leo if (vu->flags & VUF_DISPLAY) { 242 1.1 leo vu->flags &= ~(VUF_ADDED|VUF_DISPLAY); 243 1.1 leo view_display(vu); 244 1.1 leo } 245 1.1 leo grf_free_view(old); 246 1.32 tsutsui return 0; 247 1.1 leo } 248 1.1 leo 249 1.2 leo static int 250 1.28 dsl view_get_colormap (struct view_softc *vu, colormap_t *ucm) 251 1.2 leo { 252 1.2 leo int error; 253 1.2 leo long *cme; 254 1.2 leo long *uep; 255 1.2 leo 256 1.32 tsutsui if (ucm->size > MAX_CENTRIES) 257 1.32 tsutsui return EINVAL; 258 1.38 tsutsui 259 1.2 leo /* add one incase of zero, ick. */ 260 1.25 cube cme = malloc(sizeof(ucm->entry[0])*(ucm->size+1), M_TEMP,M_WAITOK); 261 1.2 leo if (cme == NULL) 262 1.32 tsutsui return ENOMEM; 263 1.2 leo 264 1.38 tsutsui error = 0; 265 1.2 leo uep = ucm->entry; 266 1.2 leo ucm->entry = cme; /* set entry to out alloc. */ 267 1.32 tsutsui if (vu->view == NULL || grf_get_colormap(vu->view, ucm)) 268 1.2 leo error = EINVAL; 269 1.32 tsutsui else 270 1.32 tsutsui error = copyout(cme, uep, sizeof(ucm->entry[0]) * ucm->size); 271 1.2 leo ucm->entry = uep; /* set entry back to users. */ 272 1.25 cube free(cme, M_TEMP); 273 1.32 tsutsui return error; 274 1.2 leo } 275 1.2 leo 276 1.2 leo static int 277 1.27 dsl view_set_colormap(struct view_softc *vu, colormap_t *ucm) 278 1.2 leo { 279 1.2 leo colormap_t *cm; 280 1.2 leo int error = 0; 281 1.2 leo 282 1.32 tsutsui if (ucm->size > MAX_CENTRIES) 283 1.32 tsutsui return EINVAL; 284 1.38 tsutsui 285 1.32 tsutsui cm = malloc(sizeof(ucm->entry[0])*ucm->size + sizeof(*cm), 286 1.32 tsutsui M_TEMP, M_WAITOK); 287 1.32 tsutsui if (cm == NULL) 288 1.32 tsutsui return ENOMEM; 289 1.2 leo 290 1.31 tsutsui memcpy(cm, ucm, sizeof(colormap_t)); 291 1.2 leo cm->entry = (long *)&cm[1]; /* table directly after. */ 292 1.38 tsutsui if (((error = 293 1.2 leo copyin(ucm->entry,cm->entry,sizeof(ucm->entry[0])*ucm->size)) == 0) 294 1.2 leo && (vu->view == NULL || grf_use_colormap(vu->view, cm))) 295 1.2 leo error = EINVAL; 296 1.25 cube free(cm, M_TEMP); 297 1.32 tsutsui return error; 298 1.2 leo } 299 1.2 leo 300 1.1 leo /* 301 1.1 leo * functions made available by conf.c 302 1.1 leo */ 303 1.1 leo 304 1.1 leo /*ARGSUSED*/ 305 1.37 tsutsui static int 306 1.27 dsl viewopen(dev_t dev, int flags, int mode, struct lwp *l) 307 1.1 leo { 308 1.1 leo dimen_t size; 309 1.1 leo struct view_softc *vu; 310 1.1 leo 311 1.1 leo vu = &views[minor(dev)]; 312 1.1 leo 313 1.32 tsutsui if (minor(dev) >= NVIEW) 314 1.32 tsutsui return EXDEV; 315 1.32 tsutsui if (vu->flags & VUF_OPEN) 316 1.32 tsutsui return EBUSY; 317 1.1 leo 318 1.1 leo vu->size.x = view_default_x; 319 1.1 leo vu->size.y = view_default_y; 320 1.1 leo size.width = vu->size.width = view_default_width; 321 1.1 leo size.height = vu->size.height = view_default_height; 322 1.1 leo vu->size.depth = view_default_depth; 323 1.1 leo vu->view = grf_alloc_view(NULL, &size, vu->size.depth); 324 1.1 leo if (vu->view == NULL) 325 1.32 tsutsui return ENOMEM; 326 1.1 leo 327 1.1 leo vu->size.x = vu->view->display.x; 328 1.1 leo vu->size.y = vu->view->display.y; 329 1.1 leo vu->size.width = vu->view->display.width; 330 1.1 leo vu->size.height = vu->view->display.height; 331 1.1 leo vu->size.depth = vu->view->bitmap->depth; 332 1.38 tsutsui vu->flags |= VUF_OPEN; 333 1.38 tsutsui return 0; 334 1.1 leo } 335 1.1 leo 336 1.1 leo /*ARGSUSED*/ 337 1.37 tsutsui static int 338 1.28 dsl viewclose (dev_t dev, int flags, int mode, struct lwp *l) 339 1.1 leo { 340 1.1 leo struct view_softc *vu; 341 1.1 leo 342 1.1 leo vu = &views[minor(dev)]; 343 1.1 leo 344 1.1 leo if ((vu->flags & VUF_OPEN) == 0) 345 1.32 tsutsui return 0; /* XXX not open? */ 346 1.1 leo view_remove (vu); 347 1.1 leo grf_free_view (vu->view); 348 1.1 leo vu->flags = 0; 349 1.1 leo vu->view = NULL; 350 1.32 tsutsui return 0; 351 1.1 leo } 352 1.1 leo 353 1.1 leo 354 1.1 leo /*ARGSUSED*/ 355 1.37 tsutsui static int 356 1.28 dsl viewioctl (dev_t dev, u_long cmd, void * data, int flag, struct lwp *l) 357 1.1 leo { 358 1.1 leo struct view_softc *vu; 359 1.1 leo bmap_t *bm; 360 1.1 leo int error; 361 1.1 leo 362 1.1 leo vu = &views[minor(dev)]; 363 1.1 leo error = 0; 364 1.1 leo 365 1.1 leo switch (cmd) { 366 1.1 leo case VIOCDISPLAY: 367 1.1 leo view_display(vu); 368 1.1 leo break; 369 1.1 leo case VIOCREMOVE: 370 1.1 leo view_remove(vu); 371 1.1 leo break; 372 1.1 leo case VIOCGSIZE: 373 1.38 tsutsui memcpy(data, &vu->size, sizeof (struct view_size)); 374 1.1 leo break; 375 1.1 leo case VIOCSSIZE: 376 1.1 leo error = view_setsize(vu, (struct view_size *)data); 377 1.1 leo break; 378 1.1 leo case VIOCGBMAP: 379 1.1 leo bm = (bmap_t *)data; 380 1.31 tsutsui memcpy(bm, vu->view->bitmap, sizeof(bmap_t)); 381 1.23 christos if (l != NOLWP) { 382 1.1 leo bm->plane = NULL; 383 1.1 leo bm->hw_address = NULL; 384 1.9 leo bm->regs = NULL; 385 1.9 leo bm->hw_regs = NULL; 386 1.1 leo } 387 1.1 leo break; 388 1.1 leo case VIOCGCMAP: 389 1.1 leo error = view_get_colormap(vu, (colormap_t *)data); 390 1.1 leo break; 391 1.1 leo case VIOCSCMAP: 392 1.1 leo error = view_set_colormap(vu, (colormap_t *)data); 393 1.1 leo break; 394 1.1 leo default: 395 1.18 atatat error = EPASSTHROUGH; 396 1.1 leo break; 397 1.1 leo } 398 1.32 tsutsui return error; 399 1.1 leo } 400 1.1 leo 401 1.1 leo /*ARGSUSED*/ 402 1.37 tsutsui static paddr_t 403 1.27 dsl viewmmap(dev_t dev, off_t off, int prot) 404 1.1 leo { 405 1.1 leo struct view_softc *vu; 406 1.1 leo bmap_t *bm; 407 1.1 leo u_char *bmd_start; 408 1.38 tsutsui u_long bmd_lin, bmd_vga; 409 1.1 leo 410 1.1 leo vu = &views[minor(dev)]; 411 1.1 leo bm = vu->view->bitmap; 412 1.38 tsutsui bmd_start = bm->hw_address; 413 1.16 thomas bmd_lin = bm->lin_base; 414 1.16 thomas bmd_vga = bm->vga_base; 415 1.14 leo 416 1.38 tsutsui /* 417 1.14 leo * control registers 418 1.14 leo */ 419 1.14 leo if (off >= 0 && off < bm->reg_size) 420 1.32 tsutsui return ((paddr_t)bm->hw_regs + off) >> PGSHIFT; 421 1.1 leo 422 1.16 thomas /* 423 1.16 thomas * VGA memory 424 1.16 thomas */ 425 1.16 thomas if (off >= bmd_vga && off < (bmd_vga + bm->vga_mappable)) 426 1.32 tsutsui return ((paddr_t)bm->vga_address - bmd_vga + off) >> PGSHIFT; 427 1.16 thomas 428 1.16 thomas /* 429 1.16 thomas * frame buffer 430 1.16 thomas */ 431 1.16 thomas if (off >= bmd_lin && off < (bmd_lin + bm->phys_mappable)) 432 1.32 tsutsui return ((paddr_t)bmd_start - bmd_lin + off) >> PGSHIFT; 433 1.1 leo 434 1.32 tsutsui return -1; 435 1.5 leo } 436 1.5 leo 437 1.5 leo view_t * 438 1.27 dsl viewview(dev_t dev) 439 1.5 leo { 440 1.32 tsutsui 441 1.32 tsutsui return views[minor(dev)].view; 442 1.1 leo } 443