1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
29 /* All Rights Reserved */
30
31 #include <sys/errno.h>
32 #include <sys/types.h>
33 #include <sys/conf.h>
34 #include <sys/kmem.h>
35 #include <sys/visual_io.h>
36 #include <sys/font.h>
37 #include <sys/fbio.h>
38
39 #include <sys/ddi.h>
40 #include <sys/stat.h>
41 #include <sys/sunddi.h>
42 #include <sys/file.h>
43 #include <sys/open.h>
44 #include <sys/modctl.h>
45 #include <sys/vgareg.h>
46 #include <sys/vgasubr.h>
47 #include <sys/pci.h>
48 #include <sys/kd.h>
49 #include <sys/ddi_impldefs.h>
50 #include <sys/sunldi.h>
51
52 #define MYNAME "vgatext"
53
54 /*
55 * Each instance of this driver has 2 minor nodes:
56 * 0: for common graphics operations
57 * 1: for agpmaster operations
58 */
59 #define GFX_MINOR 0
60 #define AGPMASTER_MINOR 1
61
62 #define MY_NBITSMINOR 1
63 #define DEV2INST(dev) (getminor(dev) >> MY_NBITSMINOR)
64 #define DEV2MINOR(dev) (getminor(dev) & ((1 << MY_NBITSMINOR) - 1))
65 #define INST2NODE1(inst) ((inst) << MY_NBITSMINOR + GFX_MINOR)
66 #define INST2NODE2(inst) (((inst) << MY_NBITSMINOR) + AGPMASTER_MINOR)
67
68 /* I don't know exactly where these should be defined, but this is a */
69 /* heck of a lot better than constants in the code. */
70 #define TEXT_ROWS 25
71 #define TEXT_COLS 80
72
73 #define VGA_BRIGHT_WHITE 0x0f
74 #define VGA_BLACK 0x00
75
76 #define VGA_REG_ADDR 0x3c0
77 #define VGA_REG_SIZE 0x20
78
79 #define VGA_MEM_ADDR 0xa0000
80 #define VGA_MEM_SIZE 0x20000
81
82 #define VGA_MMAP_FB_BASE VGA_MEM_ADDR
83
84 /*
85 * This variable allows for this driver to suspend even if it
86 * shouldn't. Note that by setting it, the framebuffer will probably
87 * not come back. So use it with a serial console, or with serial
88 * line debugging (say, for example, if this driver is being modified
89 * to support _some_ hardware doing suspend and resume).
90 */
91 int vgatext_force_suspend = 0;
92
93 static int vgatext_open(dev_t *, int, int, cred_t *);
94 static int vgatext_close(dev_t, int, int, cred_t *);
95 static int vgatext_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
96 static int vgatext_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
97 size_t *, uint_t);
98
99 static struct cb_ops cb_vgatext_ops = {
100 vgatext_open, /* cb_open */
101 vgatext_close, /* cb_close */
102 nodev, /* cb_strategy */
103 nodev, /* cb_print */
104 nodev, /* cb_dump */
105 nodev, /* cb_read */
106 nodev, /* cb_write */
107 vgatext_ioctl, /* cb_ioctl */
108 vgatext_devmap, /* cb_devmap */
109 nodev, /* cb_mmap */
110 ddi_devmap_segmap, /* cb_segmap */
111 nochpoll, /* cb_chpoll */
112 ddi_prop_op, /* cb_prop_op */
113 0, /* cb_stream */
114 D_NEW | D_MTSAFE /* cb_flag */
115 };
116
117 static int vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
118 void **result);
119 static int vgatext_attach(dev_info_t *, ddi_attach_cmd_t);
120 static int vgatext_detach(dev_info_t *, ddi_detach_cmd_t);
121
122 static struct vis_identifier text_ident = { "SUNWtext" };
123
124 static struct dev_ops vgatext_ops = {
125 DEVO_REV, /* devo_rev */
126 0, /* devo_refcnt */
127 vgatext_info, /* devo_getinfo */
128 nulldev, /* devo_identify */
129 nulldev, /* devo_probe */
130 vgatext_attach, /* devo_attach */
131 vgatext_detach, /* devo_detach */
132 nodev, /* devo_reset */
133 &cb_vgatext_ops, /* devo_cb_ops */
134 (struct bus_ops *)NULL, /* devo_bus_ops */
135 NULL, /* power */
136 ddi_quiesce_not_needed, /* quiesce */
137 };
138
139 struct vgatext_softc {
140 struct vgaregmap regs;
141 struct vgaregmap fb;
142 off_t fb_size;
143 int fb_regno;
144 dev_info_t *devi;
145 int mode; /* KD_TEXT or KD_GRAPHICS */
146 caddr_t text_base; /* hardware text base */
147 char shadow[TEXT_ROWS*TEXT_COLS*2];
148 caddr_t current_base; /* hardware or shadow */
149 struct {
150 boolean_t visible;
151 int row;
152 int col;
153 } cursor;
154 struct vis_polledio polledio;
155 struct {
156 unsigned char red;
157 unsigned char green;
158 unsigned char blue;
159 } colormap[VGA8_CMAP_ENTRIES];
160 unsigned char attrib_palette[VGA_ATR_NUM_PLT];
161 unsigned int flags;
162 kmutex_t lock;
163 };
164
165 #define VGATEXT_FLAG_CONSOLE 0x00000001
166 #define VGATEXT_IS_CONSOLE(softc) ((softc)->flags & VGATEXT_FLAG_CONSOLE)
167
168 static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data);
169 static void vgatext_cons_copy(struct vgatext_softc *,
170 struct vis_conscopy *);
171 static void vgatext_cons_display(struct vgatext_softc *,
172 struct vis_consdisplay *);
173 static void vgatext_cons_cursor(struct vgatext_softc *,
174 struct vis_conscursor *);
175 static void vgatext_polled_copy(struct vis_polledio_arg *,
176 struct vis_conscopy *);
177 static void vgatext_polled_display(struct vis_polledio_arg *,
178 struct vis_consdisplay *);
179 static void vgatext_polled_cursor(struct vis_polledio_arg *,
180 struct vis_conscursor *);
181 static void vgatext_init(struct vgatext_softc *);
182 static void vgatext_set_text(struct vgatext_softc *);
183 #if defined(USE_BORDERS)
184 static void vgatext_init_graphics(struct vgatext_softc *);
185 #endif
186 static int vgatext_kdsetmode(struct vgatext_softc *softc, int mode);
187 static void vgatext_setfont(struct vgatext_softc *softc);
188 static void vgatext_get_cursor(struct vgatext_softc *softc,
189 screen_pos_t *row, screen_pos_t *col);
190 static void vgatext_set_cursor(struct vgatext_softc *softc, int row, int col);
191 static void vgatext_hide_cursor(struct vgatext_softc *softc);
192 static void vgatext_save_colormap(struct vgatext_softc *softc);
193 static void vgatext_restore_colormap(struct vgatext_softc *softc);
194 static int vgatext_get_pci_reg_index(dev_info_t *const devi,
195 unsigned long himask, unsigned long hival, unsigned long addr,
196 off_t *offset);
197 static int vgatext_get_isa_reg_index(dev_info_t *const devi,
198 unsigned long hival, unsigned long addr, off_t *offset);
199 static void *vgatext_softc_head;
200 static char vgatext_silent;
201 static char happyface_boot;
202
203 /* Loadable Driver stuff */
204
205 static struct modldrv modldrv = {
206 &mod_driverops, /* Type of module. This one is a driver */
207 "VGA text driver", /* Name of the module. */
208 &vgatext_ops, /* driver ops */
209 };
210
211 static struct modlinkage modlinkage = {
212 MODREV_1, (void *) &modldrv, NULL
213 };
214
215 typedef enum pc_colors {
216 pc_black = 0,
217 pc_blue = 1,
218 pc_green = 2,
219 pc_cyan = 3,
220 pc_red = 4,
221 pc_magenta = 5,
222 pc_brown = 6,
223 pc_white = 7,
224 pc_grey = 8,
225 pc_brt_blue = 9,
226 pc_brt_green = 10,
227 pc_brt_cyan = 11,
228 pc_brt_red = 12,
229 pc_brt_magenta = 13,
230 pc_yellow = 14,
231 pc_brt_white = 15
232 } pc_colors_t;
233
234 static const unsigned char solaris_color_to_pc_color[16] = {
235 pc_brt_white, /* 0 - brt_white */
236 pc_black, /* 1 - black */
237 pc_blue, /* 2 - blue */
238 pc_green, /* 3 - green */
239 pc_cyan, /* 4 - cyan */
240 pc_red, /* 5 - red */
241 pc_magenta, /* 6 - magenta */
242 pc_brown, /* 7 - brown */
243 pc_white, /* 8 - white */
244 pc_grey, /* 9 - gery */
245 pc_brt_blue, /* 10 - brt_blue */
246 pc_brt_green, /* 11 - brt_green */
247 pc_brt_cyan, /* 12 - brt_cyan */
248 pc_brt_red, /* 13 - brt_red */
249 pc_brt_magenta, /* 14 - brt_magenta */
250 pc_yellow /* 15 - yellow */
251 };
252
253 static ddi_device_acc_attr_t i8xx_dev_access = {
254 DDI_DEVICE_ATTR_V0,
255 DDI_NEVERSWAP_ACC,
256 DDI_STRICTORDER_ACC
257 };
258
259 static ddi_device_acc_attr_t dev_attr = {
260 DDI_DEVICE_ATTR_V0,
261 DDI_NEVERSWAP_ACC,
262 DDI_STRICTORDER_ACC,
263 };
264
265 int
_init(void)266 _init(void)
267 {
268 int e;
269
270 if ((e = ddi_soft_state_init(&vgatext_softc_head,
271 sizeof (struct vgatext_softc), 1)) != 0) {
272 return (e);
273 }
274
275 e = mod_install(&modlinkage);
276
277 if (e) {
278 ddi_soft_state_fini(&vgatext_softc_head);
279 }
280 return (e);
281 }
282
283 int
_fini(void)284 _fini(void)
285 {
286 int e;
287
288 if ((e = mod_remove(&modlinkage)) != 0)
289 return (e);
290
291 ddi_soft_state_fini(&vgatext_softc_head);
292
293 return (0);
294 }
295
296 int
_info(struct modinfo * modinfop)297 _info(struct modinfo *modinfop)
298 {
299 return (mod_info(&modlinkage, modinfop));
300 }
301
302 /* default structure for FBIOGATTR ioctl */
303 static struct fbgattr vgatext_attr = {
304 /* real_type owner */
305 FBTYPE_SUNFAST_COLOR, 0,
306 /* fbtype: type h w depth cms size */
307 { FBTYPE_SUNFAST_COLOR, TEXT_ROWS, TEXT_COLS, 1, 256, 0 },
308 /* fbsattr: flags emu_type dev_specific */
309 { 0, FBTYPE_SUN4COLOR, { 0 } },
310 /* emu_types */
311 { -1 }
312 };
313
314 /*
315 * handy macros
316 */
317
318 #define getsoftc(instance) ((struct vgatext_softc *) \
319 ddi_get_soft_state(vgatext_softc_head, (instance)))
320
321 #define STREQ(a, b) (strcmp((a), (b)) == 0)
322
323 /*
324 * NOTE: this function is duplicated here and in gfx_private/vgatext while
325 * we work on a set of commitable interfaces to sunpci.c.
326 *
327 * Use the class code to determine if the device is a PCI-to-PCI bridge.
328 * Returns: B_TRUE if the device is a bridge.
329 * B_FALSE if the device is not a bridge or the property cannot be
330 * retrieved.
331 */
332 static boolean_t
is_pci_bridge(dev_info_t * dip)333 is_pci_bridge(dev_info_t *dip)
334 {
335 uint32_t class_code;
336
337 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
338 DDI_PROP_DONTPASS, "class-code", 0xffffffff);
339
340 if (class_code == 0xffffffff || class_code == DDI_PROP_NOT_FOUND)
341 return (B_FALSE);
342
343 class_code &= 0x00ffff00;
344 if (class_code == ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8)))
345 return (B_TRUE);
346
347 return (B_FALSE);
348 }
349
350 static void
vgatext_check_for_console(dev_info_t * devi,struct vgatext_softc * softc,int pci_pcie_bus)351 vgatext_check_for_console(dev_info_t *devi, struct vgatext_softc *softc,
352 int pci_pcie_bus)
353 {
354 ddi_acc_handle_t pci_conf;
355 dev_info_t *pdevi;
356 uint16_t data16;
357
358 /*
359 * Based on Section 11.3, "PCI Display Subsystem Initialization",
360 * of the 1.1 PCI-to-PCI Bridge Architecture Specification
361 * determine if this is the boot console device. First, see
362 * if the SBIOS has turned on PCI I/O for this device. Then if
363 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set.
364 */
365
366 if (pci_config_setup(devi, &pci_conf) != DDI_SUCCESS) {
367 cmn_err(CE_WARN,
368 MYNAME ": can't get PCI conf handle");
369 return;
370 }
371
372 data16 = pci_config_get16(pci_conf, PCI_CONF_COMM);
373 if (data16 & PCI_COMM_IO)
374 softc->flags |= VGATEXT_FLAG_CONSOLE;
375
376 pci_config_teardown(&pci_conf);
377
378 /* If IO not enabled or ISA/EISA, just return */
379 if (!(softc->flags & VGATEXT_FLAG_CONSOLE) || !pci_pcie_bus)
380 return;
381
382 /*
383 * Check for VGA Enable in the Bridge Control register for all
384 * PCI/PCIEX parents. If not set all the way up the chain,
385 * this cannot be the boot console.
386 */
387
388 pdevi = devi;
389 while (pdevi = ddi_get_parent(pdevi)) {
390 int error;
391 ddi_acc_handle_t ppci_conf;
392 char *parent_type = NULL;
393
394 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, pdevi,
395 DDI_PROP_DONTPASS, "device_type", &parent_type);
396 if (error != DDI_SUCCESS) {
397 return;
398 }
399
400 /* Verify still on the PCI/PCIEX parent tree */
401 if (!STREQ(parent_type, "pci") &&
402 !STREQ(parent_type, "pciex")) {
403 ddi_prop_free(parent_type);
404 return;
405 }
406
407 ddi_prop_free(parent_type);
408 parent_type = NULL;
409
410 /* VGAEnable is set only for PCI-to-PCI bridges. */
411 if (is_pci_bridge(pdevi) == B_FALSE)
412 continue;
413
414 if (pci_config_setup(pdevi, &ppci_conf) != DDI_SUCCESS)
415 continue;
416
417 data16 = pci_config_get16(ppci_conf, PCI_BCNF_BCNTRL);
418 pci_config_teardown(&ppci_conf);
419
420 if (!(data16 & PCI_BCNF_BCNTRL_VGA_ENABLE)) {
421 softc->flags &= ~VGATEXT_FLAG_CONSOLE;
422 return;
423 }
424 }
425 }
426
427 static int
vgatext_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)428 vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
429 {
430 struct vgatext_softc *softc;
431 int unit = ddi_get_instance(devi);
432 int error;
433 char *parent_type = NULL;
434 int reg_rnumber;
435 off_t reg_offset;
436 off_t mem_offset;
437 char buf[80], *cons;
438 int pci_pcie_bus = 0;
439
440
441 switch (cmd) {
442 case DDI_ATTACH:
443 break;
444
445 case DDI_RESUME:
446 /*
447 * Though vgatext doesn't really know how to resume
448 * on a generic framebuffer, we should succeed, as
449 * it is far better to have no console, than potentiall
450 * have no machine.
451 */
452 return (DDI_SUCCESS);
453 default:
454 return (DDI_FAILURE);
455 }
456
457 /* DDI_ATTACH */
458
459 /* Allocate softc struct */
460 if (ddi_soft_state_zalloc(vgatext_softc_head, unit) != DDI_SUCCESS) {
461 return (DDI_FAILURE);
462 }
463 softc = getsoftc(unit);
464
465 /* link it in */
466 softc->devi = devi;
467 ddi_set_driver_private(devi, softc);
468
469 softc->polledio.arg = (struct vis_polledio_arg *)softc;
470 softc->polledio.display = vgatext_polled_display;
471 softc->polledio.copy = vgatext_polled_copy;
472 softc->polledio.cursor = vgatext_polled_cursor;
473
474 mutex_init(&(softc->lock), NULL, MUTEX_DRIVER, NULL);
475
476 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi),
477 DDI_PROP_DONTPASS, "device_type", &parent_type);
478 if (error != DDI_SUCCESS) {
479 cmn_err(CE_WARN, MYNAME ": can't determine parent type.");
480 goto fail;
481 }
482
483 if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) {
484 reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR,
485 ®_offset);
486 if (reg_rnumber < 0) {
487 cmn_err(CE_WARN,
488 MYNAME ": can't find reg entry for registers");
489 error = DDI_FAILURE;
490 goto fail;
491 }
492 softc->fb_regno = vgatext_get_isa_reg_index(devi, 0,
493 VGA_MEM_ADDR, &mem_offset);
494 if (softc->fb_regno < 0) {
495 cmn_err(CE_WARN,
496 MYNAME ": can't find reg entry for memory");
497 error = DDI_FAILURE;
498 goto fail;
499 }
500 } else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) {
501 pci_pcie_bus = 1;
502 reg_rnumber = vgatext_get_pci_reg_index(devi,
503 PCI_REG_ADDR_M|PCI_REG_REL_M,
504 PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
505 ®_offset);
506 if (reg_rnumber < 0) {
507 cmn_err(CE_WARN,
508 MYNAME ": can't find reg entry for registers");
509 error = DDI_FAILURE;
510 goto fail;
511 }
512 softc->fb_regno = vgatext_get_pci_reg_index(devi,
513 PCI_REG_ADDR_M|PCI_REG_REL_M,
514 PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
515 &mem_offset);
516 if (softc->fb_regno < 0) {
517 cmn_err(CE_WARN,
518 MYNAME ": can't find reg entry for memory");
519 error = DDI_FAILURE;
520 goto fail;
521 }
522 } else {
523 cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".",
524 parent_type);
525 error = DDI_FAILURE;
526 goto fail;
527 }
528 ddi_prop_free(parent_type);
529 parent_type = NULL;
530
531 error = ddi_regs_map_setup(devi, reg_rnumber,
532 (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
533 &dev_attr, &softc->regs.handle);
534 if (error != DDI_SUCCESS)
535 goto fail;
536 softc->regs.mapped = B_TRUE;
537
538 softc->fb_size = VGA_MEM_SIZE;
539
540 error = ddi_regs_map_setup(devi, softc->fb_regno,
541 (caddr_t *)&softc->fb.addr,
542 mem_offset, softc->fb_size,
543 &dev_attr, &softc->fb.handle);
544 if (error != DDI_SUCCESS)
545 goto fail;
546 softc->fb.mapped = B_TRUE;
547
548 if (ddi_get8(softc->regs.handle,
549 softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL)
550 softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE;
551 else
552 softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE;
553
554 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
555 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
556 if (strcmp(cons, "graphics") == 0) {
557 happyface_boot = 1;
558 vgatext_silent = 1;
559 softc->current_base = softc->shadow;
560 } else {
561 softc->current_base = softc->text_base;
562 }
563 ddi_prop_free(cons);
564 } else {
565 softc->current_base = softc->text_base;
566 }
567
568 (void) sprintf(buf, "text-%d", unit);
569 error = ddi_create_minor_node(devi, buf, S_IFCHR,
570 INST2NODE1(unit), DDI_NT_DISPLAY, NULL);
571 if (error != DDI_SUCCESS)
572 goto fail;
573
574 error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit),
575 devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0);
576 if (error != DDI_SUCCESS)
577 goto fail;
578
579 vgatext_check_for_console(devi, softc, pci_pcie_bus);
580
581 /* only do this if not in graphics mode */
582 if ((vgatext_silent == 0) && (VGATEXT_IS_CONSOLE(softc))) {
583 vgatext_init(softc);
584 vgatext_save_colormap(softc);
585 }
586
587 return (DDI_SUCCESS);
588
589 fail:
590 if (parent_type != NULL)
591 ddi_prop_free(parent_type);
592 (void) vgatext_detach(devi, DDI_DETACH);
593 return (error);
594 }
595
596 static int
vgatext_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)597 vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
598 {
599 int instance = ddi_get_instance(devi);
600 struct vgatext_softc *softc = getsoftc(instance);
601
602
603 switch (cmd) {
604 case DDI_DETACH:
605 if (softc->fb.mapped)
606 ddi_regs_map_free(&softc->fb.handle);
607 if (softc->regs.mapped)
608 ddi_regs_map_free(&softc->regs.handle);
609 mutex_destroy(&(softc->lock));
610 ddi_remove_minor_node(devi, NULL);
611 (void) ddi_soft_state_free(vgatext_softc_head, instance);
612 return (DDI_SUCCESS);
613
614 case DDI_SUSPEND:
615 /*
616 * This is a generic VGA file, and therefore, cannot
617 * understand how to deal with suspend and resume on
618 * a generic interface. So we fail any attempt to
619 * suspend. At some point in the future, we might use
620 * this as an entrypoint for display drivers and this
621 * assumption may change.
622 *
623 * However, from a platform development perspective,
624 * it is important that this driver suspend if a
625 * developer is using a serial console and/or working
626 * on a framebuffer driver that will support suspend
627 * and resume. Therefore, we have this module tunable
628 * (purposely using a long name) that will allow for
629 * suspend it it is set. Otherwise we fail.
630 */
631 if (vgatext_force_suspend != 0)
632 return (DDI_SUCCESS);
633 else
634 return (DDI_FAILURE);
635
636 default:
637 cmn_err(CE_WARN, "vgatext_detach: unknown cmd 0x%x\n", cmd);
638 return (DDI_FAILURE);
639 }
640 }
641
642 /*ARGSUSED*/
643 static int
vgatext_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)644 vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
645 {
646 dev_t dev;
647 int error;
648 int instance;
649 struct vgatext_softc *softc;
650
651 error = DDI_SUCCESS;
652
653 dev = (dev_t)arg;
654 instance = DEV2INST(dev);
655 softc = getsoftc(instance);
656
657 switch (infocmd) {
658 case DDI_INFO_DEVT2DEVINFO:
659 if (softc == NULL || softc->devi == NULL) {
660 error = DDI_FAILURE;
661 } else {
662 *result = (void *) softc->devi;
663 error = DDI_SUCCESS;
664 }
665 break;
666 case DDI_INFO_DEVT2INSTANCE:
667 *result = (void *)(uintptr_t)instance;
668 error = DDI_SUCCESS;
669 break;
670 default:
671 error = DDI_FAILURE;
672 break;
673 }
674 return (error);
675 }
676
677
678 /*ARGSUSED*/
679 static int
vgatext_open(dev_t * devp,int flag,int otyp,cred_t * cred)680 vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred)
681 {
682 struct vgatext_softc *softc = getsoftc(DEV2INST(*devp));
683
684 if (softc == NULL || otyp == OTYP_BLK)
685 return (ENXIO);
686
687 return (0);
688 }
689
690 /*ARGSUSED*/
691 static int
vgatext_close(dev_t devp,int flag,int otyp,cred_t * cred)692 vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred)
693 {
694 return (0);
695 }
696
697 static int
do_gfx_ioctl(int cmd,intptr_t data,int mode,struct vgatext_softc * softc)698 do_gfx_ioctl(int cmd, intptr_t data, int mode, struct vgatext_softc *softc)
699 {
700 static char kernel_only[] =
701 "do_gfx_ioctl: %s is a kernel only ioctl";
702 int err;
703 int kd_mode;
704
705 switch (cmd) {
706 case KDSETMODE:
707 return (vgatext_kdsetmode(softc, (int)data));
708
709 case KDGETMODE:
710 kd_mode = softc->mode;
711 if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode))
712 return (EFAULT);
713 break;
714
715 case VIS_GETIDENTIFIER:
716 if (ddi_copyout(&text_ident, (void *)data,
717 sizeof (struct vis_identifier), mode))
718 return (EFAULT);
719 break;
720
721 case VIS_DEVINIT:
722
723 if (!(mode & FKIOCTL)) {
724 cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT");
725 return (ENXIO);
726 }
727
728 err = vgatext_devinit(softc, (struct vis_devinit *)data);
729 if (err != 0) {
730 cmn_err(CE_WARN,
731 "vgatext_ioctl: could not initialize console");
732 return (err);
733 }
734 break;
735
736 case VIS_CONSCOPY: /* move */
737 {
738 struct vis_conscopy pma;
739
740 if (ddi_copyin((void *)data, &pma,
741 sizeof (struct vis_conscopy), mode))
742 return (EFAULT);
743
744 vgatext_cons_copy(softc, &pma);
745 break;
746 }
747
748 case VIS_CONSDISPLAY: /* display */
749 {
750 struct vis_consdisplay display_request;
751
752 if (ddi_copyin((void *)data, &display_request,
753 sizeof (display_request), mode))
754 return (EFAULT);
755
756 vgatext_cons_display(softc, &display_request);
757 break;
758 }
759
760 case VIS_CONSCURSOR:
761 {
762 struct vis_conscursor cursor_request;
763
764 if (ddi_copyin((void *)data, &cursor_request,
765 sizeof (cursor_request), mode))
766 return (EFAULT);
767
768 vgatext_cons_cursor(softc, &cursor_request);
769
770 if (cursor_request.action == VIS_GET_CURSOR &&
771 ddi_copyout(&cursor_request, (void *)data,
772 sizeof (cursor_request), mode))
773 return (EFAULT);
774 break;
775 }
776
777 case VIS_GETCMAP:
778 case VIS_PUTCMAP:
779 case FBIOPUTCMAP:
780 case FBIOGETCMAP:
781 /*
782 * At the moment, text mode is not considered to have
783 * a color map.
784 */
785 return (EINVAL);
786
787 case FBIOGATTR:
788 if (copyout(&vgatext_attr, (void *)data,
789 sizeof (struct fbgattr)))
790 return (EFAULT);
791 break;
792
793 case FBIOGTYPE:
794 if (copyout(&vgatext_attr.fbtype, (void *)data,
795 sizeof (struct fbtype)))
796 return (EFAULT);
797 break;
798
799 default:
800 return (ENXIO);
801 }
802 return (0);
803 }
804
805
806 /*ARGSUSED*/
807 static int
vgatext_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval)808 vgatext_ioctl(
809 dev_t dev,
810 int cmd,
811 intptr_t data,
812 int mode,
813 cred_t *cred,
814 int *rval)
815 {
816 struct vgatext_softc *softc = getsoftc(DEV2INST(dev));
817 int err;
818
819 switch (DEV2MINOR(dev)) {
820 case GFX_MINOR:
821 mutex_enter(&(softc->lock));
822 err = do_gfx_ioctl(cmd, data, mode, softc);
823 mutex_exit(&(softc->lock));
824 break;
825
826 case AGPMASTER_MINOR:
827 /*
828 * This is apparently not used anymore. Let's log a
829 * message so we'll know if some consumer shows up.
830 * If it turns out that we actually do need to keep
831 * support for this pass-through to agpmaster, it
832 * would probably be better to use "layered" access
833 * to the AGP device (ldi_open, ldi_ioctl, ldi_close)
834 */
835 cmn_err(CE_NOTE, "!vgatext wants agpmaster");
836 return (EBADF);
837
838 default:
839 /* not a valid minor node */
840 return (EBADF);
841 }
842 return (err);
843 }
844
845 static void
vgatext_save_text(struct vgatext_softc * softc)846 vgatext_save_text(struct vgatext_softc *softc)
847 {
848 unsigned i;
849
850 for (i = 0; i < sizeof (softc->shadow); i++)
851 softc->shadow[i] = softc->current_base[i];
852 }
853
854 static void
vgatext_progressbar_stop()855 vgatext_progressbar_stop()
856 {
857 extern void progressbar_stop(void);
858
859 if (vgatext_silent == 1) {
860 vgatext_silent = 0;
861 progressbar_stop();
862 }
863 }
864
865 static void
vgatext_kdsettext(struct vgatext_softc * softc)866 vgatext_kdsettext(struct vgatext_softc *softc)
867 {
868 int i;
869
870 vgatext_init(softc);
871 for (i = 0; i < sizeof (softc->shadow); i++) {
872 softc->text_base[i] = softc->shadow[i];
873 }
874 softc->current_base = softc->text_base;
875 if (softc->cursor.visible) {
876 vgatext_set_cursor(softc,
877 softc->cursor.row, softc->cursor.col);
878 }
879 vgatext_restore_colormap(softc);
880 }
881
882 static void
vgatext_kdsetgraphics(struct vgatext_softc * softc)883 vgatext_kdsetgraphics(struct vgatext_softc *softc)
884 {
885 vgatext_progressbar_stop();
886 vgatext_save_text(softc);
887 softc->current_base = softc->shadow;
888 #if defined(USE_BORDERS)
889 vgatext_init_graphics(softc);
890 #endif
891 }
892
893 static int
vgatext_kdsetmode(struct vgatext_softc * softc,int mode)894 vgatext_kdsetmode(struct vgatext_softc *softc, int mode)
895 {
896 if ((mode == softc->mode) || (!VGATEXT_IS_CONSOLE(softc)))
897 return (0);
898
899 switch (mode) {
900 case KD_TEXT:
901 vgatext_kdsettext(softc);
902 break;
903
904 case KD_GRAPHICS:
905 vgatext_kdsetgraphics(softc);
906 break;
907
908 case KD_RESETTEXT:
909 /*
910 * In order to avoid racing with a starting X server,
911 * this needs to be a test and set that is performed in
912 * a single (softc->lock protected) ioctl into this driver.
913 */
914 if (softc->mode == KD_TEXT && vgatext_silent == 1) {
915 vgatext_progressbar_stop();
916 vgatext_kdsettext(softc);
917 }
918 break;
919
920 default:
921 return (EINVAL);
922 }
923 softc->mode = mode;
924 return (0);
925 }
926
927 /*ARGSUSED*/
928 static int
vgatext_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)929 vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
930 size_t *maplen, uint_t model)
931 {
932 struct vgatext_softc *softc;
933 int err;
934 size_t length;
935
936
937 softc = getsoftc(DEV2INST(dev));
938 if (softc == NULL) {
939 cmn_err(CE_WARN, "vgatext: Can't find softstate");
940 return (-1);
941 }
942
943 if (!(off >= VGA_MMAP_FB_BASE &&
944 off < VGA_MMAP_FB_BASE + softc->fb_size)) {
945 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off);
946 return (-1);
947 }
948
949 if (off + len > VGA_MMAP_FB_BASE + softc->fb_size)
950 length = VGA_MMAP_FB_BASE + softc->fb_size - off;
951 else
952 length = len;
953
954 if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno,
955 off - VGA_MMAP_FB_BASE,
956 length, PROT_ALL, 0, &dev_attr)) < 0) {
957 return (err);
958 }
959
960
961 *maplen = length;
962 return (0);
963 }
964
965
966 static int
vgatext_devinit(struct vgatext_softc * softc,struct vis_devinit * data)967 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data)
968 {
969 /* initialize console instance */
970 data->version = VIS_CONS_REV;
971 data->width = TEXT_COLS;
972 data->height = TEXT_ROWS;
973 data->linebytes = TEXT_COLS;
974 data->depth = 4;
975 data->mode = VIS_TEXT;
976 data->polledio = &softc->polledio;
977
978 return (0);
979 }
980
981 /*
982 * display a string on the screen at (row, col)
983 * assume it has been cropped to fit.
984 */
985
986 static void
vgatext_cons_display(struct vgatext_softc * softc,struct vis_consdisplay * da)987 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da)
988 {
989 unsigned char *string;
990 int i;
991 unsigned char attr;
992 struct cgatext {
993 unsigned char ch;
994 unsigned char attr;
995 };
996 struct cgatext *addr;
997
998 /*
999 * Sanity checks. This is a last-ditch effort to avoid damage
1000 * from brokenness or maliciousness above.
1001 */
1002 if (da->row < 0 || da->row >= TEXT_ROWS ||
1003 da->col < 0 || da->col >= TEXT_COLS ||
1004 da->col + da->width > TEXT_COLS)
1005 return;
1006
1007 /*
1008 * To be fully general, we should copyin the data. This is not
1009 * really relevant for this text-only driver, but a graphical driver
1010 * should support these ioctls from userland to enable simple
1011 * system startup graphics.
1012 */
1013 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4)
1014 | solaris_color_to_pc_color[da->fg_color & 0xf];
1015 string = da->data;
1016 addr = (struct cgatext *)softc->current_base
1017 + (da->row * TEXT_COLS + da->col);
1018 for (i = 0; i < da->width; i++) {
1019 addr->ch = string[i];
1020 addr->attr = attr;
1021 addr++;
1022 }
1023 }
1024
1025 static void
vgatext_polled_display(struct vis_polledio_arg * arg,struct vis_consdisplay * da)1026 vgatext_polled_display(
1027 struct vis_polledio_arg *arg,
1028 struct vis_consdisplay *da)
1029 {
1030 vgatext_cons_display((struct vgatext_softc *)arg, da);
1031 }
1032
1033 /*
1034 * screen-to-screen copy
1035 */
1036
1037 static void
vgatext_cons_copy(struct vgatext_softc * softc,struct vis_conscopy * ma)1038 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma)
1039 {
1040 unsigned short *from;
1041 unsigned short *to;
1042 int cnt;
1043 screen_size_t chars_per_row;
1044 unsigned short *to_row_start;
1045 unsigned short *from_row_start;
1046 screen_size_t rows_to_move;
1047 unsigned short *base;
1048
1049 /*
1050 * Sanity checks. Note that this is a last-ditch effort to avoid
1051 * damage caused by broken-ness or maliciousness above.
1052 */
1053 if (ma->s_col < 0 || ma->s_col >= TEXT_COLS ||
1054 ma->s_row < 0 || ma->s_row >= TEXT_ROWS ||
1055 ma->e_col < 0 || ma->e_col >= TEXT_COLS ||
1056 ma->e_row < 0 || ma->e_row >= TEXT_ROWS ||
1057 ma->t_col < 0 || ma->t_col >= TEXT_COLS ||
1058 ma->t_row < 0 || ma->t_row >= TEXT_ROWS ||
1059 ma->s_col > ma->e_col ||
1060 ma->s_row > ma->e_row)
1061 return;
1062
1063 /*
1064 * Remember we're going to copy shorts because each
1065 * character/attribute pair is 16 bits.
1066 */
1067 chars_per_row = ma->e_col - ma->s_col + 1;
1068 rows_to_move = ma->e_row - ma->s_row + 1;
1069
1070 /* More sanity checks. */
1071 if (ma->t_row + rows_to_move > TEXT_ROWS ||
1072 ma->t_col + chars_per_row > TEXT_COLS)
1073 return;
1074
1075 base = (unsigned short *)softc->current_base;
1076
1077 to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col);
1078 from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col);
1079
1080 if (to_row_start < from_row_start) {
1081 while (rows_to_move-- > 0) {
1082 to = to_row_start;
1083 from = from_row_start;
1084 to_row_start += TEXT_COLS;
1085 from_row_start += TEXT_COLS;
1086 for (cnt = chars_per_row; cnt-- > 0; )
1087 *to++ = *from++;
1088 }
1089 } else {
1090 /*
1091 * Offset to the end of the region and copy backwards.
1092 */
1093 cnt = rows_to_move * TEXT_COLS + chars_per_row;
1094 to_row_start += cnt;
1095 from_row_start += cnt;
1096
1097 while (rows_to_move-- > 0) {
1098 to_row_start -= TEXT_COLS;
1099 from_row_start -= TEXT_COLS;
1100 to = to_row_start;
1101 from = from_row_start;
1102 for (cnt = chars_per_row; cnt-- > 0; )
1103 *--to = *--from;
1104 }
1105 }
1106 }
1107
1108 static void
vgatext_polled_copy(struct vis_polledio_arg * arg,struct vis_conscopy * ca)1109 vgatext_polled_copy(
1110 struct vis_polledio_arg *arg,
1111 struct vis_conscopy *ca)
1112 {
1113 vgatext_cons_copy((struct vgatext_softc *)arg, ca);
1114 }
1115
1116
1117 static void
vgatext_cons_cursor(struct vgatext_softc * softc,struct vis_conscursor * ca)1118 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca)
1119 {
1120 if (vgatext_silent)
1121 return;
1122
1123 switch (ca->action) {
1124 case VIS_HIDE_CURSOR:
1125 softc->cursor.visible = B_FALSE;
1126 if (softc->current_base == softc->text_base)
1127 vgatext_hide_cursor(softc);
1128 break;
1129 case VIS_DISPLAY_CURSOR:
1130 /*
1131 * Sanity check. This is a last-ditch effort to avoid
1132 * damage from brokenness or maliciousness above.
1133 */
1134 if (ca->col < 0 || ca->col >= TEXT_COLS ||
1135 ca->row < 0 || ca->row >= TEXT_ROWS)
1136 return;
1137
1138 softc->cursor.visible = B_TRUE;
1139 softc->cursor.col = ca->col;
1140 softc->cursor.row = ca->row;
1141 if (softc->current_base == softc->text_base)
1142 vgatext_set_cursor(softc, ca->row, ca->col);
1143 break;
1144 case VIS_GET_CURSOR:
1145 if (softc->current_base == softc->text_base) {
1146 vgatext_get_cursor(softc, &ca->row, &ca->col);
1147 }
1148 break;
1149 }
1150 }
1151
1152 static void
vgatext_polled_cursor(struct vis_polledio_arg * arg,struct vis_conscursor * ca)1153 vgatext_polled_cursor(
1154 struct vis_polledio_arg *arg,
1155 struct vis_conscursor *ca)
1156 {
1157 vgatext_cons_cursor((struct vgatext_softc *)arg, ca);
1158 }
1159
1160
1161
1162 /*ARGSUSED*/
1163 static void
vgatext_hide_cursor(struct vgatext_softc * softc)1164 vgatext_hide_cursor(struct vgatext_softc *softc)
1165 {
1166 /* Nothing at present */
1167 }
1168
1169 static void
vgatext_set_cursor(struct vgatext_softc * softc,int row,int col)1170 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col)
1171 {
1172 short addr;
1173
1174 if (vgatext_silent)
1175 return;
1176
1177 addr = row * TEXT_COLS + col;
1178
1179 vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8);
1180 vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff);
1181 }
1182
1183 static int vga_row, vga_col;
1184
1185 static void
vgatext_get_cursor(struct vgatext_softc * softc,screen_pos_t * row,screen_pos_t * col)1186 vgatext_get_cursor(struct vgatext_softc *softc,
1187 screen_pos_t *row, screen_pos_t *col)
1188 {
1189 short addr;
1190
1191 addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) +
1192 vga_get_crtc(&softc->regs, VGA_CRTC_CLAL);
1193
1194 vga_row = *row = addr / TEXT_COLS;
1195 vga_col = *col = addr % TEXT_COLS;
1196 }
1197
1198 /*
1199 * This code is experimental. It's only enabled if console is
1200 * set to graphics, a preliminary implementation of happyface boot.
1201 */
1202 static void
vgatext_set_text(struct vgatext_softc * softc)1203 vgatext_set_text(struct vgatext_softc *softc)
1204 {
1205 int i;
1206
1207 if (happyface_boot == 0)
1208 return;
1209
1210 /* we are in graphics mode, set to text 80X25 mode */
1211
1212 /* set misc registers */
1213 vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT);
1214
1215 /* set sequencer registers */
1216 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1217 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) &
1218 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1219 for (i = 1; i < NUM_SEQ_REG; i++) {
1220 vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]);
1221 }
1222 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1223 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) |
1224 VGA_SEQ_RST_SYN_NO_ASYNC_RESET |
1225 VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1226
1227 /* set crt controller registers */
1228 vga_set_crtc(&softc->regs, VGA_CRTC_VRE,
1229 (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) &
1230 ~VGA_CRTC_VRE_LOCK));
1231 for (i = 0; i < NUM_CRTC_REG; i++) {
1232 vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]);
1233 }
1234
1235 /* set graphics controller registers */
1236 for (i = 0; i < NUM_GRC_REG; i++) {
1237 vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]);
1238 }
1239
1240 /* set attribute registers */
1241 for (i = 0; i < NUM_ATR_REG; i++) {
1242 vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]);
1243 }
1244
1245 /* set palette */
1246 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) {
1247 vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2,
1248 VGA_TEXT_PALETTES[i][1] << 2,
1249 VGA_TEXT_PALETTES[i][2] << 2);
1250 }
1251 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) {
1252 vga_put_cmap(&softc->regs, i, 0, 0, 0);
1253 }
1254
1255 vgatext_save_colormap(softc);
1256 }
1257
1258 static void
vgatext_init(struct vgatext_softc * softc)1259 vgatext_init(struct vgatext_softc *softc)
1260 {
1261 unsigned char atr_mode;
1262
1263 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1264 if (atr_mode & VGA_ATR_MODE_GRAPH)
1265 vgatext_set_text(softc);
1266 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1267 atr_mode &= ~VGA_ATR_MODE_BLINK;
1268 atr_mode &= ~VGA_ATR_MODE_9WIDE;
1269 vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode);
1270 #if defined(USE_BORDERS)
1271 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1272 vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE));
1273 #else
1274 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1275 vga_get_atr(&softc->regs, VGA_BLACK));
1276 #endif
1277 vgatext_setfont(softc); /* need selectable font? */
1278 }
1279
1280 #if defined(USE_BORDERS)
1281 static void
vgatext_init_graphics(struct vgatext_softc * softc)1282 vgatext_init_graphics(struct vgatext_softc *softc)
1283 {
1284 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1285 vga_get_atr(&softc->regs, VGA_BLACK));
1286 }
1287 #endif
1288
1289 static char vga_fontslot = 0;
1290
1291 static void
vgatext_setfont(struct vgatext_softc * softc)1292 vgatext_setfont(struct vgatext_softc *softc)
1293 {
1294 static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f};
1295
1296 extern unsigned char *ENCODINGS[];
1297 uchar_t *from;
1298 uchar_t volatile *to;
1299 int i, j, s;
1300 int bpc, f_offset;
1301
1302 /* Sync-reset the sequencer registers */
1303 vga_set_seq(&softc->regs, 0x00, 0x01);
1304 /*
1305 * enable write to plane2, since fonts
1306 * could only be loaded into plane2
1307 */
1308 vga_set_seq(&softc->regs, 0x02, 0x04);
1309 /*
1310 * sequentially access data in the bit map being
1311 * selected by MapMask register (index 0x02)
1312 */
1313 vga_set_seq(&softc->regs, 0x04, 0x07);
1314 /* Sync-reset ended, and allow the sequencer to operate */
1315 vga_set_seq(&softc->regs, 0x00, 0x03);
1316
1317 /*
1318 * select plane 2 on Read Mode 0
1319 */
1320 vga_set_grc(&softc->regs, 0x04, 0x02);
1321 /*
1322 * system addresses sequentially access data, follow
1323 * Memory Mode register bit 2 in the sequencer
1324 */
1325 vga_set_grc(&softc->regs, 0x05, 0x00);
1326 /*
1327 * set range of host memory addresses decoded by VGA
1328 * hardware -- A0000h-BFFFFh (128K region)
1329 */
1330 vga_set_grc(&softc->regs, 0x06, 0x00);
1331
1332 /*
1333 * This assumes 8x16 characters, which yield the traditional 80x25
1334 * screen. It really should support other character heights.
1335 */
1336 bpc = 16;
1337 s = vga_fontslot;
1338 f_offset = s * 8 * 1024;
1339 for (i = 0; i < 256; i++) {
1340 from = ENCODINGS[i];
1341 to = (unsigned char *)softc->fb.addr + f_offset + i * 0x20;
1342 for (j = 0; j < bpc; j++)
1343 *to++ = *from++;
1344 }
1345
1346 /* Sync-reset the sequencer registers */
1347 vga_set_seq(&softc->regs, 0x00, 0x01);
1348 /* enable write to plane 0 and 1 */
1349 vga_set_seq(&softc->regs, 0x02, 0x03);
1350 /*
1351 * enable character map selection
1352 * and odd/even addressing
1353 */
1354 vga_set_seq(&softc->regs, 0x04, 0x03);
1355 /*
1356 * select font map
1357 */
1358 vga_set_seq(&softc->regs, 0x03, fsreg[s]);
1359 /* Sync-reset ended, and allow the sequencer to operate */
1360 vga_set_seq(&softc->regs, 0x00, 0x03);
1361
1362 /* restore graphic registers */
1363
1364 /* select plane 0 */
1365 vga_set_grc(&softc->regs, 0x04, 0x00);
1366 /* enable odd/even addressing mode */
1367 vga_set_grc(&softc->regs, 0x05, 0x10);
1368 /*
1369 * range of host memory addresses decoded by VGA
1370 * hardware -- B8000h-BFFFFh (32K region)
1371 */
1372 vga_set_grc(&softc->regs, 0x06, 0x0e);
1373 /* enable all color plane */
1374 vga_set_atr(&softc->regs, 0x12, 0x0f);
1375
1376 }
1377
1378 static void
vgatext_save_colormap(struct vgatext_softc * softc)1379 vgatext_save_colormap(struct vgatext_softc *softc)
1380 {
1381 int i;
1382
1383 for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1384 softc->attrib_palette[i] = vga_get_atr(&softc->regs, i);
1385 }
1386 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1387 vga_get_cmap(&softc->regs, i,
1388 &softc->colormap[i].red,
1389 &softc->colormap[i].green,
1390 &softc->colormap[i].blue);
1391 }
1392 }
1393
1394 static void
vgatext_restore_colormap(struct vgatext_softc * softc)1395 vgatext_restore_colormap(struct vgatext_softc *softc)
1396 {
1397 int i;
1398
1399 for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1400 vga_set_atr(&softc->regs, i, softc->attrib_palette[i]);
1401 }
1402 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1403 vga_put_cmap(&softc->regs, i,
1404 softc->colormap[i].red,
1405 softc->colormap[i].green,
1406 softc->colormap[i].blue);
1407 }
1408 }
1409
1410 /*
1411 * search the entries of the "reg" property for one which has the desired
1412 * combination of phys_hi bits and contains the desired address.
1413 *
1414 * This version searches a PCI-style "reg" property. It was prompted by
1415 * issues surrounding the presence or absence of an entry for the ROM:
1416 * (a) a transition problem with PowerPC Virtual Open Firmware
1417 * (b) uncertainty as to whether an entry will be included on a device
1418 * with ROM support (and so an "active" ROM base address register),
1419 * but no ROM actually installed.
1420 *
1421 * See the note below on vgatext_get_isa_reg_index for the reasons for
1422 * returning the offset.
1423 *
1424 * Note that this routine may not be fully general; it is intended for the
1425 * specific purpose of finding a couple of particular VGA reg entries and
1426 * may not be suitable for all reg-searching purposes.
1427 */
1428 static int
vgatext_get_pci_reg_index(dev_info_t * const devi,unsigned long himask,unsigned long hival,unsigned long addr,off_t * offset)1429 vgatext_get_pci_reg_index(
1430 dev_info_t *const devi,
1431 unsigned long himask,
1432 unsigned long hival,
1433 unsigned long addr,
1434 off_t *offset)
1435 {
1436
1437 int length, index;
1438 pci_regspec_t *reg;
1439
1440 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1441 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
1442 return (-1);
1443 }
1444
1445 for (index = 0; index < length / sizeof (pci_regspec_t); index++) {
1446 if ((reg[index].pci_phys_hi & himask) != hival)
1447 continue;
1448 if (reg[index].pci_size_hi != 0)
1449 continue;
1450 if (reg[index].pci_phys_mid != 0)
1451 continue;
1452 if (reg[index].pci_phys_low > addr)
1453 continue;
1454 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr)
1455 continue;
1456
1457 *offset = addr - reg[index].pci_phys_low;
1458 kmem_free(reg, (size_t)length);
1459 return (index);
1460 }
1461 kmem_free(reg, (size_t)length);
1462
1463 return (-1);
1464 }
1465
1466 /*
1467 * search the entries of the "reg" property for one which has the desired
1468 * combination of phys_hi bits and contains the desired address.
1469 *
1470 * This version searches a ISA-style "reg" property. It was prompted by
1471 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions,
1472 * 8514/A registers should have been added after all standard VGA registers.
1473 * Unfortunately, the Solaris/Intel device configuration framework
1474 * (a) lists the 8514/A registers before the video memory, and then
1475 * (b) also sorts the entries so that I/O entries come before memory
1476 * entries.
1477 *
1478 * It returns the "reg" index and offset into that register set.
1479 * The offset is needed because there exist (broken?) BIOSes that
1480 * report larger ranges enclosing the standard ranges. One reports
1481 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the
1482 * offset adjusts for this difference in the base of the register set.
1483 *
1484 * Note that this routine may not be fully general; it is intended for the
1485 * specific purpose of finding a couple of particular VGA reg entries and
1486 * may not be suitable for all reg-searching purposes.
1487 */
1488 static int
vgatext_get_isa_reg_index(dev_info_t * const devi,unsigned long hival,unsigned long addr,off_t * offset)1489 vgatext_get_isa_reg_index(
1490 dev_info_t *const devi,
1491 unsigned long hival,
1492 unsigned long addr,
1493 off_t *offset)
1494 {
1495
1496 int length, index;
1497 struct regspec *reg;
1498
1499 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1500 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
1501 return (-1);
1502 }
1503
1504 for (index = 0; index < length / sizeof (struct regspec); index++) {
1505 if (reg[index].regspec_bustype != hival)
1506 continue;
1507 if (reg[index].regspec_addr > addr)
1508 continue;
1509 if (reg[index].regspec_addr + reg[index].regspec_size <= addr)
1510 continue;
1511
1512 *offset = addr - reg[index].regspec_addr;
1513 kmem_free(reg, (size_t)length);
1514 return (index);
1515 }
1516 kmem_free(reg, (size_t)length);
1517
1518 return (-1);
1519 }
1520