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