view.c revision 1.38
1/*	$NetBSD: view.c,v 1.38 2023/01/06 10:28:28 tsutsui 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 * 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.38 2023/01/06 10:28:28 tsutsui 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
60static void view_display(struct view_softc *);
61static void view_remove(struct view_softc *);
62static int  view_setsize(struct view_softc *, struct view_size *);
63static int  view_get_colormap(struct view_softc *, colormap_t *);
64static int  view_set_colormap(struct view_softc *, colormap_t *);
65
66struct view_softc views[NVIEW];
67static int view_inited;
68
69int view_default_x;
70int view_default_y;
71int view_default_width  = 640;
72int view_default_height = 400;
73int view_default_depth  = 1;
74
75static dev_type_open(viewopen);
76static dev_type_close(viewclose);
77static dev_type_ioctl(viewioctl);
78static dev_type_mmap(viewmmap);
79
80const 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 */
98void
99viewattach(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. */
106int
107viewprobe(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
128static void
129view_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 */
174static void
175view_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
195static int
196view_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
249static int
250view_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
276static int
277view_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*/
305static int
306viewopen(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*/
337static int
338viewclose (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*/
355static int
356viewioctl (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*/
402static paddr_t
403viewmmap(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
437view_t	*
438viewview(dev_t dev)
439{
440
441	return views[minor(dev)].view;
442}
443