xref: /illumos-gate/usr/src/uts/i86pc/os/graphics.c (revision 6e375c8351497b82ffa4f33cbf61d712999b4605)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/systm.h>
30 #include <sys/bootconf.h>
31 #include <sys/thread.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <vm/seg_kmem.h>
35 
36 #define	VIDEOMEM	0xa0000
37 
38 extern void outb(int, uchar_t);
39 
40 static int graphics_mode;
41 static int cursor_y = 309;
42 static int cursor_x = 136;
43 
44 #define	BAR_STEPS 46
45 
46 static uchar_t bar[BAR_STEPS];
47 static kthread_t *progressbar_tid;
48 static kmutex_t pbar_lock;
49 static kcondvar_t pbar_cv;
50 static char *videomem = (caddr_t)VIDEOMEM;
51 static int videomem_size;
52 
53 /* select the plane(s) to draw to */
54 static void
55 mapmask(int plane)
56 {
57 	outb(0x3c4, 2);
58 	outb(0x3c5, plane);
59 }
60 
61 static void
62 bitmask(int value)
63 {
64 	outb(0x3ce, 8);
65 	outb(0x3cf, value);
66 }
67 
68 static void
69 progressbar_show(void)
70 {
71 	int j, k, offset;
72 	uchar_t *mem, *ptr;
73 
74 	offset = cursor_y * 80 + cursor_x / 8;
75 	mem = (uchar_t *)videomem + offset;
76 
77 	bitmask(0xff);
78 	mapmask(0xff); /* write to all planes at once? */
79 	for (j = 0; j < 4; j++) {   /* bar height: 4 pixels */
80 		ptr = mem + j * 80;
81 		for (k = 0; k < BAR_STEPS; k++, ptr++)
82 			*ptr = bar[k];
83 	}
84 	bitmask(0x00);
85 }
86 
87 /*
88  * Initialize a rectangle area for progress bar
89  *
90  * Multiboot has initialized graphics mode to 640x480
91  * with 16 colors.
92  */
93 void
94 progressbar_init()
95 {
96 	int i;
97 	char cons[10];
98 
99 	/* see if we are in graphics mode */
100 	if (BOP_GETPROPLEN(bootops, "console") != sizeof ("graphics"))
101 		return;
102 	(void) BOP_GETPROP(bootops, "console", cons);
103 	if (strncmp(cons, "graphics", strlen("graphics")) != 0)
104 		return;
105 
106 	graphics_mode = 1;
107 
108 	for (i = 0; i < BAR_STEPS; i++) {
109 		bar[i] = 0x00;
110 	}
111 
112 	progressbar_show();
113 }
114 
115 static void
116 progressbar_step()
117 {
118 	static int limit = 0;
119 
120 	bar[limit] = 0xff;
121 
122 	if (limit > 3)
123 		bar[limit - 4] = 0x00;
124 	else
125 		bar[limit + BAR_STEPS - 4] = 0x00;
126 
127 	limit++;
128 	if (limit == BAR_STEPS)
129 		limit = 0;
130 
131 	progressbar_show();
132 }
133 
134 /*ARGSUSED*/
135 static void
136 progressbar_thread(void *arg)
137 {
138 	clock_t end;
139 
140 	mutex_enter(&pbar_lock);
141 	while (graphics_mode) {
142 		progressbar_step();
143 		end = ddi_get_lbolt() + drv_usectohz(150000);
144 		(void) cv_timedwait(&pbar_cv, &pbar_lock, end);
145 	}
146 	mutex_exit(&pbar_lock);
147 }
148 
149 void
150 progressbar_start(void)
151 {
152 #if !defined(__xpv)
153 	extern pri_t minclsyspri;
154 
155 	if (graphics_mode == 0)
156 		return;
157 
158 	/* map video memory to kernel heap */
159 	videomem_size = ptob(btopr(38400));	/* 640 x 480 / 8 bytes */
160 	videomem = vmem_alloc(heap_arena, videomem_size, VM_SLEEP);
161 	if (videomem == NULL) {
162 		cmn_err(CE_NOTE, "!failed to start progress bar");
163 		graphics_mode = 0;
164 		return;
165 	}
166 	hat_devload(kas.a_hat, videomem, videomem_size,
167 	    btop(VIDEOMEM), (PROT_READ | PROT_WRITE),
168 	    HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK);
169 
170 	progressbar_tid = thread_create(NULL, 0, progressbar_thread,
171 	    NULL, 0, &p0, TS_RUN, minclsyspri);
172 #endif
173 }
174 
175 void
176 progressbar_stop(void)
177 {
178 #if !defined(__xpv)
179 	if (graphics_mode == 0)
180 		return;
181 
182 	graphics_mode = 0;
183 	mutex_enter(&pbar_lock);
184 	cv_signal(&pbar_cv);
185 	mutex_exit(&pbar_lock);
186 	if (progressbar_tid != NULL)
187 		thread_join(progressbar_tid->t_did);
188 
189 	/* unmap video memory */
190 	hat_unload(kas.a_hat, videomem, videomem_size, HAT_UNLOAD_UNLOCK);
191 	vmem_free(heap_arena, videomem, videomem_size);
192 #endif
193 }
194