xref: /NextBSD/sys/pc98/cbus/gdc.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
1 /*-
2  * Copyright (c) 1999 FreeBSD(98) port team.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include "opt_gdc.h"
32 #include "opt_fb.h"
33 #include "opt_syscons.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/conf.h>
40 #include <sys/bus.h>
41 #include <machine/bus.h>
42 #include <sys/rman.h>
43 #include <machine/resource.h>
44 
45 #include <sys/fbio.h>
46 #include <sys/fcntl.h>
47 
48 #include <vm/vm.h>
49 #include <vm/pmap.h>
50 #include <vm/vm_param.h>
51 
52 #include <machine/md_var.h>
53 #include <machine/pc/bios.h>
54 
55 #include <dev/fb/fbreg.h>
56 
57 #ifdef LINE30
58 #include <pc98/cbus/cbus.h>
59 #endif
60 #include <pc98/pc98/pc98_machdep.h>
61 #include <isa/isavar.h>
62 
63 #define	TEXT_GDC	0x60
64 #define	GRAPHIC_GDC	0xa0
65 #define	ROW		25
66 #define	COL		80
67 
68 #define DRIVER_NAME	"gdc"
69 
70 /* cdev driver declaration */
71 
72 #define GDC_UNIT(dev)	dev2unit(dev)
73 #define GDC_MKMINOR(unit) (unit)
74 
75 typedef struct gdc_softc {
76 	video_adapter_t	*adp;
77 	struct resource *res_tgdc, *res_ggdc;
78 	struct resource *res_egc, *res_pegc, *res_grcg, *res_kcg;
79 	struct resource *res_tmem, *res_gmem1, *res_gmem2;
80 #ifdef FB_INSTALL_CDEV
81 	genfb_softc_t gensc;
82 #endif
83 } gdc_softc_t;
84 
85 #define GDC_SOFTC(unit)	\
86 	((gdc_softc_t *)devclass_get_softc(gdc_devclass, unit))
87 
88 static bus_addr_t	gdc_iat[] = {0, 2, 4, 6, 8, 10, 12, 14};
89 
90 static devclass_t	gdc_devclass;
91 
92 static int		gdc_probe_unit(int unit, gdc_softc_t *sc, int flags);
93 static int		gdc_attach_unit(int unit, gdc_softc_t *sc, int flags);
94 static int		gdc_alloc_resource(device_t dev);
95 static int		gdc_release_resource(device_t dev);
96 
97 #ifdef FB_INSTALL_CDEV
98 
99 static d_open_t		gdcopen;
100 static d_close_t	gdcclose;
101 static d_read_t		gdcread;
102 static d_write_t	gdcwrite;
103 static d_ioctl_t	gdcioctl;
104 static d_mmap_t		gdcmmap;
105 
106 static struct cdevsw gdc_cdevsw = {
107 	.d_version =	D_VERSION,
108 	.d_flags =	D_NEEDGIANT,
109 	.d_open =	gdcopen,
110 	.d_close =	gdcclose,
111 	.d_read =	gdcread,
112 	.d_write =	gdcwrite,
113 	.d_ioctl =	gdcioctl,
114 	.d_mmap =	gdcmmap,
115 	.d_name =	DRIVER_NAME,
116 };
117 
118 #endif /* FB_INSTALL_CDEV */
119 
120 static void
gdc_identify(driver_t * driver,device_t parent)121 gdc_identify(driver_t *driver, device_t parent)
122 {
123 	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, DRIVER_NAME, 0);
124 }
125 
126 static int
gdcprobe(device_t dev)127 gdcprobe(device_t dev)
128 {
129 	int error;
130 
131 	/* Check isapnp ids */
132 	if (isa_get_vendorid(dev))
133 		return (ENXIO);
134 
135 	device_set_desc(dev, "Generic GDC");
136 
137 	error = gdc_alloc_resource(dev);
138 	if (error)
139 		return (error);
140 
141 	error = gdc_probe_unit(device_get_unit(dev),
142 			       device_get_softc(dev),
143 			       device_get_flags(dev));
144 
145 	gdc_release_resource(dev);
146 
147 	return (error);
148 }
149 
150 static int
gdc_attach(device_t dev)151 gdc_attach(device_t dev)
152 {
153 	gdc_softc_t *sc;
154 	int error;
155 
156 	error = gdc_alloc_resource(dev);
157 	if (error)
158 		return (error);
159 
160 	sc = device_get_softc(dev);
161 	error = gdc_attach_unit(device_get_unit(dev),
162 				sc,
163 				device_get_flags(dev));
164 	if (error) {
165 		gdc_release_resource(dev);
166 		return error;
167 	}
168 
169 #ifdef FB_INSTALL_CDEV
170 	/* attach a virtual frame buffer device */
171 	error = fb_attach(GDC_MKMINOR(device_get_unit(dev)),
172 				  sc->adp, &gdc_cdevsw);
173 	if (error) {
174 		gdc_release_resource(dev);
175 		return error;
176 	}
177 #endif /* FB_INSTALL_CDEV */
178 
179 	if (bootverbose)
180 		vidd_diag(sc->adp, bootverbose);
181 
182 	return 0;
183 }
184 
185 static int
gdc_probe_unit(int unit,gdc_softc_t * sc,int flags)186 gdc_probe_unit(int unit, gdc_softc_t *sc, int flags)
187 {
188 	video_switch_t *sw;
189 
190 	sw = vid_get_switch(DRIVER_NAME);
191 	if (sw == NULL)
192 		return ENXIO;
193 	return (*sw->probe)(unit, &sc->adp, NULL, flags);
194 }
195 
196 static int
gdc_attach_unit(int unit,gdc_softc_t * sc,int flags)197 gdc_attach_unit(int unit, gdc_softc_t *sc, int flags)
198 {
199 	video_switch_t *sw;
200 
201 	sw = vid_get_switch(DRIVER_NAME);
202 	if (sw == NULL)
203 		return ENXIO;
204 	return (*sw->init)(unit, sc->adp, flags);
205 }
206 
207 
208 static int
gdc_alloc_resource(device_t dev)209 gdc_alloc_resource(device_t dev)
210 {
211 	int rid;
212 	gdc_softc_t *sc;
213 
214 	sc = device_get_softc(dev);
215 
216 	/* TEXT GDC */
217 	rid = 0;
218 	bus_set_resource(dev, SYS_RES_IOPORT, rid, TEXT_GDC, 1);
219 	sc->res_tgdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
220 					   gdc_iat, 8, RF_ACTIVE);
221 	if (sc->res_tgdc == NULL) {
222 		gdc_release_resource(dev);
223 		return (ENXIO);
224 	}
225 	isa_load_resourcev(sc->res_tgdc, gdc_iat, 8);
226 
227 	/* GRAPHIC GDC */
228 	rid = 8;
229 	bus_set_resource(dev, SYS_RES_IOPORT, rid, GRAPHIC_GDC, 1);
230 	sc->res_ggdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
231 					   gdc_iat, 8, RF_ACTIVE);
232 	if (sc->res_ggdc == NULL) {
233 		gdc_release_resource(dev);
234 		return (ENXIO);
235 	}
236 	isa_load_resourcev(sc->res_ggdc, gdc_iat, 8);
237 
238 	/* EGC */
239 	rid = 16;
240 	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4a0, 1);
241 	sc->res_egc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
242 					   gdc_iat, 8, RF_ACTIVE);
243 	if (sc->res_egc == NULL) {
244 		gdc_release_resource(dev);
245 		return (ENXIO);
246 	}
247 	isa_load_resourcev(sc->res_egc, gdc_iat, 8);
248 
249 	/* PEGC */
250 	rid = 24;
251 	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x9a0, 1);
252 	sc->res_pegc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
253 					   gdc_iat, 8, RF_ACTIVE);
254 	if (sc->res_pegc == NULL) {
255 		gdc_release_resource(dev);
256 		return (ENXIO);
257 	}
258 	isa_load_resourcev(sc->res_pegc, gdc_iat, 8);
259 
260 	/* CRTC/GRCG */
261 	rid = 32;
262 	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x70, 1);
263 	sc->res_grcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
264 					   gdc_iat, 8, RF_ACTIVE);
265 	if (sc->res_grcg == NULL) {
266 		gdc_release_resource(dev);
267 		return (ENXIO);
268 	}
269 	isa_load_resourcev(sc->res_grcg, gdc_iat, 8);
270 
271 	/* KCG */
272 	rid = 40;
273 	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0xa1, 1);
274 	sc->res_kcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
275 					  gdc_iat, 8, RF_ACTIVE);
276 	if (sc->res_kcg == NULL) {
277 		gdc_release_resource(dev);
278 		return (ENXIO);
279 	}
280 	isa_load_resourcev(sc->res_kcg, gdc_iat, 8);
281 
282 
283 	/* TEXT Memory */
284 	rid = 0;
285 	sc->res_tmem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
286 					  0xa0000, 0xa4fff, 0x5000, RF_ACTIVE);
287 	if (sc->res_tmem == NULL) {
288 		gdc_release_resource(dev);
289 		return (ENXIO);
290 	}
291 
292 	/* GRAPHIC Memory */
293 	rid = 1;
294 	sc->res_gmem1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
295 					   0xa8000, 0xbffff, 0x18000,
296 					   RF_ACTIVE);
297 	if (sc->res_gmem1 == NULL) {
298 		gdc_release_resource(dev);
299 		return (ENXIO);
300 	}
301 	rid = 2;
302 	sc->res_gmem2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
303 					   0xe0000, 0xe7fff, 0x8000,
304 					   RF_ACTIVE);
305 	if (sc->res_gmem2 == NULL) {
306 		gdc_release_resource(dev);
307 		return (ENXIO);
308 	}
309 
310 	return (0);
311 }
312 
313 static int
gdc_release_resource(device_t dev)314 gdc_release_resource(device_t dev)
315 {
316 	gdc_softc_t *sc;
317 
318 	sc = device_get_softc(dev);
319 
320 	if (sc->res_tgdc)
321 		bus_release_resource(dev, SYS_RES_IOPORT,  0, sc->res_tgdc);
322 	if (sc->res_ggdc)
323 		bus_release_resource(dev, SYS_RES_IOPORT,  8, sc->res_ggdc);
324 	if (sc->res_egc)
325 		bus_release_resource(dev, SYS_RES_IOPORT, 16, sc->res_egc);
326 	if (sc->res_pegc)
327 		bus_release_resource(dev, SYS_RES_IOPORT, 24, sc->res_pegc);
328 	if (sc->res_grcg)
329 		bus_release_resource(dev, SYS_RES_IOPORT, 32, sc->res_grcg);
330 	if (sc->res_kcg)
331 		bus_release_resource(dev, SYS_RES_IOPORT, 40, sc->res_kcg);
332 
333 	if (sc->res_tmem)
334 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res_tmem);
335 	if (sc->res_gmem1)
336 		bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->res_gmem1);
337 	if (sc->res_gmem2)
338 		bus_release_resource(dev, SYS_RES_MEMORY, 2, sc->res_gmem2);
339 
340 	return (0);
341 }
342 
343 /* cdev driver functions */
344 
345 #ifdef FB_INSTALL_CDEV
346 
347 static int
gdcopen(struct cdev * dev,int flag,int mode,struct thread * td)348 gdcopen(struct cdev *dev, int flag, int mode, struct thread *td)
349 {
350     gdc_softc_t *sc;
351 
352     sc = GDC_SOFTC(GDC_UNIT(dev));
353     if (sc == NULL)
354 	return ENXIO;
355     if (mode & (O_CREAT | O_APPEND | O_TRUNC))
356 	return ENODEV;
357 
358     return genfbopen(&sc->gensc, sc->adp, flag, mode, td);
359 }
360 
361 static int
gdcclose(struct cdev * dev,int flag,int mode,struct thread * td)362 gdcclose(struct cdev *dev, int flag, int mode, struct thread *td)
363 {
364     gdc_softc_t *sc;
365 
366     sc = GDC_SOFTC(GDC_UNIT(dev));
367     return genfbclose(&sc->gensc, sc->adp, flag, mode, td);
368 }
369 
370 static int
gdcread(struct cdev * dev,struct uio * uio,int flag)371 gdcread(struct cdev *dev, struct uio *uio, int flag)
372 {
373     gdc_softc_t *sc;
374 
375     sc = GDC_SOFTC(GDC_UNIT(dev));
376     return genfbread(&sc->gensc, sc->adp, uio, flag);
377 }
378 
379 static int
gdcwrite(struct cdev * dev,struct uio * uio,int flag)380 gdcwrite(struct cdev *dev, struct uio *uio, int flag)
381 {
382     gdc_softc_t *sc;
383 
384     sc = GDC_SOFTC(GDC_UNIT(dev));
385     return genfbread(&sc->gensc, sc->adp, uio, flag);
386 }
387 
388 static int
gdcioctl(struct cdev * dev,u_long cmd,caddr_t arg,int flag,struct thread * td)389 gdcioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
390 {
391     gdc_softc_t *sc;
392 
393     sc = GDC_SOFTC(GDC_UNIT(dev));
394     return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td);
395 }
396 
397 static int
gdcmmap(struct cdev * dev,vm_ooffset_t offset,vm_paddr_t * paddr,int prot,vm_memattr_t * memattr)398 gdcmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
399     int prot, vm_memattr_t *memattr)
400 {
401     gdc_softc_t *sc;
402 
403     sc = GDC_SOFTC(GDC_UNIT(dev));
404     return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot, memattr);
405 }
406 
407 #endif /* FB_INSTALL_CDEV */
408 
409 static device_method_t gdc_methods[] = {
410 	DEVMETHOD(device_identify,	gdc_identify),
411 	DEVMETHOD(device_probe,		gdcprobe),
412 	DEVMETHOD(device_attach,	gdc_attach),
413 	{ 0, 0 }
414 };
415 
416 static driver_t gdcdriver = {
417 	DRIVER_NAME,
418 	gdc_methods,
419 	sizeof(gdc_softc_t),
420 };
421 
422 DRIVER_MODULE(gdc, isa, gdcdriver, gdc_devclass, 0, 0);
423 
424 /* LOW-LEVEL */
425 
426 
427 #include <pc98/cbus/30line.h>
428 
429 #define TEXT_BUF_BASE		0x000a0000
430 #define TEXT_BUF_SIZE		0x00008000
431 #define GRAPHICS_BUF_BASE	0x000a8000
432 #define GRAPHICS_BUF_SIZE	0x00040000
433 #define VIDEO_BUF_BASE		0x000a0000
434 #define VIDEO_BUF_SIZE		0x00048000
435 
436 #define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
437 #define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
438 #define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
439 
440 /*
441  * NOTE: `va_window' should have a virtual address, but is initialized
442  * with a physical address in the following table, they will be
443  * converted at run-time.
444  */
445 static video_adapter_t adapter_init_value[] = {
446     { 0,
447       KD_PC98, "gdc",			/* va_type, va_name */
448       0, 0, 				/* va_unit, va_minor */
449       V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_BORDER,
450       TEXT_GDC, 16, TEXT_GDC,		/* va_io*, XXX */
451       VIDEO_BUF_BASE, VIDEO_BUF_SIZE,	/* va_mem* */
452       TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, /* va_window* */
453       0, 0, 				/* va_buffer, va_buffer_size */
454       0, M_PC98_80x25, 0, 		/* va_*mode* */
455     },
456 };
457 
458 static video_adapter_t	biosadapter[1];
459 
460 /* video driver declarations */
461 static int			gdc_configure(int flags);
462 static int			gdc_err(video_adapter_t *adp, ...);
463 static vi_probe_t		gdc_probe;
464 static vi_init_t		gdc_init;
465 static vi_get_info_t		gdc_get_info;
466 static vi_query_mode_t		gdc_query_mode;
467 static vi_set_mode_t		gdc_set_mode;
468 static vi_set_border_t		gdc_set_border;
469 static vi_save_state_t		gdc_save_state;
470 static vi_load_state_t		gdc_load_state;
471 static vi_read_hw_cursor_t	gdc_read_hw_cursor;
472 static vi_set_hw_cursor_t	gdc_set_hw_cursor;
473 static vi_set_hw_cursor_shape_t	gdc_set_hw_cursor_shape;
474 static vi_blank_display_t	gdc_blank_display;
475 static vi_mmap_t		gdc_mmap_buf;
476 static vi_ioctl_t		gdc_dev_ioctl;
477 static vi_clear_t		gdc_clear;
478 static vi_fill_rect_t		gdc_fill_rect;
479 static vi_bitblt_t		gdc_bitblt;
480 static vi_diag_t		gdc_diag;
481 static vi_save_palette_t	gdc_save_palette;
482 static vi_load_palette_t	gdc_load_palette;
483 static vi_set_win_org_t		gdc_set_origin;
484 
485 static video_switch_t gdcvidsw = {
486 	gdc_probe,
487 	gdc_init,
488 	gdc_get_info,
489 	gdc_query_mode,
490 	gdc_set_mode,
491 	(vi_save_font_t *)gdc_err,
492 	(vi_load_font_t *)gdc_err,
493 	(vi_show_font_t *)gdc_err,
494 	gdc_save_palette,
495 	gdc_load_palette,
496 	gdc_set_border,
497 	gdc_save_state,
498 	gdc_load_state,
499 	gdc_set_origin,
500 	gdc_read_hw_cursor,
501 	gdc_set_hw_cursor,
502 	gdc_set_hw_cursor_shape,
503 	gdc_blank_display,
504 	gdc_mmap_buf,
505 	gdc_dev_ioctl,
506 	gdc_clear,
507 	gdc_fill_rect,
508 	gdc_bitblt,
509 	(int (*)(void))gdc_err,
510 	(int (*)(void))gdc_err,
511 	gdc_diag,
512 };
513 
514 VIDEO_DRIVER(gdc, gdcvidsw, gdc_configure);
515 
516 /* GDC BIOS standard video modes */
517 #define EOT		(-1)
518 #define NA		(-2)
519 
520 static video_info_t bios_vmode[] = {
521     { M_PC98_80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
522       TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
523 #ifdef LINE30
524     { M_PC98_80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
525       TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
526 #endif
527 #ifndef GDC_NOGRAPHICS
528     { M_PC98_EGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS,
529       640, 400, 8, 16, 4, 4,
530       GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
531       V_INFO_MM_PLANAR },
532     { M_PC98_PEGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
533       640, 400, 8, 16, 8, 1,
534       GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
535       V_INFO_MM_PACKED, 1 },
536 #ifdef LINE30
537     { M_PC98_PEGC640x480, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
538       640, 480, 8, 16, 8, 1,
539       GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
540       V_INFO_MM_PACKED, 1 },
541 #endif
542 #endif
543     { EOT },
544 };
545 
546 static int		gdc_init_done = FALSE;
547 
548 /* local functions */
549 static int map_gen_mode_num(int type, int color, int mode);
550 static int probe_adapters(void);
551 
552 #define	prologue(adp, flag, err)			\
553 	if (!gdc_init_done || !((adp)->va_flags & (flag)))	\
554 	    return (err)
555 
556 /* a backdoor for the console driver */
557 static int
gdc_configure(int flags)558 gdc_configure(int flags)
559 {
560     probe_adapters();
561     biosadapter[0].va_flags |= V_ADP_INITIALIZED;
562     if (!config_done(&biosadapter[0])) {
563 	if (vid_register(&biosadapter[0]) < 0)
564 	    return 1;
565 	biosadapter[0].va_flags |= V_ADP_REGISTERED;
566     }
567 
568     return 1;
569 }
570 
571 /* local subroutines */
572 
573 /* map a generic video mode to a known mode number */
574 static int
map_gen_mode_num(int type,int color,int mode)575 map_gen_mode_num(int type, int color, int mode)
576 {
577     static struct {
578 	int from;
579 	int to;
580     } mode_map[] = {
581 	{ M_TEXT_80x25,	M_PC98_80x25, },
582 #ifdef LINE30
583 	{ M_TEXT_80x30,	M_PC98_80x30, },
584 #endif
585     };
586     int i;
587 
588     for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
589         if (mode_map[i].from == mode)
590             return mode_map[i].to;
591     }
592     return mode;
593 }
594 
595 static int
verify_adapter(video_adapter_t * adp)596 verify_adapter(video_adapter_t *adp)
597 {
598 #ifndef GDC_NOGRAPHICS
599     int i;
600 
601     if (PC98_SYSTEM_PARAMETER(0x45c) & 0x40) {		/* PEGC exists */
602 	adp->va_flags |= V_ADP_VESA;			/* XXX */
603     } else {
604 	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
605 	    if (bios_vmode[i].vi_flags & V_INFO_VESA)
606 		bios_vmode[i].vi_mode = NA;
607 	}
608     }
609 #endif
610     return 0;
611 }
612 
613 /* probe video adapters and return the number of detected adapters */
614 static int
probe_adapters(void)615 probe_adapters(void)
616 {
617     video_info_t info;
618 
619     /* do this test only once */
620     if (gdc_init_done)
621 	return 1;
622     gdc_init_done = TRUE;
623 
624     biosadapter[0] = adapter_init_value[0];
625     biosadapter[0].va_flags |= V_ADP_PROBED;
626     biosadapter[0].va_mode =
627 	biosadapter[0].va_initial_mode = biosadapter[0].va_initial_bios_mode;
628 
629     if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
630 	(PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
631 	gdc_FH = (inb(0x9a8) & 1) ? _31KHZ : _24KHZ;
632     } else {
633 	gdc_FH = _24KHZ;
634     }
635 
636     gdc_get_info(&biosadapter[0], biosadapter[0].va_initial_mode, &info);
637     initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
638 
639     biosadapter[0].va_window = BIOS_PADDRTOVADDR(info.vi_window);
640     biosadapter[0].va_window_size = info.vi_window_size;
641     biosadapter[0].va_window_gran = info.vi_window_gran;
642     biosadapter[0].va_buffer = 0;
643     biosadapter[0].va_buffer_size = 0;
644     if (info.vi_flags & V_INFO_GRAPHICS) {
645 	switch (info.vi_depth/info.vi_planes) {
646 	case 1:
647 	    biosadapter[0].va_line_width = info.vi_width/8;
648 	    break;
649 	case 2:
650 	    biosadapter[0].va_line_width = info.vi_width/4;
651 	    break;
652 	case 4:
653 	    biosadapter[0].va_line_width = info.vi_width/2;
654 	    break;
655 	case 8:
656 	default: /* shouldn't happen */
657 	    biosadapter[0].va_line_width = info.vi_width;
658 	    break;
659 	}
660     } else {
661 	biosadapter[0].va_line_width = info.vi_width;
662     }
663     bcopy(&info, &biosadapter[0].va_info, sizeof(info));
664 
665     verify_adapter(&biosadapter[0]);
666 
667     return 1;
668 }
669 
master_gdc_cmd(unsigned int cmd)670 static void master_gdc_cmd(unsigned int cmd)
671 {
672     while ( (inb(TEXT_GDC) & 2) != 0);
673     outb(TEXT_GDC+2, cmd);
674 }
675 
master_gdc_prm(unsigned int pmtr)676 static void master_gdc_prm(unsigned int pmtr)
677 {
678     while ( (inb(TEXT_GDC) & 2) != 0);
679     outb(TEXT_GDC, pmtr);
680 }
681 
master_gdc_word_prm(unsigned int wpmtr)682 static void master_gdc_word_prm(unsigned int wpmtr)
683 {
684     master_gdc_prm(wpmtr & 0x00ff);
685     master_gdc_prm((wpmtr >> 8) & 0x00ff);
686 }
687 
688 #ifdef LINE30
master_gdc_fifo_empty(void)689 static void master_gdc_fifo_empty(void)
690 {
691     while ( (inb(TEXT_GDC) & 4) == 0);
692 }
693 #endif
694 
master_gdc_wait_vsync(void)695 static void master_gdc_wait_vsync(void)
696 {
697     while ( (inb(TEXT_GDC) & 0x20) != 0);
698     while ( (inb(TEXT_GDC) & 0x20) == 0);
699 }
700 
gdc_cmd(unsigned int cmd)701 static void gdc_cmd(unsigned int cmd)
702 {
703     while ( (inb(GRAPHIC_GDC) & 2) != 0);
704     outb( GRAPHIC_GDC+2, cmd);
705 }
706 
707 #ifdef LINE30
gdc_prm(unsigned int pmtr)708 static void gdc_prm(unsigned int pmtr)
709 {
710     while ( (inb(GRAPHIC_GDC) & 2) != 0);
711     outb( GRAPHIC_GDC, pmtr);
712 }
713 
gdc_word_prm(unsigned int wpmtr)714 static void gdc_word_prm(unsigned int wpmtr)
715 {
716     gdc_prm(wpmtr & 0x00ff);
717     gdc_prm((wpmtr >> 8) & 0x00ff);
718 }
719 
gdc_fifo_empty(void)720 static void gdc_fifo_empty(void)
721 {
722     while ( (inb(GRAPHIC_GDC) & 0x04) == 0);
723 }
724 #endif
725 
gdc_wait_vsync(void)726 static void gdc_wait_vsync(void)
727 {
728     while ( (inb(GRAPHIC_GDC) & 0x20) != 0);
729     while ( (inb(GRAPHIC_GDC) & 0x20) == 0);
730 }
731 
732 #ifdef LINE30
check_gdc_clock(void)733 static int check_gdc_clock(void)
734 {
735     if ((inb(IO_SYSPORT) & 0x80) == 0){
736        	return _5MHZ;
737     } else {
738        	return _2_5MHZ;
739     }
740 }
741 #endif
742 
initialize_gdc(unsigned int mode,int isGraph)743 static void initialize_gdc(unsigned int mode, int isGraph)
744 {
745 #ifdef LINE30
746     /* start 30line initialize */
747     int m_mode, s_mode, gdc_clock, hsync_clock;
748 
749     gdc_clock = check_gdc_clock();
750     m_mode = (mode == T25_G400) ? _25L : _30L;
751     s_mode = 2*mode+gdc_clock;
752     gdc_INFO = m_mode;
753 
754     master_gdc_wait_vsync();
755 
756     if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
757 	(PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
758 	if (PC98_SYSTEM_PARAMETER(0x481) & 0x08) {
759 	    hsync_clock = (m_mode == _25L) ? gdc_FH : _31KHZ;
760 	    outb(0x9a8, (hsync_clock == _31KHZ) ? 1 : 0);
761 	} else {
762 	    hsync_clock = gdc_FH;
763 	}
764     } else {
765 	hsync_clock = _24KHZ;
766     }
767 
768     if ((gdc_clock == _2_5MHZ) &&
769 	(slave_param[hsync_clock][s_mode][GDC_LF] > 400)) {
770 	outb(0x6a, 0x83);
771 	outb(0x6a, 0x85);
772 	gdc_clock = _5MHZ;
773 	s_mode = 2*mode+gdc_clock;
774     }
775 
776     master_gdc_cmd(_GDC_RESET);
777     master_gdc_cmd(_GDC_MASTER);
778     gdc_cmd(_GDC_RESET);
779     gdc_cmd(_GDC_SLAVE);
780 
781     /* GDC Master */
782     master_gdc_cmd(_GDC_SYNC);
783     master_gdc_prm(0x00);	/* flush less */ /* text & graph */
784     master_gdc_prm(master_param[hsync_clock][m_mode][GDC_CR]);
785     master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_HFP] << 10)
786 		     + (master_param[hsync_clock][m_mode][GDC_VS] << 5)
787 		     + master_param[hsync_clock][m_mode][GDC_HS]));
788     master_gdc_prm(master_param[hsync_clock][m_mode][GDC_HBP]);
789     master_gdc_prm(master_param[hsync_clock][m_mode][GDC_VFP]);
790     master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_VBP] << 10)
791        		     + (master_param[hsync_clock][m_mode][GDC_LF])));
792     master_gdc_fifo_empty();
793     master_gdc_cmd(_GDC_PITCH);
794     master_gdc_prm(MasterPCH);
795     master_gdc_fifo_empty();
796 
797     /* GDC slave */
798     gdc_cmd(_GDC_SYNC);
799     gdc_prm(0x06);
800     gdc_prm(slave_param[hsync_clock][s_mode][GDC_CR]);
801     gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_HFP] << 10)
802 		+ (slave_param[hsync_clock][s_mode][GDC_VS] << 5)
803 		+ (slave_param[hsync_clock][s_mode][GDC_HS]));
804     gdc_prm(slave_param[hsync_clock][s_mode][GDC_HBP]);
805     gdc_prm(slave_param[hsync_clock][s_mode][GDC_VFP]);
806     gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_VBP] << 10)
807 		+ (slave_param[hsync_clock][s_mode][GDC_LF]));
808     gdc_fifo_empty();
809     gdc_cmd(_GDC_PITCH);
810     gdc_prm(SlavePCH[gdc_clock]);
811     gdc_fifo_empty();
812 
813     /* set Master GDC scroll param */
814     master_gdc_wait_vsync();
815     master_gdc_wait_vsync();
816     master_gdc_wait_vsync();
817     master_gdc_cmd(_GDC_SCROLL);
818     master_gdc_word_prm(0);
819     master_gdc_word_prm((master_param[hsync_clock][m_mode][GDC_LF] << 4)
820 			| 0x0000);
821     master_gdc_fifo_empty();
822 
823     /* set Slave GDC scroll param */
824     gdc_wait_vsync();
825     gdc_cmd(_GDC_SCROLL);
826     gdc_word_prm(0);
827     if (gdc_clock == _5MHZ) {
828 	gdc_word_prm((SlaveScrlLF[mode] << 4)  | 0x4000);
829     } else {
830 	gdc_word_prm(SlaveScrlLF[mode] << 4);
831     }
832     gdc_fifo_empty();
833 
834     gdc_word_prm(0);
835     if (gdc_clock == _5MHZ) {
836 	gdc_word_prm((SlaveScrlLF[mode] << 4)  | 0x4000);
837     } else {
838 	gdc_word_prm(SlaveScrlLF[mode] << 4);
839     }
840     gdc_fifo_empty();
841 
842     /* sync start */
843     gdc_cmd(isGraph ? _GDC_START : _GDC_STOP);
844 
845     gdc_wait_vsync();
846     gdc_wait_vsync();
847     gdc_wait_vsync();
848 
849     master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START);
850 #else
851     master_gdc_wait_vsync();
852     master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START);	/* text */
853     gdc_wait_vsync();
854     gdc_cmd(isGraph ? _GDC_START : _GDC_STOP);		/* graphics */
855 #endif
856 }
857 
858 #ifndef GDC_NOGRAPHICS
859 static u_char b_palette[] = {
860     /* R     G     B */
861     0x00, 0x00, 0x00,	/* 0 */
862     0x00, 0x00, 0x7f,	/* 1 */
863     0x7f, 0x00, 0x00,	/* 2 */
864     0x7f, 0x00, 0x7f,	/* 3 */
865     0x00, 0x7f, 0x00,	/* 4 */
866     0x00, 0x7f, 0x7f,	/* 5 */
867     0x7f, 0x7f, 0x00,	/* 6 */
868     0x7f, 0x7f, 0x7f,	/* 7 */
869     0x40, 0x40, 0x40,	/* 8 */
870     0x00, 0x00, 0xff,	/* 9 */
871     0xff, 0x00, 0x00,	/* 10 */
872     0xff, 0x00, 0xff,	/* 11 */
873     0x00, 0xff, 0x00,	/* 12 */
874     0x00, 0xff, 0xff,	/* 13 */
875     0xff, 0xff, 0x00,	/* 14 */
876     0xff, 0xff, 0xff,	/* 15 */
877 };
878 #endif
879 
880 static int
gdc_load_palette(video_adapter_t * adp,u_char * palette)881 gdc_load_palette(video_adapter_t *adp, u_char *palette)
882 {
883 #ifndef GDC_NOGRAPHICS
884     int i;
885 
886     if (adp->va_info.vi_flags & V_INFO_VESA) {
887 	gdc_wait_vsync();
888 	for (i = 0; i < 256; ++i) {
889 	    outb(0xa8, i);
890 	    outb(0xac, *palette++);	/* R */
891 	    outb(0xaa, *palette++);	/* G */
892 	    outb(0xae, *palette++);	/* B */
893 	}
894     } else {
895 	/*
896 	 * XXX - Even though PC-98 text color is independent of palette,
897 	 * we should set palette in text mode.
898 	 * Because the background color of text mode is palette 0's one.
899 	 */
900 	outb(0x6a, 1);		/* 16 colors mode */
901 	bcopy(palette, b_palette, sizeof(b_palette));
902 
903 	gdc_wait_vsync();
904 	for (i = 0; i < 16; ++i) {
905 	    outb(0xa8, i);
906 	    outb(0xac, *palette++ >> 4);	/* R */
907 	    outb(0xaa, *palette++ >> 4);	/* G */
908 	    outb(0xae, *palette++ >> 4);	/* B */
909 	}
910     }
911 #endif
912     return 0;
913 }
914 
915 static int
gdc_save_palette(video_adapter_t * adp,u_char * palette)916 gdc_save_palette(video_adapter_t *adp, u_char *palette)
917 {
918 #ifndef GDC_NOGRAPHICS
919     int i;
920 
921     if (adp->va_info.vi_flags & V_INFO_VESA) {
922 	for (i = 0; i < 256; ++i) {
923 	    outb(0xa8, i);
924 	    *palette++ = inb(0xac);	/* R */
925 	    *palette++ = inb(0xaa);	/* G */
926 	    *palette++ = inb(0xae);	/* B */
927 	}
928     } else {
929 	bcopy(b_palette, palette, sizeof(b_palette));
930     }
931 #endif
932     return 0;
933 }
934 
935 static int
gdc_set_origin(video_adapter_t * adp,off_t offset)936 gdc_set_origin(video_adapter_t *adp, off_t offset)
937 {
938 #ifndef GDC_NOGRAPHICS
939     if (adp->va_info.vi_flags & V_INFO_VESA) {
940 	writew(BIOS_PADDRTOVADDR(0x000e0004), offset >> 15);
941     }
942 #endif
943     return 0;
944 }
945 
946 /* entry points */
947 
948 static int
gdc_err(video_adapter_t * adp,...)949 gdc_err(video_adapter_t *adp, ...)
950 {
951     return ENODEV;
952 }
953 
954 static int
gdc_probe(int unit,video_adapter_t ** adpp,void * arg,int flags)955 gdc_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
956 {
957     probe_adapters();
958     if (unit >= 1)
959 	return ENXIO;
960 
961     *adpp = &biosadapter[unit];
962 
963     return 0;
964 }
965 
966 static int
gdc_init(int unit,video_adapter_t * adp,int flags)967 gdc_init(int unit, video_adapter_t *adp, int flags)
968 {
969     if ((unit >= 1) || (adp == NULL) || !probe_done(adp))
970 	return ENXIO;
971 
972     if (!init_done(adp)) {
973 	/* nothing to do really... */
974 	adp->va_flags |= V_ADP_INITIALIZED;
975     }
976 
977     if (!config_done(adp)) {
978 	if (vid_register(adp) < 0)
979 		return ENXIO;
980 	adp->va_flags |= V_ADP_REGISTERED;
981     }
982 
983     return 0;
984 }
985 
986 /*
987  * get_info():
988  * Return the video_info structure of the requested video mode.
989  */
990 static int
gdc_get_info(video_adapter_t * adp,int mode,video_info_t * info)991 gdc_get_info(video_adapter_t *adp, int mode, video_info_t *info)
992 {
993     int i;
994 
995     if (!gdc_init_done)
996 	return ENXIO;
997 
998     mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
999     for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1000 	if (bios_vmode[i].vi_mode == NA)
1001 	    continue;
1002 	if (mode == bios_vmode[i].vi_mode) {
1003 	    *info = bios_vmode[i];
1004 	    info->vi_buffer_size = info->vi_window_size*info->vi_planes;
1005 	    return 0;
1006 	}
1007     }
1008     return EINVAL;
1009 }
1010 
1011 /*
1012  * query_mode():
1013  * Find a video mode matching the requested parameters.
1014  * Fields filled with 0 are considered "don't care" fields and
1015  * match any modes.
1016  */
1017 static int
gdc_query_mode(video_adapter_t * adp,video_info_t * info)1018 gdc_query_mode(video_adapter_t *adp, video_info_t *info)
1019 {
1020     int i;
1021 
1022     if (!gdc_init_done)
1023 	return ENXIO;
1024 
1025     for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1026 	if (bios_vmode[i].vi_mode == NA)
1027 	    continue;
1028 
1029 	if ((info->vi_width != 0)
1030 	    && (info->vi_width != bios_vmode[i].vi_width))
1031 		continue;
1032 	if ((info->vi_height != 0)
1033 	    && (info->vi_height != bios_vmode[i].vi_height))
1034 		continue;
1035 	if ((info->vi_cwidth != 0)
1036 	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
1037 		continue;
1038 	if ((info->vi_cheight != 0)
1039 	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
1040 		continue;
1041 	if ((info->vi_depth != 0)
1042 	    && (info->vi_depth != bios_vmode[i].vi_depth))
1043 		continue;
1044 	if ((info->vi_planes != 0)
1045 	    && (info->vi_planes != bios_vmode[i].vi_planes))
1046 		continue;
1047 	/* XXX: should check pixel format, memory model */
1048 	if ((info->vi_flags != 0)
1049 	    && (info->vi_flags != bios_vmode[i].vi_flags))
1050 		continue;
1051 
1052 	/* verify if this mode is supported on this adapter */
1053 	if (gdc_get_info(adp, bios_vmode[i].vi_mode, info))
1054 		continue;
1055 	return 0;
1056     }
1057     return ENODEV;
1058 }
1059 
1060 /*
1061  * set_mode():
1062  * Change the video mode.
1063  */
1064 static int
gdc_set_mode(video_adapter_t * adp,int mode)1065 gdc_set_mode(video_adapter_t *adp, int mode)
1066 {
1067     video_info_t info;
1068 
1069     prologue(adp, V_ADP_MODECHANGE, ENODEV);
1070 
1071     mode = map_gen_mode_num(adp->va_type,
1072 			    adp->va_flags & V_ADP_COLOR, mode);
1073     if (gdc_get_info(adp, mode, &info))
1074 	return EINVAL;
1075 
1076     switch (info.vi_mode) {
1077 #ifndef GDC_NOGRAPHICS
1078 	case M_PC98_PEGC640x480:	/* PEGC 640x480 */
1079 	    initialize_gdc(T30_G480, info.vi_flags & V_INFO_GRAPHICS);
1080 	    break;
1081 	case M_PC98_PEGC640x400:	/* PEGC 640x400 */
1082 	case M_PC98_EGC640x400:		/* EGC GRAPHICS */
1083 #endif
1084 	case M_PC98_80x25:		/* VGA TEXT */
1085 	    initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
1086 	    break;
1087 	case M_PC98_80x30:		/* VGA TEXT */
1088 	    initialize_gdc(T30_G400, info.vi_flags & V_INFO_GRAPHICS);
1089 	    break;
1090 	default:
1091 	    break;
1092     }
1093 
1094 #ifndef GDC_NOGRAPHICS
1095     if (info.vi_flags & V_INFO_VESA) {
1096 	outb(0x6a, 0x07);		/* enable mode F/F change */
1097 	outb(0x6a, 0x21);		/* enhanced graphics */
1098 	if (info.vi_height > 400)
1099 	    outb(0x6a, 0x69);		/* 800 lines */
1100 	writeb(BIOS_PADDRTOVADDR(0x000e0100), 0);	/* packed pixel */
1101     } else {
1102 	if (adp->va_flags & V_ADP_VESA) {
1103 	    outb(0x6a, 0x07);		/* enable mode F/F change */
1104 	    outb(0x6a, 0x20);		/* normal graphics */
1105 	    outb(0x6a, 0x68);		/* 400 lines */
1106 	}
1107 	outb(0x6a, 1);			/* 16 colors */
1108     }
1109 #endif
1110 
1111     adp->va_mode = mode;
1112     adp->va_flags &= ~V_ADP_COLOR;
1113     adp->va_flags |=
1114 	(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
1115 #if 0
1116     adp->va_crtc_addr =
1117 	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
1118 #endif
1119     adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
1120     adp->va_window_size = info.vi_window_size;
1121     adp->va_window_gran = info.vi_window_gran;
1122     if (info.vi_buffer_size == 0) {
1123     	adp->va_buffer = 0;
1124     	adp->va_buffer_size = 0;
1125     } else {
1126     	adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
1127     	adp->va_buffer_size = info.vi_buffer_size;
1128     }
1129     if (info.vi_flags & V_INFO_GRAPHICS) {
1130 	switch (info.vi_depth/info.vi_planes) {
1131 	case 1:
1132 	    adp->va_line_width = info.vi_width/8;
1133 	    break;
1134 	case 2:
1135 	    adp->va_line_width = info.vi_width/4;
1136 	    break;
1137 	case 4:
1138 	    adp->va_line_width = info.vi_width/2;
1139 	    break;
1140 	case 8:
1141 	default: /* shouldn't happen */
1142 	    adp->va_line_width = info.vi_width;
1143 	    break;
1144 	}
1145     } else {
1146 	adp->va_line_width = info.vi_width;
1147     }
1148     bcopy(&info, &adp->va_info, sizeof(info));
1149 
1150     /* move hardware cursor out of the way */
1151     vidd_set_hw_cursor(adp, -1, -1);
1152 
1153     return 0;
1154 }
1155 
1156 /*
1157  * set_border():
1158  * Change the border color.
1159  */
1160 static int
gdc_set_border(video_adapter_t * adp,int color)1161 gdc_set_border(video_adapter_t *adp, int color)
1162 {
1163     outb(0x6c, color << 4);
1164     return 0;
1165 }
1166 
1167 /*
1168  * save_state():
1169  * Read video card register values.
1170  */
1171 static int
gdc_save_state(video_adapter_t * adp,void * p,size_t size)1172 gdc_save_state(video_adapter_t *adp, void *p, size_t size)
1173 {
1174     return ENODEV;
1175 }
1176 
1177 /*
1178  * load_state():
1179  * Set video card registers at once.
1180  */
1181 static int
gdc_load_state(video_adapter_t * adp,void * p)1182 gdc_load_state(video_adapter_t *adp, void *p)
1183 {
1184     return ENODEV;
1185 }
1186 
1187 /*
1188  * read_hw_cursor():
1189  * Read the position of the hardware text cursor.
1190  */
1191 static int
gdc_read_hw_cursor(video_adapter_t * adp,int * col,int * row)1192 gdc_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
1193 {
1194     u_int16_t off;
1195     int s;
1196 
1197     if (!gdc_init_done)
1198 	return ENXIO;
1199 
1200     if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
1201 	return ENODEV;
1202 
1203     s = spltty();
1204     master_gdc_cmd(0xe0);	/* _GDC_CSRR */
1205     while((inb(TEXT_GDC + 0) & 0x1) == 0) {}	/* GDC wait */
1206     off = inb(TEXT_GDC + 2);			/* EADl */
1207     off |= (inb(TEXT_GDC + 2) << 8);		/* EADh */
1208     inb(TEXT_GDC + 2);				/* dummy */
1209     inb(TEXT_GDC + 2);				/* dummy */
1210     inb(TEXT_GDC + 2);				/* dummy */
1211     splx(s);
1212 
1213     if (off >= ROW*COL)
1214 	off = 0;
1215     *row = off / adp->va_info.vi_width;
1216     *col = off % adp->va_info.vi_width;
1217 
1218     return 0;
1219 }
1220 
1221 /*
1222  * set_hw_cursor():
1223  * Move the hardware text cursor.  If col and row are both -1,
1224  * the cursor won't be shown.
1225  */
1226 static int
gdc_set_hw_cursor(video_adapter_t * adp,int col,int row)1227 gdc_set_hw_cursor(video_adapter_t *adp, int col, int row)
1228 {
1229     u_int16_t off;
1230     int s;
1231 
1232     if (!gdc_init_done)
1233 	return ENXIO;
1234 
1235     if ((col == -1) && (row == -1)) {
1236 	off = -1;
1237     } else {
1238 	if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
1239 	    return ENODEV;
1240 	off = row*adp->va_info.vi_width + col;
1241     }
1242 
1243     s = spltty();
1244     master_gdc_cmd(0x49);	/* _GDC_CSRW */
1245     master_gdc_word_prm(off);
1246     splx(s);
1247 
1248     return 0;
1249 }
1250 
1251 /*
1252  * set_hw_cursor_shape():
1253  * Change the shape of the hardware text cursor.  If the height is zero
1254  * or negative, the cursor won't be shown.
1255  */
1256 static int
gdc_set_hw_cursor_shape(video_adapter_t * adp,int base,int height,int celsize,int blink)1257 gdc_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
1258 			int celsize, int blink)
1259 {
1260     int start;
1261     int end;
1262     int s;
1263 
1264     if (!gdc_init_done)
1265 	return ENXIO;
1266 
1267     start = celsize - (base + height);
1268     end = celsize - base - 1;
1269 
1270 #if 0
1271     /*
1272      * muPD7220 GDC has anomaly that if end == celsize - 1 then start
1273      * must be 0, otherwise the cursor won't be correctly shown
1274      * in the first row in the screen.  We shall set end to celsize - 2;
1275      * if end == celsize -1 && start > 0. XXX
1276      */
1277     if ((end == celsize - 1) && (start > 0) && (start < end))
1278 	--end;
1279 #endif
1280 
1281     s = spltty();
1282     master_gdc_cmd(0x4b);			/* _GDC_CSRFORM */
1283     master_gdc_prm(((height > 0) ? 0x80 : 0)	/* cursor on/off */
1284 	| ((celsize - 1) & 0x1f));		/* cel size */
1285     master_gdc_word_prm(((end & 0x1f) << 11)	/* end line */
1286 	| (12 << 6)				/* blink rate */
1287 	| (blink ? 0 : 0x20)			/* blink on/off */
1288 	| (start & 0x1f));			/* start line */
1289     splx(s);
1290 
1291     return 0;
1292 }
1293 
1294 /*
1295  * blank_display()
1296  * Put the display in power save/power off mode.
1297  */
1298 static int
gdc_blank_display(video_adapter_t * adp,int mode)1299 gdc_blank_display(video_adapter_t *adp, int mode)
1300 {
1301     int s;
1302     static int standby = 0;
1303 
1304     if (!gdc_init_done)
1305 	return ENXIO;
1306 
1307     s = splhigh();
1308     switch (mode) {
1309     case V_DISPLAY_SUSPEND:
1310     case V_DISPLAY_STAND_BY:
1311 	outb(0x09a2, 0x80 | 0x40);		/* V/H-SYNC mask */
1312 	if (inb(0x09a2) == (0x80 | 0x40))
1313 	    standby = 1;
1314 	/* FALLTHROUGH */
1315 
1316     case V_DISPLAY_BLANK:
1317 	while (!(inb(TEXT_GDC) & 0x20))		/* V-SYNC wait */
1318 	    ;
1319 	outb(TEXT_GDC + 8, 0x0e);		/* DISP off */
1320 	break;
1321 
1322     case V_DISPLAY_ON:
1323 	while (!(inb(TEXT_GDC) & 0x20))		/* V-SYNC wait */
1324 	    ;
1325 	outb(TEXT_GDC + 8, 0x0f);		/* DISP on */
1326 	if (standby) {
1327 	    outb(0x09a2, 0x00);			/* V/H-SYNC unmask */
1328 	    standby = 0;
1329 	}
1330 	break;
1331     }
1332     splx(s);
1333     return 0;
1334 }
1335 
1336 /*
1337  * mmap():
1338  * Mmap frame buffer.
1339  */
1340 static int
gdc_mmap_buf(video_adapter_t * adp,vm_ooffset_t offset,vm_offset_t * paddr,int prot,vm_memattr_t * memattr)1341 gdc_mmap_buf(video_adapter_t *adp, vm_ooffset_t offset, vm_offset_t *paddr,
1342 	     int prot, vm_memattr_t *memattr)
1343 {
1344     /* FIXME: is this correct? XXX */
1345     if (offset > VIDEO_BUF_SIZE - PAGE_SIZE)
1346 	return -1;
1347     *paddr = adp->va_info.vi_window + offset;
1348     return 0;
1349 }
1350 
1351 #ifndef GDC_NOGRAPHICS
1352 static void
planar_fill(video_adapter_t * adp,int val)1353 planar_fill(video_adapter_t *adp, int val)
1354 {
1355 
1356     outb(0x7c, 0x80);				/* GRCG on & TDW mode */
1357     outb(0x7e, 0);				/* tile B */
1358     outb(0x7e, 0);				/* tile R */
1359     outb(0x7e, 0);				/* tile G */
1360     outb(0x7e, 0);				/* tile I */
1361 
1362     fillw_io(0, adp->va_window, 0x8000 / 2);	/* XXX */
1363 
1364     outb(0x7c, 0);				/* GRCG off */
1365 }
1366 
1367 static void
packed_fill(video_adapter_t * adp,int val)1368 packed_fill(video_adapter_t *adp, int val)
1369 {
1370     int length;
1371     int at;			/* position in the frame buffer */
1372     int l;
1373 
1374     at = 0;
1375     length = adp->va_line_width*adp->va_info.vi_height;
1376     while (length > 0) {
1377 	l = imin(length, adp->va_window_size);
1378 	vidd_set_win_org(adp, at);
1379 	bzero_io(adp->va_window, l);
1380 	length -= l;
1381 	at += l;
1382     }
1383 }
1384 
1385 static int
gdc_clear(video_adapter_t * adp)1386 gdc_clear(video_adapter_t *adp)
1387 {
1388 
1389     switch (adp->va_info.vi_mem_model) {
1390     case V_INFO_MM_TEXT:
1391 	/* do nothing? XXX */
1392 	break;
1393     case V_INFO_MM_PLANAR:
1394 	planar_fill(adp, 0);
1395 	break;
1396     case V_INFO_MM_PACKED:
1397 	packed_fill(adp, 0);
1398 	break;
1399     }
1400 
1401     return 0;
1402 }
1403 #else /* GDC_NOGRAPHICS */
1404 static int
gdc_clear(video_adapter_t * adp)1405 gdc_clear(video_adapter_t *adp)
1406 {
1407 
1408     return 0;
1409 }
1410 #endif /* GDC_NOGRAPHICS */
1411 
1412 static int
gdc_fill_rect(video_adapter_t * adp,int val,int x,int y,int cx,int cy)1413 gdc_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
1414 {
1415     return ENODEV;
1416 }
1417 
1418 static int
gdc_bitblt(video_adapter_t * adp,...)1419 gdc_bitblt(video_adapter_t *adp,...)
1420 {
1421     /* FIXME */
1422     return ENODEV;
1423 }
1424 
1425 static int
gdc_dev_ioctl(video_adapter_t * adp,u_long cmd,caddr_t arg)1426 gdc_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
1427 {
1428     switch (cmd) {
1429     case FBIO_GETWINORG:	/* get frame buffer window origin */
1430 	*(u_int *)arg = 0;
1431 	return 0;
1432 
1433     case FBIO_SETWINORG:	/* set frame buffer window origin */
1434     case FBIO_SETDISPSTART:	/* set display start address */
1435     case FBIO_SETLINEWIDTH:	/* set scan line length in pixel */
1436     case FBIO_GETPALETTE:	/* get color palette */
1437     case FBIO_SETPALETTE:	/* set color palette */
1438     case FBIOGETCMAP:		/* get color palette */
1439     case FBIOPUTCMAP:		/* set color palette */
1440 	return ENODEV;
1441 
1442     case FBIOGTYPE:		/* get frame buffer type info. */
1443 	((struct fbtype *)arg)->fb_type = fb_type(adp->va_type);
1444 	((struct fbtype *)arg)->fb_height = adp->va_info.vi_height;
1445 	((struct fbtype *)arg)->fb_width = adp->va_info.vi_width;
1446 	((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth;
1447 	if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8))
1448 	    ((struct fbtype *)arg)->fb_cmsize = 0;
1449 	else
1450 	    ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth;
1451 	((struct fbtype *)arg)->fb_size = adp->va_buffer_size;
1452 	return 0;
1453 
1454     default:
1455 	return fb_commonioctl(adp, cmd, arg);
1456     }
1457 }
1458 
1459 /*
1460  * diag():
1461  * Print some information about the video adapter and video modes,
1462  * with requested level of details.
1463  */
1464 static int
gdc_diag(video_adapter_t * adp,int level)1465 gdc_diag(video_adapter_t *adp, int level)
1466 {
1467 #if defined(FB_DEBUG) && FB_DEBUG > 1
1468     int i;
1469 #endif
1470 
1471     if (!gdc_init_done)
1472 	return ENXIO;
1473 
1474     fb_dump_adp_info(DRIVER_NAME, adp, level);
1475 
1476 #if defined(FB_DEBUG) && FB_DEBUG > 1
1477     for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1478 	 if (bios_vmode[i].vi_mode == NA)
1479 	    continue;
1480 	 if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
1481 	    continue;
1482 	 fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
1483     }
1484 #endif
1485 
1486     return 0;
1487 }
1488