1 /* $NetBSD: view.c,v 1.39 2023/03/26 15:24:21 andvar 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 display 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 * referred 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.39 2023/03/26 15:24:21 andvar 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 static dev_type_open(viewopen);
76 static dev_type_close(viewclose);
77 static dev_type_ioctl(viewioctl);
78 static 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
viewattach(int cnt)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
viewprobe(void)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
view_display(struct view_softc * vu)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
view_remove(struct view_softc * vu)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
view_setsize(struct view_softc * vu,struct view_size * vs)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
view_get_colormap(struct view_softc * vu,colormap_t * ucm)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
view_set_colormap(struct view_softc * vu,colormap_t * ucm)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 static int
viewopen(dev_t dev,int flags,int mode,struct lwp * l)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 static int
viewclose(dev_t dev,int flags,int mode,struct lwp * l)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 static int
viewioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)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 static paddr_t
viewmmap(dev_t dev,off_t off,int prot)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 *
viewview(dev_t dev)438 viewview(dev_t dev)
439 {
440
441 return views[minor(dev)].view;
442 }
443