1 /*- 2 * Copyright (c) 2015 Conrad Meyer <cse.cem@gmail.com> 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/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/callout.h> 32 #include <sys/cons.h> 33 #include <sys/lock.h> 34 #include <sys/kernel.h> 35 #include <sys/mutex.h> 36 #include <sys/smp.h> 37 #include <sys/systm.h> 38 #include <sys/terminal.h> 39 40 #include <dev/vt/vt.h> 41 42 extern const unsigned char vt_beastie_vga16[]; 43 extern const unsigned char vt_beastie2_vga16[]; 44 extern const unsigned char vt_orb_vga16[]; 45 46 static struct callout vt_splash_cpu_callout; 47 48 static inline unsigned char 49 vt_vga2bsd(unsigned char vga) 50 { 51 static const unsigned char lut[8] = { 52 0, 53 4, /* 1 and 4 swap */ 54 2, 55 6, /* 3 and 6 swap */ 56 1, /* 4 and 1 swap */ 57 5, 58 3, /* 6 and 3 swap */ 59 7, 60 }; 61 unsigned int bright; 62 63 bright = (vga & 0x8); 64 return (lut[vga & 0x7] | bright); 65 } 66 67 static void 68 vt_draw_2_vga16_px(struct vt_device *vd, vt_axis_t x, vt_axis_t y, 69 unsigned char color) 70 { 71 72 vd->vd_driver->vd_setpixel(vd, x, y, vt_vga2bsd(color >> 4)); 73 vd->vd_driver->vd_setpixel(vd, x + 1, y, vt_vga2bsd(color & 0xf)); 74 } 75 76 static void 77 vt_draw_1_logo(struct vt_device *vd, vt_axis_t top, vt_axis_t left) 78 { 79 const unsigned char rle_sent = 0x16, *data; 80 unsigned int xy, run, runcolor, i; 81 82 switch (vt_splash_cpu_style) { 83 case VT_LOGOS_DRAW_ALT_BEASTIE: 84 data = vt_beastie2_vga16; 85 break; 86 case VT_LOGOS_DRAW_ORB: 87 data = vt_orb_vga16; 88 break; 89 case VT_LOGOS_DRAW_BEASTIE: 90 /* FALLTHROUGH */ 91 default: 92 data = vt_beastie_vga16; 93 break; 94 } 95 96 /* Decode basic RLE (gets us to 30-40% of uncompressed data size): */ 97 for (i = 0, xy = 0; xy < vt_logo_sprite_height * vt_logo_sprite_width;) { 98 if (data[i] == rle_sent) { 99 runcolor = data[i + 1]; 100 run = data[i + 2]; 101 102 for (; run; run--, xy += 2) 103 vt_draw_2_vga16_px(vd, 104 left + (xy % vt_logo_sprite_width), 105 top + (xy / vt_logo_sprite_width), 106 runcolor); 107 108 i += 3; 109 } else { 110 vt_draw_2_vga16_px(vd, left + (xy % vt_logo_sprite_width), 111 top + (xy / vt_logo_sprite_width), data[i]); 112 113 i++; 114 xy += 2; 115 } 116 } 117 } 118 119 void 120 vtterm_draw_cpu_logos(struct vt_device *vd) 121 { 122 unsigned int ncpu, i; 123 vt_axis_t left; 124 125 if (vt_splash_ncpu) 126 ncpu = vt_splash_ncpu; 127 else { 128 ncpu = mp_ncpus; 129 if (ncpu < 1) 130 ncpu = 1; 131 } 132 133 if (vd->vd_driver->vd_drawrect) 134 vd->vd_driver->vd_drawrect(vd, 0, 0, vd->vd_width, 135 vt_logo_sprite_height, 1, TC_BLACK); 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, TC_BLACK); 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) 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 tm = &vt_consterm; 221 vw = tm->tm_softc; 222 if (vw == NULL) 223 return; 224 vd = vw->vw_device; 225 if (vd == NULL) 226 return; 227 vf = vw->vw_font; 228 if (vf == NULL) 229 return; 230 231 VT_LOCK(vd); 232 KASSERT((vd->vd_flags & VDF_INITIALIZED) != 0, 233 ("vd %p not initialized", vd)); 234 235 if ((vd->vd_flags & (VDF_DEAD | VDF_TEXTMODE)) != 0) 236 goto out; 237 if (vd->vd_height <= vt_logo_sprite_height) 238 goto out; 239 240 vt_draw_logo_cpus = 1; 241 VT_UNLOCK(vd); 242 243 vt_termsize(vd, vf, &size); 244 vt_winsize(vd, vf, &wsz); 245 246 /* Resize screen buffer and terminal. */ 247 terminal_mute(tm, 1); 248 vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 249 terminal_set_winsize_blank(tm, &wsz, 0, NULL); 250 terminal_set_cursor(tm, &vw->vw_buf.vb_cursor); 251 terminal_mute(tm, 0); 252 253 VT_LOCK(vd); 254 vt_compute_drawable_area(vw); 255 256 if (vd->vd_curwindow == vw) { 257 vd->vd_flags |= VDF_INVALID; 258 vt_resume_flush_timer(vw, 0); 259 } 260 261 callout_init(&vt_splash_cpu_callout, 1); 262 callout_reset(&vt_splash_cpu_callout, vt_splash_cpu_duration * hz, 263 vt_fini_logos, NULL); 264 265 out: 266 VT_UNLOCK(vd); 267 } 268 SYSINIT(vt_logos, SI_SUB_CPU + 1, SI_ORDER_ANY, vt_init_logos, NULL); 269