1 /*- 2 * Copyright (c) 2015 Conrad Meyer <cem@FreeBSD.org> 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. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/callout.h> 29 #include <sys/cons.h> 30 #include <sys/lock.h> 31 #include <sys/kernel.h> 32 #include <sys/mutex.h> 33 #include <sys/smp.h> 34 #include <sys/systm.h> 35 #include <sys/terminal.h> 36 37 #include <dev/vt/vt.h> 38 39 extern const unsigned char vt_beastie_vga16[]; 40 extern const unsigned char vt_beastie2_vga16[]; 41 extern const unsigned char vt_orb_vga16[]; 42 43 static struct timeout_task vt_splash_cpu_fini_task; 44 45 static inline unsigned char 46 vt_vga2bsd(unsigned char vga) 47 { 48 static const unsigned char lut[8] = { 49 0, 50 4, /* 1 and 4 swap */ 51 2, 52 6, /* 3 and 6 swap */ 53 1, /* 4 and 1 swap */ 54 5, 55 3, /* 6 and 3 swap */ 56 7, 57 }; 58 unsigned int bright; 59 60 bright = (vga & 0x8); 61 return (lut[vga & 0x7] | bright); 62 } 63 64 static void 65 vt_draw_2_vga16_px(struct vt_device *vd, vt_axis_t x, vt_axis_t y, 66 unsigned char color) 67 { 68 69 vd->vd_driver->vd_setpixel(vd, x, y, vt_vga2bsd(color >> 4)); 70 vd->vd_driver->vd_setpixel(vd, x + 1, y, vt_vga2bsd(color & 0xf)); 71 } 72 73 static void 74 vt_draw_1_logo(struct vt_device *vd, vt_axis_t top, vt_axis_t left) 75 { 76 const unsigned char rle_sent = 0x16, *data; 77 unsigned int xy, run, runcolor, i; 78 79 switch (vt_splash_cpu_style) { 80 case VT_LOGOS_DRAW_ALT_BEASTIE: 81 data = vt_beastie2_vga16; 82 break; 83 case VT_LOGOS_DRAW_ORB: 84 data = vt_orb_vga16; 85 break; 86 case VT_LOGOS_DRAW_BEASTIE: 87 /* FALLTHROUGH */ 88 default: 89 data = vt_beastie_vga16; 90 break; 91 } 92 93 /* Decode basic RLE (gets us to 30-40% of uncompressed data size): */ 94 for (i = 0, xy = 0; xy < vt_logo_sprite_height * vt_logo_sprite_width;) { 95 if (data[i] == rle_sent) { 96 runcolor = data[i + 1]; 97 run = data[i + 2]; 98 99 for (; run; run--, xy += 2) 100 vt_draw_2_vga16_px(vd, 101 left + (xy % vt_logo_sprite_width), 102 top + (xy / vt_logo_sprite_width), 103 runcolor); 104 105 i += 3; 106 } else { 107 vt_draw_2_vga16_px(vd, left + (xy % vt_logo_sprite_width), 108 top + (xy / vt_logo_sprite_width), data[i]); 109 110 i++; 111 xy += 2; 112 } 113 } 114 } 115 116 void 117 vtterm_draw_cpu_logos(struct vt_device *vd) 118 { 119 unsigned int ncpu, i; 120 vt_axis_t left; 121 struct terminal *tm = vd->vd_curwindow->vw_terminal; 122 const teken_attr_t *a; 123 124 if (vt_splash_ncpu) 125 ncpu = vt_splash_ncpu; 126 else { 127 ncpu = mp_ncpus; 128 if (ncpu < 1) 129 ncpu = 1; 130 } 131 132 a = teken_get_curattr(&tm->tm_emulator); 133 if (vd->vd_driver->vd_drawrect) 134 vd->vd_driver->vd_drawrect(vd, 0, 0, vd->vd_width - 1, 135 vt_logo_sprite_height - 1, 1, a->ta_bgcolor); 136 /* 137 * Blank is okay because we only ever draw beasties on full screen 138 * refreshes. 139 */ 140 else if (vd->vd_driver->vd_blank) 141 vd->vd_driver->vd_blank(vd, a->ta_bgcolor); 142 143 ncpu = MIN(ncpu, vd->vd_width / vt_logo_sprite_width); 144 for (i = 0, left = 0; i < ncpu; left += vt_logo_sprite_width, i++) 145 vt_draw_1_logo(vd, 0, left); 146 } 147 148 static void 149 vt_fini_logos(void *dummy __unused, int pending __unused) 150 { 151 struct vt_device *vd; 152 struct vt_window *vw; 153 struct terminal *tm; 154 struct vt_font *vf; 155 struct winsize wsz; 156 term_pos_t size; 157 unsigned int i; 158 159 if (!vt_draw_logo_cpus) 160 return; 161 if (!vty_enabled(VTY_VT)) 162 return; 163 if (!vt_splash_cpu) 164 return; 165 166 vd = &vt_consdev; 167 VT_LOCK(vd); 168 if ((vd->vd_flags & (VDF_DEAD | VDF_TEXTMODE)) != 0) { 169 VT_UNLOCK(vd); 170 return; 171 } 172 vt_draw_logo_cpus = 0; 173 VT_UNLOCK(vd); 174 175 for (i = 0; i < VT_MAXWINDOWS; i++) { 176 vw = vd->vd_windows[i]; 177 if (vw == NULL) 178 continue; 179 tm = vw->vw_terminal; 180 vf = vw->vw_font; 181 if (vf == NULL) 182 continue; 183 184 vt_termsize(vd, vf, &size); 185 vt_winsize(vd, vf, &wsz); 186 187 /* Resize screen buffer and terminal. */ 188 terminal_mute(tm, 1); 189 vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 190 terminal_set_winsize_blank(tm, &wsz, 0, NULL); 191 terminal_set_cursor(tm, &vw->vw_buf.vb_cursor); 192 terminal_mute(tm, 0); 193 194 VT_LOCK(vd); 195 vt_compute_drawable_area(vw); 196 197 if (vd->vd_curwindow == vw) { 198 vd->vd_flags |= VDF_INVALID; 199 vt_resume_flush_timer(vw, 0); 200 } 201 VT_UNLOCK(vd); 202 } 203 } 204 205 static void 206 vt_init_logos(void *dummy) 207 { 208 struct vt_device *vd; 209 struct vt_window *vw; 210 struct terminal *tm; 211 struct vt_font *vf; 212 struct winsize wsz; 213 term_pos_t size; 214 215 if (!vty_enabled(VTY_VT)) 216 return; 217 if (!vt_splash_cpu) 218 return; 219 220 vd = &vt_consdev; 221 if (vd == NULL) 222 return; 223 vw = vd->vd_curwindow; 224 if (vw == NULL) 225 return; 226 tm = vw->vw_terminal; 227 if (tm == NULL) 228 return; 229 vf = vw->vw_font; 230 if (vf == NULL) 231 return; 232 233 VT_LOCK(vd); 234 if ((vd->vd_flags & VDF_INITIALIZED) == 0) 235 goto out; 236 if ((vd->vd_flags & (VDF_DEAD | VDF_TEXTMODE)) != 0) 237 goto out; 238 if (vd->vd_height <= vt_logo_sprite_height) 239 goto out; 240 241 vt_draw_logo_cpus = 1; 242 VT_UNLOCK(vd); 243 244 vt_termsize(vd, vf, &size); 245 vt_winsize(vd, vf, &wsz); 246 247 /* Resize screen buffer and terminal. */ 248 terminal_mute(tm, 1); 249 vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 250 terminal_set_winsize_blank(tm, &wsz, 0, NULL); 251 terminal_set_cursor(tm, &vw->vw_buf.vb_cursor); 252 terminal_mute(tm, 0); 253 254 VT_LOCK(vd); 255 vt_compute_drawable_area(vw); 256 257 if (vd->vd_curwindow == vw) { 258 vd->vd_flags |= VDF_INVALID; 259 vt_resume_flush_timer(vw, 0); 260 } 261 262 TIMEOUT_TASK_INIT(taskqueue_thread, &vt_splash_cpu_fini_task, 0, 263 vt_fini_logos, NULL); 264 taskqueue_enqueue_timeout(taskqueue_thread, &vt_splash_cpu_fini_task, 265 vt_splash_cpu_duration * hz); 266 267 out: 268 VT_UNLOCK(vd); 269 } 270 SYSINIT(vt_logos, SI_SUB_TASKQ, SI_ORDER_ANY, vt_init_logos, NULL); 271