xref: /netbsd-src/sys/arch/mac68k/dev/grf_compat.c (revision 08c81a9c2dc8c7300e893321eb65c0925d60871c)
1 /*	$NetBSD: grf_compat.c,v 1.8 2002/09/06 13:18:43 gehenna Exp $	*/
2 
3 /*
4  * Copyright (C) 1999 Scott Reynolds
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. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * macfb compatibility with legacy grf devices
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/cdefs.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/errno.h>
40 #include <sys/ioctl.h>
41 #include <sys/malloc.h>
42 #include <sys/mman.h>
43 #include <sys/proc.h>
44 #include <sys/resourcevar.h>
45 #include <sys/vnode.h>
46 
47 #include <machine/autoconf.h>
48 #include <machine/bus.h>
49 #include <machine/grfioctl.h>
50 
51 #include <mac68k/nubus/nubus.h>
52 #include <mac68k/dev/grfvar.h>
53 #include <mac68k/dev/macfbvar.h>
54 
55 #include <miscfs/specfs/specdev.h>
56 
57 #include <uvm/uvm_extern.h>
58 #include <uvm/uvm_map.h>
59 
60 dev_type_open(grfopen);
61 dev_type_close(grfclose);
62 dev_type_ioctl(grfioctl);
63 dev_type_poll(grfpoll);
64 dev_type_mmap(grfmmap);
65 
66 const struct cdevsw grf_cdevsw = {
67 	grfopen, grfclose, noread, nowrite, grfioctl,
68 	nostop, notty, grfpoll, grfmmap,
69 };
70 
71 void	grf_scinit __P((struct grf_softc *, const char *, int));
72 void	grf_init __P((int));
73 void	grfattach __P((int));
74 int	grfmap __P((dev_t, struct macfb_softc *, caddr_t *, struct proc *));
75 int	grfunmap __P((dev_t, struct macfb_softc *, caddr_t, struct proc *));
76 
77 /* Non-private for the benefit of libkvm. */
78 struct	grf_softc *grf_softc;
79 int	numgrf = 0;
80 
81 /*
82  * Initialize a softc to sane defaults.
83  */
84 void
85 grf_scinit(sc, name, unit)
86 	struct grf_softc *sc;
87 	const char *name;
88 	int unit;
89 {
90 	memset(sc, 0, sizeof(struct grf_softc));
91 	snprintf(sc->sc_xname, sizeof(sc->sc_xname), "%s%d", name, unit);
92 	sc->mfb_sc = NULL;
93 }
94 
95 /*
96  * (Re-)initialize the grf_softc block so that at least the requested
97  * number of elements has been allocated.  If this results in more
98  * elements than we had prior to getting here, we initialize each of
99  * them to avoid problems down the road.
100  */
101 void
102 grf_init(n)
103 	int n;
104 {
105 	struct grf_softc *sc;
106 	int i;
107 
108 	if (n >= numgrf) {
109 		i = numgrf;
110 		numgrf = n + 1;
111 
112 		if (grf_softc == NULL)
113 			sc = (struct grf_softc *)
114 			    malloc(numgrf * sizeof(*sc),
115 			    M_DEVBUF, M_NOWAIT);
116 		else
117 			sc = (struct grf_softc *)
118 			    realloc(grf_softc, numgrf * sizeof(*sc),
119 			    M_DEVBUF, M_NOWAIT);
120 		if (sc == NULL) {
121 			printf("WARNING: no memory for grf emulation\n");
122 			if (grf_softc != NULL)
123 				free(grf_softc, M_DEVBUF);
124 			return;
125 		}
126 		grf_softc = sc;
127 
128 		/* Initialize per-softc structures. */
129 		while (i < numgrf) {
130 			grf_scinit(&grf_softc[i], "grf", i);
131 			i++;
132 		}
133 	}
134 }
135 
136 /*
137  * Called by main() during pseudo-device attachment.  If we had a
138  * way to configure additional grf devices later, this would actually
139  * allocate enough space for them.  As it stands, it's nonsensical,
140  * so other than a basic sanity check we do nothing.
141  */
142 void
143 grfattach(n)
144 	int n;
145 {
146 	if (n <= 0) {
147 #ifdef DIAGNOSTIC
148 		panic("grfattach: count <= 0");
149 #endif
150 		return;
151 	}
152 
153 #if 0 /* XXX someday, if we implement a way to attach after autoconfig */
154 	grf_init(n);
155 #endif
156 }
157 
158 /*
159  * Called from macfb_attach() after setting up the frame buffer.  Since
160  * there is a 1:1 correspondence between the macfb device and the grf
161  * device, the only bit of information we really need is the macfb_softc.
162  */
163 void
164 grf_attach(sc, unit)
165 	struct macfb_softc *sc;
166 	int unit;
167 {
168 	grf_init(unit);
169 
170 	if (unit < numgrf)
171 		grf_softc[unit].mfb_sc = sc;
172 }
173 
174 /*
175  * Standard device ops
176  */
177 int
178 grfopen(dev, flag, mode, p)
179 	dev_t dev;
180 	int flag;
181 	int mode;
182 	struct proc *p;
183 {
184 	struct grf_softc *sc;
185 	int unit = GRFUNIT(dev);
186 	int rv = 0;
187 
188 	if (grf_softc == NULL || unit >= numgrf)
189 		return ENXIO;
190 
191 	sc = &grf_softc[unit];
192 	if (sc->mfb_sc == NULL)
193 		rv = ENXIO;
194 
195 	return rv;
196 }
197 
198 int
199 grfclose(dev, flag, mode, p)
200 	dev_t dev;
201 	int flag;
202 	int mode;
203 	struct proc *p;
204 {
205 	struct grf_softc *sc;
206 	int unit = GRFUNIT(dev);
207 	int rv = 0;
208 
209 	if (grf_softc == NULL || unit >= numgrf)
210 		return ENXIO;
211 
212 	sc = &grf_softc[unit];
213 	if (sc->mfb_sc != NULL)
214 		macfb_clear(sc->mfb_sc->sc_dc);	/* clear the display */
215 	else
216 		rv = ENXIO;
217 
218 	return rv;
219 }
220 
221 int
222 grfioctl(dev, cmd, data, flag, p)
223 	dev_t dev;
224 	u_long cmd;
225 	caddr_t data;
226 	int flag;
227 	struct proc *p;
228 {
229 	struct grf_softc *sc;
230 	struct macfb_devconfig *dc;
231 #if defined(GRF_COMPAT) || (NGRF > 0)
232 	struct grfinfo *gd;
233 #endif /* GRF_COMPAT || (NGRF > 0) */
234 	struct grfmode *gm;
235 	int unit = GRFUNIT(dev);
236 	int rv;
237 
238 	if (grf_softc == NULL || unit >= numgrf)
239 		return ENXIO;
240 
241 	sc = &grf_softc[unit];
242 	if (sc->mfb_sc == NULL)
243 		return ENXIO;
244 
245 	dc = sc->mfb_sc->sc_dc;
246 
247 	switch (cmd) {
248 #if defined(GRF_COMPAT) || (NGRF > 0)
249 	case GRFIOCGINFO:
250 		gd = (struct grfinfo *)data;
251 		memset(gd, 0, sizeof(struct grfinfo));
252 		gd->gd_fbaddr     = (caddr_t)dc->dc_paddr;
253 		gd->gd_fbsize     = dc->dc_size;
254 		gd->gd_colors     = (short)(1 << dc->dc_depth);
255 		gd->gd_planes     = (short)dc->dc_depth;
256 		gd->gd_fbwidth    = dc->dc_wid;
257 		gd->gd_fbheight   = dc->dc_ht;
258 		gd->gd_fbrowbytes = dc->dc_rowbytes;
259 		gd->gd_dwidth     = dc->dc_raster.width;
260 		gd->gd_dheight    = dc->dc_raster.height;
261 		rv = 0;
262 		break;
263 #endif /* GRF_COMPAT || (NGRF > 0) */
264 
265 	case GRFIOCON:
266 	case GRFIOCOFF:
267 		/* Nothing to do */
268 		rv = 0;
269 		break;
270 
271 #if defined(GRF_COMPAT) || (NGRF > 0)
272 	case GRFIOCMAP:
273 		rv = grfmap(dev, sc->mfb_sc, (caddr_t *)data, p);
274 		break;
275 
276 	case GRFIOCUNMAP:
277 		rv = grfunmap(dev, sc->mfb_sc, *(caddr_t *)data, p);
278 		break;
279 #endif /* GRF_COMPAT || (NGRF > 0) */
280 
281 	case GRFIOCGMODE:
282 		gm = (struct grfmode *)data;
283 		memset(gm, 0, sizeof(struct grfmode));
284 		gm->fbbase   = (char *)dc->dc_vaddr;
285 		gm->fbsize   = dc->dc_size;
286 		gm->fboff    = dc->dc_offset;
287 		gm->rowbytes = dc->dc_rowbytes;
288 		gm->width    = dc->dc_wid;
289 		gm->height   = dc->dc_ht;
290 		gm->psize    = dc->dc_depth;
291 		rv = 0;
292 		break;
293 
294 	case GRFIOCLISTMODES:
295 	case GRFIOCGETMODE:
296 	case GRFIOCSETMODE:
297 		/* NONE of these operations are (officially) supported. */
298 	default:
299 		rv = EINVAL;
300 		break;
301 	}
302 	return rv;
303 }
304 
305 int
306 grfpoll(dev, events, p)
307 	dev_t dev;
308 	int events;
309 	struct proc *p;
310 {
311 	return EINVAL;
312 }
313 
314 paddr_t
315 grfmmap(dev, off, prot)
316 	dev_t dev;
317 	off_t off;
318 	int prot;
319 {
320 	struct grf_softc *sc;
321 	struct macfb_devconfig *dc;
322 	paddr_t addr;
323 	int unit = GRFUNIT(dev);
324 
325 	if (grf_softc == NULL || unit >= numgrf)
326 		return ENXIO;
327 
328 	sc = &grf_softc[unit];
329 	if (sc->mfb_sc == NULL)
330 		return ENXIO;
331 
332 	dc = sc->mfb_sc->sc_dc;
333 
334 	if (off >= 0 &&
335 	    off < m68k_round_page(dc->dc_offset + dc->dc_size))
336 		addr = m68k_btop(dc->dc_paddr + off);
337 	else
338 		addr = (-1);	/* XXX bogus */
339 
340 	return addr;
341 }
342 
343 int
344 grfmap(dev, sc, addrp, p)
345 	dev_t dev;
346 	struct macfb_softc *sc;
347 	caddr_t *addrp;
348 	struct proc *p;
349 {
350 	struct specinfo si;
351 	struct vnode vn;
352 	u_long len;
353 	int error, flags;
354 
355 	*addrp = (caddr_t)sc->sc_dc->dc_paddr;
356 	len = m68k_round_page(sc->sc_dc->dc_offset + sc->sc_dc->dc_size);
357 	flags = MAP_SHARED | MAP_FIXED;
358 
359 	vn.v_type = VCHR;		/* XXX */
360 	vn.v_specinfo = &si;		/* XXX */
361 	vn.v_rdev = dev;		/* XXX */
362 
363 	error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp,
364 	    (vsize_t)len, VM_PROT_ALL, VM_PROT_ALL,
365 	    flags, (caddr_t)&vn, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
366 
367 	/* Offset into page: */
368 	*addrp += sc->sc_dc->dc_offset;
369 
370 	return (error);
371 }
372 
373 int
374 grfunmap(dev, sc, addr, p)
375 	dev_t dev;
376 	struct macfb_softc *sc;
377 	caddr_t addr;
378 	struct proc *p;
379 {
380 	vm_size_t size;
381 
382 	addr -= sc->sc_dc->dc_offset;
383 
384 	if (addr <= 0)
385 		return (-1);
386 
387 	size = m68k_round_page(sc->sc_dc->dc_offset + sc->sc_dc->dc_size);
388 	uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)addr, (vaddr_t)addr + size);
389 	return 0;
390 }
391