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