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