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