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 #include <sys/ddi.h>
39 #include <sys/stat.h>
40 #include <sys/sunddi.h>
41 #include <sys/file.h>
42 #include <sys/open.h>
43 #include <sys/modctl.h>
44 #include <sys/vgareg.h>
45 #include <sys/vgasubr.h>
46 #include <sys/pci.h>
47 #include <sys/kd.h>
48 #include <sys/ddi_impldefs.h>
49
50 #include "gfx_private.h"
51
52 #define MYNAME "gfxp_vgatext"
53
54 #define TEXT_ROWS 25
55 #define TEXT_COLS 80
56
57 #define VGA_BRIGHT_WHITE 0x0f
58 #define VGA_BLACK 0x00
59
60 #define VGA_REG_ADDR 0x3c0
61 #define VGA_REG_SIZE 0x20
62
63 #define VGA_MEM_ADDR 0xa0000
64 #define VGA_MEM_SIZE 0x20000
65
66 #define VGA_MMAP_FB_BASE VGA_MEM_ADDR
67
68 struct vgatext_softc {
69 struct vgaregmap regs;
70 struct vgaregmap fb;
71 off_t fb_size;
72 int fb_regno;
73 dev_info_t *devi;
74 int mode; /* KD_TEXT or KD_GRAPHICS */
75 caddr_t text_base; /* hardware text base */
76 char shadow[TEXT_ROWS*TEXT_COLS*2];
77 caddr_t current_base; /* hardware or shadow */
78 struct {
79 boolean_t visible;
80 int row;
81 int col;
82 } cursor;
83 struct vis_polledio polledio;
84 struct {
85 unsigned char red;
86 unsigned char green;
87 unsigned char blue;
88 } colormap[VGA8_CMAP_ENTRIES];
89 unsigned char attrib_palette[VGA_ATR_NUM_PLT];
90 unsigned int flags;
91 kmutex_t lock;
92 };
93
94 typedef enum pc_colors {
95 pc_black = 0,
96 pc_blue = 1,
97 pc_green = 2,
98 pc_cyan = 3,
99 pc_red = 4,
100 pc_magenta = 5,
101 pc_brown = 6,
102 pc_white = 7,
103 pc_grey = 8,
104 pc_brt_blue = 9,
105 pc_brt_green = 10,
106 pc_brt_cyan = 11,
107 pc_brt_red = 12,
108 pc_brt_magenta = 13,
109 pc_yellow = 14,
110 pc_brt_white = 15
111 } pc_colors_t;
112
113 static const unsigned char solaris_color_to_pc_color[16] = {
114 pc_brt_white, /* 0 - brt_white */
115 pc_black, /* 1 - black */
116 pc_blue, /* 2 - blue */
117 pc_green, /* 3 - green */
118 pc_cyan, /* 4 - cyan */
119 pc_red, /* 5 - red */
120 pc_magenta, /* 6 - magenta */
121 pc_brown, /* 7 - brown */
122 pc_white, /* 8 - white */
123 pc_grey, /* 9 - gery */
124 pc_brt_blue, /* 10 - brt_blue */
125 pc_brt_green, /* 11 - brt_green */
126 pc_brt_cyan, /* 12 - brt_cyan */
127 pc_brt_red, /* 13 - brt_red */
128 pc_brt_magenta, /* 14 - brt_magenta */
129 pc_yellow /* 15 - yellow */
130 };
131
132 static ddi_device_acc_attr_t dev_attr = {
133 DDI_DEVICE_ATTR_V0,
134 DDI_NEVERSWAP_ACC,
135 DDI_STRICTORDER_ACC,
136 };
137
138 /* default structure for FBIOGATTR ioctl */
139 static struct fbgattr vgatext_attr = {
140 /* real_type owner */
141 FBTYPE_SUNFAST_COLOR, 0,
142 /* fbtype: type h w depth cms size */
143 { FBTYPE_SUNFAST_COLOR, TEXT_ROWS, TEXT_COLS, 1, 256, 0 },
144 /* fbsattr: flags emu_type dev_specific */
145 { 0, FBTYPE_SUN4COLOR, { 0 } },
146 /* emu_types */
147 { -1 }
148 };
149
150 #define GFXP_FLAG_CONSOLE 0x00000001
151 #define GFXP_IS_CONSOLE(softc) ((softc)->flags & GFXP_FLAG_CONSOLE)
152
153 /*
154 * Global name used to write the softc pointer in, for the
155 * data wrapper vgatext_return_pointers()
156 */
157
158
159 int gfxp_vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd,
160 gfxp_vgatext_softc_ptr_t ptr);
161 static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data);
162 static void vgatext_cons_copy(struct vgatext_softc *,
163 struct vis_conscopy *);
164 static void vgatext_cons_display(struct vgatext_softc *,
165 struct vis_consdisplay *);
166 static void vgatext_cons_cursor(struct vgatext_softc *,
167 struct vis_conscursor *);
168 static void vgatext_polled_copy(struct vis_polledio_arg *,
169 struct vis_conscopy *);
170 static void vgatext_polled_display(struct vis_polledio_arg *,
171 struct vis_consdisplay *);
172 static void vgatext_polled_cursor(struct vis_polledio_arg *,
173 struct vis_conscursor *);
174 static void vgatext_init(struct vgatext_softc *);
175 static void vgatext_set_text(struct vgatext_softc *);
176
177 static void vgatext_save_text(struct vgatext_softc *softc);
178 static void vgatext_restore_textmode(struct vgatext_softc *softc);
179 static int vgatext_suspend(struct vgatext_softc *softc);
180 static void vgatext_resume(struct vgatext_softc *softc);
181
182 #if defined(USE_BORDERS)
183 static void vgatext_init_graphics(struct vgatext_softc *);
184 #endif
185
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
200 static char vgatext_silent;
201 static char happyface_boot;
202
203 gfxp_vgatext_softc_ptr_t
gfxp_vgatext_softc_alloc(void)204 gfxp_vgatext_softc_alloc(void)
205 {
206 return (kmem_zalloc(sizeof (struct vgatext_softc), KM_SLEEP));
207 }
208
209 void
gfxp_vgatext_softc_free(gfxp_vgatext_softc_ptr_t ptr)210 gfxp_vgatext_softc_free(gfxp_vgatext_softc_ptr_t ptr)
211 {
212 kmem_free(ptr, sizeof (struct vgatext_softc));
213 }
214
215 /*
216 * NOTE: this function is duplicated here and in consplat/vgatext while
217 * we work on a set of commitable interfaces to sunpci.c.
218 *
219 * Use the class code to determine if the device is a PCI-to-PCI bridge.
220 * Returns: B_TRUE if the device is a bridge.
221 * B_FALSE if the device is not a bridge or the property cannot be
222 * retrieved.
223 */
224 static boolean_t
is_pci_bridge(dev_info_t * dip)225 is_pci_bridge(dev_info_t *dip)
226 {
227 uint32_t class_code;
228
229 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
230 DDI_PROP_DONTPASS, "class-code", 0xffffffff);
231
232 if (class_code == 0xffffffff || class_code == DDI_PROP_NOT_FOUND)
233 return (B_FALSE);
234
235 class_code &= 0x00ffff00;
236 if (class_code == ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8)))
237 return (B_TRUE);
238
239 return (B_FALSE);
240 }
241
242 #define STREQ(a, b) (strcmp((a), (b)) == 0)
243
244 static void
gfxp_check_for_console(dev_info_t * devi,struct vgatext_softc * softc,int pci_pcie_bus)245 gfxp_check_for_console(dev_info_t *devi, struct vgatext_softc *softc,
246 int pci_pcie_bus)
247 {
248 ddi_acc_handle_t pci_conf;
249 dev_info_t *pdevi;
250 uint16_t data16;
251
252 /*
253 * Based on Section 11.3, "PCI Display Subsystem Initialization",
254 * of the 1.1 PCI-to-PCI Bridge Architecture Specification
255 * determine if this is the boot console device. First, see
256 * if the SBIOS has turned on PCI I/O for this device. Then if
257 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set.
258 */
259
260 if (pci_config_setup(devi, &pci_conf) != DDI_SUCCESS) {
261 cmn_err(CE_WARN,
262 MYNAME
263 ": can't get PCI conf handle");
264 return;
265 }
266
267 data16 = pci_config_get16(pci_conf, PCI_CONF_COMM);
268 if (data16 & PCI_COMM_IO)
269 softc->flags |= GFXP_FLAG_CONSOLE;
270
271 pci_config_teardown(&pci_conf);
272
273 /* If IO not enabled or ISA/EISA, just return */
274 if (!(softc->flags & GFXP_FLAG_CONSOLE) || !pci_pcie_bus)
275 return;
276
277 /*
278 * Check for VGA Enable in the Bridge Control register for all
279 * PCI/PCIEX parents. If not set all the way up the chain,
280 * this cannot be the boot console.
281 */
282
283 pdevi = devi;
284 while (pdevi = ddi_get_parent(pdevi)) {
285 int error;
286 ddi_acc_handle_t ppci_conf;
287 char *parent_type = NULL;
288
289 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, pdevi,
290 DDI_PROP_DONTPASS, "device_type", &parent_type);
291 if (error != DDI_SUCCESS) {
292 return;
293 }
294
295 /* Verify still on the PCI/PCIEX parent tree */
296 if (!STREQ(parent_type, "pci") &&
297 !STREQ(parent_type, "pciex")) {
298 ddi_prop_free(parent_type);
299 return;
300 }
301
302 ddi_prop_free(parent_type);
303 parent_type = NULL;
304
305 /* VGAEnable is set only for PCI-to-PCI bridges. */
306 if (is_pci_bridge(pdevi) == B_FALSE)
307 continue;
308
309 if (pci_config_setup(pdevi, &ppci_conf) != DDI_SUCCESS)
310 continue;
311
312 data16 = pci_config_get16(ppci_conf, PCI_BCNF_BCNTRL);
313 pci_config_teardown(&ppci_conf);
314
315 if (!(data16 & PCI_BCNF_BCNTRL_VGA_ENABLE)) {
316 softc->flags &= ~GFXP_FLAG_CONSOLE;
317 return;
318 }
319 }
320 }
321
322 int
gfxp_vgatext_attach(dev_info_t * devi,ddi_attach_cmd_t cmd,gfxp_vgatext_softc_ptr_t ptr)323 gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
324 gfxp_vgatext_softc_ptr_t ptr)
325 {
326 struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
327 int unit = ddi_get_instance(devi);
328 int error;
329 char *parent_type = NULL;
330 int reg_rnumber;
331 off_t reg_offset;
332 off_t mem_offset;
333 char *cons;
334 int pci_pcie_bus = 0;
335 int value;
336
337 switch (cmd) {
338 case DDI_ATTACH:
339 break;
340
341 case DDI_RESUME:
342 vgatext_resume(softc);
343 return (DDI_SUCCESS);
344
345 default:
346 return (DDI_FAILURE);
347 }
348
349 /* DDI_ATTACH */
350
351 softc->devi = devi; /* Copy and init DEVI */
352
353 softc->polledio.arg = (struct vis_polledio_arg *)softc;
354 softc->polledio.display = vgatext_polled_display;
355 softc->polledio.copy = vgatext_polled_copy;
356 softc->polledio.cursor = vgatext_polled_cursor;
357
358 mutex_init(&(softc->lock), NULL, MUTEX_DRIVER, NULL);
359
360 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi),
361 DDI_PROP_DONTPASS, "device_type", &parent_type);
362 if (error != DDI_SUCCESS) {
363 cmn_err(CE_WARN, MYNAME ": can't determine parent type.");
364 goto fail;
365 }
366
367 /* Not enable AGP and DRM by default */
368 if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) {
369 reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR,
370 ®_offset);
371 if (reg_rnumber < 0) {
372 cmn_err(CE_WARN,
373 MYNAME
374 ": can't find reg entry for registers");
375 error = DDI_FAILURE;
376 goto fail;
377 }
378 softc->fb_regno = vgatext_get_isa_reg_index(devi, 0,
379 VGA_MEM_ADDR, &mem_offset);
380 if (softc->fb_regno < 0) {
381 cmn_err(CE_WARN,
382 MYNAME
383 ": can't find reg entry for memory");
384 error = DDI_FAILURE;
385 goto fail;
386 }
387 } else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) {
388 pci_pcie_bus = 1;
389 reg_rnumber = vgatext_get_pci_reg_index(devi,
390 PCI_REG_ADDR_M|PCI_REG_REL_M,
391 PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
392 ®_offset);
393 if (reg_rnumber < 0) {
394 cmn_err(CE_WARN,
395 MYNAME
396 ": can't find reg entry for registers");
397 error = DDI_FAILURE;
398 goto fail;
399 }
400 softc->fb_regno = vgatext_get_pci_reg_index(devi,
401 PCI_REG_ADDR_M|PCI_REG_REL_M,
402 PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
403 &mem_offset);
404 if (softc->fb_regno < 0) {
405 cmn_err(CE_WARN,
406 MYNAME
407 ": can't find reg entry for memory");
408 error = DDI_FAILURE;
409 goto fail;
410 }
411 } else {
412 cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".",
413 parent_type);
414 error = DDI_FAILURE;
415 goto fail;
416 }
417 ddi_prop_free(parent_type);
418 parent_type = NULL;
419
420 error = ddi_regs_map_setup(devi, reg_rnumber,
421 (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
422 &dev_attr, &softc->regs.handle);
423 if (error != DDI_SUCCESS)
424 goto fail;
425 softc->regs.mapped = B_TRUE;
426
427 softc->fb_size = VGA_MEM_SIZE;
428
429 error = ddi_regs_map_setup(devi, softc->fb_regno,
430 (caddr_t *)&softc->fb.addr,
431 mem_offset, softc->fb_size,
432 &dev_attr, &softc->fb.handle);
433 if (error != DDI_SUCCESS)
434 goto fail;
435 softc->fb.mapped = B_TRUE;
436
437 if (ddi_get8(softc->regs.handle,
438 softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL)
439 softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE;
440 else
441 softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE;
442
443 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
444 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
445 if (strcmp(cons, "graphics") == 0) {
446 happyface_boot = 1;
447 vgatext_silent = 1;
448 softc->current_base = softc->shadow;
449 } else {
450 softc->current_base = softc->text_base;
451 }
452 ddi_prop_free(cons);
453 } else {
454 softc->current_base = softc->text_base;
455 }
456
457 error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit),
458 devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0);
459 if (error != DDI_SUCCESS)
460 goto fail;
461
462 gfxp_check_for_console(devi, softc, pci_pcie_bus);
463
464 value = GFXP_IS_CONSOLE(softc) ? 1 : 0;
465 if (ddi_prop_update_int(DDI_DEV_T_NONE, devi,
466 "primary-controller", value) != DDI_SUCCESS) {
467 cmn_err(CE_WARN,
468 "Can not %s primary-controller "
469 "property for driver", value ? "set" : "clear");
470 }
471
472 /* only do this if not in graphics mode */
473 if ((vgatext_silent == 0) && (GFXP_IS_CONSOLE(softc))) {
474 vgatext_init(softc);
475 vgatext_save_colormap(softc);
476 }
477
478 return (DDI_SUCCESS);
479
480 fail:
481 if (parent_type != NULL)
482 ddi_prop_free(parent_type);
483 (void) gfxp_vgatext_detach(devi, DDI_DETACH, (void *)softc);
484 return (error);
485 }
486
487 /*ARGSUSED*/
488 int
gfxp_vgatext_detach(dev_info_t * devi,ddi_detach_cmd_t cmd,gfxp_vgatext_softc_ptr_t ptr)489 gfxp_vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd,
490 gfxp_vgatext_softc_ptr_t ptr)
491 {
492 struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
493
494 (void) ddi_prop_remove(DDI_DEV_T_ANY, devi, "primary-controller");
495
496 switch (cmd) {
497
498 case DDI_SUSPEND:
499 return (vgatext_suspend(softc));
500 /* break; */
501 case DDI_DETACH:
502 if (softc->fb.mapped)
503 ddi_regs_map_free(&softc->fb.handle);
504 if (softc->regs.mapped)
505 ddi_regs_map_free(&softc->regs.handle);
506 mutex_destroy(&(softc->lock));
507 return (DDI_SUCCESS);
508
509 default:
510 cmn_err(CE_WARN, "gfxp_vgatext_detach: unknown cmd 0x%x\n",
511 cmd);
512 return (DDI_FAILURE);
513 }
514 }
515
516 /*ARGSUSED*/
517 int
gfxp_vgatext_open(dev_t * devp,int flag,int otyp,cred_t * cred,gfxp_vgatext_softc_ptr_t ptr)518 gfxp_vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred,
519 gfxp_vgatext_softc_ptr_t ptr)
520 {
521 struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
522
523 if (softc == NULL || otyp == OTYP_BLK)
524 return (ENXIO);
525
526 return (0);
527 }
528
529 /*ARGSUSED*/
530 int
gfxp_vgatext_close(dev_t devp,int flag,int otyp,cred_t * cred,gfxp_vgatext_softc_ptr_t ptr)531 gfxp_vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred,
532 gfxp_vgatext_softc_ptr_t ptr)
533 {
534 return (0);
535 }
536
537 static int
do_gfx_ioctl(int cmd,intptr_t data,int mode,struct vgatext_softc * softc)538 do_gfx_ioctl(int cmd, intptr_t data, int mode, struct vgatext_softc *softc)
539 {
540 static char kernel_only[] =
541 "gfxp_vgatext_ioctl: %s is a kernel only ioctl";
542 int err;
543 int kd_mode;
544
545 switch (cmd) {
546 case KDSETMODE:
547 return (vgatext_kdsetmode(softc, (int)data));
548
549 case KDGETMODE:
550 kd_mode = softc->mode;
551 if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode))
552 return (EFAULT);
553 break;
554
555 case VIS_DEVINIT:
556
557 if (!(mode & FKIOCTL)) {
558 cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT");
559 return (ENXIO);
560 }
561
562 err = vgatext_devinit(softc, (struct vis_devinit *)data);
563 if (err != 0) {
564 cmn_err(CE_WARN,
565 "gfxp_vgatext_ioctl: could not"
566 " initialize console");
567 return (err);
568 }
569 break;
570
571 case VIS_CONSCOPY: /* move */
572 {
573 struct vis_conscopy pma;
574
575 if (ddi_copyin((void *)data, &pma,
576 sizeof (struct vis_conscopy), mode))
577 return (EFAULT);
578
579 vgatext_cons_copy(softc, &pma);
580 break;
581 }
582
583 case VIS_CONSDISPLAY: /* display */
584 {
585 struct vis_consdisplay display_request;
586
587 if (ddi_copyin((void *)data, &display_request,
588 sizeof (display_request), mode))
589 return (EFAULT);
590
591 vgatext_cons_display(softc, &display_request);
592 break;
593 }
594
595 case VIS_CONSCURSOR:
596 {
597 struct vis_conscursor cursor_request;
598
599 if (ddi_copyin((void *)data, &cursor_request,
600 sizeof (cursor_request), mode))
601 return (EFAULT);
602
603 vgatext_cons_cursor(softc, &cursor_request);
604
605 if (cursor_request.action == VIS_GET_CURSOR &&
606 ddi_copyout(&cursor_request, (void *)data,
607 sizeof (cursor_request), mode))
608 return (EFAULT);
609 break;
610 }
611
612 case VIS_GETCMAP:
613 case VIS_PUTCMAP:
614 case FBIOPUTCMAP:
615 case FBIOGETCMAP:
616 /*
617 * At the moment, text mode is not considered to have
618 * a color map.
619 */
620 return (EINVAL);
621
622 case FBIOGATTR:
623 if (copyout(&vgatext_attr, (void *)data,
624 sizeof (struct fbgattr)))
625 return (EFAULT);
626 break;
627
628 case FBIOGTYPE:
629 if (copyout(&vgatext_attr.fbtype, (void *)data,
630 sizeof (struct fbtype)))
631 return (EFAULT);
632 break;
633
634 default:
635 return (ENXIO);
636 }
637 return (0);
638 }
639
640 /*ARGSUSED*/
641 int
gfxp_vgatext_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval,gfxp_vgatext_softc_ptr_t ptr)642 gfxp_vgatext_ioctl(
643 dev_t dev,
644 int cmd,
645 intptr_t data,
646 int mode,
647 cred_t *cred,
648 int *rval,
649 gfxp_vgatext_softc_ptr_t ptr)
650 {
651 int err;
652
653 struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
654
655 mutex_enter(&(softc->lock));
656 err = do_gfx_ioctl(cmd, data, mode, softc);
657 mutex_exit(&(softc->lock));
658
659 return (err);
660 }
661
662 /*
663 * vgatext_save_text
664 * vgatext_restore_textmode
665 * vgatext_suspend
666 * vgatext_resume
667 *
668 * Routines to save and restore contents of the VGA text area
669 * Mostly, this is to support Suspend/Resume operation for graphics
670 * device drivers. Here in the VGAtext common code, we simply squirrel
671 * away the contents of the hardware's text area during Suspend and then
672 * put it back during Resume
673 */
674 static void
vgatext_save_text(struct vgatext_softc * softc)675 vgatext_save_text(struct vgatext_softc *softc)
676 {
677 unsigned i;
678
679 for (i = 0; i < sizeof (softc->shadow); i++)
680 softc->shadow[i] = softc->current_base[i];
681 }
682
683 static void
vgatext_restore_textmode(struct vgatext_softc * softc)684 vgatext_restore_textmode(struct vgatext_softc *softc)
685 {
686 unsigned i;
687
688 vgatext_init(softc);
689 for (i = 0; i < sizeof (softc->shadow); i++) {
690 softc->text_base[i] = softc->shadow[i];
691 }
692 if (softc->cursor.visible) {
693 vgatext_set_cursor(softc,
694 softc->cursor.row, softc->cursor.col);
695 }
696 vgatext_restore_colormap(softc);
697 }
698
699 static int
vgatext_suspend(struct vgatext_softc * softc)700 vgatext_suspend(struct vgatext_softc *softc)
701 {
702 switch (softc->mode) {
703 case KD_TEXT:
704 vgatext_save_text(softc);
705 break;
706
707 case KD_GRAPHICS:
708 break;
709
710 default:
711 cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_suspend.");
712 return (DDI_FAILURE);
713 }
714 return (DDI_SUCCESS);
715 }
716
717 static void
vgatext_resume(struct vgatext_softc * softc)718 vgatext_resume(struct vgatext_softc *softc)
719 {
720
721 switch (softc->mode) {
722 case KD_TEXT:
723 vgatext_restore_textmode(softc);
724 break;
725
726 case KD_GRAPHICS:
727
728 /*
729 * Upon RESUME, the graphics device will always actually
730 * be in TEXT mode even though the Xorg server did not
731 * make that mode change itself (the suspend code did).
732 * We want first, therefore, to restore textmode
733 * operation fully, and then the Xorg server will
734 * do the rest to restore the device to its
735 * (hi resolution) graphics mode
736 */
737 vgatext_restore_textmode(softc);
738 #if defined(USE_BORDERS)
739 vgatext_init_graphics(softc);
740 #endif
741 break;
742 default:
743 cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_resume.");
744 break;
745 }
746 }
747
748 static void
vgatext_progressbar_stop()749 vgatext_progressbar_stop()
750 {
751 extern void progressbar_stop(void);
752
753 if (vgatext_silent == 1) {
754 vgatext_silent = 0;
755 progressbar_stop();
756 }
757 }
758
759 static void
vgatext_kdsettext(struct vgatext_softc * softc)760 vgatext_kdsettext(struct vgatext_softc *softc)
761 {
762 int i;
763
764 vgatext_init(softc);
765 for (i = 0; i < sizeof (softc->shadow); i++) {
766 softc->text_base[i] = softc->shadow[i];
767 }
768 softc->current_base = softc->text_base;
769 if (softc->cursor.visible) {
770 vgatext_set_cursor(softc,
771 softc->cursor.row, softc->cursor.col);
772 }
773 vgatext_restore_colormap(softc);
774 }
775
776 static void
vgatext_kdsetgraphics(struct vgatext_softc * softc)777 vgatext_kdsetgraphics(struct vgatext_softc *softc)
778 {
779 vgatext_progressbar_stop();
780 vgatext_save_text(softc);
781 softc->current_base = softc->shadow;
782 #if defined(USE_BORDERS)
783 vgatext_init_graphics(softc);
784 #endif
785 }
786
787 static int
vgatext_kdsetmode(struct vgatext_softc * softc,int mode)788 vgatext_kdsetmode(struct vgatext_softc *softc, int mode)
789 {
790 if ((mode == softc->mode) || (!GFXP_IS_CONSOLE(softc)))
791 return (0);
792
793 switch (mode) {
794 case KD_TEXT:
795 vgatext_kdsettext(softc);
796 break;
797
798 case KD_GRAPHICS:
799 vgatext_kdsetgraphics(softc);
800 break;
801
802 case KD_RESETTEXT:
803 /*
804 * In order to avoid racing with a starting X server,
805 * this needs to be a test and set that is performed in
806 * a single (softc->lock protected) ioctl into this driver.
807 */
808 if (softc->mode == KD_TEXT && vgatext_silent == 1) {
809 vgatext_progressbar_stop();
810 vgatext_kdsettext(softc);
811 }
812 break;
813
814 default:
815 return (EINVAL);
816 }
817
818 softc->mode = mode;
819 return (0);
820 }
821
822 /*ARGSUSED*/
823 int
gfxp_vgatext_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model,void * ptr)824 gfxp_vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
825 size_t *maplen, uint_t model, void *ptr)
826 {
827 struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
828 int err;
829 size_t length;
830
831
832 if (softc == NULL) {
833 cmn_err(CE_WARN, "vgatext: Can't find softstate");
834 return (-1);
835 }
836
837 if (!(off >= VGA_MMAP_FB_BASE &&
838 off < VGA_MMAP_FB_BASE + softc->fb_size)) {
839 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off);
840 return (-1);
841 }
842
843 if (off + len > VGA_MMAP_FB_BASE + softc->fb_size)
844 length = VGA_MMAP_FB_BASE + softc->fb_size - off;
845 else
846 length = len;
847
848 if ((err = devmap_devmem_setup(dhp, softc->devi,
849 NULL, softc->fb_regno, off - VGA_MMAP_FB_BASE,
850 length, PROT_ALL, 0, &dev_attr)) < 0) {
851 return (err);
852 }
853
854
855 *maplen = length;
856 return (0);
857 }
858
859
860 static int
vgatext_devinit(struct vgatext_softc * softc,struct vis_devinit * data)861 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data)
862 {
863 /* initialize console instance */
864 data->version = VIS_CONS_REV;
865 data->width = TEXT_COLS;
866 data->height = TEXT_ROWS;
867 data->linebytes = TEXT_COLS;
868 data->depth = 4;
869 data->mode = VIS_TEXT;
870 data->polledio = &softc->polledio;
871
872 return (0);
873 }
874
875 /*
876 * display a string on the screen at (row, col)
877 * assume it has been cropped to fit.
878 */
879
880 static void
vgatext_cons_display(struct vgatext_softc * softc,struct vis_consdisplay * da)881 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da)
882 {
883 unsigned char *string;
884 int i;
885 unsigned char attr;
886 struct cgatext {
887 unsigned char ch;
888 unsigned char attr;
889 };
890 struct cgatext *addr;
891
892 /*
893 * Sanity checks. This is a last-ditch effort to avoid damage
894 * from brokenness or maliciousness above.
895 */
896 if (da->row < 0 || da->row >= TEXT_ROWS ||
897 da->col < 0 || da->col >= TEXT_COLS ||
898 da->col + da->width > TEXT_COLS)
899 return;
900
901 /*
902 * To be fully general, we should copyin the data. This is not
903 * really relevant for this text-only driver, but a graphical driver
904 * should support these ioctls from userland to enable simple
905 * system startup graphics.
906 */
907 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4)
908 | solaris_color_to_pc_color[da->fg_color & 0xf];
909 string = da->data;
910 addr = (struct cgatext *)softc->current_base
911 + (da->row * TEXT_COLS + da->col);
912 for (i = 0; i < da->width; i++) {
913 addr->ch = string[i];
914 addr->attr = attr;
915 addr++;
916 }
917 }
918
919 static void
vgatext_polled_display(struct vis_polledio_arg * arg,struct vis_consdisplay * da)920 vgatext_polled_display(
921 struct vis_polledio_arg *arg,
922 struct vis_consdisplay *da)
923 {
924 vgatext_cons_display((struct vgatext_softc *)arg, da);
925 }
926
927 /*
928 * screen-to-screen copy
929 */
930
931 static void
vgatext_cons_copy(struct vgatext_softc * softc,struct vis_conscopy * ma)932 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma)
933 {
934 unsigned short *from;
935 unsigned short *to;
936 int cnt;
937 screen_size_t chars_per_row;
938 unsigned short *to_row_start;
939 unsigned short *from_row_start;
940 screen_size_t rows_to_move;
941 unsigned short *base;
942
943 /*
944 * Sanity checks. Note that this is a last-ditch effort to avoid
945 * damage caused by broken-ness or maliciousness above.
946 */
947 if (ma->s_col < 0 || ma->s_col >= TEXT_COLS ||
948 ma->s_row < 0 || ma->s_row >= TEXT_ROWS ||
949 ma->e_col < 0 || ma->e_col >= TEXT_COLS ||
950 ma->e_row < 0 || ma->e_row >= TEXT_ROWS ||
951 ma->t_col < 0 || ma->t_col >= TEXT_COLS ||
952 ma->t_row < 0 || ma->t_row >= TEXT_ROWS ||
953 ma->s_col > ma->e_col ||
954 ma->s_row > ma->e_row)
955 return;
956
957 /*
958 * Remember we're going to copy shorts because each
959 * character/attribute pair is 16 bits.
960 */
961 chars_per_row = ma->e_col - ma->s_col + 1;
962 rows_to_move = ma->e_row - ma->s_row + 1;
963
964 /* More sanity checks. */
965 if (ma->t_row + rows_to_move > TEXT_ROWS ||
966 ma->t_col + chars_per_row > TEXT_COLS)
967 return;
968
969 base = (unsigned short *)softc->current_base;
970
971 to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col);
972 from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col);
973
974 if (to_row_start < from_row_start) {
975 while (rows_to_move-- > 0) {
976 to = to_row_start;
977 from = from_row_start;
978 to_row_start += TEXT_COLS;
979 from_row_start += TEXT_COLS;
980 for (cnt = chars_per_row; cnt-- > 0; )
981 *to++ = *from++;
982 }
983 } else {
984 /*
985 * Offset to the end of the region and copy backwards.
986 */
987 cnt = rows_to_move * TEXT_COLS + chars_per_row;
988 to_row_start += cnt;
989 from_row_start += cnt;
990
991 while (rows_to_move-- > 0) {
992 to_row_start -= TEXT_COLS;
993 from_row_start -= TEXT_COLS;
994 to = to_row_start;
995 from = from_row_start;
996 for (cnt = chars_per_row; cnt-- > 0; )
997 *--to = *--from;
998 }
999 }
1000 }
1001
1002 static void
vgatext_polled_copy(struct vis_polledio_arg * arg,struct vis_conscopy * ca)1003 vgatext_polled_copy(
1004 struct vis_polledio_arg *arg,
1005 struct vis_conscopy *ca)
1006 {
1007 vgatext_cons_copy((struct vgatext_softc *)arg, ca);
1008 }
1009
1010
1011 static void
vgatext_cons_cursor(struct vgatext_softc * softc,struct vis_conscursor * ca)1012 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca)
1013 {
1014 if (vgatext_silent)
1015 return;
1016
1017 switch (ca->action) {
1018 case VIS_HIDE_CURSOR:
1019 softc->cursor.visible = B_FALSE;
1020 if (softc->current_base == softc->text_base)
1021 vgatext_hide_cursor(softc);
1022 break;
1023 case VIS_DISPLAY_CURSOR:
1024 /*
1025 * Sanity check. This is a last-ditch effort to avoid
1026 * damage from brokenness or maliciousness above.
1027 */
1028 if (ca->col < 0 || ca->col >= TEXT_COLS ||
1029 ca->row < 0 || ca->row >= TEXT_ROWS)
1030 return;
1031
1032 softc->cursor.visible = B_TRUE;
1033 softc->cursor.col = ca->col;
1034 softc->cursor.row = ca->row;
1035 if (softc->current_base == softc->text_base)
1036 vgatext_set_cursor(softc, ca->row, ca->col);
1037 break;
1038 case VIS_GET_CURSOR:
1039 if (softc->current_base == softc->text_base) {
1040 vgatext_get_cursor(softc, &ca->row, &ca->col);
1041 }
1042 break;
1043 }
1044 }
1045
1046 static void
vgatext_polled_cursor(struct vis_polledio_arg * arg,struct vis_conscursor * ca)1047 vgatext_polled_cursor(
1048 struct vis_polledio_arg *arg,
1049 struct vis_conscursor *ca)
1050 {
1051 vgatext_cons_cursor((struct vgatext_softc *)arg, ca);
1052 }
1053
1054
1055
1056 /*ARGSUSED*/
1057 static void
vgatext_hide_cursor(struct vgatext_softc * softc)1058 vgatext_hide_cursor(struct vgatext_softc *softc)
1059 {
1060 /* Nothing at present */
1061 }
1062
1063 static void
vgatext_set_cursor(struct vgatext_softc * softc,int row,int col)1064 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col)
1065 {
1066 short addr;
1067
1068 if (vgatext_silent)
1069 return;
1070
1071 addr = row * TEXT_COLS + col;
1072
1073 vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8);
1074 vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff);
1075 }
1076
1077 static int vga_row, vga_col;
1078
1079 static void
vgatext_get_cursor(struct vgatext_softc * softc,screen_pos_t * row,screen_pos_t * col)1080 vgatext_get_cursor(struct vgatext_softc *softc,
1081 screen_pos_t *row, screen_pos_t *col)
1082 {
1083 short addr;
1084
1085 addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) +
1086 vga_get_crtc(&softc->regs, VGA_CRTC_CLAL);
1087
1088 vga_row = *row = addr / TEXT_COLS;
1089 vga_col = *col = addr % TEXT_COLS;
1090 }
1091
1092 /*
1093 * This code is experimental. It's only enabled if console is
1094 * set to graphics, a preliminary implementation of happyface boot.
1095 */
1096 static void
vgatext_set_text(struct vgatext_softc * softc)1097 vgatext_set_text(struct vgatext_softc *softc)
1098 {
1099 int i;
1100
1101 if (happyface_boot == 0)
1102 return;
1103
1104 /* we are in graphics mode, set to text 80X25 mode */
1105
1106 /* set misc registers */
1107 vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT);
1108
1109 /* set sequencer registers */
1110 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1111 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) &
1112 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1113 for (i = 1; i < NUM_SEQ_REG; i++) {
1114 vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]);
1115 }
1116 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1117 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) |
1118 VGA_SEQ_RST_SYN_NO_ASYNC_RESET |
1119 VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1120
1121 /* set crt controller registers */
1122 vga_set_crtc(&softc->regs, VGA_CRTC_VRE,
1123 (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) &
1124 ~VGA_CRTC_VRE_LOCK));
1125 for (i = 0; i < NUM_CRTC_REG; i++) {
1126 vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]);
1127 }
1128
1129 /* set graphics controller registers */
1130 for (i = 0; i < NUM_GRC_REG; i++) {
1131 vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]);
1132 }
1133
1134 /* set attribute registers */
1135 for (i = 0; i < NUM_ATR_REG; i++) {
1136 vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]);
1137 }
1138
1139 /* set palette */
1140 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) {
1141 vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2,
1142 VGA_TEXT_PALETTES[i][1] << 2,
1143 VGA_TEXT_PALETTES[i][2] << 2);
1144 }
1145 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) {
1146 vga_put_cmap(&softc->regs, i, 0, 0, 0);
1147 }
1148
1149 vgatext_save_colormap(softc);
1150 }
1151
1152 static void
vgatext_init(struct vgatext_softc * softc)1153 vgatext_init(struct vgatext_softc *softc)
1154 {
1155 unsigned char atr_mode;
1156
1157 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1158 if (atr_mode & VGA_ATR_MODE_GRAPH)
1159 vgatext_set_text(softc);
1160 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1161 atr_mode &= ~VGA_ATR_MODE_BLINK;
1162 atr_mode &= ~VGA_ATR_MODE_9WIDE;
1163 vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode);
1164 #if defined(USE_BORDERS)
1165 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1166 vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE));
1167 #else
1168 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1169 vga_get_atr(&softc->regs, VGA_BLACK));
1170 #endif
1171 vgatext_setfont(softc); /* need selectable font? */
1172 }
1173
1174 #if defined(USE_BORDERS)
1175 static void
vgatext_init_graphics(struct vgatext_softc * softc)1176 vgatext_init_graphics(struct vgatext_softc *softc)
1177 {
1178 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1179 vga_get_atr(&softc->regs, VGA_BLACK));
1180 }
1181 #endif
1182
1183 static void
vgatext_setfont(struct vgatext_softc * softc)1184 vgatext_setfont(struct vgatext_softc *softc)
1185 {
1186 extern unsigned char *ENCODINGS[];
1187 unsigned char *from;
1188 unsigned char *to;
1189 int i;
1190 int j;
1191 int bpc;
1192
1193 /*
1194 * The newboot code to use font plane 2 breaks NVIDIA
1195 * (and some ATI) behavior. Revert back to the S10
1196 * code.
1197 */
1198
1199 /*
1200 * I'm embarassed to say that I don't know what these magic
1201 * sequences do, other than at the high level of "set the
1202 * memory window to allow font setup". I stole them straight
1203 * from "kd"...
1204 */
1205 vga_set_seq(&softc->regs, 0x02, 0x04);
1206 vga_set_seq(&softc->regs, 0x04, 0x06);
1207 vga_set_grc(&softc->regs, 0x05, 0x00);
1208 vga_set_grc(&softc->regs, 0x06, 0x04);
1209
1210 /*
1211 * This assumes 8x16 characters, which yield the traditional 80x25
1212 * screen. It really should support other character heights.
1213 */
1214 bpc = 16;
1215 for (i = 0; i < 256; i++) {
1216 from = ENCODINGS[i];
1217 to = (unsigned char *)softc->fb.addr + i * 0x20;
1218 for (j = 0; j < bpc; j++)
1219 *to++ = *from++;
1220 }
1221
1222 vga_set_seq(&softc->regs, 0x02, 0x03);
1223 vga_set_seq(&softc->regs, 0x04, 0x02);
1224 vga_set_grc(&softc->regs, 0x04, 0x00);
1225 vga_set_grc(&softc->regs, 0x05, 0x10);
1226 vga_set_grc(&softc->regs, 0x06, 0x0e);
1227
1228 }
1229
1230 static void
vgatext_save_colormap(struct vgatext_softc * softc)1231 vgatext_save_colormap(struct vgatext_softc *softc)
1232 {
1233 int i;
1234
1235 for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1236 softc->attrib_palette[i] = vga_get_atr(&softc->regs, i);
1237 }
1238 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1239 vga_get_cmap(&softc->regs, i,
1240 &softc->colormap[i].red,
1241 &softc->colormap[i].green,
1242 &softc->colormap[i].blue);
1243 }
1244 }
1245
1246 static void
vgatext_restore_colormap(struct vgatext_softc * softc)1247 vgatext_restore_colormap(struct vgatext_softc *softc)
1248 {
1249 int i;
1250
1251 for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1252 vga_set_atr(&softc->regs, i, softc->attrib_palette[i]);
1253 }
1254 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1255 vga_put_cmap(&softc->regs, i,
1256 softc->colormap[i].red,
1257 softc->colormap[i].green,
1258 softc->colormap[i].blue);
1259 }
1260 }
1261
1262 /*
1263 * search the entries of the "reg" property for one which has the desired
1264 * combination of phys_hi bits and contains the desired address.
1265 *
1266 * This version searches a PCI-style "reg" property. It was prompted by
1267 * issues surrounding the presence or absence of an entry for the ROM:
1268 * (a) a transition problem with PowerPC Virtual Open Firmware
1269 * (b) uncertainty as to whether an entry will be included on a device
1270 * with ROM support (and so an "active" ROM base address register),
1271 * but no ROM actually installed.
1272 *
1273 * See the note below on vgatext_get_isa_reg_index for the reasons for
1274 * returning the offset.
1275 *
1276 * Note that this routine may not be fully general; it is intended for the
1277 * specific purpose of finding a couple of particular VGA reg entries and
1278 * may not be suitable for all reg-searching purposes.
1279 */
1280 static int
vgatext_get_pci_reg_index(dev_info_t * const devi,unsigned long himask,unsigned long hival,unsigned long addr,off_t * offset)1281 vgatext_get_pci_reg_index(
1282 dev_info_t *const devi,
1283 unsigned long himask,
1284 unsigned long hival,
1285 unsigned long addr,
1286 off_t *offset)
1287 {
1288
1289 int length, index;
1290 pci_regspec_t *reg;
1291
1292 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1293 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
1294 return (-1);
1295 }
1296
1297 for (index = 0; index < length / sizeof (pci_regspec_t); index++) {
1298 if ((reg[index].pci_phys_hi & himask) != hival)
1299 continue;
1300 if (reg[index].pci_size_hi != 0)
1301 continue;
1302 if (reg[index].pci_phys_mid != 0)
1303 continue;
1304 if (reg[index].pci_phys_low > addr)
1305 continue;
1306 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr)
1307 continue;
1308
1309 *offset = addr - reg[index].pci_phys_low;
1310 kmem_free(reg, (size_t)length);
1311 return (index);
1312 }
1313 kmem_free(reg, (size_t)length);
1314
1315 return (-1);
1316 }
1317
1318 /*
1319 * search the entries of the "reg" property for one which has the desired
1320 * combination of phys_hi bits and contains the desired address.
1321 *
1322 * This version searches a ISA-style "reg" property. It was prompted by
1323 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions,
1324 * 8514/A registers should have been added after all standard VGA registers.
1325 * Unfortunately, the Solaris/Intel device configuration framework
1326 * (a) lists the 8514/A registers before the video memory, and then
1327 * (b) also sorts the entries so that I/O entries come before memory
1328 * entries.
1329 *
1330 * It returns the "reg" index and offset into that register set.
1331 * The offset is needed because there exist (broken?) BIOSes that
1332 * report larger ranges enclosing the standard ranges. One reports
1333 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the
1334 * offset adjusts for this difference in the base of the register set.
1335 *
1336 * Note that this routine may not be fully general; it is intended for the
1337 * specific purpose of finding a couple of particular VGA reg entries and
1338 * may not be suitable for all reg-searching purposes.
1339 */
1340 static int
vgatext_get_isa_reg_index(dev_info_t * const devi,unsigned long hival,unsigned long addr,off_t * offset)1341 vgatext_get_isa_reg_index(
1342 dev_info_t *const devi,
1343 unsigned long hival,
1344 unsigned long addr,
1345 off_t *offset)
1346 {
1347
1348 int length, index;
1349 struct regspec *reg;
1350
1351 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1352 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
1353 return (-1);
1354 }
1355
1356 for (index = 0; index < length / sizeof (struct regspec); index++) {
1357 if (reg[index].regspec_bustype != hival)
1358 continue;
1359 if (reg[index].regspec_addr > addr)
1360 continue;
1361 if (reg[index].regspec_addr + reg[index].regspec_size <= addr)
1362 continue;
1363
1364 *offset = addr - reg[index].regspec_addr;
1365 kmem_free(reg, (size_t)length);
1366 return (index);
1367 }
1368 kmem_free(reg, (size_t)length);
1369
1370 return (-1);
1371 }
1372
1373 /*
1374 * This vgatext function is used to return the fb, and reg pointers
1375 * and handles for peer graphics drivers.
1376 */
1377
1378 void
vgatext_return_pointers(struct vgatext_softc * softc,struct vgaregmap * fbs,struct vgaregmap * regss)1379 vgatext_return_pointers(struct vgatext_softc *softc,
1380 struct vgaregmap *fbs,
1381 struct vgaregmap *regss)
1382 {
1383
1384 fbs->addr = softc->fb.addr;
1385 fbs->handle = softc->fb.handle;
1386 fbs->mapped = softc->fb.mapped;
1387 regss->addr = softc->regs.addr;
1388 regss->handle = softc->regs.handle;
1389 regss->mapped = softc->regs.mapped;
1390 }
1391