]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/pc98/cbus/gdc.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / pc98 / cbus / gdc.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
676 static void master_gdc_prm(unsigned int pmtr)
677 {
678     while ( (inb(TEXT_GDC) & 2) != 0);
679     outb(TEXT_GDC, pmtr);
680 }
681
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
689 static void master_gdc_fifo_empty(void)
690 {
691     while ( (inb(TEXT_GDC) & 4) == 0);     
692 }
693 #endif
694
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
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
708 static void gdc_prm(unsigned int pmtr)
709 {
710     while ( (inb(GRAPHIC_GDC) & 2) != 0);
711     outb( GRAPHIC_GDC, pmtr);
712 }
713
714 static void gdc_word_prm(unsigned int wpmtr)
715 {
716     gdc_prm(wpmtr & 0x00ff);
717     gdc_prm((wpmtr >> 8) & 0x00ff);
718 }
719
720 static void gdc_fifo_empty(void)
721 {
722     while ( (inb(GRAPHIC_GDC) & 0x04) == 0);          
723 }
724 #endif
725
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
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
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
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
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
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
949 gdc_err(video_adapter_t *adp, ...)
950 {
951     return ENODEV;
952 }
953
954 static int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1405 gdc_clear(video_adapter_t *adp)
1406 {
1407
1408     return 0;
1409 }
1410 #endif /* GDC_NOGRAPHICS */
1411
1412 static int
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
1419 gdc_bitblt(video_adapter_t *adp,...)
1420 {
1421     /* FIXME */
1422     return ENODEV;
1423 }
1424
1425 static int
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
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 }