]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/pc98/cbus/gdc.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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_offset_t offset, vm_paddr_t *paddr, int prot)
399 {
400     gdc_softc_t *sc;
401
402     sc = GDC_SOFTC(GDC_UNIT(dev));
403     return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot);
404 }
405
406 #endif /* FB_INSTALL_CDEV */
407
408 static device_method_t gdc_methods[] = {
409         DEVMETHOD(device_identify,      gdc_identify),
410         DEVMETHOD(device_probe,         gdcprobe),
411         DEVMETHOD(device_attach,        gdc_attach),
412         { 0, 0 }
413 };
414
415 static driver_t gdcdriver = {
416         DRIVER_NAME,
417         gdc_methods,
418         sizeof(gdc_softc_t),
419 };
420
421 DRIVER_MODULE(gdc, isa, gdcdriver, gdc_devclass, 0, 0);
422
423 /* LOW-LEVEL */
424
425
426 #include <pc98/cbus/30line.h>
427
428 #define TEXT_BUF_BASE           0x000a0000
429 #define TEXT_BUF_SIZE           0x00008000
430 #define GRAPHICS_BUF_BASE       0x000a8000
431 #define GRAPHICS_BUF_SIZE       0x00040000
432 #define VIDEO_BUF_BASE          0x000a0000
433 #define VIDEO_BUF_SIZE          0x00048000
434
435 #define probe_done(adp)         ((adp)->va_flags & V_ADP_PROBED)
436 #define init_done(adp)          ((adp)->va_flags & V_ADP_INITIALIZED)
437 #define config_done(adp)        ((adp)->va_flags & V_ADP_REGISTERED)
438
439 /* 
440  * NOTE: `va_window' should have a virtual address, but is initialized
441  * with a physical address in the following table, they will be
442  * converted at run-time.
443  */
444 static video_adapter_t adapter_init_value[] = {
445     { 0,
446       KD_PC98, "gdc",                   /* va_type, va_name */
447       0, 0,                             /* va_unit, va_minor */
448       V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_BORDER, 
449       TEXT_GDC, 16, TEXT_GDC,           /* va_io*, XXX */
450       VIDEO_BUF_BASE, VIDEO_BUF_SIZE,   /* va_mem* */
451       TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, /* va_window* */
452       0, 0,                             /* va_buffer, va_buffer_size */
453       0, M_PC98_80x25, 0,               /* va_*mode* */
454     },
455 };
456
457 static video_adapter_t  biosadapter[1];
458
459 /* video driver declarations */
460 static int                      gdc_configure(int flags);
461 static int                      gdc_err(video_adapter_t *adp, ...);
462 static vi_probe_t               gdc_probe;
463 static vi_init_t                gdc_init;
464 static vi_get_info_t            gdc_get_info;
465 static vi_query_mode_t          gdc_query_mode;
466 static vi_set_mode_t            gdc_set_mode;
467 static vi_set_border_t          gdc_set_border;
468 static vi_save_state_t          gdc_save_state;
469 static vi_load_state_t          gdc_load_state;
470 static vi_read_hw_cursor_t      gdc_read_hw_cursor;
471 static vi_set_hw_cursor_t       gdc_set_hw_cursor;
472 static vi_set_hw_cursor_shape_t gdc_set_hw_cursor_shape;
473 static vi_blank_display_t       gdc_blank_display;
474 static vi_mmap_t                gdc_mmap_buf;
475 static vi_ioctl_t               gdc_dev_ioctl;
476 static vi_clear_t               gdc_clear;
477 static vi_fill_rect_t           gdc_fill_rect;
478 static vi_bitblt_t              gdc_bitblt;
479 static vi_diag_t                gdc_diag;
480 static vi_save_palette_t        gdc_save_palette;
481 static vi_load_palette_t        gdc_load_palette;
482 static vi_set_win_org_t         gdc_set_origin;
483
484 static video_switch_t gdcvidsw = {
485         gdc_probe,
486         gdc_init,
487         gdc_get_info,
488         gdc_query_mode, 
489         gdc_set_mode,
490         (vi_save_font_t *)gdc_err,
491         (vi_load_font_t *)gdc_err,
492         (vi_show_font_t *)gdc_err,
493         gdc_save_palette,
494         gdc_load_palette,
495         gdc_set_border,
496         gdc_save_state,
497         gdc_load_state,
498         gdc_set_origin,
499         gdc_read_hw_cursor,
500         gdc_set_hw_cursor,
501         gdc_set_hw_cursor_shape,
502         gdc_blank_display,
503         gdc_mmap_buf,
504         gdc_dev_ioctl,
505         gdc_clear,
506         gdc_fill_rect,
507         gdc_bitblt,
508         (int (*)(void))gdc_err,
509         (int (*)(void))gdc_err,
510         gdc_diag,
511 };
512
513 VIDEO_DRIVER(gdc, gdcvidsw, gdc_configure);
514
515 /* GDC BIOS standard video modes */
516 #define EOT             (-1)
517 #define NA              (-2)
518
519 static video_info_t bios_vmode[] = {
520     { M_PC98_80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
521       TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
522 #ifdef LINE30
523     { M_PC98_80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
524       TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
525 #endif
526 #ifndef GDC_NOGRAPHICS
527     { M_PC98_EGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS,
528       640, 400, 8, 16, 4, 4,
529       GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
530       V_INFO_MM_PLANAR },
531     { M_PC98_PEGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
532       640, 400, 8, 16, 8, 1,
533       GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
534       V_INFO_MM_PACKED, 1 },
535 #ifdef LINE30
536     { M_PC98_PEGC640x480, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
537       640, 480, 8, 16, 8, 1,
538       GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
539       V_INFO_MM_PACKED, 1 },
540 #endif
541 #endif
542     { EOT },
543 };
544
545 static int              gdc_init_done = FALSE;
546
547 /* local functions */
548 static int map_gen_mode_num(int type, int color, int mode);
549 static int probe_adapters(void);
550
551 #define prologue(adp, flag, err)                        \
552         if (!gdc_init_done || !((adp)->va_flags & (flag)))      \
553             return (err)
554
555 /* a backdoor for the console driver */
556 static int
557 gdc_configure(int flags)
558 {
559     probe_adapters();
560     biosadapter[0].va_flags |= V_ADP_INITIALIZED;
561     if (!config_done(&biosadapter[0])) {
562         if (vid_register(&biosadapter[0]) < 0)
563             return 1;
564         biosadapter[0].va_flags |= V_ADP_REGISTERED;
565     }
566
567     return 1;
568 }
569
570 /* local subroutines */
571
572 /* map a generic video mode to a known mode number */
573 static int
574 map_gen_mode_num(int type, int color, int mode)
575 {
576     static struct {
577         int from;
578         int to;
579     } mode_map[] = {
580         { M_TEXT_80x25, M_PC98_80x25, },
581 #ifdef LINE30
582         { M_TEXT_80x30, M_PC98_80x30, },
583 #endif
584     };
585     int i;
586
587     for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
588         if (mode_map[i].from == mode)
589             return mode_map[i].to;
590     }
591     return mode;
592 }
593
594 static int
595 verify_adapter(video_adapter_t *adp)
596 {
597 #ifndef GDC_NOGRAPHICS
598     int i;
599
600     if (PC98_SYSTEM_PARAMETER(0x45c) & 0x40) {          /* PEGC exists */
601         adp->va_flags |= V_ADP_VESA;                    /* XXX */
602     } else {
603         for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
604             if (bios_vmode[i].vi_flags & V_INFO_VESA)
605                 bios_vmode[i].vi_mode = NA;
606         }
607     }
608 #endif
609     return 0;
610 }
611
612 /* probe video adapters and return the number of detected adapters */
613 static int
614 probe_adapters(void)
615 {
616     video_info_t info;
617
618     /* do this test only once */
619     if (gdc_init_done)
620         return 1;
621     gdc_init_done = TRUE;
622
623     biosadapter[0] = adapter_init_value[0];
624     biosadapter[0].va_flags |= V_ADP_PROBED;
625     biosadapter[0].va_mode = 
626         biosadapter[0].va_initial_mode = biosadapter[0].va_initial_bios_mode;
627
628     if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
629         (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
630         gdc_FH = (inb(0x9a8) & 1) ? _31KHZ : _24KHZ;
631     } else {
632         gdc_FH = _24KHZ;
633     }
634
635     gdc_get_info(&biosadapter[0], biosadapter[0].va_initial_mode, &info);
636     initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
637
638     biosadapter[0].va_window = BIOS_PADDRTOVADDR(info.vi_window);
639     biosadapter[0].va_window_size = info.vi_window_size;
640     biosadapter[0].va_window_gran = info.vi_window_gran;
641     biosadapter[0].va_buffer = 0;
642     biosadapter[0].va_buffer_size = 0;
643     if (info.vi_flags & V_INFO_GRAPHICS) {
644         switch (info.vi_depth/info.vi_planes) {
645         case 1:
646             biosadapter[0].va_line_width = info.vi_width/8;
647             break;
648         case 2:
649             biosadapter[0].va_line_width = info.vi_width/4;
650             break;
651         case 4:
652             biosadapter[0].va_line_width = info.vi_width/2;
653             break;
654         case 8:
655         default: /* shouldn't happen */
656             biosadapter[0].va_line_width = info.vi_width;
657             break;
658         }
659     } else {
660         biosadapter[0].va_line_width = info.vi_width;
661     }
662     bcopy(&info, &biosadapter[0].va_info, sizeof(info));
663
664     verify_adapter(&biosadapter[0]);
665
666     return 1;
667 }
668
669 static void master_gdc_cmd(unsigned int cmd)
670 {
671     while ( (inb(TEXT_GDC) & 2) != 0);
672     outb(TEXT_GDC+2, cmd);
673 }
674
675 static void master_gdc_prm(unsigned int pmtr)
676 {
677     while ( (inb(TEXT_GDC) & 2) != 0);
678     outb(TEXT_GDC, pmtr);
679 }
680
681 static void master_gdc_word_prm(unsigned int wpmtr)
682 {
683     master_gdc_prm(wpmtr & 0x00ff);
684     master_gdc_prm((wpmtr >> 8) & 0x00ff);
685 }       
686
687 #ifdef LINE30
688 static void master_gdc_fifo_empty(void)
689 {
690     while ( (inb(TEXT_GDC) & 4) == 0);     
691 }
692 #endif
693
694 static void master_gdc_wait_vsync(void)
695 {
696     while ( (inb(TEXT_GDC) & 0x20) != 0);          
697     while ( (inb(TEXT_GDC) & 0x20) == 0);          
698 }
699
700 static void gdc_cmd(unsigned int cmd)
701 {
702     while ( (inb(GRAPHIC_GDC) & 2) != 0);
703     outb( GRAPHIC_GDC+2, cmd);
704 }
705
706 #ifdef LINE30
707 static void gdc_prm(unsigned int pmtr)
708 {
709     while ( (inb(GRAPHIC_GDC) & 2) != 0);
710     outb( GRAPHIC_GDC, pmtr);
711 }
712
713 static void gdc_word_prm(unsigned int wpmtr)
714 {
715     gdc_prm(wpmtr & 0x00ff);
716     gdc_prm((wpmtr >> 8) & 0x00ff);
717 }
718
719 static void gdc_fifo_empty(void)
720 {
721     while ( (inb(GRAPHIC_GDC) & 0x04) == 0);          
722 }
723 #endif
724
725 static void gdc_wait_vsync(void)
726 {
727     while ( (inb(GRAPHIC_GDC) & 0x20) != 0);          
728     while ( (inb(GRAPHIC_GDC) & 0x20) == 0);          
729 }
730
731 #ifdef LINE30
732 static int check_gdc_clock(void)
733 {
734     if ((inb(IO_SYSPORT) & 0x80) == 0){
735         return _5MHZ;
736     } else {
737         return _2_5MHZ;
738     }
739 }
740 #endif
741
742 static void initialize_gdc(unsigned int mode, int isGraph)
743 {
744 #ifdef LINE30
745     /* start 30line initialize */
746     int m_mode, s_mode, gdc_clock, hsync_clock;
747
748     gdc_clock = check_gdc_clock();
749     m_mode = (mode == T25_G400) ? _25L : _30L;
750     s_mode = 2*mode+gdc_clock;
751     gdc_INFO = m_mode;
752
753     master_gdc_wait_vsync();
754
755     if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
756         (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
757         if (PC98_SYSTEM_PARAMETER(0x481) & 0x08) {
758             hsync_clock = (m_mode == _25L) ? gdc_FH : _31KHZ;
759             outb(0x9a8, (hsync_clock == _31KHZ) ? 1 : 0);
760         } else {
761             hsync_clock = gdc_FH;
762         }
763     } else {
764         hsync_clock = _24KHZ;
765     }
766
767     if ((gdc_clock == _2_5MHZ) &&
768         (slave_param[hsync_clock][s_mode][GDC_LF] > 400)) {
769         outb(0x6a, 0x83);
770         outb(0x6a, 0x85);
771         gdc_clock = _5MHZ;
772         s_mode = 2*mode+gdc_clock;
773     }
774
775     master_gdc_cmd(_GDC_RESET);
776     master_gdc_cmd(_GDC_MASTER);
777     gdc_cmd(_GDC_RESET);
778     gdc_cmd(_GDC_SLAVE);                
779
780     /* GDC Master */
781     master_gdc_cmd(_GDC_SYNC);
782     master_gdc_prm(0x00);       /* flush less */ /* text & graph */
783     master_gdc_prm(master_param[hsync_clock][m_mode][GDC_CR]);
784     master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_HFP] << 10) 
785                      + (master_param[hsync_clock][m_mode][GDC_VS] << 5) 
786                      + master_param[hsync_clock][m_mode][GDC_HS]));
787     master_gdc_prm(master_param[hsync_clock][m_mode][GDC_HBP]);
788     master_gdc_prm(master_param[hsync_clock][m_mode][GDC_VFP]);
789     master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_VBP] << 10) 
790                      + (master_param[hsync_clock][m_mode][GDC_LF])));
791     master_gdc_fifo_empty();
792     master_gdc_cmd(_GDC_PITCH);
793     master_gdc_prm(MasterPCH);
794     master_gdc_fifo_empty();
795         
796     /* GDC slave */
797     gdc_cmd(_GDC_SYNC);
798     gdc_prm(0x06);
799     gdc_prm(slave_param[hsync_clock][s_mode][GDC_CR]);
800     gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_HFP] << 10) 
801                 + (slave_param[hsync_clock][s_mode][GDC_VS] << 5) 
802                 + (slave_param[hsync_clock][s_mode][GDC_HS]));
803     gdc_prm(slave_param[hsync_clock][s_mode][GDC_HBP]);
804     gdc_prm(slave_param[hsync_clock][s_mode][GDC_VFP]);
805     gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_VBP] << 10) 
806                 + (slave_param[hsync_clock][s_mode][GDC_LF]));
807     gdc_fifo_empty();
808     gdc_cmd(_GDC_PITCH);
809     gdc_prm(SlavePCH[gdc_clock]);
810     gdc_fifo_empty();
811
812     /* set Master GDC scroll param */
813     master_gdc_wait_vsync();
814     master_gdc_wait_vsync();
815     master_gdc_wait_vsync();
816     master_gdc_cmd(_GDC_SCROLL);
817     master_gdc_word_prm(0);
818     master_gdc_word_prm((master_param[hsync_clock][m_mode][GDC_LF] << 4)
819                         | 0x0000);
820     master_gdc_fifo_empty();
821
822     /* set Slave GDC scroll param */
823     gdc_wait_vsync();
824     gdc_cmd(_GDC_SCROLL);
825     gdc_word_prm(0);
826     if (gdc_clock == _5MHZ) {
827         gdc_word_prm((SlaveScrlLF[mode] << 4)  | 0x4000);
828     } else {
829         gdc_word_prm(SlaveScrlLF[mode] << 4);
830     }
831     gdc_fifo_empty();
832
833     gdc_word_prm(0);
834     if (gdc_clock == _5MHZ) {
835         gdc_word_prm((SlaveScrlLF[mode] << 4)  | 0x4000);
836     } else {
837         gdc_word_prm(SlaveScrlLF[mode] << 4);
838     }
839     gdc_fifo_empty();
840
841     /* sync start */
842     gdc_cmd(isGraph ? _GDC_START : _GDC_STOP);
843
844     gdc_wait_vsync();
845     gdc_wait_vsync();
846     gdc_wait_vsync();
847
848     master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START);
849 #else
850     master_gdc_wait_vsync();
851     master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START);   /* text */
852     gdc_wait_vsync();
853     gdc_cmd(isGraph ? _GDC_START : _GDC_STOP);          /* graphics */
854 #endif
855 }
856
857 #ifndef GDC_NOGRAPHICS
858 static u_char b_palette[] = {
859     /* R     G     B */
860     0x00, 0x00, 0x00,   /* 0 */
861     0x00, 0x00, 0x7f,   /* 1 */
862     0x7f, 0x00, 0x00,   /* 2 */
863     0x7f, 0x00, 0x7f,   /* 3 */
864     0x00, 0x7f, 0x00,   /* 4 */
865     0x00, 0x7f, 0x7f,   /* 5 */
866     0x7f, 0x7f, 0x00,   /* 6 */
867     0x7f, 0x7f, 0x7f,   /* 7 */
868     0x40, 0x40, 0x40,   /* 8 */
869     0x00, 0x00, 0xff,   /* 9 */
870     0xff, 0x00, 0x00,   /* 10 */
871     0xff, 0x00, 0xff,   /* 11 */
872     0x00, 0xff, 0x00,   /* 12 */
873     0x00, 0xff, 0xff,   /* 13 */
874     0xff, 0xff, 0x00,   /* 14 */
875     0xff, 0xff, 0xff,   /* 15 */
876 };
877 #endif
878
879 static int
880 gdc_load_palette(video_adapter_t *adp, u_char *palette)
881 {
882 #ifndef GDC_NOGRAPHICS
883     int i;
884
885     if (adp->va_info.vi_flags & V_INFO_VESA) {
886         gdc_wait_vsync();
887         for (i = 0; i < 256; ++i) {
888             outb(0xa8, i);
889             outb(0xac, *palette++);     /* R */
890             outb(0xaa, *palette++);     /* G */
891             outb(0xae, *palette++);     /* B */
892         }
893     } else {
894         /*
895          * XXX - Even though PC-98 text color is independent of palette,
896          * we should set palette in text mode.
897          * Because the background color of text mode is palette 0's one.
898          */
899         outb(0x6a, 1);          /* 16 colors mode */
900         bcopy(palette, b_palette, sizeof(b_palette));
901
902         gdc_wait_vsync();
903         for (i = 0; i < 16; ++i) {
904             outb(0xa8, i);
905             outb(0xac, *palette++ >> 4);        /* R */
906             outb(0xaa, *palette++ >> 4);        /* G */
907             outb(0xae, *palette++ >> 4);        /* B */
908         }
909     }
910 #endif
911     return 0;
912 }
913
914 static int
915 gdc_save_palette(video_adapter_t *adp, u_char *palette)
916 {
917 #ifndef GDC_NOGRAPHICS
918     int i;
919
920     if (adp->va_info.vi_flags & V_INFO_VESA) {
921         for (i = 0; i < 256; ++i) {
922             outb(0xa8, i);
923             *palette++ = inb(0xac);     /* R */
924             *palette++ = inb(0xaa);     /* G */
925             *palette++ = inb(0xae);     /* B */
926         }
927     } else {
928         bcopy(b_palette, palette, sizeof(b_palette));
929     }
930 #endif
931     return 0;
932 }
933
934 static int
935 gdc_set_origin(video_adapter_t *adp, off_t offset)
936 {
937 #ifndef GDC_NOGRAPHICS
938     if (adp->va_info.vi_flags & V_INFO_VESA) {
939         writew(BIOS_PADDRTOVADDR(0x000e0004), offset >> 15);
940     }
941 #endif
942     return 0;
943 }
944
945 /* entry points */
946
947 static int
948 gdc_err(video_adapter_t *adp, ...)
949 {
950     return ENODEV;
951 }
952
953 static int
954 gdc_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
955 {
956     probe_adapters();
957     if (unit >= 1)
958         return ENXIO;
959
960     *adpp = &biosadapter[unit];
961
962     return 0;
963 }
964
965 static int
966 gdc_init(int unit, video_adapter_t *adp, int flags)
967 {
968     if ((unit >= 1) || (adp == NULL) || !probe_done(adp))
969         return ENXIO;
970
971     if (!init_done(adp)) {
972         /* nothing to do really... */
973         adp->va_flags |= V_ADP_INITIALIZED;
974     }
975
976     if (!config_done(adp)) {
977         if (vid_register(adp) < 0)
978                 return ENXIO;
979         adp->va_flags |= V_ADP_REGISTERED;
980     }
981
982     return 0;
983 }
984
985 /*
986  * get_info():
987  * Return the video_info structure of the requested video mode.
988  */
989 static int
990 gdc_get_info(video_adapter_t *adp, int mode, video_info_t *info)
991 {
992     int i;
993
994     if (!gdc_init_done)
995         return ENXIO;
996
997     mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
998     for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
999         if (bios_vmode[i].vi_mode == NA)
1000             continue;
1001         if (mode == bios_vmode[i].vi_mode) {
1002             *info = bios_vmode[i];
1003             info->vi_buffer_size = info->vi_window_size*info->vi_planes;
1004             return 0;
1005         }
1006     }
1007     return EINVAL;
1008 }
1009
1010 /*
1011  * query_mode():
1012  * Find a video mode matching the requested parameters.
1013  * Fields filled with 0 are considered "don't care" fields and
1014  * match any modes.
1015  */
1016 static int
1017 gdc_query_mode(video_adapter_t *adp, video_info_t *info)
1018 {
1019     int i;
1020
1021     if (!gdc_init_done)
1022         return ENXIO;
1023
1024     for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1025         if (bios_vmode[i].vi_mode == NA)
1026             continue;
1027
1028         if ((info->vi_width != 0)
1029             && (info->vi_width != bios_vmode[i].vi_width))
1030                 continue;
1031         if ((info->vi_height != 0)
1032             && (info->vi_height != bios_vmode[i].vi_height))
1033                 continue;
1034         if ((info->vi_cwidth != 0)
1035             && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
1036                 continue;
1037         if ((info->vi_cheight != 0)
1038             && (info->vi_cheight != bios_vmode[i].vi_cheight))
1039                 continue;
1040         if ((info->vi_depth != 0)
1041             && (info->vi_depth != bios_vmode[i].vi_depth))
1042                 continue;
1043         if ((info->vi_planes != 0)
1044             && (info->vi_planes != bios_vmode[i].vi_planes))
1045                 continue;
1046         /* XXX: should check pixel format, memory model */
1047         if ((info->vi_flags != 0)
1048             && (info->vi_flags != bios_vmode[i].vi_flags))
1049                 continue;
1050
1051         /* verify if this mode is supported on this adapter */
1052         if (gdc_get_info(adp, bios_vmode[i].vi_mode, info))
1053                 continue;
1054         return 0;
1055     }
1056     return ENODEV;
1057 }
1058
1059 /*
1060  * set_mode():
1061  * Change the video mode.
1062  */
1063 static int
1064 gdc_set_mode(video_adapter_t *adp, int mode)
1065 {
1066     video_info_t info;
1067
1068     prologue(adp, V_ADP_MODECHANGE, ENODEV);
1069
1070     mode = map_gen_mode_num(adp->va_type, 
1071                             adp->va_flags & V_ADP_COLOR, mode);
1072     if (gdc_get_info(adp, mode, &info))
1073         return EINVAL;
1074
1075     switch (info.vi_mode) {
1076 #ifndef GDC_NOGRAPHICS
1077         case M_PC98_PEGC640x480:        /* PEGC 640x480 */
1078             initialize_gdc(T30_G480, info.vi_flags & V_INFO_GRAPHICS);
1079             break;
1080         case M_PC98_PEGC640x400:        /* PEGC 640x400 */
1081         case M_PC98_EGC640x400:         /* EGC GRAPHICS */
1082 #endif
1083         case M_PC98_80x25:              /* VGA TEXT */
1084             initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
1085             break;
1086         case M_PC98_80x30:              /* VGA TEXT */
1087             initialize_gdc(T30_G400, info.vi_flags & V_INFO_GRAPHICS);
1088             break;
1089         default:
1090             break;
1091     }
1092
1093 #ifndef GDC_NOGRAPHICS
1094     if (info.vi_flags & V_INFO_VESA) {
1095         outb(0x6a, 0x07);               /* enable mode F/F change */
1096         outb(0x6a, 0x21);               /* enhanced graphics */
1097         if (info.vi_height > 400)
1098             outb(0x6a, 0x69);           /* 800 lines */
1099         writeb(BIOS_PADDRTOVADDR(0x000e0100), 0);       /* packed pixel */
1100     } else {
1101         if (adp->va_flags & V_ADP_VESA) {
1102             outb(0x6a, 0x07);           /* enable mode F/F change */
1103             outb(0x6a, 0x20);           /* normal graphics */
1104             outb(0x6a, 0x68);           /* 400 lines */
1105         }
1106         outb(0x6a, 1);                  /* 16 colors */
1107     }
1108 #endif
1109
1110     adp->va_mode = mode;
1111     adp->va_flags &= ~V_ADP_COLOR;
1112     adp->va_flags |= 
1113         (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
1114 #if 0
1115     adp->va_crtc_addr =
1116         (adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
1117 #endif
1118     adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
1119     adp->va_window_size = info.vi_window_size;
1120     adp->va_window_gran = info.vi_window_gran;
1121     if (info.vi_buffer_size == 0) {
1122         adp->va_buffer = 0;
1123         adp->va_buffer_size = 0;
1124     } else {
1125         adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
1126         adp->va_buffer_size = info.vi_buffer_size;
1127     }
1128     if (info.vi_flags & V_INFO_GRAPHICS) {
1129         switch (info.vi_depth/info.vi_planes) {
1130         case 1:
1131             adp->va_line_width = info.vi_width/8;
1132             break;
1133         case 2:
1134             adp->va_line_width = info.vi_width/4;
1135             break;
1136         case 4:
1137             adp->va_line_width = info.vi_width/2;
1138             break;
1139         case 8:
1140         default: /* shouldn't happen */
1141             adp->va_line_width = info.vi_width;
1142             break;
1143         }
1144     } else {
1145         adp->va_line_width = info.vi_width;
1146     }
1147     bcopy(&info, &adp->va_info, sizeof(info));
1148
1149     /* move hardware cursor out of the way */
1150     vidd_set_hw_cursor(adp, -1, -1);
1151
1152     return 0;
1153 }
1154
1155 /*
1156  * set_border():
1157  * Change the border color.
1158  */
1159 static int
1160 gdc_set_border(video_adapter_t *adp, int color)
1161 {
1162     outb(0x6c, color << 4);                                                 
1163     return 0;
1164 }
1165
1166 /*
1167  * save_state():
1168  * Read video card register values.
1169  */
1170 static int
1171 gdc_save_state(video_adapter_t *adp, void *p, size_t size)
1172 {
1173     return ENODEV;
1174 }
1175
1176 /*
1177  * load_state():
1178  * Set video card registers at once.
1179  */
1180 static int
1181 gdc_load_state(video_adapter_t *adp, void *p)
1182 {
1183     return ENODEV;
1184 }
1185
1186 /*
1187  * read_hw_cursor():
1188  * Read the position of the hardware text cursor.
1189  */
1190 static int
1191 gdc_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
1192 {
1193     u_int16_t off;
1194     int s;
1195
1196     if (!gdc_init_done)
1197         return ENXIO;
1198
1199     if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
1200         return ENODEV;
1201
1202     s = spltty();
1203     master_gdc_cmd(0xe0);       /* _GDC_CSRR */
1204     while((inb(TEXT_GDC + 0) & 0x1) == 0) {}    /* GDC wait */
1205     off = inb(TEXT_GDC + 2);                    /* EADl */
1206     off |= (inb(TEXT_GDC + 2) << 8);            /* EADh */
1207     inb(TEXT_GDC + 2);                          /* dummy */
1208     inb(TEXT_GDC + 2);                          /* dummy */
1209     inb(TEXT_GDC + 2);                          /* dummy */
1210     splx(s);
1211
1212     if (off >= ROW*COL)
1213         off = 0;
1214     *row = off / adp->va_info.vi_width;
1215     *col = off % adp->va_info.vi_width;
1216
1217     return 0;
1218 }
1219
1220 /*
1221  * set_hw_cursor():
1222  * Move the hardware text cursor.  If col and row are both -1, 
1223  * the cursor won't be shown.
1224  */
1225 static int
1226 gdc_set_hw_cursor(video_adapter_t *adp, int col, int row)
1227 {
1228     u_int16_t off;
1229     int s;
1230
1231     if (!gdc_init_done)
1232         return ENXIO;
1233
1234     if ((col == -1) && (row == -1)) {
1235         off = -1;
1236     } else {
1237         if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
1238             return ENODEV;
1239         off = row*adp->va_info.vi_width + col;
1240     }
1241
1242     s = spltty();
1243     master_gdc_cmd(0x49);       /* _GDC_CSRW */
1244     master_gdc_word_prm(off);
1245     splx(s);
1246
1247     return 0;
1248 }
1249
1250 /*
1251  * set_hw_cursor_shape():
1252  * Change the shape of the hardware text cursor.  If the height is zero
1253  * or negative, the cursor won't be shown.
1254  */
1255 static int
1256 gdc_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
1257                         int celsize, int blink)
1258 {
1259     int start;
1260     int end;
1261     int s;
1262
1263     if (!gdc_init_done)
1264         return ENXIO;
1265
1266     start = celsize - (base + height);
1267     end = celsize - base - 1;
1268
1269 #if 0
1270     /*
1271      * muPD7220 GDC has anomaly that if end == celsize - 1 then start
1272      * must be 0, otherwise the cursor won't be correctly shown 
1273      * in the first row in the screen.  We shall set end to celsize - 2;
1274      * if end == celsize -1 && start > 0. XXX
1275      */
1276     if ((end == celsize - 1) && (start > 0) && (start < end))
1277         --end;
1278 #endif
1279
1280     s = spltty();
1281     master_gdc_cmd(0x4b);                       /* _GDC_CSRFORM */
1282     master_gdc_prm(((height > 0) ? 0x80 : 0)    /* cursor on/off */
1283         | ((celsize - 1) & 0x1f));              /* cel size */
1284     master_gdc_word_prm(((end & 0x1f) << 11)    /* end line */
1285         | (12 << 6)                             /* blink rate */
1286         | (blink ? 0 : 0x20)                    /* blink on/off */
1287         | (start & 0x1f));                      /* start line */
1288     splx(s);
1289
1290     return 0;
1291 }
1292
1293 /*
1294  * blank_display()
1295  * Put the display in power save/power off mode.
1296  */
1297 static int
1298 gdc_blank_display(video_adapter_t *adp, int mode)
1299 {
1300     int s;
1301     static int standby = 0;
1302
1303     if (!gdc_init_done)
1304         return ENXIO;
1305
1306     s = splhigh();
1307     switch (mode) {
1308     case V_DISPLAY_SUSPEND:
1309     case V_DISPLAY_STAND_BY:
1310         outb(0x09a2, 0x80 | 0x40);              /* V/H-SYNC mask */
1311         if (inb(0x09a2) == (0x80 | 0x40))
1312             standby = 1;
1313         /* FALLTHROUGH */
1314
1315     case V_DISPLAY_BLANK:
1316         while (!(inb(TEXT_GDC) & 0x20))         /* V-SYNC wait */
1317             ;
1318         outb(TEXT_GDC + 8, 0x0e);               /* DISP off */
1319         break;
1320
1321     case V_DISPLAY_ON:
1322         while (!(inb(TEXT_GDC) & 0x20))         /* V-SYNC wait */
1323             ;
1324         outb(TEXT_GDC + 8, 0x0f);               /* DISP on */
1325         if (standby) {
1326             outb(0x09a2, 0x00);                 /* V/H-SYNC unmask */
1327             standby = 0;
1328         }
1329         break;
1330     }
1331     splx(s);
1332     return 0;
1333 }
1334
1335 /*
1336  * mmap():
1337  * Mmap frame buffer.
1338  */
1339 static int
1340 gdc_mmap_buf(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr,
1341              int prot)
1342 {
1343     /* FIXME: is this correct? XXX */
1344     if (offset > VIDEO_BUF_SIZE - PAGE_SIZE)
1345         return -1;
1346     *paddr = adp->va_info.vi_window + offset;
1347     return 0;
1348 }
1349
1350 #ifndef GDC_NOGRAPHICS
1351 static void
1352 planar_fill(video_adapter_t *adp, int val)
1353 {
1354
1355     outb(0x7c, 0x80);                           /* GRCG on & TDW mode */
1356     outb(0x7e, 0);                              /* tile B */
1357     outb(0x7e, 0);                              /* tile R */
1358     outb(0x7e, 0);                              /* tile G */
1359     outb(0x7e, 0);                              /* tile I */
1360
1361     fillw_io(0, adp->va_window, 0x8000 / 2);    /* XXX */
1362
1363     outb(0x7c, 0);                              /* GRCG off */
1364 }
1365
1366 static void
1367 packed_fill(video_adapter_t *adp, int val)
1368 {
1369     int length;
1370     int at;                     /* position in the frame buffer */
1371     int l;
1372
1373     at = 0;
1374     length = adp->va_line_width*adp->va_info.vi_height;
1375     while (length > 0) {
1376         l = imin(length, adp->va_window_size);
1377         vidd_set_win_org(adp, at);
1378         bzero_io(adp->va_window, l);
1379         length -= l;
1380         at += l;
1381     }
1382 }
1383
1384 static int
1385 gdc_clear(video_adapter_t *adp)
1386 {
1387
1388     switch (adp->va_info.vi_mem_model) {
1389     case V_INFO_MM_TEXT:
1390         /* do nothing? XXX */
1391         break;
1392     case V_INFO_MM_PLANAR:
1393         planar_fill(adp, 0);
1394         break;
1395     case V_INFO_MM_PACKED:
1396         packed_fill(adp, 0);
1397         break;
1398     }
1399
1400     return 0;
1401 }
1402 #else /* GDC_NOGRAPHICS */
1403 static int
1404 gdc_clear(video_adapter_t *adp)
1405 {
1406
1407     return 0;
1408 }
1409 #endif /* GDC_NOGRAPHICS */
1410
1411 static int
1412 gdc_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
1413 {
1414     return ENODEV;
1415 }
1416
1417 static int
1418 gdc_bitblt(video_adapter_t *adp,...)
1419 {
1420     /* FIXME */
1421     return ENODEV;
1422 }
1423
1424 static int
1425 gdc_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
1426 {
1427     switch (cmd) {
1428     case FBIO_GETWINORG:        /* get frame buffer window origin */
1429         *(u_int *)arg = 0;
1430         return 0;
1431
1432     case FBIO_SETWINORG:        /* set frame buffer window origin */
1433     case FBIO_SETDISPSTART:     /* set display start address */
1434     case FBIO_SETLINEWIDTH:     /* set scan line length in pixel */
1435     case FBIO_GETPALETTE:       /* get color palette */
1436     case FBIO_SETPALETTE:       /* set color palette */
1437     case FBIOGETCMAP:           /* get color palette */
1438     case FBIOPUTCMAP:           /* set color palette */
1439         return ENODEV;
1440
1441     case FBIOGTYPE:             /* get frame buffer type info. */
1442         ((struct fbtype *)arg)->fb_type = fb_type(adp->va_type);
1443         ((struct fbtype *)arg)->fb_height = adp->va_info.vi_height;
1444         ((struct fbtype *)arg)->fb_width = adp->va_info.vi_width;
1445         ((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth;
1446         if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8))
1447             ((struct fbtype *)arg)->fb_cmsize = 0;
1448         else
1449             ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth;
1450         ((struct fbtype *)arg)->fb_size = adp->va_buffer_size;
1451         return 0;
1452
1453     default:
1454         return fb_commonioctl(adp, cmd, arg);
1455     }
1456 }
1457
1458 /*
1459  * diag():
1460  * Print some information about the video adapter and video modes,
1461  * with requested level of details.
1462  */
1463 static int
1464 gdc_diag(video_adapter_t *adp, int level)
1465 {
1466 #if defined(FB_DEBUG) && FB_DEBUG > 1
1467     int i;
1468 #endif
1469
1470     if (!gdc_init_done)
1471         return ENXIO;
1472
1473     fb_dump_adp_info(DRIVER_NAME, adp, level);
1474
1475 #if defined(FB_DEBUG) && FB_DEBUG > 1
1476     for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1477          if (bios_vmode[i].vi_mode == NA)
1478             continue;
1479          if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
1480             continue;
1481          fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
1482     }
1483 #endif
1484
1485     return 0;
1486 }