xref: /netbsd-src/sys/arch/amiga/dev/grf.c (revision 23e63c4b5cecc703250c97faac1ad970f4954821)
1 /*	$NetBSD: grf.c,v 1.69 2023/12/20 00:40:42 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * the Systems Programming Group of the University of Utah Computer
10  * Science Department.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * from: Utah $Hdr: grf.c 1.31 91/01/21$
37  *
38  *	@(#)grf.c	7.8 (Berkeley) 5/7/91
39  */
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: grf.c,v 1.69 2023/12/20 00:40:42 thorpej Exp $");
43 
44 /*
45  * Graphics display driver for the Amiga
46  * This is the hardware-independent portion of the driver.
47  * Hardware access is through the grf_softc->g_mode routine.
48  */
49 
50 #include "view.h"
51 #include "grf.h"
52 #include "kbd.h"
53 #include "wsdisplay.h"
54 
55 #include <sys/param.h>
56 #include <sys/proc.h>
57 #include <sys/ioctl.h>
58 #include <sys/device.h>
59 #include <sys/file.h>
60 #include <sys/systm.h>
61 #include <sys/vnode.h>
62 #include <sys/mman.h>
63 #include <sys/bus.h>
64 #include <sys/kauth.h>
65 
66 #include <machine/cpu.h>
67 
68 #include <dev/cons.h>
69 #include <dev/sun/fbio.h>
70 #include <dev/wscons/wsconsio.h>
71 #include <dev/wscons/wsdisplayvar.h>
72 #include <dev/rasops/rasops.h>
73 #include <dev/wscons/wsdisplay_vconsvar.h>
74 
75 #include <amiga/amiga/color.h>	/* DEBUG */
76 #include <amiga/amiga/device.h>
77 #include <amiga/dev/grfioctl.h>
78 #include <amiga/dev/grfvar.h>
79 #include <amiga/dev/itevar.h>
80 #include <amiga/dev/kbdvar.h>
81 #include <amiga/dev/viewioctl.h>
82 
83 #include <sys/conf.h>
84 
85 #if NGRF > 0
86 #include "ite.h"
87 #if NITE == 0
88 #define	ite_on(u,f)
89 #define	ite_off(u,f)
90 #define ite_reinit(d)
91 #endif
92 
93 int grfon(dev_t);
94 int grfoff(dev_t);
95 int grfsinfo(dev_t, struct grfdyninfo *);
96 
97 void grfattach(device_t, device_t, void *);
98 int grfmatch(device_t, cfdata_t, void *);
99 int grfprint(void *, const char *);
100 #ifdef DEBUG
101 void grfdebug(struct grf_softc *, const char *, ...);
102 #endif
103 /*
104  * pointers to grf drivers device structs
105  */
106 struct grf_softc *grfsp[NGRF];
107 
108 CFATTACH_DECL_NEW(grf, 0,
109     grfmatch, grfattach, NULL, NULL);
110 
111 dev_type_open(grfopen);
112 dev_type_close(grfclose);
113 dev_type_ioctl(grfioctl);
114 dev_type_mmap(grfmmap);
115 
116 const struct cdevsw grf_cdevsw = {
117 	.d_open = grfopen,
118 	.d_close = grfclose,
119 	.d_read = nullread,
120 	.d_write = nullwrite,
121 	.d_ioctl = grfioctl,
122 	.d_stop = nostop,
123 	.d_tty = notty,
124 	.d_poll = nopoll,
125 	.d_mmap = grfmmap,
126 	.d_kqfilter = nokqfilter,
127 	.d_discard = nodiscard,
128 	.d_flag = 0
129 };
130 
131 /*
132  * only used in console init.
133  */
134 static cfdata_t cfdata;
135 
136 #if NWSDISPLAY > 0
137 static struct vcons_screen console_vcons;
138 
139 static void grf_init_screen(void *, struct vcons_screen *, int, long *);
140 static struct rasops_info *grf_setup_rasops(struct grf_softc *,
141     struct vcons_screen *);
142 
143 cons_decl(grf);
144 #endif
145 
146 /*
147  * match if the unit of grf matches its perspective
148  * low level board driver.
149  */
150 int
grfmatch(device_t parent,cfdata_t cf,void * aux)151 grfmatch(device_t parent, cfdata_t cf, void *aux)
152 {
153 	struct grf_softc *psc;
154 
155 	psc = device_private(parent);
156 	if (cf->cf_unit != psc->g_unit)
157 		return(0);
158 	cfdata = cf;
159 	return(1);
160 }
161 
162 /*
163  * Attach.. plug pointer in and print some info.
164  * Then try and attach a wsdisplay or ite to us.
165  * Note: self is NULL during console init.
166  */
167 void
grfattach(device_t parent,device_t self,void * aux)168 grfattach(device_t parent, device_t self, void *aux)
169 {
170 #if NWSDISPLAY > 0
171 	struct wsemuldisplaydev_attach_args wa;
172 	long defattr;
173 #endif
174 	struct grf_softc *gp;
175 	int maj;
176 
177 	gp = device_private(parent);
178 	gp->g_device = self;
179 	grfsp[gp->g_unit] = gp;
180 
181 	/*
182 	 * find our major device number, make device
183 	 */
184 	maj = cdevsw_lookup_major(&grf_cdevsw);
185 	gp->g_grfdev = makedev(maj, gp->g_unit);
186 
187 	if (self != NULL) {
188 		printf(": width %d height %d", gp->g_display.gd_dwidth,
189 		    gp->g_display.gd_dheight);
190 		if (gp->g_display.gd_colors == 2)
191 			printf(" monochrome\n");
192 		else
193 			printf(" colors %d\n", gp->g_display.gd_colors);
194 
195 #if NWSDISPLAY > 0
196 		vcons_init(&gp->g_vd, gp, gp->g_defaultscr, gp->g_accessops);
197 		gp->g_vd.init_screen = grf_init_screen;
198 
199 		if (gp->g_flags & GF_CONSOLE) {
200 			console_vcons.scr_flags |= VCONS_SCREEN_IS_STATIC;
201 			vcons_init_screen(&gp->g_vd,
202 			    &console_vcons, 1, &defattr);
203 			gp->g_defaultscr->textops =
204 			    &console_vcons.scr_ri.ri_ops;
205 			wsdisplay_cnattach(gp->g_defaultscr,
206 			    &console_vcons.scr_ri, 0, 0, defattr);
207 			vcons_replay_msgbuf(&console_vcons);
208 		}
209 
210 		/* attach wsdisplay */
211 		wa.console = (gp->g_flags & GF_CONSOLE) != 0;
212 		wa.scrdata = gp->g_scrlist;
213 		wa.accessops = gp->g_accessops;
214 		wa.accesscookie = &gp->g_vd;
215 		config_found(self, &wa, wsemuldisplaydevprint,
216 		    CFARGS(.iattr = "wsemuldisplaydev"));
217 #endif  /* NWSDISPLAY > 0 */
218 	}
219 
220 #if NWSDISPLAY == 0
221 	/*
222 	 * try and attach an ite
223 	 */
224 	amiga_config_found(cfdata, self, gp, grfprint,
225 	    CFARGS(.iattr = "grf"));
226 #endif
227 }
228 
229 int
grfprint(void * aux,const char * pnp)230 grfprint(void *aux, const char *pnp)
231 {
232 	if (pnp)
233 		aprint_normal("ite at %s", pnp);
234 	return(UNCONF);
235 }
236 
237 /*ARGSUSED*/
238 int
grfopen(dev_t dev,int flags,int devtype,struct lwp * l)239 grfopen(dev_t dev, int flags, int devtype, struct lwp *l)
240 {
241 	struct grf_softc *gp;
242 
243 	if (GRFUNIT(dev) >= NGRF || (gp = grfsp[GRFUNIT(dev)]) == NULL)
244 		return(ENXIO);
245 
246 	if ((gp->g_flags & GF_ALIVE) == 0)
247 		return(ENXIO);
248 
249 	if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE))
250 		return(EBUSY);
251 
252 	return(0);
253 }
254 
255 /*ARGSUSED*/
256 int
grfclose(dev_t dev,int flags,int mode,struct lwp * l)257 grfclose(dev_t dev, int flags, int mode, struct lwp *l)
258 {
259 	struct grf_softc *gp;
260 
261 	gp = grfsp[GRFUNIT(dev)];
262 	(void)grfoff(dev);
263 	gp->g_flags &= GF_ALIVE;
264 	return(0);
265 }
266 
267 /*ARGSUSED*/
268 int
grfioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)269 grfioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
270 {
271 	struct grf_softc *gp;
272 	int error;
273 
274 	gp = grfsp[GRFUNIT(dev)];
275 	error = 0;
276 
277 	switch (cmd) {
278 	case OGRFIOCGINFO:
279 	        /* argl.. no bank-member.. */
280 	  	memcpy(data, (void *)&gp->g_display, sizeof(struct grfinfo)-4);
281 		break;
282 	case GRFIOCGINFO:
283 		memcpy(data, (void *)&gp->g_display, sizeof(struct grfinfo));
284 		break;
285 	case GRFIOCON:
286 		error = grfon(dev);
287 		break;
288 	case GRFIOCOFF:
289 		error = grfoff(dev);
290 		break;
291 	case GRFIOCSINFO:
292 		error = grfsinfo(dev, (struct grfdyninfo *) data);
293 		break;
294 	case GRFGETVMODE:
295 		return(gp->g_mode(gp, GM_GRFGETVMODE, data, 0, 0));
296 	case GRFSETVMODE:
297 		error = gp->g_mode(gp, GM_GRFSETVMODE, data, 0, 0);
298 		if (error == 0 && gp->g_itedev && !(gp->g_flags & GF_GRFON))
299 			ite_reinit(gp->g_itedev);
300 		break;
301 	case GRFGETNUMVM:
302 		return(gp->g_mode(gp, GM_GRFGETNUMVM, data, 0, 0));
303 	/*
304 	 * these are all hardware dependent, and have to be resolved
305 	 * in the respective driver.
306 	 */
307 	case GRFIOCPUTCMAP:
308 	case GRFIOCGETCMAP:
309 	case GRFIOCSSPRITEPOS:
310 	case GRFIOCGSPRITEPOS:
311 	case GRFIOCSSPRITEINF:
312 	case GRFIOCGSPRITEINF:
313 	case GRFIOCGSPRITEMAX:
314 	case GRFIOCBITBLT:
315     	case GRFIOCSETMON:
316 	case GRFTOGGLE: /* Toggles between Cirrus boards and native ECS on
317                      Amiga. 15/11/94 ill */
318 		/*
319 		 * We need the minor dev number to get the overlay/image
320 		 * information for grf_ul.
321 		 */
322 		return(gp->g_mode(gp, GM_GRFIOCTL, data, cmd, dev));
323 
324 	case GRFIOCBLANK:	/* blank ioctl, IOCON/OFF will turn ite on */
325 	case FBIOSVIDEO:
326 		error = gp->g_mode(gp, GM_GRFIOCTL, data, GRFIOCBLANK, dev);
327 		if (!error)
328 			gp->g_blank = *(int *)data;
329 		return (error);
330 
331 	case FBIOGVIDEO:
332 		*(int *)data = gp->g_blank;
333 		return (0);
334 
335 	default:
336 #if NVIEW > 0
337 		/*
338 		 * check to see whether it's a command recognized by the
339 		 * view code if the unit is 0
340 		 * XXX
341 		 */
342 		if (GRFUNIT(dev) == 0) {
343 			extern const struct cdevsw view_cdevsw;
344 
345 			return((*view_cdevsw.d_ioctl)(dev, cmd, data, flag, l));
346 		}
347 #endif
348 		error = EPASSTHROUGH;
349 		break;
350 
351 	}
352 	return(error);
353 }
354 
355 /*
356  * map the contents of a graphics display card into process'
357  * memory space.
358  */
359 paddr_t
grfmmap(dev_t dev,off_t off,int prot)360 grfmmap(dev_t dev, off_t off, int prot)
361 {
362 	struct grf_softc *gp;
363 	struct grfinfo *gi;
364 
365 	gp = grfsp[GRFUNIT(dev)];
366 	gi = &gp->g_display;
367 
368 	/*
369 	 * control registers
370 	 */
371 	if (off >= 0 && off < gi->gd_regsize)
372 		return MD_BTOP((paddr_t)gi->gd_regaddr + off);
373 
374 	/*
375 	 * frame buffer
376 	 */
377 	if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) {
378 		off -= gi->gd_regsize;
379 		return MD_BTOP((paddr_t)gi->gd_fbaddr + off);
380 	}
381 	/* bogus */
382 	return(-1);
383 }
384 
385 int
grfon(dev_t dev)386 grfon(dev_t dev)
387 {
388 	struct grf_softc *gp;
389 
390 	gp = grfsp[GRFUNIT(dev)];
391 
392 	if (gp->g_flags & GF_GRFON)
393 		return(0);
394 
395 	gp->g_flags |= GF_GRFON;
396 	if (gp->g_itedev != NODEV)
397 		ite_off(gp->g_itedev, 3);
398 
399 	return(gp->g_mode(gp, (dev & GRFOVDEV) ? GM_GRFOVON : GM_GRFON,
400 							NULL, 0, 0));
401 }
402 
403 int
grfoff(dev_t dev)404 grfoff(dev_t dev)
405 {
406 	struct grf_softc *gp;
407 	int error;
408 
409 	gp = grfsp[GRFUNIT(dev)];
410 
411 	if ((gp->g_flags & GF_GRFON) == 0)
412 		return(0);
413 
414 	gp->g_flags &= ~GF_GRFON;
415 	error = gp->g_mode(gp, (dev & GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF,
416 							NULL, 0, 0);
417 
418 	/*
419 	 * Closely tied together no X's
420 	 */
421 	if (gp->g_itedev != NODEV)
422 		ite_on(gp->g_itedev, 2);
423 
424 	return(error);
425 }
426 
427 int
grfsinfo(dev_t dev,struct grfdyninfo * dyninfo)428 grfsinfo(dev_t dev, struct grfdyninfo *dyninfo)
429 {
430 	struct grf_softc *gp;
431 	int error;
432 
433 	gp = grfsp[GRFUNIT(dev)];
434 	error = gp->g_mode(gp, GM_GRFCONFIG, dyninfo, 0, 0);
435 
436 	/*
437 	 * Closely tied together no X's
438 	 */
439 	if (gp->g_itedev != NODEV)
440 		ite_reinit(gp->g_itedev);
441 	return(error);
442 }
443 
444 #if NWSDISPLAY > 0
445 void
grfcnprobe(struct consdev * cd)446 grfcnprobe(struct consdev *cd)
447 {
448 	struct grf_softc *gp;
449 	int unit;
450 
451 	/*
452 	 * Find the first working grf device for being console.
453 	 * Ignore unit 0 (grfcc), which should use amidisplaycc instead.
454 	 */
455 	for (unit = 1; unit < NGRF; unit++) {
456 		gp = grfsp[unit];
457 		if (gp != NULL && (gp->g_flags & GF_ALIVE)) {
458 			cd->cn_pri = CN_INTERNAL;
459 			cd->cn_dev = NODEV;  /* initialized later by wscons */
460 			return;
461 		}
462 	}
463 
464 	/* no grf console alive */
465 	cd->cn_pri = CN_DEAD;
466 }
467 
468 void
grfcninit(struct consdev * cd)469 grfcninit(struct consdev *cd)
470 {
471 	struct grf_softc *gp;
472 	struct rasops_info *ri;
473 	long defattr;
474 	int unit;
475 
476 	/* find console grf and set up wsdisplay for it */
477 	for (unit = 1; unit < NGRF; unit++) {
478 		gp = grfsp[unit];
479 		if (gp != NULL && (gp->g_flags & GF_ALIVE)) {
480 			gp->g_flags |= GF_CONSOLE;  /* we are console! */
481 
482 			gp->g_defaultscr->ncols = gp->g_display.gd_fbwidth /
483 			    gp->g_defaultscr->fontwidth;
484 			gp->g_defaultscr->nrows = gp->g_display.gd_fbheight /
485 			    gp->g_defaultscr->fontheight;
486 
487 			ri = grf_setup_rasops(gp, &console_vcons);
488 			console_vcons.scr_cookie = gp;
489 			defattr = 0;  /* XXX */
490 
491 			wsdisplay_preattach(gp->g_defaultscr, ri, 0, 0,
492 			    defattr);
493 #if NKBD > 0
494 			/* tell kbd device it is used as console keyboard */
495 			kbd_cnattach();
496 #endif
497 			return;
498 		}
499 	}
500 	panic("grfcninit: lost console");
501 }
502 
503 static void
grf_init_screen(void * cookie,struct vcons_screen * scr,int existing,long * defattr)504 grf_init_screen(void *cookie, struct vcons_screen *scr, int existing,
505     long *defattr)
506 {
507 	struct grf_softc *gp;
508 	struct rasops_info *ri __unused;
509 
510 	gp = cookie;
511 	ri = grf_setup_rasops(gp, scr);
512 }
513 
514 static struct rasops_info *
grf_setup_rasops(struct grf_softc * gp,struct vcons_screen * scr)515 grf_setup_rasops(struct grf_softc *gp, struct vcons_screen *scr)
516 {
517 	struct rasops_info *ri;
518 	int i;
519 
520 	ri = &scr->scr_ri;
521 	scr->scr_flags |= VCONS_DONT_READ;
522 	memset(ri, 0, sizeof(struct rasops_info));
523 
524 	ri->ri_rows = gp->g_defaultscr->nrows;
525 	ri->ri_cols = gp->g_defaultscr->ncols;
526 	ri->ri_hw = scr;
527 	ri->ri_ops.cursor    = gp->g_emulops->cursor;
528 	ri->ri_ops.mapchar   = gp->g_emulops->mapchar;
529 	ri->ri_ops.copyrows  = gp->g_emulops->copyrows;
530 	ri->ri_ops.eraserows = gp->g_emulops->eraserows;
531 	ri->ri_ops.copycols  = gp->g_emulops->copycols;
532 	ri->ri_ops.erasecols = gp->g_emulops->erasecols;
533 	ri->ri_ops.putchar   = gp->g_emulops->putchar;
534 	ri->ri_ops.allocattr = gp->g_emulops->allocattr;
535 
536 	/* multiplication table for row-offsets */
537 	for (i = 0; i < ri->ri_rows; i++)
538 		gp->g_rowoffset[i] = i * ri->ri_cols;
539 
540 	return ri;
541 }
542 
543 /*
544  * Called as fallback for ioctls which are not handled by the specific
545  * grf driver.
546  */
547 int
grf_wsioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)548 grf_wsioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
549 {
550 	struct wsdisplayio_fbinfo *iofbi;
551 	struct wsdisplay_fbinfo *fbinfo;
552 	struct vcons_data *vd;
553 	struct grf_softc *gp;
554 	struct vcons_screen *scr;
555 	struct grfinfo *gi;
556 
557 	vd = v;
558 	gp = vd->cookie;
559 	scr = vd->active;
560 
561 	switch (cmd) {
562 	case WSDISPLAYIO_GET_FBINFO:
563 		if (scr != NULL) {
564 			iofbi = data;
565 			return wsdisplayio_get_fbinfo(&scr->scr_ri, iofbi);
566 		}
567 		return ENODEV;
568 
569 	case WSDISPLAYIO_GINFO:
570 		if (scr != NULL) {
571 			fbinfo = (struct wsdisplay_fbinfo *)data;
572 			gi = &gp->g_display;
573 
574 			/*
575 			 * We should return truth about the current mode here,
576 			 * because X11 wsfb driver depends on this!
577 			 */
578 			fbinfo->height = gi->gd_fbheight;
579 			fbinfo->width = gi->gd_fbwidth;
580 			fbinfo->depth = gi->gd_planes;
581 			fbinfo->cmsize = gi->gd_colors;
582 			return 0;
583 		}
584 		return ENODEV;
585 
586 	case WSDISPLAYIO_GTYPE:
587 		*(u_int *)data = WSDISPLAY_TYPE_GRF;
588 		return 0;
589 
590 	case WSDISPLAYIO_SMODE:
591 		if ((*(int *)data) != gp->g_wsmode) {
592 			gp->g_wsmode = *(int *)data;
593 			if (gp->g_wsmode == WSDISPLAYIO_MODE_EMUL &&
594 			    scr != NULL)
595 				vcons_redraw_screen(scr);
596 		}
597 		return 0;
598 	}
599 
600 	return EPASSTHROUGH;
601 }
602 
603 paddr_t
grf_wsmmap(void * v,void * vs,off_t off,int prot)604 grf_wsmmap(void *v, void *vs, off_t off, int prot)
605 {
606 	struct vcons_data *vd;
607 	struct grf_softc *gp;
608 	struct grfinfo *gi;
609 
610 	vd = v;
611 	gp = vd->cookie;
612 	gi = &gp->g_display;
613 
614 	/* Normal fb mapping */
615 	if (off < gi->gd_fbsize)
616 		return MD_BTOP(((paddr_t)gi->gd_fbaddr) + off);
617 
618 	/*
619 	 * restrict all other mappings to processes with superuser privileges
620 	 * or the kernel itself
621 	 */
622 	if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM,
623 	    NULL, NULL, NULL, NULL) != 0) {
624 		aprint_normal("%s: permission to mmap denied.\n",
625 		    device_xname(gp->g_device));
626 		return -1;
627 	}
628 
629 	/* Handle register mapping */
630 	if ((off >= (paddr_t)gi->gd_regaddr) &&
631 	    (off < ((paddr_t)gi->gd_regaddr + (size_t)gi->gd_regsize)))
632 		return MD_BTOP(off);
633 
634 	if ((off >= (paddr_t)gi->gd_fbaddr) &&
635 	    (off < ((paddr_t)gi->gd_fbaddr + (size_t)gi->gd_fbsize)))
636 		return MD_BTOP(off);
637 
638 	return -1;
639 }
640 
641 #endif  /* NWSDISPLAY > 0 */
642 
643 #endif	/* NGRF > 0 */
644