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